1 /*******************************************************************************
2 **3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789
3 ** 10 20 30 40 50 60 70 80
4 **
5 ** notify-osd
6 **
7 ** util.c - all sorts of helper functions
8 **
9 ** Copyright 2009 Canonical Ltd.
10 **
11 ** Authors:
12 ** Cody Russell <cody.russell@canonical.com>
13 ** Mirco "MacSlow" Mueller <mirco.mueller@canonical.com>
14 **
15 ** This program is free software: you can redistribute it and/or modify it
16 ** under the terms of the GNU General Public License version 3, as published
17 ** by the Free Software Foundation.
18 **
19 ** This program is distributed in the hope that it will be useful, but
20 ** WITHOUT ANY WARRANTY; without even the implied warranties of
21 ** MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
22 ** PURPOSE. See the GNU General Public License for more details.
23 **
24 ** You should have received a copy of the GNU General Public License along
25 ** with this program. If not, see <http://www.gnu.org/licenses/>.
26 **
27 *******************************************************************************/
28
29 #include <string.h>
30 #include <glib.h>
31 #include <gtk/gtk.h>
32 #include <gdk/gdkx.h>
33 #include <pango/pango.h>
34 #include <cairo.h>
35
36 #define CHARACTER_LT_REGEX "&(lt;|#60;|#x3c;)"
37 #define CHARACTER_GT_REGEX "&(gt;|#62;|#x3e;)"
38 #define CHARACTER_AMP_REGEX "&(amp;|#38;|#x26;)"
39 #define CHARACTER_APOS_REGEX "'"
40 #define CHARACTER_QUOT_REGEX """
41 #define CHARACTER_NEWLINE_REGEX " *((<br[^/>]*/?>|\r|\n)+ *)+"
42
43 #define TAG_MATCH_REGEX "<(b|i|u|big|a|img|span|s|sub|small|tt|html|qt)\\b[^>]*>(.*?)</\\1>|<(img|span|a)[^>]/>|<(img)[^>]*>"
44 #define TAG_REPLACE_REGEX "<(b|i|u|big|a|img|span|s|sub|small|tt|html|qt)\\b[^>]*>|</(b|i|u|big|a|img|span|s|sub|small|tt|html|qt)>"
45
46 struct _ReplaceMarkupData
47 {
48 gchar* regex;
49 gchar* replacement;
50 };
51
52 typedef struct _ReplaceMarkupData ReplaceMarkupData;
53
54 static gchar*
strip_html(const gchar * text,const gchar * match_regex,const gchar * replace_regex)55 strip_html (const gchar *text, const gchar *match_regex, const gchar* replace_regex)
56 {
57 GRegex *regex;
58 gchar *ret;
59 gboolean match = FALSE;
60 GMatchInfo *info = NULL;
61
62 regex = g_regex_new (match_regex, G_REGEX_DOTALL | G_REGEX_OPTIMIZE, 0, NULL);
63 match = g_regex_match (regex, text, 0, &info);
64 g_regex_unref (regex);
65
66 if (match) {
67 regex = g_regex_new (replace_regex, G_REGEX_DOTALL | G_REGEX_OPTIMIZE, 0, NULL);
68 ret = g_regex_replace (regex, text, -1, 0, "", 0, NULL);
69 g_regex_unref (regex);
70 } else {
71 ret = g_strdup (text);
72 }
73
74 if (info)
75 g_match_info_free (info);
76
77 return ret;
78 }
79
80 static gchar*
replace_markup(const gchar * text,const gchar * match_regex,const gchar * replace_text)81 replace_markup (const gchar *text, const gchar *match_regex, const gchar *replace_text)
82 {
83 GRegex *regex;
84 gchar *ret;
85
86 regex = g_regex_new (match_regex, G_REGEX_DOTALL | G_REGEX_OPTIMIZE, 0, NULL);
87 ret = g_regex_replace (regex, text, -1, 0, replace_text, 0, NULL);
88 g_regex_unref (regex);
89
90 return ret;
91 }
92
93 gchar*
filter_text(const gchar * text)94 filter_text (const gchar *text)
95 {
96 gchar *text1;
97
98 text1 = strip_html (text, TAG_MATCH_REGEX, TAG_REPLACE_REGEX);
99
100 static ReplaceMarkupData data[] = {
101 { CHARACTER_AMP_REGEX, "&" },
102 { CHARACTER_LT_REGEX, "<" },
103 { CHARACTER_GT_REGEX, ">" },
104 { CHARACTER_APOS_REGEX, "'" },
105 { CHARACTER_QUOT_REGEX, "\"" },
106 { CHARACTER_NEWLINE_REGEX, "\n" }
107 };
108
109 ReplaceMarkupData* ptr = data;
110 ReplaceMarkupData* end = data + sizeof(data) / sizeof(ReplaceMarkupData);
111 for (; ptr != end; ++ptr) {
112 gchar* tmp = replace_markup (text1, ptr->regex, ptr->replacement);
113 g_free (text1);
114 text1 = tmp;
115 }
116
117 return text1;
118 }
119
120 gchar*
newline_to_space(const gchar * text)121 newline_to_space (const gchar *text)
122 {
123 gchar *text1;
124
125 text1 = strip_html (text, TAG_MATCH_REGEX, TAG_REPLACE_REGEX);
126
127 static ReplaceMarkupData data[] = {
128 { CHARACTER_NEWLINE_REGEX, " " }
129 };
130
131 ReplaceMarkupData* ptr = data;
132 ReplaceMarkupData* end = data + sizeof(data) / sizeof(ReplaceMarkupData);
133 for (; ptr != end; ++ptr) {
134 gchar* tmp = replace_markup (text1, ptr->regex, ptr->replacement);
135 g_free (text1);
136 text1 = tmp;
137 }
138
139 return text1;
140 }
141
142 gboolean
destroy_cloned_surface(cairo_surface_t * surface)143 destroy_cloned_surface (cairo_surface_t* surface)
144 {
145 gboolean finalref = FALSE;
146 g_return_val_if_fail (surface, FALSE);
147
148 if (cairo_surface_get_reference_count (surface) == 1) {
149 g_free (cairo_image_surface_get_data (surface));
150 finalref = TRUE;
151 }
152 cairo_surface_destroy (surface);
153 return finalref;
154 }
155
156 cairo_surface_t*
copy_surface(cairo_surface_t * orig)157 copy_surface (cairo_surface_t* orig)
158 {
159 cairo_surface_t* copy = NULL;
160 guchar* pixels_src = NULL;
161 guchar* pixels_cpy = NULL;
162 cairo_format_t format;
163 gint width;
164 gint height;
165 gint stride;
166
167 pixels_src = cairo_image_surface_get_data (orig);
168 if (!pixels_src)
169 return NULL;
170
171 format = cairo_image_surface_get_format (orig);
172 width = cairo_image_surface_get_width (orig);
173 height = cairo_image_surface_get_height (orig);
174 stride = cairo_image_surface_get_stride (orig);
175
176 pixels_cpy = g_malloc0 (stride * height);
177 if (!pixels_cpy)
178 return NULL;
179
180 memcpy ((void*) pixels_cpy, (void*) pixels_src, height * stride);
181
182 copy = cairo_image_surface_create_for_data (pixels_cpy,
183 format,
184 width,
185 height,
186 stride);
187
188 return copy;
189 }
190
191 // code of get_wm_name() based in large chunks on www.amsn-project.net
192 gchar*
get_wm_name(Display * dpy)193 get_wm_name (Display* dpy)
194 {
195 int screen;
196 Atom type;
197 int format;
198 unsigned long bytes_returned;
199 unsigned long n_returned;
200 unsigned char* buffer;
201 Window* child;
202 Window root;
203 Atom supwmcheck;
204 Atom wmname;
205
206 if (!dpy)
207 return NULL;
208
209 screen = DefaultScreen (dpy);
210 root = RootWindow (dpy, screen);
211 supwmcheck = XInternAtom (dpy, "_NET_SUPPORTING_WM_CHECK", False);
212 wmname = XInternAtom (dpy, "_NET_WM_NAME", False);
213
214 XGetWindowProperty (dpy,
215 root,
216 supwmcheck,
217 0,
218 8,
219 False,
220 AnyPropertyType,
221 &type,
222 &format,
223 &n_returned,
224 &bytes_returned,
225 &buffer);
226
227 child = (Window*) buffer;
228
229 if (n_returned != 1)
230 return NULL;
231
232 XGetWindowProperty (dpy,
233 *child,
234 wmname,
235 0,
236 128,
237 False,
238 AnyPropertyType,
239 &type,
240 &format,
241 &n_returned,
242 &bytes_returned,
243 &buffer);
244
245 if (n_returned == 0)
246 return NULL;
247
248 XFree (child);
249
250 // example wm-names as reported by get_wm_name()
251 //
252 // compiz
253 // Metacity
254 // Xfwm4
255 // KWin
256 // xmonad
257
258 return (gchar*) buffer;
259 }
260
261 GString*
extract_font_face(const gchar * string)262 extract_font_face (const gchar* string)
263 {
264 GRegex* regex = NULL;
265 GMatchInfo* match_info = NULL;
266 GString* font_face = NULL;
267
268 // sanity check
269 if (!string)
270 return NULL;
271
272 // extract font-face-name/style
273 font_face = g_string_new ("");
274 if (!font_face)
275 return NULL;
276
277 // setup regular expression to extract leading text before trailing int
278 regex = g_regex_new ("([A-Z a-z])+", 0, 0, NULL);
279
280 // walk the string
281 g_regex_match (regex, string, 0, &match_info);
282 while (g_match_info_matches (match_info))
283 {
284 gchar* word = NULL;
285
286 word = g_match_info_fetch (match_info, 0);
287 if (word)
288 {
289 g_string_append (font_face, word);
290 g_free (word);
291 }
292
293 g_match_info_next (match_info, NULL);
294 }
295
296 // clean up
297 g_match_info_free (match_info);
298 g_regex_unref (regex);
299
300 return font_face;
301 }
302