"Fossies" - the Fresh Open Source Software Archive

Member "gentoo-0.20.7/src/progress.c" (15 Jun 2016, 12986 Bytes) of package /linux/misc/gentoo-0.20.7.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "progress.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 0.20.6_vs_0.20.7.

    1 /*
    2 ** 1998-09-29 - This is a Russion space shuttle. It is also the module responsible for
    3 **      reporting various commands' progress to the user, and providing a nice
    4 **      way of aborting commands prematurely.
    5 ** 1999-01-30 - Now cancels operation if ESCape is hit. Pretty convenient.
    6 ** 1999-03-05 - Adapted for new selection management. Also fixes a couple of minor bugs.
    7 ** 2000-07-16 - Operation can now be cancelled by closing the progress window.
    8 */
    9 
   10 #include "gentoo.h"
   11 
   12 #include <sys/stat.h>
   13 #include <unistd.h>
   14 
   15 #include <gdk/gdkkeysyms.h>
   16 
   17 #include "dirpane.h"
   18 #include "fileutil.h"
   19 #include "guiutil.h"
   20 #include "miscutil.h"
   21 #include "sizeutil.h"
   22 
   23 #include "progress.h"
   24 
   25 /* ----------------------------------------------------------------------------------------- */
   26 
   27 static struct {
   28     guint       level;          /* Current begin/end nesting level. Keep first!! */
   29     guint32     flags;          /* Flags from original progress_begin() call. */
   30     GCancellable    *cancel;        /* This is from the future. */
   31     gboolean    show_byte;      /* Show total bytes progress bar? */
   32     gboolean    show_item;      /* Show the item bar? */
   33     gboolean    delayed;        /* Set to 1 during initial display delay. */
   34     guint       tot_num;        /* Total number of items to process. */
   35     guint       tot_pos;        /* Index of current item. */
   36     guint64     byte_tot;       /* Total bytes in operation. */
   37     guint64     byte_pos;       /* Position, in bytes. */
   38     gchar       name[4 * FILENAME_MAX]; /* Current filename. */
   39     off_t       item_size;      /* Size of current item being processed. */
   40     off_t       item_pos;       /* Position in the item. */
   41     GTimeVal    time_begin;     /* The time when pgs_progress_begin() was called. */
   42     guint       delay_time;     /* Delay until display, in microseconds (!). */
   43     guint       last_secs;      /* Elapsed seconds last time we displayed ETA and stuff. */
   44 
   45     MainInfo    *min;
   46     GtkWidget   *dlg;
   47     GtkWidget   *body;
   48     GtkWidget   *tot_pgs;
   49 
   50     GtkWidget   *byte_pgs;
   51     GtkWidget   *byte_high;
   52 
   53     GtkWidget   *item;
   54     GtkWidget   *item_pgs;
   55 
   56     GtkWidget   *eta;       /* Label for elapsed time, speed, and ETA. */
   57 } pgs_info = { 0U };
   58 
   59 /* ----------------------------------------------------------------------------------------- */
   60 
   61 /* 1998-09-30 - Count number of top-level selections.
   62 ** 1998-10-01 - Added size support.
   63 */
   64 static guint count_toplevel_selected(MainInfo *min, guint64 *size)
   65 {
   66     DirPane *dp = min->gui->cur_pane;
   67     GSList  *slist, *iter;
   68     guint   num = 0;
   69     guint64 dummy;
   70 
   71     if(size == NULL)
   72         size = &dummy;
   73 
   74     for(iter = slist = dp_get_selection(dp), *size = 0; iter != NULL; iter = g_slist_next(iter), num++)
   75         *size += dp_row_get_size(dp_get_tree_model(dp), iter->data);
   76     dp_free_selection(slist);
   77 
   78     return num;
   79 }
   80 
   81 /* 1998-09-30 - Count number of items recursively from all selections.
   82 ** 1998-10-01 - Added size support.
   83 ** 1998-12-20 - Now uses the fut_dir_size() function for the recursive scanning.
   84 */
   85 static guint count_recursive_selected(MainInfo *min, guint64 *size)
   86 {
   87     DirPane *dp = min->gui->cur_pane;
   88     GSList  *slist, *iter;
   89     guint   num = 0;
   90 
   91     if(size != NULL)
   92         *size = 0U;
   93     for(iter = slist = dp_get_selection(dp); iter != NULL; iter = g_slist_next(iter), num++)
   94     {
   95         if(size)
   96             *size += dp_row_get_size(dp_get_tree_model(dp), iter->data);
   97         if(dp_row_get_file_type(dp_get_tree_model(dp), iter->data, TRUE) == G_FILE_TYPE_DIRECTORY)
   98         {
   99             FUCount fu;
  100             GFile   *dir;
  101 
  102             dir = dp_get_file_from_row(dp, iter->data);
  103             if(fut_size_gfile(min, dir, size, &fu, NULL))
  104                 num += fu.num_total;
  105             g_object_unref(dir);
  106         }
  107     }
  108     dp_free_selection(slist);
  109 
  110     return num;
  111 }
  112 
  113 static gint evt_delete(GtkWidget *wid, GdkEvent *evt, gpointer user)
  114 {
  115     g_cancellable_cancel(user);
  116     return TRUE;
  117 }
  118 
  119 /* 1998-09-30 - A callback for the big "Cancel" button. */
  120 static gint evt_cancel_clicked(GtkWidget *wid, gpointer user)
  121 {
  122     g_cancellable_cancel(user);
  123     return TRUE;
  124 }
  125 
  126 static gint evt_keypress(GtkWidget *wid, GdkEventKey *evt, gpointer user)
  127 {
  128     if(evt->keyval == GDK_KEY_Escape)
  129         g_cancellable_cancel(user);
  130     return TRUE;
  131 }
  132 
  133 /* 1998-09-30 - Begin a new "session" with progress reporting. */
  134 void pgs_progress_begin(MainInfo *min, const gchar *op_name, guint32 flags)
  135 {
  136     gchar       size_buf[32], buf[128];
  137     GtkWidget   *cancel, *hbox, *label;
  138 
  139     pgs_info.min = min;
  140 
  141     if(pgs_info.level == 0)
  142     {
  143         if(flags & PFLG_BUSY_MODE)
  144             flags &= PFLG_BUSY_MODE;    /* Clear any other flag. */
  145 
  146         pgs_info.flags      = flags;
  147         pgs_info.show_byte  = (flags & PFLG_BYTE_VISIBLE) ? TRUE : FALSE;
  148         pgs_info.show_item  = (flags & PFLG_ITEM_VISIBLE) ? TRUE : FALSE;
  149         pgs_info.delayed    = TRUE;
  150         pgs_info.delay_time = 250000U;
  151         pgs_info.byte_pos   = 0;
  152         pgs_info.last_secs  = 0U;
  153 
  154         if(pgs_info.cancel == NULL)
  155             pgs_info.cancel = g_cancellable_new();
  156         else
  157             g_cancellable_reset(pgs_info.cancel);
  158 
  159         if(flags & PFLG_COUNT_RECURSIVE)
  160             pgs_info.tot_num = count_recursive_selected(min, &pgs_info.byte_tot);
  161         else
  162             pgs_info.tot_num = count_toplevel_selected(min, &pgs_info.byte_tot);
  163 
  164         pgs_info.tot_pos = 0;
  165 
  166         pgs_info.dlg = win_dialog_open(min->gui->window);
  167         gtk_widget_set_size_request(pgs_info.dlg, 384, -1);
  168         pgs_info.body = gtk_label_new(op_name);
  169         g_signal_connect(G_OBJECT(pgs_info.dlg), "delete_event", G_CALLBACK(evt_delete), pgs_info.cancel);
  170         g_signal_connect(G_OBJECT(pgs_info.dlg), "key_press_event", G_CALLBACK(evt_keypress), pgs_info.cancel);
  171         gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(pgs_info.dlg))), pgs_info.body, FALSE, FALSE, 0);
  172 
  173         if(pgs_info.show_item)
  174         {
  175             pgs_info.item = gtk_label_new("");
  176             gtk_label_set_xalign(GTK_LABEL(pgs_info.item), 0.f);
  177             gtk_label_set_yalign(GTK_LABEL(pgs_info.item), 0.5f);
  178             gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(pgs_info.dlg))), pgs_info.item, FALSE, FALSE, 5);
  179             hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
  180             pgs_info.item_pgs = gtk_progress_bar_new();
  181             gtk_progress_bar_set_show_text(GTK_PROGRESS_BAR(pgs_info.item_pgs), TRUE);
  182             gtk_box_pack_start(GTK_BOX(hbox), pgs_info.item_pgs, TRUE, TRUE, 0);
  183             gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(pgs_info.item_pgs), 0.f);
  184             gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(pgs_info.dlg))), hbox, FALSE, FALSE, 0);
  185         }
  186 
  187         pgs_info.tot_pgs = gtk_progress_bar_new();
  188         hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
  189         if(flags & PFLG_BUSY_MODE)
  190         {
  191             gtk_progress_bar_set_pulse_step(GTK_PROGRESS_BAR(pgs_info.tot_pgs), 1.f / 10.f);
  192             gtk_box_pack_start(GTK_BOX(hbox), pgs_info.tot_pgs, TRUE, TRUE, 0);
  193         }
  194         else
  195         {
  196             label = gtk_label_new("0");
  197             gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 5);
  198             gtk_box_pack_start(GTK_BOX(hbox), pgs_info.tot_pgs, TRUE, TRUE, 0);
  199             g_snprintf(buf, sizeof buf, "%d", pgs_info.tot_num);
  200             label = gtk_label_new(buf);
  201             gtk_box_pack_end(GTK_BOX(hbox), label, FALSE, FALSE, 5);
  202             gtk_progress_bar_set_show_text(GTK_PROGRESS_BAR(pgs_info.tot_pgs), TRUE);
  203         }
  204         gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(pgs_info.tot_pgs), 0.f);
  205         gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(pgs_info.dlg))), hbox, FALSE, FALSE, 0);
  206 
  207         if(pgs_info.show_byte)
  208         {
  209             sze_put_offset(size_buf, sizeof size_buf, pgs_info.byte_tot, SZE_AUTO, 3, ',');
  210             g_snprintf(buf, sizeof buf, _("Total (%s)"), size_buf);
  211             label = gtk_label_new(buf);
  212             gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(pgs_info.dlg))), label, FALSE, FALSE, 0);
  213             pgs_info.byte_pgs = gtk_progress_bar_new();
  214             gtk_progress_bar_set_show_text(GTK_PROGRESS_BAR(pgs_info.byte_pgs), TRUE);
  215             gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(pgs_info.dlg))), pgs_info.byte_pgs, TRUE, TRUE, 0);
  216         }
  217         if(!(flags & PFLG_BUSY_MODE))
  218         {
  219             pgs_info.eta = gtk_label_new("");
  220             gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(pgs_info.dlg))), pgs_info.eta, FALSE, FALSE, 0);
  221         }
  222         else
  223             pgs_info.eta = NULL;
  224         cancel = gtk_button_new_with_label(_("Cancel"));
  225         g_signal_connect(G_OBJECT(cancel), "clicked", G_CALLBACK(evt_cancel_clicked), pgs_info.cancel);
  226         gtk_dialog_add_action_widget(GTK_DIALOG(pgs_info.dlg), cancel, GTK_RESPONSE_CANCEL);
  227 
  228         g_get_current_time(&pgs_info.time_begin);
  229     }
  230     else
  231         g_warning("pgs_progress_begin() doesn't nest");
  232     pgs_info.level++;
  233 }
  234 
  235 GCancellable * pgs_progress_get_cancellable(void)
  236 {
  237     return pgs_info.cancel;
  238 }
  239 
  240 /* 1998-09-30 - End a progress-reporting session. Closes down the dialog box. */
  241 void pgs_progress_end(MainInfo *min)
  242 {
  243     if(pgs_info.level == 1)
  244     {
  245         gtk_widget_destroy(pgs_info.dlg);
  246         pgs_info.dlg = NULL;
  247     }
  248     pgs_info.level--;
  249 }
  250 
  251 /* ----------------------------------------------------------------------------------------- */
  252 
  253 /* 1998-09-30 - Begin on a new "item"; typically a file, being <size> bytes. */
  254 void pgs_progress_item_begin(MainInfo *min, const gchar *name, off_t size)
  255 {
  256     if(pgs_info.flags & PFLG_BUSY_MODE)
  257         gtk_progress_bar_pulse(GTK_PROGRESS_BAR(pgs_info.tot_pgs));
  258     else
  259     {
  260         gchar buf[32];
  261         g_snprintf(buf, sizeof buf, "%u", pgs_info.tot_pos);
  262         gtk_progress_bar_set_text(GTK_PROGRESS_BAR(pgs_info.tot_pgs), buf);
  263         pgs_info.tot_pos++;
  264     }
  265     g_snprintf(pgs_info.name, sizeof pgs_info.name, "%s", name);
  266     pgs_progress_item_resize(min, size);
  267 }
  268 
  269 /* 2012-01-09 - Set a new size for the current item. This makes sense when moving. */
  270 void pgs_progress_item_resize(MainInfo *min, off_t new_size)
  271 {
  272     pgs_info.item_size = new_size;
  273 
  274     if(pgs_info.show_item)
  275     {
  276         gchar   size_buf[32], buf[FILENAME_MAX + 32];
  277 
  278         sze_put_offset(size_buf, sizeof size_buf, pgs_info.item_size, SZE_AUTO, 3, ',');
  279         g_snprintf(buf, sizeof buf, "%s (%s)", pgs_info.name, size_buf);
  280         gtk_label_set_text(GTK_LABEL(pgs_info.item), buf);
  281     }
  282     gui_events_flush();
  283 }
  284 
  285 /* 2014-03-02 - Format a bunch of seconds into a more friendly "time" format. */
  286 static void format_eta(gchar *buf, gsize buf_max, guint seconds)
  287 {
  288     const guint base[] = { 60, 60, 24, 0 };
  289     guint       field[sizeof base / sizeof *base], i, conv = seconds;
  290 
  291     for(i = 0; i < sizeof field / sizeof *field; ++i)
  292     {
  293         if(base[i])
  294         {
  295             field[i] = conv % base[i];
  296             conv /= base[i];
  297         }
  298         else
  299             field[i] = conv;
  300     }
  301 
  302     if(seconds < 60 * 60)   /* Enough with MM:SS? */
  303         g_snprintf(buf, buf_max, "%02u:%02u", field[1], field[0]);
  304     else if(seconds < 24 * 60 * 60) /* Enough with HH:MM:SS? */
  305         g_snprintf(buf, buf_max, "%02u:%02u:%02u", field[2], field[1], field[0]);
  306     else if(field[3] == 1)      /* FIXME: Perhaps there's better I18N magic to use here for day(s). */
  307         g_snprintf(buf, buf_max, _("%u day, %02u:%02u:%02u"), field[3], field[2], field[1], field[0]);
  308     else
  309         g_snprintf(buf, buf_max, _("%u days, %02u:%02u:%02u"), field[3], field[2], field[1], field[0]);
  310 }
  311 
  312 /* 1998-09-30 - Indicate progress operating on the most recently registered item. Our
  313 **      current position in the item is <pos> bytes.
  314 */
  315 PgsRes pgs_progress_item_update(MainInfo *min, off_t pos)
  316 {
  317     GTimeVal    time_now;
  318 
  319     if(pgs_info.dlg != NULL)
  320     {
  321         g_get_current_time(&time_now);
  322         if(pgs_info.delayed)
  323         {
  324             const guint micro = 1E6 * (time_now.tv_sec  - pgs_info.time_begin.tv_sec) +
  325                               (time_now.tv_usec - pgs_info.time_begin.tv_usec);
  326 
  327             if(micro >= pgs_info.delay_time)
  328                 pgs_info.delayed = FALSE;
  329         }
  330         if(!pgs_info.delayed)
  331         {
  332             if(pgs_info.eta != NULL)
  333             {
  334                 const gfloat    secs = msu_diff_timeval(&pgs_info.time_begin, &time_now);
  335                 if((guint) secs != pgs_info.last_secs)
  336                 {
  337                     gchar   buf[64], spdbuf[16], etabuf[32];
  338                     gfloat  spd;
  339                     guint   eta;
  340 
  341                     pgs_info.last_secs = secs;
  342                     spd = (pgs_info.byte_pos + pos) / secs;
  343                     eta = (pgs_info.byte_tot - (pgs_info.byte_pos + pos)) / spd;
  344                     format_eta(etabuf, sizeof etabuf, eta);
  345                     sze_put_offset(spdbuf, sizeof spdbuf, spd, SZE_AUTO, 3, ',');
  346                     g_snprintf(buf, sizeof buf, _("Elapsed %02d:%02d  Speed %s/s  ETA %s"),
  347                         pgs_info.last_secs / 60, pgs_info.last_secs % 60, spdbuf,
  348                         etabuf);
  349                     gtk_label_set_text(GTK_LABEL(pgs_info.eta), buf);
  350                 }
  351             }
  352             gtk_widget_realize(pgs_info.dlg);
  353             gdk_window_set_group(gtk_widget_get_window(pgs_info.dlg), gtk_widget_get_window(pgs_info.min->gui->window));
  354             gtk_widget_show_all(pgs_info.dlg);
  355         }
  356         if(pgs_info.show_byte && pgs_info.byte_tot)
  357         {
  358             gchar tmp[32];
  359             gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(pgs_info.byte_pgs), (gfloat) (pgs_info.byte_pos + pos) / pgs_info.byte_tot);
  360             sze_put_offset(tmp, sizeof tmp, pgs_info.byte_pos + pos, SZE_AUTO, 3, ',');
  361             gtk_progress_bar_set_text(GTK_PROGRESS_BAR(pgs_info.byte_pgs), tmp);
  362         }
  363         if(pgs_info.show_item && pgs_info.item_size)
  364         {
  365             gchar tmp[32];
  366             gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(pgs_info.item_pgs), (gfloat) pos / pgs_info.item_size);
  367             sze_put_offset(tmp, sizeof tmp, pos, SZE_AUTO, 3, ',');
  368             gtk_progress_bar_set_text(GTK_PROGRESS_BAR(pgs_info.item_pgs), tmp);
  369         }
  370         gui_events_flush();
  371         if(g_cancellable_is_cancelled(pgs_info.cancel))
  372             return PGS_CANCEL;
  373     }
  374     return PGS_PROCEED;
  375 }
  376 
  377 /* 1998-09-30 - Done with an item. */
  378 void pgs_progress_item_end(MainInfo *min)
  379 {
  380     pgs_info.byte_pos += pgs_info.item_size;
  381 
  382     gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(pgs_info.tot_pgs), (gfloat) pgs_info.tot_pos / pgs_info.tot_num);
  383     gui_events_flush();
  384 }