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 }