Bug Summary

File:themes/standard/theme.c
Warning:line 473, column 5
Value stored to 'arrow_side2_width' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name theme.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/rootdir/src/themes/standard -resource-dir /usr/lib/llvm-16/lib/clang/16 -D HAVE_CONFIG_H -I . -I ../../.. -I /usr/include/ctk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/x86_64-linux-gnu -I /usr/include/webp -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/at-spi-2.0 -I /usr/include/dbus-1.0 -I /usr/lib/x86_64-linux-gnu/dbus-1.0/include -D _REENTRANT -D _REENTRANT -I /usr/local/include/libvnck-3.0 -I /usr/include/startup-notification-1.0 -I /usr/include/ctk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/x86_64-linux-gnu -I /usr/include/webp -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/at-spi-2.0 -I /usr/include/dbus-1.0 -I /usr/lib/x86_64-linux-gnu/dbus-1.0/include -I /usr/include/libxml2 -D PIC -internal-isystem /usr/lib/llvm-16/lib/clang/16/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/13/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fdebug-compilation-dir=/rootdir/src/themes/standard -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2024-08-05-192803-39007-1 -x c theme.c
1/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 *
3 * Copyright (C) 2006-2007 Christian Hammond <chipx86@chipx86.com>
4 * Copyright (C) 2009 Red Hat, Inc.
5 * Copyright (C) 2011 Perberos <perberos@gmail.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2, or (at your option)
10 * any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301, USA.
21 */
22#include "config.h"
23
24#include <glib/gi18n.h>
25#include <ctk/ctk.h>
26
27#include <libxml/xpath.h>
28
29typedef void (*ActionInvokedCb) (CtkWindow* nw, const char* key);
30typedef void (*UrlClickedCb) (CtkWindow* nw, const char* url);
31
32typedef struct {
33 CtkWidget* win;
34 CtkWidget* top_spacer;
35 CtkWidget* bottom_spacer;
36 CtkWidget* main_hbox;
37 CtkWidget* iconbox;
38 CtkWidget* icon;
39 CtkWidget* content_hbox;
40 CtkWidget* summary_label;
41 CtkWidget* close_button;
42 CtkWidget* body_label;
43 CtkWidget* actions_box;
44 CtkWidget* last_sep;
45 CtkWidget* stripe_spacer;
46 CtkWidget* pie_countdown;
47
48 gboolean has_arrow;
49 gboolean composited;
50 gboolean action_icons;
51
52 int point_x;
53 int point_y;
54
55 int drawn_arrow_begin_x;
56 int drawn_arrow_begin_y;
57 int drawn_arrow_middle_x;
58 int drawn_arrow_middle_y;
59 int drawn_arrow_end_x;
60 int drawn_arrow_end_y;
61
62 int width;
63 int height;
64
65 CdkPoint* border_points;
66 size_t num_border_points;
67
68 cairo_region_t *window_region;
69
70 guchar urgency;
71 glong timeout;
72 glong remaining;
73
74 UrlClickedCb url_clicked;
75
76} WindowData;
77
78enum {
79 URGENCY_LOW,
80 URGENCY_NORMAL,
81 URGENCY_CRITICAL
82};
83
84gboolean theme_check_init(unsigned int major_ver, unsigned int minor_ver,
85 unsigned int micro_ver);
86void get_theme_info(char **theme_name, char **theme_ver, char **author,
87 char **homepage);
88CtkWindow* create_notification(UrlClickedCb url_clicked);
89void set_notification_text(CtkWindow *nw, const char *summary,
90 const char *body);
91void set_notification_icon(CtkWindow *nw, GdkPixbuf *pixbuf);
92void set_notification_arrow(CtkWidget *nw, gboolean visible, int x, int y);
93void add_notification_action(CtkWindow *nw, const char *text, const char *key,
94 ActionInvokedCb cb);
95void clear_notification_actions(CtkWindow *nw);
96void move_notification(CtkWidget *nw, int x, int y);
97void set_notification_timeout(CtkWindow *nw, glong timeout);
98void set_notification_hints(CtkWindow *nw, GVariant *hints);
99void notification_tick(CtkWindow *nw, glong remaining);
100
101//#define ENABLE_GRADIENT_LOOK
102
103#ifdef ENABLE_GRADIENT_LOOK
104 #define STRIPE_WIDTH30 45
105#else
106 #define STRIPE_WIDTH30 30
107#endif
108
109#define WIDTH400 400
110#define IMAGE_SIZE32 32
111#define IMAGE_PADDING10 10
112#define SPACER_LEFT30 30
113#define PIE_RADIUS12 12
114#define PIE_WIDTH(2 * 12) (2 * PIE_RADIUS12)
115#define PIE_HEIGHT(2 * 12) (2 * PIE_RADIUS12)
116#define BODY_X_OFFSET(32 + 8) (IMAGE_SIZE32 + 8)
117#define DEFAULT_ARROW_OFFSET(30 + 2) (SPACER_LEFT30 + 2)
118#define DEFAULT_ARROW_HEIGHT14 14
119#define DEFAULT_ARROW_WIDTH28 28
120#define BACKGROUND_OPACITY0.92 0.92
121#define BOTTOM_GRADIENT_HEIGHT30 30
122
123static void
124get_background_color (CtkStyleContext *context,
125 CtkStateFlags state,
126 CdkRGBA *color)
127{
128 CdkRGBA *c;
129
130 g_return_if_fail (color != NULL)do { if ((color != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "color != NULL");
return; } } while (0)
;
131 g_return_if_fail (CTK_IS_STYLE_CONTEXT (context))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((context)); GType __t = ((ctk_style_context_get_type ()))
; gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class
&& __inst->g_class->g_type == __t) __r = (!(0)
); else __r = g_type_check_instance_is_a (__inst, __t); __r; }
)))))) { } else { g_return_if_fail_warning (((gchar*) 0), ((const
char*) (__func__)), "CTK_IS_STYLE_CONTEXT (context)"); return
; } } while (0)
;
132
133 ctk_style_context_get (context, state,
134 "background-color", &c,
135 NULL((void*)0));
136
137 *color = *c;
138 cdk_rgba_free (c);
139}
140
141static void fill_background(CtkWidget* widget, WindowData* windata, cairo_t* cr)
142{
143 CtkStyleContext *context;
144 CdkRGBA bg;
145
146 CtkAllocation allocation;
147
148 ctk_widget_get_allocation(widget, &allocation);
149
150 #ifdef ENABLE_GRADIENT_LOOK
151
152 cairo_pattern_t *gradient;
153 int gradient_y;
154
155 gradient_y = allocation.height - BOTTOM_GRADIENT_HEIGHT30;
156
157 #endif
158
159 context = ctk_widget_get_style_context (windata->win);
160
161 ctk_style_context_save (context);
162 ctk_style_context_set_state (context, CTK_STATE_FLAG_NORMAL);
163
164 get_background_color (context, CTK_STATE_FLAG_NORMAL, &bg);
165
166 ctk_style_context_restore (context);
167
168 if (windata->composited)
169 {
170 cairo_set_source_rgba(cr, bg.red, bg.green, bg.blue, BACKGROUND_OPACITY0.92);
171 }
172 else
173 {
174 cdk_cairo_set_source_rgba (cr, &bg);
175 }
176
177 cairo_rectangle(cr, 0, 0, allocation.width, allocation.height);
178
179 cairo_fill(cr);
180
181 #ifdef ENABLE_GRADIENT_LOOK
182 /* Add a very subtle gradient to the bottom of the notification */
183 gradient = cairo_pattern_create_linear(0, gradient_y, 0, allocation.height);
184 cairo_pattern_add_color_stop_rgba(gradient, 0, 0, 0, 0, 0);
185 cairo_pattern_add_color_stop_rgba(gradient, 1, 0, 0, 0, 0.15);
186 cairo_rectangle(cr, 0, gradient_y, allocation.width, BOTTOM_GRADIENT_HEIGHT30);
187
188 cairo_set_source(cr, gradient);
189 cairo_fill(cr);
190 cairo_pattern_destroy(gradient);
191 #endif
192}
193
194static void draw_stripe(CtkWidget* widget, WindowData* windata, cairo_t* cr)
195{
196 CtkStyleContext* context;
197 CdkRGBA bg;
198 int stripe_x;
199 int stripe_y;
200 int stripe_height;
201 #ifdef ENABLE_GRADIENT_LOOK
202 cairo_pattern_t* gradient;
203 double r, g, b;
204 #endif
205
206 context = ctk_widget_get_style_context (widget);
207
208 ctk_style_context_save (context);
209
210 CtkAllocation alloc;
211 ctk_widget_get_allocation(windata->main_hbox, &alloc);
212
213 stripe_x = alloc.x + 1;
214
215 if (ctk_widget_get_direction(widget) == CTK_TEXT_DIR_RTL)
216 {
217 stripe_x = windata->width - STRIPE_WIDTH30 - stripe_x;
218 }
219
220 stripe_y = alloc.y + 1;
221 stripe_height = alloc.height - 2;
222
223 switch (windata->urgency)
224 {
225 case URGENCY_LOW: // LOW
226 ctk_style_context_set_state (context, CTK_STATE_FLAG_NORMAL);
227 ctk_style_context_add_class (context, CTK_STYLE_CLASS_VIEW"view");
228 get_background_color (context, CTK_STATE_FLAG_NORMAL, &bg);
229 cdk_cairo_set_source_rgba (cr, &bg);
230 break;
231
232 case URGENCY_CRITICAL: // CRITICAL
233 cdk_rgba_parse (&bg, "#CC0000");
234 break;
235
236 case URGENCY_NORMAL: // NORMAL
237 default:
238 ctk_style_context_set_state (context, CTK_STATE_FLAG_SELECTED);
239 ctk_style_context_add_class (context, CTK_STYLE_CLASS_VIEW"view");
240 get_background_color (context, CTK_STATE_FLAG_SELECTED, &bg);
241 cdk_cairo_set_source_rgba (cr, &bg);
242 break;
243 }
244
245 ctk_style_context_restore (context);
246
247 cairo_rectangle(cr, stripe_x, stripe_y, STRIPE_WIDTH30, stripe_height);
248
249 #ifdef ENABLE_GRADIENT_LOOK
250 r = color.red / 65535.0;
251 g = color.green / 65535.0;
252 b = color.blue / 65535.0;
253
254 gradient = cairo_pattern_create_linear(stripe_x, 0, STRIPE_WIDTH30, 0);
255 cairo_pattern_add_color_stop_rgba(gradient, 0, r, g, b, 1);
256 cairo_pattern_add_color_stop_rgba(gradient, 1, r, g, b, 0);
257 cairo_set_source(cr, gradient);
258 cairo_fill(cr);
259 cairo_pattern_destroy(gradient);
260 #else
261 cdk_cairo_set_source_rgba (cr, &bg);
262 cairo_fill(cr);
263 #endif
264}
265
266static CtkArrowType get_notification_arrow_type(CtkWidget* nw)
267{
268 WindowData* windata;
269 CdkScreen* screen;
270 CdkRectangle monitor_geometry;
271 CdkDisplay* display;
272 CdkMonitor* monitor;
273
274 windata = g_object_get_data(G_OBJECT(nw)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((nw)), (((GType) ((20) << (2))))))))
, "windata");
275
276 screen = cdk_window_get_screen(CDK_WINDOW( ctk_widget_get_window(nw))((((CdkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((ctk_widget_get_window(nw))), ((cdk_window_get_type ())))
)))
);
277 display = cdk_screen_get_display (screen);
278 monitor = cdk_display_get_monitor_at_point (display, windata->point_x, windata->point_y);
279 cdk_monitor_get_geometry (monitor, &monitor_geometry);
280
281 if (windata->point_y - monitor_geometry.y + windata->height + DEFAULT_ARROW_HEIGHT14 > monitor_geometry.height)
282 {
283 return CTK_ARROW_DOWN;
284 }
285 else
286 {
287 return CTK_ARROW_UP;
288 }
289}
290
291#define ADD_POINT(_x, _y, shapeoffset_x, shapeoffset_y)do { windata->border_points[i].x = (_x); windata->border_points
[i].y = (_y); shape_points[i].x = (_x) + (shapeoffset_x); shape_points
[i].y = (_y) + (shapeoffset_y); i++; } while (0)
\
292 G_STMT_STARTdo { \
293 windata->border_points[i].x = (_x); \
294 windata->border_points[i].y = (_y); \
295 shape_points[i].x = (_x) + (shapeoffset_x); \
296 shape_points[i].y = (_y) + (shapeoffset_y); \
297 i++;\
298 } G_STMT_ENDwhile (0)
299
300static void create_border_with_arrow(CtkWidget* nw, WindowData* windata)
301{
302 int width;
303 int height;
304 int y;
305 int norm_point_x;
306 int norm_point_y;
307 CtkArrowType arrow_type;
308 CdkScreen* screen;
309 int arrow_side1_width = DEFAULT_ARROW_WIDTH28 / 2;
310 int arrow_side2_width = DEFAULT_ARROW_WIDTH28 / 2;
311 int arrow_offset = DEFAULT_ARROW_OFFSET(30 + 2);
312 CdkPoint* shape_points = NULL((void*)0);
313 int i = 0;
314 CdkMonitor* monitor;
315 CdkDisplay* display;
316 CdkRectangle monitor_geometry;
317
318 width = windata->width;
319 height = windata->height;
320
321 screen = cdk_window_get_screen(CDK_WINDOW(ctk_widget_get_window(nw))((((CdkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((ctk_widget_get_window(nw))), ((cdk_window_get_type ())))
)))
);
322 display = cdk_screen_get_display (screen);
323 monitor = cdk_display_get_monitor_at_point (display, windata->point_x, windata->point_y);
324 cdk_monitor_get_geometry (monitor, &monitor_geometry);
325
326 windata->num_border_points = 5;
327
328 arrow_type = get_notification_arrow_type(windata->win);
329
330 norm_point_x = windata->point_x - monitor_geometry.x;
331 norm_point_y = windata->point_y - monitor_geometry.y;
332
333 /* Handle the offset and such */
334 switch (arrow_type)
335 {
336 case CTK_ARROW_UP:
337 case CTK_ARROW_DOWN:
338
339 if (norm_point_x < arrow_side1_width)
340 {
341 arrow_side1_width = 0;
342 arrow_offset = 0;
343 }
344 else if (norm_point_x > monitor_geometry.width - arrow_side2_width)
345 {
346 arrow_side2_width = 0;
347 arrow_offset = width - arrow_side1_width;
348 }
349 else
350 {
351 if (norm_point_x - arrow_side2_width + width >= monitor_geometry.width)
352 {
353 arrow_offset = width - monitor_geometry.width + norm_point_x;
354 }
355 else
356 {
357 arrow_offset = MIN(norm_point_x - arrow_side1_width, DEFAULT_ARROW_OFFSET)(((norm_point_x - arrow_side1_width) < ((30 + 2))) ? (norm_point_x
- arrow_side1_width) : ((30 + 2)))
;
358 }
359
360 if (arrow_offset == 0 || arrow_offset == width - arrow_side1_width)
361 {
362 windata->num_border_points++;
363 }
364 else
365 {
366 windata->num_border_points += 2;
367 }
368 }
369
370 /*
371 * Why risk this for official builds? If it's somehow off the
372 * screen, it won't horribly impact the user. Definitely less
373 * than an assertion would...
374 */
375 #if 0
376 g_assert(arrow_offset + arrow_side1_width >= 0)do { if (arrow_offset + arrow_side1_width >= 0) ; else g_assertion_message_expr
(((gchar*) 0), "theme.c", 376, ((const char*) (__func__)), "arrow_offset + arrow_side1_width >= 0"
); } while (0)
;
377 g_assert(arrow_offset + arrow_side1_width + arrow_side2_width <= width)do { if (arrow_offset + arrow_side1_width + arrow_side2_width
<= width) ; else g_assertion_message_expr (((gchar*) 0), "theme.c"
, 377, ((const char*) (__func__)), "arrow_offset + arrow_side1_width + arrow_side2_width <= width"
); } while (0)
;
378 #endif
379
380 windata->border_points = g_new0(CdkPoint, windata->num_border_points)((CdkPoint *) g_malloc0_n ((windata->num_border_points), sizeof
(CdkPoint)))
;
381 shape_points = g_new0(CdkPoint, windata->num_border_points)((CdkPoint *) g_malloc0_n ((windata->num_border_points), sizeof
(CdkPoint)))
;
382
383 windata->drawn_arrow_begin_x = arrow_offset;
384 windata->drawn_arrow_middle_x = arrow_offset + arrow_side1_width;
385 windata->drawn_arrow_end_x = arrow_offset + arrow_side1_width + arrow_side2_width;
386
387 if (arrow_type == CTK_ARROW_UP)
388 {
389 windata->drawn_arrow_begin_y = DEFAULT_ARROW_HEIGHT14;
390 windata->drawn_arrow_middle_y = 0;
391 windata->drawn_arrow_end_y = DEFAULT_ARROW_HEIGHT14;
392
393 if (arrow_side1_width == 0)
394 {
395 ADD_POINT(0, 0, 0, 0)do { windata->border_points[i].x = (0); windata->border_points
[i].y = (0); shape_points[i].x = (0) + (0); shape_points[i].y
= (0) + (0); i++; } while (0)
;
396 }
397 else
398 {
399 ADD_POINT(0, DEFAULT_ARROW_HEIGHT, 0, 0)do { windata->border_points[i].x = (0); windata->border_points
[i].y = (14); shape_points[i].x = (0) + (0); shape_points[i].
y = (14) + (0); i++; } while (0)
;
400
401 if (arrow_offset > 0)
402 {
403 ADD_POINT(arrow_offset - (arrow_side2_width > 0 ? 0 : 1), DEFAULT_ARROW_HEIGHT, 0, 0)do { windata->border_points[i].x = (arrow_offset - (arrow_side2_width
> 0 ? 0 : 1)); windata->border_points[i].y = (14); shape_points
[i].x = (arrow_offset - (arrow_side2_width > 0 ? 0 : 1)) +
(0); shape_points[i].y = (14) + (0); i++; } while (0)
;
404 }
405
406 ADD_POINT(arrow_offset + arrow_side1_width - (arrow_side2_width > 0 ? 0 : 1), 0, 0, 0)do { windata->border_points[i].x = (arrow_offset + arrow_side1_width
- (arrow_side2_width > 0 ? 0 : 1)); windata->border_points
[i].y = (0); shape_points[i].x = (arrow_offset + arrow_side1_width
- (arrow_side2_width > 0 ? 0 : 1)) + (0); shape_points[i]
.y = (0) + (0); i++; } while (0)
;
407 }
408
409 if (arrow_side2_width > 0)
410 {
411 ADD_POINT(windata->drawn_arrow_end_x, windata->drawn_arrow_end_y, 1, 0)do { windata->border_points[i].x = (windata->drawn_arrow_end_x
); windata->border_points[i].y = (windata->drawn_arrow_end_y
); shape_points[i].x = (windata->drawn_arrow_end_x) + (1);
shape_points[i].y = (windata->drawn_arrow_end_y) + (0); i
++; } while (0)
;
412 ADD_POINT(width - 1, DEFAULT_ARROW_HEIGHT, 1, 0)do { windata->border_points[i].x = (width - 1); windata->
border_points[i].y = (14); shape_points[i].x = (width - 1) + (
1); shape_points[i].y = (14) + (0); i++; } while (0)
;
413 }
414
415 ADD_POINT(width - 1, height - 1, 1, 1)do { windata->border_points[i].x = (width - 1); windata->
border_points[i].y = (height - 1); shape_points[i].x = (width
- 1) + (1); shape_points[i].y = (height - 1) + (1); i++; } while
(0)
;
416 ADD_POINT(0, height - 1, 0, 1)do { windata->border_points[i].x = (0); windata->border_points
[i].y = (height - 1); shape_points[i].x = (0) + (0); shape_points
[i].y = (height - 1) + (1); i++; } while (0)
;
417
418 y = windata->point_y;
419 }
420 else
421 {
422 windata->drawn_arrow_begin_y = height - DEFAULT_ARROW_HEIGHT14;
423 windata->drawn_arrow_middle_y = height;
424 windata->drawn_arrow_end_y = height - DEFAULT_ARROW_HEIGHT14;
425
426 ADD_POINT(0, 0, 0, 0)do { windata->border_points[i].x = (0); windata->border_points
[i].y = (0); shape_points[i].x = (0) + (0); shape_points[i].y
= (0) + (0); i++; } while (0)
;
427 ADD_POINT(width - 1, 0, 1, 0)do { windata->border_points[i].x = (width - 1); windata->
border_points[i].y = (0); shape_points[i].x = (width - 1) + (
1); shape_points[i].y = (0) + (0); i++; } while (0)
;
428
429 if (arrow_side2_width == 0)
430 {
431 ADD_POINT(width - 1, height, (arrow_side1_width > 0 ? 0 : 1), 0)do { windata->border_points[i].x = (width - 1); windata->
border_points[i].y = (height); shape_points[i].x = (width - 1
) + ((arrow_side1_width > 0 ? 0 : 1)); shape_points[i].y =
(height) + (0); i++; } while (0)
;
432 }
433 else
434 {
435 ADD_POINT(width - 1, height - DEFAULT_ARROW_HEIGHT, 1, 1)do { windata->border_points[i].x = (width - 1); windata->
border_points[i].y = (height - 14); shape_points[i].x = (width
- 1) + (1); shape_points[i].y = (height - 14) + (1); i++; } while
(0)
;
436
437 if (arrow_offset < width - arrow_side1_width)
438 {
439 ADD_POINT(arrow_offset + arrow_side1_width + arrow_side2_width, height - DEFAULT_ARROW_HEIGHT, 0, 1)do { windata->border_points[i].x = (arrow_offset + arrow_side1_width
+ arrow_side2_width); windata->border_points[i].y = (height
- 14); shape_points[i].x = (arrow_offset + arrow_side1_width
+ arrow_side2_width) + (0); shape_points[i].y = (height - 14
) + (1); i++; } while (0)
;
440 }
441
442 ADD_POINT(arrow_offset + arrow_side1_width, height, 0, 1)do { windata->border_points[i].x = (arrow_offset + arrow_side1_width
); windata->border_points[i].y = (height); shape_points[i]
.x = (arrow_offset + arrow_side1_width) + (0); shape_points[i
].y = (height) + (1); i++; } while (0)
;
443 }
444
445 if (arrow_side1_width > 0)
446 {
447 ADD_POINT(windata->drawn_arrow_begin_x - (arrow_side2_width > 0 ? 0 : 1), windata->drawn_arrow_begin_y, 0, 0)do { windata->border_points[i].x = (windata->drawn_arrow_begin_x
- (arrow_side2_width > 0 ? 0 : 1)); windata->border_points
[i].y = (windata->drawn_arrow_begin_y); shape_points[i].x =
(windata->drawn_arrow_begin_x - (arrow_side2_width > 0
? 0 : 1)) + (0); shape_points[i].y = (windata->drawn_arrow_begin_y
) + (0); i++; } while (0)
;
448 ADD_POINT(0, height - DEFAULT_ARROW_HEIGHT, 0, 1)do { windata->border_points[i].x = (0); windata->border_points
[i].y = (height - 14); shape_points[i].x = (0) + (0); shape_points
[i].y = (height - 14) + (1); i++; } while (0)
;
449 }
450
451 y = windata->point_y - height;
452 }
453
454 #if 0
455 g_assert(i == windata->num_border_points)do { if (i == windata->num_border_points) ; else g_assertion_message_expr
(((gchar*) 0), "theme.c", 455, ((const char*) (__func__)), "i == windata->num_border_points"
); } while (0)
;
456 g_assert(windata->point_x - arrow_offset - arrow_side1_width >= 0)do { if (windata->point_x - arrow_offset - arrow_side1_width
>= 0) ; else g_assertion_message_expr (((gchar*) 0), "theme.c"
, 456, ((const char*) (__func__)), "windata->point_x - arrow_offset - arrow_side1_width >= 0"
); } while (0)
;
457 #endif
458
459 ctk_window_move(CTK_WINDOW(windata->win)((((CtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((windata->win)), ((ctk_window_get_type ()))))))
, windata->point_x - arrow_offset - arrow_side1_width, y);
460
461 break;
462
463 case CTK_ARROW_LEFT:
464 case CTK_ARROW_RIGHT:
465
466 if (norm_point_y < arrow_side1_width)
467 {
468 arrow_side1_width = 0;
469 arrow_offset = norm_point_y;
470 }
471 else if (norm_point_y > monitor_geometry.height - arrow_side2_width)
472 {
473 arrow_side2_width = 0;
Value stored to 'arrow_side2_width' is never read
474 arrow_offset = norm_point_y - arrow_side1_width;
475 }
476 break;
477
478 default:
479 g_assert_not_reached()do { g_assertion_message_expr (((gchar*) 0), "theme.c", 479, (
(const char*) (__func__)), ((void*)0)); } while (0)
;
480 }
481
482 g_assert(shape_points != NULL)do { if (shape_points != ((void*)0)) ; else g_assertion_message_expr
(((gchar*) 0), "theme.c", 482, ((const char*) (__func__)), "shape_points != NULL"
); } while (0)
;
483
484 /* FIXME won't work with CTK+3, need a replacement */
485 /*windata->window_region = cdk_region_polygon(shape_points, windata->num_border_points, CDK_EVEN_ODD_RULE);*/
486 g_free(shape_points);
487}
488
489static void draw_border(CtkWidget* widget, WindowData *windata, cairo_t* cr)
490{
491 cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 1.0);
492 cairo_set_line_width(cr, 1.0);
493
494 if (windata->has_arrow)
495 {
496 size_t i;
497
498 create_border_with_arrow(windata->win, windata);
499
500 cairo_move_to(cr, windata->border_points[0].x + 0.5, windata->border_points[0].y + 0.5);
501
502 for (i = 1; i < windata->num_border_points; i++)
503 {
504 cairo_line_to(cr, windata->border_points[i].x + 0.5, windata->border_points[i].y + 0.5);
505 }
506
507 cairo_close_path(cr);
508 /* FIXME window_region is not set up anyway, see previous fixme */
509 /*cdk_window_shape_combine_region (ctk_widget_get_window (windata->win), windata->window_region, 0, 0);*/
510 g_free(windata->border_points);
511 windata->border_points = NULL((void*)0);
512 }
513 else
514 {
515 cairo_rectangle(cr, 0.5, 0.5, windata->width - 0.5, windata->height - 0.5);
516 }
517
518 cairo_stroke(cr);
519}
520
521static void
522paint_window (CtkWidget *widget,
523 cairo_t *cr,
524 WindowData *windata)
525{
526 cairo_t* cr2;
527 cairo_surface_t* surface;
528 CtkAllocation allocation;
529
530 ctk_widget_get_allocation(windata->win, &allocation);
531
532 if (windata->width == 0)
533 {
534 windata->width = allocation.width;
535 windata->height = allocation.height;
536 }
537
538 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
539
540 ctk_widget_get_allocation(widget, &allocation);
541
542 surface = cairo_surface_create_similar (cairo_get_target (cr),
543 CAIRO_CONTENT_COLOR_ALPHA,
544 allocation.width,
545 allocation.height);
546
547 cr2 = cairo_create (surface);
548
549 fill_background(widget, windata, cr2);
550 draw_border(widget, windata, cr2);
551 draw_stripe(widget, windata, cr2);
552 cairo_fill (cr2);
553 cairo_destroy (cr2);
554
555 cairo_set_source_surface (cr, surface, 0, 0);
556 cairo_paint(cr);
557 cairo_surface_destroy(surface);
558}
559
560static gboolean
561on_draw (CtkWidget *widget, cairo_t *cr, WindowData *windata)
562{
563 paint_window (widget, cr, windata);
564
565 return FALSE(0);
566}
567
568static void destroy_windata(WindowData* windata)
569{
570 if (windata->window_region != NULL((void*)0))
571 {
572 cairo_region_destroy(windata->window_region);
573 }
574
575 g_free(windata);
576}
577
578static void update_spacers(CtkWidget* nw)
579{
580 WindowData* windata;
581
582 windata = g_object_get_data(G_OBJECT(nw)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((nw)), (((GType) ((20) << (2))))))))
, "windata");
583
584 if (windata->has_arrow)
585 {
586 switch (get_notification_arrow_type(CTK_WIDGET(nw)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((nw)), ((ctk_widget_get_type ()))))))
))
587 {
588 case CTK_ARROW_UP:
589 ctk_widget_show(windata->top_spacer);
590 ctk_widget_hide(windata->bottom_spacer);
591 break;
592
593 case CTK_ARROW_DOWN:
594 ctk_widget_hide(windata->top_spacer);
595 ctk_widget_show(windata->bottom_spacer);
596 break;
597
598 default:
599 g_assert_not_reached()do { g_assertion_message_expr (((gchar*) 0), "theme.c", 599, (
(const char*) (__func__)), ((void*)0)); } while (0)
;
600 }
601 }
602 else
603 {
604 ctk_widget_hide(windata->top_spacer);
605 ctk_widget_hide(windata->bottom_spacer);
606 }
607}
608
609static void update_content_hbox_visibility(WindowData* windata)
610{
611 /*
612 * This is all a hack, but until we have a libview-style ContentBox,
613 * it'll just have to do.
614 */
615 if (ctk_widget_get_visible(windata->icon) || ctk_widget_get_visible(windata->body_label) || ctk_widget_get_visible(windata->actions_box))
616 {
617 ctk_widget_show(windata->content_hbox);
618 }
619 else
620 {
621 ctk_widget_hide(windata->content_hbox);
622 }
623}
624
625static gboolean configure_event_cb(CtkWidget* nw, CdkEventConfigure* event, WindowData* windata)
626{
627 windata->width = event->width;
628 windata->height = event->height;
629
630 update_spacers(nw);
631 ctk_widget_queue_draw(nw);
632
633 return FALSE(0);
634}
635
636static gboolean activate_link(CtkLabel* label, const char* url, WindowData* windata)
637{
638 windata->url_clicked(CTK_WINDOW(windata->win)((((CtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((windata->win)), ((ctk_window_get_type ()))))))
, url);
639
640 return TRUE(!(0));
641}
642
643CtkWindow* create_notification(UrlClickedCb url_clicked)
644{
645 CtkWidget* spacer;
646 CtkWidget* win;
647 CtkWidget* main_vbox;
648 CtkWidget* hbox;
649 CtkWidget* vbox;
650 CtkWidget* close_button;
651 CtkWidget* image;
652 AtkObject* atkobj;
653 WindowData* windata;
654
655 CdkVisual *visual;
656 CdkScreen* screen;
657
658 windata = g_new0(WindowData, 1)((WindowData *) g_malloc0_n ((1), sizeof (WindowData)));
659 windata->urgency = URGENCY_NORMAL;
660 windata->url_clicked = url_clicked;
661
662 win = ctk_window_new(CTK_WINDOW_POPUP);
663 ctk_window_set_resizable(CTK_WINDOW(win)((((CtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((win)), ((ctk_window_get_type ()))))))
, FALSE(0));
664 windata->win = win;
665
666 windata->composited = FALSE(0);
667
668
669 screen = ctk_window_get_screen(CTK_WINDOW(win)((((CtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((win)), ((ctk_window_get_type ()))))))
);
670
671 visual = cdk_screen_get_rgba_visual(screen);
672
673 if (visual != NULL((void*)0))
674 {
675 ctk_widget_set_visual(win, visual);
676
677 if (cdk_screen_is_composited(screen))
678 {
679 windata->composited = TRUE(!(0));
680 }
681 }
682
683 ctk_window_set_title(CTK_WINDOW(win)((((CtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((win)), ((ctk_window_get_type ()))))))
, "Notification");
684 ctk_window_set_type_hint(CTK_WINDOW(win)((((CtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((win)), ((ctk_window_get_type ()))))))
, CDK_WINDOW_TYPE_HINT_NOTIFICATION);
685 ctk_widget_add_events(win, CDK_BUTTON_PRESS_MASK | CDK_BUTTON_RELEASE_MASK);
686 ctk_widget_realize(win);
687 ctk_widget_set_size_request(win, WIDTH400, -1);
688
689 g_object_set_data_full(G_OBJECT(win)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((win)), (((GType) ((20) << (2))))))))
, "windata", windata, (GDestroyNotify) destroy_windata);
690 atk_object_set_role(ctk_widget_get_accessible(win), ATK_ROLE_ALERT);
691
692 g_signal_connect(G_OBJECT(win), "configure_event", G_CALLBACK(configure_event_cb), windata)g_signal_connect_data ((((((GObject*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((win)), (((GType) ((20) << (2))))))
))), ("configure_event"), (((GCallback) (configure_event_cb))
), (windata), ((void*)0), (GConnectFlags) 0)
;
693
694 main_vbox = ctk_box_new(CTK_ORIENTATION_VERTICAL, 0);
695 ctk_widget_show(main_vbox);
696 ctk_container_add (CTK_CONTAINER (win)((((CtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((win)), ((ctk_container_get_type ()))))))
, main_vbox);
697 ctk_container_set_border_width(CTK_CONTAINER(main_vbox)((((CtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((main_vbox)), ((ctk_container_get_type ()))))))
, 1);
698
699 g_signal_connect (G_OBJECT (main_vbox), "draw", G_CALLBACK (on_draw), windata)g_signal_connect_data ((((((GObject*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((main_vbox)), (((GType) ((20) << (2
))))))))), ("draw"), (((GCallback) (on_draw))), (windata), ((
void*)0), (GConnectFlags) 0)
;
700
701 windata->top_spacer = ctk_image_new();
702 ctk_box_pack_start(CTK_BOX(main_vbox)((((CtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((main_vbox)), ((ctk_box_get_type ()))))))
, windata->top_spacer, FALSE(0), FALSE(0), 0);
703 ctk_widget_set_size_request(windata->top_spacer, -1, DEFAULT_ARROW_HEIGHT14);
704
705 windata->main_hbox = ctk_box_new(CTK_ORIENTATION_HORIZONTAL, 0);
706 ctk_widget_show(windata->main_hbox);
707 ctk_box_pack_start(CTK_BOX(main_vbox)((((CtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((main_vbox)), ((ctk_box_get_type ()))))))
, windata->main_hbox, FALSE(0), FALSE(0), 0);
708
709 windata->bottom_spacer = ctk_image_new();
710 ctk_box_pack_start(CTK_BOX(main_vbox)((((CtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((main_vbox)), ((ctk_box_get_type ()))))))
, windata->bottom_spacer, FALSE(0), FALSE(0), 0);
711 ctk_widget_set_size_request(windata->bottom_spacer, -1, DEFAULT_ARROW_HEIGHT14);
712
713 vbox = ctk_box_new(CTK_ORIENTATION_VERTICAL, 6);
714 ctk_widget_show(vbox);
715 ctk_box_pack_start(CTK_BOX(windata->main_hbox)((((CtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((windata->main_hbox)), ((ctk_box_get_type ()))))))
, vbox, TRUE(!(0)), TRUE(!(0)), 0);
716 ctk_container_set_border_width(CTK_CONTAINER(vbox)((((CtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((vbox)), ((ctk_container_get_type ()))))))
, 10);
717
718 hbox = ctk_box_new(CTK_ORIENTATION_HORIZONTAL, 6);
719 ctk_widget_show(hbox);
720 ctk_box_pack_start(CTK_BOX(vbox)((((CtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((vbox)), ((ctk_box_get_type ()))))))
, hbox, FALSE(0), FALSE(0), 0);
721
722 spacer = ctk_image_new();
723 ctk_widget_show(spacer);
724 ctk_box_pack_start(CTK_BOX(hbox)((((CtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((hbox)), ((ctk_box_get_type ()))))))
, spacer, FALSE(0), FALSE(0), 0);
725 ctk_widget_set_size_request(spacer, SPACER_LEFT30, -1);
726
727 windata->summary_label = ctk_label_new(NULL((void*)0));
728 ctk_widget_show(windata->summary_label);
729 ctk_box_pack_start(CTK_BOX(hbox)((((CtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((hbox)), ((ctk_box_get_type ()))))))
, windata->summary_label, TRUE(!(0)), TRUE(!(0)), 0);
730 ctk_label_set_xalign (CTK_LABEL (windata->summary_label)((((CtkLabel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((windata->summary_label)), ((ctk_label_get_type ()))))
))
, 0.0);
731 ctk_label_set_yalign (CTK_LABEL (windata->summary_label)((((CtkLabel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((windata->summary_label)), ((ctk_label_get_type ()))))
))
, 0.0);
732 ctk_label_set_line_wrap(CTK_LABEL(windata->summary_label)((((CtkLabel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((windata->summary_label)), ((ctk_label_get_type ()))))
))
, TRUE(!(0)));
733 ctk_label_set_line_wrap_mode (CTK_LABEL (windata->summary_label)((((CtkLabel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((windata->summary_label)), ((ctk_label_get_type ()))))
))
, PANGO_WRAP_WORD_CHAR);
734
735 atkobj = ctk_widget_get_accessible(windata->summary_label);
736 atk_object_set_description (atkobj, _("Notification summary text.")gettext ("Notification summary text."));
737
738 /* Add the close button */
739 close_button = ctk_button_new();
740 windata->close_button = close_button;
741 ctk_widget_set_halign (close_button, CTK_ALIGN_END);
742 ctk_widget_set_valign (close_button, CTK_ALIGN_START);
743 ctk_widget_show(close_button);
744 ctk_box_pack_start(CTK_BOX(hbox)((((CtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((hbox)), ((ctk_box_get_type ()))))))
, close_button, FALSE(0), FALSE(0), 0);
745 ctk_button_set_relief(CTK_BUTTON(close_button)((((CtkButton*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((close_button)), ((ctk_button_get_type ()))))))
, CTK_RELIEF_NONE);
746 ctk_container_set_border_width(CTK_CONTAINER(close_button)((((CtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((close_button)), ((ctk_container_get_type ()))))))
, 0);
747 //ctk_widget_set_size_request(close_button, 20, 20);
748 g_signal_connect_swapped(G_OBJECT(close_button), "clicked", G_CALLBACK(ctk_widget_destroy), win)g_signal_connect_data ((((((GObject*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((close_button)), (((GType) ((20) <<
(2))))))))), ("clicked"), (((GCallback) (ctk_widget_destroy)
)), (win), ((void*)0), G_CONNECT_SWAPPED)
;
749
750 atkobj = ctk_widget_get_accessible(close_button);
751 atk_action_set_description(ATK_ACTION(atkobj)(((AtkAction*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((atkobj)), ((atk_action_get_type ())))))
, 0,
752 _("Closes the notification.")gettext ("Closes the notification."));
753 atk_object_set_name(atkobj, "");
754 atk_object_set_description (atkobj, _("Closes the notification.")gettext ("Closes the notification."));
755
756 image = ctk_image_new_from_icon_name ("window-close", CTK_ICON_SIZE_MENU);
757 ctk_widget_show(image);
758 ctk_container_add(CTK_CONTAINER(close_button)((((CtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((close_button)), ((ctk_container_get_type ()))))))
, image);
759
760 windata->content_hbox = ctk_box_new(CTK_ORIENTATION_HORIZONTAL, 6);
761 ctk_box_pack_start(CTK_BOX(vbox)((((CtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((vbox)), ((ctk_box_get_type ()))))))
, windata->content_hbox, FALSE(0), FALSE(0), 0);
762
763 windata->iconbox = ctk_box_new(CTK_ORIENTATION_HORIZONTAL, 0);
764 ctk_widget_show(windata->iconbox);
765 ctk_box_pack_start(CTK_BOX(windata->content_hbox)((((CtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((windata->content_hbox)), ((ctk_box_get_type ()))))))
, windata->iconbox, FALSE(0), FALSE(0), 0);
766 ctk_widget_set_size_request(windata->iconbox, BODY_X_OFFSET(32 + 8), -1);
767
768 windata->icon = ctk_image_new();
769 ctk_box_pack_start(CTK_BOX(windata->iconbox)((((CtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((windata->iconbox)), ((ctk_box_get_type ()))))))
, windata->icon, TRUE(!(0)), TRUE(!(0)), 0);
770 ctk_widget_set_halign (windata->icon, CTK_ALIGN_CENTER);
771 ctk_widget_set_valign (windata->icon, CTK_ALIGN_START);
772
773 vbox = ctk_box_new(CTK_ORIENTATION_VERTICAL, 6);
774 ctk_widget_show(vbox);
775 ctk_box_pack_start(CTK_BOX(windata->content_hbox)((((CtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((windata->content_hbox)), ((ctk_box_get_type ()))))))
, vbox, TRUE(!(0)), TRUE(!(0)), 0);
776
777 windata->body_label = ctk_label_new(NULL((void*)0));
778 ctk_widget_show(windata->body_label);
779 ctk_box_pack_start(CTK_BOX(vbox)((((CtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((vbox)), ((ctk_box_get_type ()))))))
, windata->body_label, TRUE(!(0)), TRUE(!(0)), 0);
780 ctk_label_set_xalign (CTK_LABEL (windata->body_label)((((CtkLabel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((windata->body_label)), ((ctk_label_get_type ()))))))
, 0.0);
781 ctk_label_set_yalign (CTK_LABEL (windata->body_label)((((CtkLabel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((windata->body_label)), ((ctk_label_get_type ()))))))
, 0.0);
782 ctk_label_set_line_wrap(CTK_LABEL(windata->body_label)((((CtkLabel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((windata->body_label)), ((ctk_label_get_type ()))))))
, TRUE(!(0)));
783 ctk_label_set_line_wrap_mode (CTK_LABEL (windata->body_label)((((CtkLabel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((windata->body_label)), ((ctk_label_get_type ()))))))
, PANGO_WRAP_WORD_CHAR);
784 ctk_label_set_max_width_chars (CTK_LABEL (windata->body_label)((((CtkLabel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((windata->body_label)), ((ctk_label_get_type ()))))))
, 50);
785 g_signal_connect(G_OBJECT(windata->body_label), "activate-link", G_CALLBACK(activate_link), windata)g_signal_connect_data ((((((GObject*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((windata->body_label)), (((GType) ((20
) << (2))))))))), ("activate-link"), (((GCallback) (activate_link
))), (windata), ((void*)0), (GConnectFlags) 0)
;
786
787 atkobj = ctk_widget_get_accessible(windata->body_label);
788 atk_object_set_description (atkobj, _("Notification body text.")gettext ("Notification body text."));
789
790 windata->actions_box = ctk_box_new(CTK_ORIENTATION_HORIZONTAL, 6);
791 ctk_widget_set_halign (windata->actions_box, CTK_ALIGN_END);
792 ctk_widget_show(windata->actions_box);
793 ctk_box_pack_start(CTK_BOX(vbox)((((CtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((vbox)), ((ctk_box_get_type ()))))))
, windata->actions_box, FALSE(0), TRUE(!(0)), 0);
794
795 return CTK_WINDOW(win)((((CtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((win)), ((ctk_window_get_type ()))))))
;
796}
797
798void set_notification_hints(CtkWindow *nw, GVariant *hints)
799{
800 WindowData *windata = g_object_get_data(G_OBJECT(nw)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((nw)), (((GType) ((20) << (2))))))))
, "windata");
801 guint8 urgency;
802 gboolean action_icons;
803
804 g_assert(windata != NULL)do { if (windata != ((void*)0)) ; else g_assertion_message_expr
(((gchar*) 0), "theme.c", 804, ((const char*) (__func__)), "windata != NULL"
); } while (0)
;
805
806 if (g_variant_lookup(hints, "urgency", "y", &urgency))
807 {
808 windata->urgency = urgency;
809
810 if (windata->urgency == URGENCY_CRITICAL) {
811 ctk_window_set_title(CTK_WINDOW(nw)((((CtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((nw)), ((ctk_window_get_type ()))))))
, "Critical Notification");
812 } else {
813 ctk_window_set_title(CTK_WINDOW(nw)((((CtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((nw)), ((ctk_window_get_type ()))))))
, "Notification");
814 }
815 }
816
817 /* Determine if action-icons have been requested */
818 if (g_variant_lookup(hints, "action-icons", "b", &action_icons))
819 {
820 windata->action_icons = action_icons;
821 }
822}
823
824void set_notification_timeout(CtkWindow* nw, glong timeout)
825{
826 WindowData* windata = g_object_get_data(G_OBJECT(nw)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((nw)), (((GType) ((20) << (2))))))))
, "windata");
827
828 g_assert(windata != NULL)do { if (windata != ((void*)0)) ; else g_assertion_message_expr
(((gchar*) 0), "theme.c", 828, ((const char*) (__func__)), "windata != NULL"
); } while (0)
;
829
830 windata->timeout = timeout;
831}
832
833void notification_tick(CtkWindow* nw, glong remaining)
834{
835 WindowData* windata = g_object_get_data(G_OBJECT(nw)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((nw)), (((GType) ((20) << (2))))))))
, "windata");
836
837 windata->remaining = remaining;
838
839 if (windata->pie_countdown != NULL((void*)0))
840 {
841 ctk_widget_queue_draw_area(windata->pie_countdown, 0, 0, PIE_WIDTH(2 * 12), PIE_HEIGHT(2 * 12));
842 }
843}
844
845void set_notification_text(CtkWindow* nw, const char* summary, const char* body)
846{
847 char* str;
848 char* quoted;
849 CtkRequisition req;
850 WindowData* windata;
851
852 windata = g_object_get_data(G_OBJECT(nw)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((nw)), (((GType) ((20) << (2))))))))
, "windata");
853 g_assert(windata != NULL)do { if (windata != ((void*)0)) ; else g_assertion_message_expr
(((gchar*) 0), "theme.c", 853, ((const char*) (__func__)), "windata != NULL"
); } while (0)
;
854
855 quoted = g_markup_escape_text(summary, -1);
856 str = g_strdup_printf("<b><big>%s</big></b>", quoted);
857 g_free(quoted);
858
859 ctk_label_set_markup(CTK_LABEL(windata->summary_label)((((CtkLabel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((windata->summary_label)), ((ctk_label_get_type ()))))
))
, str);
860 g_free(str);
861
862 /* body */
863 xmlDocPtr doc;
864 xmlInitParser();
865 str = g_strconcat ("<markup>", body, "</markup>", NULL((void*)0));
866 /* parse notification body */
867 doc = xmlReadMemory(str, strlen (str), "noname.xml", NULL((void*)0), 0);
868 g_free (str);
869 if (doc != NULL((void*)0)) {
870 xmlXPathContextPtr xpathCtx;
871 xmlXPathObjectPtr xpathObj;
872 xmlNodeSetPtr nodes;
873 const char *body_label_text;
874 int i, size;
875
876 /* filterout img nodes */
877 xpathCtx = xmlXPathNewContext(doc);
878 xpathObj = xmlXPathEvalExpression((unsigned char *)"//img", xpathCtx);
879 nodes = xpathObj->nodesetval;
880 size = (nodes) ? nodes->nodeNr : 0;
881 for(i = size - 1; i >= 0; i--) {
882 xmlUnlinkNode (nodes->nodeTab[i]);
883 xmlFreeNode (nodes->nodeTab[i]);
884 }
885
886 /* write doc to string */
887 xmlBufferPtr buf = xmlBufferCreate();
888 (void) xmlNodeDump(buf, doc, xmlDocGetRootElement (doc), 0, 0);
889 str = (char *)buf->content;
890 ctk_label_set_markup (CTK_LABEL (windata->body_label)((((CtkLabel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((windata->body_label)), ((ctk_label_get_type ()))))))
, str);
891
892 /* cleanup */
893 xmlBufferFree (buf);
894 xmlXPathFreeObject (xpathObj);
895 xmlXPathFreeContext (xpathCtx);
896 xmlFreeDoc (doc);
897
898 /* Does it render properly? */
899 body_label_text = ctk_label_get_text (CTK_LABEL (windata->body_label)((((CtkLabel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((windata->body_label)), ((ctk_label_get_type ()))))))
);
900 if ((body_label_text == NULL((void*)0)) || (strlen (body_label_text) == 0)) {
901 goto render_fail;
902 }
903 goto renrer_ok;
904 }
905
906render_fail:
907 /* could not parse notification body */
908 quoted = g_markup_escape_text(body, -1);
909 ctk_label_set_markup (CTK_LABEL (windata->body_label)((((CtkLabel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((windata->body_label)), ((ctk_label_get_type ()))))))
, quoted);
910 g_free (quoted);
911
912renrer_ok:
913 xmlCleanupParser ();
914
915 if (body == NULL((void*)0) || *body == '\0')
916 ctk_widget_hide(windata->body_label);
917 else
918 ctk_widget_show(windata->body_label);
919
920 update_content_hbox_visibility(windata);
921
922 if (body != NULL((void*)0) && *body != '\0')
923 {
924 ctk_widget_get_preferred_size (windata->iconbox, NULL((void*)0), &req);
925 /* -1: border width for
926 * -6: spacing for hbox */
927 ctk_widget_set_size_request(windata->body_label, WIDTH400 - (1 * 2) - (10 * 2) - req.width - 6, -1);
928 }
929
930 ctk_widget_get_preferred_size (windata->close_button, NULL((void*)0), &req);
931 /* -1: main_vbox border width
932 * -10: vbox border width
933 * -6: spacing for hbox */
934 ctk_widget_set_size_request(windata->summary_label, WIDTH400 - (1 * 2) - (10 * 2) - SPACER_LEFT30 - req.width - (6 * 2), -1);
935}
936
937void set_notification_icon(CtkWindow* nw, GdkPixbuf* pixbuf)
938{
939 WindowData* windata = g_object_get_data(G_OBJECT(nw)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((nw)), (((GType) ((20) << (2))))))))
, "windata");
940
941 g_assert(windata != NULL)do { if (windata != ((void*)0)) ; else g_assertion_message_expr
(((gchar*) 0), "theme.c", 941, ((const char*) (__func__)), "windata != NULL"
); } while (0)
;
942
943 ctk_image_set_from_pixbuf(CTK_IMAGE(windata->icon)((((CtkImage*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((windata->icon)), ((ctk_image_get_type ()))))))
, pixbuf);
944
945 if (pixbuf != NULL((void*)0))
946 {
947 int pixbuf_width = gdk_pixbuf_get_width(pixbuf);
948
949 ctk_widget_show(windata->icon);
950 ctk_widget_set_size_request(windata->iconbox, MAX(BODY_X_OFFSET, pixbuf_width)((((32 + 8)) > (pixbuf_width)) ? ((32 + 8)) : (pixbuf_width
))
, -1);
951 }
952 else
953 {
954 ctk_widget_hide(windata->icon);
955 ctk_widget_set_size_request(windata->iconbox, BODY_X_OFFSET(32 + 8), -1);
956 }
957
958 update_content_hbox_visibility(windata);
959}
960
961void set_notification_arrow(CtkWidget* nw, gboolean visible, int x, int y)
962{
963 WindowData* windata = g_object_get_data(G_OBJECT(nw)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((nw)), (((GType) ((20) << (2))))))))
, "windata");
964
965 g_assert(windata != NULL)do { if (windata != ((void*)0)) ; else g_assertion_message_expr
(((gchar*) 0), "theme.c", 965, ((const char*) (__func__)), "windata != NULL"
); } while (0)
;
966
967 windata->has_arrow = visible;
968 windata->point_x = x;
969 windata->point_y = y;
970
971 update_spacers(nw);
972}
973
974static void
975paint_countdown (CtkWidget *pie,
976 cairo_t *cr,
977 WindowData *windata)
978{
979 CtkStyleContext *context;
980 CdkRGBA bg;
981 CtkAllocation alloc;
982 cairo_t* cr2;
983 cairo_surface_t* surface;
984
985 context = ctk_widget_get_style_context (windata->win);
986
987 ctk_style_context_save (context);
988 ctk_style_context_set_state (context, CTK_STATE_FLAG_SELECTED);
989
990 get_background_color (context, CTK_STATE_FLAG_SELECTED, &bg);
991
992 ctk_style_context_restore (context);
993
994 ctk_widget_get_allocation(pie, &alloc);
995 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
996 surface = cairo_surface_create_similar (cairo_get_target(cr),
997 CAIRO_CONTENT_COLOR_ALPHA,
998 alloc.width,
999 alloc.height);
1000
1001 cr2 = cairo_create (surface);
1002
1003 fill_background (pie, windata, cr2);
1004
1005 if (windata->timeout > 0)
1006 {
1007 gdouble pct = (gdouble) windata->remaining / (gdouble) windata->timeout;
1008
1009 cdk_cairo_set_source_rgba (cr2, &bg);
1010
1011 cairo_move_to (cr2, PIE_RADIUS12, PIE_RADIUS12);
1012 cairo_arc_negative (cr2, PIE_RADIUS12, PIE_RADIUS12, PIE_RADIUS12, -G_PI_21.5707963267948966192313216916397514420985846996876, -(pct * G_PI3.1415926535897932384626433832795028841971693993751 * 2) - G_PI_21.5707963267948966192313216916397514420985846996876);
1013 cairo_line_to (cr2, PIE_RADIUS12, PIE_RADIUS12);
1014 cairo_fill (cr2);
1015 }
1016
1017 cairo_destroy(cr2);
1018
1019 cairo_save (cr);
1020 cairo_set_source_surface (cr, surface, 0, 0);
1021 cairo_paint (cr);
1022 cairo_restore (cr);
1023
1024 cairo_surface_destroy(surface);
1025}
1026
1027static gboolean
1028on_countdown_draw (CtkWidget *widget, cairo_t *cr, WindowData *windata)
1029{
1030 paint_countdown (widget, cr, windata);
1031
1032 return FALSE(0);
1033}
1034
1035static void action_clicked_cb(CtkWidget* w, CdkEventButton* event, ActionInvokedCb action_cb)
1036{
1037 CtkWindow* nw;
1038 const char* key;
1039 nw = g_object_get_data(G_OBJECT(w)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((w)), (((GType) ((20) << (2))))))))
, "_nw");
1040 key = g_object_get_data(G_OBJECT(w)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((w)), (((GType) ((20) << (2))))))))
, "_action_key");
1041 action_cb(nw, key);
1042}
1043
1044void add_notification_action(CtkWindow* nw, const char* text, const char* key, ActionInvokedCb cb)
1045{
1046 WindowData* windata;
1047 CtkWidget* label;
1048 CtkWidget* button;
1049 CtkWidget* hbox;
1050 GdkPixbuf* pixbuf;
1051 char* buf;
1052
1053 windata = g_object_get_data(G_OBJECT(nw)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((nw)), (((GType) ((20) << (2))))))))
, "windata");
1054
1055 g_assert(windata != NULL)do { if (windata != ((void*)0)) ; else g_assertion_message_expr
(((gchar*) 0), "theme.c", 1055, ((const char*) (__func__)), "windata != NULL"
); } while (0)
;
1056
1057 if (ctk_widget_get_visible(windata->actions_box))
1058 {
1059 ctk_widget_show(windata->actions_box);
1060 update_content_hbox_visibility(windata);
1061
1062 /* Don't try to re-add a pie_countdown */
1063 if (!windata->pie_countdown) {
1064 windata->pie_countdown = ctk_drawing_area_new();
1065 ctk_widget_set_halign (windata->pie_countdown, CTK_ALIGN_END);
1066 ctk_widget_show(windata->pie_countdown);
1067
1068 ctk_box_pack_end (CTK_BOX (windata->actions_box)((((CtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((windata->actions_box)), ((ctk_box_get_type ()))))))
, windata->pie_countdown, FALSE(0), TRUE(!(0)), 0);
1069 ctk_widget_set_size_request(windata->pie_countdown,
1070 PIE_WIDTH(2 * 12), PIE_HEIGHT(2 * 12));
1071 g_signal_connect(G_OBJECT(windata->pie_countdown), "draw",g_signal_connect_data ((((((GObject*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((windata->pie_countdown)), (((GType) (
(20) << (2))))))))), ("draw"), (((GCallback) (on_countdown_draw
))), (windata), ((void*)0), (GConnectFlags) 0)
1072 G_CALLBACK(on_countdown_draw), windata)g_signal_connect_data ((((((GObject*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((windata->pie_countdown)), (((GType) (
(20) << (2))))))))), ("draw"), (((GCallback) (on_countdown_draw
))), (windata), ((void*)0), (GConnectFlags) 0)
;
1073 }
1074 }
1075
1076 if (windata->action_icons) {
1077 button = ctk_button_new_from_icon_name(key, CTK_ICON_SIZE_BUTTON);
1078 goto add_button;
1079 }
1080
1081 button = ctk_button_new();
1082 hbox = ctk_box_new(CTK_ORIENTATION_HORIZONTAL, 6);
1083 ctk_widget_show(hbox);
1084 ctk_container_add(CTK_CONTAINER(button)((((CtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((button)), ((ctk_container_get_type ()))))))
, hbox);
1085
1086 /* Try to be smart and find a suitable icon. */
1087 buf = g_strdup_printf("stock_%s", key);
1088 pixbuf = ctk_icon_theme_load_icon(ctk_icon_theme_get_for_screen(cdk_window_get_screen(ctk_widget_get_window(CTK_WIDGET(nw)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((nw)), ((ctk_widget_get_type ()))))))
))),
1089 buf, 16, CTK_ICON_LOOKUP_USE_BUILTIN, NULL((void*)0));
1090 g_free(buf);
1091
1092 if (pixbuf != NULL((void*)0))
1093 {
1094 CtkWidget* image = ctk_image_new_from_pixbuf(pixbuf);
1095 ctk_widget_show(image);
1096 ctk_box_pack_start(CTK_BOX(hbox)((((CtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((hbox)), ((ctk_box_get_type ()))))))
, image, FALSE(0), FALSE(0), 0);
1097 ctk_widget_set_halign (image, CTK_ALIGN_CENTER);
1098 ctk_widget_set_valign (image, CTK_ALIGN_CENTER);
1099 }
1100
1101 label = ctk_label_new(NULL((void*)0));
1102 ctk_widget_show(label);
1103 ctk_box_pack_start(CTK_BOX(hbox)((((CtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((hbox)), ((ctk_box_get_type ()))))))
, label, FALSE(0), FALSE(0), 0);
1104 ctk_label_set_xalign (CTK_LABEL (label)((((CtkLabel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((label)), ((ctk_label_get_type ()))))))
, 0.0);
1105 ctk_label_set_yalign (CTK_LABEL (label)((((CtkLabel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((label)), ((ctk_label_get_type ()))))))
, 0.5);
1106 buf = g_strdup_printf("<small>%s</small>", text);
1107 ctk_label_set_markup(CTK_LABEL(label)((((CtkLabel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((label)), ((ctk_label_get_type ()))))))
, buf);
1108 g_free(buf);
1109
1110add_button:
1111 ctk_widget_show(button);
1112 ctk_box_pack_start(CTK_BOX(windata->actions_box)((((CtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((windata->actions_box)), ((ctk_box_get_type ()))))))
, button, FALSE(0), FALSE(0), 0);
1113
1114 g_object_set_data(G_OBJECT(button)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((button)), (((GType) ((20) << (2))))))))
, "_nw", nw);
1115 g_object_set_data_full(G_OBJECT(button)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((button)), (((GType) ((20) << (2))))))))
, "_action_key", g_strdup(key)g_strdup_inline (key), g_free);
1116 g_signal_connect(G_OBJECT(button), "button-release-event", G_CALLBACK(action_clicked_cb), cb)g_signal_connect_data ((((((GObject*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((button)), (((GType) ((20) << (2)))
)))))), ("button-release-event"), (((GCallback) (action_clicked_cb
))), (cb), ((void*)0), (GConnectFlags) 0)
;
1117
1118 ctk_widget_show_all(windata->actions_box);
1119}
1120
1121void clear_notification_actions(CtkWindow* nw)
1122{
1123 WindowData* windata = g_object_get_data(G_OBJECT(nw)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((nw)), (((GType) ((20) << (2))))))))
, "windata");
1124
1125 windata->pie_countdown = NULL((void*)0);
1126
1127 ctk_widget_hide(windata->actions_box);
1128 ctk_container_foreach(CTK_CONTAINER(windata->actions_box)((((CtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((windata->actions_box)), ((ctk_container_get_type ()))
))))
, (CtkCallback) ctk_widget_destroy, NULL((void*)0));
1129}
1130
1131void move_notification(CtkWidget* nw, int x, int y)
1132{
1133 WindowData* windata = g_object_get_data(G_OBJECT(nw)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((nw)), (((GType) ((20) << (2))))))))
, "windata");
1134
1135 g_assert(windata != NULL)do { if (windata != ((void*)0)) ; else g_assertion_message_expr
(((gchar*) 0), "theme.c", 1135, ((const char*) (__func__)), "windata != NULL"
); } while (0)
;
1136
1137 if (windata->has_arrow)
1138 {
1139 ctk_widget_queue_resize(nw);
1140 }
1141 else
1142 {
1143 ctk_window_move(CTK_WINDOW(nw)((((CtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((nw)), ((ctk_window_get_type ()))))))
, x, y);
1144 }
1145}
1146
1147void get_theme_info(char** theme_name, char** theme_ver, char** author, char** homepage)
1148{
1149 *theme_name = g_strdup("Standard")g_strdup_inline ("Standard");
1150
1151 /* If they are constants, maybe we can remove printf and use G_STRINGIFY() */
1152 *theme_ver = g_strdup_printf("%d.%d.%d", NOTIFICATION_DAEMON_MAJOR_VERSION1, NOTIFICATION_DAEMON_MINOR_VERSION3, NOTIFICATION_DAEMON_MICRO_VERSION0);
1153 *author = g_strdup("Christian Hammond")g_strdup_inline ("Christian Hammond");
1154 *homepage = g_strdup("http://www.galago-project.org/")g_strdup_inline ("http://www.galago-project.org/");
1155}
1156
1157gboolean theme_check_init(unsigned int major_ver, unsigned int minor_ver, unsigned int micro_ver)
1158{
1159 return major_ver == NOTIFICATION_DAEMON_MAJOR_VERSION1 && minor_ver == NOTIFICATION_DAEMON_MINOR_VERSION3 && micro_ver == NOTIFICATION_DAEMON_MICRO_VERSION0;
1160}