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 | |
---|
23 | static GdkPixbuf *button_load_pixbuf (const char *file, |
---|
24 | int preffered_size, |
---|
25 | char **error); |
---|
26 | |
---|
27 | enum { |
---|
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 | |
---|
38 | extern GlobalConfig global_config; |
---|
39 | |
---|
40 | static GObjectClass *parent_class; |
---|
41 | |
---|
42 | static void |
---|
43 | translate_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 | |
---|
54 | static GtkWidget * |
---|
55 | get_frame(BasePWidget *basep) |
---|
56 | { |
---|
57 | if (GTK_WIDGET_VISIBLE (basep->frame)) { |
---|
58 | return basep->frame; |
---|
59 | } else { |
---|
60 | return basep->innerebox; |
---|
61 | } |
---|
62 | } |
---|
63 | |
---|
64 | static void |
---|
65 | calculate_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 */ |
---|
149 | static void |
---|
150 | do_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 | |
---|
188 | static GdkPixbuf * |
---|
189 | make_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 | |
---|
206 | static void |
---|
207 | button_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 | |
---|
254 | static void |
---|
255 | button_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 | |
---|
275 | static void |
---|
276 | button_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 | |
---|
291 | static void |
---|
292 | button_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 | |
---|
362 | static void |
---|
363 | button_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 | |
---|
377 | static void |
---|
378 | button_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 | |
---|
397 | static void |
---|
398 | button_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 | |
---|
431 | static void |
---|
432 | button_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 | |
---|
498 | static char *default_pixmap = NULL; |
---|
499 | |
---|
500 | static GdkPixbuf * |
---|
501 | get_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 | |
---|
517 | static GdkPixbuf * |
---|
518 | button_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 | |
---|
553 | static void |
---|
554 | draw_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 | |
---|
592 | void |
---|
593 | button_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 | |
---|
604 | static gboolean |
---|
605 | button_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 | |
---|
701 | static void |
---|
702 | button_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 | |
---|
710 | static void |
---|
711 | button_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 | |
---|
740 | static gboolean |
---|
741 | pressed_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 | |
---|
754 | static gboolean |
---|
755 | button_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 | |
---|
770 | static gboolean |
---|
771 | button_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 | |
---|
782 | static gboolean |
---|
783 | button_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 | |
---|
798 | static void |
---|
799 | button_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 | |
---|
813 | static void |
---|
814 | button_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 | |
---|
822 | static void |
---|
823 | button_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 | |
---|
839 | static void |
---|
840 | button_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 | |
---|
911 | GType |
---|
912 | button_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 | |
---|
936 | GtkWidget * |
---|
937 | button_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 | |
---|
955 | GtkWidget * |
---|
956 | button_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 | |
---|
974 | void |
---|
975 | button_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 | |
---|
983 | void |
---|
984 | button_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 | |
---|
992 | void |
---|
993 | button_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 | } |
---|