1 /*
2 * Copyright �� 2007 Novell, Inc.
3 *
4 * Permission to use, copy, modify, distribute, and sell this software
5 * and its documentation for any purpose is hereby granted without
6 * fee, provided that the above copyright notice appear in all copies
7 * and that both that copyright notice and this permission notice
8 * appear in supporting documentation, and that the name of
9 * Novell, Inc. not be used in advertising or publicity pertaining to
10 * distribution of the software without specific, written prior permission.
11 * Novell, Inc. makes no representations about the suitability of this
12 * software for any purpose. It is provided "as is" without express or
13 * implied warranty.
14 *
15 * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
17 * NO EVENT SHALL NOVELL, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
18 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
19 * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
20 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
21 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22 *
23 * Author: David Reveman <davidr@novell.com>
24 */
25
26 #include "regexplugin.h"
27
28 #include "core/atoms.h"
29
30 #include <regex.h>
31 #include <limits.h>
32
33 COMPIZ_PLUGIN_20090315 (regex, RegexPluginVTable)
34
35 class RegexExp : public CompMatch::Expression
36 {
37 public:
38 typedef enum {
39 TypeTitle,
40 TypeRole,
41 TypeClass,
42 TypeName,
43 } Type;
44
45 RegexExp (const CompString& str, int item);
46 virtual ~RegexExp ();
47
48 bool evaluate (const CompWindow *w) const;
49 static int matches (const CompString& str);
50
51 private:
52 typedef struct {
53 const char *name;
54 size_t length;
55 Type type;
56 unsigned int flags;
57 } Prefix;
58
59 static const Prefix prefix[];
60
CID 12582 - UNINIT_CTOR
Class member declaration for "mType".
61 Type mType;
62 regex_t *mRegex;
63 };
64
65 const RegexExp::Prefix RegexExp::prefix[] = {
66 { "title=", 6, TypeTitle, 0 },
67 { "role=", 5, TypeRole, 0 },
68 { "class=", 6, TypeClass, 0 },
69 { "name=", 5, TypeName, 0 },
70 { "ititle=", 7, TypeTitle, REG_ICASE },
71 { "irole=", 6, TypeRole, REG_ICASE },
72 { "iclass=", 7, TypeClass, REG_ICASE },
73 { "iname=", 6, TypeName, REG_ICASE }
74 };
75
76 RegexExp::RegexExp (const CompString& str, int item) :
77 mRegex (NULL)
78 {
Condition "(unsigned int)item < 8UL /* sizeof (RegexExp::prefix) / sizeof (RegexExp::prefix[0]) */", taking false branch
79 if ((unsigned int) item < sizeof (prefix) / sizeof (prefix[0]))
80 {
81 int status;
82 CompString value;
83
84 value = str.substr (prefix[item].length);
85 mRegex = new regex_t;
86 status = regcomp (mRegex, value.c_str (),
87 REG_NOSUB | prefix[item].flags);
88
89 if (status)
90 {
91 char errMsg[1024];
92
93 regerror (status, mRegex, errMsg, sizeof (errMsg));
94
95 compLogMessage ("regex", CompLogLevelWarn,
96 "%s = %s", errMsg, value.c_str ());
97
98 regfree (mRegex);
99 delete mRegex;
100 mRegex = NULL;
101 }
102
103 mType = prefix[item].type;
End of if statement
104 }
CID 12582 - UNINIT_CTOR
Non-static class member "mType" is not initialized in this constructor nor in any functions that it calls.
105 }
106
107 RegexExp::~RegexExp ()
108 {
109 if (mRegex)
110 {
111 regfree (mRegex);
112 delete mRegex;
113 }
114 }
115
116 bool
117 RegexExp::evaluate (const CompWindow *w) const
118 {
119 const CompString *string = NULL;
120 const RegexWindow *rw = RegexWindow::get (w);
121
122 switch (mType)
123 {
124 case TypeRole:
125 string = &rw->role;
126 break;
127 case TypeTitle:
128 string = &rw->title;
129 break;
130 case TypeClass:
131 string = &rw->resClass;
132 break;
133 case TypeName:
134 string = &rw->resName;
135 break;
136 }
137
138 if (!mRegex || !string)
139 return false;
140
141 if (regexec (mRegex, string->c_str (), 0, NULL, 0))
142 return false;
143
144 return true;
145 }
146
147 int
148 RegexExp::matches (const CompString& str)
149 {
150 for (unsigned int i = 0; i < sizeof (prefix) / sizeof (prefix[0]); i++)
151 if (str.compare (0, prefix[i].length, prefix[i].name) == 0)
152 return (int) i;
153
154 return -1;
155 }
156
157 CompMatch::Expression *
158 RegexScreen::matchInitExp (const CompString& str)
159 {
160 int item = RegexExp::matches (str);
161
162 if (item >= 0)
163 return new RegexExp (str, item);
164
165 return screen->matchInitExp (str);
166 }
167
168 bool
169 RegexWindow::getStringProperty (Atom nameAtom,
170 Atom typeAtom,
171 CompString& string)
172 {
173 Atom type;
174 unsigned long nItems;
175 unsigned long bytesAfter;
176 unsigned char *str = NULL;
177 int format, result;
178
179 result = XGetWindowProperty (screen->dpy (), window->id (), nameAtom, 0,
180 LONG_MAX, false, typeAtom, &type, &format,
181 &nItems, &bytesAfter, (unsigned char **) &str);
182
183 if (result != Success)
184 return false;
185
186 if (type != typeAtom)
187 {
188 XFree (str);
189 return false;
190 }
191
192 string = (char *) str;
193
194 XFree (str);
195
196 return true;
197 }
198
199 void
200 RegexWindow::updateRole ()
201 {
202 RegexScreen *rs = RegexScreen::get (screen);
203
204 role = "";
205 getStringProperty (rs->roleAtom, XA_STRING, role);
206 }
207
208 void
209 RegexWindow::updateTitle ()
210 {
211 RegexScreen *rs = RegexScreen::get (screen);
212
213 title = "";
214
215 if (getStringProperty (rs->visibleNameAtom, Atoms::utf8String, title))
216 return;
217
218 if (getStringProperty (Atoms::wmName, Atoms::utf8String, title))
219 return;
220
221 getStringProperty (XA_WM_NAME, XA_STRING, title);
222 }
223
224 void RegexWindow::updateClass ()
225 {
226 XClassHint classHint;
227
228 resClass = "";
229 resName = "";
230
231 if (!XGetClassHint (screen->dpy (), window->id (), &classHint) != Success)
232 return;
233
234 if (classHint.res_name)
235 {
236 resName = classHint.res_name;
237 XFree (classHint.res_name);
238 }
239
240 if (classHint.res_class)
241 {
242 resClass = classHint.res_class;
243 XFree (classHint.res_class);
244 }
245 }
246
247 void
248 RegexScreen::handleEvent (XEvent *event)
249 {
250 CompWindow *w;
251
252 screen->handleEvent (event);
253
254 if (event->type != PropertyNotify)
255 return;
256
257 w = screen->findWindow (event->xproperty.window);
258 if (!w)
259 return;
260
261 if (event->xproperty.atom == XA_WM_NAME)
262 {
263 RegexWindow::get (w)->updateTitle ();
264 screen->matchPropertyChanged (w);
265 }
266 else if (event->xproperty.atom == roleAtom)
267 {
268 RegexWindow::get (w)->updateRole ();
269 screen->matchPropertyChanged (w);
270 }
271 else if (event->xproperty.atom == XA_WM_CLASS)
272 {
273 RegexWindow::get (w)->updateClass ();
274 screen->matchPropertyChanged (w);
275 }
276 }
277
278 /* It's not safe to call CompScreen::matchExpHandlerChanged
279 * from the ::RegexScreen constructor since that could end
280 * up calling RegexWindow::get () on windows (which haven't
281 * had a RegexWindow struct created for them) through
282 * ::matchExpHandlerChanged -> CompMatch::evaluate () ->
283 * RegexExp::evaluate () -> RegexWindow::get ()
284 */
285
286 bool
287 RegexScreen::applyInitialActions ()
288 {
289 screen->matchExpHandlerChanged ();
290 return false;
291 }
292
293 RegexScreen::RegexScreen (CompScreen *s) :
294 PluginClassHandler<RegexScreen, CompScreen> (s)
295 {
296 CompTimer::CallBack cb =
297 boost::bind (&RegexScreen::applyInitialActions, this);
298 ScreenInterface::setHandler (s);
299
300 roleAtom = XInternAtom (s->dpy (), "WM_WINDOW_ROLE", 0);
301 visibleNameAtom = XInternAtom (s->dpy (), "_NET_WM_VISIBLE_NAME", 0);
302
303 mApplyInitialActionsTimer.setTimes (0, 0);
304 mApplyInitialActionsTimer.setCallback (cb);
305 mApplyInitialActionsTimer.start ();
306 }
307
308 RegexScreen::~RegexScreen ()
309 {
310 screen->matchInitExpSetEnabled (this, false);
311 screen->matchExpHandlerChanged ();
312 }
313
314 RegexWindow::RegexWindow (CompWindow *w) :
315 PluginClassHandler<RegexWindow, CompWindow> (w),
316 window (w)
317 {
318 updateRole ();
319 updateTitle ();
320 updateClass ();
321 }
322
323 bool
324 RegexPluginVTable::init ()
325 {
326 if (!CompPlugin::checkPluginABI ("core", CORE_ABIVERSION))
327 return false;
328
329 return true;
330 }