Logo Search packages:      
Sourcecode: vertex version File versions

progressdialog.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <sys/types.h>
#include <gtk/gtk.h>
#include <gdk/gdkkeysyms.h>

#include "guiutils.h"
#include "progressdialog.h"



/*
 *    Animated icon structure
 */
typedef struct {

      GdkPixmap *pixmap;
      GdkBitmap *mask;
      gint width, height;

} icon_struct;

/* Progress dialog structure. */
typedef struct {

      gbool initialized;
      gbool map_state;
      GdkVisibilityState visibility;
      gint stop_count;
        GtkWidget *transient_for;   /* Transient for widget. */

      GtkAccelGroup *accelgrp;

      GtkWidget   *toplevel,
                  *main_vbox,
                  *icon_vbox, /* Holds icon fixed and pixmap widgets. */
                  *icon_fixed,      /* For single icon mode. */
                  *icon_pm,
                  *label,
                  *progress_bar,
                  *stop_btn,
                  *stop_btn_label;

      /* Members for animated progress display. */
      GdkGC *animation_gc;
      GtkWidget *animation_da;
      GdkPixmap *animation_buffer;
      guint16 animation_position, animation_increment;
      glong animation_time_last, animation_interval;  /* In ms. */
      icon_struct **start_icon;
      gint total_start_icons;
        icon_struct **icon;
        gint total_icons;
        icon_struct **end_icon;
        gint total_end_icons;


} progress_dialog_struct;
static progress_dialog_struct progress_dialog;


/* Callbacks. */
static void ProgressDialogStopCB(GtkWidget *w, gpointer data);
static void ProgressDialogDestroyCB(GtkObject *object, gpointer data);
static gint ProgressDialogCloseCB(
        GtkWidget *widget, GdkEvent *event, gpointer data
);
static gint ProgressDialogVisibilityCB(
        GtkWidget *widget, GdkEventVisibility *visibility, gpointer data
);
static gint ProgressDialogAnimationDrawCB(
      GtkWidget *widget, GdkEventExpose *expose, gpointer data
);

/* Utilities. */
static glong ProgressDialogCurrentTime(void);
static void ProgressDialogChangeIcon(
      progress_dialog_struct *pd, const u_int8_t **icon_data
);
static icon_struct *ProgressDialogIconNew(
      progress_dialog_struct *pd, const u_int8_t **icon_data
);
static void ProgressDialogIconDelete(
      progress_dialog_struct *pd, icon_struct *icon
);
static void ProgressDialogIconDeleteAll(
        progress_dialog_struct *pd
);

/* Front ends. */
gint ProgressDialogInit(void);
void ProgressDialogSetTransientFor(GtkWidget *w);
void ProgressDialogSetWMIconData(const u_int8_t **icon_data);
gbool ProgressDialogIsQuery(void);
void ProgressDialogBreakQuery(gbool allow_gtk_iteration);
gint ProgressDialogStopCount(void);
void ProgressDialogMap(
        const gchar *title,
        const gchar *label,
        const u_int8_t **icon_data,
        const gchar *stop_btn_label
);
void ProgressDialogMapAnimation(
        const gchar *title,
        const gchar *label,
        const gchar *stop_btn_label,
      u_int8_t ***start_icon_data, gint total_start_icon_datas,
      u_int8_t ***icon_data, gint total_icon_datas,
      u_int8_t ***end_icon_data, gint total_end_icon_datas,
        glong animation_interval, guint16 animation_increment
);
void ProgressDialogUpdate(
      const gchar *title,
      const gchar *label,
      const u_int8_t **icon_data,
      const gchar *stop_btn_label,
      gdouble position,       /* 0.0 to 1.0. */
        guint nblocks,              /* 0 for continuous. */
      gbool allow_gtk_iteration
);
void ProgressDialogUpdateUnknown(
        const gchar *title,
        const gchar *label,
        const u_int8_t **icon_data,
        const gchar *stop_btn_label,
        gbool allow_gtk_iteration
);
void ProgressDialogUnmap(void);
void ProgressDialogShutdown(void);


#define PROGRESS_DIALOG_WIDTH       380
#define PROGRESS_DIALOG_HEIGHT            -1

#define PROGRESS_DIALOG_ANIMATION_DA_WIDTH      270
#define PROGRESS_DIALOG_ANIMATION_DA_HEIGHT     45

#define PROGRESS_DIALOG_BTN_WIDTH   (100 + (2 * 3))
#define PROGRESS_DIALOG_BTN_HEIGHT  (30 + (2 * 3))


/* #define PROGRESS_DIALOG_PROGRESS_HEIGHT      (20 + (2 * 2)) */
#define PROGRESS_DIALOG_PROGRESS_HEIGHT         20


#define MAX(a,b)        (((a) > (b)) ? (a) : (b))
#define MIN(a,b)        (((a) < (b)) ? (a) : (b))
#define CLIP(a,l,h)     (MIN(MAX((a),(l)),(h)))


/*
 *    Stop button callback.
 */
static void ProgressDialogStopCB(GtkWidget *w, gpointer data)
{
      progress_dialog_struct *pd = (progress_dialog_struct *)data;
      if(pd == NULL)
          return;

      if(pd->stop_count < 0)
          pd->stop_count = 0;

      pd->stop_count++;

      /* Give up on the fifth press? */
      if(pd->stop_count >= 5)
          ProgressDialogUnmap();
}

/*
 *    Destroy callback.
 */
static void ProgressDialogDestroyCB(GtkObject *object, gpointer data)
{
      return;
}

/*
 *    Close callback.
 */
static gint ProgressDialogCloseCB(
      GtkWidget *widget, GdkEvent *event, gpointer data
)
{
      ProgressDialogStopCB(widget, data);

      return(TRUE);
}

/*
 *    Toplevel "visibility_notify_event" signal callback.
 */
static gint ProgressDialogVisibilityCB(
        GtkWidget *widget, GdkEventVisibility *visibility, gpointer data
)
{
      progress_dialog_struct *pd = (progress_dialog_struct *)data;
      if((visibility == NULL) || (pd == NULL))
          return(FALSE);

      pd->visibility = visibility->state;

      return(TRUE);
}

/*
 *    Animation redraw and "expose_event" signal callback.
 */
static gint ProgressDialogAnimationDrawCB(
        GtkWidget *widget, GdkEventExpose *expose, gpointer data
)
{
      gint state, width, height;
      gint start_icon_width = 0, end_icon_width = 0;
      gint frame, total_frames;
      gint anim_per_frame;
      GdkGC *animation_gc;
      GdkColormap *colormap;
      GdkWindow *window;
      GdkPixmap *pixmap, *bg_pixmap;
      GtkStyle *style;
      GtkWidget *w;
      progress_dialog_struct *pd = (progress_dialog_struct *)data;
        if(pd == NULL)
            return(TRUE);


      w = pd->animation_da;
      if((w == NULL) || (pd->visibility == GDK_VISIBILITY_FULLY_OBSCURED) ||
         !pd->map_state
      )
          return(TRUE);

      window = w->window;
      style = gtk_widget_get_style(w);
      if((window == NULL) || (style == NULL))
          return(TRUE);

        /* Get colormap and off screen buffer. */
        colormap = gdk_window_get_colormap(window);
        pixmap = pd->animation_buffer;
        if((colormap == NULL) || (pixmap == NULL))
            return(TRUE);

      /* Get state and size of window. */
        state = GTK_WIDGET_STATE(w);
      gdk_window_get_size((GdkWindow *)pixmap, &width, &height);
        if((width < 1) || (height < 1))
            return(TRUE);

      /* Get graphic contexts. */
      animation_gc = pd->animation_gc;
      bg_pixmap = style->bg_pixmap[state];
      if(animation_gc == NULL)
          return(TRUE);


      /* Begin drawing. */

      /* Set background pixmap if the style has one. */
      if(bg_pixmap != NULL)
      {
          gint tx, ty;

          gdk_gc_set_tile(animation_gc, bg_pixmap);
          gdk_gc_set_fill(animation_gc, GDK_TILED);
          gdk_window_get_position(window, &tx, &ty);
            gdk_gc_set_ts_origin(animation_gc, -tx, -ty);
      }
      else
      {
          gdk_gc_set_fill(animation_gc, GDK_SOLID);
      }
      gdk_gc_set_clip_mask(animation_gc, NULL);

      /* Draw background to cover entire pixmap buffer. */
        gdk_gc_set_foreground(animation_gc, &style->bg[state]);
      gdk_draw_rectangle(
          (GdkDrawable *)pixmap, animation_gc, TRUE,
          0, 0, width, height
      );

      gdk_gc_set_fill(animation_gc, GDK_SOLID);
      gdk_gc_set_ts_origin(animation_gc, 0, 0);


      /* Begin drawing icons. */

      /* Calculate total frames, this is the number of icons in the
       * inside animatino frame plus two end point icons (the start and
       * end icons).
       */
      total_frames = MAX(pd->total_icons + 2, 2);

      /* Calculate animation frame index. */
      frame = (gfloat)pd->animation_position / (gfloat)((guint16)-1) *
          total_frames;

      /* Calculate number of animation units in one frame. */
      if(total_frames > 0)
          anim_per_frame = (gint)((guint16)-1) / total_frames;
      else
          anim_per_frame = 0;


      /* Draw start icons. */
      if(pd->total_start_icons > 0)
      {
          icon_struct *icon = NULL;

          /* Check which icon structure to draw based on frame index. */
          if((frame == 0) && (pd->total_start_icons > 0))
          {
            icon = pd->start_icon[0];
          }
          else if((frame == (total_frames - 1)) && (pd->total_start_icons > 2))
          {
            icon = pd->start_icon[2];
          }
          else if(pd->total_start_icons > 1)
          {
            icon = pd->start_icon[1];
          }

          /* Found a valid icon structure to draw? */
          if(icon != NULL)
          {
                gint    x = 0,
                        y = height - icon->height - 1;

            /* Record icon width. */
            start_icon_width = icon->width;

            /* Icon pixmap available for drawing? */
            if(icon->pixmap != NULL)
            {
                /* Mask available? */
                if(icon->mask != NULL)
                {
                  gdk_gc_set_clip_mask(animation_gc, icon->mask);
                  gdk_gc_set_clip_origin(animation_gc, x, y);
                }
                else
                {
                  gdk_gc_set_clip_mask(animation_gc, NULL);
                }

                gdk_draw_pixmap(
                  (GdkDrawable *)pixmap,
                  animation_gc,
                  (GdkDrawable *)icon->pixmap,
                  0, 0,
                  x, y,
                  icon->width, icon->height
                );
            }
          }
      }

        /* Draw end icons. */
        if(pd->total_end_icons > 0)
        {
            icon_struct *icon = NULL;

            /* Check which icon structure to draw based on frame index. */
            if((frame == 0) && (pd->total_end_icons > 0))
            {
                icon = pd->end_icon[0];
            }
            else if((frame == (total_frames - 1)) && (pd->total_end_icons > 2))
            {
                icon = pd->end_icon[2];
            }
            else if(pd->total_end_icons > 1)
            {
                icon = pd->end_icon[1];
            }

            /* Found a valid icon structure to draw? */
            if(icon != NULL)
            {
                gint    x = width - icon->width - 1,
                  y = height - icon->height - 1;

                /* Record icon width. */
                end_icon_width = icon->width;

            /* Pixmap available for drawing? */
                if(icon->pixmap != NULL)
                {
                    /* Mask available? */
                    if(icon->mask != NULL)
                    {
                        gdk_gc_set_clip_mask(animation_gc, icon->mask);
                        gdk_gc_set_clip_origin(animation_gc, x, y);
                    }
                    else
                    {
                        gdk_gc_set_clip_mask(animation_gc, NULL);
                    }

                    gdk_draw_pixmap(
                        (GdkDrawable *)pixmap,
                        animation_gc,
                        (GdkDrawable *)icon->pixmap,
                        0, 0,
                        x, y,
                        icon->width, icon->height
                    );
                }
            }
        }


      /* Draw intermediate icons. */
      if((pd->total_icons > 0) &&
         (frame > 0) && (frame < (total_frames - 1))
      )
      {
          gint i, iframe_max;
          gfloat iframe_coeff;
            icon_struct *icon = NULL;


          /* Calculate inside frame coeff. */
          iframe_max = (gint)((guint16)-1) - (2 * anim_per_frame);
          if(iframe_max > 0)
            iframe_coeff = CLIP(
                ((gfloat)pd->animation_position - (gfloat)anim_per_frame) /
                (gfloat)iframe_max, 0.0, 1.0
            );
          else
            iframe_coeff = 0.0;

          /* Calculate icon index based on inside frame coeff. */
          i = iframe_coeff * pd->total_icons;

            /* Check which icon structure to draw based on frame index. */
            if((i >= 0) && (i < pd->total_icons))
                icon = pd->icon[i];
          else
            icon = NULL;

            /* Found a valid icon structure to draw? */
            if(icon != NULL)
            {
            gint y_border = 0;
            gint x, y, range;


            /* Calculate x position based on iframe_coeff and range. */
            range = MAX(
                width - start_icon_width - end_icon_width - icon->width,
                0
            );
            x = (iframe_coeff * range) + start_icon_width;

            /* Calculate y position based on iframe_coeff and range. */
            range = MAX(
                (height / 2) - (icon->height / 2) - y_border,
                0
            );
            if(iframe_coeff > 0.5)
            {
                gfloat tc = (iframe_coeff - 0.5) / 0.5;
                y = (tc * tc) * range;
            }
            else
            {
                    gfloat tc = 1.0 - (iframe_coeff / 0.5);
                y = (tc * tc) * range;
            }
            y += y_border;    /* Add 5 pixels margin. */


                /* Pixmap available for drawing? */
                if(icon->pixmap != NULL)
                {
                    /* Mask available? */
                    if(icon->mask != NULL)
                    {
                        gdk_gc_set_clip_mask(animation_gc, icon->mask);
                        gdk_gc_set_clip_origin(animation_gc, x, y);
                    }
                    else
                    {
                        gdk_gc_set_clip_mask(animation_gc, NULL);
                    }

                    gdk_draw_pixmap(
                        (GdkDrawable *)pixmap,
                        animation_gc,
                        (GdkDrawable *)icon->pixmap,
                        0, 0,
                        x, y,
                        icon->width, icon->height
                    );
                }
            }
      }

      /* Put newly drawn GdkPixmap buffer to drawing area's GdkWindow. */
        gdk_gc_set_clip_mask(animation_gc, NULL);
      gdk_window_copy_area(
          window, animation_gc,
          0, 0,
          (GdkWindow *)pixmap,
          0, 0,
          width, height
      );

      return(TRUE);
}


/*
 *    Returns the current time in milliseconds.
 */
static glong ProgressDialogCurrentTime(void)
{
#ifdef __MSW__
        SYSTEMTIME t;   /* Current time of day structure. */

        GetSystemTime(&t);
        return(
            (glong)(
                (((((t.wHour * 60.0) + t.wMinute) * 60) + t.wSecond) * 1000) +
                t.wMilliseconds
            )
        );
#else
        struct timeval tv[1];

        if(gettimeofday(tv, NULL) < 0)
            return(-1);

        return(((tv->tv_sec % 86400) * 1000) + (tv->tv_usec / 1000));
#endif
}



/*
 *    Recreates a new icon for the given progress dialog.
 *
 *    Inputs assumed valid.
 */
static void ProgressDialogChangeIcon(
        progress_dialog_struct *pd, const u_int8_t **icon_data
)
{
        gint width, height;
        GdkGC *gc;
        GdkPixmap *pixmap;
        GdkBitmap *mask;
        GtkStyle *style;
        GtkWidget *w, *parent, *toplevel;


        toplevel = pd->toplevel;
        if(toplevel == NULL)
            return;

        style = gtk_widget_get_style(toplevel);
      if(style == NULL)
          style = gtk_widget_get_default_style();
      if(style == NULL)
          return;
        gc = style->black_gc;

        /* Get fixed widget as the parent for the icon GtkPixmap. */
        parent = pd->icon_fixed;
        if(parent == NULL)
            return;

        /* Load pixmap and mask pair from the given icon data. */
        pixmap = gdk_pixmap_create_from_xpm_d(
            toplevel->window, &mask,
            &style->bg[GTK_STATE_NORMAL],
            (gchar **)icon_data
        );
      if(pixmap == NULL)
          return;

      /* Get GtkPixmap widget, create it as needed. */
      w = pd->icon_pm;
      if(w == NULL)
      {
          pd->icon_pm = w = gtk_pixmap_new(pixmap, mask);
            gtk_fixed_put(GTK_FIXED(parent), w, 0, 0);
          gtk_widget_show(w);
      }
      else
      {
          gtk_pixmap_set(GTK_PIXMAP(w), pixmap, mask);
      }

        gtk_widget_shape_combine_mask(parent, mask, 0, 0);

        gdk_window_get_size((GdkWindow *)pixmap, &width, &height);
        gtk_widget_set_usize(parent, width, height);
/*    gtk_widget_queue_resize(parent); */


      /* Unref the pixmap and mask pair, they are no longer needed. */
        gdk_pixmap_unref(pixmap);
      pixmap = NULL;
        if(mask != NULL)
      {
            gdk_bitmap_unref(mask);
          mask = NULL;
      }

        /* Set WM icon for toplevel. */
/*
 Do not set toplevel icon, let it be parent relative to the transient
 window.

        GUISetWMIcon(toplevel->window, (u_int8_t **)icon_data);
 */
}

/*
 *    Allocates and returns a new icon structure, loading the icon
 *    data from icon_data.
 */
static icon_struct *ProgressDialogIconNew(
      progress_dialog_struct *pd, const u_int8_t **icon_data
)
{
        GdkGC *gc;
      GdkWindow *window;
        GdkPixmap *pixmap;
        GdkBitmap *mask;
        GtkWidget *toplevel;
        GtkStyle *style;
        gint width, height;
      icon_struct *icon;


      if((pd == NULL) || (icon_data == NULL))
          return(NULL);

        toplevel = pd->toplevel;
        if(toplevel == NULL)
            return(NULL);

      window = toplevel->window;
      if(window == NULL)
          return(NULL);

        style = gtk_widget_get_style(toplevel);
        if(style == NULL)
            style = gtk_widget_get_default_style();
        if(style == NULL)
            return(NULL);
        gc = style->black_gc;

        /* Create new pixmap. */
      pixmap = gdk_pixmap_create_from_xpm_d(
            window, &mask,
            &style->bg[GTK_STATE_NORMAL],
            (gchar **)icon_data
        );
        if(pixmap == NULL)
            return(NULL);


      /* Allocate a new animated icon structure. */
      icon = (icon_struct *)g_malloc0(sizeof(icon_struct));
      if(icon == NULL)
      {
          gdk_pixmap_unref(pixmap);
          if(mask != NULL)
            gdk_bitmap_unref(mask);
          return(NULL);
      }

      icon->pixmap = pixmap;
      icon->mask = mask;

      /* Get size. */
        gdk_window_get_size((GdkWindow *)pixmap, &width, &height);
      icon->width = width;
      icon->height = height;

      return(icon);
}

/*
 *    Deletes the animation icon structure and all its resources.
 */
static void ProgressDialogIconDelete(
      progress_dialog_struct *pd, icon_struct *icon
)
{
      if((pd == NULL) || (icon == NULL))
          return;

      if(icon->pixmap != NULL)
          gdk_pixmap_unref(icon->pixmap);

      if(icon->mask != NULL)
          gdk_bitmap_unref(icon->mask);

      g_free(icon);
}


/*
 *    Deletes all animation icons on the given progress dialog.
 */
static void ProgressDialogIconDeleteAll(
        progress_dialog_struct *pd
)
{
      gint i;


        if(pd == NULL)
            return;

      /* Delete all animation start icons. */
      for(i = 0; i < pd->total_start_icons; i++)
          ProgressDialogIconDelete(pd, pd->start_icon[i]);
      g_free(pd->start_icon);
      pd->start_icon = NULL;
        pd->total_start_icons = 0;

        /* Delete all animation intermediate icons. */
        for(i = 0; i < pd->total_icons; i++)
            ProgressDialogIconDelete(pd, pd->icon[i]);
        g_free(pd->icon);
        pd->icon = NULL;
        pd->total_icons = 0;

        /* Delete all animation end icons. */
        for(i = 0; i < pd->total_end_icons; i++)
            ProgressDialogIconDelete(pd, pd->end_icon[i]);
        g_free(pd->end_icon);
        pd->end_icon = NULL;
        pd->total_end_icons = 0;
}

/*
 *    Initializes progress dialog.
 *
 *    Returns non-zero on error.
 */
gint ProgressDialogInit(void)
{
      gint border_major = 5;
      gint width, height;
      GdkColormap *colormap = NULL;
      GdkGC *gc;
      GdkWindow *window;
      GtkStyle *style;
        GtkWidget *w, *parent, *parent2, *parent3;
        GtkAdjustment *adj;
      GtkAccelGroup *accelgrp;
      progress_dialog_struct *pd = &progress_dialog;


        /* Reset globals. */
/* None. */

        /* Reset values. */
        memset(pd, 0x00, sizeof(progress_dialog_struct));

        pd->initialized = TRUE;
        pd->map_state = FALSE;
      pd->visibility = GDK_VISIBILITY_FULLY_OBSCURED;
        pd->stop_count = 0;;
      pd->transient_for = NULL;


      /* Keyboard accelerator group. */
      pd->accelgrp = accelgrp = gtk_accel_group_new();


        /* Toplevel. */
        pd->toplevel = w = gtk_window_new(GTK_WINDOW_DIALOG);
      gtk_widget_add_events(
          w,
          GDK_VISIBILITY_NOTIFY_MASK
      );
        gtk_widget_set_usize(w, PROGRESS_DIALOG_WIDTH, PROGRESS_DIALOG_HEIGHT);
        gtk_window_set_title(GTK_WINDOW(w), "Progress");
      gtk_widget_realize(w);
        window = w->window;
        if(window != NULL)
        {
            gdk_window_set_decorations(
                window,
                GDK_DECOR_TITLE | GDK_DECOR_MENU | GDK_DECOR_MINIMIZE
            );
            gdk_window_set_functions(
                window,
                GDK_FUNC_MOVE | GDK_FUNC_MINIMIZE | GDK_FUNC_CLOSE
            );
          colormap = gdk_window_get_colormap(window);
        }
      gtk_signal_connect(
            GTK_OBJECT(w), "visibility_notify_event",
            GTK_SIGNAL_FUNC(ProgressDialogVisibilityCB), pd
        );
        gtk_signal_connect(
            GTK_OBJECT(w), "delete_event",
            GTK_SIGNAL_FUNC(ProgressDialogCloseCB), pd
        );
        gtk_signal_connect(
            GTK_OBJECT(w), "destroy",
            GTK_SIGNAL_FUNC(ProgressDialogDestroyCB), pd
        );
        gtk_container_border_width(GTK_CONTAINER(w), 0);
      gtk_accel_group_attach(accelgrp, GTK_OBJECT(w));
        parent = w;


        /* Main vbox. */
        pd->main_vbox = w = gtk_vbox_new(FALSE, 0);
        gtk_container_add(GTK_CONTAINER(parent), w);
        gtk_widget_show(w);
        parent = w;


      /* Hbox for animated drawing area (double border). */
      w = gtk_hbox_new(FALSE, 0);
        gtk_box_pack_start(
          GTK_BOX(parent), w,
          FALSE, FALSE, 2 * border_major
      );
        gtk_widget_show(w);
        parent2 = w;
      /* Animated drawing area. */
      width = PROGRESS_DIALOG_ANIMATION_DA_WIDTH;
      height = PROGRESS_DIALOG_ANIMATION_DA_HEIGHT;
      pd->animation_da = w = gtk_drawing_area_new();
        gtk_widget_set_events(
            w,
            GDK_EXPOSURE_MASK
        );
        gtk_signal_connect(
            GTK_OBJECT(w), "expose_event",
            GTK_SIGNAL_FUNC(ProgressDialogAnimationDrawCB), pd
        );
      gtk_drawing_area_size(GTK_DRAWING_AREA(w), width, height);
      /* Pack into parent box with double border. */
      gtk_box_pack_start(
          GTK_BOX(parent2), w,
          FALSE, FALSE, 2 * border_major
      );
/*    gtk_widget_show(w); */
      /* Animated drawing area buffer. */
      pd->animation_buffer = gdk_pixmap_new(
          window, width, height, -1
        );


      /* Hbox for icon and label. */
      w = gtk_hbox_new(FALSE, 0);
      gtk_box_pack_start(GTK_BOX(parent), w, TRUE, TRUE, border_major);
        gtk_widget_show(w);
      parent2 = w;

      /* Vbox to align icon fixed. */
        pd->icon_vbox = w = gtk_vbox_new(FALSE, 0);
        gtk_box_pack_start(GTK_BOX(parent2), w, FALSE, FALSE, border_major);
/*    gtk_widget_show(w); */
        parent3 = w;

      /* Icon fixed. */
        pd->icon_fixed = w = gtk_fixed_new();
        gtk_box_pack_start(GTK_BOX(parent3), w, TRUE, FALSE, 0);
        gtk_widget_realize(w);
      gtk_widget_show(w);

        pd->icon_pm = NULL;   /* No icon GtkPixmap at startup. */

        /* Vbox to align label. */
        w = gtk_vbox_new(TRUE, 0);
        gtk_box_pack_start(GTK_BOX(parent2), w, TRUE, TRUE, border_major);
        gtk_widget_show(w);
        parent3 = w;
      /* Hbox to align label to left. */
        w = gtk_hbox_new(FALSE, 0);
        gtk_box_pack_start(GTK_BOX(parent3), w, TRUE, FALSE, 0);
        gtk_widget_show(w);
        parent3 = w;
        /* Label. */
        pd->label = w = gtk_label_new("Processing...");
        gtk_label_set_justify(GTK_LABEL(w), GTK_JUSTIFY_LEFT);
        gtk_box_pack_start(GTK_BOX(parent3), w, FALSE, FALSE, 0);
        gtk_widget_show(w);


      /* Hbox to hold progress bar and stop button. */
      w = gtk_hbox_new(FALSE, 0);
      gtk_box_pack_start(GTK_BOX(parent), w, FALSE, FALSE, border_major);
      gtk_widget_show(w);
      parent2 = w;

        w = gtk_hbox_new(FALSE, border_major);
        gtk_box_pack_start(GTK_BOX(parent2), w, TRUE, TRUE, border_major);
        gtk_widget_show(w);
        parent2 = w;


      /* Vbox for progress bar. */
      w = gtk_vbox_new(FALSE, 0);
      gtk_box_pack_start(GTK_BOX(parent2), w, TRUE, TRUE, 0);
      gtk_widget_show(w);
      parent3 = w;

        /* Progress bar. */
        adj = (GtkAdjustment *)gtk_adjustment_new(0, 1, 100, 0, 5, 5);
        pd->progress_bar = w = gtk_progress_bar_new_with_adjustment(adj);
      gtk_widget_set_usize(w, -1, PROGRESS_DIALOG_PROGRESS_HEIGHT);
        gtk_progress_bar_set_orientation(
            GTK_PROGRESS_BAR(w), GTK_PROGRESS_LEFT_TO_RIGHT
        );
        gtk_progress_bar_set_bar_style(
            GTK_PROGRESS_BAR(w), GTK_PROGRESS_CONTINUOUS
        );
        gtk_progress_set_activity_mode(  
            GTK_PROGRESS(w), FALSE
        );
/* This was to make progress bar vertically aligned with the stop
   button homogeniously. We don't want that.
      gtk_box_pack_start(GTK_BOX(parent3), w, TRUE, FALSE, 0);
 */
        gtk_box_pack_start(GTK_BOX(parent3), w, FALSE, FALSE, 0);
        gtk_widget_show(w);


      /* Stop button. */
      pd->stop_btn = w = gtk_button_new();
        GTK_WIDGET_SET_FLAGS(w, GTK_CAN_DEFAULT);
      gtk_widget_set_usize(w, PROGRESS_DIALOG_BTN_WIDTH, PROGRESS_DIALOG_BTN_HEIGHT);
      gtk_box_pack_start(GTK_BOX(parent2), w, FALSE, FALSE, 0);
        gtk_signal_connect(
            GTK_OBJECT(w), "clicked",
            GTK_SIGNAL_FUNC(ProgressDialogStopCB),
            (gpointer)pd
        );
        gtk_accel_group_add(
            accelgrp, GDK_Escape, 0, GTK_ACCEL_VISIBLE,
            GTK_OBJECT(w), "clicked"
        );
      gtk_widget_show(w);
      parent3 = w;
      /* Stop button label. */
      pd->stop_btn_label = w = gtk_label_new("Stop");
      gtk_container_add(GTK_CONTAINER(parent3), w);
      gtk_widget_show(w);



      /* Get values for creating animation resources. */
      style = gtk_widget_get_style(pd->animation_da);
      if(style == NULL)
            style = gtk_widget_get_default_style();
      if(colormap == NULL)
            colormap = gdk_colormap_get_system();

        /* Create graphic context for animating icons. */
      pd->animation_gc = gc = gdk_gc_new(window);



      return(0);
}

/*
 *      Sets dialog to be a transient for the given toplevel window
 *      widget w. If w is NULL then no transient for will be unset.
 */
void ProgressDialogSetTransientFor(GtkWidget *w)
{
        progress_dialog_struct *pd = &progress_dialog;


        if(!pd->initialized)
            return;

        if(pd->toplevel != NULL)
        {
            if(w != NULL)
            {
                if(!GTK_IS_WINDOW(GTK_OBJECT(w)))
                    return;

            if(GTK_WINDOW(w)->modal)
                gtk_window_set_modal(GTK_WINDOW(w), FALSE);

                gtk_window_set_modal(
                    GTK_WINDOW(pd->toplevel), TRUE
                );
                gtk_window_set_transient_for(
                    GTK_WINDOW(pd->toplevel), GTK_WINDOW(w)
                );
            pd->transient_for = w;
            }
            else
            {
                gtk_window_set_modal(
                    GTK_WINDOW(pd->toplevel), FALSE
                );
                gtk_window_set_transient_for(
                    GTK_WINDOW(pd->toplevel), NULL
                );
            pd->transient_for = NULL;
            }
        }
}

/*
 *    Explicitly sets the progress dialog's toplevel WM icon.
 */
void ProgressDialogSetWMIconData(const u_int8_t **icon_data)
{
      GtkWidget *w;
        progress_dialog_struct *pd = &progress_dialog;


        if(!pd->initialized)
            return;

      w = pd->toplevel;
        if(w == NULL)
            return;

        /* Set WM icon for toplevel. */
        GUISetWMIcon(w->window, (u_int8_t **)icon_data);
}

/*
 *    Returns TRUE if dialog is mapped.
 */
gbool ProgressDialogIsQuery(void)
{
        progress_dialog_struct *pd = &progress_dialog;

      if(!pd->initialized)
          return(FALSE);
      else
          return(pd->map_state);
}

/*
 *      Just unmaps the dialog.
 */
void ProgressDialogBreakQuery(gbool allow_gtk_iteration)
{
      progress_dialog_struct *pd = &progress_dialog;


      if(allow_gtk_iteration)
      {
          while((gtk_events_pending() > 0) && pd->initialized)
            gtk_main_iteration();
      }
      gdk_flush();
      ProgressDialogUnmap();
      gdk_flush();
        if(allow_gtk_iteration)
        {
            while((gtk_events_pending() > 0) && pd->initialized)
                gtk_main_iteration();
        }
}

/*
 *    Returns the number of stop counts.
 */
gint ProgressDialogStopCount(void)
{
      progress_dialog_struct *pd = &progress_dialog;
                    
        if(!pd->initialized)
          return(0);
      else
          return(pd->stop_count);
}

/*
 *    Maps the progress dialog for standard progress display.
 *
 *    The icon_data specifies the icon xpm data to load for the progress
 *    icon. The size of the icon should be 32x32.
 */
void ProgressDialogMap(
        const gchar *title,
        const gchar *label,
        const u_int8_t **icon_data,
        const gchar *stop_btn_label
)
{
        progress_dialog_struct *pd = &progress_dialog;
      GtkWidget *w;


      if(!pd->initialized)
          return;

      /* Reset stop count. */
      pd->stop_count = 0;

        /* Set new title? */
        if(title != NULL)
        {
            w = pd->toplevel;
            if(w != NULL)
                gtk_window_set_title(GTK_WINDOW(w), title);
        }

        /* Set new label? */
        if(label != NULL)
        {
            w = pd->label;
            if(w != NULL)
                gtk_label_set_text(GTK_LABEL(w), label);
        }


      /* Map icon vbox that holds icon fixed and pixmap widgets. */
      if(pd->icon_vbox != NULL)
          gtk_widget_show(pd->icon_vbox);

      /* Unmap the animation drawing area. */
      if(pd->animation_da != NULL)
          gtk_widget_hide(pd->animation_da);


        /* Change icon? */
        if(icon_data != NULL)
          ProgressDialogChangeIcon(pd, icon_data);
        
        /* Change stop button label? */
        if(stop_btn_label != NULL)
        {
            w = pd->stop_btn_label;
            if(w != NULL)
                gtk_label_set_text(GTK_LABEL(w), stop_btn_label);
        }

      /* Set stop button to be the default button. */
      w = pd->stop_btn;
      if(w != NULL)
      {
          gtk_widget_grab_focus(w);
          gtk_widget_grab_default(w);
      }

      /* Map progress dialog (as needed). */
      if(!pd->map_state)
      {
          w = pd->toplevel;
          gtk_widget_show_raise(w);
          pd->map_state = TRUE;
      }
}

/*
 *      Maps the progress dialog in animation mode and loads the given
 *    set of animation icon xpm data.
 *
 *    The animation_interval specifies the maximum lapse of time
 *    per increment in ms (typical value would be 500 ms).
 *
 *    The animation_increment specifies a positive value up to
 *    (guint16)-1. Smaller values produce slower and finer animation
 *    while larger values produce faster and rougher animation.
 */
void ProgressDialogMapAnimation(
        const gchar *title,
        const gchar *label,
        const gchar *stop_btn_label,
      u_int8_t ***start_icon_data, gint total_start_icon_datas,
      u_int8_t ***icon_data, gint total_icon_datas,
      u_int8_t ***end_icon_data, gint total_end_icon_datas,
      glong animation_interval, guint16 animation_increment
)
{
      gint i;
        progress_dialog_struct *pd = &progress_dialog;
        GtkWidget *w;


        if(!pd->initialized)
            return;

        /* Reset stop count. */
        pd->stop_count = 0;

        /* Set new title? */
        if(title != NULL)
        {
            w = pd->toplevel;
            if(w != NULL)
                gtk_window_set_title(GTK_WINDOW(w), title);
        }

        /* Set new label? */
        if(label != NULL)
        {
            w = pd->label;
            if(w != NULL)
                gtk_label_set_text(GTK_LABEL(w), label);
        }


        /* Unmap icon vbox that holds icon fixed and pixmap widgets. */
        if(pd->icon_vbox != NULL)
            gtk_widget_hide(pd->icon_vbox);

        /* Map the animation drawing area. */
        if(pd->animation_da != NULL)
            gtk_widget_show(pd->animation_da);


        /* Change stop button label? */
        if(stop_btn_label != NULL)
        {
            w = pd->stop_btn_label;
            if(w != NULL)
                gtk_label_set_text(GTK_LABEL(w), stop_btn_label);
        }


      /* Begin setting new animation icons. */

      /* Deallocate all existing animation icons (if any). */
      ProgressDialogIconDeleteAll(pd);

      /* Start icons. */
      pd->total_start_icons = total_start_icon_datas;
      if(pd->total_start_icons > 0)
      {
          pd->start_icon = (icon_struct **)g_realloc(
            pd->start_icon,
            pd->total_start_icons * sizeof(icon_struct *)
          );
          if(pd->start_icon == NULL)
            pd->total_start_icons = 0;
          for(i = 0; i < pd->total_start_icons; i++)
            pd->start_icon[i] = ProgressDialogIconNew(
                pd, (const u_int8_t **)start_icon_data[i]
            );
      }
        /* Icons. */
        pd->total_icons = total_icon_datas;
        if(pd->total_icons > 0)
        {
            pd->icon = (icon_struct **)g_realloc(
            pd->icon,
                pd->total_icons * sizeof(icon_struct *)
            );
            if(pd->icon == NULL)
                pd->total_icons = 0;
            for(i = 0; i < pd->total_icons; i++)
                pd->icon[i] = ProgressDialogIconNew(
                    pd, (const u_int8_t **)icon_data[i]
                );
        }
        /* End icons. */
        pd->total_end_icons = total_end_icon_datas;
        if(pd->total_end_icons > 0)
        {
            pd->end_icon = (icon_struct **)g_realloc(
                pd->end_icon,
                pd->total_end_icons * sizeof(icon_struct *)
            );
            if(pd->end_icon == NULL)
                pd->total_end_icons = 0;
            for(i = 0; i < pd->total_end_icons; i++)
                pd->end_icon[i] = ProgressDialogIconNew(
                    pd, (const u_int8_t **)end_icon_data[i]
                );
        }

      /* Reset animation values. */
      pd->animation_time_last = ProgressDialogCurrentTime();
      pd->animation_interval = animation_interval;
      pd->animation_position = 0;
      pd->animation_increment = animation_increment;


        /* Set stop button to be the default button. */
        w = pd->stop_btn;
        if(w != NULL)
        {
            gtk_widget_grab_focus(w);
            gtk_widget_grab_default(w);
        }

        /* Map progress dialog (as needed). */
        if(!pd->map_state)
        {
            w = pd->toplevel;
          gtk_widget_show_raise(w);
            pd->map_state = TRUE;
        }
}


/*
 *    Updates the progress dialog with the given values.
 *
 *    This function has no affect if ProgressDialogMap() was not called
 *    before to map the progress dialog.
 *
 *    If allow_gtk_iteration is TRUE then gtk_main_iteration()
 *    may be called one or more times during this call (note possible
 *    reenterant issue).
 */
void ProgressDialogUpdate(
        const gchar *title,
        const gchar *label,
        const u_int8_t **icon_data,
        const gchar *stop_btn_label,
        gdouble position,               /* 0.0 to 1.0. */
      guint nblocks,                /* 0 for continuous. */
        gbool allow_gtk_iteration
)
{
        progress_dialog_struct *pd = &progress_dialog;
        GtkWidget *w;


        if(!pd->initialized || !pd->map_state)
            return;

      /* Change title? */
      if(title != NULL)
      {
          w = pd->toplevel;
          if(w != NULL)
            gtk_window_set_title(GTK_WINDOW(w), title);
      }

      /* Change label? */
      if(label != NULL)
      {
            w = pd->label;
            if(w != NULL)  
                gtk_label_set_text(GTK_LABEL(w), label);
      }

      /* Change icon? */
      if(icon_data != NULL)
            ProgressDialogChangeIcon(pd, icon_data);

      /* Change stop button label? */
      if(stop_btn_label != NULL)
      {
            w = pd->stop_btn_label;
            if(w != NULL)
                gtk_label_set_text(GTK_LABEL(w), stop_btn_label);
      }

      /* Begin updating progress bar position */
      w = pd->progress_bar;
      if(w != NULL)
      {
          GtkProgress *pr = GTK_PROGRESS(w);
          GtkProgressBar *pb = GTK_PROGRESS_BAR(w);


          if(position > 1.0)
            position = 1.0;
          else if(position < 0.0)
            position = 0.0;

          gtk_progress_set_activity_mode(pr, FALSE);
/*
          gtk_progress_set_format_string(pr, "%p%%");
          gtk_progress_set_show_text(pr, FALSE);
 */
          if(nblocks > 0)
          {
            gtk_progress_bar_set_bar_style(
                pb, GTK_PROGRESS_DISCRETE
            );
            gtk_progress_bar_set_discrete_blocks(pb, nblocks);
          }
          else
          {
            gtk_progress_bar_set_bar_style(
                    pb, GTK_PROGRESS_CONTINUOUS
                );
          }
          gtk_progress_bar_update(pb, position);
      }

      /* Check if animation drawing area widget is mapped. */
      w = pd->animation_da;
      if((w != NULL) ? GTK_WIDGET_MAPPED(w) : FALSE)
      {
#if 0
/* For syncing animation position with progress. */
          /* Set animation position to match progress position. */
          pd->animation_position = (guint16)(
            position * (guint16)-1
          );

            /* Redraw animation. */
          ProgressDialogAnimationDrawCB(w, NULL, pd);
#endif

          glong cur_time = ProgressDialogCurrentTime();
          glong dt;
          gfloat tc;


            /* Calculate delta time from last time update. */
            if(cur_time >= pd->animation_time_last)
                dt = cur_time - pd->animation_time_last;
            else
                dt = 0;
            if(dt > pd->animation_interval)
                dt = pd->animation_interval;

            /* Calculate time coefficient. */
            if(pd->animation_interval > 0)
                tc = (gfloat)dt / (gfloat)pd->animation_interval;
            else
                tc = 0.0;

            pd->animation_position += (guint16)(
                pd->animation_increment * tc
            );


            /* Redraw animation. */
            ProgressDialogAnimationDrawCB(w, NULL, pd);

            /* Record animation handled time. */
            pd->animation_time_last = cur_time;
      }

      /* Allow gtk main iteration to be called so that updated
       * values get enacted within this call?
       */
      if(allow_gtk_iteration)
      {
          while((gtk_events_pending() > 0) && pd->initialized)
            gtk_main_iteration();
      }
}

/*
 *      Updates the progress dialog with the given values.
 *
 *      This function has no affect if ProgressDialogMap() was not called
 *      before to map the progress dialog.
 *
 *      If allow_gtk_iteration is TRUE then gtk_main_iteration()
 *      may be called one or more times during this call (note possible
 *      reenterant issue).
 */
void ProgressDialogUpdateUnknown(
        const gchar *title,
        const gchar *label,
        const u_int8_t **icon_data,
        const gchar *stop_btn_label,
        gbool allow_gtk_iteration
)
{
        progress_dialog_struct *pd = &progress_dialog;
        GtkWidget *w;
  

        if(!pd->initialized || !pd->map_state)
            return;

        /* Set new title? */
        if(title != NULL)
        {
            w = pd->toplevel;
            if(w != NULL)
                gtk_window_set_title(GTK_WINDOW(w), title);
        }

        /* Set new label? */
        if(label != NULL)
        {
            w = pd->label;
            if(w != NULL)
                gtk_label_set_text(GTK_LABEL(w), label);
        }

        /* Change icon? */   
        if(icon_data != NULL)
            ProgressDialogChangeIcon(pd, icon_data);

        /* Change stop button label? */
        if(stop_btn_label != NULL)
        {
            w = pd->stop_btn_label;
            if(w != NULL)
                gtk_label_set_text(GTK_LABEL(w), stop_btn_label);
        }
 
        /* Begin updating progress bar position in activity mode. */
        w = pd->progress_bar;
        if(w != NULL)
        {
            GtkProgress *pr = GTK_PROGRESS(w);
          GtkProgressBar *pb = GTK_PROGRESS_BAR(w);
          GtkAdjustment *adj;
          gdouble position;


          adj = pr->adjustment;
          position = gtk_progress_get_value(pr) + 1.0;
            if(adj != NULL)
          {
            if(position > adj->upper)
                position = adj->lower;
          }

          gtk_progress_set_activity_mode(pr, TRUE);
            gtk_progress_set_show_text(pr, FALSE);
            gtk_progress_bar_set_bar_style(
                pb, GTK_PROGRESS_CONTINUOUS
            );
          gtk_progress_set_value(pr, position);
        }

        /* Check if animation drawing area widget is mapped. */
        w = pd->animation_da;
        if((w != NULL) ? GTK_WIDGET_MAPPED(w) : FALSE)
        {
          glong cur_time = ProgressDialogCurrentTime();
          glong dt;
          gfloat tc;


          /* Calculate delta time from last time update. */
          if(cur_time >= pd->animation_time_last)
            dt = cur_time - pd->animation_time_last;
          else
            dt = 0;
          if(dt > pd->animation_interval)
            dt = pd->animation_interval;

          /* Calculate time coefficient. */
          if(pd->animation_interval > 0)
            tc = (gfloat)dt / (gfloat)pd->animation_interval;
          else
            tc = 0.0;

          pd->animation_position += (guint16)(
            pd->animation_increment * tc
          );


          /* Redraw animation. */
          ProgressDialogAnimationDrawCB(w, NULL, pd);

          /* Record animation handled time. */
          pd->animation_time_last = cur_time;
        }

        /* Allow gtk main iteration to be called so that updated
         * values get enacted within this call?
         */
        if(allow_gtk_iteration)
        {
            while((gtk_events_pending() > 0) && pd->initialized)
                gtk_main_iteration();
        }
}

/*
 *    Unmaps the progress dialog.
 */
void ProgressDialogUnmap(void)
{
        progress_dialog_struct *pd = &progress_dialog;
        GtkWidget *w;


        if(!pd->initialized)
            return;

      /* Delete all animation icons (if any). */
      ProgressDialogIconDeleteAll(pd);

/* Do not check current map state. */

      w = pd->toplevel;
      if(w != NULL)
      {
          gtk_widget_hide(w);
          gtk_widget_unmap(w);
          pd->map_state = FALSE;
      }
}

/*
 *    Deallocates all resources on the progress dialog structure.
 */
void ProgressDialogShutdown(void)
{
        progress_dialog_struct *pd = &progress_dialog;
        GtkWidget **w;


        if(pd->initialized)
      {
#define DO_DESTROY_WIDGET       \
{ \
 if((*w) != NULL) \
 { \
  GtkWidget *tmp_w = *w; \
  (*w) = NULL; \
  gtk_widget_destroy(tmp_w); \
 } \
}

          /* Unset transient for widget as needed. */
          if(pd->transient_for != NULL)
            ProgressDialogSetTransientFor(NULL);

          /* Deallocate all animation icons (if any). */
          ProgressDialogIconDeleteAll(pd);

          /* Deallocate animation resources. */
          w = &pd->animation_da;
          DO_DESTROY_WIDGET

          if(pd->animation_buffer != NULL)
          {
            gdk_pixmap_unref(pd->animation_buffer);
            pd->animation_buffer = NULL;
          }

          if(pd->animation_gc != NULL)
          {
            gdk_gc_unref(pd->animation_gc);
            pd->animation_gc = NULL;
          }


          /* Destroy icon. */
            w = &pd->icon_pm;
            DO_DESTROY_WIDGET
 

          /* Destroy all other widgets. */
            w = &pd->toplevel;
            DO_DESTROY_WIDGET

          if(pd->accelgrp != NULL)
          {
            gtk_accel_group_unref(pd->accelgrp);
            pd->accelgrp = NULL;
          }

#undef DO_DESTROY_WIDGET
      }

      /* Clear progress dialog structure. */
        memset(pd, 0x00, sizeof(progress_dialog_struct));
}

Generated by  Doxygen 1.6.0   Back to index