~ubuntu-branches/ubuntu/hardy/notification-daemon/hardy

« back to all changes in this revision

Viewing changes to debian/01_ubuntu_theme.patch

  • Committer: Bazaar Package Importer
  • Author(s): Michael Vogt
  • Date: 2007-08-15 13:37:03 UTC
  • Revision ID: james.westby@ubuntu.com-20070815133703-lraalwaoujflscjc
Tags: 0.3.7-1ubuntu6
* 01_ubuntu_theme.patch: 
  - improve the pie chart (LP: #132512), thanks to
    Alex Jones

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 
4
@@ -174,6 +174,7 @@
 
5
 src/themes/Makefile
 
6
 src/themes/bubble/Makefile
 
7
 src/themes/standard/Makefile
 
8
+src/themes/ubuntu/Makefile
 
9
 ])
 
10
 
 
11
 AC_OUTPUT
 
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
 
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 -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
 
23
@@ -0,0 +1,9 @@
 
24
+enginedir = $(libdir)/notification-daemon-1.0/engines
 
25
+
 
26
+engine_LTLIBRARIES = libubuntu.la
 
27
+
 
28
+libubuntu_la_SOURCES = theme.c
 
29
+libubuntu_la_LDFLAGS = -module -avoid-version
 
30
+libubuntu_la_LIBADD  = $(NOTIFICATION_DAEMON_LIBS)
 
31
+
 
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
 
36
@@ -0,0 +1,830 @@
 
37
+#include "config.h"
 
38
+
 
39
+#include <gtk/gtk.h>
 
40
+#include <libsexy/sexy-url-label.h>
 
41
+
 
42
+typedef void (*ActionInvokedCb)(GtkWindow *nw, const char *key);
 
43
+typedef void (*UrlClickedCb)(GtkWindow *nw, const char *url);
 
44
+
 
45
+typedef struct
 
46
+{
 
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;
 
60
+
 
61
+       /* do we have a arrow and where do we point to */
 
62
+       gboolean has_arrow;
 
63
+       int point_x;
 
64
+       int point_y;
 
65
+
 
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;
 
73
+
 
74
+       GdkGC *gc;
 
75
+       GdkRegion *window_region;
 
76
+
 
77
+       guchar urgency;
 
78
+       glong timeout;
 
79
+       glong remaining;
 
80
+
 
81
+       UrlClickedCb url_clicked;
 
82
+
 
83
+} WindowData;
 
84
+
 
85
+enum
 
86
+{
 
87
+       URGENCY_LOW,
 
88
+       URGENCY_NORMAL,
 
89
+       URGENCY_CRITICAL
 
90
+};
 
91
+
 
92
+#define WIDTH         300
 
93
+#define IMAGE_SIZE    32
 
94
+#define IMAGE_PADDING 10
 
95
+#define STRIPE_WIDTH  30
 
96
+
 
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
 
101
+
 
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
 
107
+
 
108
+static GtkStyle *
 
109
+get_tooltip_style()
 
110
+{
 
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);
 
117
+       return style;
 
118
+}
 
119
+
 
120
+static void
 
121
+fill_background(GtkWidget *widget, WindowData *windata, cairo_t *cr)
 
122
+{
 
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);
 
128
+       cairo_fill(cr);
 
129
+}
 
130
+
 
131
+static void
 
132
+draw_stripe(GtkWidget *win, cairo_t *cr, WindowData *windata)
 
133
+{
 
134
+       GtkStyle *style = gtk_widget_get_style(windata->win);
 
135
+
 
136
+       switch (windata->urgency)
 
137
+       {
 
138
+               case URGENCY_LOW: 
 
139
+                  cairo_set_source_rgb(cr, 
 
140
+                                       242.0/255.0,
 
141
+                                       242.0/255.0,
 
142
+                                       190.0/255.0);
 
143
+                  break;
 
144
+               case URGENCY_NORMAL: 
 
145
+                  cairo_set_source_rgb(cr, 
 
146
+                                       220.0/255.0,
 
147
+                                       220.0/255.0,
 
148
+                                       160.0/255.0);
 
149
+                  break;
 
150
+               case URGENCY_CRITICAL: 
 
151
+                  
 
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);
 
156
+
 
157
+                  break;
 
158
+       }
 
159
+       cairo_rectangle(cr,
 
160
+                       windata->main_hbox->allocation.x,
 
161
+                       windata->main_hbox->allocation.y,
 
162
+                       STRIPE_WIDTH,
 
163
+                       // FIXME: its unclear why we need the padding
 
164
+                       //        here
 
165
+                       windata->win->allocation.height+IMAGE_PADDING);
 
166
+       cairo_fill(cr);
 
167
+       return;
 
168
+}
 
169
+
 
170
+void draw_rounded_window(cairo_t *mask_cr, float x, float y, 
 
171
+                        float w, float h, WindowData *windata)
 
172
+{
 
173
+       if(windata->has_arrow) 
 
174
+       {
 
175
+               // fix the border
 
176
+               if(windata->arrow_type == GTK_ARROW_UP) {
 
177
+                       y += DEFAULT_ARROW_HEIGHT;
 
178
+                       h -= DEFAULT_ARROW_HEIGHT;
 
179
+               } else {
 
180
+                  h -= (DEFAULT_ARROW_HEIGHT+ARROW_DISTANCE);
 
181
+               }
 
182
+       }
 
183
+
 
184
+       int radius = 6;
 
185
+       int bx, by, mx, my, ex, ey;
 
186
+       
 
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;
 
193
+
 
194
+       cairo_move_to(mask_cr, x+radius, y);
 
195
+
 
196
+       // the arrow is on top, so we need to draw it here
 
197
+       if(windata->has_arrow && windata->arrow_type == GTK_ARROW_UP) {
 
198
+               if (mx < w/2 ) {
 
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);
 
202
+               } else {
 
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);
 
206
+               }
 
207
+       }
 
208
+
 
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);
 
211
+
 
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) {   
 
214
+               if (mx > w/2 ) {
 
215
+                       cairo_line_to(mask_cr, bx+10, by);
 
216
+            
 
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);
 
219
+               } else {
 
220
+                       cairo_line_to(mask_cr, bx+16, by);
 
221
+
 
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);
 
224
+               }
 
225
+       }
 
226
+
 
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);
 
229
+}
 
230
+
 
231
+static gboolean
 
232
+mouse_over(GtkWidget *win, GdkEventExpose *event, WindowData *windata)
 
233
+{
 
234
+   gtk_widget_set_state(GTK_WIDGET((WindowData*)windata->close_button), GTK_STATE_PRELIGHT); 
 
235
+   return FALSE;
 
236
+}
 
237
+
 
238
+static gboolean
 
239
+mouse_over_end(GtkWidget *win, GdkEventExpose *event, WindowData *windata)
 
240
+{
 
241
+   gtk_widget_set_state(GTK_WIDGET((WindowData*)windata->close_button), GTK_STATE_NORMAL); 
 
242
+   return FALSE;
 
243
+}
 
244
+
 
245
+
 
246
+static gboolean
 
247
+draw_border(GtkWidget *win, GdkEventExpose *event, WindowData *windata)
 
248
+{
 
249
+       int w, h;
 
250
+
 
251
+       gdk_drawable_get_size(win->window, &w, &h);
 
252
+
 
253
+       // calculate a shape for it
 
254
+       GdkPixmap *mask;
 
255
+       cairo_t *mask_cr;
 
256
+
 
257
+       mask = gdk_pixmap_new (NULL, w, h, 1);
 
258
+       mask_cr = gdk_cairo_create ((GdkDrawable *) mask);
 
259
+
 
260
+       // draw border
 
261
+       cairo_t *cr = gdk_cairo_create((GdkDrawable*) win->window);
 
262
+
 
263
+       GtkStyle *style = get_tooltip_style();
 
264
+       GdkColor bg_color = style->bg[GTK_STATE_NORMAL];
 
265
+
 
266
+       cairo_set_source_rgb(cr, 
 
267
+                            bg_color.red/65535.0,
 
268
+                            bg_color.green/65535.0,
 
269
+                            bg_color.blue/65535.0);
 
270
+
 
271
+       draw_rounded_window(cr, 0, 0, w, h, windata);
 
272
+       cairo_fill(cr);
 
273
+
 
274
+       // draw a stripe
 
275
+       draw_stripe(win, cr, windata);
 
276
+
 
277
+       // then a redish one
 
278
+       cairo_set_source_rgb(cr, 
 
279
+                            218.0/255.0,
 
280
+                            178.0/255.0,
 
281
+                            85.0/255.0);
 
282
+       draw_rounded_window(cr, 0.5, 1.5, w-1, h-3, windata);
 
283
+       cairo_set_line_width (cr, 1);
 
284
+       cairo_stroke(cr);
 
285
+
 
286
+       // clear the mask
 
287
+       cairo_set_operator (mask_cr, CAIRO_OPERATOR_CLEAR);
 
288
+       cairo_paint (mask_cr);
 
289
+
 
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);
 
293
+
 
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);
 
297
+
 
298
+       return FALSE;
 
299
+}
 
300
+
 
301
+
 
302
+
 
303
+static void
 
304
+destroy_windata(WindowData *windata)
 
305
+{
 
306
+       if (windata->gc != NULL)
 
307
+               g_object_unref(G_OBJECT(windata->gc));
 
308
+
 
309
+       if (windata->window_region != NULL)
 
310
+               gdk_region_destroy(windata->window_region);
 
311
+}
 
312
+
 
313
+static void
 
314
+update_content_hbox_visibility(WindowData *windata)
 
315
+{
 
316
+       /*
 
317
+        * This is all a hack, but until we have a libview-style ContentBox,
 
318
+        * it'll just have to do.
 
319
+        */
 
320
+       if (GTK_WIDGET_VISIBLE(windata->icon) ||
 
321
+               GTK_WIDGET_VISIBLE(windata->body_label) ||
 
322
+               GTK_WIDGET_VISIBLE(windata->actions_box))
 
323
+       {
 
324
+               gtk_widget_show(windata->content_hbox);
 
325
+       }
 
326
+       else
 
327
+       {
 
328
+               gtk_widget_hide(windata->content_hbox);
 
329
+       }
 
330
+}
 
331
+
 
332
+GtkWindow *
 
333
+create_notification(UrlClickedCb url_clicked)
 
334
+{
 
335
+       GtkWidget *spacer;
 
336
+       GtkWidget *win;
 
337
+       GtkWidget *main_vbox;
 
338
+       GtkWidget *hbox;
 
339
+       GtkWidget *vbox;
 
340
+       GtkWidget *close_button;
 
341
+       GtkWidget *image;
 
342
+       GtkWidget *alignment;
 
343
+       WindowData *windata;
 
344
+
 
345
+       windata = g_new0(WindowData, 1);
 
346
+       windata->urgency = URGENCY_NORMAL;
 
347
+       windata->url_clicked = url_clicked;
 
348
+
 
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);
 
356
+
 
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);
 
363
+
 
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);
 
368
+
 
369
+       windata->top_spacer = gtk_image_new();
 
370
+       gtk_box_pack_start(GTK_BOX(main_vbox), windata->top_spacer,
 
371
+                                          FALSE, FALSE, 0);
 
372
+       gtk_widget_set_size_request(windata->top_spacer, -1, DEFAULT_ARROW_HEIGHT);
 
373
+
 
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,
 
377
+                                          FALSE, FALSE, 0);
 
378
+
 
379
+       windata->bottom_spacer = gtk_image_new();
 
380
+       gtk_box_pack_start(GTK_BOX(main_vbox), windata->bottom_spacer,
 
381
+                                          FALSE, FALSE, 0);
 
382
+       gtk_widget_set_size_request(windata->bottom_spacer, -1,
 
383
+                                   DEFAULT_ARROW_HEIGHT+ARROW_DISTANCE);
 
384
+
 
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);
 
389
+
 
390
+       hbox = gtk_hbox_new(FALSE, 6);
 
391
+       gtk_widget_show(hbox);
 
392
+       gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
 
393
+
 
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);
 
398
+
 
399
+       windata->summary_label = gtk_label_new(NULL);
 
400
+       gtk_widget_show(windata->summary_label);
 
401
+
 
402
+
 
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);
 
406
+
 
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);
 
416
+
 
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);
 
420
+
 
421
+       windata->content_hbox = gtk_hbox_new(FALSE, 6);
 
422
+       gtk_box_pack_start(GTK_BOX(vbox), windata->content_hbox, FALSE, FALSE, 0);
 
423
+
 
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,
 
427
+                                          FALSE, FALSE, 0);
 
428
+       gtk_widget_set_size_request(windata->iconbox, BODY_X_OFFSET, -1);
 
429
+
 
430
+       windata->icon = gtk_image_new();
 
431
+       gtk_box_pack_start(GTK_BOX(windata->iconbox), windata->icon,
 
432
+                                          TRUE, TRUE, 0);
 
433
+       gtk_misc_set_alignment(GTK_MISC(windata->icon), 0.5, 0.0);
 
434
+
 
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);
 
438
+
 
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);
 
445
+
 
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);
 
449
+
 
450
+       windata->actions_box = gtk_hbox_new(FALSE, 6);
 
451
+       gtk_container_add(GTK_CONTAINER(alignment), windata->actions_box);
 
452
+
 
453
+       return GTK_WINDOW(win);
 
454
+}
 
455
+
 
456
+void
 
457
+set_notification_hints(GtkWindow *nw, GHashTable *hints)
 
458
+{
 
459
+       WindowData *windata = g_object_get_data(G_OBJECT(nw), "windata");
 
460
+       GValue *value;
 
461
+
 
462
+       g_assert(windata != NULL);
 
463
+
 
464
+       value = (GValue *)g_hash_table_lookup(hints, "urgency");
 
465
+
 
466
+       if (value)
 
467
+               windata->urgency = g_value_get_uchar(value);
 
468
+}
 
469
+
 
470
+void
 
471
+set_notification_timeout(GtkWindow *nw, glong timeout)
 
472
+{
 
473
+       WindowData *windata = g_object_get_data(G_OBJECT(nw), "windata");
 
474
+       g_assert(windata != NULL);
 
475
+
 
476
+       windata->timeout = timeout;
 
477
+}
 
478
+
 
479
+void
 
480
+notification_tick(GtkWindow *nw, glong remaining)
 
481
+{
 
482
+       WindowData *windata = g_object_get_data(G_OBJECT(nw), "windata");
 
483
+       windata->remaining = remaining;
 
484
+
 
485
+       if (windata->pie_countdown != NULL)
 
486
+       {
 
487
+               gtk_widget_queue_draw_area(windata->pie_countdown, 0, 0,
 
488
+                                                                  PIE_WIDTH, PIE_HEIGHT);
 
489
+       }
 
490
+}
 
491
+
 
492
+void
 
493
+set_notification_text(GtkWindow *nw, const char *summary, const char *body)
 
494
+{
 
495
+       char *str;
 
496
+       WindowData *windata = g_object_get_data(G_OBJECT(nw), "windata");
 
497
+       g_assert(windata != NULL);
 
498
+
 
499
+       str = g_strdup_printf("<b>%s</b>", summary);
 
500
+       gtk_label_set_markup(GTK_LABEL(windata->summary_label), str);
 
501
+       g_free(str);
 
502
+
 
503
+       sexy_url_label_set_markup(SEXY_URL_LABEL(windata->body_label), body);
 
504
+
 
505
+       if (body == NULL || *body == '\0')
 
506
+               gtk_widget_hide(windata->body_label);
 
507
+       else
 
508
+               gtk_widget_show(windata->body_label);
 
509
+
 
510
+       update_content_hbox_visibility(windata);
 
511
+
 
512
+      gtk_widget_set_size_request(((body != NULL && *body == '\0') ? 
 
513
+                                 windata->body_label : windata->summary_label), 
 
514
+                                WIDTH - (IMAGE_SIZE + IMAGE_PADDING) - 10,
 
515
+                                -1);
 
516
+}
 
517
+
 
518
+void
 
519
+set_notification_icon(GtkWindow *nw, GdkPixbuf *pixbuf)
 
520
+{
 
521
+       WindowData *windata = g_object_get_data(G_OBJECT(nw), "windata");
 
522
+       g_assert(windata != NULL);
 
523
+
 
524
+       gtk_image_set_from_pixbuf(GTK_IMAGE(windata->icon), pixbuf);
 
525
+
 
526
+       if (pixbuf != NULL)
 
527
+       {
 
528
+               int pixbuf_width = gdk_pixbuf_get_width(pixbuf);
 
529
+
 
530
+               gtk_widget_show(windata->icon);
 
531
+               gtk_widget_set_size_request(windata->iconbox,
 
532
+                                                                       MAX(BODY_X_OFFSET, pixbuf_width), -1);
 
533
+       }
 
534
+       else
 
535
+       {
 
536
+               gtk_widget_hide(windata->icon);
 
537
+               gtk_widget_set_size_request(windata->iconbox, BODY_X_OFFSET, -1);
 
538
+       }
 
539
+
 
540
+       update_content_hbox_visibility(windata);
 
541
+}
 
542
+
 
543
+void
 
544
+set_notification_arrow(GtkWindow *nw, gboolean visible, int x, int y)
 
545
+{
 
546
+       WindowData *windata = g_object_get_data(G_OBJECT(nw), "windata");
 
547
+       g_assert(windata != NULL);
 
548
+
 
549
+       windata->has_arrow = visible;
 
550
+       windata->point_x = x;
 
551
+       windata->point_y = y;
 
552
+
 
553
+       if (!visible)
 
554
+       {
 
555
+               gtk_widget_hide(windata->top_spacer);
 
556
+               gtk_widget_hide(windata->bottom_spacer);
 
557
+       }
 
558
+}
 
559
+
 
560
+static gboolean
 
561
+countdown_expose_cb(GtkWidget *pie, GdkEventExpose *event,
 
562
+                                       WindowData *windata)
 
563
+{
 
564
+       GtkStyle *style = gtk_widget_get_style(windata->win);
 
565
+
 
566
+       cairo_t *context;
 
567
+       cairo_surface_t *surface;
 
568
+       cairo_t *cr;
 
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);
 
577
+
 
578
+       fill_background(pie, windata, cr);
 
579
+
 
580
+       gdk_cairo_set_source_color(cr, &style->base[GTK_STATE_NORMAL]);
 
581
+       
 
582
+       cairo_arc(cr, PIE_RADIUS, PIE_RADIUS, PIE_RADIUS, 0, 2 * G_PI);
 
583
+       cairo_close_path(cr);
 
584
+       
 
585
+       cairo_fill(cr);
 
586
+
 
587
+       if (windata->timeout > 0)
 
588
+       {
 
589
+               gdouble pct = (gdouble)windata->remaining / (gdouble)windata->timeout;
 
590
+
 
591
+               gdk_cairo_set_source_color(cr, &style->base[GTK_STATE_SELECTED]);
 
592
+
 
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);
 
597
+               cairo_fill(cr);
 
598
+       }
 
599
+       
 
600
+       cairo_destroy(cr);
 
601
+       cairo_set_source_surface(context, surface, 0, 0);
 
602
+       cairo_paint(context);
 
603
+       cairo_surface_destroy(surface);
 
604
+       cairo_destroy(context);
 
605
+
 
606
+       return TRUE;
 
607
+}
 
608
+
 
609
+static void
 
610
+action_clicked_cb(GtkWidget *w, GdkEventButton *event,
 
611
+                                 ActionInvokedCb action_cb)
 
612
+{
 
613
+       GtkWindow *nw   = g_object_get_data(G_OBJECT(w), "_nw");
 
614
+       const char *key = g_object_get_data(G_OBJECT(w), "_action_key");
 
615
+
 
616
+       action_cb(nw, key);
 
617
+}
 
618
+
 
619
+void
 
620
+add_notification_action(GtkWindow *nw, const char *text, const char *key,
 
621
+                                               ActionInvokedCb cb)
 
622
+{
 
623
+       WindowData *windata = g_object_get_data(G_OBJECT(nw), "windata");
 
624
+       GtkWidget *label;
 
625
+       GtkWidget *button;
 
626
+       GtkWidget *hbox;
 
627
+       GdkPixbuf *pixbuf;
 
628
+       char *buf;
 
629
+
 
630
+       g_assert(windata != NULL);
 
631
+
 
632
+       if (!GTK_WIDGET_VISIBLE(windata->actions_box))
 
633
+       {
 
634
+               GtkWidget *alignment;
 
635
+
 
636
+               gtk_widget_show(windata->actions_box);
 
637
+               update_content_hbox_visibility(windata);
 
638
+
 
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,
 
642
+                                                  FALSE, TRUE, 0);
 
643
+
 
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);
 
651
+       }
 
652
+
 
653
+       button = gtk_button_new();
 
654
+       gtk_widget_show(button);
 
655
+       gtk_box_pack_start(GTK_BOX(windata->actions_box), button, FALSE, FALSE, 0);
 
656
+
 
657
+       hbox = gtk_hbox_new(FALSE, 6);
 
658
+       gtk_widget_show(hbox);
 
659
+       gtk_container_add(GTK_CONTAINER(button), hbox);
 
660
+
 
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);
 
667
+       g_free(buf);
 
668
+
 
669
+       if (pixbuf != NULL)
 
670
+       {
 
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);
 
675
+       }
 
676
+
 
677
+       label = gtk_label_new(NULL);
 
678
+       /* mvo: hardcode black here, it sucks */
 
679
+       GdkColor black;
 
680
+       gdk_color_black(gdk_colormap_get_system(), &black);
 
681
+       gtk_widget_modify_fg(label, GTK_STATE_NORMAL, &black);
 
682
+
 
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);
 
688
+
 
689
+       g_free(buf);
 
690
+
 
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);
 
696
+}
 
697
+
 
698
+
 
699
+static void
 
700
+create_border_with_arrow(GtkWidget *nw, WindowData *windata)
 
701
+{
 
702
+       GtkRequisition req;
 
703
+       GdkScreen *screen;
 
704
+       int monitor_num;
 
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;
 
710
+
 
711
+       gtk_widget_realize(nw);
 
712
+       gtk_widget_size_request(nw, &req);
 
713
+
 
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);
 
718
+
 
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;
 
723
+
 
724
+       if (windata->point_y + req.height + DEFAULT_ARROW_HEIGHT >= monitor_bottom)
 
725
+               windata->arrow_type = GTK_ARROW_DOWN;
 
726
+       else
 
727
+               windata->arrow_type = GTK_ARROW_UP;
 
728
+
 
729
+       /* Handle the offset and such */
 
730
+       switch (windata->arrow_type)
 
731
+       {
 
732
+               case GTK_ARROW_NONE:
 
733
+                  /* nothing to do */
 
734
+                  break;
 
735
+               case GTK_ARROW_UP:
 
736
+               case GTK_ARROW_DOWN:
 
737
+                       if (windata->point_x < monitor_left + arrow_side1_width)
 
738
+                       {
 
739
+                               arrow_side1_width = 0;
 
740
+                               arrow_offset = 0;
 
741
+                       }
 
742
+                       else if (windata->point_x >= monitor_right - arrow_side2_width)
 
743
+                       {
 
744
+                               arrow_side2_width = 0;
 
745
+                               arrow_offset = req.width - arrow_side1_width;
 
746
+                       }
 
747
+                       else
 
748
+                       {
 
749
+                               if (windata->point_x - arrow_side2_width + req.width >=
 
750
+                                       monitor_right)
 
751
+                               {
 
752
+                                       arrow_offset =
 
753
+                                               req.width - arrow_side1_width - arrow_side2_width -
 
754
+                                               (monitor_right - MAX(windata->point_x +
 
755
+                                                                                       arrow_side1_width,
 
756
+                                                                                       monitor_right -
 
757
+                                                                                       DEFAULT_ARROW_OFFSET));
 
758
+                               }
 
759
+                               else
 
760
+                               {
 
761
+                                       arrow_offset = MIN(windata->point_x - arrow_side1_width - monitor_left,
 
762
+                                                                          DEFAULT_ARROW_OFFSET);
 
763
+                               }
 
764
+
 
765
+                       }
 
766
+
 
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 +
 
770
+                                                                                arrow_side2_width;
 
771
+
 
772
+                       if (windata->arrow_type == GTK_ARROW_UP)
 
773
+                       {
 
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;
 
778
+                       }
 
779
+                       else
 
780
+                       {
 
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;
 
786
+                       }
 
787
+
 
788
+                       gtk_window_move(GTK_WINDOW(nw),
 
789
+                                                       windata->point_x - arrow_offset -
 
790
+                                                       arrow_side1_width,
 
791
+                                                       (windata->arrow_type == GTK_ARROW_UP
 
792
+                                                        ? windata->point_y
 
793
+                                                        : windata->point_y - req.height -
 
794
+                                                          DEFAULT_ARROW_HEIGHT));
 
795
+
 
796
+                       break;
 
797
+
 
798
+               case GTK_ARROW_LEFT:
 
799
+               case GTK_ARROW_RIGHT:
 
800
+                       if (windata->point_y < monitor_top + arrow_side1_width)
 
801
+                       {
 
802
+                               arrow_side1_width = 0;
 
803
+                               arrow_offset = windata->point_y;
 
804
+                       }
 
805
+                       else if (windata->point_y >= monitor_bottom - arrow_side2_width)
 
806
+                       {
 
807
+                               arrow_side2_width = 0;
 
808
+                               arrow_offset = windata->point_y - arrow_side1_width;
 
809
+                       }
 
810
+                       break;
 
811
+       }
 
812
+
 
813
+       draw_border(nw, NULL, windata);
 
814
+}
 
815
+
 
816
+void
 
817
+move_notification(GtkWindow *nw, int x, int y)
 
818
+{
 
819
+       WindowData *windata = g_object_get_data(G_OBJECT(nw), "windata");
 
820
+       g_assert(windata != NULL);
 
821
+
 
822
+       if (windata->has_arrow)
 
823
+       {
 
824
+               create_border_with_arrow(GTK_WIDGET(nw), windata);
 
825
+       }
 
826
+       else
 
827
+       {
 
828
+               gtk_window_move(GTK_WINDOW(nw), x, y);
 
829
+       }
 
830
+}
 
831
+
 
832
+void
 
833
+get_theme_info(char **theme_name,
 
834
+                           char **theme_ver,
 
835
+                           char **author,
 
836
+                           char **homepage)
 
837
+{
 
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/");
 
845
+}
 
846
+
 
847
+gboolean
 
848
+theme_check_init(unsigned int major_ver, unsigned int minor_ver,
 
849
+                                 unsigned int micro_ver)
 
850
+{
 
851
+        return major_ver == NOTIFICATION_DAEMON_MAJOR_VERSION &&
 
852
+               minor_ver == NOTIFICATION_DAEMON_MINOR_VERSION &&
 
853
+               micro_ver == NOTIFICATION_DAEMON_MICRO_VERSION;
 
854
+}
 
855
+
 
856
+void
 
857
+clear_notification_actions(GtkWindow *nw)
 
858
+{
 
859
+        WindowData *windata = g_object_get_data(G_OBJECT(nw), "windata");
 
860
+
 
861
+        windata->pie_countdown = NULL;
 
862
+
 
863
+        gtk_widget_hide(windata->actions_box);
 
864
+        gtk_container_foreach(GTK_CONTAINER(windata->actions_box),
 
865
+                                                  (GtkCallback)gtk_object_destroy, NULL);
 
866
+}