source: trunk/third/gnome-panel/gnome-panel/button-widget.c @ 18631

Revision 18631, 24.0 KB checked in by ghudson, 21 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r18630, which included commits to RCS files with non-trunk default branches.
Line 
1#include <config.h>
2#include <math.h>
3#include <string.h>
4
5#include <gdk/gdkkeysyms.h>
6#include <gtk/gtk.h>
7#include <libgnome/gnome-i18n.h>
8#include <libgnome/gnome-util.h>
9#include <libgnome/gnome-desktop-item.h>
10#include <gdk-pixbuf/gdk-pixbuf.h>
11
12#include "button-widget.h"
13#include "panel-widget.h"
14#include "basep-widget.h"
15#include "panel-main.h"
16#include "panel-types.h"
17#include "panel-util.h"
18#include "panel-config-global.h"
19#include "panel-marshal.h"
20#include "panel-typebuiltins.h"
21
22
23static GdkPixbuf *button_load_pixbuf (const char  *file,
24                                      int          preffered_size,
25                                      char       **error);
26
27enum {
28        PROP_0,
29        PROP_SIZE,
30        PROP_HAS_ARROW,
31        PROP_ORIENT,
32        PROP_ICON_NAME,
33        PROP_STOCK_ID,
34};
35
36#define BUTTON_WIDGET_DISPLACEMENT 2
37
38extern GlobalConfig global_config;
39
40static GObjectClass *parent_class;
41
42static void
43translate_to(GtkWidget *from, GtkWidget *to, int *x, int *y)
44{
45        while (from != to) {
46                if (!GTK_WIDGET_NO_WINDOW (from)) {
47                        *x += MAX (from->allocation.x, 0);
48                        *y += MAX (from->allocation.y, 0);
49                }
50                from = from->parent;
51        }
52}
53
54static GtkWidget *
55get_frame(BasePWidget *basep)
56{
57        if (GTK_WIDGET_VISIBLE (basep->frame)) {
58                return basep->frame;
59        } else {
60                return basep->innerebox;
61        }
62}
63
64static void
65calculate_overlay_geometry (PanelWidget *panel,
66                            GtkWidget   *parent,
67                            GtkWidget   *applet,
68                            int         *x,
69                            int         *y,
70                            int         *w,
71                            int         *h)
72{
73        *x = applet->allocation.x;
74        *y = applet->allocation.y;
75        *w = applet->allocation.width;
76        *h = applet->allocation.height;
77
78        translate_to (GTK_WIDGET(panel), parent, x, y);
79
80        if(panel->orient == GTK_ORIENTATION_HORIZONTAL) {
81                if (applet->allocation.x > panel->size) {
82                        *x = parent->requisition.width + 1;
83                        *y = parent->requisition.height + 1;
84                        return;
85                }
86
87                *y = 0;
88                /* we use the requisition, since allocation might have not
89                   yet happened if we are inside the allocation, anyway
90                   they are the same for basep */
91                if(*h < parent->requisition.height)
92                        *h = parent->requisition.height;
93
94                if ((*w + applet->allocation.x) > panel->size) {
95                        *w = panel->size - applet->allocation.x;
96                }
97
98                if ( ! BASEP_IS_WIDGET(parent)) {
99                        /*don't do the edge flushing on foobar*/
100                        return;
101                }
102
103                /* if on the edge (only if padding is 0)
104                   then make the thing flush with the innerebox or frame
105                   of the basep */
106                if(applet->allocation.x == 0) {
107                        GtkWidget *frame = get_frame(BASEP_WIDGET(parent));
108                        *w += (*x - frame->allocation.x);
109                        *x = frame->allocation.x;
110                } else if(applet->allocation.x + *w == panel->size) {
111                        GtkWidget *frame = get_frame(BASEP_WIDGET(parent));
112                        *w = frame->allocation.width + frame->allocation.x - *x;
113                }
114        } else {
115                if (applet->allocation.y > panel->size) {
116                        *x = parent->requisition.width + 1;
117                        *y = parent->requisition.height + 1;
118                        return;
119                }
120
121                *x = 0;
122                if(*w < parent->requisition.width)
123                        *w = parent->requisition.width;
124
125                if ((*h + applet->allocation.y) > panel->size) {
126                        *h = panel->size - applet->allocation.y;
127                }
128
129                if ( ! BASEP_IS_WIDGET(parent)) {
130                        /*don't do the edge flushing on foobar*/
131                        return;
132                }
133
134                /* if on the edge (only if padding is 0)
135                   then make the thing flush with the innerbox of frame
136                   of the basep */
137                if(applet->allocation.y == 0) {
138                        GtkWidget *frame = get_frame(BASEP_WIDGET(parent));
139                        *h += (*y - frame->allocation.y);
140                        *y = frame->allocation.y;
141                } else if(applet->allocation.y + *h == panel->size) {
142                        GtkWidget *frame = get_frame(BASEP_WIDGET(parent));
143                        *h = frame->allocation.height + frame->allocation.y - *y;
144                }
145        }
146}
147
148/* colorshift a pixbuf */
149static void
150do_colorshift (GdkPixbuf *dest, GdkPixbuf *src, int shift)
151{
152        gint i, j;
153        gint width, height, has_alpha, srcrowstride, destrowstride;
154        guchar *target_pixels;
155        guchar *original_pixels;
156        guchar *pixsrc;
157        guchar *pixdest;
158        int val;
159        guchar r,g,b;
160
161        has_alpha = gdk_pixbuf_get_has_alpha (src);
162        width = gdk_pixbuf_get_width (src);
163        height = gdk_pixbuf_get_height (src);
164        srcrowstride = gdk_pixbuf_get_rowstride (src);
165        destrowstride = gdk_pixbuf_get_rowstride (dest);
166        target_pixels = gdk_pixbuf_get_pixels (dest);
167        original_pixels = gdk_pixbuf_get_pixels (src);
168
169        for (i = 0; i < height; i++) {
170                pixdest = target_pixels + i*destrowstride;
171                pixsrc = original_pixels + i*srcrowstride;
172                for (j = 0; j < width; j++) {
173                        r = *(pixsrc++);
174                        g = *(pixsrc++);
175                        b = *(pixsrc++);
176                        val = r + shift;
177                        *(pixdest++) = CLAMP(val, 0, 255);
178                        val = g + shift;
179                        *(pixdest++) = CLAMP(val, 0, 255);
180                        val = b + shift;
181                        *(pixdest++) = CLAMP(val, 0, 255);
182                        if (has_alpha)
183                                *(pixdest++) = *(pixsrc++);
184                }
185        }
186}
187
188static GdkPixbuf *
189make_hc_pixbuf (GdkPixbuf *pb)
190{
191        GdkPixbuf *new;
192       
193        if (!pb)
194                return NULL;
195
196        new = gdk_pixbuf_new (gdk_pixbuf_get_colorspace (pb),
197                              gdk_pixbuf_get_has_alpha (pb),
198                              gdk_pixbuf_get_bits_per_sample (pb),
199                              gdk_pixbuf_get_width (pb),
200                              gdk_pixbuf_get_height (pb));
201        do_colorshift (new, pb, 30);
202
203        return new;
204}
205
206static void
207button_widget_realize(GtkWidget *widget)
208{
209        GdkWindowAttr attributes;
210        gint attributes_mask;
211        GtkButton *button;
212        PanelWidget *panel;
213        GtkWidget *parent;
214        int x,y,w,h;
215
216        g_return_if_fail (widget != NULL);
217        g_return_if_fail (BUTTON_IS_WIDGET (widget));
218
219        panel = PANEL_WIDGET(widget->parent);
220        parent = panel->panel_parent;
221
222        calculate_overlay_geometry(panel, parent, widget, &x, &y, &w, &h);
223
224        button = GTK_BUTTON (widget);
225
226        GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
227
228        attributes.window_type = GDK_WINDOW_CHILD;
229        attributes.x = x;
230        attributes.y = y;
231        attributes.width = w;
232        attributes.height = h;
233        attributes.wclass = GDK_INPUT_ONLY;
234        attributes.event_mask = (GDK_BUTTON_PRESS_MASK |
235                                 GDK_BUTTON_RELEASE_MASK |
236                                 GDK_POINTER_MOTION_MASK |
237                                 GDK_POINTER_MOTION_HINT_MASK |
238                                 GDK_KEY_PRESS_MASK |
239                                 GDK_ENTER_NOTIFY_MASK |
240                                 GDK_LEAVE_NOTIFY_MASK);
241        attributes_mask = GDK_WA_X | GDK_WA_Y;
242
243        widget->window = gtk_widget_get_parent_window(widget);
244        g_object_ref (G_OBJECT (widget->window));
245     
246        button->event_window = gdk_window_new (parent->window,
247                                               &attributes,
248                                               attributes_mask);
249        gdk_window_set_user_data (button->event_window, widget);
250
251        widget->style = gtk_style_attach (widget->style, widget->window);
252}
253
254static void
255button_widget_parent_set (GtkWidget *widget,
256                          GtkWidget *previous_parent)
257{
258        GtkWidget *parent;
259        int        x, y, w, h;
260
261        g_return_if_fail (BUTTON_IS_WIDGET (widget));
262
263        if (!GTK_WIDGET_REALIZED (widget)|| !widget->parent)
264                return;
265
266        parent = PANEL_WIDGET (widget->parent)->panel_parent;
267
268        calculate_overlay_geometry (
269                PANEL_WIDGET (widget->parent), parent, widget, &x, &y, &w, &h);
270
271        gdk_window_reparent (
272                GTK_BUTTON (widget)->event_window, parent->window, x, y);
273}
274
275static void
276button_widget_unset_pixbufs (ButtonWidget *button)
277{
278        if (button->pixbuf)
279                g_object_unref (button->pixbuf);
280        button->pixbuf = NULL;
281
282        if (button->scaled)
283                g_object_unref (button->scaled);
284        button->scaled = NULL;
285
286        if (button->scaled_hc)
287                g_object_unref (button->scaled_hc);
288        button->scaled_hc = NULL;
289}
290
291static void
292button_widget_load_pixbuf_and_scale (ButtonWidget *button,
293                                     int           dest_width,
294                                     int           dest_height)
295{
296        double scale;
297        double scale_x;
298        double scale_y;
299        int    width;
300        int    height;
301
302        if (!button->pixbuf) {
303                g_assert (!button->filename || !button->stock_id);
304
305                if (!button->filename && !button->stock_id)
306                        return;
307
308                if (button->stock_id)
309                        button->pixbuf = gtk_widget_render_icon (
310                                                GTK_WIDGET (button),
311                                                button->stock_id,
312                                                (GtkIconSize) -1,
313                                                NULL);
314                else {
315                        char *error = NULL;
316
317                        button->pixbuf = button_load_pixbuf (
318                                                button->filename, button->size, &error);
319                        if (error) {
320                                panel_error_dialog (gdk_screen_get_default (),
321                                                    "cannot_load_pixbuf",
322                                                    _("Failed to load image %s\n\n"
323                                                    "Details: %s"),
324                                                    button->filename,
325                                                    error);
326                                g_free (error);
327                        }
328                }
329
330                if (!button->pixbuf)
331                        return;
332        }
333
334        width  = gdk_pixbuf_get_width  (button->pixbuf);
335        height = gdk_pixbuf_get_height (button->pixbuf);
336
337        scale_x = (double) dest_width  / width;
338        scale_y = (double) dest_height / height;
339
340        scale = MIN (scale_x, scale_y);
341
342        width  *= scale;
343        height *= scale;
344
345        if (button->scaled) {
346                if (gdk_pixbuf_get_width  (button->scaled) == width &&
347                    gdk_pixbuf_get_height (button->scaled) == height)
348                        return; /* no need to re-scale */
349
350                g_object_unref (button->scaled);
351        }
352
353        button->scaled = gdk_pixbuf_scale_simple (
354                                button->pixbuf, width, height, GDK_INTERP_BILINEAR);
355
356        if (button->scaled_hc)
357                g_object_unref (button->scaled_hc);
358       
359        button->scaled_hc = make_hc_pixbuf (button->scaled);
360}
361
362static void
363button_widget_reload_pixbuf (ButtonWidget *button)
364{
365        button_widget_unset_pixbufs (button);
366        if (GTK_WIDGET (button)->allocation.width  <= 1 ||
367            GTK_WIDGET (button)->allocation.height <= 1)
368                return;
369
370        button_widget_load_pixbuf_and_scale (
371                button,
372                GTK_WIDGET (button)->allocation.width,
373                GTK_WIDGET (button)->allocation.height);
374        gtk_widget_queue_draw (GTK_WIDGET (button));
375}
376
377static void
378button_widget_finalize (GObject *object)
379{
380        ButtonWidget *button = (ButtonWidget *) object;
381
382        if (button->pressed_timeout)
383                g_source_remove (button->pressed_timeout);
384        button->pressed_timeout = 0;
385
386        button_widget_unset_pixbufs (button);
387
388        g_free (button->filename);
389        button->filename = NULL;
390
391        g_free (button->stock_id);
392        button->stock_id = NULL;
393       
394        parent_class->finalize (object);
395}
396
397static void
398button_widget_get_property (GObject    *object,
399                            guint       prop_id,
400                            GValue     *value,
401                            GParamSpec *pspec)
402{
403        ButtonWidget *button;
404
405        g_return_if_fail (BUTTON_IS_WIDGET (object));
406
407        button = BUTTON_WIDGET (object);
408
409        switch (prop_id) {
410        case PROP_SIZE:
411                g_value_set_int (value, button->size);
412                break;
413        case PROP_HAS_ARROW:
414                g_value_set_boolean (value, button->arrow);
415                break;
416        case PROP_ORIENT:
417                g_value_set_enum (value, button->orient);
418                break;
419        case PROP_ICON_NAME:
420                g_value_set_string (value, button->filename);
421                break;
422        case PROP_STOCK_ID:
423                g_value_set_string (value, button->stock_id);
424                break;
425        default:
426                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
427                break;
428        }
429}
430
431static void
432button_widget_set_property (GObject      *object,
433                            guint         prop_id,
434                            const GValue *value,
435                            GParamSpec   *pspec)
436{
437        ButtonWidget *button;
438
439        g_return_if_fail (BUTTON_IS_WIDGET (object));
440
441        button = BUTTON_WIDGET (object);
442
443        switch (prop_id) {
444                const char *icon_name;
445                const char *stock_id;
446
447        case PROP_SIZE:
448                button->size = g_value_get_int (value);
449                gtk_widget_queue_resize (GTK_WIDGET (button));
450                break;
451        case PROP_HAS_ARROW:
452                button->arrow = g_value_get_boolean (value) ? 1 : 0;
453                gtk_widget_queue_draw (GTK_WIDGET (button));
454                break;
455        case PROP_ORIENT:
456                button->orient = g_value_get_enum (value);
457                gtk_widget_queue_draw (GTK_WIDGET (button));
458                break;
459        case PROP_ICON_NAME:
460                icon_name = g_value_get_string (value);
461
462                g_assert (!button->filename || !button->stock_id);
463
464                if (button->stock_id) {
465                        g_free (button->stock_id);
466                        button->stock_id = NULL;
467                }
468
469                if (button->filename)
470                        g_free (button->filename);
471                button->filename = g_strdup (icon_name);
472
473                button_widget_reload_pixbuf (button);
474                break;
475        case PROP_STOCK_ID:
476                stock_id = g_value_get_string (value);
477
478                g_assert (!button->filename || !button->stock_id);
479
480                if (button->filename) {
481                        g_free (button->filename);
482                        button->filename = NULL;
483                }
484
485                if (button->stock_id)
486                        g_free (button->stock_id);
487                button->stock_id = g_strdup (stock_id);
488
489                button_widget_reload_pixbuf (button);
490                break;
491
492        default:
493                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
494                break;
495        }
496}
497
498static char *default_pixmap = NULL;
499
500static GdkPixbuf *
501get_missing (int preffered_size)
502{
503        GdkPixbuf *retval = NULL;
504
505        if (default_pixmap == NULL)
506                default_pixmap = panel_pixmap_discovery ("gnome-unknown.png",
507                                                         FALSE /* fallback */);
508        if (default_pixmap != NULL)
509                retval = gdk_pixbuf_new_from_file (default_pixmap,
510                                                   NULL);
511        if (retval == NULL)
512                retval = missing_pixbuf (preffered_size);
513
514        return retval;
515}
516
517static GdkPixbuf *
518button_load_pixbuf (const char  *file,
519                    int          preffered_size,
520                    char       **error)
521{
522        GdkPixbuf *retval = NULL;
523        GError *gerror = NULL;
524        char *full;
525
526        if (preffered_size <= 0)
527                preffered_size = 48;
528       
529        if (string_empty (file))
530                return get_missing (preffered_size);
531
532        full = gnome_desktop_item_find_icon (panel_icon_theme, file,
533                                             preffered_size, 0);
534        if (full != NULL) {
535                retval = gdk_pixbuf_new_from_file (full, &gerror);
536                if (retval == NULL) {
537                        *error = g_strdup (gerror ? gerror->message : _("none"));
538                        g_clear_error (&gerror);
539                }
540                g_free (full);
541        } else {
542                *error = g_strdup (_("file not found"));
543        }
544
545        if (retval == NULL)
546                retval = get_missing (preffered_size);
547
548        return retval;
549}
550
551#define SCALE(x) (((x)*size)/48.0)
552
553static void
554draw_arrow(GdkPoint *points, PanelOrient orient, int size)
555{
556        switch(orient) {
557        case PANEL_ORIENT_UP:
558                points[0].x = SCALE(48-12);
559                points[0].y = SCALE(10);
560                points[1].x = SCALE(48-4);
561                points[1].y = SCALE(10);
562                points[2].x = SCALE(48-8);
563                points[2].y = SCALE(3);
564                break;
565        case PANEL_ORIENT_DOWN:
566                points[0].x = SCALE(4);
567                points[0].y = SCALE(48 - 10);
568                points[1].x = SCALE(12);
569                points[1].y = SCALE(48 - 10);
570                points[2].x = SCALE(8);
571                points[2].y = SCALE(48 - 3);
572                break;
573        case PANEL_ORIENT_LEFT:
574                points[0].x = SCALE(10);
575                points[0].y = SCALE(4);
576                points[1].x = SCALE(10);
577                points[1].y = SCALE(12);
578                points[2].x = SCALE(3);
579                points[2].y = SCALE(8);
580                break;
581        case PANEL_ORIENT_RIGHT:
582                points[0].x = SCALE(48 - 10);
583                points[0].y = SCALE(48 - 12);
584                points[1].x = SCALE(48 - 10);
585                points[1].y = SCALE(48 - 4);
586                points[2].x = SCALE(48 - 3);
587                points[2].y = SCALE(48 - 8);
588                break;
589        }
590}
591
592void
593button_widget_set_dnd_highlight(ButtonWidget *button, gboolean highlight)
594{
595        g_return_if_fail (button != NULL);
596        g_return_if_fail (BUTTON_IS_WIDGET (button));
597
598        if(button->dnd_highlight != highlight) {
599                button->dnd_highlight = highlight;
600                gtk_widget_queue_draw (GTK_WIDGET (button));
601        }
602}
603
604static gboolean
605button_widget_expose (GtkWidget         *widget,
606                      GdkEventExpose    *event)
607{
608        ButtonWidget *button_widget;
609        GtkButton *button;
610        GdkRectangle area, image_bound;
611        int off, size;
612        int x, y, w, h;
613        GdkPixbuf *pb = NULL;
614 
615        g_return_val_if_fail (BUTTON_IS_WIDGET (widget), FALSE);
616        g_return_val_if_fail (event != NULL, FALSE);
617
618        button_widget = BUTTON_WIDGET (widget);
619        button = GTK_BUTTON (widget);
620       
621        if (!GTK_WIDGET_VISIBLE (widget) || !GTK_WIDGET_MAPPED (widget)) {
622                return FALSE;
623        }
624
625        size = widget->allocation.height;
626        /* offset for pressed buttons */
627        off = (button->in_button && button->button_down) ?
628                SCALE(BUTTON_WIDGET_DISPLACEMENT) : 0;
629       
630        if (global_config.highlight_when_over &&
631            (button->in_button || GTK_WIDGET_HAS_FOCUS (widget)))
632                pb = button_widget->scaled_hc;
633        else
634                pb = button_widget->scaled;
635       
636        w = gdk_pixbuf_get_width (pb);
637        h = gdk_pixbuf_get_height (pb);
638        x = widget->allocation.x + off + (widget->allocation.width - w)/2;
639        y = widget->allocation.y + off + (widget->allocation.height - h)/2;
640       
641        image_bound.x = x;
642        image_bound.y = y;     
643        image_bound.width = w;
644        image_bound.height = h;
645       
646        area = event->area;
647       
648        if (gdk_rectangle_intersect (&area, &widget->allocation, &area) &&
649            gdk_rectangle_intersect (&image_bound, &area, &image_bound))  {
650                gdk_pixbuf_render_to_drawable_alpha (pb,
651                                                     widget->window,
652                                                     image_bound.x - x, image_bound.y - y,
653                                                     image_bound.x, image_bound.y,
654                                                     image_bound.width, image_bound.height,
655                                                     GDK_PIXBUF_ALPHA_FULL,
656                                                     128,
657                                                     GDK_RGB_DITHER_NORMAL,
658                                                     0, 0);
659        }
660       
661        if(button_widget->arrow) {
662                int i;
663                GdkPoint points[3];
664                draw_arrow (points, button_widget->orient, widget->allocation.height);
665                for (i = 0; i < 3; i++) {
666                        points[i].x += off + widget->allocation.x;
667                        points[i].y += off + widget->allocation.y;
668                }
669                gdk_draw_polygon (widget->window, widget->style->white_gc, TRUE, points, 3);
670                gdk_draw_polygon (widget->window, widget->style->black_gc, FALSE, points, 3);
671        }
672
673        if (button_widget->dnd_highlight) {
674                gdk_draw_rectangle(widget->window, widget->style->black_gc, FALSE,
675                                   widget->allocation.x, widget->allocation.y,
676                                   widget->allocation.width - 1,
677                                   widget->allocation.height - 1);
678        }
679
680        if (GTK_WIDGET_HAS_FOCUS (widget)) {
681                gint focus_width, focus_pad;
682                gint x, y, width, height;
683
684                gtk_widget_style_get (widget,
685                                      "focus-line-width", &focus_width,
686                                      "focus-padding", &focus_pad,
687                                      NULL);
688                x = widget->allocation.x + focus_pad;
689                y = widget->allocation.y + focus_pad;
690                width = widget->allocation.width -  2 * focus_pad;
691                height = widget->allocation.height - 2 * focus_pad;
692                gtk_paint_focus (widget->style, widget->window,
693                                 GTK_WIDGET_STATE (widget),
694                                 &event->area, widget, "button",
695                                 x, y, width, height);
696        }
697       
698        return FALSE;
699}
700
701static void
702button_widget_size_request (GtkWidget      *widget,
703                            GtkRequisition *requisition)
704{
705        PanelWidget *panel = PANEL_WIDGET (widget->parent);
706
707        requisition->width = requisition->height = panel->sz;
708}
709
710static void
711button_widget_size_allocate (GtkWidget     *widget,
712                             GtkAllocation *allocation)
713{
714        ButtonWidget *button_widget;
715        GtkButton    *button;
716
717        g_return_if_fail (BUTTON_IS_WIDGET (widget));
718
719        button_widget = BUTTON_WIDGET (widget);
720        button        = GTK_BUTTON (widget);
721
722        widget->allocation = *allocation;
723
724        button_widget_load_pixbuf_and_scale (
725                button_widget, allocation->width, allocation->height);
726
727        if (GTK_WIDGET_REALIZED (widget)) {
728                PanelWidget *panel;
729                int          x, y, w, h;
730
731                panel = PANEL_WIDGET (widget->parent);
732
733                calculate_overlay_geometry (panel, panel->panel_parent,
734                                            widget, &x, &y, &w, &h);
735
736                gdk_window_move_resize (button->event_window, x, y, w, h);
737        }
738}
739
740static gboolean
741pressed_timeout_func(gpointer data)
742{
743        ButtonWidget *button;
744
745        g_return_val_if_fail (BUTTON_IS_WIDGET (data), FALSE);
746
747        button = BUTTON_WIDGET (data);
748
749        button->pressed_timeout = 0;
750
751        return FALSE;
752}
753
754static gboolean
755button_widget_button_press (GtkWidget *widget, GdkEventButton *event)
756{
757        ButtonWidget *button;
758
759        g_return_val_if_fail (BUTTON_IS_WIDGET (widget), FALSE);
760        g_return_val_if_fail (event != NULL, FALSE);
761
762        button = BUTTON_WIDGET (widget);
763
764        if (button->pressed_timeout)
765                return TRUE;
766
767        return GTK_WIDGET_CLASS (parent_class)->button_press_event (widget, event);
768}
769
770static gboolean
771button_widget_enter_notify (GtkWidget *widget, GdkEventCrossing *event)
772{
773        g_return_val_if_fail (BUTTON_IS_WIDGET (widget), FALSE);
774
775        GTK_WIDGET_CLASS (parent_class)->enter_notify_event (widget, event);
776        if (GTK_BUTTON (widget)->in_button)
777                gtk_widget_queue_draw (widget);
778
779        return FALSE;
780}
781
782static gboolean
783button_widget_leave_notify (GtkWidget *widget, GdkEventCrossing *event)
784{
785        gboolean in_button;
786
787        g_return_val_if_fail (BUTTON_IS_WIDGET (widget), FALSE);
788
789        in_button = GTK_BUTTON (widget)->in_button;
790        GTK_WIDGET_CLASS (parent_class)->leave_notify_event (widget, event);
791        if (in_button != GTK_BUTTON (widget)->in_button &&
792            global_config.highlight_when_over)
793                gtk_widget_queue_draw (widget);
794
795        return FALSE;
796}
797
798static void
799button_widget_button_pressed (GtkButton *button)
800{
801        ButtonWidget *button_widget;
802
803        g_return_if_fail (BUTTON_IS_WIDGET (button));
804
805        GTK_BUTTON_CLASS (parent_class)->pressed (button);
806
807        button_widget = BUTTON_WIDGET (button);
808        button_widget->pressed_timeout =
809                g_timeout_add (400, pressed_timeout_func, button_widget);
810        gtk_widget_queue_draw (GTK_WIDGET (button));
811}
812
813static void
814button_widget_button_released (GtkButton *button)
815{
816        g_return_if_fail (BUTTON_IS_WIDGET (button));
817
818        GTK_BUTTON_CLASS (parent_class)->released (button);
819        gtk_widget_queue_draw (GTK_WIDGET (button));
820}
821
822static void
823button_widget_instance_init (ButtonWidget *button)
824{
825        button->pixbuf    = NULL;
826        button->scaled    = NULL;
827        button->scaled_hc = NULL;
828       
829        button->arrow  = 0;
830        button->size   = -1;
831        button->orient = PANEL_ORIENT_UP;
832       
833        button->ignore_leave  = FALSE;
834        button->dnd_highlight = FALSE;
835
836        button->pressed_timeout = 0;
837}
838
839static void
840button_widget_class_init (ButtonWidgetClass *klass)
841{
842        GObjectClass *gobject_class   = (GObjectClass   *) klass;
843        GtkWidgetClass *widget_class  = (GtkWidgetClass *) klass;
844        GtkButtonClass *button_class  = (GtkButtonClass *) klass;
845
846        parent_class = g_type_class_peek_parent (klass);
847
848        gobject_class->finalize     = button_widget_finalize;
849        gobject_class->get_property = button_widget_get_property;
850        gobject_class->set_property = button_widget_set_property;
851         
852        widget_class->realize            = button_widget_realize;
853        widget_class->parent_set         = button_widget_parent_set;
854        widget_class->size_allocate      = button_widget_size_allocate;
855        widget_class->size_request       = button_widget_size_request;
856        widget_class->button_press_event = button_widget_button_press;
857        widget_class->enter_notify_event = button_widget_enter_notify;
858        widget_class->leave_notify_event = button_widget_leave_notify;
859        widget_class->expose_event       = button_widget_expose;
860
861        button_class->pressed  = button_widget_button_pressed;
862        button_class->released = button_widget_button_released;
863
864        g_object_class_install_property (
865                        gobject_class,
866                        PROP_SIZE,
867                        g_param_spec_int ("size",
868                                          _("Size"),
869                                          _("The desired ButtonWidget size"),
870                                          G_MININT, G_MAXINT, -1,
871                                          G_PARAM_READWRITE));
872
873        g_object_class_install_property (
874                        gobject_class,
875                        PROP_HAS_ARROW,
876                        g_param_spec_boolean ("has-arrow",
877                                              _("Has Arrow"),
878                                              _("Whether or not to draw an arrow indicator"),
879                                              FALSE,
880                                              G_PARAM_READWRITE));
881
882        g_object_class_install_property (
883                        gobject_class,
884                        PROP_ORIENT,
885                        g_param_spec_enum ("orient",
886                                           _("Orientation"),
887                                           _("The ButtonWidget orientation"),
888                                           PANEL_TYPE_ORIENT,
889                                           PANEL_ORIENT_UP,
890                                           G_PARAM_READWRITE));
891
892        g_object_class_install_property (
893                        gobject_class,
894                        PROP_ICON_NAME,
895                        g_param_spec_string ("icon-name",
896                                             _("Icon Name"),
897                                             _("The desired icon for the ButtonWidget"),
898                                             NULL,
899                                             G_PARAM_READWRITE));
900
901        g_object_class_install_property (
902                        gobject_class,
903                        PROP_STOCK_ID,
904                        g_param_spec_string ("stock-id",
905                                             _("Stock Icon ID"),
906                                             _("The desired stock icon for the ButtonWidget"),
907                                             NULL,
908                                             G_PARAM_READWRITE));
909}
910
911GType
912button_widget_get_type (void)
913{
914        static GType object_type = 0;
915
916        if (object_type == 0) {
917                static const GTypeInfo object_info = {
918                        sizeof (ButtonWidgetClass),
919                        (GBaseInitFunc)         NULL,
920                        (GBaseFinalizeFunc)     NULL,
921                        (GClassInitFunc)        button_widget_class_init,
922                        NULL,                   /* class_finalize */
923                        NULL,                   /* class_data */
924                        sizeof (ButtonWidget),
925                        0,                      /* n_preallocs */
926                        (GInstanceInitFunc)     button_widget_instance_init
927
928                };
929
930                object_type = g_type_register_static (GTK_TYPE_BUTTON, "ButtonWidget", &object_info, 0);
931        }
932
933        return object_type;
934}
935
936GtkWidget *
937button_widget_new (const char  *filename,
938                   int          size,
939                   gboolean     arrow,
940                   PanelOrient  orient)
941{
942        GtkWidget *retval;
943
944        retval = g_object_new (
945                        BUTTON_TYPE_WIDGET,
946                        "size", size,
947                        "has-arrow", arrow,
948                        "orient", orient,
949                        "icon-name", filename,
950                        NULL);
951       
952        return retval;
953}
954
955GtkWidget *
956button_widget_new_from_stock (const char  *stock_id,
957                              int          size,
958                              gboolean     arrow,
959                              PanelOrient  orient)
960{
961        GtkWidget *retval;
962
963        retval = g_object_new (
964                        BUTTON_TYPE_WIDGET,
965                        "size", size,
966                        "has-arrow", arrow,
967                        "orient", orient,
968                        "stock-id", stock_id,
969                        NULL);
970       
971        return retval;
972}
973
974void
975button_widget_set_pixmap (ButtonWidget *button,
976                          const char   *pixmap)
977{
978        g_return_if_fail (BUTTON_IS_WIDGET (button));
979
980        g_object_set (G_OBJECT (button), "icon-name", pixmap, NULL);
981}
982
983void
984button_widget_set_stock_id (ButtonWidget *button,
985                            const char   *stock_id)
986{
987        g_return_if_fail (BUTTON_IS_WIDGET (button));
988
989        g_object_set (G_OBJECT (button), "stock-id", stock_id, NULL);
990}
991
992void
993button_widget_set_params(ButtonWidget *button,
994                         gboolean arrow,
995                         PanelOrient orient)
996{
997        g_return_if_fail (BUTTON_IS_WIDGET (button));
998
999        g_object_set (G_OBJECT (button), "has-arrow", arrow, NULL);
1000        g_object_set (G_OBJECT (button), "orient", orient, NULL);
1001}
Note: See TracBrowser for help on using the repository browser.