1 | |
2 | #include "config.h" |
3 | |
4 | #include <gtk/gtk.h> |
5 | |
6 | typedef GtkApplication DemoApplication; |
7 | typedef GtkApplicationClass DemoApplicationClass; |
8 | |
9 | G_DEFINE_TYPE (DemoApplication, demo_application, GTK_TYPE_APPLICATION) |
10 | |
11 | typedef struct { |
12 | GtkApplicationWindow parent_instance; |
13 | |
14 | GtkWidget *message; |
15 | GtkWidget *infobar; |
16 | GtkWidget *status; |
17 | GtkWidget *; |
18 | GMenuModel *; |
19 | GtkTextBuffer *buffer; |
20 | |
21 | int width; |
22 | int height; |
23 | gboolean maximized; |
24 | gboolean fullscreen; |
25 | } DemoApplicationWindow; |
26 | typedef GtkApplicationWindowClass DemoApplicationWindowClass; |
27 | |
28 | G_DEFINE_TYPE (DemoApplicationWindow, demo_application_window, GTK_TYPE_APPLICATION_WINDOW) |
29 | |
30 | static void create_window (GApplication *app, const char *contents); |
31 | |
32 | static void |
33 | show_action_dialog (GSimpleAction *action) |
34 | { |
35 | const gchar *name; |
36 | GtkWidget *dialog; |
37 | |
38 | name = g_action_get_name (G_ACTION (action)); |
39 | |
40 | dialog = gtk_message_dialog_new (NULL, |
41 | GTK_DIALOG_DESTROY_WITH_PARENT, |
42 | GTK_MESSAGE_INFO, |
43 | GTK_BUTTONS_CLOSE, |
44 | "You activated action: \"%s\"" , |
45 | name); |
46 | |
47 | g_signal_connect (dialog, "response" , |
48 | G_CALLBACK (gtk_widget_destroy), NULL); |
49 | |
50 | gtk_widget_show (dialog); |
51 | } |
52 | |
53 | static void |
54 | show_action_infobar (GSimpleAction *action, |
55 | GVariant *parameter, |
56 | gpointer data) |
57 | { |
58 | DemoApplicationWindow *window = data; |
59 | gchar *text; |
60 | const gchar *name; |
61 | const gchar *value; |
62 | |
63 | name = g_action_get_name (G_ACTION (action)); |
64 | value = g_variant_get_string (parameter, NULL); |
65 | |
66 | text = g_strdup_printf ("You activated radio action: \"%s\".\n" |
67 | "Current value: %s" , name, value); |
68 | gtk_label_set_text (GTK_LABEL (window->message), text); |
69 | gtk_widget_show (window->infobar); |
70 | g_free (text); |
71 | } |
72 | |
73 | static void |
74 | activate_action (GSimpleAction *action, |
75 | GVariant *parameter, |
76 | gpointer user_data) |
77 | { |
78 | show_action_dialog (action); |
79 | } |
80 | |
81 | static void |
82 | activate_new (GSimpleAction *action, |
83 | GVariant *parameter, |
84 | gpointer user_data) |
85 | { |
86 | GApplication *app = user_data; |
87 | |
88 | create_window (app, NULL); |
89 | } |
90 | |
91 | static void |
92 | open_response_cb (GtkNativeDialog *dialog, |
93 | gint response_id, |
94 | gpointer user_data) |
95 | { |
96 | GtkFileChooserNative *native = user_data; |
97 | GApplication *app = g_object_get_data (G_OBJECT (native), "app" ); |
98 | GtkWidget *message_dialog; |
99 | GFile *file; |
100 | char *contents; |
101 | GError *error = NULL; |
102 | |
103 | if (response_id == GTK_RESPONSE_ACCEPT) |
104 | { |
105 | file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (native)); |
106 | |
107 | if (g_file_load_contents (file, NULL, &contents, NULL, NULL, &error)) |
108 | { |
109 | create_window (app, contents); |
110 | g_free (contents); |
111 | } |
112 | else |
113 | { |
114 | message_dialog = gtk_message_dialog_new (NULL, |
115 | GTK_DIALOG_DESTROY_WITH_PARENT, |
116 | GTK_MESSAGE_ERROR, |
117 | GTK_BUTTONS_CLOSE, |
118 | "Error loading file: \"%s\"" , |
119 | error->message); |
120 | g_signal_connect (message_dialog, "response" , |
121 | G_CALLBACK (gtk_widget_destroy), NULL); |
122 | gtk_widget_show (message_dialog); |
123 | g_error_free (error); |
124 | } |
125 | } |
126 | |
127 | gtk_native_dialog_destroy (GTK_NATIVE_DIALOG (native)); |
128 | g_object_unref (native); |
129 | } |
130 | |
131 | |
132 | static void |
133 | activate_open (GSimpleAction *action, |
134 | GVariant *parameter, |
135 | gpointer user_data) |
136 | { |
137 | GApplication *app = user_data; |
138 | GtkFileChooserNative *native; |
139 | |
140 | native = gtk_file_chooser_native_new ("Open File" , |
141 | NULL, |
142 | GTK_FILE_CHOOSER_ACTION_OPEN, |
143 | "_Open" , |
144 | "_Cancel" ); |
145 | |
146 | g_object_set_data_full (G_OBJECT (native), "app" , g_object_ref (app), g_object_unref); |
147 | g_signal_connect (native, |
148 | "response" , |
149 | G_CALLBACK (open_response_cb), |
150 | native); |
151 | |
152 | gtk_native_dialog_show (GTK_NATIVE_DIALOG (native)); |
153 | } |
154 | |
155 | static void |
156 | activate_toggle (GSimpleAction *action, |
157 | GVariant *parameter, |
158 | gpointer user_data) |
159 | { |
160 | GVariant *state; |
161 | |
162 | show_action_dialog (action); |
163 | |
164 | state = g_action_get_state (G_ACTION (action)); |
165 | g_action_change_state (G_ACTION (action), g_variant_new_boolean (!g_variant_get_boolean (state))); |
166 | g_variant_unref (state); |
167 | } |
168 | |
169 | static void |
170 | activate_radio (GSimpleAction *action, |
171 | GVariant *parameter, |
172 | gpointer user_data) |
173 | { |
174 | show_action_infobar (action, parameter, user_data); |
175 | |
176 | g_action_change_state (G_ACTION (action), parameter); |
177 | } |
178 | |
179 | static void |
180 | activate_about (GSimpleAction *action, |
181 | GVariant *parameter, |
182 | gpointer user_data) |
183 | { |
184 | GtkWidget *window = user_data; |
185 | |
186 | const gchar *authors[] = { |
187 | "Peter Mattis" , |
188 | "Spencer Kimball" , |
189 | "Josh MacDonald" , |
190 | "and many more..." , |
191 | NULL |
192 | }; |
193 | |
194 | const gchar *documentors[] = { |
195 | "Owen Taylor" , |
196 | "Tony Gale" , |
197 | "Matthias Clasen <mclasen@redhat.com>" , |
198 | "and many more..." , |
199 | NULL |
200 | }; |
201 | |
202 | gtk_show_about_dialog (GTK_WINDOW (window), |
203 | "program-name" , "GTK+ Code Demos" , |
204 | "version" , g_strdup_printf ("%s,\nRunning against GTK+ %d.%d.%d" , |
205 | PACKAGE_VERSION, |
206 | gtk_get_major_version (), |
207 | gtk_get_minor_version (), |
208 | gtk_get_micro_version ()), |
209 | "copyright" , "(C) 1997-2013 The GTK+ Team" , |
210 | "license-type" , GTK_LICENSE_LGPL_2_1, |
211 | "website" , "http://www.gtk.org" , |
212 | "comments" , "Program to demonstrate GTK+ functions." , |
213 | "authors" , authors, |
214 | "documenters" , documentors, |
215 | "logo-icon-name" , "gtk3-demo" , |
216 | "title" , "About GTK+ Code Demos" , |
217 | NULL); |
218 | } |
219 | |
220 | static void |
221 | activate_quit (GSimpleAction *action, |
222 | GVariant *parameter, |
223 | gpointer user_data) |
224 | { |
225 | GtkApplication *app = user_data; |
226 | GtkWidget *win; |
227 | GList *list, *next; |
228 | |
229 | list = gtk_application_get_windows (app); |
230 | while (list) |
231 | { |
232 | win = list->data; |
233 | next = list->next; |
234 | |
235 | gtk_widget_destroy (GTK_WIDGET (win)); |
236 | |
237 | list = next; |
238 | } |
239 | } |
240 | |
241 | static void |
242 | update_statusbar (GtkTextBuffer *buffer, |
243 | DemoApplicationWindow *window) |
244 | { |
245 | gchar *msg; |
246 | gint row, col; |
247 | gint count; |
248 | GtkTextIter iter; |
249 | |
250 | /* clear any previous message, underflow is allowed */ |
251 | gtk_statusbar_pop (GTK_STATUSBAR (window->status), 0); |
252 | |
253 | count = gtk_text_buffer_get_char_count (buffer); |
254 | |
255 | gtk_text_buffer_get_iter_at_mark (buffer, |
256 | &iter, |
257 | gtk_text_buffer_get_insert (buffer)); |
258 | |
259 | row = gtk_text_iter_get_line (&iter); |
260 | col = gtk_text_iter_get_line_offset (&iter); |
261 | |
262 | msg = g_strdup_printf ("Cursor at row %d column %d - %d chars in document" , |
263 | row, col, count); |
264 | |
265 | gtk_statusbar_push (GTK_STATUSBAR (window->status), 0, msg); |
266 | |
267 | g_free (msg); |
268 | } |
269 | |
270 | static void |
271 | mark_set_callback (GtkTextBuffer *buffer, |
272 | const GtkTextIter *new_location, |
273 | GtkTextMark *mark, |
274 | DemoApplicationWindow *window) |
275 | { |
276 | update_statusbar (buffer, window); |
277 | } |
278 | |
279 | static void |
280 | change_theme_state (GSimpleAction *action, |
281 | GVariant *state, |
282 | gpointer user_data) |
283 | { |
284 | GtkSettings *settings = gtk_settings_get_default (); |
285 | |
286 | g_object_set (G_OBJECT (settings), |
287 | "gtk-application-prefer-dark-theme" , |
288 | g_variant_get_boolean (state), |
289 | NULL); |
290 | |
291 | g_simple_action_set_state (action, state); |
292 | } |
293 | |
294 | static void |
295 | change_titlebar_state (GSimpleAction *action, |
296 | GVariant *state, |
297 | gpointer user_data) |
298 | { |
299 | GtkWindow *window = user_data; |
300 | |
301 | gtk_window_set_hide_titlebar_when_maximized (GTK_WINDOW (window), |
302 | g_variant_get_boolean (state)); |
303 | |
304 | g_simple_action_set_state (action, state); |
305 | } |
306 | |
307 | static void |
308 | change_radio_state (GSimpleAction *action, |
309 | GVariant *state, |
310 | gpointer user_data) |
311 | { |
312 | g_simple_action_set_state (action, state); |
313 | } |
314 | |
315 | static GActionEntry app_entries[] = { |
316 | { "new" , activate_new, NULL, NULL, NULL }, |
317 | { "open" , activate_open, NULL, NULL, NULL }, |
318 | { "save" , activate_action, NULL, NULL, NULL }, |
319 | { "save-as" , activate_action, NULL, NULL, NULL }, |
320 | { "quit" , activate_quit, NULL, NULL, NULL }, |
321 | { "dark" , activate_toggle, NULL, "false" , change_theme_state } |
322 | }; |
323 | |
324 | static GActionEntry win_entries[] = { |
325 | { "titlebar" , activate_toggle, NULL, "false" , change_titlebar_state }, |
326 | { "shape" , activate_radio, "s" , "'oval'" , change_radio_state }, |
327 | { "bold" , activate_toggle, NULL, "false" , NULL }, |
328 | { "about" , activate_about, NULL, NULL, NULL }, |
329 | { "file1" , activate_action, NULL, NULL, NULL }, |
330 | { "logo" , activate_action, NULL, NULL, NULL } |
331 | }; |
332 | |
333 | static void |
334 | clicked_cb (GtkWidget *widget, DemoApplicationWindow *window) |
335 | { |
336 | gtk_widget_hide (window->infobar); |
337 | } |
338 | |
339 | static void |
340 | startup (GApplication *app) |
341 | { |
342 | GtkBuilder *builder; |
343 | GMenuModel *; |
344 | GMenuModel *; |
345 | |
346 | G_APPLICATION_CLASS (demo_application_parent_class)->startup (app); |
347 | |
348 | builder = gtk_builder_new (); |
349 | gtk_builder_add_from_resource (builder, "/application_demo/menus.ui" , NULL); |
350 | |
351 | appmenu = (GMenuModel *)gtk_builder_get_object (builder, "appmenu" ); |
352 | menubar = (GMenuModel *)gtk_builder_get_object (builder, "menubar" ); |
353 | |
354 | gtk_application_set_app_menu (GTK_APPLICATION (app), appmenu); |
355 | gtk_application_set_menubar (GTK_APPLICATION (app), menubar); |
356 | |
357 | g_object_unref (builder); |
358 | } |
359 | |
360 | static void |
361 | create_window (GApplication *app, |
362 | const char *content) |
363 | { |
364 | DemoApplicationWindow *window; |
365 | |
366 | window = (DemoApplicationWindow *)g_object_new (demo_application_window_get_type (), |
367 | "application" , app, |
368 | NULL); |
369 | if (content) |
370 | gtk_text_buffer_set_text (window->buffer, content, -1); |
371 | |
372 | gtk_window_present (GTK_WINDOW (window)); |
373 | } |
374 | |
375 | static void |
376 | activate (GApplication *app) |
377 | { |
378 | create_window (app, NULL); |
379 | } |
380 | |
381 | static void |
382 | demo_application_init (DemoApplication *app) |
383 | { |
384 | GSettings *settings; |
385 | GAction *action; |
386 | |
387 | settings = g_settings_new ("org.gtk.Demo" ); |
388 | |
389 | g_action_map_add_action_entries (G_ACTION_MAP (app), |
390 | app_entries, G_N_ELEMENTS (app_entries), |
391 | app); |
392 | |
393 | action = g_settings_create_action (settings, "color" ); |
394 | |
395 | g_action_map_add_action (G_ACTION_MAP (app), action); |
396 | |
397 | g_object_unref (settings); |
398 | } |
399 | |
400 | static void |
401 | demo_application_class_init (DemoApplicationClass *class) |
402 | { |
403 | GApplicationClass *app_class = G_APPLICATION_CLASS (class); |
404 | |
405 | app_class->startup = startup; |
406 | app_class->activate = activate; |
407 | } |
408 | |
409 | static void |
410 | demo_application_window_store_state (DemoApplicationWindow *win) |
411 | { |
412 | GSettings *settings; |
413 | |
414 | settings = g_settings_new ("org.gtk.Demo" ); |
415 | g_settings_set (settings, "window-size" , "(ii)" , win->width, win->height); |
416 | g_settings_set_boolean (settings, "maximized" , win->maximized); |
417 | g_settings_set_boolean (settings, "fullscreen" , win->fullscreen); |
418 | g_object_unref (settings); |
419 | } |
420 | |
421 | static void |
422 | demo_application_window_load_state (DemoApplicationWindow *win) |
423 | { |
424 | GSettings *settings; |
425 | |
426 | settings = g_settings_new ("org.gtk.Demo" ); |
427 | g_settings_get (settings, "window-size" , "(ii)" , &win->width, &win->height); |
428 | win->maximized = g_settings_get_boolean (settings, "maximized" ); |
429 | win->fullscreen = g_settings_get_boolean (settings, "fullscreen" ); |
430 | g_object_unref (settings); |
431 | } |
432 | |
433 | static void |
434 | demo_application_window_init (DemoApplicationWindow *window) |
435 | { |
436 | GtkWidget *; |
437 | |
438 | window->width = -1; |
439 | window->height = -1; |
440 | window->maximized = FALSE; |
441 | window->fullscreen = FALSE; |
442 | |
443 | gtk_widget_init_template (GTK_WIDGET (window)); |
444 | |
445 | menu = gtk_menu_new_from_model (window->toolmenu); |
446 | gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (window->menutool), menu); |
447 | |
448 | g_action_map_add_action_entries (G_ACTION_MAP (window), |
449 | win_entries, G_N_ELEMENTS (win_entries), |
450 | window); |
451 | } |
452 | |
453 | static void |
454 | demo_application_window_constructed (GObject *object) |
455 | { |
456 | DemoApplicationWindow *window = (DemoApplicationWindow *)object; |
457 | |
458 | demo_application_window_load_state (window); |
459 | |
460 | gtk_window_set_default_size (GTK_WINDOW (window), window->width, window->height); |
461 | |
462 | if (window->maximized) |
463 | gtk_window_maximize (GTK_WINDOW (window)); |
464 | |
465 | if (window->fullscreen) |
466 | gtk_window_fullscreen (GTK_WINDOW (window)); |
467 | |
468 | G_OBJECT_CLASS (demo_application_window_parent_class)->constructed (object); |
469 | } |
470 | |
471 | static void |
472 | demo_application_window_size_allocate (GtkWidget *widget, |
473 | GtkAllocation *allocation) |
474 | { |
475 | DemoApplicationWindow *window = (DemoApplicationWindow *)widget; |
476 | |
477 | GTK_WIDGET_CLASS (demo_application_window_parent_class)->size_allocate (widget, allocation); |
478 | |
479 | if (!window->maximized && !window->fullscreen) |
480 | gtk_window_get_size (GTK_WINDOW (window), &window->width, &window->height); |
481 | } |
482 | |
483 | static gboolean |
484 | demo_application_window_state_event (GtkWidget *widget, |
485 | GdkEventWindowState *event) |
486 | { |
487 | DemoApplicationWindow *window = (DemoApplicationWindow *)widget; |
488 | gboolean res = GDK_EVENT_PROPAGATE; |
489 | |
490 | if (GTK_WIDGET_CLASS (demo_application_window_parent_class)->window_state_event) |
491 | res = GTK_WIDGET_CLASS (demo_application_window_parent_class)->window_state_event (widget, event); |
492 | |
493 | window->maximized = (event->new_window_state & GDK_WINDOW_STATE_MAXIMIZED) != 0; |
494 | window->fullscreen = (event->new_window_state & GDK_WINDOW_STATE_FULLSCREEN) != 0; |
495 | |
496 | return res; |
497 | } |
498 | |
499 | static void |
500 | demo_application_window_destroy (GtkWidget *widget) |
501 | { |
502 | DemoApplicationWindow *window = (DemoApplicationWindow *)widget; |
503 | |
504 | demo_application_window_store_state (window); |
505 | |
506 | GTK_WIDGET_CLASS (demo_application_window_parent_class)->destroy (widget); |
507 | } |
508 | |
509 | static void |
510 | demo_application_window_class_init (DemoApplicationWindowClass *class) |
511 | { |
512 | GObjectClass *object_class = G_OBJECT_CLASS (class); |
513 | GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class); |
514 | |
515 | object_class->constructed = demo_application_window_constructed; |
516 | |
517 | widget_class->size_allocate = demo_application_window_size_allocate; |
518 | widget_class->window_state_event = demo_application_window_state_event; |
519 | widget_class->destroy = demo_application_window_destroy; |
520 | |
521 | gtk_widget_class_set_template_from_resource (widget_class, "/application_demo/application.ui" ); |
522 | gtk_widget_class_bind_template_child (widget_class, DemoApplicationWindow, message); |
523 | gtk_widget_class_bind_template_child (widget_class, DemoApplicationWindow, infobar); |
524 | gtk_widget_class_bind_template_child (widget_class, DemoApplicationWindow, status); |
525 | gtk_widget_class_bind_template_child (widget_class, DemoApplicationWindow, buffer); |
526 | gtk_widget_class_bind_template_child (widget_class, DemoApplicationWindow, menutool); |
527 | gtk_widget_class_bind_template_child (widget_class, DemoApplicationWindow, toolmenu); |
528 | gtk_widget_class_bind_template_callback (widget_class, clicked_cb); |
529 | gtk_widget_class_bind_template_callback (widget_class, update_statusbar); |
530 | gtk_widget_class_bind_template_callback (widget_class, mark_set_callback); |
531 | } |
532 | |
533 | int |
534 | main (int argc, char *argv[]) |
535 | { |
536 | GtkApplication *app; |
537 | |
538 | app = GTK_APPLICATION (g_object_new (demo_application_get_type (), |
539 | "application-id" , "org.gtk.Demo2" , |
540 | "flags" , G_APPLICATION_HANDLES_OPEN, |
541 | NULL)); |
542 | |
543 | return g_application_run (G_APPLICATION (app), 0, NULL); |
544 | } |
545 | |