updated on Thu Jan 26 16:09:46 UTC 2012
[aur-mirror.git] / notification-daemon-engine-ubuntu / ubuntu_theme.patch
blob17c42855c66c17a78afca2ce35662a436a8111a1
1 diff -Naur notification-daemon-0.4.0.orig/configure.ac notification-daemon-0.4.0/configure.ac
2 --- notification-daemon-0.4.0.orig/configure.ac 2008-11-20 12:46:52.000000000 +0200
3 +++ notification-daemon-0.4.0/configure.ac 2010-07-29 12:56:04.000000000 +0300
4 @@ -207,6 +207,7 @@
5 src/themes/Makefile
6 src/themes/bubble/Makefile
7 src/themes/standard/Makefile
8 +src/themes/ubuntu/Makefile
9 ])
11 AC_OUTPUT
12 diff -Naur notification-daemon-0.4.0.orig/src/themes/Makefile.am notification-daemon-0.4.0/src/themes/Makefile.am
13 --- notification-daemon-0.4.0.orig/src/themes/Makefile.am 2008-03-15 01:11:44.000000000 +0200
14 +++ notification-daemon-0.4.0/src/themes/Makefile.am 2010-07-29 13:16:49.000000000 +0300
15 @@ -1,2 +1,2 @@
16 -SUBDIRS = standard
17 -DIST_SUBDIRS = $(SUBDIRS) bubble
18 +SUBDIRS = standard ubuntu
19 +DIST_SUBDIRS = $(SUBDIRS) bubble ubuntu
20 diff -Naur notification-daemon-0.4.0.orig/src/themes/ubuntu/Makefile.am notification-daemon-0.4.0/src/themes/ubuntu/Makefile.am
21 --- notification-daemon-0.4.0.orig/src/themes/ubuntu/Makefile.am 1970-01-01 02:00:00.000000000 +0200
22 +++ notification-daemon-0.4.0/src/themes/ubuntu/Makefile.am 2010-07-29 13:29:54.000000000 +0300
23 @@ -0,0 +1,9 @@
24 +enginedir = $(libdir)/notification-daemon-1.0/engines
26 +engine_LTLIBRARIES = libubuntu.la
28 +libubuntu_la_SOURCES = theme.c
29 +libubuntu_la_LDFLAGS = -module -avoid-version
30 +libubuntu_la_LIBADD = $(NOTIFICATION_DAEMON_LIBS)
32 +INCLUDES = $(NOTIFICATION_DAEMON_CFLAGS)
33 diff -Naur notification-daemon-0.4.0.orig/src/themes/ubuntu/theme.c notification-daemon-0.4.0/src/themes/ubuntu/theme.c
34 --- notification-daemon-0.4.0.orig/src/themes/ubuntu/theme.c 1970-01-01 02:00:00.000000000 +0200
35 +++ notification-daemon-0.4.0/src/themes/ubuntu/theme.c 2010-07-29 13:01:59.000000000 +0300
36 @@ -0,0 +1,870 @@
37 +#include "config.h"
39 +#include <gtk/gtk.h>
40 +#include <libsexy/sexy-url-label.h>
42 +typedef void (*ActionInvokedCb)(GtkWindow *nw, const char *key);
43 +typedef void (*UrlClickedCb)(GtkWindow *nw, const char *url);
45 +typedef struct
47 + GtkWidget *win;
48 + GtkWidget *top_spacer;
49 + GtkWidget *bottom_spacer;
50 + GtkWidget *main_hbox;
51 + GtkWidget *iconbox;
52 + GtkWidget *icon;
53 + GtkWidget *content_hbox;
54 + GtkWidget *summary_label;
55 + GtkWidget *body_label;
56 + GtkWidget *actions_box;
57 + GtkWidget *last_sep;
58 + GtkWidget *pie_countdown;
59 + GtkWidget *close_button;
61 + /* do we have a arrow and where do we point to */
62 + gboolean has_arrow;
64 + gboolean enable_transparency;
66 + int point_x;
67 + int point_y;
69 + int drawn_arrow_begin_x;
70 + int drawn_arrow_begin_y;
71 + int drawn_arrow_middle_x;
72 + int drawn_arrow_middle_y;
73 + int drawn_arrow_end_x;
74 + int drawn_arrow_end_y;
75 + GtkArrowType arrow_type;
77 + GdkGC *gc;
78 + GdkRegion *window_region;
80 + guchar urgency;
81 + glong timeout;
82 + glong remaining;
84 + UrlClickedCb url_clicked;
86 +} WindowData;
88 +enum
90 + URGENCY_LOW,
91 + URGENCY_NORMAL,
92 + URGENCY_CRITICAL
93 +};
95 +#define WIDTH 300
96 +#define IMAGE_SIZE 32
97 +#define IMAGE_PADDING 10
98 +#define STRIPE_WIDTH 30
100 +#define PIE_RADIUS 14
101 +#define PIE_WIDTH (2 * PIE_RADIUS)
102 +#define PIE_HEIGHT (2 * PIE_RADIUS)
103 +#define PIE_INSIDE_BORDER 2
105 +#define BODY_X_OFFSET (IMAGE_SIZE + 8)
106 +#define DEFAULT_ARROW_OFFSET (STRIPE_WIDTH + 2)
107 +#define DEFAULT_ARROW_HEIGHT 12
108 +#define DEFAULT_ARROW_WIDTH 8
109 +#define ARROW_DISTANCE 6
111 +static GtkStyle *
112 +get_tooltip_style()
114 + /* This is a hack to let us copy the style of tooltips for this theme. */
115 + GtkWidget *fake = gtk_window_new(GTK_WINDOW_POPUP);
116 + gtk_widget_set_name(fake, "gtk-tooltip");
117 + gtk_widget_realize(fake);
118 + // we copy the style to ensure that its available
119 + GtkStyle *style = gtk_style_copy(gtk_widget_get_style(fake));
120 + gtk_widget_destroy(fake);
121 + // having no style is a fatal error
122 + g_assert(style != NULL);
123 + return style;
126 +static void
127 +fill_background(GtkWidget *widget, WindowData *windata, cairo_t *cr)
129 + GtkStyle *style = get_tooltip_style();
130 + gdk_cairo_set_source_color(cr, &style->bg[GTK_STATE_NORMAL]);
131 + cairo_rectangle(cr, 0, 0,
132 + widget->allocation.width,
133 + widget->allocation.height);
134 + cairo_fill(cr);
135 + g_object_unref(G_OBJECT(style));
138 +static void
139 +draw_stripe(GtkWidget *win, cairo_t *cr, WindowData *windata)
141 + GtkStyle *style = gtk_widget_get_style(windata->win);
143 + switch (windata->urgency)
145 + case URGENCY_LOW:
146 + cairo_set_source_rgb(cr,
147 + 242.0/255.0,
148 + 242.0/255.0,
149 + 190.0/255.0);
150 + break;
151 + case URGENCY_NORMAL:
152 + cairo_set_source_rgb(cr,
153 + 220.0/255.0,
154 + 220.0/255.0,
155 + 160.0/255.0);
156 + break;
157 + case URGENCY_CRITICAL:
159 + cairo_set_source_rgb(cr,
160 + style->bg[GTK_STATE_SELECTED].red/65535.0,
161 + style->bg[GTK_STATE_SELECTED].green/65535.0,
162 + style->bg[GTK_STATE_SELECTED].blue/65535.0);
164 + break;
166 + cairo_rectangle(cr,
167 + windata->main_hbox->allocation.x,
168 + windata->main_hbox->allocation.y,
169 + STRIPE_WIDTH,
170 + // FIXME: its unclear why we need the padding
171 + // here
172 + windata->win->allocation.height+IMAGE_PADDING);
173 + cairo_fill(cr);
174 + return;
177 +void draw_rounded_window(cairo_t *mask_cr, float x, float y,
178 + float w, float h, WindowData *windata)
180 + if(windata->has_arrow)
182 + // fix the border
183 + if(windata->arrow_type == GTK_ARROW_UP) {
184 + y += DEFAULT_ARROW_HEIGHT;
185 + h -= DEFAULT_ARROW_HEIGHT;
186 + } else {
187 + h -= (DEFAULT_ARROW_HEIGHT+ARROW_DISTANCE);
191 + int radius = 6;
192 + int bx, by, mx, my, ex, ey;
194 + bx = windata->drawn_arrow_begin_x;
195 + by = windata->drawn_arrow_begin_y;
196 + mx = windata->drawn_arrow_middle_x;
197 + my = windata->drawn_arrow_middle_y;
198 + ex = windata->drawn_arrow_end_x;
199 + ey = windata->drawn_arrow_end_y;
201 + cairo_move_to(mask_cr, x+radius, y);
203 + // the arrow is on top, so we need to draw it here
204 + if(windata->has_arrow && windata->arrow_type == GTK_ARROW_UP) {
205 + if (mx < w/2 ) {
206 + cairo_line_to(mask_cr, bx-10, by);
207 + cairo_curve_to(mask_cr, mx-3, by, mx-3, by, mx, my+ARROW_DISTANCE);
208 + cairo_curve_to(mask_cr, mx+8, ey, mx+8, ey, ex+16, ey);
209 + } else {
210 + cairo_line_to(mask_cr, bx-16, by);
211 + cairo_curve_to(mask_cr, mx-8, by, mx-8, by, mx, my+ARROW_DISTANCE);
212 + cairo_curve_to(mask_cr, mx+3, ey, mx+5, ey, ex+10, ey);
216 + cairo_arc(mask_cr, x+w-radius, y+radius, radius, G_PI * 1.5, G_PI * 2);
217 + cairo_arc(mask_cr, x+w-radius, y+h-radius, radius, 0, G_PI * 0.5);
219 + // the arrow is at the bottom, so it needs to be drawn here
220 + if(windata->has_arrow && windata->arrow_type == GTK_ARROW_DOWN) {
221 + if (mx > w/2 ) {
222 + cairo_line_to(mask_cr, bx+10, by);
224 + cairo_curve_to(mask_cr, mx+3, by, mx+3, by, mx, my-ARROW_DISTANCE);
225 + cairo_curve_to(mask_cr, mx-8, ey, mx-8, ey, ex-16, ey);
226 + } else {
227 + cairo_line_to(mask_cr, bx+16, by);
229 + cairo_curve_to(mask_cr, mx+8, by, mx+8, by, mx, my-ARROW_DISTANCE);
230 + cairo_curve_to(mask_cr, mx-3, ey, mx-5, ey, ex-10, ey);
234 + cairo_arc(mask_cr, x+radius, y+h-radius, radius, G_PI * 0.5, G_PI);
235 + cairo_arc(mask_cr, x+radius, y+radius, radius, G_PI, G_PI *1.5);
238 +static gboolean
239 +mouse_over(GtkWidget *win, GdkEventExpose *event, WindowData *windata)
241 + gtk_widget_set_state(GTK_WIDGET((WindowData*)windata->close_button), GTK_STATE_PRELIGHT);
242 + return FALSE;
245 +static gboolean
246 +mouse_over_end(GtkWidget *win, GdkEventExpose *event, WindowData *windata)
248 + gtk_widget_set_state(GTK_WIDGET((WindowData*)windata->close_button), GTK_STATE_NORMAL);
249 + return FALSE;
253 +static gboolean
254 +draw_border(GtkWidget *win, GdkEventExpose *event, WindowData *windata)
256 + int w, h;
258 + gdk_drawable_get_size(win->window, &w, &h);
260 + // calculate a shape for it
261 + GdkPixmap *mask;
262 + cairo_t *mask_cr;
264 + mask = gdk_pixmap_new (NULL, w, h, 1);
265 + mask_cr = gdk_cairo_create ((GdkDrawable *) mask);
267 + // draw border
268 + cairo_t *cr = gdk_cairo_create((GdkDrawable*) win->window);
270 + GtkStyle *style = get_tooltip_style();
271 + GdkColor bg_color = style->bg[GTK_STATE_NORMAL];
273 + cairo_set_source_rgb(cr,
274 + bg_color.red/65535.0,
275 + bg_color.green/65535.0,
276 + bg_color.blue/65535.0);
278 + cairo_paint (cr);
280 + // draw a stripe
281 + draw_stripe(win, cr, windata);
283 + // then a redish one
284 + cairo_set_source_rgb(cr,
285 + 218.0/255.0,
286 + 178.0/255.0,
287 + 85.0/255.0);
288 + draw_rounded_window (cr, 0, 0, w, h, windata);
289 + // Stroke the border 2 pixels wide so we get a 1 pixel stroke inside our
290 + // path (we'll mask the outside half of it later).
291 + cairo_set_line_width (cr, 2);
292 + cairo_stroke (cr);
294 + // Clear the shape mask
295 + cairo_set_operator (mask_cr, CAIRO_OPERATOR_CLEAR);
296 + cairo_paint (mask_cr);
298 + // Draw the window shape to the input mask
299 + cairo_set_source_rgba(mask_cr, 1, 1, 1, 1);
300 + cairo_set_operator (mask_cr, CAIRO_OPERATOR_OVER);
301 + draw_rounded_window(mask_cr, 0, 0, w, h, windata);
302 + cairo_fill(mask_cr);
304 + if (windata->enable_transparency) {
305 + // If transparency is enabled, we can mask the drawing itself and just
306 + // use the shape mask as an input mask.
307 + cairo_set_operator (cr, CAIRO_OPERATOR_DEST_IN);
308 + cairo_set_source_rgb (cr, 0, 0, 0);
309 + draw_rounded_window (cr, 0, 0, w, h, windata);
310 + cairo_fill (cr);
311 + gdk_window_input_shape_combine_mask (win->window, (GdkBitmap *) mask, 0, 0);
312 + } else {
313 + // Otherwise, use the shape mask for bilevel visual shaping as well.
314 + gdk_window_shape_combine_mask (win->window, (GdkBitmap *) mask, 0, 0);
316 + g_object_unref(G_OBJECT(style));
317 + cairo_destroy(mask_cr);
318 + cairo_destroy(cr);
320 + return FALSE;
325 +static void
326 +destroy_windata(WindowData *windata)
328 + if (windata->gc != NULL)
329 + g_object_unref(G_OBJECT(windata->gc));
331 + if (windata->window_region != NULL)
332 + gdk_region_destroy(windata->window_region);
335 +static void
336 +update_content_hbox_visibility(WindowData *windata)
338 + /*
339 + * This is all a hack, but until we have a libview-style ContentBox,
340 + * it'll just have to do.
341 + */
342 + if (GTK_WIDGET_VISIBLE(windata->icon) ||
343 + GTK_WIDGET_VISIBLE(windata->body_label) ||
344 + GTK_WIDGET_VISIBLE(windata->actions_box))
346 + gtk_widget_show(windata->content_hbox);
348 + else
350 + gtk_widget_hide(windata->content_hbox);
354 +GtkWindow *
355 +create_notification(UrlClickedCb url_clicked)
357 + GtkWidget *spacer;
358 + GtkWidget *win;
359 + GtkWidget *main_vbox;
360 + GtkWidget *hbox;
361 + GtkWidget *vbox;
362 + GtkWidget *close_button;
363 + GtkWidget *image;
364 + GtkWidget *alignment;
365 + WindowData *windata;
366 + GdkColormap *colormap;
367 + GdkScreen *screen;
369 + windata = g_new0(WindowData, 1);
370 + windata->urgency = URGENCY_NORMAL;
371 + windata->url_clicked = url_clicked;
373 + win = gtk_window_new(GTK_WINDOW_POPUP);
374 + windata->win = win;
376 + windata->enable_transparency = FALSE;
377 + screen = gtk_window_get_screen(GTK_WINDOW(win));
378 + colormap = gdk_screen_get_rgba_colormap(screen);
380 + if (colormap != NULL && gdk_screen_is_composited(screen))
382 + gtk_widget_set_colormap(win, colormap);
383 + windata->enable_transparency = TRUE;
387 + gtk_widget_add_events(win, GDK_BUTTON_RELEASE_MASK);
388 + gtk_widget_realize(win);
389 + g_object_set_data_full(G_OBJECT(win), "windata", windata,
390 + (GDestroyNotify)destroy_windata);
391 + gtk_widget_set_app_paintable(win, TRUE);
393 + g_signal_connect(G_OBJECT(win), "expose-event",
394 + G_CALLBACK(draw_border), windata);
395 + g_signal_connect(G_OBJECT(win), "motion-notify-event",
396 + G_CALLBACK(mouse_over), windata);
397 + g_signal_connect(G_OBJECT(win), "leave-notify-event",
398 + G_CALLBACK(mouse_over_end), windata);
400 + main_vbox = gtk_vbox_new(FALSE, 0);
401 + gtk_widget_show(main_vbox);
402 + gtk_container_add(GTK_CONTAINER(win), main_vbox);
403 + gtk_container_set_border_width(GTK_CONTAINER(main_vbox), 1);
405 + windata->top_spacer = gtk_image_new();
406 + gtk_box_pack_start(GTK_BOX(main_vbox), windata->top_spacer,
407 + FALSE, FALSE, 0);
408 + gtk_widget_set_size_request(windata->top_spacer, -1, DEFAULT_ARROW_HEIGHT);
410 + windata->main_hbox = gtk_hbox_new(FALSE, 0);
411 + gtk_widget_show(windata->main_hbox);
412 + gtk_box_pack_start(GTK_BOX(main_vbox), windata->main_hbox,
413 + FALSE, FALSE, 0);
415 + windata->bottom_spacer = gtk_image_new();
416 + gtk_box_pack_start(GTK_BOX(main_vbox), windata->bottom_spacer,
417 + FALSE, FALSE, 0);
418 + gtk_widget_set_size_request(windata->bottom_spacer, -1,
419 + DEFAULT_ARROW_HEIGHT+ARROW_DISTANCE);
421 + vbox = gtk_vbox_new(FALSE, 0);
422 + gtk_widget_show(vbox);
423 + gtk_box_pack_start(GTK_BOX(windata->main_hbox), vbox, TRUE, TRUE, 0);
424 + gtk_container_set_border_width(GTK_CONTAINER(vbox), 6);
426 + hbox = gtk_hbox_new(FALSE, 6);
427 + gtk_widget_show(hbox);
428 + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
430 + spacer = gtk_image_new();
431 + gtk_widget_show(spacer);
432 + gtk_box_pack_start(GTK_BOX(hbox), spacer, FALSE, FALSE, 0);
433 + gtk_widget_set_size_request(spacer, STRIPE_WIDTH, -1);
435 + windata->summary_label = gtk_label_new(NULL);
436 + gtk_widget_show(windata->summary_label);
437 + GtkStyle *style = get_tooltip_style();
438 + gtk_widget_set_style(windata->summary_label, style);
440 + gtk_box_pack_start(GTK_BOX(hbox), windata->summary_label, TRUE, TRUE, 0);
441 + gtk_misc_set_alignment(GTK_MISC(windata->summary_label), 0, 0);
442 + gtk_label_set_line_wrap(GTK_LABEL(windata->summary_label), TRUE);
444 + /* Add the close button */
445 + windata->close_button = close_button = gtk_button_new();
446 + gtk_widget_show(close_button);
447 + gtk_box_pack_start(GTK_BOX(hbox), close_button, FALSE, FALSE, 0);
448 + gtk_button_set_relief(GTK_BUTTON(close_button), GTK_RELIEF_NONE);
449 + gtk_container_set_border_width(GTK_CONTAINER(close_button), 0);
450 + gtk_widget_set_size_request(close_button, 20, 20);
451 + g_signal_connect_swapped(G_OBJECT(close_button), "clicked",
452 + G_CALLBACK(gtk_widget_destroy), win);
454 + image = gtk_image_new_from_stock(GTK_STOCK_CLOSE, GTK_ICON_SIZE_MENU);
455 + gtk_widget_show(image);
456 + gtk_container_add(GTK_CONTAINER(close_button), image);
458 + windata->content_hbox = gtk_hbox_new(FALSE, 6);
459 + gtk_box_pack_start(GTK_BOX(vbox), windata->content_hbox, FALSE, FALSE, 0);
461 + windata->iconbox = gtk_hbox_new(FALSE, 0);
462 + gtk_widget_show(windata->iconbox);
463 + gtk_box_pack_start(GTK_BOX(windata->content_hbox), windata->iconbox,
464 + FALSE, FALSE, 0);
465 + gtk_widget_set_size_request(windata->iconbox, BODY_X_OFFSET, -1);
467 + windata->icon = gtk_image_new();
468 + gtk_box_pack_start(GTK_BOX(windata->iconbox), windata->icon,
469 + TRUE, TRUE, 0);
470 + gtk_misc_set_alignment(GTK_MISC(windata->icon), 0.5, 0.0);
472 + vbox = gtk_vbox_new(FALSE, 6);
473 + gtk_widget_show(vbox);
474 + gtk_box_pack_start(GTK_BOX(windata->content_hbox), vbox, TRUE, TRUE, 0);
476 + windata->body_label = sexy_url_label_new();
477 + gtk_box_pack_start(GTK_BOX(vbox), windata->body_label, TRUE, TRUE, 0);
478 + gtk_misc_set_alignment(GTK_MISC(windata->body_label), 0, 0);
479 + gtk_label_set_line_wrap(GTK_LABEL(windata->body_label), TRUE);
480 + g_signal_connect_swapped(G_OBJECT(windata->body_label), "url_activated",
481 + G_CALLBACK(windata->url_clicked), win);
482 + gtk_widget_set_style(windata->body_label, style);
484 + alignment = gtk_alignment_new(1, 0.5, 0, 0);
485 + gtk_widget_show(alignment);
486 + gtk_box_pack_start(GTK_BOX(vbox), alignment, FALSE, TRUE, 0);
488 + windata->actions_box = gtk_hbox_new(FALSE, 6);
489 + gtk_container_add(GTK_CONTAINER(alignment), windata->actions_box);
490 + g_object_unref(G_OBJECT(style));
492 + return GTK_WINDOW(win);
495 +void
496 +set_notification_hints(GtkWindow *nw, GHashTable *hints)
498 + WindowData *windata = g_object_get_data(G_OBJECT(nw), "windata");
499 + GValue *value;
501 + g_assert(windata != NULL);
503 + value = (GValue *)g_hash_table_lookup(hints, "urgency");
505 + if (value)
506 + windata->urgency = g_value_get_uchar(value);
509 +void
510 +set_notification_timeout(GtkWindow *nw, glong timeout)
512 + WindowData *windata = g_object_get_data(G_OBJECT(nw), "windata");
513 + g_assert(windata != NULL);
515 + windata->timeout = timeout;
518 +void
519 +notification_tick(GtkWindow *nw, glong remaining)
521 + WindowData *windata = g_object_get_data(G_OBJECT(nw), "windata");
522 + windata->remaining = remaining;
524 + if (windata->pie_countdown != NULL)
526 + gtk_widget_queue_draw_area(windata->pie_countdown, 0, 0,
527 + PIE_WIDTH, PIE_HEIGHT);
531 +void
532 +set_notification_text(GtkWindow *nw, const char *summary, const char *body)
534 + char *str;
535 + WindowData *windata = g_object_get_data(G_OBJECT(nw), "windata");
536 + g_assert(windata != NULL);
538 + str = g_markup_printf_escaped("<b>%s</b>", summary);
539 + gtk_label_set_markup(GTK_LABEL(windata->summary_label), str);
540 + g_free(str);
542 + sexy_url_label_set_markup(SEXY_URL_LABEL(windata->body_label), body);
544 + if (body == NULL || *body == '\0')
545 + gtk_widget_hide(windata->body_label);
546 + else
547 + gtk_widget_show(windata->body_label);
549 + update_content_hbox_visibility(windata);
551 + gtk_widget_set_size_request(((body != NULL && *body != '\0') ?
552 + windata->body_label : windata->summary_label),
553 + WIDTH - (IMAGE_SIZE + IMAGE_PADDING) - 10,
554 + -1);
557 +void
558 +set_notification_icon(GtkWindow *nw, GdkPixbuf *pixbuf)
560 + WindowData *windata = g_object_get_data(G_OBJECT(nw), "windata");
561 + g_assert(windata != NULL);
563 + gtk_image_set_from_pixbuf(GTK_IMAGE(windata->icon), pixbuf);
565 + if (pixbuf != NULL)
567 + int pixbuf_width = gdk_pixbuf_get_width(pixbuf);
569 + gtk_widget_show(windata->icon);
570 + gtk_widget_set_size_request(windata->iconbox,
571 + MAX(BODY_X_OFFSET, pixbuf_width), -1);
573 + else
575 + gtk_widget_hide(windata->icon);
576 + gtk_widget_set_size_request(windata->iconbox, BODY_X_OFFSET, -1);
579 + update_content_hbox_visibility(windata);
582 +void
583 +set_notification_arrow(GtkWindow *nw, gboolean visible, int x, int y)
585 + WindowData *windata = g_object_get_data(G_OBJECT(nw), "windata");
586 + g_assert(windata != NULL);
588 + windata->has_arrow = visible;
589 + windata->point_x = x;
590 + windata->point_y = y;
592 + if (!visible)
594 + gtk_widget_hide(windata->top_spacer);
595 + gtk_widget_hide(windata->bottom_spacer);
599 +static gboolean
600 +countdown_expose_cb(GtkWidget *pie, GdkEventExpose *event,
601 + WindowData *windata)
603 + GtkStyle *style = gtk_widget_get_style(windata->win);
605 + cairo_t *context;
606 + cairo_surface_t *surface;
607 + cairo_t *cr;
608 + context = gdk_cairo_create(GDK_DRAWABLE(windata->pie_countdown->window));
609 + cairo_set_operator(context, CAIRO_OPERATOR_SOURCE);
610 + surface = cairo_surface_create_similar(
611 + cairo_get_target(context),
612 + CAIRO_CONTENT_COLOR_ALPHA,
613 + pie->allocation.width,
614 + pie->allocation.height);
615 + cr = cairo_create(surface);
617 + fill_background(pie, windata, cr);
619 + gdk_cairo_set_source_color(cr, &style->base[GTK_STATE_NORMAL]);
621 + cairo_arc(cr, PIE_RADIUS, PIE_RADIUS, PIE_RADIUS, 0, 2 * G_PI);
622 + cairo_close_path(cr);
624 + cairo_fill(cr);
626 + if (windata->timeout > 0)
628 + gdouble pct = (gdouble)windata->remaining / (gdouble)windata->timeout;
630 + gdk_cairo_set_source_color(cr, &style->base[GTK_STATE_SELECTED]);
632 + cairo_move_to(cr, PIE_RADIUS, PIE_RADIUS);
633 + cairo_arc_negative(cr, PIE_RADIUS, PIE_RADIUS, PIE_RADIUS - PIE_INSIDE_BORDER,
634 + -G_PI_2, -(pct * G_PI * 2) - G_PI_2);
635 + cairo_line_to(cr, PIE_RADIUS, PIE_RADIUS);
636 + cairo_fill(cr);
639 + cairo_destroy(cr);
640 + cairo_set_source_surface(context, surface, 0, 0);
641 + cairo_paint(context);
642 + cairo_surface_destroy(surface);
643 + cairo_destroy(context);
645 + return TRUE;
648 +static void
649 +action_clicked_cb(GtkWidget *w, GdkEventButton *event,
650 + ActionInvokedCb action_cb)
652 + GtkWindow *nw = g_object_get_data(G_OBJECT(w), "_nw");
653 + const char *key = g_object_get_data(G_OBJECT(w), "_action_key");
655 + action_cb(nw, key);
658 +void
659 +add_notification_action(GtkWindow *nw, const char *text, const char *key,
660 + ActionInvokedCb cb)
662 + WindowData *windata = g_object_get_data(G_OBJECT(nw), "windata");
663 + GtkWidget *label;
664 + GtkWidget *button;
665 + GtkWidget *hbox;
666 + GdkPixbuf *pixbuf;
667 + char *buf;
669 + g_assert(windata != NULL);
671 + if (!GTK_WIDGET_VISIBLE(windata->actions_box))
673 + GtkWidget *alignment;
675 + gtk_widget_show(windata->actions_box);
676 + update_content_hbox_visibility(windata);
678 + alignment = gtk_alignment_new(1, 0.5, 0, 0);
679 + gtk_widget_show(alignment);
680 + gtk_box_pack_end(GTK_BOX(windata->actions_box), alignment,
681 + FALSE, TRUE, 0);
683 + windata->pie_countdown = gtk_drawing_area_new();
684 + gtk_widget_show(windata->pie_countdown);
685 + gtk_container_add(GTK_CONTAINER(alignment), windata->pie_countdown);
686 + gtk_widget_set_size_request(windata->pie_countdown,
687 + PIE_WIDTH, PIE_HEIGHT);
688 + g_signal_connect(G_OBJECT(windata->pie_countdown), "expose_event",
689 + G_CALLBACK(countdown_expose_cb), windata);
692 + button = gtk_button_new();
693 + gtk_widget_show(button);
694 + gtk_box_pack_start(GTK_BOX(windata->actions_box), button, FALSE, FALSE, 0);
696 + hbox = gtk_hbox_new(FALSE, 6);
697 + gtk_widget_show(hbox);
698 + gtk_container_add(GTK_CONTAINER(button), hbox);
700 + /* Try to be smart and find a suitable icon. */
701 + buf = g_strdup_printf("stock_%s", key);
702 + pixbuf = gtk_icon_theme_load_icon(
703 + gtk_icon_theme_get_for_screen(
704 + gdk_drawable_get_screen(GTK_WIDGET(nw)->window)),
705 + buf, 16, GTK_ICON_LOOKUP_USE_BUILTIN, NULL);
706 + g_free(buf);
708 + if (pixbuf != NULL)
710 + GtkWidget *image = gtk_image_new_from_pixbuf(pixbuf);
711 + gtk_widget_show(image);
712 + gtk_box_pack_start(GTK_BOX(hbox), image, FALSE, FALSE, 0);
713 + gtk_misc_set_alignment(GTK_MISC(image), 0.5, 0.5);
716 + label = gtk_label_new(NULL);
717 + /* mvo: hardcode black here, it sucks */
718 + GdkColor black;
719 + gdk_color_black(gdk_colormap_get_system(), &black);
720 + gtk_widget_modify_fg(label, GTK_STATE_NORMAL, &black);
722 + gtk_widget_show(label);
723 + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
724 + gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
725 + buf = g_strdup_printf("<small>%s</small>", text);
726 + gtk_label_set_markup(GTK_LABEL(label), buf);
728 + g_free(buf);
730 + g_object_set_data(G_OBJECT(button), "_nw", nw);
731 + g_object_set_data_full(G_OBJECT(button),
732 + "_action_key", g_strdup(key), g_free);
733 + g_signal_connect(G_OBJECT(button), "button-release-event",
734 + G_CALLBACK(action_clicked_cb), cb);
738 +static void
739 +create_border_with_arrow(GtkWidget *nw, WindowData *windata)
741 + GtkRequisition req;
742 + GdkScreen *screen;
743 + int monitor_num;
744 + GdkRectangle monitor_geom;
745 + int monitor_left, monitor_right, monitor_top, monitor_bottom;
746 + int arrow_side1_width = DEFAULT_ARROW_WIDTH / 2;
747 + int arrow_side2_width = DEFAULT_ARROW_WIDTH / 2;
748 + int arrow_offset = DEFAULT_ARROW_OFFSET;
750 + gtk_widget_realize(nw);
751 + gtk_widget_size_request(nw, &req);
753 + screen = gdk_drawable_get_screen(GDK_DRAWABLE(nw->window));
754 + monitor_num = gdk_screen_get_monitor_at_point(screen,
755 + windata->point_x, windata->point_y);
756 + gdk_screen_get_monitor_geometry(screen, monitor_num, &monitor_geom);
758 + monitor_left = monitor_geom.x;
759 + monitor_right = monitor_left + monitor_geom.width;
760 + monitor_top = monitor_geom.y;
761 + monitor_bottom = monitor_top + monitor_geom.height;
763 + if (windata->point_y + req.height + DEFAULT_ARROW_HEIGHT >= monitor_bottom)
764 + windata->arrow_type = GTK_ARROW_DOWN;
765 + else
766 + windata->arrow_type = GTK_ARROW_UP;
768 + /* Handle the offset and such */
769 + switch (windata->arrow_type)
771 + case GTK_ARROW_NONE:
772 + /* nothing to do */
773 + break;
774 + case GTK_ARROW_UP:
775 + case GTK_ARROW_DOWN:
776 + if (windata->point_x < monitor_left + arrow_side1_width)
778 + arrow_side1_width = 0;
779 + arrow_offset = 0;
781 + else if (windata->point_x >= monitor_right - arrow_side2_width)
783 + arrow_side2_width = 0;
784 + arrow_offset = req.width - arrow_side1_width;
786 + else
788 + if (windata->point_x - arrow_side2_width + req.width >=
789 + monitor_right)
791 + arrow_offset =
792 + req.width - arrow_side1_width - arrow_side2_width -
793 + (monitor_right - MAX(windata->point_x +
794 + arrow_side1_width,
795 + monitor_right -
796 + DEFAULT_ARROW_OFFSET));
798 + else
800 + arrow_offset = MIN(windata->point_x - arrow_side1_width - monitor_left,
801 + DEFAULT_ARROW_OFFSET);
806 + windata->drawn_arrow_begin_x = arrow_offset;
807 + windata->drawn_arrow_middle_x = arrow_offset + arrow_side1_width;
808 + windata->drawn_arrow_end_x = arrow_offset + arrow_side1_width +
809 + arrow_side2_width;
811 + if (windata->arrow_type == GTK_ARROW_UP)
813 + gtk_widget_show(windata->top_spacer);
814 + windata->drawn_arrow_begin_y = DEFAULT_ARROW_HEIGHT;
815 + windata->drawn_arrow_middle_y = 0;
816 + windata->drawn_arrow_end_y = DEFAULT_ARROW_HEIGHT;
818 + else
820 + gtk_widget_show(windata->bottom_spacer);
821 + windata->drawn_arrow_begin_y = req.height;
822 + windata->drawn_arrow_middle_y = req.height +
823 + DEFAULT_ARROW_HEIGHT;
824 + windata->drawn_arrow_end_y = req.height;
827 + gtk_window_move(GTK_WINDOW(nw),
828 + windata->point_x - arrow_offset -
829 + arrow_side1_width,
830 + (windata->arrow_type == GTK_ARROW_UP
831 + ? windata->point_y
832 + : windata->point_y - req.height -
833 + DEFAULT_ARROW_HEIGHT));
835 + break;
837 + case GTK_ARROW_LEFT:
838 + case GTK_ARROW_RIGHT:
839 + if (windata->point_y < monitor_top + arrow_side1_width)
841 + arrow_side1_width = 0;
842 + arrow_offset = windata->point_y;
844 + else if (windata->point_y >= monitor_bottom - arrow_side2_width)
846 + arrow_side2_width = 0;
847 + arrow_offset = windata->point_y - arrow_side1_width;
849 + break;
852 + draw_border(nw, NULL, windata);
855 +void
856 +move_notification(GtkWindow *nw, int x, int y)
858 + WindowData *windata = g_object_get_data(G_OBJECT(nw), "windata");
859 + g_assert(windata != NULL);
861 + if (windata->has_arrow)
863 + create_border_with_arrow(GTK_WIDGET(nw), windata);
865 + else
867 + gtk_window_move(GTK_WINDOW(nw), x, y);
871 +void
872 +get_theme_info(char **theme_name,
873 + char **theme_ver,
874 + char **author,
875 + char **homepage)
877 + *theme_name = g_strdup("Ubuntu");
878 + *theme_ver = g_strdup_printf("%d.%d.%d",
879 + NOTIFICATION_DAEMON_MAJOR_VERSION,
880 + NOTIFICATION_DAEMON_MINOR_VERSION,
881 + NOTIFICATION_DAEMON_MICRO_VERSION);
882 + *author = g_strdup("Michael Vogt");
883 + *homepage = g_strdup("http://www.ubuntu.com/");
886 +gboolean
887 +theme_check_init(unsigned int major_ver, unsigned int minor_ver,
888 + unsigned int micro_ver)
890 + return major_ver == NOTIFICATION_DAEMON_MAJOR_VERSION &&
891 + minor_ver == NOTIFICATION_DAEMON_MINOR_VERSION &&
892 + micro_ver == NOTIFICATION_DAEMON_MICRO_VERSION;
895 +void
896 +clear_notification_actions(GtkWindow *nw)
898 + WindowData *windata = g_object_get_data(G_OBJECT(nw), "windata");
900 + windata->pie_countdown = NULL;
902 + gtk_widget_hide(windata->actions_box);
903 + gtk_container_foreach(GTK_CONTAINER(windata->actions_box),
904 + (GtkCallback)gtk_object_destroy, NULL);