]> Pileus Git - ~andy/gtk/blob - examples/bloatpad.c
stylecontext: Do invalidation on first resize container
[~andy/gtk] / examples / bloatpad.c
1 #include <stdlib.h>
2 #include <gtk/gtk.h>
3
4 static void
5 activate_toggle (GSimpleAction *action,
6                  GVariant      *parameter,
7                  gpointer       user_data)
8 {
9   GVariant *state;
10
11   state = g_action_get_state (G_ACTION (action));
12   g_action_change_state (G_ACTION (action), g_variant_new_boolean (!g_variant_get_boolean (state)));
13   g_variant_unref (state);
14 }
15
16 static void
17 activate_radio (GSimpleAction *action,
18                 GVariant      *parameter,
19                 gpointer       user_data)
20 {
21   g_action_change_state (G_ACTION (action), parameter);
22 }
23
24 static void
25 change_fullscreen_state (GSimpleAction *action,
26                          GVariant      *state,
27                          gpointer       user_data)
28 {
29   if (g_variant_get_boolean (state))
30     gtk_window_fullscreen (user_data);
31   else
32     gtk_window_unfullscreen (user_data);
33
34   g_simple_action_set_state (action, state);
35 }
36
37 static void
38 change_justify_state (GSimpleAction *action,
39                       GVariant      *state,
40                       gpointer       user_data)
41 {
42   GtkTextView *text = g_object_get_data (user_data, "bloatpad-text");
43   const gchar *str;
44
45   str = g_variant_get_string (state, NULL);
46
47   if (g_str_equal (str, "left"))
48     gtk_text_view_set_justification (text, GTK_JUSTIFY_LEFT);
49   else if (g_str_equal (str, "center"))
50     gtk_text_view_set_justification (text, GTK_JUSTIFY_CENTER);
51   else if (g_str_equal (str, "right"))
52     gtk_text_view_set_justification (text, GTK_JUSTIFY_RIGHT);
53   else
54     /* ignore this attempted change */
55     return;
56
57   g_simple_action_set_state (action, state);
58 }
59
60 static GtkClipboard *
61 get_clipboard (GtkWidget *widget)
62 {
63   return gtk_widget_get_clipboard (widget, gdk_atom_intern_static_string ("CLIPBOARD"));
64 }
65
66 static void
67 window_copy (GSimpleAction *action,
68              GVariant      *parameter,
69              gpointer       user_data)
70 {
71   GtkWindow *window = GTK_WINDOW (user_data);
72   GtkTextView *text = g_object_get_data ((GObject*)window, "bloatpad-text");
73
74   gtk_text_buffer_copy_clipboard (gtk_text_view_get_buffer (text),
75                                   get_clipboard ((GtkWidget*) text));
76 }
77
78 static void
79 window_paste (GSimpleAction *action,
80               GVariant      *parameter,
81               gpointer       user_data)
82 {
83   GtkWindow *window = GTK_WINDOW (user_data);
84   GtkTextView *text = g_object_get_data ((GObject*)window, "bloatpad-text");
85   
86   gtk_text_buffer_paste_clipboard (gtk_text_view_get_buffer (text),
87                                    get_clipboard ((GtkWidget*) text),
88                                    NULL,
89                                    TRUE);
90
91 }
92
93 static GActionEntry win_entries[] = {
94   { "copy", window_copy, NULL, NULL, NULL },
95   { "paste", window_paste, NULL, NULL, NULL },
96   { "fullscreen", activate_toggle, NULL, "false", change_fullscreen_state },
97   { "justify", activate_radio, "s", "'left'", change_justify_state }
98 };
99
100 static void
101 new_window (GApplication *app,
102             GFile        *file)
103 {
104   GtkWidget *window, *grid, *scrolled, *view;
105   GtkWidget *toolbar;
106   GtkToolItem *button;
107   GtkWidget *sw, *box, *label;
108
109   window = gtk_application_window_new (GTK_APPLICATION (app));
110   gtk_window_set_default_size ((GtkWindow*)window, 640, 480);
111   g_action_map_add_action_entries (G_ACTION_MAP (window), win_entries, G_N_ELEMENTS (win_entries), window);
112   gtk_window_set_title (GTK_WINDOW (window), "Bloatpad");
113
114   grid = gtk_grid_new ();
115   gtk_container_add (GTK_CONTAINER (window), grid);
116
117   toolbar = gtk_toolbar_new ();
118   button = gtk_toggle_tool_button_new_from_stock (GTK_STOCK_JUSTIFY_LEFT);
119   gtk_actionable_set_detailed_action_name (GTK_ACTIONABLE (button), "win.justify::left");
120   gtk_container_add (GTK_CONTAINER (toolbar), GTK_WIDGET (button));
121
122   button = gtk_toggle_tool_button_new_from_stock (GTK_STOCK_JUSTIFY_CENTER);
123   gtk_actionable_set_detailed_action_name (GTK_ACTIONABLE (button), "win.justify::center");
124   gtk_container_add (GTK_CONTAINER (toolbar), GTK_WIDGET (button));
125
126   button = gtk_toggle_tool_button_new_from_stock (GTK_STOCK_JUSTIFY_RIGHT);
127   gtk_actionable_set_detailed_action_name (GTK_ACTIONABLE (button), "win.justify::right");
128   gtk_container_add (GTK_CONTAINER (toolbar), GTK_WIDGET (button));
129
130   button = gtk_separator_tool_item_new ();
131   gtk_separator_tool_item_set_draw (GTK_SEPARATOR_TOOL_ITEM (button), FALSE);
132   gtk_tool_item_set_expand (GTK_TOOL_ITEM (button), TRUE);
133   gtk_container_add (GTK_CONTAINER (toolbar), GTK_WIDGET (button));
134
135   button = gtk_tool_item_new ();
136   box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
137   gtk_container_add (GTK_CONTAINER (button), box);
138   label = gtk_label_new ("Fullscreen:");
139   gtk_container_add (GTK_CONTAINER (box), label);
140   sw = gtk_switch_new ();
141   gtk_actionable_set_action_name (GTK_ACTIONABLE (sw), "win.fullscreen");
142   gtk_container_add (GTK_CONTAINER (box), sw);
143   gtk_container_add (GTK_CONTAINER (toolbar), GTK_WIDGET (button));
144
145   gtk_grid_attach (GTK_GRID (grid), toolbar, 0, 0, 1, 1);
146
147   scrolled = gtk_scrolled_window_new (NULL, NULL);
148   gtk_widget_set_hexpand (scrolled, TRUE);
149   gtk_widget_set_vexpand (scrolled, TRUE);
150   view = gtk_text_view_new ();
151
152   g_object_set_data ((GObject*)window, "bloatpad-text", view);
153
154   gtk_container_add (GTK_CONTAINER (scrolled), view);
155
156   gtk_grid_attach (GTK_GRID (grid), scrolled, 0, 1, 1, 1);
157
158   if (file != NULL)
159     {
160       gchar *contents;
161       gsize length;
162
163       if (g_file_load_contents (file, NULL, &contents, &length, NULL, NULL))
164         {
165           GtkTextBuffer *buffer;
166
167           buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
168           gtk_text_buffer_set_text (buffer, contents, length);
169           g_free (contents);
170         }
171     }
172
173   gtk_widget_show_all (GTK_WIDGET (window));
174 }
175
176 static void
177 bloat_pad_activate (GApplication *application)
178 {
179   new_window (application, NULL);
180 }
181
182 static void
183 bloat_pad_open (GApplication  *application,
184                 GFile        **files,
185                 gint           n_files,
186                 const gchar   *hint)
187 {
188   gint i;
189
190   for (i = 0; i < n_files; i++)
191     new_window (application, files[i]);
192 }
193
194 typedef struct
195 {
196   GtkApplication parent_instance;
197
198   GMenu *time;
199   guint timeout;
200 } BloatPad;
201
202 typedef GtkApplicationClass BloatPadClass;
203
204 G_DEFINE_TYPE (BloatPad, bloat_pad, GTK_TYPE_APPLICATION)
205
206 static void
207 bloat_pad_finalize (GObject *object)
208 {
209   G_OBJECT_CLASS (bloat_pad_parent_class)->finalize (object);
210 }
211
212 static void
213 new_activated (GSimpleAction *action,
214                GVariant      *parameter,
215                gpointer       user_data)
216 {
217   GApplication *app = user_data;
218
219   g_application_activate (app);
220 }
221
222 static void
223 about_activated (GSimpleAction *action,
224                  GVariant      *parameter,
225                  gpointer       user_data)
226 {
227   gtk_show_about_dialog (NULL,
228                          "program-name", "Bloatpad",
229                          "title", "About Bloatpad",
230                          "comments", "Not much to say, really.",
231                          NULL);
232 }
233
234 static void
235 quit_activated (GSimpleAction *action,
236                 GVariant      *parameter,
237                 gpointer       user_data)
238 {
239   GApplication *app = user_data;
240
241   g_application_quit (app);
242 }
243
244 static gboolean
245 update_time (gpointer user_data)
246 {
247   BloatPad *bloatpad = user_data;
248   GDateTime *now;
249   gchar *time;
250
251   while (g_menu_model_get_n_items (G_MENU_MODEL (bloatpad->time)))
252     g_menu_remove (bloatpad->time, 0);
253
254   g_message ("Updating the time menu (which should be open now)...");
255
256   now = g_date_time_new_now_local ();
257   time = g_date_time_format (now, "%c");
258   g_menu_append (bloatpad->time, time, NULL);
259   g_date_time_unref (now);
260   g_free (time);
261
262   return G_SOURCE_CONTINUE;
263 }
264
265 static void
266 time_active_changed (GSimpleAction *action,
267                      GVariant      *state,
268                      gpointer       user_data)
269 {
270   BloatPad *bloatpad = user_data;
271
272   if (g_variant_get_boolean (state))
273     {
274       if (!bloatpad->timeout)
275         {
276           bloatpad->timeout = g_timeout_add (1000, update_time, bloatpad);
277           update_time (bloatpad);
278         }
279     }
280   else
281     {
282       if (bloatpad->timeout)
283         {
284           g_source_remove (bloatpad->timeout);
285           bloatpad->timeout = 0;
286         }
287     }
288
289   g_simple_action_set_state (action, state);
290 }
291
292 static GActionEntry app_entries[] = {
293   { "new", new_activated, NULL, NULL, NULL },
294   { "about", about_activated, NULL, NULL, NULL },
295   { "quit", quit_activated, NULL, NULL, NULL },
296   { "time-active", NULL, NULL, "false", time_active_changed }
297 };
298
299 static void
300 bloat_pad_startup (GApplication *application)
301 {
302   BloatPad *bloatpad = (BloatPad*) application;
303   GtkBuilder *builder;
304
305   G_APPLICATION_CLASS (bloat_pad_parent_class)
306     ->startup (application);
307
308   g_action_map_add_action_entries (G_ACTION_MAP (application), app_entries, G_N_ELEMENTS (app_entries), application);
309
310   builder = gtk_builder_new ();
311   gtk_builder_add_from_string (builder,
312                                "<interface>"
313                                "  <menu id='app-menu'>"
314                                "    <section>"
315                                "      <item>"
316                                "        <attribute name='label' translatable='yes'>_New Window</attribute>"
317                                "        <attribute name='action'>app.new</attribute>"
318                                "        <attribute name='accel'>&lt;Primary&gt;n</attribute>"
319                                "      </item>"
320                                "    </section>"
321                                "    <section>"
322                                "      <item>"
323                                "        <attribute name='label' translatable='yes'>_About Bloatpad</attribute>"
324                                "        <attribute name='action'>app.about</attribute>"
325                                "      </item>"
326                                "    </section>"
327                                "    <section>"
328                                "      <item>"
329                                "        <attribute name='label' translatable='yes'>_Quit</attribute>"
330                                "        <attribute name='action'>app.quit</attribute>"
331                                "        <attribute name='accel'>&lt;Primary&gt;q</attribute>"
332                                "      </item>"
333                                "    </section>"
334                                "  </menu>"
335                                "  <menu id='menubar'>"
336                                "    <submenu>"
337                                "      <attribute name='label' translatable='yes'>_Edit</attribute>"
338                                "      <section>"
339                                "        <item>"
340                                "          <attribute name='label' translatable='yes'>_Copy</attribute>"
341                                "          <attribute name='action'>win.copy</attribute>"
342                                "          <attribute name='accel'>&lt;Primary&gt;c</attribute>"
343                                "        </item>"
344                                "        <item>"
345                                "          <attribute name='label' translatable='yes'>_Paste</attribute>"
346                                "          <attribute name='action'>win.paste</attribute>"
347                                "          <attribute name='accel'>&lt;Primary&gt;v</attribute>"
348                                "        </item>"
349                                "      </section>"
350                                "    </submenu>"
351                                "    <submenu>"
352                                "      <attribute name='label' translatable='yes'>_View</attribute>"
353                                "      <section>"
354                                "        <item>"
355                                "          <attribute name='label' translatable='yes'>_Fullscreen</attribute>"
356                                "          <attribute name='action'>win.fullscreen</attribute>"
357                                "          <attribute name='accel'>F11</attribute>"
358                                "        </item>"
359                                "      </section>"
360                                "    </submenu>"
361                                "    <submenu id='time-menu'>"
362                                "      <attribute name='label' translatable='yes'>Time</attribute>"
363                                "      <attribute name='submenu-action'>app.time-active</attribute>"
364                                "    </submenu>"
365                                "  </menu>"
366                                "</interface>", -1, NULL);
367   gtk_application_set_app_menu (GTK_APPLICATION (application), G_MENU_MODEL (gtk_builder_get_object (builder, "app-menu")));
368   gtk_application_set_menubar (GTK_APPLICATION (application), G_MENU_MODEL (gtk_builder_get_object (builder, "menubar")));
369   //gtk_application_set_menubar (GTK_APPLICATION (application), G_MENU_MODEL (gtk_builder_get_object (builder, "app-menu")));
370   bloatpad->time = G_MENU (gtk_builder_get_object (builder, "time-menu"));
371   g_object_unref (builder);
372 }
373
374 static void
375 bloat_pad_shutdown (GApplication *application)
376 {
377   BloatPad *bloatpad = (BloatPad *) application;
378
379   if (bloatpad->timeout)
380     {
381       g_source_remove (bloatpad->timeout);
382       bloatpad->timeout = 0;
383     }
384
385   G_APPLICATION_CLASS (bloat_pad_parent_class)
386     ->shutdown (application);
387 }
388
389 static void
390 bloat_pad_init (BloatPad *app)
391 {
392 }
393
394 static void
395 bloat_pad_class_init (BloatPadClass *class)
396 {
397   GApplicationClass *application_class = G_APPLICATION_CLASS (class);
398   GObjectClass *object_class = G_OBJECT_CLASS (class);
399
400   application_class->startup = bloat_pad_startup;
401   application_class->shutdown = bloat_pad_shutdown;
402   application_class->activate = bloat_pad_activate;
403   application_class->open = bloat_pad_open;
404
405   object_class->finalize = bloat_pad_finalize;
406
407 }
408
409 BloatPad *
410 bloat_pad_new (void)
411 {
412   BloatPad *bloat_pad;
413
414   g_set_application_name ("Bloatpad");
415
416   bloat_pad = g_object_new (bloat_pad_get_type (),
417                             "application-id", "org.gtk.Test.bloatpad",
418                             "flags", G_APPLICATION_HANDLES_OPEN,
419                             "inactivity-timeout", 30000,
420                             "register-session", TRUE,
421                             NULL);
422
423   return bloat_pad;
424 }
425
426 int
427 main (int argc, char **argv)
428 {
429   BloatPad *bloat_pad;
430   int status;
431
432   bloat_pad = bloat_pad_new ();
433
434   gtk_application_add_accelerator (GTK_APPLICATION (bloat_pad),
435                                    "F11", "win.fullscreen", NULL);
436
437   status = g_application_run (G_APPLICATION (bloat_pad), argc, argv);
438
439   g_object_unref (bloat_pad);
440
441   return status;
442 }