]> www.fi.muni.cz Git - evince.git/blob - cut-n-paste/gedit-message-area/gedit-message-area.c
Use a message area instead of a popup dialog for error notifications.
[evince.git] / cut-n-paste / gedit-message-area / gedit-message-area.c
1 /*
2  * gedit-message-area.c
3  * This file is part of gedit
4  *
5  * Copyright (C) 2005 - Paolo Maggi
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23 /*
24  * Modified by the gedit Team, 2005. See the AUTHORS file for a
25  * list of people on the gedit Team.
26  * See the ChangeLog files for a list of changes.
27  *
28  * $Id: gedit-message-area.c 5887 2007-09-07 07:20:19Z pborelli $
29  */
30
31 /* TODO: Style properties */
32
33 #ifdef HAVE_CONFIG_H
34 #include <config.h>
35 #endif
36
37 #include <glib/gi18n.h>
38 #include <gtk/gtk.h>
39 #include <gdk/gdk.h>
40 #include <gdk/gdkkeysyms.h>
41
42 #include "gedit-message-area.h"
43
44 #define GEDIT_MESSAGE_AREA_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), \
45                                                GEDIT_TYPE_MESSAGE_AREA, \
46                                                GeditMessageAreaPrivate))
47
48 struct _GeditMessageAreaPrivate
49 {
50         GtkWidget *main_hbox;
51
52         GtkWidget *contents;
53         GtkWidget *action_area;
54
55         gboolean changing_style;
56 };
57
58 typedef struct _ResponseData ResponseData;
59
60 struct _ResponseData
61 {
62         gint response_id;
63 };
64
65 enum {
66         RESPONSE,
67         CLOSE,
68         LAST_SIGNAL
69 };
70
71 static guint signals[LAST_SIGNAL];
72
73 G_DEFINE_TYPE(GeditMessageArea, gedit_message_area, GTK_TYPE_HBOX)
74
75
76 static void
77 gedit_message_area_finalize (GObject *object)
78 {
79         /*
80         GeditMessageArea *message_area = GEDIT_MESSAGE_AREA (object);
81         */
82
83         G_OBJECT_CLASS (gedit_message_area_parent_class)->finalize (object);
84 }
85
86 static ResponseData *
87 get_response_data (GtkWidget *widget,
88                    gboolean   create)
89 {
90         ResponseData *ad = g_object_get_data (G_OBJECT (widget),
91                                               "gedit-message-area-response-data");
92
93         if (ad == NULL && create)
94         {
95                 ad = g_new (ResponseData, 1);
96
97                 g_object_set_data_full (G_OBJECT (widget),
98                                         "gedit-message-area-response-data",
99                                         ad,
100                                         g_free);
101         }
102
103         return ad;
104 }
105
106 static GtkWidget *
107 find_button (GeditMessageArea *message_area,
108              gint              response_id)
109 {
110         GList *children, *tmp_list;
111         GtkWidget *child = NULL;
112
113         children = gtk_container_get_children (
114                         GTK_CONTAINER (message_area->priv->action_area));
115
116         for (tmp_list = children; tmp_list; tmp_list = tmp_list->next)
117         {
118                 ResponseData *rd = get_response_data (tmp_list->data, FALSE);
119
120                 if (rd && rd->response_id == response_id)
121                 {
122                         child = tmp_list->data;
123                         break;
124                 }
125         }
126
127         g_list_free (children);
128
129         return child;
130 }
131
132 static void
133 gedit_message_area_close (GeditMessageArea *message_area)
134 {
135         if (!find_button (message_area, GTK_RESPONSE_CANCEL))
136                 return;
137
138         /* emit response signal */
139         gedit_message_area_response (GEDIT_MESSAGE_AREA (message_area),
140                                      GTK_RESPONSE_CANCEL);
141 }
142
143 static gboolean
144 paint_message_area (GtkWidget      *widget,
145                     GdkEventExpose *event,
146                     gpointer        user_data)
147 {
148         gtk_paint_flat_box (widget->style,
149                             widget->window,
150                             GTK_STATE_NORMAL,
151                             GTK_SHADOW_OUT,
152                             NULL,
153                             widget,
154                             "tooltip",
155                             widget->allocation.x + 1,
156                             widget->allocation.y + 1,
157                             widget->allocation.width - 2,
158                             widget->allocation.height - 2);
159
160         return FALSE;
161 }
162
163 static void
164 gedit_message_area_class_init (GeditMessageAreaClass *klass)
165 {
166         GObjectClass *object_class;
167         GtkBindingSet *binding_set;
168
169         object_class = G_OBJECT_CLASS (klass);
170         object_class->finalize = gedit_message_area_finalize;
171
172         klass->close = gedit_message_area_close;
173
174         g_type_class_add_private (object_class, sizeof(GeditMessageAreaPrivate));
175
176         signals[RESPONSE] = g_signal_new ("response",
177                                           G_OBJECT_CLASS_TYPE (klass),
178                                           G_SIGNAL_RUN_LAST,
179                                           G_STRUCT_OFFSET (GeditMessageAreaClass, response),
180                                           NULL, NULL,
181                                           g_cclosure_marshal_VOID__INT,
182                                           G_TYPE_NONE, 1,
183                                           G_TYPE_INT);
184
185         signals[CLOSE] =  g_signal_new ("close",
186                                         G_OBJECT_CLASS_TYPE (klass),
187                                         G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
188                                         G_STRUCT_OFFSET (GeditMessageAreaClass, close),
189                                         NULL, NULL,
190                                         g_cclosure_marshal_VOID__VOID,
191                                         G_TYPE_NONE, 0);
192
193         binding_set = gtk_binding_set_by_class (klass);
194
195         gtk_binding_entry_add_signal (binding_set, GDK_Escape, 0, "close", 0);
196 }
197
198 static void
199 style_set (GtkWidget        *widget,
200            GtkStyle         *prev_style,
201            GeditMessageArea *message_area)
202 {
203         GtkWidget *window;
204         GtkStyle *style;
205
206         if (message_area->priv->changing_style)
207                 return;
208
209         /* This is a hack needed to use the tooltip background color */
210         window = gtk_window_new (GTK_WINDOW_POPUP);
211         gtk_widget_set_name (window, "gtk-tooltip");
212         gtk_widget_ensure_style (window);
213         style = gtk_widget_get_style (window);
214
215         message_area->priv->changing_style = TRUE;
216         gtk_widget_set_style (GTK_WIDGET (message_area), style);
217         message_area->priv->changing_style = FALSE;
218
219         gtk_widget_destroy (window);
220
221         gtk_widget_queue_draw (GTK_WIDGET (message_area));
222 }
223
224 static void
225 gedit_message_area_init (GeditMessageArea *message_area)
226 {
227         message_area->priv = GEDIT_MESSAGE_AREA_GET_PRIVATE (message_area);
228
229         message_area->priv->main_hbox = gtk_hbox_new (FALSE, 16); /* FIXME: use style properties */
230         gtk_widget_show (message_area->priv->main_hbox);
231         gtk_container_set_border_width (GTK_CONTAINER (message_area->priv->main_hbox),
232                                         8); /* FIXME: use style properties */
233
234         message_area->priv->action_area = gtk_vbox_new (TRUE, 10); /* FIXME: use style properties */
235         gtk_widget_show (message_area->priv->action_area);
236         gtk_box_pack_end (GTK_BOX (message_area->priv->main_hbox),
237                             message_area->priv->action_area,
238                             FALSE,
239                             TRUE,
240                             0);
241
242         gtk_box_pack_start (GTK_BOX (message_area),
243                             message_area->priv->main_hbox,
244                             TRUE,
245                             TRUE,
246                             0);
247
248         gtk_widget_set_app_paintable (GTK_WIDGET (message_area), TRUE);
249
250         g_signal_connect (message_area,
251                           "expose-event",
252                           G_CALLBACK (paint_message_area),
253                           NULL);
254
255         /* Note that we connect to style-set on one of the internal
256          * widgets, not on the message area itself, since gtk does
257          * not deliver any further style-set signals for a widget on
258          * which the style has been forced with gtk_widget_set_style() */
259         g_signal_connect (message_area->priv->main_hbox,
260                           "style-set",
261                           G_CALLBACK (style_set),
262                           message_area);
263 }
264
265 static gint
266 get_response_for_widget (GeditMessageArea *message_area,
267                          GtkWidget        *widget)
268 {
269         ResponseData *rd;
270
271         rd = get_response_data (widget, FALSE);
272         if (!rd)
273                 return GTK_RESPONSE_NONE;
274         else
275                 return rd->response_id;
276 }
277
278 static void
279 action_widget_activated (GtkWidget *widget, GeditMessageArea *message_area)
280 {
281         gint response_id;
282
283         response_id = get_response_for_widget (message_area, widget);
284
285         gedit_message_area_response (message_area, response_id);
286 }
287
288 void
289 gedit_message_area_add_action_widget (GeditMessageArea *message_area,
290                                       GtkWidget        *child,
291                                       gint              response_id)
292 {
293         ResponseData *ad;
294         guint signal_id;
295
296         g_return_if_fail (GEDIT_IS_MESSAGE_AREA (message_area));
297         g_return_if_fail (GTK_IS_WIDGET (child));
298
299         ad = get_response_data (child, TRUE);
300
301         ad->response_id = response_id;
302
303         if (GTK_IS_BUTTON (child))
304                 signal_id = g_signal_lookup ("clicked", GTK_TYPE_BUTTON);
305         else
306                 signal_id = GTK_WIDGET_GET_CLASS (child)->activate_signal;
307
308         if (signal_id)
309         {
310                 GClosure *closure;
311
312                 closure = g_cclosure_new_object (G_CALLBACK (action_widget_activated),
313                                                  G_OBJECT (message_area));
314
315                 g_signal_connect_closure_by_id (child,
316                                                 signal_id,
317                                                 0,
318                                                 closure,
319                                                 FALSE);
320         }
321         else
322                 g_warning ("Only 'activatable' widgets can be packed into the action area of a GeditMessageArea");
323
324         if (response_id != GTK_RESPONSE_HELP)
325                 gtk_box_pack_start (GTK_BOX (message_area->priv->action_area),
326                                     child,
327                                     FALSE,
328                                     FALSE,
329                                     0);
330         else
331                 gtk_box_pack_end (GTK_BOX (message_area->priv->action_area),
332                                     child,
333                                     FALSE,
334                                     FALSE,
335                                     0);
336 }
337
338 void
339 gedit_message_area_set_contents (GeditMessageArea *message_area,
340                                  GtkWidget        *contents)
341 {
342         g_return_if_fail (GEDIT_IS_MESSAGE_AREA (message_area));
343         g_return_if_fail (GTK_IS_WIDGET (contents));
344
345         message_area->priv->contents = contents;
346         gtk_box_pack_start (GTK_BOX (message_area->priv->main_hbox),
347                             message_area->priv->contents,
348                             TRUE,
349                             TRUE,
350                             0);
351 }
352
353 GtkWidget*
354 gedit_message_area_add_button (GeditMessageArea *message_area,
355                                const gchar      *button_text,
356                                gint              response_id)
357 {
358         GtkWidget *button;
359
360         g_return_val_if_fail (GEDIT_IS_MESSAGE_AREA (message_area), NULL);
361         g_return_val_if_fail (button_text != NULL, NULL);
362
363         button = gtk_button_new_from_stock (button_text);
364
365         GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
366
367         gtk_widget_show (button);
368
369         gedit_message_area_add_action_widget (message_area,
370                                               button,
371                                               response_id);
372
373         return button;
374 }
375
376 void
377 gedit_message_area_add_buttons_valist (GeditMessageArea *message_area,
378                                        const gchar      *first_button_text,
379                                        va_list           args)
380 {
381         const gchar* text;
382         gint response_id;
383
384         g_return_if_fail (GEDIT_IS_MESSAGE_AREA (message_area));
385
386         if (first_button_text == NULL)
387                 return;
388
389         text = first_button_text;
390         response_id = va_arg (args, gint);
391
392         while (text != NULL)
393         {
394                 gedit_message_area_add_button (message_area,
395                                                text,
396                                                response_id);
397
398                 text = va_arg (args, gchar*);
399                 if (text == NULL)
400                         break;
401
402                 response_id = va_arg (args, int);
403         }
404 }
405
406 void
407 gedit_message_area_add_buttons (GeditMessageArea *message_area,
408                                 const gchar      *first_button_text,
409                                 ...)
410 {
411         va_list args;
412
413         va_start (args, first_button_text);
414
415         gedit_message_area_add_buttons_valist (message_area,
416                                                first_button_text,
417                                                args);
418
419         va_end (args);
420 }
421
422 GtkWidget *
423 gedit_message_area_new (void)
424 {
425         return g_object_new (GEDIT_TYPE_MESSAGE_AREA, NULL);
426 }
427
428 GtkWidget *
429 gedit_message_area_new_with_buttons (const gchar *first_button_text,
430                                      ...)
431 {
432         GeditMessageArea *message_area;
433         va_list args;
434
435         message_area = GEDIT_MESSAGE_AREA (gedit_message_area_new ());
436
437         va_start (args, first_button_text);
438
439         gedit_message_area_add_buttons_valist (message_area,
440                                                first_button_text,
441                                                args);
442
443         va_end (args);
444
445         return GTK_WIDGET (message_area);
446 }
447
448 void
449 gedit_message_area_set_response_sensitive (GeditMessageArea *message_area,
450                                            gint              response_id,
451                                            gboolean          setting)
452 {
453         GList *children;
454         GList *tmp_list;
455
456         g_return_if_fail (GEDIT_IS_MESSAGE_AREA (message_area));
457
458         children = gtk_container_get_children (GTK_CONTAINER (message_area->priv->action_area));
459
460         tmp_list = children;
461         while (tmp_list != NULL)
462         {
463                 GtkWidget *widget = tmp_list->data;
464                 ResponseData *rd = get_response_data (widget, FALSE);
465
466                 if (rd && rd->response_id == response_id)
467                         gtk_widget_set_sensitive (widget, setting);
468
469                 tmp_list = g_list_next (tmp_list);
470         }
471
472         g_list_free (children);
473 }
474
475 void
476 gedit_message_area_set_default_response (GeditMessageArea *message_area,
477                                          gint              response_id)
478 {
479         GList *children;
480         GList *tmp_list;
481
482         g_return_if_fail (GEDIT_IS_MESSAGE_AREA (message_area));
483
484         children = gtk_container_get_children (GTK_CONTAINER (message_area->priv->action_area));
485
486         tmp_list = children;
487         while (tmp_list != NULL)
488         {
489                 GtkWidget *widget = tmp_list->data;
490                 ResponseData *rd = get_response_data (widget, FALSE);
491
492                 if (rd && rd->response_id == response_id)
493                 gtk_widget_grab_default (widget);
494
495                 tmp_list = g_list_next (tmp_list);
496         }
497
498         g_list_free (children);
499 }
500
501 void
502 gedit_message_area_response (GeditMessageArea *message_area,
503                              gint              response_id)
504 {
505         g_return_if_fail (GEDIT_IS_MESSAGE_AREA (message_area));
506
507         g_signal_emit (message_area,
508                        signals[RESPONSE],
509                        0,
510                        response_id);
511 }
512
513 GtkWidget *
514 gedit_message_area_add_stock_button_with_text (GeditMessageArea *message_area,
515                                                const gchar      *text,
516                                                const gchar      *stock_id,
517                                                gint              response_id)
518 {
519         GtkWidget *button;
520
521         g_return_val_if_fail (GEDIT_IS_MESSAGE_AREA (message_area), NULL);
522         g_return_val_if_fail (text != NULL, NULL);
523         g_return_val_if_fail (stock_id != NULL, NULL);
524
525         button = gtk_button_new_with_mnemonic (text);
526         gtk_button_set_image (GTK_BUTTON (button),
527                               gtk_image_new_from_stock (stock_id,
528                                                         GTK_ICON_SIZE_BUTTON));
529
530         GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
531
532         gtk_widget_show (button);
533
534         gedit_message_area_add_action_widget (message_area,
535                                               button,
536                                               response_id);
537
538         return button;
539 }
540