]> Pileus Git - ~andy/gtk/blob - demos/gtk-demo/appwindow.c
63814588018e494c83f023c205cbcdfa8e21efbe
[~andy/gtk] / demos / gtk-demo / appwindow.c
1 /* Application main window
2  *
3  * Demonstrates a typical application window with menubar, toolbar, statusbar.
4  */
5
6 #include <gtk/gtk.h>
7 #include "config.h"
8 #include "demo-common.h"
9
10 static GtkWidget *window = NULL;
11 static GtkWidget *infobar = NULL;
12 static GtkWidget *messagelabel = NULL;
13
14 static void
15 activate_action (GtkAction *action)
16 {
17   const gchar *name = gtk_action_get_name (action);
18   const gchar *typename = G_OBJECT_TYPE_NAME (action);
19
20   GtkWidget *dialog;
21
22   if (g_str_equal (name, "DarkTheme"))
23     {
24       gboolean value = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
25       GtkSettings *settings = gtk_settings_get_default ();
26
27       g_object_set (G_OBJECT (settings),
28                     "gtk-application-prefer-dark-theme", value,
29                     NULL);
30       return;
31     }
32   dialog = gtk_message_dialog_new (GTK_WINDOW (window),
33                                    GTK_DIALOG_DESTROY_WITH_PARENT,
34                                    GTK_MESSAGE_INFO,
35                                    GTK_BUTTONS_CLOSE,
36                                    "You activated action: \"%s\" of type \"%s\"",
37                                     name, typename);
38
39   /* Close dialog on user response */
40   g_signal_connect (dialog,
41                     "response",
42                     G_CALLBACK (gtk_widget_destroy),
43                     NULL);
44
45   gtk_widget_show (dialog);
46 }
47
48 static void
49 activate_radio_action (GtkAction *action, GtkRadioAction *current)
50 {
51   const gchar *name = gtk_action_get_name (GTK_ACTION (current));
52   const gchar *typename = G_OBJECT_TYPE_NAME (GTK_ACTION (current));
53   gboolean active = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (current));
54   gint value = gtk_radio_action_get_current_value (GTK_RADIO_ACTION (current));
55
56   if (active)
57     {
58       gchar *text;
59
60       text = g_strdup_printf ("You activated radio action: \"%s\" of type \"%s\".\n"
61                               "Current value: %d",
62                               name, typename, value);
63       gtk_label_set_text (GTK_LABEL (messagelabel), text);
64       gtk_info_bar_set_message_type (GTK_INFO_BAR (infobar), (GtkMessageType)value);
65       gtk_widget_show (infobar);
66       g_free (text);
67     }
68 }
69
70 static void
71 about_cb (GtkAction *action,
72           GtkWidget *window)
73 {
74   GdkPixbuf *pixbuf, *transparent;
75   gchar *filename;
76
77   const gchar *authors[] = {
78     "Peter Mattis",
79     "Spencer Kimball",
80     "Josh MacDonald",
81     "and many more...",
82     NULL
83   };
84
85   const gchar *documentors[] = {
86     "Owen Taylor",
87     "Tony Gale",
88     "Matthias Clasen <mclasen@redhat.com>",
89     "and many more...",
90     NULL
91   };
92
93   pixbuf = NULL;
94   transparent = NULL;
95   filename = demo_find_file ("gtk-logo-rgb.gif", NULL);
96   if (filename)
97     {
98       pixbuf = gdk_pixbuf_new_from_file (filename, NULL);
99       g_free (filename);
100       transparent = gdk_pixbuf_add_alpha (pixbuf, TRUE, 0xff, 0xff, 0xff);
101       g_object_unref (pixbuf);
102     }
103
104   gtk_show_about_dialog (GTK_WINDOW (window),
105                          "program-name", "GTK+ Code Demos",
106                          "version", g_strdup_printf ("%s,\nRunning against GTK+ %d.%d.%d",
107                                                      PACKAGE_VERSION,
108                                                      gtk_get_major_version (),
109                                                      gtk_get_minor_version (),
110                                                      gtk_get_micro_version ()),
111                          "copyright", "(C) 1997-2009 The GTK+ Team",
112                          "license-type", GTK_LICENSE_LGPL_2_1,
113                          "website", "http://www.gtk.org",
114                          "comments", "Program to demonstrate GTK+ functions.",
115                          "authors", authors,
116                          "documenters", documentors,
117                          "logo", transparent,
118                          "title", "About GTK+ Code Demos",
119                          NULL);
120
121   g_object_unref (transparent);
122 }
123
124 typedef struct
125 {
126   GtkAction action;
127 } ToolMenuAction;
128
129 typedef struct
130 {
131   GtkActionClass parent_class;
132 } ToolMenuActionClass;
133
134 G_DEFINE_TYPE(ToolMenuAction, tool_menu_action, GTK_TYPE_ACTION)
135
136 static void
137 tool_menu_action_class_init (ToolMenuActionClass *class)
138 {
139   GTK_ACTION_CLASS (class)->toolbar_item_type = GTK_TYPE_MENU_TOOL_BUTTON;
140 }
141
142 static void
143 tool_menu_action_init (ToolMenuAction *action)
144 {
145 }
146
147 static GtkActionEntry entries[] = {
148   { "FileMenu", NULL, "_File" },               /* name, stock id, label */
149   { "OpenMenu", NULL, "_Open" },               /* name, stock id, label */
150   { "PreferencesMenu", NULL, "_Preferences" }, /* name, stock id, label */
151   { "ColorMenu", NULL, "_Color"  },            /* name, stock id, label */
152   { "ShapeMenu", NULL, "_Shape" },             /* name, stock id, label */
153   { "HelpMenu", NULL, "_Help" },               /* name, stock id, label */
154   { "New", GTK_STOCK_NEW,                      /* name, stock id */
155     "_New", "<control>N",                      /* label, accelerator */
156     "Create a new file",                       /* tooltip */
157     G_CALLBACK (activate_action) },
158   { "File1", NULL,                             /* name, stock id */
159     "File1", NULL,                             /* label, accelerator */
160     "Open first file",                         /* tooltip */
161     G_CALLBACK (activate_action) },
162   { "Save", GTK_STOCK_SAVE,                    /* name, stock id */
163     "_Save","<control>S",                      /* label, accelerator */
164     "Save current file",                       /* tooltip */
165     G_CALLBACK (activate_action) },
166   { "SaveAs", GTK_STOCK_SAVE,                  /* name, stock id */
167     "Save _As...", NULL,                       /* label, accelerator */
168     "Save to a file",                          /* tooltip */
169     G_CALLBACK (activate_action) },
170   { "Quit", GTK_STOCK_QUIT,                    /* name, stock id */
171     "_Quit", "<control>Q",                     /* label, accelerator */
172     "Quit",                                    /* tooltip */
173     G_CALLBACK (activate_action) },
174   { "About", NULL,                             /* name, stock id */
175     "_About", "<control>A",                    /* label, accelerator */
176     "About",                                   /* tooltip */
177     G_CALLBACK (about_cb) },
178   { "Logo", "demo-gtk-logo",                   /* name, stock id */
179      NULL, NULL,                               /* label, accelerator */
180     "GTK+",                                    /* tooltip */
181     G_CALLBACK (activate_action) },
182 };
183 static guint n_entries = G_N_ELEMENTS (entries);
184
185
186 static GtkToggleActionEntry toggle_entries[] = {
187   { "Bold", GTK_STOCK_BOLD,                    /* name, stock id */
188      "_Bold", "<control>B",                    /* label, accelerator */
189     "Bold",                                    /* tooltip */
190     G_CALLBACK (activate_action),
191     TRUE },                                    /* is_active */
192   { "DarkTheme", NULL,                         /* name, stock id */
193      "_Prefer Dark Theme", NULL,               /* label, accelerator */
194     "Prefer Dark Theme",                       /* tooltip */
195     G_CALLBACK (activate_action),
196     FALSE },                                   /* is_active */
197 };
198 static guint n_toggle_entries = G_N_ELEMENTS (toggle_entries);
199
200 enum {
201   COLOR_RED,
202   COLOR_GREEN,
203   COLOR_BLUE
204 };
205
206 static GtkRadioActionEntry color_entries[] = {
207   { "Red", NULL,                               /* name, stock id */
208     "_Red", "<control>R",                      /* label, accelerator */
209     "Blood", COLOR_RED },                      /* tooltip, value */
210   { "Green", NULL,                             /* name, stock id */
211     "_Green", "<control>G",                    /* label, accelerator */
212     "Grass", COLOR_GREEN },                    /* tooltip, value */
213   { "Blue", NULL,                              /* name, stock id */
214     "_Blue", "<control>B",                     /* label, accelerator */
215     "Sky", COLOR_BLUE },                       /* tooltip, value */
216 };
217 static guint n_color_entries = G_N_ELEMENTS (color_entries);
218
219 enum {
220   SHAPE_SQUARE,
221   SHAPE_RECTANGLE,
222   SHAPE_OVAL
223 };
224
225 static GtkRadioActionEntry shape_entries[] = {
226   { "Square", NULL,                            /* name, stock id */
227     "_Square", "<control>S",                   /* label, accelerator */
228     "Square",  SHAPE_SQUARE },                 /* tooltip, value */
229   { "Rectangle", NULL,                         /* name, stock id */
230     "_Rectangle", "<control>R",                /* label, accelerator */
231     "Rectangle", SHAPE_RECTANGLE },            /* tooltip, value */
232   { "Oval", NULL,                              /* name, stock id */
233     "_Oval", "<control>O",                     /* label, accelerator */
234     "Egg", SHAPE_OVAL },                       /* tooltip, value */
235 };
236 static guint n_shape_entries = G_N_ELEMENTS (shape_entries);
237
238 static const gchar *ui_info =
239 "<ui>"
240 "  <menubar name='MenuBar'>"
241 "    <menu action='FileMenu'>"
242 "      <menuitem action='New'/>"
243 "      <menuitem action='Open'/>"
244 "      <menuitem action='Save'/>"
245 "      <menuitem action='SaveAs'/>"
246 "      <separator/>"
247 "      <menuitem action='Quit'/>"
248 "    </menu>"
249 "    <menu action='PreferencesMenu'>"
250 "      <menuitem action='DarkTheme'/>"
251 "      <menu action='ColorMenu'>"
252 "       <menuitem action='Red'/>"
253 "       <menuitem action='Green'/>"
254 "       <menuitem action='Blue'/>"
255 "      </menu>"
256 "      <menu action='ShapeMenu'>"
257 "        <menuitem action='Square'/>"
258 "        <menuitem action='Rectangle'/>"
259 "        <menuitem action='Oval'/>"
260 "      </menu>"
261 "      <menuitem action='Bold'/>"
262 "    </menu>"
263 "    <menu action='HelpMenu'>"
264 "      <menuitem action='About'/>"
265 "    </menu>"
266 "  </menubar>"
267 "  <toolbar name='ToolBar'>"
268 "    <toolitem action='Open'>"
269 "      <menu action='OpenMenu'>"
270 "        <menuitem action='File1'/>"
271 "      </menu>"
272 "    </toolitem>"
273 "    <toolitem action='Quit'/>"
274 "    <separator action='Sep1'/>"
275 "    <toolitem action='Logo'/>"
276 "  </toolbar>"
277 "</ui>";
278
279
280
281 /* This function registers our custom toolbar icons, so they can be themed.
282  *
283  * It's totally optional to do this, you could just manually insert icons
284  * and have them not be themeable, especially if you never expect people
285  * to theme your app.
286  */
287 static void
288 register_stock_icons (void)
289 {
290   static gboolean registered = FALSE;
291
292   if (!registered)
293     {
294       GdkPixbuf *pixbuf;
295       GtkIconFactory *factory;
296       char *filename;
297
298       static GtkStockItem items[] = {
299         { "demo-gtk-logo",
300           "_GTK!",
301           0, 0, NULL }
302       };
303
304       registered = TRUE;
305
306       /* Register our stock items */
307       gtk_stock_add (items, G_N_ELEMENTS (items));
308
309       /* Add our custom icon factory to the list of defaults */
310       factory = gtk_icon_factory_new ();
311       gtk_icon_factory_add_default (factory);
312
313       /* demo_find_file() looks in the current directory first,
314        * so you can run gtk-demo without installing GTK, then looks
315        * in the location where the file is installed.
316        */
317       pixbuf = NULL;
318       filename = demo_find_file ("gtk-logo-rgb.gif", NULL);
319       if (filename)
320         {
321           pixbuf = gdk_pixbuf_new_from_file (filename, NULL);
322           g_free (filename);
323         }
324
325       /* Register icon to accompany stock item */
326       if (pixbuf != NULL)
327         {
328           GtkIconSet *icon_set;
329           GdkPixbuf *transparent;
330
331           /* The gtk-logo-rgb icon has a white background, make it transparent */
332           transparent = gdk_pixbuf_add_alpha (pixbuf, TRUE, 0xff, 0xff, 0xff);
333
334           icon_set = gtk_icon_set_new_from_pixbuf (transparent);
335           gtk_icon_factory_add (factory, "demo-gtk-logo", icon_set);
336           gtk_icon_set_unref (icon_set);
337           g_object_unref (pixbuf);
338           g_object_unref (transparent);
339         }
340       else
341         g_warning ("failed to load GTK logo for toolbar");
342
343       /* Drop our reference to the factory, GTK will hold a reference. */
344       g_object_unref (factory);
345     }
346 }
347
348 static void
349 update_statusbar (GtkTextBuffer *buffer,
350                   GtkStatusbar  *statusbar)
351 {
352   gchar *msg;
353   gint row, col;
354   gint count;
355   GtkTextIter iter;
356
357   gtk_statusbar_pop (statusbar, 0); /* clear any previous message,
358                                      * underflow is allowed
359                                      */
360
361   count = gtk_text_buffer_get_char_count (buffer);
362
363   gtk_text_buffer_get_iter_at_mark (buffer,
364                                     &iter,
365                                     gtk_text_buffer_get_insert (buffer));
366
367   row = gtk_text_iter_get_line (&iter);
368   col = gtk_text_iter_get_line_offset (&iter);
369
370   msg = g_strdup_printf ("Cursor at row %d column %d - %d chars in document",
371                          row, col, count);
372
373   gtk_statusbar_push (statusbar, 0, msg);
374
375   g_free (msg);
376 }
377
378 static void
379 mark_set_callback (GtkTextBuffer     *buffer,
380                    const GtkTextIter *new_location,
381                    GtkTextMark       *mark,
382                    gpointer           data)
383 {
384   update_statusbar (buffer, GTK_STATUSBAR (data));
385 }
386
387 static void
388 update_resize_grip (GtkWidget           *widget,
389                     GdkEventWindowState *event,
390                     GtkStatusbar        *statusbar)
391 {
392   if (event->changed_mask & (GDK_WINDOW_STATE_MAXIMIZED |
393                              GDK_WINDOW_STATE_FULLSCREEN))
394     {
395       gboolean maximized;
396
397       maximized = event->new_window_state & (GDK_WINDOW_STATE_MAXIMIZED |
398                                              GDK_WINDOW_STATE_FULLSCREEN);
399       gtk_statusbar_set_has_resize_grip (statusbar, !maximized);
400     }
401 }
402
403
404 GtkWidget *
405 do_appwindow (GtkWidget *do_widget)
406 {
407   if (!window)
408     {
409       GtkWidget *table;
410       GtkWidget *statusbar;
411       GtkWidget *contents;
412       GtkWidget *sw;
413       GtkWidget *bar;
414       GtkTextBuffer *buffer;
415       GtkActionGroup *action_group;
416       GtkAction *open_action;
417       GtkUIManager *merge;
418       GError *error = NULL;
419
420       register_stock_icons ();
421
422       /* Create the toplevel window
423        */
424
425       window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
426       gtk_window_set_screen (GTK_WINDOW (window),
427                              gtk_widget_get_screen (do_widget));
428       gtk_window_set_title (GTK_WINDOW (window), "Application Window");
429       gtk_window_set_icon_name (GTK_WINDOW (window), "document-open");
430
431       /* NULL window variable when window is closed */
432       g_signal_connect (window, "destroy",
433                         G_CALLBACK (gtk_widget_destroyed),
434                         &window);
435
436       table = gtk_table_new (1, 5, FALSE);
437
438       gtk_container_add (GTK_CONTAINER (window), table);
439
440       /* Create the menubar and toolbar
441        */
442
443       action_group = gtk_action_group_new ("AppWindowActions");
444       open_action = g_object_new (tool_menu_action_get_type (),
445                                   "name", "Open",
446                                   "label", "_Open",
447                                   "tooltip", "Open a file",
448                                   "stock-id", GTK_STOCK_OPEN,
449                                   NULL);
450       gtk_action_group_add_action (action_group, open_action);
451       g_object_unref (open_action);
452       gtk_action_group_add_actions (action_group,
453                                     entries, n_entries,
454                                     window);
455       gtk_action_group_add_toggle_actions (action_group,
456                                            toggle_entries, n_toggle_entries,
457                                            NULL);
458       gtk_action_group_add_radio_actions (action_group,
459                                           color_entries, n_color_entries,
460                                           COLOR_RED,
461                                           G_CALLBACK (activate_radio_action),
462                                           NULL);
463       gtk_action_group_add_radio_actions (action_group,
464                                           shape_entries, n_shape_entries,
465                                           SHAPE_SQUARE,
466                                           G_CALLBACK (activate_radio_action),
467                                           NULL);
468
469       merge = gtk_ui_manager_new ();
470       g_object_set_data_full (G_OBJECT (window), "ui-manager", merge,
471                               g_object_unref);
472       gtk_ui_manager_insert_action_group (merge, action_group, 0);
473       gtk_window_add_accel_group (GTK_WINDOW (window),
474                                   gtk_ui_manager_get_accel_group (merge));
475
476       if (!gtk_ui_manager_add_ui_from_string (merge, ui_info, -1, &error))
477         {
478           g_message ("building menus failed: %s", error->message);
479           g_error_free (error);
480         }
481
482       bar = gtk_ui_manager_get_widget (merge, "/MenuBar");
483       gtk_widget_show (bar);
484       gtk_table_attach (GTK_TABLE (table),
485                         bar,
486                         /* X direction */          /* Y direction */
487                         0, 1,                      0, 1,
488                         GTK_EXPAND | GTK_FILL,     0,
489                         0,                         0);
490
491       bar = gtk_ui_manager_get_widget (merge, "/ToolBar");
492       gtk_widget_show (bar);
493       gtk_table_attach (GTK_TABLE (table),
494                         bar,
495                         /* X direction */       /* Y direction */
496                         0, 1,                   1, 2,
497                         GTK_EXPAND | GTK_FILL,  0,
498                         0,                      0);
499
500       /* Create document
501        */
502
503       infobar = gtk_info_bar_new ();
504       gtk_widget_set_no_show_all (infobar, TRUE);
505       messagelabel = gtk_label_new ("");
506       gtk_widget_show (messagelabel);
507       gtk_box_pack_start (GTK_BOX (gtk_info_bar_get_content_area (GTK_INFO_BAR (infobar))),
508                           messagelabel,
509                           TRUE, TRUE, 0);
510       gtk_info_bar_add_button (GTK_INFO_BAR (infobar),
511                                GTK_STOCK_OK, GTK_RESPONSE_OK);
512       g_signal_connect (infobar, "response",
513                         G_CALLBACK (gtk_widget_hide), NULL);
514
515       gtk_table_attach (GTK_TABLE (table),
516                         infobar,
517                         /* X direction */       /* Y direction */
518                         0, 1,                   2, 3,
519                         GTK_EXPAND | GTK_FILL,  0,
520                         0,                      0);
521
522       sw = gtk_scrolled_window_new (NULL, NULL);
523
524       gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
525                                       GTK_POLICY_AUTOMATIC,
526                                       GTK_POLICY_AUTOMATIC);
527
528       gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw),
529                                            GTK_SHADOW_IN);
530
531       gtk_table_attach (GTK_TABLE (table),
532                         sw,
533                         /* X direction */       /* Y direction */
534                         0, 1,                   3, 4,
535                         GTK_EXPAND | GTK_FILL,  GTK_EXPAND | GTK_FILL,
536                         0,                      0);
537
538       gtk_window_set_default_size (GTK_WINDOW (window),
539                                    200, 200);
540
541       contents = gtk_text_view_new ();
542       gtk_widget_grab_focus (contents);
543
544       gtk_container_add (GTK_CONTAINER (sw),
545                          contents);
546
547       /* Create statusbar */
548
549       statusbar = gtk_statusbar_new ();
550       gtk_table_attach (GTK_TABLE (table),
551                         statusbar,
552                         /* X direction */       /* Y direction */
553                         0, 1,                   4, 5,
554                         GTK_EXPAND | GTK_FILL,  0,
555                         0,                      0);
556
557       /* Show text widget info in the statusbar */
558       buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (contents));
559       
560       g_signal_connect_object (buffer,
561                                "changed",
562                                G_CALLBACK (update_statusbar),
563                                statusbar,
564                                0);
565
566       g_signal_connect_object (buffer,
567                                "mark_set", /* cursor moved */
568                                G_CALLBACK (mark_set_callback),
569                                statusbar,
570                                0);
571
572       g_signal_connect_object (window,
573                                "window_state_event",
574                                G_CALLBACK (update_resize_grip),
575                                statusbar,
576                                0);
577
578       update_statusbar (buffer, GTK_STATUSBAR (statusbar));
579     }
580
581   if (!gtk_widget_get_visible (window))
582     {
583       gtk_widget_show_all (window);
584     }
585   else
586     {
587       gtk_widget_destroy (window);
588       window = NULL;
589       infobar = NULL;
590       messagelabel = NULL;
591     }
592
593   return window;
594 }
595