~canonical-dx-team/ubuntu/maverick/gtk+2.0/menuproxy

« back to all changes in this revision

Viewing changes to demos/gtk-demo/changedisplay.c

  • Committer: Bazaar Package Importer
  • Author(s): Sebastien Bacher
  • Date: 2007-05-04 12:24:25 UTC
  • mfrom: (1.1.21 upstream)
  • Revision ID: james.westby@ubuntu.com-20070504122425-0m8midgzrp40y8w2
Tags: 2.10.12-1ubuntu1
* Sync with Debian
* New upstream version:
  Fixed bugs:
  - 379414 file chooser warnings when changing path in the entry
  - 418585 GtkFileChooserDefault sizing code is not DPI independent
  - 419568 Crash in search if start with special letter
  - 435062 build dies with icon cache validation
  - 379399 Segfault to call gtk_print_operation_run twice.
  - 387889 cups backend has problems when there are too many printers
  - 418531 invalid read to gtkicontheme.c gtk_icon_theme_lookup_icon...
  - 423916 crash in color scheme code
  - 424042 Segmentation fault while quickly pressing Alt+arrows
  - 415260 Protect against negative indices when setting values in G...
  - 419171 XGetVisualInfo() may not set nxvisuals
  - 128852 Gdk cursors don't look good on win32
  - 344657 Ctrl-H doesn't toggle "Show Hidden Files" setting
  - 345345 PrintOperation::paginate is not emitted for class handler
  - 347567 GtkPrintOperation::end-print is not emitted if it's cance...
  - 369112 gtk_ui_manager_add_ui should accept unnamed separator
  - 392015 Selected menu item invisible on Windows Vista
  - 399253 MS-Windows Theme Bottom Tab placement rendering glitches
  - 399425 gtk_input_dialog_fill_axes() adds child to gtkscrolledwin...
  - 403251 [patch] little memory leak in GtkPrintJob
  - 403267 [patch] memory leak in GtkPageSetupUnixDialog
  - 403470 MS-Windows Theme tab placement other than on top leaks a ...
  - 404506 Windows system fonts that have multi-byte font names cann...
  - 405089 Incorrect window placement for GtkEventBox private window
  - 405515 Minor leak in gtkfilesystemmodel.c
  - 405539 gdk_pixbuf_save() for PNG saver can return FALSE without ...
  - 415681 gdk_window_clear_area includes an extra line and column o...
  - 418219 GtkRecentChooser should apply filter before sorting and c...
  - 418403 Scroll to printer after selecting it from settings
  - 421985 _gtk_print_operation_platform_backend_launch_preview
  - 421990 gtk_print_job_get_surface
  - 421993 gtk_print_operation_init
  - 423064 Conditional jump or move depends on uninitialised value(s...
  - 423722 Fix printing header in gtk-demo
  - 424168 gtk_print_operation_run on async preview
  - 425655 Don't install gtk+-unix-print-2.0.pc on non-UNIX platforms
  - 425786 GDK segfaults if XineramaQueryScreens fails
  - 428665 Lpr Backend gets stuck in infinite loop during gtk_enumer...
  - 429902 GtkPrintOperation leaks cairo contextes
  - 431997 First delay of GdkPixbufAnimationIter is wrong
  - 433242 Inconsistent scroll arrow position calculations
  - 433972 Placing gtk.Expander inside a gtk.TextView() changes gtk....
  - 434261 _gtk_toolbar_elide_underscores incorrectly handles some s...
  - 383354 ctrl-L should make 'Location' entry disappear
  - 418673 gtk_recent_manager_add_item
  - 429732 gtk_accel_group_finalize accesses invalid memory
  - 435028 WM_CLIENT_LEADER is wrong on the leader_window
  - 431067 Background of the header window is not updated
  - 338843 add recent files support inside the ui manager
  - 148535 add drop shadow to menus, tooltips, etc. under Windows XP
* debian/control.in:
  - Conflicts on ubuntulooks (<= 0.9.11-1)
* debian/patches/15_default-fallback-icon-theme.patch:
  - patch from Debian, fallback on gnome icon theme

Show diffs side-by-side

added added

removed removed

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