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

Revision 16302, 30.1 KB checked in by ghudson, 24 years ago (diff)
Merge with gnome-core 1.4.0.4.
Line 
1#include <config.h>
2#include <string.h>
3#include <gtk/gtk.h>
4#include <gnome.h>
5#include <gdk-pixbuf/gdk-pixbuf.h>
6#include <libart_lgpl/art_misc.h>
7#include <libart_lgpl/art_affine.h>
8#include <libart_lgpl/art_filterlevel.h>
9#include "button-widget.h"
10#include "panel-widget.h"
11#include "basep-widget.h"
12#include "panel-types.h"
13#include "panel-util.h"
14#include "panel_config_global.h"
15#include "rgb-stuff.h"
16
17extern GlobalConfig global_config;
18
19static void button_widget_class_init    (ButtonWidgetClass *klass);
20static void button_widget_init          (ButtonWidget      *button);
21static void button_widget_size_request  (GtkWidget         *widget,
22                                         GtkRequisition    *requisition);
23static void button_widget_size_allocate (GtkWidget         *widget,
24                                         GtkAllocation     *allocation);
25static void button_widget_realize       (GtkWidget         *widget);
26static void button_widget_unrealize     (GtkWidget         *widget);
27static void button_widget_map           (GtkWidget         *widget);
28static void button_widget_unmap         (GtkWidget         *widget);
29static void button_widget_real_draw     (GtkWidget         *widget,
30                                         GdkRectangle      *area);
31
32static gboolean  button_widget_button_press     (GtkWidget         *widget,
33                                                 GdkEventButton    *event);
34static gboolean  button_widget_button_release(GtkWidget         *widget,
35                                              GdkEventButton    *event);
36static gboolean  button_widget_enter_notify     (GtkWidget         *widget,
37                                                 GdkEventCrossing  *event);
38static gboolean  button_widget_leave_notify     (GtkWidget         *widget,
39                                                 GdkEventCrossing  *event);
40static void button_widget_pressed       (ButtonWidget *button);
41static void button_widget_unpressed     (ButtonWidget *button);
42
43/*list of all the button widgets*/
44static GList *buttons = NULL;
45
46/*the tiles go here*/
47static struct {
48        GdkPixbuf *tiles_up[LAST_TILE];
49        GdkPixbuf *tiles_up_hc[LAST_TILE];
50        GdkPixbuf *tiles_down[LAST_TILE];
51        GdkPixbuf *tiles_down_hc[LAST_TILE];
52} tiles = {{NULL}}; /*ansi C trick to make it all 0*/
53
54static int tile_border[LAST_TILE]={0,0,0,0};
55static int tile_depth[LAST_TILE]={0,0,0,0};
56
57/*are tiles enabled*/
58static gboolean tiles_enabled[LAST_TILE] = {FALSE,FALSE,FALSE,FALSE};
59
60static gboolean pixmaps_enabled[LAST_TILE] = {TRUE,TRUE,TRUE,TRUE};
61static gboolean always_text[LAST_TILE] = {FALSE,FALSE,FALSE,FALSE}; /*text always displayed*/
62
63static GtkWidgetClass *parent_class;
64
65guint
66button_widget_get_type (void)
67{
68        static guint button_widget_type = 0;
69
70        if (!button_widget_type) {
71                GtkTypeInfo button_widget_info = {
72                        "ButtonWidget",
73                        sizeof (ButtonWidget),
74                        sizeof (ButtonWidgetClass),
75                        (GtkClassInitFunc) button_widget_class_init,
76                        (GtkObjectInitFunc) button_widget_init,
77                        (GtkArgSetFunc) NULL,
78                        (GtkArgGetFunc) NULL,
79                };
80
81                button_widget_type = gtk_type_unique (GTK_TYPE_WIDGET,
82                                                      &button_widget_info);
83        }
84
85        return button_widget_type;
86}
87
88enum {
89        CLICKED_SIGNAL,
90        PRESSED_SIGNAL,
91        UNPRESSED_SIGNAL,
92        LAST_SIGNAL
93};
94
95static guint button_widget_signals[LAST_SIGNAL] = {0};
96
97static void
98button_widget_class_init (ButtonWidgetClass *class)
99{
100        GtkObjectClass *object_class = (GtkObjectClass*) class;
101        GtkWidgetClass *widget_class = (GtkWidgetClass*) class;
102
103        parent_class = gtk_type_class (GTK_TYPE_WIDGET);
104
105        button_widget_signals[CLICKED_SIGNAL] =
106                gtk_signal_new("clicked",
107                               GTK_RUN_LAST,
108                               object_class->type,
109                               GTK_SIGNAL_OFFSET(ButtonWidgetClass,
110                                                 clicked),
111                               gtk_signal_default_marshaller,
112                               GTK_TYPE_NONE,
113                               0);
114        button_widget_signals[PRESSED_SIGNAL] =
115                gtk_signal_new("pressed",
116                               GTK_RUN_LAST,
117                               object_class->type,
118                               GTK_SIGNAL_OFFSET(ButtonWidgetClass,
119                                                 pressed),
120                               gtk_signal_default_marshaller,
121                               GTK_TYPE_NONE,
122                               0);
123        button_widget_signals[UNPRESSED_SIGNAL] =
124                gtk_signal_new("unpressed",
125                               GTK_RUN_LAST,
126                               object_class->type,
127                               GTK_SIGNAL_OFFSET(ButtonWidgetClass,
128                                                 unpressed),
129                               gtk_signal_default_marshaller,
130                               GTK_TYPE_NONE,
131                               0);
132        gtk_object_class_add_signals(object_class,button_widget_signals,
133                                     LAST_SIGNAL);
134       
135        class->clicked = NULL;
136        class->pressed = button_widget_pressed;
137        class->unpressed = button_widget_unpressed;
138
139        widget_class->realize = button_widget_realize;
140        widget_class->unrealize = button_widget_unrealize;
141        widget_class->draw = button_widget_real_draw;
142        widget_class->map = button_widget_map;
143        widget_class->unmap = button_widget_unmap;
144        widget_class->size_allocate = button_widget_size_allocate;
145        widget_class->size_request = button_widget_size_request;
146        widget_class->button_press_event = button_widget_button_press;
147        widget_class->button_release_event = button_widget_button_release;
148        widget_class->enter_notify_event = button_widget_enter_notify;
149        widget_class->leave_notify_event = button_widget_leave_notify;
150       
151}
152
153static void
154setup_no_alpha(ButtonWidget *button)
155{
156        button->no_alpha = 0;
157        if(!tiles_enabled[button->tile] ||
158           global_config.tile_when_over)
159                return;
160        if(button->pressed) {
161                if(tiles.tiles_down[button->tile] &&
162                   !gdk_pixbuf_get_has_alpha(tiles.tiles_down[button->tile]))
163                        button->no_alpha = 1;
164        } else {
165                if(tiles.tiles_up[button->tile] &&
166                   !gdk_pixbuf_get_has_alpha(tiles.tiles_up[button->tile]))
167                        button->no_alpha = 1;
168        }
169}
170
171static void
172translate_to(GtkWidget *from, GtkWidget *to, int *x, int *y)
173{
174        while (from != to) {
175                if(!GTK_WIDGET_NO_WINDOW(from)) {
176                        *x += from->allocation.x;
177                        *y += from->allocation.y;
178                }
179                from = from->parent;
180        }
181}
182
183static GtkWidget *
184get_frame(BasePWidget *basep)
185{
186        if (GTK_WIDGET_VISIBLE (basep->frame)) {
187                return basep->frame;
188        } else {
189                return basep->innerebox;
190        }
191}
192
193static void
194calculate_overlay_geometry (PanelWidget *panel, GtkWidget *parent,
195                            GtkWidget *applet, int *x, int *y, int *w, int *h)
196{
197        *x = applet->allocation.x;
198        *y = applet->allocation.y;
199        *w = applet->allocation.width;
200        *h = applet->allocation.height;
201
202        translate_to (GTK_WIDGET(panel), parent, x, y);
203
204        /* when not shown, things are somewhat weird, and we try to put the
205         * window completely off as it can't be clickable anyway */
206        /* XXX: These window thingies should really be unmapped in hidden
207         * case, or something like that, this is ugly, but who gives a fuck,
208         * this is all going to be rewritten soon (famous last words?) */
209        if(IS_BASEP_WIDGET(parent) &&
210           BASEP_WIDGET(parent)->state != BASEP_SHOWN &&
211           BASEP_WIDGET(parent)->state != BASEP_AUTO_HIDDEN) {
212                *x = parent->requisition.width + 1;
213                *y = parent->requisition.height + 1;
214                return;
215        }
216
217        if(panel->orient == PANEL_HORIZONTAL) {
218                if (applet->allocation.x > panel->size) {
219                        *x = parent->requisition.width + 1;
220                        *y = parent->requisition.height + 1;
221                        return;
222                }
223
224                *y = 0;
225                /* we use the requisition, since allocation might have not
226                   yet happened if we are inside the allocation, anyway
227                   they are the same for basep */
228                *h = parent->requisition.height;
229
230                if ((*w + applet->allocation.x) > panel->size) {
231                        *w = panel->size - applet->allocation.x;
232                }
233
234                if ( ! IS_BASEP_WIDGET(parent)) {
235                        /*don't do the edge flushing on foobar*/
236                        return;
237                }
238
239                /* if on the edge (only if padding is 0)
240                   then make the thing flush with the innerebox or frame
241                   of the basep */
242                if(applet->allocation.x == 0) {
243                        GtkWidget *frame = get_frame(BASEP_WIDGET(parent));
244                        *w += (*x - frame->allocation.x);
245                        *x = frame->allocation.x;
246                } else if(applet->allocation.x + *w == panel->size) {
247                        GtkWidget *frame = get_frame(BASEP_WIDGET(parent));
248                        *w = frame->allocation.width + frame->allocation.x - *x;
249                }
250        } else {
251                if (applet->allocation.y > panel->size) {
252                        *x = parent->requisition.width + 1;
253                        *y = parent->requisition.height + 1;
254                        return;
255                }
256
257                *x = 0;
258                *w = parent->requisition.width;
259
260                if ((*h + applet->allocation.y) > panel->size) {
261                        *h = panel->size - applet->allocation.y;
262                }
263
264                if ( ! IS_BASEP_WIDGET(parent)) {
265                        /*don't do the edge flushing on foobar*/
266                        return;
267                }
268
269                /* if on the edge (only if padding is 0)
270                   then make the thing flush with the innerbox of frame
271                   of the basep */
272                if(applet->allocation.y == 0) {
273                        GtkWidget *frame = get_frame(BASEP_WIDGET(parent));
274                        *h += (*y - frame->allocation.y);
275                        *y = frame->allocation.y;
276                } else if(applet->allocation.y + *h == panel->size) {
277                        GtkWidget *frame = get_frame(BASEP_WIDGET(parent));
278                        *h = frame->allocation.height + frame->allocation.y - *y;
279                }
280        }
281}
282
283static void
284button_widget_realize(GtkWidget *widget)
285{
286        GdkWindowAttr attributes;
287        gint attributes_mask;
288        ButtonWidget *button_widget;
289        PanelWidget *panel;
290        GtkWidget *parent;
291        int x,y,w,h;
292
293        g_return_if_fail (widget != NULL);
294        g_return_if_fail (IS_BUTTON_WIDGET (widget));
295
296        panel = PANEL_WIDGET(widget->parent);
297        parent = panel->panel_parent;
298
299        calculate_overlay_geometry(panel, parent, widget, &x, &y, &w, &h);
300
301        button_widget = BUTTON_WIDGET (widget);
302
303        GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
304
305        attributes.window_type = GDK_WINDOW_CHILD;
306        attributes.x = x;
307        attributes.y = y;
308        attributes.width = w;
309        attributes.height = h;
310        attributes.wclass = GDK_INPUT_ONLY;
311        attributes.event_mask = (GDK_BUTTON_PRESS_MASK |
312                                 GDK_BUTTON_RELEASE_MASK |
313                                 GDK_POINTER_MOTION_MASK |
314                                 GDK_POINTER_MOTION_HINT_MASK |
315                                 GDK_KEY_PRESS_MASK |
316                                 GDK_ENTER_NOTIFY_MASK |
317                                 GDK_LEAVE_NOTIFY_MASK);
318        attributes_mask = GDK_WA_X | GDK_WA_Y;
319
320        widget->window = gtk_widget_get_parent_window(widget);
321        gdk_window_ref(widget->window);
322     
323        button_widget->event_window = gdk_window_new (parent->window,
324                                                      &attributes,
325                                                      attributes_mask);
326        gdk_window_set_user_data (button_widget->event_window, widget);
327
328        widget->style = gtk_style_attach (widget->style, widget->window);
329}
330
331static void
332button_widget_unrealize (GtkWidget *widget)
333{
334        ButtonWidget *button_widget;
335 
336        g_return_if_fail (widget != NULL);
337        g_return_if_fail (IS_BUTTON_WIDGET (widget));
338
339        button_widget = BUTTON_WIDGET (widget);
340       
341        gdk_window_set_user_data (button_widget->event_window, NULL);
342        gdk_window_destroy (button_widget->event_window);
343        button_widget->event_window = NULL;
344       
345        if (GTK_WIDGET_CLASS (parent_class)->unrealize)
346                (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
347}
348
349static void
350button_widget_map (GtkWidget *widget)
351{
352        g_return_if_fail (widget != NULL);
353        g_return_if_fail (IS_BUTTON_WIDGET (widget));
354
355        if (GTK_WIDGET_REALIZED (widget) && !GTK_WIDGET_MAPPED (widget))
356                gdk_window_show (BUTTON_WIDGET (widget)->event_window);
357
358        GTK_WIDGET_CLASS (parent_class)->map (widget);
359}
360
361static void
362button_widget_unmap (GtkWidget *widget)
363{
364        g_return_if_fail (widget != NULL);
365        g_return_if_fail (IS_BUTTON_WIDGET (widget));
366
367        if (GTK_WIDGET_MAPPED (widget))
368                gdk_window_hide (BUTTON_WIDGET (widget)->event_window);
369
370        GTK_WIDGET_CLASS (parent_class)->unmap (widget);
371}
372
373static void
374button_widget_destroy(GtkWidget *w, gpointer data)
375{
376        ButtonWidget *button = BUTTON_WIDGET(w);
377
378        if(button->pressed_timeout != 0)
379                gtk_timeout_remove(button->pressed_timeout);
380
381        if(button->pixbuf)
382                gdk_pixbuf_unref(button->pixbuf);
383        button->pixbuf = NULL;
384        if(button->pixbuf_hc)
385                gdk_pixbuf_unref(button->pixbuf_hc);
386        button->pixbuf_hc = NULL;
387        if(button->cache)
388                gdk_pixmap_unref(button->cache);
389        button->cache = NULL;
390
391        g_free(button->filename);
392        g_free(button->text);
393
394        buttons = g_list_remove(buttons,button);
395}
396
397static GdkPixbuf *
398loadup_file(const char *file)
399{
400        GdkPixbuf *pb = NULL;
401       
402        if (string_empty (file))
403                return NULL;
404
405        if ( ! g_path_is_absolute(file)) {
406                char *f;
407                f = gnome_pixmap_file (file);
408                if (f != NULL) {
409                        pb = gdk_pixbuf_new_from_file(f);
410                        g_free (f);
411                }
412        } else {
413                pb = gdk_pixbuf_new_from_file (file);
414        }
415        return pb;
416}
417
418#if 0
419/*#define INTENSITY(r, g, b) ((r) * 0.30 + (g) * 0.59 + (b) * 0.11)*/
420#define INTENSITY(r, g, b) (((r)*77 + (g)*150 + (b)*28)>>8)
421
422/* saturation is 0-255, darken is 0-255 */
423static void
424do_saturate_darken (GdkPixbuf *dest, GdkPixbuf *src,
425                    int saturation, int darken)
426{
427        gint i, j;
428        gint width, height, has_alpha, srcrowstride, destrowstride;
429        guchar *target_pixels;
430        guchar *original_pixels;
431        guchar *pixsrc;
432        guchar *pixdest;
433        int intensity;
434        int alpha;
435        int negalpha;
436        int val;
437        guchar r,g,b;
438
439        has_alpha = gdk_pixbuf_get_has_alpha (src);
440        width = gdk_pixbuf_get_width (src);
441        height = gdk_pixbuf_get_height (src);
442        srcrowstride = gdk_pixbuf_get_rowstride (src);
443        destrowstride = gdk_pixbuf_get_rowstride (dest);
444        target_pixels = gdk_pixbuf_get_pixels (dest);
445        original_pixels = gdk_pixbuf_get_pixels (src);
446
447        for (i = 0; i < height; i++) {
448                pixdest = target_pixels + i*destrowstride;
449                pixsrc = original_pixels + i*srcrowstride;
450                for (j = 0; j < width; j++) {
451                        r = *(pixsrc++);
452                        g = *(pixsrc++);
453                        b = *(pixsrc++);
454                        intensity = INTENSITY(r,g,b);
455                        negalpha = ((255 - saturation)*darken)>>8;
456                        alpha = (saturation*darken)>>8;
457                        val = (negalpha * intensity + alpha * r) >> 8;
458                        *(pixdest++) = MIN(val, 255);
459                        val = (negalpha * intensity + alpha * g) >> 8;
460                        *(pixdest++) = MIN(val, 255);
461                        val = (negalpha * intensity + alpha * b) >> 8;
462                        *(pixdest++) = MIN(val, 255);
463                        if (has_alpha)
464                                *(pixdest++) = *(pixsrc++);
465                }
466        }
467}
468#undef INTENSITY
469#endif
470
471/* colorshift a pixbuf */
472static void
473do_colorshift (GdkPixbuf *dest, GdkPixbuf *src, int shift)
474{
475        gint i, j;
476        gint width, height, has_alpha, srcrowstride, destrowstride;
477        guchar *target_pixels;
478        guchar *original_pixels;
479        guchar *pixsrc;
480        guchar *pixdest;
481        int val;
482        guchar r,g,b;
483
484        has_alpha = gdk_pixbuf_get_has_alpha (src);
485        width = gdk_pixbuf_get_width (src);
486        height = gdk_pixbuf_get_height (src);
487        srcrowstride = gdk_pixbuf_get_rowstride (src);
488        destrowstride = gdk_pixbuf_get_rowstride (dest);
489        target_pixels = gdk_pixbuf_get_pixels (dest);
490        original_pixels = gdk_pixbuf_get_pixels (src);
491
492        for (i = 0; i < height; i++) {
493                pixdest = target_pixels + i*destrowstride;
494                pixsrc = original_pixels + i*srcrowstride;
495                for (j = 0; j < width; j++) {
496                        r = *(pixsrc++);
497                        g = *(pixsrc++);
498                        b = *(pixsrc++);
499                        val = r + shift;
500                        *(pixdest++) = CLAMP(val, 0, 255);
501                        val = g + shift;
502                        *(pixdest++) = CLAMP(val, 0, 255);
503                        val = b + shift;
504                        *(pixdest++) = CLAMP(val, 0, 255);
505                        if (has_alpha)
506                                *(pixdest++) = *(pixsrc++);
507                }
508        }
509}
510
511
512
513#define SCALE(x) (((x)*size)/48.0)
514
515static void
516draw_arrow(GdkPoint *points, PanelOrientType orient, int size)
517{
518        switch(orient) {
519        case ORIENT_UP:
520                points[0].x = SCALE(48-12);
521                points[0].y = SCALE(10);
522                points[1].x = SCALE(48-4);
523                points[1].y = SCALE(10);
524                points[2].x = SCALE(48-8);
525                points[2].y = SCALE(3);
526                break;
527        case ORIENT_DOWN:
528                points[0].x = SCALE(4);
529                points[0].y = SCALE(48 - 10);
530                points[1].x = SCALE(12);
531                points[1].y = SCALE(48 - 10);
532                points[2].x = SCALE(8);
533                points[2].y = SCALE(48 - 3);
534                break;
535        case ORIENT_LEFT:
536                points[0].x = SCALE(10);
537                points[0].y = SCALE(4);
538                points[1].x = SCALE(10);
539                points[1].y = SCALE(12);
540                points[2].x = SCALE(3);
541                points[2].y = SCALE(8);
542                break;
543        case ORIENT_RIGHT:
544                points[0].x = SCALE(48 - 10);
545                points[0].y = SCALE(48 - 12);
546                points[1].x = SCALE(48 - 10);
547                points[1].y = SCALE(48 - 4);
548                points[2].x = SCALE(48 - 3);
549                points[2].y = SCALE(48 - 8);
550                break;
551        }
552}
553
554void
555button_widget_set_dnd_highlight(ButtonWidget *button, gboolean highlight)
556{
557        g_return_if_fail (button != NULL);
558        g_return_if_fail (IS_BUTTON_WIDGET (button));
559
560        if(button->dnd_highlight != highlight) {
561                button->dnd_highlight = highlight;
562                if(button->cache)
563                        gdk_pixmap_unref(button->cache);
564                button->cache = NULL;
565
566                panel_widget_draw_icon(PANEL_WIDGET(GTK_WIDGET(button)->parent),
567                                       button);
568        }
569}
570
571static void
572button_widget_real_draw(GtkWidget *widget, GdkRectangle *area)
573{
574        if(widget->parent && IS_PANEL_WIDGET(widget->parent))
575                panel_widget_draw_icon(PANEL_WIDGET(widget->parent), BUTTON_WIDGET(widget));
576
577}
578
579void
580button_widget_draw(ButtonWidget *button, guchar *rgb, int rowstride)
581{
582        GtkWidget *widget, *pwidget;
583        PanelWidget *panel;
584        int size, off, border;
585
586        g_return_if_fail(button != NULL);
587        g_return_if_fail(IS_BUTTON_WIDGET(button));
588        g_return_if_fail(rgb != NULL);
589        g_return_if_fail(rowstride >= 0);
590
591        widget = GTK_WIDGET(button);
592        panel = PANEL_WIDGET(widget->parent);
593        size = panel->sz;
594        /*offset for pressed buttons*/
595        off = (button->in_button && button->pressed) ?
596                SCALE(tile_depth[button->tile]) : 0;
597        /*border to not draw when drawing a tile*/
598        border = tiles_enabled[button->tile] ?
599                SCALE(tile_border[button->tile]) : 0;
600         
601        button->size = size;
602       
603        pwidget = widget->parent;
604       
605        if(tiles_enabled[button->tile]) {
606                GdkPixbuf *pb = NULL;
607                if (button->pressed &&
608                    button->in_button) {
609                        /* Pressed down */
610                        if(!global_config.saturate_when_over ||
611                           !button->in_button) {
612                                pb = tiles.tiles_down[button->tile];
613                        } else {
614                                pb = tiles.tiles_down_hc[button->tile];
615                        }
616                } else if ( ! global_config.tile_when_over ||
617                            button->in_button) {
618                        /* not pressed */
619                        if( ! global_config.saturate_when_over ||
620                            ! button->in_button) {
621                                pb = tiles.tiles_up[button->tile];
622                        } else {
623                                pb = tiles.tiles_up_hc[button->tile];
624                        }
625                }
626
627                if(pb != NULL) {
628                        GdkPixbuf *scaled_pb;
629                        double affine[6];
630                        GdkInterpType interp;
631
632                        if (global_config.fast_button_scaling)
633                                interp = GDK_INTERP_NEAREST;
634                        else
635                                interp = GDK_INTERP_HYPER;
636
637                        scaled_pb = scale_pixbuf_to_square (pb, size,
638                                                            NULL, NULL,
639                                                            interp);
640
641                        art_affine_identity (affine);
642
643                        transform_pixbuf (rgb, 0, 0, size, size,
644                                          rowstride, scaled_pb, affine,
645                                          ART_FILTER_NEAREST, NULL);
646
647                        gdk_pixbuf_unref (scaled_pb);
648                }
649        }
650
651        if (pixmaps_enabled[button->tile]) {
652                GdkPixbuf *pb = NULL;
653                if(!global_config.saturate_when_over || !button->in_button) {
654                        pb = button->pixbuf;
655                } else {
656                        pb = button->pixbuf_hc;
657                }
658                if(pb != NULL) {
659                        double affine[6];
660                        int w, h;
661                        GdkPixbuf *scaled_pb;
662                        GdkInterpType interp;
663
664                        if (global_config.fast_button_scaling)
665                                interp = GDK_INTERP_NEAREST;
666                        else
667                                interp = GDK_INTERP_HYPER;
668
669                        scaled_pb = scale_pixbuf_to_square (pb, size, &w, &h,
670                                                            interp);
671
672                        art_affine_translate(affine,
673                                             -border+off + (size-w)/2,
674                                             -border+off + (size-h)/2);
675
676                        transform_pixbuf((rgb+border*rowstride+border*3),
677                                         0, 0,
678                                         size-2*border, size-2*border,
679                                         rowstride,
680                                         scaled_pb,
681                                         affine, ART_FILTER_NEAREST, NULL);
682
683                        gdk_pixbuf_unref (scaled_pb);
684                }
685        }
686}
687
688/* draw the xlib part (arrow/text/dndhighlight) */
689void
690button_widget_draw_xlib(ButtonWidget *button, GdkPixmap *pixmap)
691{
692        GtkWidget *widget, *pwidget;
693        GdkGC *gc;
694        int size, off;
695
696        g_return_if_fail(button != NULL);
697        g_return_if_fail(IS_BUTTON_WIDGET(button));
698        g_return_if_fail(pixmap != NULL);
699
700        widget = GTK_WIDGET(button);
701        size = button->size;
702
703        /*offset for pressed buttons*/
704        off = (button->in_button && button->pressed) ?
705                SCALE(tile_depth[button->tile]) : 0;
706         
707        gc = gdk_gc_new(pixmap);
708       
709        pwidget = widget->parent;
710        /*draw text*/
711        if (!pixmaps_enabled[button->tile] ||
712            always_text[button->tile] ||
713            !button->pixbuf) {
714                char *text = g_strdup(button->text);
715                int twidth,theight;
716                GdkFont *font;
717                GdkRectangle rect;
718                 
719                rect.x = 0;
720                rect.y = 0;
721                rect.width = widget->allocation.width;
722                rect.height = widget->allocation.height;
723
724                if(!text) text = g_strdup("XXX");
725               
726                font = gdk_fontset_load(_("-*-helvetica-medium-r-normal-*-8-*-*-*-*-*-*-*"));
727                if(!font)
728                        font = gdk_font_load("fixed");
729                if(!font)
730                        font = widget->style->font;
731               
732
733                gdk_gc_set_clip_rectangle (gc, &rect);
734
735                twidth = gdk_string_width(font,text);
736                theight = gdk_string_height(font,text);
737                if(twidth>size)
738                        twidth = size;
739               
740                gdk_gc_set_foreground(gc,&widget->style->black);
741                gdk_draw_rectangle(pixmap,gc,TRUE,
742                                   (widget->allocation.width/2)-(twidth/2)+off-1,
743                                   (widget->allocation.height/2)-(theight/2)-1+off,
744                                   twidth+2,
745                                   theight+2);
746                gdk_gc_set_foreground(gc,&widget->style->white);
747                gdk_draw_string(pixmap,font,gc,
748                                (widget->allocation.width/2)-(twidth/2)+off,
749                                (widget->allocation.height/2)+(theight/2)+off,
750                                text);
751                gdk_gc_set_foreground(gc,&widget->style->black);
752                gdk_gc_set_clip_rectangle (gc, NULL);
753                if(font!=widget->style->font)
754                        gdk_font_unref(font);
755                g_free(text);
756        }
757
758       
759        if(button->arrow) {
760                int i;
761                GdkPoint points[3];
762                draw_arrow(points,button->orient,size);
763                for(i=0;i<3;i++) {
764                        points[i].x+=off;
765                        points[i].y+=off;
766                }
767                gdk_gc_set_foreground(gc,&pwidget->style->white);
768                gdk_draw_polygon(pixmap,gc,TRUE,points,3);
769                gdk_gc_set_foreground(gc,&pwidget->style->black);
770                gdk_draw_polygon(pixmap,gc,FALSE,points,3);
771        }
772
773        if (button->dnd_highlight) {
774                gdk_gc_set_foreground(gc, &widget->style->black);
775                gdk_draw_rectangle(pixmap, gc, FALSE,
776                                   0, 0,
777                                   widget->allocation.width - 1,
778                                   widget->allocation.height - 1);
779        }
780       
781        gdk_gc_destroy(gc);
782}
783
784static void
785button_widget_size_request(GtkWidget *widget, GtkRequisition *requisition)
786{
787        PanelWidget *panel = PANEL_WIDGET(widget->parent);
788        requisition->width = requisition->height = panel->sz;
789}
790
791static void
792button_widget_size_allocate(GtkWidget *widget, GtkAllocation *allocation)
793{
794        ButtonWidget *button_widget;
795
796        g_return_if_fail (widget != NULL);
797        g_return_if_fail (IS_BUTTON_WIDGET (widget));
798
799        button_widget = BUTTON_WIDGET (widget);
800
801        widget->allocation = *allocation;
802        if (GTK_WIDGET_REALIZED (widget)) {
803                PanelWidget *panel;
804                int x,y,w,h;
805
806                panel = PANEL_WIDGET(widget->parent);
807
808                calculate_overlay_geometry (panel, panel->panel_parent,
809                                            widget, &x, &y, &w, &h);
810                gdk_window_move_resize (button_widget->event_window,
811                                        x, y, w, h);
812        }
813}
814
815
816
817static void
818button_widget_init (ButtonWidget *button)
819{
820        buttons = g_list_prepend(buttons,button);
821
822        GTK_WIDGET_SET_FLAGS (button, GTK_NO_WINDOW);
823
824        button->pixbuf = NULL;
825        button->pixbuf_hc = NULL;
826       
827        button->tile = 0;
828        button->arrow = 0;
829        button->orient = ORIENT_UP;
830       
831        button->pressed = FALSE;
832        button->in_button = FALSE;
833        button->ignore_leave = FALSE;
834        button->dnd_highlight = FALSE;
835       
836        button->pressed_timeout = 0;
837       
838        gtk_signal_connect(GTK_OBJECT(button),"destroy",
839                           GTK_SIGNAL_FUNC(button_widget_destroy),
840                           NULL);
841}
842
843static gboolean
844pressed_timeout_func(gpointer data)
845{
846        ButtonWidget *button;
847
848        g_return_val_if_fail (data != NULL, FALSE);
849        g_return_val_if_fail (IS_BUTTON_WIDGET (data), FALSE);
850
851        button = BUTTON_WIDGET (data);
852       
853        button->pressed_timeout = 0;
854       
855        return FALSE;
856}
857
858static gboolean
859button_widget_button_press (GtkWidget *widget, GdkEventButton *event)
860{
861        ButtonWidget *button;
862
863        g_return_val_if_fail (widget != NULL, FALSE);
864        g_return_val_if_fail (IS_BUTTON_WIDGET (widget), FALSE);
865        g_return_val_if_fail (event != NULL, FALSE);
866
867        button = BUTTON_WIDGET (widget);
868
869        if (button->pressed_timeout)
870                return TRUE;
871
872        if (event->button == 1) {
873                gtk_grab_add(widget);
874                button_widget_down (button);
875                button->pressed_timeout =
876                        gtk_timeout_add(400, pressed_timeout_func, button);
877        }
878        return TRUE;
879}
880
881static gboolean
882button_widget_button_release (GtkWidget *widget, GdkEventButton *event)
883{
884        g_return_val_if_fail (widget != NULL, FALSE);
885        g_return_val_if_fail (IS_BUTTON_WIDGET (widget), FALSE);
886        g_return_val_if_fail (event != NULL, FALSE);
887
888        if (event->button == 1) {
889                ButtonWidget *button = BUTTON_WIDGET (widget);
890                gtk_grab_remove (widget);
891                button_widget_up (button);
892        }
893
894        return TRUE;
895}
896
897static gboolean
898button_widget_enter_notify (GtkWidget *widget, GdkEventCrossing *event)
899{
900        GtkWidget *event_widget;
901
902        g_return_val_if_fail (widget != NULL, FALSE);
903        g_return_val_if_fail (IS_BUTTON_WIDGET (widget), FALSE);
904        g_return_val_if_fail (event != NULL, FALSE);
905
906        event_widget = gtk_get_event_widget ((GdkEvent*) event);
907
908        if ((event_widget == widget) &&
909            (event->detail != GDK_NOTIFY_INFERIOR)) {
910                ButtonWidget *button = BUTTON_WIDGET (widget);
911                button->in_button = TRUE;
912                if(global_config.tile_when_over ||
913                   global_config.saturate_when_over) {
914                        if(button->cache)
915                                gdk_pixmap_unref(button->cache);
916                        button->cache = NULL;
917                        panel_widget_draw_icon(PANEL_WIDGET(widget->parent),
918                                               button);
919                }
920        }
921
922        return FALSE;
923}
924
925static gboolean
926button_widget_leave_notify (GtkWidget *widget, GdkEventCrossing *event)
927{
928        GtkWidget *event_widget;
929        ButtonWidget *button;
930
931        g_return_val_if_fail (widget != NULL, FALSE);
932        g_return_val_if_fail (IS_BUTTON_WIDGET (widget), FALSE);
933        g_return_val_if_fail (event != NULL, FALSE);
934
935        event_widget = gtk_get_event_widget ((GdkEvent*) event);
936
937        button = BUTTON_WIDGET (widget);
938
939        if ((event_widget == widget) &&
940            (event->detail != GDK_NOTIFY_INFERIOR) &&
941            (!button->ignore_leave)) {
942                button->in_button = FALSE;
943                if(global_config.tile_when_over ||
944                   global_config.saturate_when_over) {
945                        if(button->cache)
946                                gdk_pixmap_unref(button->cache);
947                        button->cache = NULL;
948                        panel_widget_draw_icon(PANEL_WIDGET(widget->parent),
949                                               button);
950                }
951        }
952
953        return FALSE;
954}
955
956
957void
958button_widget_clicked(ButtonWidget *button)
959{
960        gtk_signal_emit(GTK_OBJECT(button),
961                        button_widget_signals[CLICKED_SIGNAL]);
962}
963
964static void
965button_widget_pressed(ButtonWidget *button)
966{
967        g_return_if_fail(button != NULL);
968        g_return_if_fail(IS_BUTTON_WIDGET(button));
969
970        button->pressed = TRUE;
971        if(button->cache)
972                gdk_pixmap_unref(button->cache);
973        button->cache = NULL;
974        setup_no_alpha(button);
975        panel_widget_draw_icon(PANEL_WIDGET(GTK_WIDGET(button)->parent),
976                               button);
977}
978static void
979button_widget_unpressed(ButtonWidget *button)
980{
981        g_return_if_fail(button != NULL);
982        g_return_if_fail(IS_BUTTON_WIDGET(button));
983
984        button->pressed = FALSE;
985        if(button->cache)
986                gdk_pixmap_unref(button->cache);
987        button->cache = NULL;
988        setup_no_alpha(button);
989        panel_widget_draw_icon(PANEL_WIDGET(GTK_WIDGET(button)->parent),
990                               button);
991        if(button->in_button)
992                button_widget_clicked(button);
993}
994
995void
996button_widget_down(ButtonWidget *button)
997{
998        g_return_if_fail(button != NULL);
999        g_return_if_fail(IS_BUTTON_WIDGET(button));
1000
1001        if(!button->pressed)
1002                gtk_signal_emit(GTK_OBJECT(button),
1003                                button_widget_signals[PRESSED_SIGNAL]);
1004}
1005void
1006button_widget_up(ButtonWidget *button)
1007{
1008        g_return_if_fail(button != NULL);
1009        g_return_if_fail(IS_BUTTON_WIDGET(button));
1010
1011        if(button->pressed)
1012                gtk_signal_emit(GTK_OBJECT(button),
1013                                button_widget_signals[UNPRESSED_SIGNAL]);
1014}
1015
1016static GdkPixbuf *
1017make_hc_pixbuf(GdkPixbuf *pb)
1018{
1019        GdkPixbuf *new;
1020        if(!pb)
1021                return NULL;
1022
1023        new = gdk_pixbuf_new(gdk_pixbuf_get_colorspace(pb),
1024                             gdk_pixbuf_get_has_alpha(pb),
1025                             gdk_pixbuf_get_bits_per_sample(pb),
1026                             gdk_pixbuf_get_width(pb),
1027                             gdk_pixbuf_get_height(pb));
1028        do_colorshift(new, pb, 30);
1029        /*do_saturate_darken (new, pb, (int)(1.00*255), (int)(1.15*255));*/
1030
1031        return new;
1032}
1033
1034
1035GtkWidget*
1036button_widget_new(const char *filename,
1037                  int size,
1038                  int tile,
1039                  gboolean arrow,
1040                  PanelOrientType orient,
1041                  const char *text)
1042{
1043        ButtonWidget *button;
1044
1045        g_return_val_if_fail(tile >= 0, NULL);
1046        g_return_val_if_fail(tile < LAST_TILE, NULL);
1047
1048        button = BUTTON_WIDGET (gtk_type_new (button_widget_get_type ()));
1049       
1050        button->pixbuf = loadup_file (filename);
1051        button->pixbuf_hc = make_hc_pixbuf (button->pixbuf);
1052        button->filename = g_strdup (filename);
1053        button->size = size;
1054        button->tile = tile;
1055        button->arrow = arrow ? 1 : 0;
1056        button->orient = orient;
1057        button->text = text ? g_strdup (text) : NULL;
1058
1059        setup_no_alpha(button);
1060       
1061        return GTK_WIDGET(button);
1062}
1063
1064gboolean
1065button_widget_set_pixmap(ButtonWidget *button, const char *pixmap, int size)
1066{
1067        g_return_val_if_fail(button != NULL, FALSE);
1068        g_return_val_if_fail(IS_BUTTON_WIDGET(button), FALSE);
1069
1070        if (size < 0)
1071                size = PANEL_WIDGET(GTK_WIDGET(button)->parent)->sz;
1072       
1073        if (button->pixbuf != NULL)
1074                gdk_pixbuf_unref(button->pixbuf);
1075        if (button->pixbuf_hc != NULL)
1076                gdk_pixbuf_unref(button->pixbuf_hc);
1077
1078        button->pixbuf = loadup_file(pixmap);
1079        button->pixbuf_hc = make_hc_pixbuf(button->pixbuf);
1080
1081        g_free(button->filename);
1082        button->filename = g_strdup(pixmap);
1083        button->size = size;
1084        if (button->cache != NULL)
1085                gdk_pixmap_unref(button->cache);
1086        button->cache = NULL;
1087
1088        panel_widget_draw_icon(PANEL_WIDGET(GTK_WIDGET(button)->parent),
1089                               button);
1090
1091        if (button->pixbuf == NULL)
1092                return FALSE;
1093       
1094        return TRUE;
1095}
1096
1097void
1098button_widget_set_text(ButtonWidget *button, const char *text)
1099{
1100        g_return_if_fail(button != NULL);
1101        g_return_if_fail(IS_BUTTON_WIDGET(button));
1102
1103        g_free(button->text);
1104        button->text = text?g_strdup(text):NULL;
1105
1106        if (button->cache != NULL)
1107                gdk_pixmap_unref(button->cache);
1108        button->cache = NULL;
1109       
1110        panel_widget_draw_icon(PANEL_WIDGET(GTK_WIDGET(button)->parent),
1111                               button);
1112}
1113
1114void
1115button_widget_set_params(ButtonWidget *button,
1116                         int tile,
1117                         gboolean arrow,
1118                         PanelOrientType orient)
1119{
1120        g_return_if_fail(button != NULL);
1121        g_return_if_fail(IS_BUTTON_WIDGET(button));
1122        g_return_if_fail(tile >= 0);
1123        g_return_if_fail(tile < LAST_TILE);
1124
1125        button->tile = tile;
1126        button->arrow = arrow?1:0;
1127        button->orient = orient;
1128
1129        if(button->cache)
1130                gdk_pixmap_unref(button->cache);
1131        button->cache = NULL;
1132        setup_no_alpha(button);
1133       
1134        panel_widget_draw_icon(PANEL_WIDGET(GTK_WIDGET(button)->parent),
1135                               button);
1136}
1137
1138void
1139button_widget_load_tile(int tile, const char *tile_up, const char *tile_down,
1140                        int border, int depth)
1141{
1142        GdkPixbuf *pb;
1143
1144        g_return_if_fail(tile >= 0);
1145        g_return_if_fail(tile < LAST_TILE);
1146        g_return_if_fail(tile_up != NULL);
1147        g_return_if_fail(tile_down != NULL);
1148
1149        if(tiles.tiles_up[tile])
1150                gdk_pixbuf_unref(tiles.tiles_up[tile]);
1151        if(tiles.tiles_up_hc[tile])
1152                gdk_pixbuf_unref(tiles.tiles_up_hc[tile]);
1153
1154        pb = loadup_file(tile_up);
1155        tiles.tiles_up[tile] = pb;
1156        tiles.tiles_up_hc[tile] = make_hc_pixbuf(pb);
1157
1158        if(tiles.tiles_down[tile])
1159                gdk_pixbuf_unref(tiles.tiles_down[tile]);
1160        if(tiles.tiles_down_hc[tile])
1161                gdk_pixbuf_unref(tiles.tiles_down_hc[tile]);
1162
1163        pb = loadup_file(tile_down);
1164        tiles.tiles_down[tile] = pb;
1165        tiles.tiles_down_hc[tile] = make_hc_pixbuf(pb);
1166
1167        tile_border[tile] = border;
1168        tile_depth[tile] = depth;
1169
1170        button_widget_redo_all ();
1171}
1172
1173void
1174button_widget_set_flags(int tile,
1175                        gboolean enable_tiles,
1176                        gboolean enable_pixmaps,
1177                        gboolean text_always)
1178{
1179        g_return_if_fail (tile >= 0);
1180        g_return_if_fail (tile < LAST_TILE);
1181
1182        if(tiles_enabled[tile] != enable_tiles ||
1183           pixmaps_enabled[tile] != enable_pixmaps ||
1184           always_text[tile] != text_always) {
1185                tiles_enabled[tile] = enable_tiles;
1186                pixmaps_enabled[tile] = enable_pixmaps;
1187                always_text[tile] = text_always;
1188
1189                button_widget_redo_all ();
1190        }
1191}
1192
1193void
1194button_widget_redo_all (void)
1195{
1196        GList *list;
1197
1198        for(list = buttons; list != NULL; list = list->next) {
1199                ButtonWidget *button = list->data;
1200                if(button->cache != NULL)
1201                        gdk_pixmap_unref(button->cache);
1202                button->cache = NULL;
1203                setup_no_alpha(button);
1204                gtk_widget_queue_draw (GTK_WIDGET (button));
1205        }
1206}
Note: See TracBrowser for help on using the repository browser.