Data hosted with ♥ by Pastebin.com - Download Raw - See Original
  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <gtk/gtk.h>
  4. #include <gdk/gdk.h>
  5. #include <glib.h>
  6.  
  7. #define IMAGE     "josh.png"
  8. #define ANIMATION "josh.gif"
  9.  
  10. /*  Strobl's animated progressbar
  11.                                
  12.     gcc -Wall -Wextra -o josh josh.c `pkg-config --cflags --libs gtk+-3.0`
  13.     Code: Misko 2021
  14.                                  depends: gcc libgtk-3-dev (at least 3.24)
  15. */
  16.  
  17. guint threadID = 0;
  18. guint anim_threadID = 0;
  19.  
  20. typedef struct {
  21.     GtkWidget              *progress_bar;
  22.     GtkWidget              *button1;
  23.     GdkPixbufAnimation     *animation;
  24.     GdkPixbufAnimationIter *iter;
  25.     GtkWidget              *progress_image;
  26.     GtkWidget              *progress_label;
  27.     GtkStyleProvider       *progressbar_style_provider;
  28. } app_widgets;
  29.  
  30.  
  31. void destroy_handler (GtkApplication* app, gpointer data)
  32. {
  33.     (void) app;
  34.     g_application_quit(G_APPLICATION (data));
  35. }
  36.  
  37.  
  38. void
  39. stop_progress_cb (gpointer user_data)
  40. {
  41.   app_widgets *widgets = (app_widgets *) user_data;
  42.   gdouble fraction;
  43.   fraction = gtk_progress_bar_get_fraction (GTK_PROGRESS_BAR(widgets->progress_bar));
  44.   gtk_image_set_from_file(GTK_IMAGE(widgets->progress_image),
  45.                                                           IMAGE);
  46.   g_print("Strobl-ing progress: %.0f %%\n", fraction*100);
  47. }
  48.  
  49.  
  50. static gboolean
  51. fill (gpointer  user_data)
  52. {
  53.   app_widgets *widgets = (app_widgets *) user_data;
  54.   GtkAllocation *alloc = g_new(GtkAllocation, 1);
  55.   gdouble fraction;
  56.  
  57.   fraction = gtk_progress_bar_get_fraction (GTK_PROGRESS_BAR(widgets->progress_bar));
  58.  
  59.    if (fraction > 0.999) {
  60.       fraction = 0;
  61.    }
  62.  
  63.   /* Increase the bar by 1% each time this function is called */
  64.   if (fraction < 0.999)
  65.     fraction += 0.01;
  66.  
  67.   gtk_widget_get_allocation (widgets->progress_bar, alloc);
  68.  
  69.   gtk_widget_set_margin_start(widgets->progress_image,
  70.                                         alloc->width);
  71.   g_free(alloc);
  72.  
  73.   gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR(widgets->progress_bar),
  74.                                 fraction);
  75.   gchar temp[256];
  76.   memset(&temp, 0x0, 256);
  77.   if (fraction > 0.999) {
  78.      snprintf(temp, 255, "Rolled: %.0f %%", fraction*100);
  79.      gtk_button_set_label (GTK_BUTTON(widgets->button1),
  80.                                               "Roll");
  81.      threadID = 0;
  82.      anim_threadID = 0;
  83.    }
  84.    else {
  85.      snprintf(temp, 255, "Rolling: %.0f %%", fraction*100);
  86.    }
  87.   gtk_label_set_text (GTK_LABEL(widgets->progress_label),
  88.                                                    temp);
  89.   /* Ensures that the fraction stays below 1.0 */
  90.   if (fraction < 0.999)
  91.     return TRUE;
  92.  
  93.   return FALSE;
  94. }
  95.  
  96. static gboolean
  97. animate (gpointer  user_data)
  98. {
  99.   app_widgets *widgets = (app_widgets *) user_data;
  100.  
  101.   gdk_pixbuf_animation_iter_advance (widgets->iter, NULL);
  102.  
  103.   gtk_image_set_from_pixbuf(GTK_IMAGE(widgets->progress_image),
  104.                             gdk_pixbuf_animation_iter_get_pixbuf(widgets->iter));
  105.  
  106.   if (anim_threadID != 0)
  107.     return TRUE;
  108.  
  109.   return FALSE;
  110. }
  111.  
  112.  
  113. void
  114. button1_clicked_cb (GtkButton *button,
  115.                     app_widgets *widgets)
  116. {
  117.     if (threadID == 0)
  118.     {
  119.         threadID = g_timeout_add_full (0, 100, fill,
  120.                       widgets, stop_progress_cb);
  121.         gtk_button_set_label (button,
  122.                       "Pause");
  123.         widgets->iter = gdk_pixbuf_animation_get_iter (widgets->animation,
  124.                                                                     NULL);
  125.         guint delay = gdk_pixbuf_animation_iter_get_delay_time(widgets->iter);
  126.  
  127.         anim_threadID = g_timeout_add(delay, animate, widgets);
  128.     }
  129.     else
  130.     {
  131.         GSource *source = g_main_context_find_source_by_id(NULL,
  132.                                                        threadID);
  133.         GSource *anim_source = g_main_context_find_source_by_id(NULL,
  134.                                                        anim_threadID);
  135.          if (source)
  136.          {
  137.             g_source_destroy (source);
  138.          }
  139.          if (anim_source)
  140.          {
  141.             g_source_destroy (anim_source);
  142.          }
  143.          threadID = 0;
  144.          anim_threadID = 0;
  145.          gtk_button_set_label (button,
  146.                       "Roll");
  147.          animate(widgets);
  148.  
  149.          g_object_unref(widgets->iter);
  150.     }
  151. }
  152.  
  153. static void
  154. progress_bar_size_allocate (GtkWidget       *progress_bar,
  155.                               GdkRectangle    *allocation,
  156.                               gpointer         user_data)
  157. {
  158.   (void) progress_bar;
  159.   app_widgets *widgets = (app_widgets *) user_data;
  160.  
  161.   gdouble fraction;
  162.  
  163.   /*Get the current progress*/
  164.   fraction = gtk_progress_bar_get_fraction
  165.               (GTK_PROGRESS_BAR(widgets->progress_bar));
  166.   if (fraction == 0)
  167.   {
  168.      fraction = 0.01;
  169.   }
  170.   /*Set the margin of animation when the window width changes*/
  171.   gtk_widget_set_margin_start(widgets->progress_image,
  172.                                allocation->width*fraction);
  173.   if (fraction > 0.999)
  174.      gtk_widget_set_margin_start(widgets->progress_image, 1);
  175. }
  176.  
  177.  
  178. static void
  179. progress_image_size_allocate (GtkWidget   *animation,
  180.                               GdkRectangle    *allocation,
  181.                               gpointer         user_data)
  182. {
  183.   (void) animation;
  184.   app_widgets   *widgets = (app_widgets *) user_data;
  185.   GtkAllocation *progress_bar_allocation = g_new(GtkAllocation, 1);
  186.   char          *css_text;
  187.  
  188.   gtk_widget_get_allocation (widgets->progress_bar,
  189.                              progress_bar_allocation);
  190.  
  191.   progress_bar_allocation->height = allocation->height;
  192.  
  193.   css_text = g_strdup_printf ("progressbar trough,\n"
  194.                               "progressbar progress\n"
  195.                               "{\n"
  196.                               "  min-height: %dpx;\n"
  197.                               "}\n",
  198.                               allocation->height);
  199.  
  200.   gtk_css_provider_load_from_data (GTK_CSS_PROVIDER
  201.                                    (widgets->progressbar_style_provider),
  202.                                    css_text, -1, NULL);
  203.   g_free(progress_bar_allocation);
  204.   g_free (css_text);
  205. }
  206.  
  207.  
  208. static void
  209. activate (GtkApplication  *app,
  210.           app_widgets     *widgets,
  211.           gpointer        user_data)
  212. {
  213.   (void) user_data;
  214.   GtkSizeGroup       *size_group;
  215.   GtkWidget          *window;
  216.   GtkWidget          *grid;
  217.   GtkWidget          *button2;
  218.   GtkWidget          *progress_overlay;
  219.   GError              *error = NULL;
  220.   GtkWidget           *box;
  221.  
  222.   gdouble fraction = 0.0;
  223.  
  224.   window = gtk_application_window_new (app);
  225.  
  226.   gtk_window_set_title (GTK_WINDOW (window),
  227.                                "Josh Strobl's Rolling Bar");
  228.   gtk_window_set_default_size (GTK_WINDOW (window),
  229.                                450, 60);
  230.   grid = gtk_grid_new ();
  231.   gtk_grid_set_row_spacing (GTK_GRID (grid), 10);
  232.   gtk_grid_set_column_spacing (GTK_GRID (grid), 10);
  233.   gtk_grid_set_column_homogeneous (GTK_GRID (grid), TRUE);
  234.   gtk_grid_set_row_homogeneous (GTK_GRID (grid), FALSE);
  235.  
  236.   widgets->progress_bar = gtk_progress_bar_new();
  237.   gtk_progress_bar_set_inverted (GTK_PROGRESS_BAR(widgets->progress_bar),
  238.                                  FALSE);
  239.   gtk_progress_bar_set_show_text (GTK_PROGRESS_BAR(widgets->progress_bar),
  240.                                  FALSE);            
  241.   /* Fill in the given fraction of the bar.
  242.     It has to be between 0.0-1.0 inclusive */
  243.   gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (widgets->progress_bar),
  244.                                  fraction);
  245.   widgets->progress_label = gtk_label_new ("Josh is ready");
  246.  
  247.   widgets->button1 = gtk_button_new_with_label ("Roll");
  248.   button2 = gtk_button_new_with_label ("Cancel");
  249.  
  250.   progress_overlay = gtk_overlay_new ();
  251.   gtk_widget_set_hexpand (progress_overlay, TRUE);
  252.   gtk_widget_set_vexpand (progress_overlay, FALSE);
  253.   gtk_container_add (GTK_CONTAINER (progress_overlay),
  254.                      widgets->progress_bar);
  255.   widgets->animation = gdk_pixbuf_animation_new_from_file(ANIMATION, &error);
  256.   if (error) {
  257.       g_warning("No image found\n*ERROR %s\n", error->message);
  258.       destroy_handler(NULL, app);
  259.   }
  260.    gtk_window_set_icon (GTK_WINDOW(window),
  261.                         gdk_pixbuf_new_from_file(IMAGE, NULL));
  262.   widgets->progress_image = gtk_image_new_from_file (IMAGE);
  263.   gtk_widget_set_vexpand(widgets->progress_bar, FALSE);
  264.   gtk_widget_set_name (widgets->progress_image,
  265.                          "progress-image");
  266.   /*create a box container for the image*/
  267.   box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
  268.   gtk_box_pack_start (GTK_BOX(box), widgets->progress_image,
  269.                       FALSE, FALSE, 2);
  270.   gtk_widget_set_halign (widgets->progress_image,
  271.                         GTK_ALIGN_START);
  272.   gtk_overlay_add_overlay (GTK_OVERLAY (progress_overlay),
  273.                            box);
  274.   gtk_overlay_set_overlay_pass_through (GTK_OVERLAY (progress_overlay),
  275.                            box, TRUE);
  276.   size_group = gtk_size_group_new (GTK_SIZE_GROUP_VERTICAL);
  277.   gtk_size_group_add_widget (size_group, widgets->progress_bar);
  278.   gtk_size_group_add_widget (size_group, box);
  279.  
  280.   widgets->progressbar_style_provider = GTK_STYLE_PROVIDER (gtk_css_provider_new ());
  281.   gtk_style_context_add_provider (gtk_widget_get_style_context (widgets->progress_bar),
  282.                                   widgets->progressbar_style_provider,
  283.                                   GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
  284.  
  285.   gtk_grid_attach (GTK_GRID (grid), progress_overlay, 0, 0, 4, 1);
  286.   gtk_grid_attach (GTK_GRID (grid), widgets->progress_label, 0, 1, 2, 1);
  287.   gtk_grid_attach (GTK_GRID (grid), widgets->button1, 2, 1, 1, 1);
  288.   gtk_grid_attach_next_to (GTK_GRID (grid), button2, widgets->button1,
  289.                            GTK_POS_RIGHT, 1, 1);
  290.   gtk_container_add (GTK_CONTAINER (window), grid);
  291.   gtk_container_set_border_width(GTK_CONTAINER(grid),12);
  292.   gtk_container_set_border_width(GTK_CONTAINER(window),5);
  293.  
  294.   g_signal_connect (widgets->progress_image, "size-allocate",
  295.                     G_CALLBACK (progress_image_size_allocate),
  296.                      widgets);
  297.   g_signal_connect (widgets->progress_bar, "size-allocate",
  298.                     G_CALLBACK (progress_bar_size_allocate),
  299.                      widgets);
  300.   g_signal_connect (widgets->button1, "clicked",
  301.                     G_CALLBACK (button1_clicked_cb), widgets);
  302.   g_signal_connect (button2, "clicked",
  303.                     G_CALLBACK (destroy_handler), app);
  304.   g_signal_connect (G_OBJECT(window), "destroy",
  305.                     G_CALLBACK (destroy_handler), app);
  306.   gtk_widget_show_all (window);
  307.  
  308. }
  309.  
  310.  
  311. int
  312. main (int argc, char **argv)
  313. {
  314.   GtkApplication *app;
  315.   int status;
  316.  
  317.   app = gtk_application_new ("org.gtk.josh_rollbar", G_APPLICATION_FLAGS_NONE);
  318.   app_widgets *widgets = g_slice_new(app_widgets);
  319.   g_signal_connect (app, "activate", G_CALLBACK (activate), widgets);
  320.   status = g_application_run (G_APPLICATION (app), argc, argv);
  321.   g_slice_free(app_widgets, widgets);
  322.   g_object_unref (app);
  323.  
  324.   return status;
  325. }
  326.