1#include <stdlib.h>
2#include <gtk/gtk.h>
3#include <string.h>
4
5
6static const char *red_css =
7"textview {"
8" color: red;"
9"}";
10
11static const char *black_css =
12"textview {"
13" color: black;"
14"}";
15
16static void
17activate_toggle (GSimpleAction *action,
18 GVariant *parameter,
19 gpointer user_data)
20{
21 GVariant *state;
22
23 state = g_action_get_state (G_ACTION (action));
24 g_action_change_state (G_ACTION (action), value: g_variant_new_boolean (value: !g_variant_get_boolean (value: state)));
25 g_variant_unref (value: state);
26}
27
28static void
29change_fullscreen_state (GSimpleAction *action,
30 GVariant *state,
31 gpointer user_data)
32{
33 if (g_variant_get_boolean (value: state))
34 gtk_window_fullscreen (window: user_data);
35 else
36 gtk_window_unfullscreen (window: user_data);
37
38 g_simple_action_set_state (simple: action, value: state);
39}
40
41static void
42window_copy (GSimpleAction *action,
43 GVariant *parameter,
44 gpointer user_data)
45{
46 GtkWindow *window = GTK_WINDOW (user_data);
47 GtkTextView *text = g_object_get_data (object: (GObject*)window, key: "plugman-text");
48
49 gtk_text_buffer_copy_clipboard (buffer: gtk_text_view_get_buffer (text_view: text),
50 clipboard: gtk_widget_get_clipboard (GTK_WIDGET (text)));
51}
52
53static void
54window_paste (GSimpleAction *action,
55 GVariant *parameter,
56 gpointer user_data)
57{
58 GtkWindow *window = GTK_WINDOW (user_data);
59 GtkTextView *text = g_object_get_data (object: (GObject*)window, key: "plugman-text");
60
61 gtk_text_buffer_paste_clipboard (buffer: gtk_text_view_get_buffer (text_view: text),
62 clipboard: gtk_widget_get_clipboard (GTK_WIDGET (text)),
63 NULL,
64 TRUE);
65
66}
67
68static GActionEntry win_entries[] = {
69 { "copy", window_copy, NULL, NULL, NULL },
70 { "paste", window_paste, NULL, NULL, NULL },
71 { "fullscreen", activate_toggle, NULL, "false", change_fullscreen_state }
72};
73
74static void
75new_window (GApplication *app,
76 GFile *file)
77{
78 GtkWidget *window, *grid, *scrolled, *view;
79
80 window = gtk_application_window_new (GTK_APPLICATION (app));
81 gtk_window_set_default_size (window: (GtkWindow*)window, width: 640, height: 480);
82 g_action_map_add_action_entries (G_ACTION_MAP (window), entries: win_entries, G_N_ELEMENTS (win_entries), user_data: window);
83 gtk_window_set_title (GTK_WINDOW (window), title: "Plugman");
84 gtk_application_window_set_show_menubar (GTK_APPLICATION_WINDOW (window), TRUE);
85
86 grid = gtk_grid_new ();
87 gtk_window_set_child (GTK_WINDOW (window), child: grid);
88
89 scrolled = gtk_scrolled_window_new ();
90 gtk_widget_set_hexpand (widget: scrolled, TRUE);
91 gtk_widget_set_vexpand (widget: scrolled, TRUE);
92 view = gtk_text_view_new ();
93
94 g_object_set_data (object: (GObject*)window, key: "plugman-text", data: view);
95
96 gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scrolled), child: view);
97
98 gtk_grid_attach (GTK_GRID (grid), child: scrolled, column: 0, row: 0, width: 1, height: 1);
99
100 if (file != NULL)
101 {
102 char *contents;
103 gsize length;
104
105 if (g_file_load_contents (file, NULL, contents: &contents, length: &length, NULL, NULL))
106 {
107 GtkTextBuffer *buffer;
108
109 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
110 gtk_text_buffer_set_text (buffer, text: contents, len: length);
111 g_free (mem: contents);
112 }
113 }
114
115 gtk_widget_show (GTK_WIDGET (window));
116}
117
118static void
119plug_man_activate (GApplication *application)
120{
121 new_window (app: application, NULL);
122}
123
124static void
125plug_man_open (GApplication *application,
126 GFile **files,
127 int n_files,
128 const char *hint)
129{
130 int i;
131
132 for (i = 0; i < n_files; i++)
133 new_window (app: application, file: files[i]);
134}
135
136typedef GtkApplication PlugMan;
137typedef GtkApplicationClass PlugManClass;
138
139static GType plug_man_get_type (void);
140G_DEFINE_TYPE (PlugMan, plug_man, GTK_TYPE_APPLICATION)
141
142static void
143plug_man_finalize (GObject *object)
144{
145 G_OBJECT_CLASS (plug_man_parent_class)->finalize (object);
146}
147
148static void
149show_about (GSimpleAction *action,
150 GVariant *parameter,
151 gpointer user_data)
152{
153 gtk_show_about_dialog (NULL,
154 first_property_name: "program-name", "Plugman",
155 "title", "About Plugman",
156 "comments", "A cheap Bloatpad clone.",
157 NULL);
158}
159
160
161static void
162quit_app (GSimpleAction *action,
163 GVariant *parameter,
164 gpointer user_data)
165{
166 GList *list, *next;
167 GtkWindow *win;
168
169 g_print (format: "Going down...\n");
170
171 list = gtk_application_get_windows (GTK_APPLICATION (g_application_get_default ()));
172 while (list)
173 {
174 win = list->data;
175 next = list->next;
176
177 gtk_window_destroy (GTK_WINDOW (win));
178
179 list = next;
180 }
181}
182
183static gboolean is_red_plugin_enabled;
184static gboolean is_black_plugin_enabled;
185
186static gboolean
187plugin_enabled (const char *name)
188{
189 if (g_strcmp0 (str1: name, str2: "red") == 0)
190 return is_red_plugin_enabled;
191 else
192 return is_black_plugin_enabled;
193}
194
195static GMenuModel *
196find_plugin_menu (void)
197{
198 return (GMenuModel*) g_object_get_data (G_OBJECT (g_application_get_default ()), key: "plugin-menu");
199}
200
201static void
202plugin_action (GAction *action,
203 GVariant *parameter,
204 gpointer data)
205{
206 const char *action_name;
207 const char *css_to_load;
208 GtkCssProvider *css_provider;
209
210 action_name = g_action_get_name (action);
211 if (strcmp (s1: action_name, s2: "red") == 0)
212 css_to_load = red_css;
213 else if (strcmp (s1: action_name, s2: "black") == 0)
214 css_to_load = black_css;
215 else
216 {
217 g_critical ("Unknown action name: %s", action_name);
218 return;
219 }
220
221 g_message ("Color: %s", g_action_get_name (action));
222
223 css_provider = gtk_css_provider_new ();
224 gtk_css_provider_load_from_data (css_provider, data: css_to_load, length: -1);
225 gtk_style_context_add_provider_for_display (display: gdk_display_get_default (),
226 GTK_STYLE_PROVIDER (css_provider),
227 GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
228}
229
230static void
231enable_plugin (const char *name)
232{
233 GMenuModel *plugin_menu;
234 GAction *action;
235
236 g_print (format: "Enabling '%s' plugin\n", name);
237
238 action = (GAction *)g_simple_action_new (name, NULL);
239 g_signal_connect (action, "activate", G_CALLBACK (plugin_action), (gpointer)name);
240 g_action_map_add_action (G_ACTION_MAP (g_application_get_default ()), action);
241 g_print (format: "Actions of '%s' plugin added\n", name);
242 g_object_unref (object: action);
243
244 plugin_menu = find_plugin_menu ();
245 if (plugin_menu)
246 {
247 GMenu *section;
248 GMenuItem *item;
249 char *label;
250 char *action_name;
251
252 section = g_menu_new ();
253 label = g_strdup_printf (format: "Turn text %s", name);
254 action_name = g_strconcat (string1: "app.", name, NULL);
255 g_menu_insert (menu: section, position: 0, label, detailed_action: action_name);
256 g_free (mem: label);
257 g_free (mem: action_name);
258 item = g_menu_item_new_section (NULL, section: (GMenuModel*)section);
259 g_menu_item_set_attribute (menu_item: item, attribute: "id", format_string: "s", name);
260 g_menu_append_item (G_MENU (plugin_menu), item);
261 g_object_unref (object: item);
262 g_object_unref (object: section);
263 g_print (format: "Menus of '%s' plugin added\n", name);
264 }
265 else
266 g_warning ("Plugin menu not found");
267
268 if (g_strcmp0 (str1: name, str2: "red") == 0)
269 is_red_plugin_enabled = TRUE;
270 else
271 is_black_plugin_enabled = TRUE;
272}
273
274static void
275disable_plugin (const char *name)
276{
277 GMenuModel *plugin_menu;
278
279 g_print (format: "Disabling '%s' plugin\n", name);
280
281 plugin_menu = find_plugin_menu ();
282 if (plugin_menu)
283 {
284 int i;
285
286 for (i = 0; i < g_menu_model_get_n_items (model: plugin_menu); i++)
287 {
288 char *id;
289 if (g_menu_model_get_item_attribute (model: plugin_menu, item_index: i, attribute: "id", format_string: "s", &id))
290 {
291 if (g_strcmp0 (str1: id, str2: name) == 0)
292 {
293 g_menu_remove (G_MENU (plugin_menu), position: i);
294 g_print (format: "Menus of '%s' plugin removed\n", name);
295 }
296 g_free (mem: id);
297 }
298 }
299 }
300 else
301 g_warning ("Plugin menu not found");
302
303 g_action_map_remove_action (G_ACTION_MAP (g_application_get_default ()), action_name: name);
304 g_print (format: "Actions of '%s' plugin removed\n", name);
305
306 if (g_strcmp0 (str1: name, str2: "red") == 0)
307 is_red_plugin_enabled = FALSE;
308 else
309 is_black_plugin_enabled = FALSE;
310}
311
312static void
313enable_or_disable_plugin (GtkToggleButton *button,
314 const char *name)
315{
316 if (plugin_enabled (name))
317 disable_plugin (name);
318 else
319 enable_plugin (name);
320}
321
322
323static void
324configure_plugins (GSimpleAction *action,
325 GVariant *parameter,
326 gpointer user_data)
327{
328 GtkBuilder *builder;
329 GtkWidget *dialog;
330 GtkWidget *check;
331 GError *error = NULL;
332
333 builder = gtk_builder_new ();
334 gtk_builder_add_from_string (builder,
335 buffer: "<interface>"
336 " <object class='GtkDialog' id='plugin-dialog'>"
337 " <property name='title'>Plugins</property>"
338 " <child internal-child='content_area'>"
339 " <object class='GtkBox' id='content-area'>"
340 " <property name='visible'>True</property>"
341 " <property name='orientation'>vertical</property>"
342 " <child>"
343 " <object class='GtkCheckButton' id='red-plugin'>"
344 " <property name='label' translatable='yes'>Red Plugin - turn your text red</property>"
345 " <property name='visible'>True</property>"
346 " </object>"
347 " </child>"
348 " <child>"
349 " <object class='GtkCheckButton' id='black-plugin'>"
350 " <property name='label' translatable='yes'>Black Plugin - turn your text black</property>"
351 " <property name='visible'>True</property>"
352 " </object>"
353 " </child>"
354 " </object>"
355 " </child>"
356 " <child internal-child='action_area'>"
357 " <object class='GtkBox' id='action-area'>"
358 " <property name='visible'>True</property>"
359 " <child>"
360 " <object class='GtkButton' id='close-button'>"
361 " <property name='label' translatable='yes'>Close</property>"
362 " <property name='visible'>True</property>"
363 " </object>"
364 " </child>"
365 " </object>"
366 " </child>"
367 " <action-widgets>"
368 " <action-widget response='-5'>close-button</action-widget>"
369 " </action-widgets>"
370 " </object>"
371 "</interface>", length: -1, error: &error);
372 if (error)
373 {
374 g_warning ("%s", error->message);
375 g_error_free (error);
376 goto out;
377 }
378
379 dialog = (GtkWidget *)gtk_builder_get_object (builder, name: "plugin-dialog");
380 check = (GtkWidget *)gtk_builder_get_object (builder, name: "red-plugin");
381 gtk_check_button_set_active (GTK_CHECK_BUTTON (check), setting: plugin_enabled (name: "red"));
382 g_signal_connect (check, "toggled", G_CALLBACK (enable_or_disable_plugin), (char *) "red");
383 check = (GtkWidget *)gtk_builder_get_object (builder, name: "black-plugin");
384 gtk_check_button_set_active (GTK_CHECK_BUTTON (check), setting: plugin_enabled (name: "black"));
385 g_signal_connect (check, "toggled", G_CALLBACK (enable_or_disable_plugin), (char *) "black");
386
387 g_signal_connect (dialog, "response", G_CALLBACK (gtk_window_destroy), NULL);
388
389 gtk_window_present (GTK_WINDOW (dialog));
390
391out:
392 g_object_unref (object: builder);
393}
394
395static GActionEntry app_entries[] = {
396 { "about", show_about, NULL, NULL, NULL },
397 { "quit", quit_app, NULL, NULL, NULL },
398 { "plugins", configure_plugins, NULL, NULL, NULL },
399};
400
401static void
402plug_man_startup (GApplication *application)
403{
404 GtkBuilder *builder;
405
406 G_APPLICATION_CLASS (plug_man_parent_class)
407 ->startup (application);
408
409 g_action_map_add_action_entries (G_ACTION_MAP (application), entries: app_entries, G_N_ELEMENTS (app_entries), user_data: application);
410
411 builder = gtk_builder_new ();
412 gtk_builder_add_from_string (builder,
413 buffer: "<interface>"
414 " <menu id='menubar'>"
415 " <submenu>"
416 " <attribute name='label' translatable='yes'>_Plugman</attribute>"
417 " <section>"
418 " <item>"
419 " <attribute name='label' translatable='yes'>_About Plugman</attribute>"
420 " <attribute name='action'>app.about</attribute>"
421 " </item>"
422 " </section>"
423 " <section>"
424 " <item>"
425 " <attribute name='label' translatable='yes'>_Quit</attribute>"
426 " <attribute name='action'>app.quit</attribute>"
427 " <attribute name='accel'>&lt;Primary&gt;q</attribute>"
428 " </item>"
429 " </section>"
430 " </submenu>"
431 " <submenu>"
432 " <attribute name='label' translatable='yes'>_Edit</attribute>"
433 " <section>"
434 " <item>"
435 " <attribute name='label' translatable='yes'>_Copy</attribute>"
436 " <attribute name='action'>win.copy</attribute>"
437 " </item>"
438 " <item>"
439 " <attribute name='label' translatable='yes'>_Paste</attribute>"
440 " <attribute name='action'>win.paste</attribute>"
441 " </item>"
442 " </section>"
443 " <item><link name='section' id='plugins'>"
444 " </link></item>"
445 " <section>"
446 " <item>"
447 " <attribute name='label' translatable='yes'>Plugins</attribute>"
448 " <attribute name='action'>app.plugins</attribute>"
449 " </item>"
450 " </section>"
451 " </submenu>"
452 " <submenu>"
453 " <attribute name='label' translatable='yes'>_View</attribute>"
454 " <section>"
455 " <item>"
456 " <attribute name='label' translatable='yes'>_Fullscreen</attribute>"
457 " <attribute name='action'>win.fullscreen</attribute>"
458 " </item>"
459 " </section>"
460 " </submenu>"
461 " </menu>"
462 "</interface>", length: -1, NULL);
463 gtk_application_set_menubar (GTK_APPLICATION (application), G_MENU_MODEL (gtk_builder_get_object (builder, "menubar")));
464 g_object_set_data_full (G_OBJECT (application), key: "plugin-menu", data: gtk_builder_get_object (builder, name: "plugins"), destroy: g_object_unref);
465 g_object_unref (object: builder);
466}
467
468static void
469plug_man_init (PlugMan *app)
470{
471}
472
473static void
474plug_man_class_init (PlugManClass *class)
475{
476 GApplicationClass *application_class = G_APPLICATION_CLASS (class);
477 GObjectClass *object_class = G_OBJECT_CLASS (class);
478
479 application_class->startup = plug_man_startup;
480 application_class->activate = plug_man_activate;
481 application_class->open = plug_man_open;
482
483 object_class->finalize = plug_man_finalize;
484
485}
486
487static PlugMan *
488plug_man_new (void)
489{
490 return g_object_new (object_type: plug_man_get_type (),
491 first_property_name: "application-id", "org.gtk.Test.plugman",
492 "flags", G_APPLICATION_HANDLES_OPEN,
493 NULL);
494}
495
496int
497main (int argc, char **argv)
498{
499 PlugMan *plug_man;
500 int status;
501 const char *accels[] = { "F11", NULL };
502
503 plug_man = plug_man_new ();
504 gtk_application_set_accels_for_action (GTK_APPLICATION (plug_man),
505 detailed_action_name: "win.fullscreen", accels);
506 status = g_application_run (G_APPLICATION (plug_man), argc, argv);
507 g_object_unref (object: plug_man);
508
509 return status;
510}
511

source code of gtk/examples/plugman.c