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          "&apos;"
40 #define CHARACTER_QUOT_REGEX          "&quot;"
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