Page 1 of 1

gtkdialog embedded progressbar

Posted: Sat Oct 31, 2020 2:11 am
by BarryK
Is there a special thread for gtkdialog, like "gtkdialog tips" that zigbert created in the Murga Forum?

Can't see one in this forum, so posting here.

The official documentation shows <progressbar> being used in a popup window. I searched and found some code posted for having it embedded in the main GUI, but my experience was that it did not behave properly, like starting to play even when it was hidden at first startup of the GUI. Then I had trouble getting it to replay properly.

It seems that <progressbar> is really only designed for use in a popup window. Or, has someone got it running properly embedded?

Anyway, I thought why not just use a one-shot animated SVG or GIF progress bar? Turned out to be real easy and simple to put an animated GIF into the gtkdialog XML, and to start it playing, and show or hide, whenever required.

Posted a how-to, right from the first steps using mtPaint:

https://bkhome.org/news/202010/how-to-c ... d-gui.html

Thought that I would put it out there, in case anyone finds it useful.

Re: gtkdialog embedded progressbar

Posted: Sat Oct 31, 2020 7:22 am
by BarryK
An extra note about the above.

SVG would probably be better. It might not be known by everybody, but SVG has had animation capability right from the beginning.

The GIF I created has a fixed 40 sec duration, but with SVG the duration could be changed at runtime. Also it could be much smoother playback.

It should be simple to create a rectangle, solid-filled, that grows linearly with time? Whatever SVG coding I did was back around year 2000 and I can't remember any of it.

Re: gtkdialog embedded progressbar

Posted: Tue Dec 15, 2020 8:33 am
by Eastler_Dart

did you see the (old) examples from 01micko ?
https://github.com/01micko/gtkdialog/tr ... rogressbar

maybe it helps :-)

[edit: add a second link]
and another example, using gtkdialog in another way.
If you correct first line #! /usr/bin/gtkdialog -e
to #! /usr/sbin/gtkdialog -e (because my upup-ef has gtkdialog in /usr/sbin
it works:
http://xpt.sourceforge.net/techdocs/lan ... 01s20.html


Re: gtkdialog embedded progressbar

Posted: Sat Dec 26, 2020 11:52 am
by misko_2083

BarryK a while ago I think someone asked how to start a progressbar on a button press.
There it Is.
http://www.murga-linux.com/puppy/viewto ... 969#956035
The progressbar data Is populated using the named pipes.


Re: gtkdialog embedded progressbar

Posted: Mon Feb 01, 2021 4:16 am
by MochiMoppel
BarryK wrote: Sat Oct 31, 2020 7:22 am

SVG would probably be better. It might not be known by everybody, but SVG has had animation capability right from the beginning.

AFAIK not possible with a stand-alone SVG. You can animate SVGs in a browser supporting the SMIL specification or JavaScript but not as an icon in a dialog

misko_2083 wrote: Sat Dec 26, 2020 11:52 am

BarryK a while ago I think someone asked how to start a progressbar on a button press.
There it Is.
http://www.murga-linux.com/puppy/viewto ... 969#956035
The progressbar data Is populated using the named pipes.

Interesting concept. I can't get your linked example to work because I don't have strace . It also appears to be quite dangerous and not suitable as a demo.

After much trial and error I created a demo with elements of your script and a gtkdialog documentation example:

Code: Select all

#!/bin/bash
export pipe="/tmp/progbartest" 
[[ -p $pipe ]] || mkfifo $pipe 
exec 9<> $pipe

trap "rm -f $pipe" EXIT

progress() {
	for i in $(seq 0 10 100); do 
		echo -e "$i\nProgress: $i%"
		sleep 0.3 
	done;
	sleep 1 
	echo  $'0\n '
}; export -f progress

export MAIN_DIALOG='
<window>
	<vbox>
		<text>
			<label>Some text describing what is happening.</label>
		</text>
		<progressbar>
			<label>" "</label>
			<input>cat $pipe</input> 
		</progressbar>
		<hbox>
			<button>
				<label>Start action</label>
				<action>progress > $pipe &</action>
			</button>
			<button cancel></button>
		</hbox>
	</vbox>
</window>
'
gtkdialog --program=MAIN_DIALOG

The good news: It works.
The bad news: Only once. Pushing the 'Start action' button a second time does not call the progress function anymore. What's going on here? When I open a console window and type cat /tmp/progbartest the cat command is listening to the pipe and pushing the 'Start action' button will cause the console to output what the functions writes to the pipe. How can I make the progressbar to read this output? Why did it work in the first instance and not in a second?

EDIT Problem is solved. Inserted exec 9<> $pipe fix provided by JakeSFR


Re: gtkdialog embedded progressbar

Posted: Mon Feb 01, 2021 8:07 pm
by Eastler_Dart

my thoughts:

Code: Select all

   		<progressbar>
			<label>" "</label>
			<input>cat $pipe</input> 
		</progressbar>

I think, this woud be done first time. After that, the position 'cat $pipe' holds the first result as static value.

Give to the <progressbar> a Variable,

Code: Select all

   		<progressbar>
			<label>" "</label>
                        <variable>MyProgressBar</variable> <----------------
			<input>cat $pipe</input> 
		</progressbar>

Then try to update/refresh the variable

Code: Select all

   		<progressbar>
			<label>" "</label>
                        <variable>MyProgressBar</variable>
			<input>cat $pipe</input> 
                        <action>refresh:MyProgressBar</action>  <-----------
		</progressbar>

If that doesn't help, try to give <progressbar> a InputFile instead of Input (close <input file> with a simple </input>),
in that case, <action>refresh:[Varname]</action> should do the same, as your 'cat',
with luck it will do it every time

Code: Select all

   		<progressbar>
			<label>" "</label>
                        <variable>MyProgressBar</variable>
			<input file>/tmp/progbartest</input>  <----------------
                        <action>refresh:MyProgressBar</action>
		</progressbar>

If that also not works, keep it, and give the Button also the refresh-Command:

Code: Select all

                <hbox>
			<button>
				<label>Start action</label>
				<action>progress > $pipe &</action>
                                <action>refresh:MyProgressBar</action>  <--------------
			</button>
			<button cancel></button>
		</hbox>

But Sorry, I havn't the time to write and test my thoughts as a real functional script.

Hope it helps


Re: gtkdialog embedded progressbar

Posted: Tue Feb 02, 2021 2:08 am
by MochiMoppel
Eastler_Dart wrote:

Hope it helps

It doesn't, but thanks anyway for trying to help.


Re: gtkdialog embedded progressbar

Posted: Tue Feb 02, 2021 11:31 am
by JakeSFR
MochiMoppel wrote:

The good news: It works.
The bad news: Only once. Pushing the 'Start action' button a second time does not call the progress function anymore. What's going on here?

Once the first pass is done, cat in <input>cat $pipe</input> just disconnects from the pipe.
You could, for example, put that cat in an infinite loop, or even better keep the pipe open with:

Code: Select all

exec 9<> $pipe

right after creating it.

Greetings!


Re: gtkdialog embedded progressbar

Posted: Wed Feb 03, 2021 2:41 am
by MochiMoppel

@JakeSFR Great, thanks, this does the trick.


Re: gtkdialog embedded progressbar

Posted: Wed Feb 03, 2021 5:55 am
by step

alternatively tail -f $pipe ?


Re: gtkdialog embedded progressbar

Posted: Thu Feb 04, 2021 2:54 am
by MochiMoppel
step wrote:

alternatively tail -f $pipe ?

tail seems not to work.


Re: gtkdialog embedded progressbar

Posted: Thu Feb 04, 2021 8:33 pm
by step

You're right, It needed a bit of cajoling

Code: Select all

<input>stdbuf -oL tail -n+1 --pid '$$' -f $pipe</input>

stdbuf -oL to output a line as soon as it is read
-n+1 to start outputting immediately(*)
--pid '$$' to exit when the script exits**)

(*) without -n+1 tail -f does work but only the second time you press the button
(**) single quote assuming that the gtkdialog is itself within single quotes

GNU-flavored tail and stdbuf


Re: gtkdialog embedded progressbar

Posted: Fri Feb 05, 2021 8:25 am
by MochiMoppel
step wrote:

You're right, It needed a bit of cajoling

It still does:

Code: Select all

stdbuf: failed to find ‘libstdbuf.so’

I think I'll keep the cat. You can have the tail :lol:


Re: gtkdialog embedded progressbar

Posted: Fri Feb 05, 2021 8:37 am
by step
MochiMoppel wrote: Fri Feb 05, 2021 8:25 am
step wrote:

You're right, It needed a bit of cajoling

It still does:

Code: Select all

stdbuf: failed to find ‘libstdbuf.so’

I think I'll keep the cat. You can have the tail :lol:

I'll keep the tail alright :lol:. Too bad your system is missing a required library file (or else stdbuf shouldn't be installed at all).


Re: gtkdialog embedded progressbar

Posted: Sun Feb 07, 2021 12:55 am
by BarryK
MochiMoppel wrote: Mon Feb 01, 2021 4:16 am
BarryK wrote: Sat Oct 31, 2020 7:22 am

SVG would probably be better. It might not be known by everybody, but SVG has had animation capability right from the beginning.

AFAIK not possible with a stand-alone SVG. You can animate SVGs in a browser supporting the SMIL specification or JavaScript but not as an icon in a dialog

Ah, I see. I was remembering the <animate> tag from the distant past. This page has a simple example:

https://developer.mozilla.org/en-US/doc ... nt/animate

And yeah, animates in a browser, but gtkdialog will just render it without the animation.


Re: gtkdialog embedded progressbar

Posted: Mon Feb 08, 2021 3:09 am
by MochiMoppel
step wrote:

Too bad your system is missing a required library file (or else stdbuf shouldn't be installed at all).

Just copied it from the coreutils-8.24 collection. That's how far I'm willing to go to test stuff that I don't need :)

@BarryK A GIF may be the better option if all you need is a growing bar. However such bar would not reflect the amount of progress made like a genuine progress bar.

Maybe something useful can be achieved without a progressbar widget and without a tricky pipe. The following example uses just pango text, which can be sized and colored in any way. I find it less obstrusive than a progressbar.

Screenshot.gif
Screenshot.gif (5.81 KiB) Viewed 1440 times

Code: Select all

#!/bin/bash
export pbtmp=/tmp/progbartest
> $pbtmp 
trap "rm -f $pbtmp" EXIT

progress() {
	PBAR_CHAR='\xe2\x80\x81'	#Unicode U+2001 (EM QUAD, a wide space character)
	for i in $(seq 0 10 100); do
		printf -vP "%.s$PBAR_CHAR" $(seq $i)
		printf -vR "%.s$PBAR_CHAR" $(seq $((100-i)))
		echo -n "<span font='2' bgcolor='red'>$P</span><span font='2' bgcolor='gray'>$R</span>" > $pbtmp
		sleep .6 
	done;
	sleep 1 
	> $pbtmp
}; export -f progress

export MAIN_DIALOG='
<window width-request="350">
<vbox>
	<hbox height-request="10" homogeneous="true">
		<text use-markup="true" file-monitor="true">
			<variable>vPBAR</variable>
			<input file>'$pbtmp'</input>
			<action signal="file-changed">refresh:vPBAR</action>
		</text>
	</hbox>
	<text>
		<label>Some text describing what is happening.</label>
	</text>
	<hbox>
		<button>
			<label>Start action</label>
			<action>progress &</action>
		</button>
		<button cancel></button>
	</hbox>
</vbox>
</window>
'
gtkdialog --program=MAIN_DIALOG

Re: gtkdialog embedded progressbar

Posted: Fri Feb 26, 2021 4:02 pm
by misko_2083

MochiMopel, I've tried to make it work
The trick seems to be to keep the loop running in the input.

Code: Select all

#!/bin/bash
export pipe="/tmp/progbartest" 
[[ -p $pipe ]] || mkfifo $pipe 

trap "rm -f $pipe" INT TERM EXIT

progress() {
	for i in $(seq 0 10 100); do 
		[[ -p $pipe ]] || exit
		[[ "${i}" -eq 100 ]] && echo 100
		echo -e "${i}\nProgress: ${i}%"
		sleep 0.3 
	done;
	sleep 1
}; export -f progress

export MAIN_DIALOG='
<window>
	<vbox>
		<text>
			<label>Some text describing what is happening.</label>
		</text>
		<progressbar>
			<label>Ready</label>
			<input>while cat $pipe 2>/dev/null;do :; done</input>
		</progressbar>
		<hbox>
			<button>
				<label>Start action</label>
				<action>progress > $pipe &</action>
			</button>
			<button cancel>
			</button>
		</hbox>
	</vbox>
</window>
'

gtkdialog --program=MAIN_DIALOG

This works for me but the progress is messed if the start button is pressed several times.

Sort of a quick workaround. :lol:
Starts the progress when the temp file is not empty.

Code: Select all

#!/bin/bash
export pipe="/tmp/progbartest" 
[[ -f $pipe ]] || touch $pipe

trap "rm -f $pipe" INT TERM EXIT

progress() {
	for i in $(seq 0 10 100); do 
		[[ -f $pipe ]] || exit
		[[ "${i}" -eq 100 ]] && echo 100
		echo -e "${i}\nProgress: ${i}%"
		sleep 0.3 
	done;
	>$pipe
	sleep 1
}; export -f progress

input() {
	while [[ -f $pipe ]]; do
		[[ -s $pipe ]] && progress
	done
}; export -f input

export MAIN_DIALOG='
<window>
	<vbox>
		<text>
			<label>Some text describing what is happening.</label>
		</text>
		<progressbar>
			<label>Ready</label>
			<input>input</input>
		</progressbar>
		<hbox>
			<button>
				<label>Start action</label>
				<action>echo "GO" > $pipe &</action>
			</button>
			<button cancel>
			</button>
		</hbox>
	</vbox>
</window>
'

gtkdialog --program=MAIN_DIALOG

rm -f $pipe
exit 0

The flaw is it would kill the input loop if the temp file is removed while the script is running.
But it runs fine.


Re: gtkdialog embedded progressbar

Posted: Sat Feb 27, 2021 3:14 am
by MochiMoppel
misko_2083 wrote:

MochiMopel, I've tried to make it work

It works already ;) . You must have missed JakeSFR's post.


Re: gtkdialog embedded progressbar

Posted: Thu Mar 18, 2021 1:17 pm
by misko_2083

Gtkdialog can't do this :D
Image
I used one user's profile picture and used this website to animate it.
Option 1 Image
Option 2 Image
The website leaves the watermark on gifs, but this one is too small to fit. (Or too small to notice, ha, ha)
Gtk3 dropped the text inside the progress so it takes some CSS styling inside the app.
It takes some coding to position it in front of the running progress bar and when the window size changes.
Maybe I can make it play "Meep meep meep meeep" sound. :D


Re: gtkdialog embedded progressbar

Posted: Fri Aug 20, 2021 1:12 pm
by misko_2083

OK here's the code and images I used to make a joke app (cough, cough, troll) in other thread:
Image
I wonder how to make some simple sound effects play pause with this without doing some low level programming.

Code: Select all

#include <stdio.h>
#include <string.h>
#include <gtk/gtk.h>
#include <gdk/gdk.h>
#include <glib.h>

#define IMAGE     "puppy.png"
#define ANIMATION "puppy.gif"

/* Puppy animated progressbar

    Compiles with:                           
    gcc -Wall -Wextra -o proppy proppy.c `pkg-config --cflags --libs gtk+-3.0`
    Code: Misko 2021
                                 filename: proppy.c
                                 depends: gcc libgtk-3-dev (version 3.24 from debian 10 buster)
*/

guint threadID = 0;
guint anim_threadID = 0;

typedef struct {
    GtkWidget              *progress_bar;
    GtkWidget              *button1;
    GdkPixbufAnimation     *animation;
    GdkPixbufAnimationIter *iter;
    GtkWidget              *progress_image;
    GtkWidget              *progress_label;
    GtkStyleProvider       *progressbar_style_provider;
} app_widgets;


void destroy_handler (GtkApplication* app, gpointer data)
{
    (void) app;
    g_application_quit(G_APPLICATION (data));
}


void
stop_progress_cb (gpointer user_data)
{
  app_widgets *widgets = (app_widgets *) user_data;
  gdouble fraction;
  fraction = gtk_progress_bar_get_fraction (GTK_PROGRESS_BAR(widgets->progress_bar));
  gtk_image_set_from_file(GTK_IMAGE(widgets->progress_image),
                                                          IMAGE);
  g_print("whining progress: %.0f %%\n", fraction*100);
}


static gboolean
fill (gpointer  user_data)
{
  app_widgets *widgets = (app_widgets *) user_data;
  GtkAllocation *alloc = g_new(GtkAllocation, 1);
  gdouble fraction;

  fraction = gtk_progress_bar_get_fraction (GTK_PROGRESS_BAR(widgets->progress_bar));

   if (fraction > 0.999) {
      fraction = 0;
   }

  /* Increase the bar by 1% each time this function is called */
  if (fraction < 0.999)
    fraction += 0.01;

  gtk_widget_get_allocation (widgets->progress_bar, alloc);
  
  gtk_widget_set_margin_start(widgets->progress_image,
                                        alloc->width);
  g_free(alloc);

  gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR(widgets->progress_bar),
                                fraction);
  gchar temp[256];
  memset(&temp, 0x0, 256);
  if (fraction > 0.999) {
     snprintf(temp, 255, "Whined: %.0f %%", fraction*100);
     gtk_button_set_label (GTK_BUTTON(widgets->button1),
                                              "Whine");
     threadID = 0;
     anim_threadID = 0;
   }
   else {
     snprintf(temp, 255, "Whining: %.0f %%", fraction*100);
   }
  gtk_label_set_text (GTK_LABEL(widgets->progress_label),
                                                   temp);
  /* Ensures that the fraction stays below 1.0 */
  if (fraction < 0.999)
    return TRUE;

  return FALSE;
}

static gboolean
animate (gpointer  user_data)
{
  app_widgets *widgets = (app_widgets *) user_data;

  gdk_pixbuf_animation_iter_advance (widgets->iter, NULL);

  gtk_image_set_from_pixbuf(GTK_IMAGE(widgets->progress_image),
                            gdk_pixbuf_animation_iter_get_pixbuf(widgets->iter));

  if (anim_threadID != 0)
    return TRUE;
  
  return FALSE;
}


void
button1_clicked_cb (GtkButton *button,
                    app_widgets *widgets)
{
    if (threadID == 0)
    {
        threadID = g_timeout_add_full (0, 100, fill,
                      widgets, stop_progress_cb);
        gtk_button_set_label (button,
                      "Pause");
        widgets->iter = gdk_pixbuf_animation_get_iter (widgets->animation,
                                                                    NULL);
        guint64 delay = gdk_pixbuf_animation_iter_get_delay_time(widgets->iter);

        anim_threadID = g_timeout_add(delay, animate, widgets);
    }
    else
    {
        GSource *source = g_main_context_find_source_by_id(NULL,
                                                       threadID);
        GSource *anim_source = g_main_context_find_source_by_id(NULL,
                                                       anim_threadID);
         if (source)
         {
            g_source_destroy (source);
         }
         if (anim_source)
         {
            g_source_destroy (anim_source);
         }
         threadID = 0;
         anim_threadID = 0;
         gtk_button_set_label (button,
                      "Whine");
         animate(widgets);

         g_object_unref(widgets->iter);
    }
}

static void
progress_bar_size_allocate (GtkWidget       *progress_bar,
                              GdkRectangle    *allocation,
                              gpointer         user_data)
{
  (void) progress_bar;
  app_widgets *widgets = (app_widgets *) user_data;

  gdouble fraction;
  
  /*Get the current progress*/
  fraction = gtk_progress_bar_get_fraction
              (GTK_PROGRESS_BAR(widgets->progress_bar));
  if (fraction == 0)
  { 
     fraction = 0.01;
  }
  /*Set the margin of animation when the window width changes*/
  gtk_widget_set_margin_start(widgets->progress_image,
                               allocation->width*fraction);
  if (fraction > 0.999)
     gtk_widget_set_margin_start(widgets->progress_image, 1);
}


static void
progress_image_size_allocate (GtkWidget   *animation,
                              GdkRectangle    *allocation,
                              gpointer         user_data)
{
  (void) animation;
  app_widgets   *widgets = (app_widgets *) user_data;
  GtkAllocation *progress_bar_allocation = g_new(GtkAllocation, 1);
  char          *css_text;

  gtk_widget_get_allocation (widgets->progress_bar,
                             progress_bar_allocation);

  progress_bar_allocation->height = allocation->height;

  css_text = g_strdup_printf ("progressbar trough,\n"
                              "progressbar progress\n"
                              "{\n"
                              "  min-height: %dpx;\n"
                              "}\n",
                              allocation->height);

  gtk_css_provider_load_from_data (GTK_CSS_PROVIDER
                                   (widgets->progressbar_style_provider),
                                   css_text, -1, NULL);
  g_free(progress_bar_allocation);
  g_free (css_text);
}


static void
activate (GtkApplication  *app,
          app_widgets     *widgets,
          gpointer        user_data)
{
  (void) user_data;
  GtkSizeGroup       *size_group;
  GtkWidget          *window;
  GtkWidget          *grid;
  GtkWidget          *button2;
  GtkWidget          *progress_overlay;
  GError              *error = NULL;
  GtkWidget           *box;

  gdouble fraction = 0.0;

  window = gtk_application_window_new (app);

  gtk_window_set_title (GTK_WINDOW (window),
                               "Puppy Progress Bar");
  gtk_window_set_default_size (GTK_WINDOW (window),
                               420, 60);
  grid = gtk_grid_new ();
  gtk_grid_set_row_spacing (GTK_GRID (grid), 10);
  gtk_grid_set_column_spacing (GTK_GRID (grid), 10);
  gtk_grid_set_column_homogeneous (GTK_GRID (grid), TRUE);
  gtk_grid_set_row_homogeneous (GTK_GRID (grid), FALSE);

  widgets->progress_bar = gtk_progress_bar_new();
  gtk_progress_bar_set_inverted (GTK_PROGRESS_BAR(widgets->progress_bar),
                                 FALSE);
  gtk_progress_bar_set_show_text (GTK_PROGRESS_BAR(widgets->progress_bar),
                                 FALSE);            
  /* Fill in the given fraction of the bar.
    It has to be between 0.0-1.0 inclusive */
  gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (widgets->progress_bar),
                                 fraction);
  widgets->progress_label = gtk_label_new ("Puppy is ready");

  widgets->button1 = gtk_button_new_with_label ("Whine");
  button2 = gtk_button_new_with_label ("Cancel");

  progress_overlay = gtk_overlay_new ();
  gtk_widget_set_hexpand (progress_overlay, TRUE);
  gtk_widget_set_vexpand (progress_overlay, FALSE);
  gtk_container_add (GTK_CONTAINER (progress_overlay),
                     widgets->progress_bar);
  widgets->animation = gdk_pixbuf_animation_new_from_file(ANIMATION, &error);
  if (error) {
      g_warning("No image found\n*ERROR %s\n", error->message);
      destroy_handler(NULL, app);
  }
   gtk_window_set_icon (GTK_WINDOW(window),
                        gdk_pixbuf_new_from_file(IMAGE, NULL));
  widgets->progress_image = gtk_image_new_from_file (IMAGE);
  gtk_widget_set_vexpand(widgets->progress_bar, FALSE);
  gtk_widget_set_name (widgets->progress_image,
                         "progress-image");
  /*create a box container for the image*/
  box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
  gtk_box_pack_start (GTK_BOX(box), widgets->progress_image,
                      FALSE, FALSE, 2); 
  gtk_widget_set_halign (widgets->progress_image,
                        GTK_ALIGN_START);
  gtk_overlay_add_overlay (GTK_OVERLAY (progress_overlay),
                           box);
  gtk_overlay_set_overlay_pass_through (GTK_OVERLAY (progress_overlay),
                           box, TRUE);
  size_group = gtk_size_group_new (GTK_SIZE_GROUP_VERTICAL);
  gtk_size_group_add_widget (size_group, widgets->progress_bar);
  gtk_size_group_add_widget (size_group, box);

  widgets->progressbar_style_provider = GTK_STYLE_PROVIDER (gtk_css_provider_new ());
  gtk_style_context_add_provider (gtk_widget_get_style_context (widgets->progress_bar),
                                  widgets->progressbar_style_provider,
                                  GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);

  gtk_grid_attach (GTK_GRID (grid), progress_overlay, 0, 0, 4, 1);
  gtk_grid_attach (GTK_GRID (grid), widgets->progress_label, 0, 1, 2, 1);
  gtk_grid_attach (GTK_GRID (grid), widgets->button1, 2, 1, 1, 1);
  gtk_grid_attach_next_to (GTK_GRID (grid), button2, widgets->button1,
                           GTK_POS_RIGHT, 1, 1);
  gtk_container_add (GTK_CONTAINER (window), grid);
  gtk_container_set_border_width(GTK_CONTAINER(grid),12);
  gtk_container_set_border_width(GTK_CONTAINER(window),5);

  g_signal_connect (widgets->progress_image, "size-allocate",
                    G_CALLBACK (progress_image_size_allocate),
                     widgets);
  g_signal_connect (widgets->progress_bar, "size-allocate",
                    G_CALLBACK (progress_bar_size_allocate),
                     widgets);
  g_signal_connect (widgets->button1, "clicked",
                    G_CALLBACK (button1_clicked_cb), widgets);
  g_signal_connect (button2, "clicked",
                    G_CALLBACK (destroy_handler), app);
  g_signal_connect (G_OBJECT(window), "destroy",
                    G_CALLBACK (destroy_handler), app);
  gtk_widget_show_all (window);

}

int
main (int argc, char **argv)
{
  GtkApplication *app;
  int status;

  app = gtk_application_new ("org.gtk.puppy_bar", G_APPLICATION_FLAGS_NONE);
  app_widgets *widgets = g_slice_new(app_widgets);
  g_signal_connect (app, "activate", G_CALLBACK (activate), widgets);
  status = g_application_run (G_APPLICATION (app), argc, argv);
  g_slice_free(app_widgets, widgets);
  g_object_unref (app);

  return status;
}

It's going to need these images in the same folder as well: