1
diff -Nur notification-daemon-0.3.7/configure.ac notification-daemon-0.3.7.new/configure.ac
2
--- notification-daemon-0.3.7/configure.ac 2007-02-28 05:16:16.000000000 +0000
3
+++ notification-daemon-0.3.7.new/configure.ac 2007-08-14 19:52:23.000000000 +0100
6
src/themes/bubble/Makefile
7
src/themes/standard/Makefile
8
+src/themes/ubuntu/Makefile
12
diff -Nur notification-daemon-0.3.7/src/themes/Makefile.am notification-daemon-0.3.7.new/src/themes/Makefile.am
13
--- notification-daemon-0.3.7/src/themes/Makefile.am 2006-10-08 22:04:02.000000000 +0100
14
+++ notification-daemon-0.3.7.new/src/themes/Makefile.am 2007-08-14 19:52:23.000000000 +0100
17
-DIST_SUBDIRS = $(SUBDIRS) bubble
18
+SUBDIRS = standard ubuntu
19
+DIST_SUBDIRS = $(SUBDIRS) bubble ubuntu
20
diff -Nur notification-daemon-0.3.7/src/themes/ubuntu/Makefile.am notification-daemon-0.3.7.new/src/themes/ubuntu/Makefile.am
21
--- notification-daemon-0.3.7/src/themes/ubuntu/Makefile.am 1970-01-01 01:00:00.000000000 +0100
22
+++ notification-daemon-0.3.7.new/src/themes/ubuntu/Makefile.am 2007-08-14 19:52:23.000000000 +0100
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 -Nur notification-daemon-0.3.7/src/themes/ubuntu/theme.c notification-daemon-0.3.7.new/src/themes/ubuntu/theme.c
34
--- notification-daemon-0.3.7/src/themes/ubuntu/theme.c 1970-01-01 01:00:00.000000000 +0100
35
+++ notification-daemon-0.3.7.new/src/themes/ubuntu/theme.c 2007-08-14 19:52:26.000000000 +0100
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);
48
+ GtkWidget *top_spacer;
49
+ GtkWidget *bottom_spacer;
50
+ GtkWidget *main_hbox;
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 */
66
+ int drawn_arrow_begin_x;
67
+ int drawn_arrow_begin_y;
68
+ int drawn_arrow_middle_x;
69
+ int drawn_arrow_middle_y;
70
+ int drawn_arrow_end_x;
71
+ int drawn_arrow_end_y;
72
+ GtkArrowType arrow_type;
75
+ GdkRegion *window_region;
81
+ UrlClickedCb url_clicked;
93
+#define IMAGE_SIZE 32
94
+#define IMAGE_PADDING 10
95
+#define STRIPE_WIDTH 30
97
+#define PIE_RADIUS 14
98
+#define PIE_WIDTH (2 * PIE_RADIUS)
99
+#define PIE_HEIGHT (2 * PIE_RADIUS)
100
+#define PIE_INSIDE_BORDER 2
102
+#define BODY_X_OFFSET (IMAGE_SIZE + 8)
103
+#define DEFAULT_ARROW_OFFSET (STRIPE_WIDTH + 2)
104
+#define DEFAULT_ARROW_HEIGHT 12
105
+#define DEFAULT_ARROW_WIDTH 8
106
+#define ARROW_DISTANCE 6
111
+ /* This is a hack to let us copy the style of tooltips for this theme. */
112
+ GtkWidget *fake = gtk_window_new(GTK_WINDOW_POPUP);
113
+ gtk_widget_set_name(fake, "gtk-tooltip");
114
+ gtk_widget_realize(fake);
115
+ GtkStyle *style = gtk_widget_get_style(fake);
116
+ gtk_widget_destroy(fake);
121
+fill_background(GtkWidget *widget, WindowData *windata, cairo_t *cr)
123
+ GtkStyle *style = get_tooltip_style();
124
+ gdk_cairo_set_source_color(cr, &style->bg[GTK_STATE_NORMAL]);
125
+ cairo_rectangle(cr, 0, 0,
126
+ widget->allocation.width,
127
+ widget->allocation.height);
132
+draw_stripe(GtkWidget *win, cairo_t *cr, WindowData *windata)
134
+ GtkStyle *style = gtk_widget_get_style(windata->win);
136
+ switch (windata->urgency)
139
+ cairo_set_source_rgb(cr,
144
+ case URGENCY_NORMAL:
145
+ cairo_set_source_rgb(cr,
150
+ case URGENCY_CRITICAL:
152
+ cairo_set_source_rgb(cr,
153
+ style->bg[GTK_STATE_SELECTED].red/65535.0,
154
+ style->bg[GTK_STATE_SELECTED].green/65535.0,
155
+ style->bg[GTK_STATE_SELECTED].blue/65535.0);
159
+ cairo_rectangle(cr,
160
+ windata->main_hbox->allocation.x,
161
+ windata->main_hbox->allocation.y,
163
+ // FIXME: its unclear why we need the padding
165
+ windata->win->allocation.height+IMAGE_PADDING);
170
+void draw_rounded_window(cairo_t *mask_cr, float x, float y,
171
+ float w, float h, WindowData *windata)
173
+ if(windata->has_arrow)
176
+ if(windata->arrow_type == GTK_ARROW_UP) {
177
+ y += DEFAULT_ARROW_HEIGHT;
178
+ h -= DEFAULT_ARROW_HEIGHT;
180
+ h -= (DEFAULT_ARROW_HEIGHT+ARROW_DISTANCE);
185
+ int bx, by, mx, my, ex, ey;
187
+ bx = windata->drawn_arrow_begin_x;
188
+ by = windata->drawn_arrow_begin_y;
189
+ mx = windata->drawn_arrow_middle_x;
190
+ my = windata->drawn_arrow_middle_y;
191
+ ex = windata->drawn_arrow_end_x;
192
+ ey = windata->drawn_arrow_end_y;
194
+ cairo_move_to(mask_cr, x+radius, y);
196
+ // the arrow is on top, so we need to draw it here
197
+ if(windata->has_arrow && windata->arrow_type == GTK_ARROW_UP) {
199
+ cairo_line_to(mask_cr, bx-10, by);
200
+ cairo_curve_to(mask_cr, mx-3, by, mx-3, by, mx, my+ARROW_DISTANCE);
201
+ cairo_curve_to(mask_cr, mx+8, ey, mx+8, ey, ex+16, ey);
203
+ cairo_line_to(mask_cr, bx-16, by);
204
+ cairo_curve_to(mask_cr, mx-8, by, mx-8, by, mx, my+ARROW_DISTANCE);
205
+ cairo_curve_to(mask_cr, mx+3, ey, mx+5, ey, ex+10, ey);
209
+ cairo_arc(mask_cr, x+w-radius, y+radius, radius, G_PI * 1.5, G_PI * 2);
210
+ cairo_arc(mask_cr, x+w-radius, y+h-radius, radius, 0, G_PI * 0.5);
212
+ // the arrow is at the bottom, so it needs to be drawn here
213
+ if(windata->has_arrow && windata->arrow_type == GTK_ARROW_DOWN) {
215
+ cairo_line_to(mask_cr, bx+10, by);
217
+ cairo_curve_to(mask_cr, mx+3, by, mx+3, by, mx, my-ARROW_DISTANCE);
218
+ cairo_curve_to(mask_cr, mx-8, ey, mx-8, ey, ex-16, ey);
220
+ cairo_line_to(mask_cr, bx+16, by);
222
+ cairo_curve_to(mask_cr, mx+8, by, mx+8, by, mx, my-ARROW_DISTANCE);
223
+ cairo_curve_to(mask_cr, mx-3, ey, mx-5, ey, ex-10, ey);
227
+ cairo_arc(mask_cr, x+radius, y+h-radius, radius, G_PI * 0.5, G_PI);
228
+ cairo_arc(mask_cr, x+radius, y+radius, radius, G_PI, G_PI *1.5);
232
+mouse_over(GtkWidget *win, GdkEventExpose *event, WindowData *windata)
234
+ gtk_widget_set_state(GTK_WIDGET((WindowData*)windata->close_button), GTK_STATE_PRELIGHT);
239
+mouse_over_end(GtkWidget *win, GdkEventExpose *event, WindowData *windata)
241
+ gtk_widget_set_state(GTK_WIDGET((WindowData*)windata->close_button), GTK_STATE_NORMAL);
247
+draw_border(GtkWidget *win, GdkEventExpose *event, WindowData *windata)
251
+ gdk_drawable_get_size(win->window, &w, &h);
253
+ // calculate a shape for it
257
+ mask = gdk_pixmap_new (NULL, w, h, 1);
258
+ mask_cr = gdk_cairo_create ((GdkDrawable *) mask);
261
+ cairo_t *cr = gdk_cairo_create((GdkDrawable*) win->window);
263
+ GtkStyle *style = get_tooltip_style();
264
+ GdkColor bg_color = style->bg[GTK_STATE_NORMAL];
266
+ cairo_set_source_rgb(cr,
267
+ bg_color.red/65535.0,
268
+ bg_color.green/65535.0,
269
+ bg_color.blue/65535.0);
271
+ draw_rounded_window(cr, 0, 0, w, h, windata);
275
+ draw_stripe(win, cr, windata);
277
+ // then a redish one
278
+ cairo_set_source_rgb(cr,
282
+ draw_rounded_window(cr, 0.5, 1.5, w-1, h-3, windata);
283
+ cairo_set_line_width (cr, 1);
287
+ cairo_set_operator (mask_cr, CAIRO_OPERATOR_CLEAR);
288
+ cairo_paint (mask_cr);
290
+ // draw a "black" rounded thing
291
+ cairo_set_source_rgba(mask_cr, 1,1,1,1);
292
+ cairo_set_operator (mask_cr, CAIRO_OPERATOR_OVER);
294
+ draw_rounded_window(mask_cr, 0,1,w,h-2, windata);
295
+ cairo_fill(mask_cr);
296
+ gdk_window_shape_combine_mask (win->window, (GdkBitmap *) mask, 0, 0);
304
+destroy_windata(WindowData *windata)
306
+ if (windata->gc != NULL)
307
+ g_object_unref(G_OBJECT(windata->gc));
309
+ if (windata->window_region != NULL)
310
+ gdk_region_destroy(windata->window_region);
314
+update_content_hbox_visibility(WindowData *windata)
317
+ * This is all a hack, but until we have a libview-style ContentBox,
318
+ * it'll just have to do.
320
+ if (GTK_WIDGET_VISIBLE(windata->icon) ||
321
+ GTK_WIDGET_VISIBLE(windata->body_label) ||
322
+ GTK_WIDGET_VISIBLE(windata->actions_box))
324
+ gtk_widget_show(windata->content_hbox);
328
+ gtk_widget_hide(windata->content_hbox);
333
+create_notification(UrlClickedCb url_clicked)
337
+ GtkWidget *main_vbox;
340
+ GtkWidget *close_button;
342
+ GtkWidget *alignment;
343
+ WindowData *windata;
345
+ windata = g_new0(WindowData, 1);
346
+ windata->urgency = URGENCY_NORMAL;
347
+ windata->url_clicked = url_clicked;
349
+ win = gtk_window_new(GTK_WINDOW_POPUP);
350
+ windata->win = win;
351
+ gtk_widget_add_events(win, GDK_BUTTON_RELEASE_MASK);
352
+ gtk_widget_realize(win);
353
+ g_object_set_data_full(G_OBJECT(win), "windata", windata,
354
+ (GDestroyNotify)destroy_windata);
355
+ gtk_widget_set_app_paintable(win, TRUE);
357
+ g_signal_connect(G_OBJECT(win), "expose-event",
358
+ G_CALLBACK(draw_border), windata);
359
+ g_signal_connect(G_OBJECT(win), "motion-notify-event",
360
+ G_CALLBACK(mouse_over), windata);
361
+ g_signal_connect(G_OBJECT(win), "leave-notify-event",
362
+ G_CALLBACK(mouse_over_end), windata);
364
+ main_vbox = gtk_vbox_new(FALSE, 0);
365
+ gtk_widget_show(main_vbox);
366
+ gtk_container_add(GTK_CONTAINER(win), main_vbox);
367
+ gtk_container_set_border_width(GTK_CONTAINER(main_vbox), 1);
369
+ windata->top_spacer = gtk_image_new();
370
+ gtk_box_pack_start(GTK_BOX(main_vbox), windata->top_spacer,
372
+ gtk_widget_set_size_request(windata->top_spacer, -1, DEFAULT_ARROW_HEIGHT);
374
+ windata->main_hbox = gtk_hbox_new(FALSE, 0);
375
+ gtk_widget_show(windata->main_hbox);
376
+ gtk_box_pack_start(GTK_BOX(main_vbox), windata->main_hbox,
379
+ windata->bottom_spacer = gtk_image_new();
380
+ gtk_box_pack_start(GTK_BOX(main_vbox), windata->bottom_spacer,
382
+ gtk_widget_set_size_request(windata->bottom_spacer, -1,
383
+ DEFAULT_ARROW_HEIGHT+ARROW_DISTANCE);
385
+ vbox = gtk_vbox_new(FALSE, 0);
386
+ gtk_widget_show(vbox);
387
+ gtk_box_pack_start(GTK_BOX(windata->main_hbox), vbox, TRUE, TRUE, 0);
388
+ gtk_container_set_border_width(GTK_CONTAINER(vbox), 6);
390
+ hbox = gtk_hbox_new(FALSE, 6);
391
+ gtk_widget_show(hbox);
392
+ gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
394
+ spacer = gtk_image_new();
395
+ gtk_widget_show(spacer);
396
+ gtk_box_pack_start(GTK_BOX(hbox), spacer, FALSE, FALSE, 0);
397
+ gtk_widget_set_size_request(spacer, STRIPE_WIDTH, -1);
399
+ windata->summary_label = gtk_label_new(NULL);
400
+ gtk_widget_show(windata->summary_label);
403
+ gtk_box_pack_start(GTK_BOX(hbox), windata->summary_label, TRUE, TRUE, 0);
404
+ gtk_misc_set_alignment(GTK_MISC(windata->summary_label), 0, 0);
405
+ gtk_label_set_line_wrap(GTK_LABEL(windata->summary_label), TRUE);
407
+ /* Add the close button */
408
+ windata->close_button = close_button = gtk_button_new();
409
+ gtk_widget_show(close_button);
410
+ gtk_box_pack_start(GTK_BOX(hbox), close_button, FALSE, FALSE, 0);
411
+ gtk_button_set_relief(GTK_BUTTON(close_button), GTK_RELIEF_NONE);
412
+ gtk_container_set_border_width(GTK_CONTAINER(close_button), 0);
413
+ gtk_widget_set_size_request(close_button, 20, 20);
414
+ g_signal_connect_swapped(G_OBJECT(close_button), "clicked",
415
+ G_CALLBACK(gtk_widget_destroy), win);
417
+ image = gtk_image_new_from_stock(GTK_STOCK_CLOSE, GTK_ICON_SIZE_MENU);
418
+ gtk_widget_show(image);
419
+ gtk_container_add(GTK_CONTAINER(close_button), image);
421
+ windata->content_hbox = gtk_hbox_new(FALSE, 6);
422
+ gtk_box_pack_start(GTK_BOX(vbox), windata->content_hbox, FALSE, FALSE, 0);
424
+ windata->iconbox = gtk_hbox_new(FALSE, 0);
425
+ gtk_widget_show(windata->iconbox);
426
+ gtk_box_pack_start(GTK_BOX(windata->content_hbox), windata->iconbox,
428
+ gtk_widget_set_size_request(windata->iconbox, BODY_X_OFFSET, -1);
430
+ windata->icon = gtk_image_new();
431
+ gtk_box_pack_start(GTK_BOX(windata->iconbox), windata->icon,
433
+ gtk_misc_set_alignment(GTK_MISC(windata->icon), 0.5, 0.0);
435
+ vbox = gtk_vbox_new(FALSE, 6);
436
+ gtk_widget_show(vbox);
437
+ gtk_box_pack_start(GTK_BOX(windata->content_hbox), vbox, TRUE, TRUE, 0);
439
+ windata->body_label = sexy_url_label_new();
440
+ gtk_box_pack_start(GTK_BOX(vbox), windata->body_label, TRUE, TRUE, 0);
441
+ gtk_misc_set_alignment(GTK_MISC(windata->body_label), 0, 0);
442
+ gtk_label_set_line_wrap(GTK_LABEL(windata->body_label), TRUE);
443
+ g_signal_connect_swapped(G_OBJECT(windata->body_label), "url_activated",
444
+ G_CALLBACK(windata->url_clicked), win);
446
+ alignment = gtk_alignment_new(1, 0.5, 0, 0);
447
+ gtk_widget_show(alignment);
448
+ gtk_box_pack_start(GTK_BOX(vbox), alignment, FALSE, TRUE, 0);
450
+ windata->actions_box = gtk_hbox_new(FALSE, 6);
451
+ gtk_container_add(GTK_CONTAINER(alignment), windata->actions_box);
453
+ return GTK_WINDOW(win);
457
+set_notification_hints(GtkWindow *nw, GHashTable *hints)
459
+ WindowData *windata = g_object_get_data(G_OBJECT(nw), "windata");
462
+ g_assert(windata != NULL);
464
+ value = (GValue *)g_hash_table_lookup(hints, "urgency");
467
+ windata->urgency = g_value_get_uchar(value);
471
+set_notification_timeout(GtkWindow *nw, glong timeout)
473
+ WindowData *windata = g_object_get_data(G_OBJECT(nw), "windata");
474
+ g_assert(windata != NULL);
476
+ windata->timeout = timeout;
480
+notification_tick(GtkWindow *nw, glong remaining)
482
+ WindowData *windata = g_object_get_data(G_OBJECT(nw), "windata");
483
+ windata->remaining = remaining;
485
+ if (windata->pie_countdown != NULL)
487
+ gtk_widget_queue_draw_area(windata->pie_countdown, 0, 0,
488
+ PIE_WIDTH, PIE_HEIGHT);
493
+set_notification_text(GtkWindow *nw, const char *summary, const char *body)
496
+ WindowData *windata = g_object_get_data(G_OBJECT(nw), "windata");
497
+ g_assert(windata != NULL);
499
+ str = g_strdup_printf("<b>%s</b>", summary);
500
+ gtk_label_set_markup(GTK_LABEL(windata->summary_label), str);
503
+ sexy_url_label_set_markup(SEXY_URL_LABEL(windata->body_label), body);
505
+ if (body == NULL || *body == '\0')
506
+ gtk_widget_hide(windata->body_label);
508
+ gtk_widget_show(windata->body_label);
510
+ update_content_hbox_visibility(windata);
512
+ gtk_widget_set_size_request(((body != NULL && *body == '\0') ?
513
+ windata->body_label : windata->summary_label),
514
+ WIDTH - (IMAGE_SIZE + IMAGE_PADDING) - 10,
519
+set_notification_icon(GtkWindow *nw, GdkPixbuf *pixbuf)
521
+ WindowData *windata = g_object_get_data(G_OBJECT(nw), "windata");
522
+ g_assert(windata != NULL);
524
+ gtk_image_set_from_pixbuf(GTK_IMAGE(windata->icon), pixbuf);
526
+ if (pixbuf != NULL)
528
+ int pixbuf_width = gdk_pixbuf_get_width(pixbuf);
530
+ gtk_widget_show(windata->icon);
531
+ gtk_widget_set_size_request(windata->iconbox,
532
+ MAX(BODY_X_OFFSET, pixbuf_width), -1);
536
+ gtk_widget_hide(windata->icon);
537
+ gtk_widget_set_size_request(windata->iconbox, BODY_X_OFFSET, -1);
540
+ update_content_hbox_visibility(windata);
544
+set_notification_arrow(GtkWindow *nw, gboolean visible, int x, int y)
546
+ WindowData *windata = g_object_get_data(G_OBJECT(nw), "windata");
547
+ g_assert(windata != NULL);
549
+ windata->has_arrow = visible;
550
+ windata->point_x = x;
551
+ windata->point_y = y;
555
+ gtk_widget_hide(windata->top_spacer);
556
+ gtk_widget_hide(windata->bottom_spacer);
561
+countdown_expose_cb(GtkWidget *pie, GdkEventExpose *event,
562
+ WindowData *windata)
564
+ GtkStyle *style = gtk_widget_get_style(windata->win);
567
+ cairo_surface_t *surface;
569
+ context = gdk_cairo_create(GDK_DRAWABLE(windata->pie_countdown->window));
570
+ cairo_set_operator(context, CAIRO_OPERATOR_SOURCE);
571
+ surface = cairo_surface_create_similar(
572
+ cairo_get_target(context),
573
+ CAIRO_CONTENT_COLOR_ALPHA,
574
+ pie->allocation.width,
575
+ pie->allocation.height);
576
+ cr = cairo_create(surface);
578
+ fill_background(pie, windata, cr);
580
+ gdk_cairo_set_source_color(cr, &style->base[GTK_STATE_NORMAL]);
582
+ cairo_arc(cr, PIE_RADIUS, PIE_RADIUS, PIE_RADIUS, 0, 2 * G_PI);
583
+ cairo_close_path(cr);
587
+ if (windata->timeout > 0)
589
+ gdouble pct = (gdouble)windata->remaining / (gdouble)windata->timeout;
591
+ gdk_cairo_set_source_color(cr, &style->base[GTK_STATE_SELECTED]);
593
+ cairo_move_to(cr, PIE_RADIUS, PIE_RADIUS);
594
+ cairo_arc_negative(cr, PIE_RADIUS, PIE_RADIUS, PIE_RADIUS - PIE_INSIDE_BORDER,
595
+ -G_PI_2, -(pct * G_PI * 2) - G_PI_2);
596
+ cairo_line_to(cr, PIE_RADIUS, PIE_RADIUS);
601
+ cairo_set_source_surface(context, surface, 0, 0);
602
+ cairo_paint(context);
603
+ cairo_surface_destroy(surface);
604
+ cairo_destroy(context);
610
+action_clicked_cb(GtkWidget *w, GdkEventButton *event,
611
+ ActionInvokedCb action_cb)
613
+ GtkWindow *nw = g_object_get_data(G_OBJECT(w), "_nw");
614
+ const char *key = g_object_get_data(G_OBJECT(w), "_action_key");
616
+ action_cb(nw, key);
620
+add_notification_action(GtkWindow *nw, const char *text, const char *key,
621
+ ActionInvokedCb cb)
623
+ WindowData *windata = g_object_get_data(G_OBJECT(nw), "windata");
630
+ g_assert(windata != NULL);
632
+ if (!GTK_WIDGET_VISIBLE(windata->actions_box))
634
+ GtkWidget *alignment;
636
+ gtk_widget_show(windata->actions_box);
637
+ update_content_hbox_visibility(windata);
639
+ alignment = gtk_alignment_new(1, 0.5, 0, 0);
640
+ gtk_widget_show(alignment);
641
+ gtk_box_pack_end(GTK_BOX(windata->actions_box), alignment,
644
+ windata->pie_countdown = gtk_drawing_area_new();
645
+ gtk_widget_show(windata->pie_countdown);
646
+ gtk_container_add(GTK_CONTAINER(alignment), windata->pie_countdown);
647
+ gtk_widget_set_size_request(windata->pie_countdown,
648
+ PIE_WIDTH, PIE_HEIGHT);
649
+ g_signal_connect(G_OBJECT(windata->pie_countdown), "expose_event",
650
+ G_CALLBACK(countdown_expose_cb), windata);
653
+ button = gtk_button_new();
654
+ gtk_widget_show(button);
655
+ gtk_box_pack_start(GTK_BOX(windata->actions_box), button, FALSE, FALSE, 0);
657
+ hbox = gtk_hbox_new(FALSE, 6);
658
+ gtk_widget_show(hbox);
659
+ gtk_container_add(GTK_CONTAINER(button), hbox);
661
+ /* Try to be smart and find a suitable icon. */
662
+ buf = g_strdup_printf("stock_%s", key);
663
+ pixbuf = gtk_icon_theme_load_icon(
664
+ gtk_icon_theme_get_for_screen(
665
+ gdk_drawable_get_screen(GTK_WIDGET(nw)->window)),
666
+ buf, 16, GTK_ICON_LOOKUP_USE_BUILTIN, NULL);
669
+ if (pixbuf != NULL)
671
+ GtkWidget *image = gtk_image_new_from_pixbuf(pixbuf);
672
+ gtk_widget_show(image);
673
+ gtk_box_pack_start(GTK_BOX(hbox), image, FALSE, FALSE, 0);
674
+ gtk_misc_set_alignment(GTK_MISC(image), 0.5, 0.5);
677
+ label = gtk_label_new(NULL);
678
+ /* mvo: hardcode black here, it sucks */
680
+ gdk_color_black(gdk_colormap_get_system(), &black);
681
+ gtk_widget_modify_fg(label, GTK_STATE_NORMAL, &black);
683
+ gtk_widget_show(label);
684
+ gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
685
+ gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
686
+ buf = g_strdup_printf("<small>%s</small>", text);
687
+ gtk_label_set_markup(GTK_LABEL(label), buf);
691
+ g_object_set_data(G_OBJECT(button), "_nw", nw);
692
+ g_object_set_data_full(G_OBJECT(button),
693
+ "_action_key", g_strdup(key), g_free);
694
+ g_signal_connect(G_OBJECT(button), "button-release-event",
695
+ G_CALLBACK(action_clicked_cb), cb);
700
+create_border_with_arrow(GtkWidget *nw, WindowData *windata)
702
+ GtkRequisition req;
705
+ GdkRectangle monitor_geom;
706
+ int monitor_left, monitor_right, monitor_top, monitor_bottom;
707
+ int arrow_side1_width = DEFAULT_ARROW_WIDTH / 2;
708
+ int arrow_side2_width = DEFAULT_ARROW_WIDTH / 2;
709
+ int arrow_offset = DEFAULT_ARROW_OFFSET;
711
+ gtk_widget_realize(nw);
712
+ gtk_widget_size_request(nw, &req);
714
+ screen = gdk_drawable_get_screen(GDK_DRAWABLE(nw->window));
715
+ monitor_num = gdk_screen_get_monitor_at_point(screen,
716
+ windata->point_x, windata->point_y);
717
+ gdk_screen_get_monitor_geometry(screen, monitor_num, &monitor_geom);
719
+ monitor_left = monitor_geom.x;
720
+ monitor_right = monitor_left + monitor_geom.width;
721
+ monitor_top = monitor_geom.y;
722
+ monitor_bottom = monitor_top + monitor_geom.height;
724
+ if (windata->point_y + req.height + DEFAULT_ARROW_HEIGHT >= monitor_bottom)
725
+ windata->arrow_type = GTK_ARROW_DOWN;
727
+ windata->arrow_type = GTK_ARROW_UP;
729
+ /* Handle the offset and such */
730
+ switch (windata->arrow_type)
732
+ case GTK_ARROW_NONE:
733
+ /* nothing to do */
736
+ case GTK_ARROW_DOWN:
737
+ if (windata->point_x < monitor_left + arrow_side1_width)
739
+ arrow_side1_width = 0;
742
+ else if (windata->point_x >= monitor_right - arrow_side2_width)
744
+ arrow_side2_width = 0;
745
+ arrow_offset = req.width - arrow_side1_width;
749
+ if (windata->point_x - arrow_side2_width + req.width >=
753
+ req.width - arrow_side1_width - arrow_side2_width -
754
+ (monitor_right - MAX(windata->point_x +
757
+ DEFAULT_ARROW_OFFSET));
761
+ arrow_offset = MIN(windata->point_x - arrow_side1_width - monitor_left,
762
+ DEFAULT_ARROW_OFFSET);
767
+ windata->drawn_arrow_begin_x = arrow_offset;
768
+ windata->drawn_arrow_middle_x = arrow_offset + arrow_side1_width;
769
+ windata->drawn_arrow_end_x = arrow_offset + arrow_side1_width +
772
+ if (windata->arrow_type == GTK_ARROW_UP)
774
+ gtk_widget_show(windata->top_spacer);
775
+ windata->drawn_arrow_begin_y = DEFAULT_ARROW_HEIGHT;
776
+ windata->drawn_arrow_middle_y = 0;
777
+ windata->drawn_arrow_end_y = DEFAULT_ARROW_HEIGHT;
781
+ gtk_widget_show(windata->bottom_spacer);
782
+ windata->drawn_arrow_begin_y = req.height;
783
+ windata->drawn_arrow_middle_y = req.height +
784
+ DEFAULT_ARROW_HEIGHT;
785
+ windata->drawn_arrow_end_y = req.height;
788
+ gtk_window_move(GTK_WINDOW(nw),
789
+ windata->point_x - arrow_offset -
791
+ (windata->arrow_type == GTK_ARROW_UP
793
+ : windata->point_y - req.height -
794
+ DEFAULT_ARROW_HEIGHT));
798
+ case GTK_ARROW_LEFT:
799
+ case GTK_ARROW_RIGHT:
800
+ if (windata->point_y < monitor_top + arrow_side1_width)
802
+ arrow_side1_width = 0;
803
+ arrow_offset = windata->point_y;
805
+ else if (windata->point_y >= monitor_bottom - arrow_side2_width)
807
+ arrow_side2_width = 0;
808
+ arrow_offset = windata->point_y - arrow_side1_width;
813
+ draw_border(nw, NULL, windata);
817
+move_notification(GtkWindow *nw, int x, int y)
819
+ WindowData *windata = g_object_get_data(G_OBJECT(nw), "windata");
820
+ g_assert(windata != NULL);
822
+ if (windata->has_arrow)
824
+ create_border_with_arrow(GTK_WIDGET(nw), windata);
828
+ gtk_window_move(GTK_WINDOW(nw), x, y);
833
+get_theme_info(char **theme_name,
838
+ *theme_name = g_strdup("Ubuntu");
839
+ *theme_ver = g_strdup_printf("%d.%d.%d",
840
+ NOTIFICATION_DAEMON_MAJOR_VERSION,
841
+ NOTIFICATION_DAEMON_MINOR_VERSION,
842
+ NOTIFICATION_DAEMON_MICRO_VERSION);
843
+ *author = g_strdup("Michael Vogt");
844
+ *homepage = g_strdup("http://www.ubuntu.com/");
848
+theme_check_init(unsigned int major_ver, unsigned int minor_ver,
849
+ unsigned int micro_ver)
851
+ return major_ver == NOTIFICATION_DAEMON_MAJOR_VERSION &&
852
+ minor_ver == NOTIFICATION_DAEMON_MINOR_VERSION &&
853
+ micro_ver == NOTIFICATION_DAEMON_MICRO_VERSION;
857
+clear_notification_actions(GtkWindow *nw)
859
+ WindowData *windata = g_object_get_data(G_OBJECT(nw), "windata");
861
+ windata->pie_countdown = NULL;
863
+ gtk_widget_hide(windata->actions_box);
864
+ gtk_container_foreach(GTK_CONTAINER(windata->actions_box),
865
+ (GtkCallback)gtk_object_destroy, NULL);