How to Center Dialogs or Popups Over Any Widget (Source Code Included)



/*
 * One of my biggest complaints about Gtk+-based programs is that
 * popups never popup centered over the correct window.  At best they
 * come up in the middle of the display or over the mouse.  More
 * commonly, they quietly come up in some random location on the
 * display.
 * 
 * The correct way, IMHO, to popup a dialog is to place it in the
 * center of the window responsible for popping it.  The fact that it
 * is centered over the window tells me that, yes, this pop up is part
 * of the program underneath it.  When a dialog popups up over a
 * different program, it is confusing because the program underneath
 * the popup has no relationship with the popup itself.
 * 
 * What follows is an example of how to popup a dialog centered over
 * any widget including a GTK_WINDOW widget.  It also shows how to
 * raise an iconified popup to the same place where it was originally
 * iconified.
 * 
 * If you find a better way of doing this, please let me know.
 * 
 *                                           Paul Serice
 *                                           September 13, 2000
 */


#include <gtk/gtk.h>


static gint dialog_delete_cb(GtkWidget *w, GdkEventAny *data)
{
  gtk_widget_hide(w);
  return 1;
}

static GtkWidget* dialog_instance()
{
  static GtkWidget* dialog = 0;
  if( dialog == 0 ) {
    dialog = gtk_dialog_new();
    if( dialog ) {
      gtk_widget_set_usize(dialog, 100, 100);
      gtk_signal_connect(GTK_OBJECT(dialog),
                         "delete_event",
                         GTK_SIGNAL_FUNC(dialog_delete_cb),
                         NULL);
      gtk_widget_realize(dialog);  /* gdk_window_get_size() needs a window */
    }
  }
  return dialog;
}

static void window_manager_decides_cb(GtkWidget *w, gpointer data)
{
  GtkWidget *dialog;
  dialog = dialog_instance();
  if( dialog ) {
    gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_NONE);
    gtk_widget_show(dialog);
    /*
     * Either I'm not doing something right or I'm not thinking about
     * something right or . . . , but it seems to me that
     * "gtk_widget_show()" should raise iconified windows.  It does
     * not.  So, we have to also call gdk_window_show().
     */
    gdk_window_show(dialog->window);
  }
}

static void center_over_display_cb(GtkWidget *w, gpointer data)
{
  GtkWidget *dialog;
  dialog = dialog_instance();
  if( dialog ) {
    gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER);
    gtk_widget_show(dialog);
    /* See note in window_manager_decides_cb(). */
    gdk_window_show(dialog->window);
  }
}

static void center_over_pointer_cb(GtkWidget *w, gpointer data)
{
  GtkWidget *dialog;
  dialog = dialog_instance();
  if( dialog ) {
    gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_MOUSE);
    gtk_widget_show(dialog);
    /* See note in window_manager_decides_cb(). */
    gdk_window_show(dialog->window);
  }
}

static void center_over_widget_cb(GtkWidget* w, gpointer data)
{
  GtkWidget *dialog;
  GtkWidget *target = GTK_WIDGET(data);
  dialog = dialog_instance();
  if( dialog ) {
    if( !GTK_WIDGET_MAPPED(dialog) ) {
      int x, y, w, h;         /* target's relevant dimensions */
      int dw, dh;             /* popup's relevant dimensions  */
      int centerX, centerY;   /* popup's x and y so that it appears centered */

      gdk_window_get_origin(target->window, &x, &y);
      gdk_window_get_size(target->window, &w, &h);
      gdk_window_get_size(dialog->window, &dw, &dh);
      
      centerX = x + w/2 - dw/2;
      centerY = y + h/2 - dh/2;
      
      gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_NONE);
      gtk_widget_set_uposition(dialog, centerX, centerY);
      gtk_widget_show(dialog);
    }
    /* See note in window_manager_decides_cb(). */
    gdk_window_show(dialog->window);
  }
}

static void destroy_cb (GtkWidget *w, gpointer data)
{
  gtk_main_quit ();
}


int main (int argc, char *argv[])
{
    GtkWidget *win;
    GtkWidget *mainBox;
    GtkWidget *leftBox;      /* spacer */
    GtkWidget *rightBox;     /* spacer */
    GtkWidget *topBox;       /* spacer */
    GtkWidget *bottomBox;    /* spacer */
    GtkWidget *centralBox;
    GtkWidget *eventBox;
    GtkWidget *label;
    GtkWidget *window_manager_decides_button = 0;
    GtkWidget *center_over_display_button = 0;
    GtkWidget *center_over_pointer_button = 0;
    GtkWidget *center_over_widget_button = 0;
    
    gtk_init(&argc, &argv);
    
    win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    gtk_widget_set_usize(win, 480, 360);
    
    gtk_signal_connect(GTK_OBJECT(win),
                       "destroy",
                       GTK_SIGNAL_FUNC(destroy_cb),
                       NULL);

    mainBox = gtk_hbox_new( /* homogeneous */ FALSE, /* spacing */ 0);
    leftBox = gtk_vbox_new( /* homogeneous */ FALSE, /* spacing */ 0);
    rightBox = gtk_vbox_new( /* homogeneous */ FALSE, /* spacing */ 0);
    topBox = gtk_vbox_new( /* homogeneous */ FALSE, /* spacing */ 0);
    bottomBox = gtk_vbox_new( /* homogeneous */ FALSE, /* spacing */ 0);
    centralBox = gtk_vbox_new( /* homogeneous */ FALSE, /* spacing */ 0);

    /*
     * Place "label" in an event box so that a GdkWindow will be
     * associated with the label.
     */
    eventBox = gtk_event_box_new();
    label = gtk_label_new("Center over me");
    gtk_container_add(GTK_CONTAINER(eventBox), label);


    /*
     * Install the control buttons.
     */
    window_manager_decides_button
      = gtk_button_new_with_label("Window Manager Decides");
    gtk_signal_connect(GTK_OBJECT(window_manager_decides_button),
                       "clicked",
                       GTK_SIGNAL_FUNC(window_manager_decides_cb),
                       NULL);
    
    center_over_display_button
      = gtk_button_new_with_label("Center Over Display");
    gtk_signal_connect(GTK_OBJECT(center_over_display_button),
                       "clicked",
                       GTK_SIGNAL_FUNC(center_over_display_cb),
                       NULL);
    
    center_over_pointer_button
      = gtk_button_new_with_label("Center Over Pointer");
    gtk_signal_connect(GTK_OBJECT(center_over_pointer_button),
                       "clicked",
                       GTK_SIGNAL_FUNC(center_over_pointer_cb),
                       NULL);
    
    /*
     * Generally, you will pass in a top-level window as client data.
     * This will let your popup appear centered over the window.  In
     * this example, I'm passing in a label just to show that it does
     * work with any GtkWidget.
     */
    center_over_widget_button
      = gtk_button_new_with_label("Center Over Widget");
    gtk_signal_connect(GTK_OBJECT(center_over_widget_button),
                       "clicked",
                       GTK_SIGNAL_FUNC(center_over_widget_cb),
                       eventBox);

    /*
     * Pack.
     */

    gtk_box_pack_start(GTK_BOX(centralBox), topBox,
                       /* expand */ TRUE, /* fill */ TRUE, /* padding */ 0);
    gtk_box_pack_start(GTK_BOX(centralBox), window_manager_decides_button,
                       /* expand */ FALSE, /* fill */ FALSE, /* padding */ 0);
    gtk_box_pack_start(GTK_BOX(centralBox), center_over_display_button,
                       /* expand */ FALSE, /* fill */ FALSE, /* padding */ 0);
    gtk_box_pack_start(GTK_BOX(centralBox), center_over_pointer_button,
                       /* expand */ FALSE, /* fill */ FALSE, /* padding */ 0);
    gtk_box_pack_start(GTK_BOX(centralBox), center_over_widget_button,
                       /* expand */ FALSE, /* fill */ FALSE, /* padding */ 0);
    gtk_box_pack_start(GTK_BOX(centralBox), bottomBox,
                       /* expand */ TRUE, /* fill */ TRUE, /* padding */ 0);
    gtk_box_pack_start(GTK_BOX(centralBox), eventBox,
                       /* expand */ FALSE, /* fill */ FALSE, /* padding */ 12);

    gtk_box_pack_start(GTK_BOX(mainBox), leftBox,
                       /* expand */ TRUE, /* fill */ TRUE, /* padding */ 0);
    gtk_box_pack_start(GTK_BOX(mainBox), centralBox,
                       /* expand */ FALSE, /* fill */ FALSE, /* padding */ 0);
    gtk_box_pack_start(GTK_BOX(mainBox), rightBox,
                       /* expand */ TRUE, /* fill */ TRUE, /* padding */ 0);

    /*
     * Add.
     */
    gtk_container_add(GTK_CONTAINER(win), mainBox);

    /*
     * Show.
     */
    gtk_widget_show(window_manager_decides_button);
    gtk_widget_show(center_over_display_button);
    gtk_widget_show(center_over_pointer_button);
    gtk_widget_show(center_over_widget_button);
    gtk_widget_show(label);
    gtk_widget_show(eventBox);
    gtk_widget_show(bottomBox);
    gtk_widget_show(topBox);
    gtk_widget_show(centralBox);
    gtk_widget_show(rightBox);
    gtk_widget_show(leftBox);
    gtk_widget_show(mainBox);
    gtk_widget_show(win);
    
    gtk_main();
    
    return 0;
}




[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]