home *** CD-ROM | disk | FTP | other *** search
/ Freelog 65 / Freelog065.iso / BAS / Bureautique / Gnumeric / gnumeric-1.3.92-rc1.exe / changedisplay.c < prev    next >
C/C++ Source or Header  |  2004-10-15  |  18KB  |  629 lines

  1. /* Change Display
  2.  * 
  3.  * Demonstrates migrating a window between different displays and
  4.  * screens. A display is a mouse and keyboard with some number of
  5.  * associated monitors. A screen is a set of monitors grouped
  6.  * into a single physical work area. The neat thing about having
  7.  * multiple displays is that they can be on a completely separate
  8.  * computers, as long as there is a network connection to the
  9.  * computer where the application is running.
  10.  *
  11.  * Only some of the windowing systems where GTK+ runs have the
  12.  * concept of multiple displays and screens. (The X Window System
  13.  * is the main example.) Other windowing systems can only
  14.  * handle one keyboard and mouse, and combine all monitors into
  15.  * a single screen.
  16.  *
  17.  * This is a moderately complex example, and demonstrates:
  18.  *
  19.  *  - Tracking the currently open displays and screens
  20.  *
  21.  *  - Changing the screen for a window
  22.  *
  23.  *  - Letting the user choose a window by clicking on it
  24.  * 
  25.  *  - Using GtkListStore and GtkTreeView
  26.  *
  27.  *  - Using GtkDialog
  28.  */
  29. #include <config.h>
  30. #include <string.h>
  31. #include <gtk/gtk.h>
  32. #include "demo-common.h"
  33.  
  34. /* The ChangeDisplayInfo structure corresponds to a toplevel window and
  35.  * holds pointers to widgets inside the toplevel window along with other
  36.  * information about the contents of the window.
  37.  * This is a common organizational structure in real applications.
  38.  */
  39. typedef struct _ChangeDisplayInfo ChangeDisplayInfo;
  40.  
  41. struct _ChangeDisplayInfo
  42. {
  43.   GtkWidget *window;
  44.   GtkSizeGroup *size_group;
  45.  
  46.   GtkTreeModel *display_model;
  47.   GtkTreeModel *screen_model;
  48.   GtkTreeSelection *screen_selection;
  49.   
  50.   GdkDisplay *current_display;
  51.   GdkScreen *current_screen;
  52. };
  53.  
  54. /* These enumerations provide symbolic names for the columns
  55.  * in the two GtkListStore models.
  56.  */
  57. enum
  58. {
  59.   DISPLAY_COLUMN_NAME,
  60.   DISPLAY_COLUMN_DISPLAY,
  61.   DISPLAY_NUM_COLUMNS
  62. };
  63.  
  64. enum
  65. {
  66.   SCREEN_COLUMN_NUMBER,
  67.   SCREEN_COLUMN_SCREEN,
  68.   SCREEN_NUM_COLUMNS
  69. };
  70.  
  71. /* Finds the toplevel window under the mouse pointer, if any.
  72.  */
  73. static GtkWidget *
  74. find_toplevel_at_pointer (GdkDisplay *display)
  75. {
  76.   GdkWindow *pointer_window;
  77.   GtkWidget *widget = NULL;
  78.  
  79.   pointer_window = gdk_display_get_window_at_pointer (display, NULL, NULL);
  80.  
  81.   /* The user data field of a GdkWindow is used to store a pointer
  82.    * to the widget that created it.
  83.    */
  84.   if (pointer_window)
  85.     gdk_window_get_user_data (pointer_window, (gpointer*) &widget);
  86.  
  87.   return widget ? gtk_widget_get_toplevel (widget) : NULL;
  88. }
  89.  
  90. static gboolean
  91. button_release_event_cb (GtkWidget       *widget,
  92.              GdkEventButton  *event,
  93.              gboolean        *clicked)
  94. {
  95.   *clicked = TRUE;
  96.   return TRUE;
  97. }
  98.  
  99. /* Asks the user to click on a window, then waits for them click
  100.  * the mouse. When the mouse is released, returns the toplevel
  101.  * window under the pointer, or NULL, if there is none.
  102.  */
  103. static GtkWidget *
  104. query_for_toplevel (GdkScreen  *screen,
  105.             const char *prompt)
  106. {
  107.   GdkDisplay *display = gdk_screen_get_display (screen);
  108.   GtkWidget *popup, *label, *frame;
  109.   GdkCursor *cursor;
  110.   GtkWidget *toplevel = NULL;
  111.   
  112.   popup = gtk_window_new (GTK_WINDOW_POPUP);
  113.   gtk_window_set_screen (GTK_WINDOW (popup), screen);
  114.   gtk_window_set_modal (GTK_WINDOW (popup), TRUE);
  115.   gtk_window_set_position (GTK_WINDOW (popup), GTK_WIN_POS_CENTER);
  116.   
  117.   frame = gtk_frame_new (NULL);
  118.   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_OUT);
  119.   gtk_container_add (GTK_CONTAINER (popup), frame);
  120.   
  121.   label = gtk_label_new (prompt);
  122.   gtk_misc_set_padding (GTK_MISC (label), 10, 10);
  123.   gtk_container_add (GTK_CONTAINER (frame), label);
  124.   
  125.   gtk_widget_show_all (popup);
  126.   cursor = gdk_cursor_new_for_display (display, GDK_CROSSHAIR);
  127.   
  128.   if (gdk_pointer_grab (popup->window, FALSE,
  129.             GDK_BUTTON_RELEASE_MASK,
  130.             NULL,
  131.             cursor,
  132.             GDK_CURRENT_TIME) == GDK_GRAB_SUCCESS)
  133.     {
  134.       gboolean clicked = FALSE;
  135.       
  136.       g_signal_connect (popup, "button-release-event",
  137.             G_CALLBACK (button_release_event_cb), &clicked);
  138.       
  139.       /* Process events until clicked is set by button_release_event_cb.
  140.        * We pass in may_block=TRUE since we want to wait if there
  141.        * are no events currently.
  142.        */
  143.       while (!clicked)
  144.     g_main_context_iteration (NULL, TRUE);
  145.       
  146.       toplevel = find_toplevel_at_pointer (gdk_screen_get_display (screen));
  147.       if (toplevel == popup)
  148.     toplevel = NULL;
  149.     }
  150.       
  151.   gdk_cursor_unref (cursor);
  152.   gtk_widget_destroy (popup);
  153.   gdk_flush ();            /* Really release the grab */
  154.   
  155.   return toplevel;
  156. }
  157.  
  158. /* Prompts the user for a toplevel window to move, and then moves
  159.  * that window to the currently selected display
  160.  */
  161. static void
  162. query_change_display (ChangeDisplayInfo *info)
  163. {
  164.   GdkScreen *screen = gtk_widget_get_screen (info->window);
  165.   GtkWidget *toplevel;
  166.  
  167.   toplevel = query_for_toplevel (screen,
  168.                  "Please select the toplevel\n"
  169.                  "to move to the new screen");
  170.  
  171.   if (toplevel)
  172.     gtk_window_set_screen (GTK_WINDOW (toplevel), info->current_screen);
  173.   else
  174.     gdk_display_beep (gdk_screen_get_display (screen));
  175. }
  176.  
  177. /* Fills in the screen list based on the current display
  178.  */
  179. static void
  180. fill_screens (ChangeDisplayInfo *info)
  181. {
  182.   gtk_list_store_clear (GTK_LIST_STORE (info->screen_model));
  183.  
  184.   if (info->current_display)
  185.     {
  186.       gint n_screens = gdk_display_get_n_screens (info->current_display);
  187.       gint i;
  188.       
  189.       for (i = 0; i < n_screens; i++)
  190.     {
  191.       GdkScreen *screen = gdk_display_get_screen (info->current_display, i);
  192.       GtkTreeIter iter;
  193.       
  194.       gtk_list_store_append (GTK_LIST_STORE (info->screen_model), &iter);
  195.       gtk_list_store_set (GTK_LIST_STORE (info->screen_model), &iter,
  196.                   SCREEN_COLUMN_NUMBER, i,
  197.                   SCREEN_COLUMN_SCREEN, screen,
  198.                   -1);
  199.  
  200.       if (i == 0)
  201.         gtk_tree_selection_select_iter (info->screen_selection, &iter);
  202.     }
  203.     }
  204. }
  205.  
  206. /* Called when the user clicks on a button in our dialog or
  207.  * closes the dialog through the window manager. Unless the
  208.  * "Change" button was clicked, we destroy the dialog.
  209.  */
  210. static void
  211. response_cb (GtkDialog         *dialog,
  212.          gint               response_id,
  213.          ChangeDisplayInfo *info)
  214. {
  215.   if (response_id == GTK_RESPONSE_OK)
  216.     query_change_display (info);
  217.   else
  218.     gtk_widget_destroy (GTK_WIDGET (dialog));
  219. }
  220.  
  221. /* Called when the user clicks on "Open..." in the display
  222.  * frame. Prompts for a new display, and then opens a connection
  223.  * to that display.
  224.  */
  225. static void
  226. open_display_cb (GtkWidget         *button,
  227.          ChangeDisplayInfo *info)
  228. {
  229.   GtkWidget *dialog;
  230.   GtkWidget *display_entry;
  231.   GtkWidget *dialog_label;
  232.   gchar *new_screen_name = NULL;
  233.   GdkDisplay *result = NULL;
  234.   
  235.   dialog = gtk_dialog_new_with_buttons ("Open Display",
  236.                     GTK_WINDOW (info->window),
  237.                     GTK_DIALOG_MODAL,
  238.                     GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
  239.                     GTK_STOCK_OK, GTK_RESPONSE_OK,
  240.                     NULL);
  241.  
  242.   gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
  243.   display_entry = gtk_entry_new ();
  244.   gtk_entry_set_activates_default (GTK_ENTRY (display_entry), TRUE);
  245.   dialog_label =
  246.     gtk_label_new ("Please enter the name of\nthe new display\n");
  247.  
  248.   gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), dialog_label);
  249.   gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), display_entry);
  250.  
  251.   gtk_widget_grab_focus (display_entry);
  252.   gtk_widget_show_all (GTK_BIN (dialog)->child);
  253.   
  254.   while (!result)
  255.     {
  256.       gint response_id = gtk_dialog_run (GTK_DIALOG (dialog));
  257.       if (response_id != GTK_RESPONSE_OK)
  258.     break;
  259.       
  260.       new_screen_name = gtk_editable_get_chars (GTK_EDITABLE (display_entry),
  261.                         0, -1);
  262.  
  263.       if (strcmp (new_screen_name, "") != 0)
  264.     {
  265.       result = gdk_display_open (new_screen_name);
  266.       if (!result)
  267.         {
  268.           gchar *error_msg =
  269.         g_strdup_printf  ("Can't open display :\n\t%s\nplease try another one\n",
  270.                   new_screen_name);
  271.           gtk_label_set_text (GTK_LABEL (dialog_label), error_msg);
  272.           g_free (error_msg);
  273.         }
  274.  
  275.       g_free (new_screen_name);
  276.     }
  277.     }
  278.   
  279.   gtk_widget_destroy (dialog);
  280. }
  281.  
  282. /* Called when the user clicks on the "Close" button in the
  283.  * "Display" frame. Closes the selected display.
  284.  */
  285. static void
  286. close_display_cb (GtkWidget         *button,
  287.           ChangeDisplayInfo *info)
  288. {
  289.   if (info->current_display)
  290.     gdk_display_close (info->current_display);
  291. }
  292.  
  293. /* Called when the selected row in the display list changes.
  294.  * Updates info->current_display, then refills the list of
  295.  * screens.
  296.  */
  297. static void
  298. display_changed_cb (GtkTreeSelection  *selection,
  299.             ChangeDisplayInfo *info)
  300. {
  301.   GtkTreeModel *model;
  302.   GtkTreeIter iter;
  303.  
  304.   if (gtk_tree_selection_get_selected (selection, &model, &iter))
  305.     gtk_tree_model_get (model, &iter,
  306.             DISPLAY_COLUMN_DISPLAY, &info->current_display,
  307.             -1);
  308.   else
  309.     info->current_display = NULL;
  310.  
  311.   fill_screens (info);
  312. }
  313.  
  314. /* Called when the selected row in the sceen list changes.
  315.  * Updates info->current_screen.
  316.  */
  317. static void
  318. screen_changed_cb (GtkTreeSelection  *selection,
  319.            ChangeDisplayInfo *info)
  320. {
  321.   GtkTreeModel *model;
  322.   GtkTreeIter iter;
  323.  
  324.   if (gtk_tree_selection_get_selected (selection, &model, &iter))
  325.     gtk_tree_model_get (model, &iter,
  326.             SCREEN_COLUMN_SCREEN, &info->current_screen,
  327.             -1);
  328.   else
  329.     info->current_screen = NULL;
  330. }
  331.  
  332. /* This function is used both for creating the "Display" and
  333.  * "Screen" frames, since they have a similar structure. The
  334.  * caller hooks up the right context for the value returned
  335.  * in tree_view, and packs any relevant buttons into button_vbox.
  336.  */
  337. static void
  338. create_frame (ChangeDisplayInfo *info,
  339.           const char        *title,
  340.           GtkWidget        **frame,
  341.           GtkWidget        **tree_view,
  342.           GtkWidget        **button_vbox)
  343. {
  344.   GtkTreeSelection *selection;
  345.   GtkWidget *scrollwin;
  346.   GtkWidget *hbox;
  347.   
  348.   *frame = gtk_frame_new (title);
  349.  
  350.   hbox = gtk_hbox_new (FALSE, 8);
  351.   gtk_container_set_border_width (GTK_CONTAINER (hbox), 8);
  352.   gtk_container_add (GTK_CONTAINER (*frame), hbox);
  353.  
  354.   scrollwin = gtk_scrolled_window_new (NULL, NULL);
  355.   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrollwin),
  356.                   GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
  357.   gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrollwin),
  358.                        GTK_SHADOW_IN);
  359.   gtk_box_pack_start (GTK_BOX (hbox), scrollwin, TRUE, TRUE, 0);
  360.  
  361.   *tree_view = gtk_tree_view_new ();
  362.   gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (*tree_view), FALSE);
  363.   gtk_container_add (GTK_CONTAINER (scrollwin), *tree_view);
  364.  
  365.   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (*tree_view));
  366.   gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE);
  367.  
  368.   *button_vbox = gtk_vbox_new (FALSE, 5);
  369.   gtk_box_pack_start (GTK_BOX (hbox), *button_vbox, FALSE, FALSE, 0);
  370.  
  371.   if (!info->size_group)
  372.     info->size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
  373.   
  374.   gtk_size_group_add_widget (GTK_SIZE_GROUP (info->size_group), *button_vbox);
  375. }
  376.  
  377. /* If we have a stack of buttons, it often looks better if their contents
  378.  * are left-aligned, rather than centered. This function creates a button
  379.  * and left-aligns it contents.
  380.  */
  381. GtkWidget *
  382. left_align_button_new (const char *label)
  383. {
  384.   GtkWidget *button = gtk_button_new_with_mnemonic (label);
  385.   GtkWidget *child = gtk_bin_get_child (GTK_BIN (button));
  386.  
  387.   gtk_misc_set_alignment (GTK_MISC (child), 0., 0.5);
  388.  
  389.   return button;
  390. }
  391.  
  392. /* Creates the "Display" frame in the main window.
  393.  */
  394. GtkWidget *
  395. create_display_frame (ChangeDisplayInfo *info)
  396. {
  397.   GtkWidget *frame;
  398.   GtkWidget *tree_view;
  399.   GtkWidget *button_vbox;
  400.   GtkTreeViewColumn *column;
  401.   GtkTreeSelection *selection;
  402.   GtkWidget *button;
  403.  
  404.   create_frame (info, "Display", &frame, &tree_view, &button_vbox);
  405.  
  406.   button = left_align_button_new ("_Open...");
  407.   g_signal_connect (button, "clicked",  G_CALLBACK (open_display_cb), info);
  408.   gtk_box_pack_start (GTK_BOX (button_vbox), button, FALSE, FALSE, 0);
  409.   
  410.   button = left_align_button_new ("_Close");
  411.   g_signal_connect (button, "clicked",  G_CALLBACK (close_display_cb), info);
  412.   gtk_box_pack_start (GTK_BOX (button_vbox), button, FALSE, FALSE, 0);
  413.  
  414.   info->display_model = (GtkTreeModel *)gtk_list_store_new (DISPLAY_NUM_COLUMNS,
  415.                                 G_TYPE_STRING,
  416.                                 GDK_TYPE_DISPLAY);
  417.  
  418.   gtk_tree_view_set_model (GTK_TREE_VIEW (tree_view), info->display_model);
  419.  
  420.   column = gtk_tree_view_column_new_with_attributes ("Name",
  421.                              gtk_cell_renderer_text_new (),
  422.                              "text", DISPLAY_COLUMN_NAME,
  423.                              NULL);
  424.   gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), column);
  425.  
  426.   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view));
  427.   g_signal_connect (selection, "changed",
  428.             G_CALLBACK (display_changed_cb), info);
  429.  
  430.   return frame;
  431. }
  432.  
  433. /* Creates the "Screen" frame in the main window.
  434.  */
  435. GtkWidget *
  436. create_screen_frame (ChangeDisplayInfo *info)
  437. {
  438.   GtkWidget *frame;
  439.   GtkWidget *tree_view;
  440.   GtkWidget *button_vbox;
  441.   GtkTreeViewColumn *column;
  442.  
  443.   create_frame (info, "Screen", &frame, &tree_view, &button_vbox);
  444.  
  445.   info->screen_model = (GtkTreeModel *)gtk_list_store_new (SCREEN_NUM_COLUMNS,
  446.                                G_TYPE_INT,
  447.                                GDK_TYPE_SCREEN);
  448.  
  449.   gtk_tree_view_set_model (GTK_TREE_VIEW (tree_view), info->screen_model);
  450.  
  451.   column = gtk_tree_view_column_new_with_attributes ("Number",
  452.                              gtk_cell_renderer_text_new (),
  453.                              "text", SCREEN_COLUMN_NUMBER,
  454.                              NULL);
  455.   gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), column);
  456.  
  457.   info->screen_selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view));
  458.   g_signal_connect (info->screen_selection, "changed",
  459.             G_CALLBACK (screen_changed_cb), info);
  460.  
  461.   return frame;
  462. }
  463.  
  464. /* Called when one of the currently open displays is closed.
  465.  * Remove it from our list of displays.
  466.  */
  467. static void
  468. display_closed_cb (GdkDisplay        *display,
  469.            gboolean           is_error,
  470.            ChangeDisplayInfo *info)
  471. {
  472.   GtkTreeIter iter;
  473.   gboolean valid;
  474.  
  475.   for (valid = gtk_tree_model_get_iter_first (info->display_model, &iter);
  476.        valid;
  477.        valid = gtk_tree_model_iter_next (info->display_model, &iter))
  478.     {
  479.       GdkDisplay *tmp_display;
  480.       
  481.       gtk_tree_model_get (info->display_model, &iter,
  482.               DISPLAY_COLUMN_DISPLAY, &tmp_display,
  483.               -1);
  484.       if (tmp_display == display)
  485.     {
  486.       gtk_list_store_remove (GTK_LIST_STORE (info->display_model), &iter);
  487.       break;
  488.     }
  489.     }
  490. }
  491.  
  492. /* Adds a new display to our list of displays, and connects
  493.  * to the "closed" signal so that we can remove it from the
  494.  * list of displays again.
  495.  */
  496. static void
  497. add_display (ChangeDisplayInfo *info,
  498.          GdkDisplay        *display)
  499. {
  500.   const gchar *name = gdk_display_get_name (display);
  501.   GtkTreeIter iter;
  502.   
  503.   gtk_list_store_append (GTK_LIST_STORE (info->display_model), &iter);
  504.   gtk_list_store_set (GTK_LIST_STORE (info->display_model), &iter,
  505.               DISPLAY_COLUMN_NAME, name,
  506.               DISPLAY_COLUMN_DISPLAY, display,
  507.               -1);
  508.  
  509.   g_signal_connect (display, "closed",
  510.             G_CALLBACK (display_closed_cb), info); 
  511. }
  512.  
  513. /* Called when a new display is opened
  514.  */
  515. static void
  516. display_opened_cb (GdkDisplayManager *manager,
  517.            GdkDisplay        *display,
  518.            ChangeDisplayInfo *info)
  519. {
  520.   add_display (info, display);
  521. }
  522.  
  523. /* Adds all currently open displays to our list of displays,
  524.  * and set up a signal connection so that we'll be notified
  525.  * when displays are opened in the future as well.
  526.  */
  527. static void
  528. initialize_displays (ChangeDisplayInfo *info)
  529. {
  530.   GdkDisplayManager *manager = gdk_display_manager_get ();
  531.   GSList *displays = gdk_display_manager_list_displays (manager);
  532.   GSList *tmp_list;
  533.  
  534.   for (tmp_list = displays; tmp_list; tmp_list = tmp_list->next)
  535.     add_display (info, tmp_list->data);
  536.  
  537.   g_slist_free (tmp_list);
  538.  
  539.   g_signal_connect (manager, "display_opened",
  540.             G_CALLBACK (display_opened_cb), info);
  541. }
  542.  
  543. /* Cleans up when the toplevel is destroyed; we remove the
  544.  * connections we use to track currently open displays, then
  545.  * free the ChangeDisplayInfo structure.
  546.  */
  547. static void
  548. destroy_info (ChangeDisplayInfo *info)
  549. {
  550.   GdkDisplayManager *manager = gdk_display_manager_get ();
  551.   GSList *displays = gdk_display_manager_list_displays (manager);
  552.   GSList *tmp_list;
  553.  
  554.   g_signal_handlers_disconnect_by_func (manager,
  555.                     display_opened_cb,
  556.                     info);
  557.  
  558.   for (tmp_list = displays; tmp_list; tmp_list = tmp_list->next)
  559.     g_signal_handlers_disconnect_by_func (tmp_list->data,
  560.                       display_closed_cb,
  561.                       info);
  562.   
  563.   g_slist_free (tmp_list);
  564.  
  565.   g_object_unref (info->size_group);
  566.   g_free (info);
  567. }
  568.  
  569. static void
  570. destroy_cb (GtkObject          *object,
  571.         ChangeDisplayInfo **info)
  572. {
  573.   destroy_info (*info);
  574.   *info = NULL;
  575. }
  576.  
  577. /* Main entry point. If the dialog for this demo doesn't yet exist, creates
  578.  * it. Otherwise, destroys it.
  579.  */
  580. GtkWidget *
  581. do_changedisplay (GtkWidget *do_widget)
  582. {
  583.   static ChangeDisplayInfo *info = NULL;
  584.  
  585.   if (!info)
  586.     {
  587.       GtkWidget *vbox;
  588.       GtkWidget *frame;
  589.  
  590.       info = g_new0 (ChangeDisplayInfo, 1);
  591.  
  592.       info->window = gtk_dialog_new_with_buttons ("Change Screen or display",
  593.                         GTK_WINDOW (do_widget), 
  594.                         GTK_DIALOG_NO_SEPARATOR,
  595.                         GTK_STOCK_CLOSE,  GTK_RESPONSE_CLOSE,
  596.                         "Change",         GTK_RESPONSE_OK,
  597.                         NULL);
  598.  
  599.       gtk_window_set_default_size (GTK_WINDOW (info->window), 300, 400);
  600.  
  601.       g_signal_connect (info->window, "response",
  602.             G_CALLBACK (response_cb), info);
  603.       g_signal_connect (info->window, "destroy",
  604.             G_CALLBACK (destroy_cb), &info);
  605.  
  606.       vbox = gtk_vbox_new (FALSE, 5);
  607.       gtk_container_set_border_width (GTK_CONTAINER (vbox), 8);
  608.     
  609.       gtk_box_pack_start (GTK_BOX (GTK_DIALOG (info->window)->vbox), vbox,
  610.               TRUE, TRUE, 0);
  611.  
  612.       frame = create_display_frame (info);
  613.       gtk_box_pack_start (GTK_BOX (vbox), frame, TRUE, TRUE, 0);
  614.       
  615.       frame = create_screen_frame (info);
  616.       gtk_box_pack_start (GTK_BOX (vbox), frame, TRUE, TRUE, 0);
  617.  
  618.       initialize_displays (info);
  619.  
  620.       gtk_widget_show_all (info->window);
  621.       return info->window;
  622.     }
  623.   else
  624.     {
  625.       gtk_widget_destroy (info->window);
  626.       return NULL;
  627.     }
  628. }
  629.