1 #include <config.h>
2 #include <string.h>
3
4 #include <glib/gi18n.h>
5 #include <gdk/gdkkeysyms.h>
6 #include <gtk/gtk.h>
7 #include <gdk/gdk.h>
8
9 #include "button-widget.h"
10 #include "panel-widget.h"
11 #include "panel-types.h"
12 #include "panel-util.h"
13 #include "panel-config-global.h"
14 #include "panel-marshal.h"
15 #include "panel-typebuiltins.h"
16 #include "panel-globals.h"
17 #include "panel-enums.h"
18 #include "panel-enums-gsettings.h"
19
20 struct _ButtonWidgetPrivate {
21 GtkIconTheme *icon_theme;
22 cairo_surface_t *surface;
23 cairo_surface_t *surface_hc;
24
25 char *filename;
26
27 PanelOrientation orientation;
28
29 int size;
30
31 guint activatable : 1;
32 guint ignore_leave : 1;
33 guint arrow : 1;
34 guint dnd_highlight : 1;
35 };
36
37 static void button_widget_icon_theme_changed (ButtonWidget *button);
38 static void button_widget_reload_surface (ButtonWidget *button);
39
40 enum {
41 PROP_0,
42 PROP_ACTIVATABLE,
43 PROP_IGNORE_LEAVE,
44 PROP_HAS_ARROW,
45 PROP_DND_HIGHLIGHT,
46 PROP_ORIENTATION,
47 PROP_ICON_NAME
48 };
49
50 #define BUTTON_WIDGET_DISPLACEMENT 2
51
G_DEFINE_TYPE_WITH_PRIVATE(ButtonWidget,button_widget,GTK_TYPE_BUTTON)52 G_DEFINE_TYPE_WITH_PRIVATE (ButtonWidget, button_widget, GTK_TYPE_BUTTON)
53
54 /* colorshift a surface */
55 static void
56 do_colorshift (cairo_surface_t *dest, cairo_surface_t *src, int shift)
57 {
58 gint i, j;
59 gint width, height, has_alpha, srcrowstride, destrowstride;
60 guchar *target_pixels;
61 guchar *original_pixels;
62 int val;
63 guchar r,g,b;
64
65 has_alpha = cairo_surface_get_content (src) != CAIRO_CONTENT_COLOR;
66 width = cairo_image_surface_get_width (src);
67 height = cairo_image_surface_get_height (src);
68 srcrowstride = cairo_image_surface_get_stride (src);
69 destrowstride = cairo_image_surface_get_stride (dest);
70 original_pixels = cairo_image_surface_get_data (src);
71 target_pixels = cairo_image_surface_get_data (dest);
72
73 for (i = 0; i < height; i++) {
74 guchar *pixdest = target_pixels + i*destrowstride;
75 guchar *pixsrc = original_pixels + i*srcrowstride;
76 for (j = 0; j < width; j++) {
77 r = *(pixsrc++);
78 g = *(pixsrc++);
79 b = *(pixsrc++);
80 val = r + shift;
81 *(pixdest++) = CLAMP(val, 0, 255);
82 val = g + shift;
83 *(pixdest++) = CLAMP(val, 0, 255);
84 val = b + shift;
85 *(pixdest++) = CLAMP(val, 0, 255);
86 if (has_alpha)
87 *(pixdest++) = *(pixsrc++);
88 }
89 }
90 }
91
92 static cairo_surface_t *
make_hc_surface(cairo_surface_t * surface)93 make_hc_surface (cairo_surface_t *surface)
94 {
95 cairo_t *cr;
96 cairo_surface_t *new;
97
98 if (!surface)
99 return NULL;
100
101 new = cairo_surface_create_similar (surface,
102 cairo_surface_get_content (surface),
103 cairo_image_surface_get_width (surface),
104 cairo_image_surface_get_height (surface));
105
106 do_colorshift (new, surface, 30);
107
108 cr = cairo_create (new);
109 cairo_set_operator (cr, CAIRO_OPERATOR_DEST_IN);
110 cairo_mask_surface (cr, surface, 0, 0);
111 cairo_destroy (cr);
112
113 return new;
114 }
115
116 static void
button_widget_realize(GtkWidget * widget)117 button_widget_realize(GtkWidget *widget)
118 {
119 gtk_widget_add_events (widget, GDK_POINTER_MOTION_MASK |
120 GDK_POINTER_MOTION_HINT_MASK |
121 GDK_KEY_PRESS_MASK);
122
123 GTK_WIDGET_CLASS (button_widget_parent_class)->realize (widget);
124
125 BUTTON_WIDGET (widget)->priv->icon_theme = gtk_icon_theme_get_for_screen (gtk_widget_get_screen (widget));
126 g_signal_connect_object (BUTTON_WIDGET (widget)->priv->icon_theme,
127 "changed",
128 G_CALLBACK (button_widget_icon_theme_changed),
129 widget,
130 G_CONNECT_SWAPPED);
131
132 button_widget_reload_surface (BUTTON_WIDGET (widget));
133 }
134
135 static void
button_widget_unrealize(GtkWidget * widget)136 button_widget_unrealize (GtkWidget *widget)
137 {
138 g_signal_handlers_disconnect_by_func (BUTTON_WIDGET (widget)->priv->icon_theme,
139 G_CALLBACK (button_widget_icon_theme_changed),
140 widget);
141
142 GTK_WIDGET_CLASS (button_widget_parent_class)->unrealize (widget);
143 }
144
145 static void
button_widget_unset_surfaces(ButtonWidget * button)146 button_widget_unset_surfaces (ButtonWidget *button)
147 {
148 if (button->priv->surface)
149 cairo_surface_destroy (button->priv->surface);
150 button->priv->surface = NULL;
151
152 if (button->priv->surface_hc)
153 cairo_surface_destroy (button->priv->surface_hc);
154 button->priv->surface_hc = NULL;
155 }
156
157 static void
button_widget_reload_surface(ButtonWidget * button)158 button_widget_reload_surface (ButtonWidget *button)
159 {
160 button_widget_unset_surfaces (button);
161
162 if (button->priv->size <= 1 || button->priv->icon_theme == NULL)
163 return;
164
165 if (button->priv->filename != NULL &&
166 button->priv->filename [0] != '\0') {
167 gint scale;
168 char *error = NULL;
169
170 scale = gtk_widget_get_scale_factor (GTK_WIDGET (button));
171
172 button->priv->surface =
173 panel_load_icon (button->priv->icon_theme,
174 button->priv->filename,
175 button->priv->size * scale,
176 (button->priv->orientation & PANEL_VERTICAL_MASK) ? button->priv->size * scale : -1,
177 (button->priv->orientation & PANEL_HORIZONTAL_MASK) ? button->priv->size * scale: -1,
178 &error);
179 if (error) {
180 /* FIXME: this is not rendered at button->priv->size */
181 GtkIconTheme *icon_theme = gtk_icon_theme_get_default();
182 button->priv->surface = gtk_icon_theme_load_surface (icon_theme,
183 "image-missing",
184 GTK_ICON_SIZE_BUTTON,
185 scale,
186 NULL,
187 GTK_ICON_LOOKUP_FORCE_SVG | GTK_ICON_LOOKUP_USE_BUILTIN,
188 NULL);
189 g_free (error);
190 }
191 }
192
193 button->priv->surface_hc = make_hc_surface (button->priv->surface);
194
195 gtk_widget_queue_resize (GTK_WIDGET (button));
196 }
197
198 static void
button_widget_icon_theme_changed(ButtonWidget * button)199 button_widget_icon_theme_changed (ButtonWidget *button)
200 {
201 if (button->priv->filename != NULL)
202 button_widget_reload_surface (button);
203 }
204
205 static void
button_widget_finalize(GObject * object)206 button_widget_finalize (GObject *object)
207 {
208 ButtonWidget *button = (ButtonWidget *) object;
209
210 button_widget_unset_surfaces (button);
211
212 g_free (button->priv->filename);
213 button->priv->filename = NULL;
214
215 G_OBJECT_CLASS (button_widget_parent_class)->finalize (object);
216 }
217
218 static void
button_widget_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)219 button_widget_get_property (GObject *object,
220 guint prop_id,
221 GValue *value,
222 GParamSpec *pspec)
223 {
224 ButtonWidget *button;
225
226 g_return_if_fail (BUTTON_IS_WIDGET (object));
227
228 button = BUTTON_WIDGET (object);
229
230 switch (prop_id) {
231 case PROP_ACTIVATABLE:
232 g_value_set_boolean (value, button->priv->activatable);
233 break;
234 case PROP_IGNORE_LEAVE:
235 g_value_set_boolean (value, button->priv->ignore_leave);
236 break;
237 case PROP_HAS_ARROW:
238 g_value_set_boolean (value, button->priv->arrow);
239 break;
240 case PROP_DND_HIGHLIGHT:
241 g_value_set_boolean (value, button->priv->dnd_highlight);
242 break;
243 case PROP_ORIENTATION:
244 g_value_set_enum (value, button->priv->orientation);
245 break;
246 case PROP_ICON_NAME:
247 g_value_set_string (value, button->priv->filename);
248 break;
249 default:
250 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
251 break;
252 }
253 }
254
255 static void
button_widget_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)256 button_widget_set_property (GObject *object,
257 guint prop_id,
258 const GValue *value,
259 GParamSpec *pspec)
260 {
261 ButtonWidget *button;
262
263 g_return_if_fail (BUTTON_IS_WIDGET (object));
264
265 button = BUTTON_WIDGET (object);
266
267 switch (prop_id) {
268 case PROP_ACTIVATABLE:
269 button_widget_set_activatable (button, g_value_get_boolean (value));
270 break;
271 case PROP_IGNORE_LEAVE:
272 button_widget_set_ignore_leave (button, g_value_get_boolean (value));
273 break;
274 case PROP_HAS_ARROW:
275 button_widget_set_has_arrow (button, g_value_get_boolean (value));
276 break;
277 case PROP_DND_HIGHLIGHT:
278 button_widget_set_dnd_highlight (button, g_value_get_boolean (value));
279 break;
280 case PROP_ORIENTATION:
281 button_widget_set_orientation (button, g_value_get_enum (value));
282 break;
283 case PROP_ICON_NAME:
284 button_widget_set_icon_name (button, g_value_get_string (value));
285 break;
286 default:
287 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
288 break;
289 }
290 }
291
292 static GtkArrowType
calc_arrow(PanelOrientation orientation,int button_width,int button_height,int * x,int * y,gdouble * angle,gdouble * size)293 calc_arrow (PanelOrientation orientation,
294 int button_width,
295 int button_height,
296 int *x,
297 int *y,
298 gdouble *angle,
299 gdouble *size)
300 {
301 GtkArrowType retval = GTK_ARROW_UP;
302
303 if (orientation & PANEL_HORIZONTAL_MASK) {
304 if (button_width > 50)
305 button_width = 50;
306 } else {
307 if (button_height > 50)
308 button_height = 50;
309 }
310
311 *size = ((orientation & PANEL_HORIZONTAL_MASK) ? button_width : button_height) / 2;
312 *angle = 0;
313
314 switch (orientation) {
315 case PANEL_ORIENTATION_TOP:
316 *x = (button_width - (*size)) / 2;
317 *y = button_height * .99 - (*size) / (3/2); /* 3/2 is the approximate ratio of GTK arrows */
318 *angle = G_PI;
319 retval = GTK_ARROW_DOWN;
320 break;
321 case PANEL_ORIENTATION_BOTTOM:
322 *x = (button_width - (*size)) / 2;
323 *y = button_height * .01;
324 *angle = 0;
325 retval = GTK_ARROW_UP;
326 break;
327 case PANEL_ORIENTATION_LEFT:
328 *x = button_width * .99 - (*size) / (3/2); /* 3/2 is the approximate ratio of GTK arrows */
329 *y = (button_height - (*size)) / 2;
330 *angle = G_PI / 2;
331 retval = GTK_ARROW_RIGHT;
332 break;
333 case PANEL_ORIENTATION_RIGHT:
334 *x = button_width * .01;
335 *y = (button_height - (*size)) / 2;
336 *angle = 3 * (G_PI / 2);
337 retval = GTK_ARROW_LEFT;
338 break;
339 }
340
341 return retval;
342 }
343
344 static gboolean
button_widget_draw(GtkWidget * widget,cairo_t * cr)345 button_widget_draw (GtkWidget *widget,
346 cairo_t *cr)
347 {
348 ButtonWidget *button_widget;
349 int width;
350 int height;
351 GtkStyleContext *context;
352 GtkStateFlags state_flags;
353 int off;
354 int x, y, w, h;
355 int scale;
356
357 g_return_val_if_fail (BUTTON_IS_WIDGET (widget), FALSE);
358
359 button_widget = BUTTON_WIDGET (widget);
360
361 if (!button_widget->priv->surface_hc && !button_widget->priv->surface)
362 return FALSE;
363
364 state_flags = gtk_widget_get_state_flags (widget);
365 width = gtk_widget_get_allocated_width (widget);
366 height = gtk_widget_get_allocated_height (widget);
367 scale = gtk_widget_get_scale_factor (widget);
368
369 /* offset for pressed buttons */
370 off = (button_widget->priv->activatable &&
371 (state_flags & GTK_STATE_FLAG_PRELIGHT) && (state_flags & GTK_STATE_FLAG_ACTIVE)) ?
372 BUTTON_WIDGET_DISPLACEMENT * height / 48.0 : 0;
373
374 w = cairo_image_surface_get_width (button_widget->priv->surface) / scale;
375 h = cairo_image_surface_get_height (button_widget->priv->surface) / scale;
376 x = off + (width - w) / 2;
377 y = off + (height - h) / 2;
378
379 cairo_save (cr);
380
381 if (!button_widget->priv->activatable) {
382 cairo_set_source_surface (cr, button_widget->priv->surface, x, y);
383 cairo_mask_surface (cr, button_widget->priv->surface, x, y);
384 cairo_set_operator (cr, CAIRO_OPERATOR_HSL_SATURATION);
385 cairo_set_source_rgba (cr, 0, 0, 0, 0.2);
386 } else if (panel_global_config_get_highlight_when_over () &&
387 (state_flags & GTK_STATE_FLAG_PRELIGHT || gtk_widget_has_focus (widget))) {
388 cairo_set_source_surface (cr, button_widget->priv->surface_hc, x, y);
389 } else {
390 cairo_set_source_surface (cr, button_widget->priv->surface, x, y);
391 }
392
393 cairo_paint (cr);
394 cairo_restore (cr);
395
396 context = gtk_widget_get_style_context (widget);
397
398 if (button_widget->priv->arrow) {
399 gdouble angle, size;
400 gtk_style_context_save (context);
401 gtk_style_context_set_state (context, state_flags);
402
403 calc_arrow (button_widget->priv->orientation,
404 width, height,
405 &x, &y,
406 &angle, &size);
407
408 cairo_save (cr);
409 gtk_render_arrow (context, cr, angle, x, y, size);
410 cairo_restore (cr);
411
412 gtk_style_context_restore (context);
413 }
414
415 if (button_widget->priv->dnd_highlight) {
416
417 cairo_save (cr);
418 cairo_set_line_width (cr, 1);
419 cairo_set_source_rgb (cr, 0., 0., 0.);
420 cairo_rectangle (cr, 0.5, 0.5, width - 1, height - 1);
421 cairo_stroke (cr);
422 cairo_restore (cr);
423 }
424
425 if (gtk_widget_has_focus (widget)) {
426 gtk_style_context_save (context);
427 gtk_style_context_set_state (context, state_flags);
428
429 cairo_save (cr);
430 gtk_render_focus (context, cr, 0, 0, width, height);
431 cairo_restore (cr);
432
433 gtk_style_context_restore (context);
434 }
435
436 return FALSE;
437 }
438
439 static void
button_widget_get_preferred_width(GtkWidget * widget,gint * minimal_width,gint * natural_width)440 button_widget_get_preferred_width (GtkWidget *widget,
441 gint *minimal_width,
442 gint *natural_width)
443 {
444 ButtonWidget *button_widget = BUTTON_WIDGET (widget);
445 GtkWidget *parent;
446 int size;
447
448 parent = gtk_widget_get_parent (widget);
449
450 if (button_widget->priv->orientation & PANEL_HORIZONTAL_MASK){
451 size = gtk_widget_get_allocated_height (parent);
452
453 /* should get this value (50) from gsettings, user defined value in properties of the panel (max_icon_size) OR use 48*/
454 if ( size > 50 )
455 size = 50;
456
457 } else
458 size = gtk_widget_get_allocated_width (parent);
459
460 *minimal_width = *natural_width = size;
461 }
462
463 static void
button_widget_get_preferred_height(GtkWidget * widget,gint * minimal_height,gint * natural_height)464 button_widget_get_preferred_height (GtkWidget *widget,
465 gint *minimal_height,
466 gint *natural_height)
467 {
468 ButtonWidget *button_widget = BUTTON_WIDGET (widget);
469 GtkWidget *parent;
470 int size;
471
472 parent = gtk_widget_get_parent (widget);
473
474 if (button_widget->priv->orientation & PANEL_HORIZONTAL_MASK)
475 size = gtk_widget_get_allocated_height (parent);
476 else {
477 size = gtk_widget_get_allocated_width (parent);
478
479 /* should get this value (50) from gsettings, user defined value in properties of the panel (max_icon_size) OR use 48*/
480 if ( size > 50 )
481 size = 50;
482
483 }
484
485 *minimal_height = *natural_height = size;
486 }
487
488 static void
button_widget_size_allocate(GtkWidget * widget,GtkAllocation * allocation)489 button_widget_size_allocate (GtkWidget *widget,
490 GtkAllocation *allocation)
491 {
492 ButtonWidget *button_widget = BUTTON_WIDGET (widget);
493 int size;
494
495 /* should get this value (50) from gsettings, user defined value in properties of the panel (max_icon_size) OR use 48?*/
496 if (button_widget->priv->orientation & PANEL_HORIZONTAL_MASK) {
497 if ( allocation->height > 50 ) {
498 allocation->width = 50;
499 }
500 } else {
501 if ( allocation->width > 50 ) {
502 allocation->height = 50;
503 }
504 }
505
506 GTK_WIDGET_CLASS (button_widget_parent_class)->size_allocate (widget, allocation);
507
508 if (button_widget->priv->orientation & PANEL_HORIZONTAL_MASK)
509 size = allocation->height;
510 else
511 size = allocation->width;
512
513 if (size < 22)
514 size = 16;
515 else if (size < 24)
516 size = 22;
517 else if (size < 32)
518 size = 24;
519 else if (size < 48)
520 size = 32;
521 else
522 size = 48;
523
524 if (button_widget->priv->size != size) {
525 button_widget->priv->size = size;
526
527 button_widget_reload_surface (button_widget);
528 }
529 }
530
531 static void
button_widget_activate(GtkButton * button)532 button_widget_activate (GtkButton *button)
533 {
534 ButtonWidget *button_widget = BUTTON_WIDGET (button);
535
536 if (!button_widget->priv->activatable)
537 return;
538
539 if (GTK_BUTTON_CLASS (button_widget_parent_class)->activate)
540 GTK_BUTTON_CLASS (button_widget_parent_class)->activate (button);
541 }
542
543 static gboolean
button_widget_button_press(GtkWidget * widget,GdkEventButton * event)544 button_widget_button_press (GtkWidget *widget, GdkEventButton *event)
545 {
546 g_return_val_if_fail (BUTTON_IS_WIDGET (widget), FALSE);
547 g_return_val_if_fail (event != NULL, FALSE);
548
549 if (event->button == 1 && BUTTON_WIDGET (widget)->priv->activatable &&
550 /* we don't want to have two/three "click" events for double/triple
551 * clicks. FIXME: this is only a workaround, waiting for bug 159101 */
552 event->type == GDK_BUTTON_PRESS)
553 return GTK_WIDGET_CLASS (button_widget_parent_class)->button_press_event (widget, event);
554
555 return FALSE;
556 }
557
558 static gboolean
button_widget_enter_notify(GtkWidget * widget,GdkEventCrossing * event)559 button_widget_enter_notify (GtkWidget *widget, GdkEventCrossing *event)
560 {
561 gboolean in_button;
562
563 g_return_val_if_fail (BUTTON_IS_WIDGET (widget), FALSE);
564
565 GtkStateFlags state_flags = gtk_widget_get_state_flags (widget);
566 in_button = state_flags & GTK_STATE_FLAG_PRELIGHT;
567
568 GTK_WIDGET_CLASS (button_widget_parent_class)->enter_notify_event (widget, event);
569
570 state_flags = gtk_widget_get_state_flags (widget);
571 if (in_button != (state_flags & GTK_STATE_FLAG_PRELIGHT) &&
572 panel_global_config_get_highlight_when_over ())
573 gtk_widget_queue_draw (widget);
574
575 return FALSE;
576 }
577
578 static gboolean
button_widget_leave_notify(GtkWidget * widget,GdkEventCrossing * event)579 button_widget_leave_notify (GtkWidget *widget, GdkEventCrossing *event)
580 {
581 gboolean in_button;
582
583 g_return_val_if_fail (BUTTON_IS_WIDGET (widget), FALSE);
584
585 GtkStateFlags state_flags = gtk_widget_get_state_flags (widget);
586 in_button = state_flags & GTK_STATE_FLAG_PRELIGHT;
587
588 GTK_WIDGET_CLASS (button_widget_parent_class)->leave_notify_event (widget, event);
589
590 state_flags = gtk_widget_get_state_flags (widget);
591 if (in_button != (state_flags & GTK_STATE_FLAG_PRELIGHT) &&
592 panel_global_config_get_highlight_when_over ())
593 gtk_widget_queue_draw (widget);
594
595 return FALSE;
596 }
597
598 static void
button_widget_init(ButtonWidget * button)599 button_widget_init (ButtonWidget *button)
600 {
601 button->priv = button_widget_get_instance_private (button);
602
603 button->priv->icon_theme = NULL;
604 button->priv->surface = NULL;
605 button->priv->surface_hc = NULL;
606
607 button->priv->filename = NULL;
608
609 button->priv->orientation = PANEL_ORIENTATION_TOP;
610
611 button->priv->size = 0;
612
613 button->priv->activatable = FALSE;
614 button->priv->ignore_leave = FALSE;
615 button->priv->arrow = FALSE;
616 button->priv->dnd_highlight = FALSE;
617 }
618
619 static void
button_widget_class_init(ButtonWidgetClass * klass)620 button_widget_class_init (ButtonWidgetClass *klass)
621 {
622 GObjectClass *gobject_class = (GObjectClass *) klass;
623 GtkWidgetClass *widget_class = (GtkWidgetClass *) klass;
624 GtkButtonClass *button_class = (GtkButtonClass *) klass;
625
626 gobject_class->finalize = button_widget_finalize;
627 gobject_class->get_property = button_widget_get_property;
628 gobject_class->set_property = button_widget_set_property;
629
630 widget_class->realize = button_widget_realize;
631 widget_class->unrealize = button_widget_unrealize;
632 widget_class->size_allocate = button_widget_size_allocate;
633 widget_class->get_preferred_width = button_widget_get_preferred_width;
634 widget_class->get_preferred_height = button_widget_get_preferred_height;
635 widget_class->draw = button_widget_draw;
636 widget_class->button_press_event = button_widget_button_press;
637 widget_class->enter_notify_event = button_widget_enter_notify;
638 widget_class->leave_notify_event = button_widget_leave_notify;
639
640 button_class->activate = button_widget_activate;
641
642 g_object_class_install_property (
643 gobject_class,
644 PROP_ACTIVATABLE,
645 g_param_spec_boolean ("activatable",
646 "Activatable",
647 "Whether the button is activatable",
648 TRUE,
649 G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
650
651 g_object_class_install_property (
652 gobject_class,
653 PROP_IGNORE_LEAVE,
654 g_param_spec_boolean ("ignore-leave",
655 "Ignore leaving to not unhighlight the icon",
656 "Whether or not to unhighlight the icon when the cursor leaves it",
657 FALSE,
658 G_PARAM_READWRITE));
659
660 g_object_class_install_property (
661 gobject_class,
662 PROP_HAS_ARROW,
663 g_param_spec_boolean ("has-arrow",
664 "Has Arrow",
665 "Whether or not to draw an arrow indicator",
666 FALSE,
667 G_PARAM_READWRITE));
668
669 g_object_class_install_property (
670 gobject_class,
671 PROP_DND_HIGHLIGHT,
672 g_param_spec_boolean ("dnd-highlight",
673 "Drag and drop Highlight",
674 "Whether or not to highlight the icon during drag and drop",
675 FALSE,
676 G_PARAM_READWRITE));
677
678 g_object_class_install_property (
679 gobject_class,
680 PROP_ORIENTATION,
681 g_param_spec_enum ("orientation",
682 "Orientation",
683 "The ButtonWidget orientation",
684 PANEL_TYPE_ORIENTATION,
685 PANEL_ORIENTATION_TOP,
686 G_PARAM_READWRITE));
687
688 g_object_class_install_property (
689 gobject_class,
690 PROP_ICON_NAME,
691 g_param_spec_string ("icon-name",
692 "Icon Name",
693 "The desired icon for the ButtonWidget",
694 NULL,
695 G_PARAM_READWRITE));
696 }
697
698 GtkWidget *
button_widget_new(const char * filename,gboolean arrow,PanelOrientation orientation)699 button_widget_new (const char *filename,
700 gboolean arrow,
701 PanelOrientation orientation)
702 {
703 GtkWidget *retval;
704
705 retval = g_object_new (
706 BUTTON_TYPE_WIDGET,
707 "has-arrow", arrow,
708 "orientation", orientation,
709 "icon-name", filename,
710 NULL);
711
712 return retval;
713 }
714
715 void
button_widget_set_activatable(ButtonWidget * button,gboolean activatable)716 button_widget_set_activatable (ButtonWidget *button,
717 gboolean activatable)
718 {
719 g_return_if_fail (BUTTON_IS_WIDGET (button));
720
721 activatable = activatable != FALSE;
722
723 if (button->priv->activatable != activatable) {
724 button->priv->activatable = activatable;
725
726 if (gtk_widget_is_drawable (GTK_WIDGET (button)))
727 gtk_widget_queue_draw (GTK_WIDGET (button));
728
729 g_object_notify (G_OBJECT (button), "activatable");
730 }
731 }
732
733 gboolean
button_widget_get_activatable(ButtonWidget * button)734 button_widget_get_activatable (ButtonWidget *button)
735 {
736 g_return_val_if_fail (BUTTON_IS_WIDGET (button), FALSE);
737
738 return button->priv->activatable;
739 }
740
741 void
button_widget_set_icon_name(ButtonWidget * button,const char * icon_name)742 button_widget_set_icon_name (ButtonWidget *button,
743 const char *icon_name)
744 {
745 g_return_if_fail (BUTTON_IS_WIDGET (button));
746
747 if (button->priv->filename && icon_name &&
748 !strcmp (button->priv->filename, icon_name))
749 return;
750
751 if (button->priv->filename)
752 g_free (button->priv->filename);
753 button->priv->filename = g_strdup (icon_name);
754
755 button_widget_reload_surface (button);
756
757 g_object_notify (G_OBJECT (button), "icon-name");
758 }
759
760 const char *
button_widget_get_icon_name(ButtonWidget * button)761 button_widget_get_icon_name (ButtonWidget *button)
762 {
763 g_return_val_if_fail (BUTTON_IS_WIDGET (button), NULL);
764
765 return button->priv->filename;
766 }
767
768 void
button_widget_set_orientation(ButtonWidget * button,PanelOrientation orientation)769 button_widget_set_orientation (ButtonWidget *button,
770 PanelOrientation orientation)
771 {
772 g_return_if_fail (BUTTON_IS_WIDGET (button));
773
774 if (button->priv->orientation == orientation)
775 return;
776
777 button->priv->orientation = orientation;
778
779 /* Force a re-scale */
780 button->priv->size = -1;
781
782 gtk_widget_queue_resize (GTK_WIDGET (button));
783
784 g_object_notify (G_OBJECT (button), "orientation");
785 }
786
787 PanelOrientation
button_widget_get_orientation(ButtonWidget * button)788 button_widget_get_orientation (ButtonWidget *button)
789 {
790 g_return_val_if_fail (BUTTON_IS_WIDGET (button), 0);
791
792 return button->priv->orientation;
793 }
794
795 void
button_widget_set_has_arrow(ButtonWidget * button,gboolean has_arrow)796 button_widget_set_has_arrow (ButtonWidget *button,
797 gboolean has_arrow)
798 {
799 g_return_if_fail (BUTTON_IS_WIDGET (button));
800
801 has_arrow = has_arrow != FALSE;
802
803 if (button->priv->arrow == has_arrow)
804 return;
805
806 button->priv->arrow = has_arrow;
807
808 gtk_widget_queue_draw (GTK_WIDGET (button));
809
810 g_object_notify (G_OBJECT (button), "has-arrow");
811 }
812
813 gboolean
button_widget_get_has_arrow(ButtonWidget * button)814 button_widget_get_has_arrow (ButtonWidget *button)
815 {
816 g_return_val_if_fail (BUTTON_IS_WIDGET (button), FALSE);
817
818 return button->priv->arrow;
819 }
820
821 void
button_widget_set_dnd_highlight(ButtonWidget * button,gboolean dnd_highlight)822 button_widget_set_dnd_highlight (ButtonWidget *button,
823 gboolean dnd_highlight)
824 {
825 g_return_if_fail (BUTTON_IS_WIDGET (button));
826
827 dnd_highlight = dnd_highlight != FALSE;
828
829 if (button->priv->dnd_highlight == dnd_highlight)
830 return;
831
832 button->priv->dnd_highlight = dnd_highlight;
833
834 gtk_widget_queue_draw (GTK_WIDGET (button));
835
836 g_object_notify (G_OBJECT (button), "dnd-highlight");
837 }
838
839 gboolean
button_widget_get_dnd_highlight(ButtonWidget * button)840 button_widget_get_dnd_highlight (ButtonWidget *button)
841 {
842 g_return_val_if_fail (BUTTON_IS_WIDGET (button), FALSE);
843
844 return button->priv->dnd_highlight;
845 }
846
847 void
button_widget_set_ignore_leave(ButtonWidget * button,gboolean ignore_leave)848 button_widget_set_ignore_leave (ButtonWidget *button,
849 gboolean ignore_leave)
850 {
851 g_return_if_fail (BUTTON_IS_WIDGET (button));
852
853 ignore_leave = ignore_leave != FALSE;
854
855 if (button->priv->ignore_leave == ignore_leave)
856 return;
857
858 button->priv->ignore_leave = ignore_leave;
859
860 gtk_widget_queue_draw (GTK_WIDGET (button));
861
862 g_object_notify (G_OBJECT (button), "ignore-leave");
863 }
864
865 gboolean
button_widget_get_ignore_leave(ButtonWidget * button)866 button_widget_get_ignore_leave (ButtonWidget *button)
867 {
868 g_return_val_if_fail (BUTTON_IS_WIDGET (button), FALSE);
869
870 return button->priv->ignore_leave;
871 }
872
873 GtkIconTheme *
button_widget_get_icon_theme(ButtonWidget * button)874 button_widget_get_icon_theme (ButtonWidget *button)
875 {
876 g_return_val_if_fail (BUTTON_IS_WIDGET (button), NULL);
877
878 return button->priv->icon_theme;
879 }
880
881 cairo_surface_t *
button_widget_get_surface(ButtonWidget * button)882 button_widget_get_surface (ButtonWidget *button)
883 {
884 g_return_val_if_fail (BUTTON_IS_WIDGET (button), NULL);
885
886 if (!button->priv->surface)
887 return NULL;
888
889 return cairo_surface_reference (button->priv->surface);
890 }
891