1 /*
  2  *
  3  * Compiz title bar information extension plugin
  4  *
  5  * titleinfo.cpp
  6  *
  7  * Copyright : (C) 2009 by Danny Baumann
  8  * E-mail    : maniac@compiz.org
  9  *
 10  * Ported to Compiz 0.9 by:
 11  * Copyright : (C) 2009 Sam Spilsbury
 12  * E-mail    : smspillaz@gmail.com
 13  *
 14  * This program is free software; you can redistribute it and/or
 15  * modify it under the terms of the GNU General Public License
 16  * as published by the Free Software Foundation; either version 2
 17  * of the License, or (at your option) any later version.
 18  *
 19  * This program is distributed in the hope that it will be useful,
 20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 22  * GNU General Public License for more details.
 23  *
 24  */
 25 
 26 #include "titleinfo.h"
 27 
 28 
 29 COMPIZ_PLUGIN_20090315 (titleinfo, TitleinfoPluginVTable);
 30 
 31 void
 32 TitleinfoWindow::updateVisibleName ()
 33 {
 34     CompString  text, f_machine;
 35     CompString  root, f_title;
 36 
 37     TITLEINFO_SCREEN (screen);
 38 
 39     f_title = title.size () ? title : "";
 40 
 41     if (ts->optionGetShowRoot () && owner == 0)
 42 	root = "ROOT: ";
 43 
 44     if (ts->optionGetShowRemoteMachine () && remoteMachine.size ())
 45     {
 46 	char hostname[256];
 47 
 48 	if (gethostname (hostname, 256) || strcmp (hostname, remoteMachine.c_str ()))
 49 	    f_machine = remoteMachine;
 50     }
 51 
 52     if (f_machine.size ())
 53 	text = root + f_title + "(@" + f_machine + ")";
 54     else if (root.size ())
 55 	text = root + f_title;
 56 
 57     if (text.size ())
 58     {
 59 	XChangeProperty (screen->dpy (), window->id (), ts->visibleNameAtom,
 60 			 Atoms::utf8String, 8, PropModeReplace,
 61 			 (unsigned char *) text.c_str (), text.size ());
 62 	text.clear ();
 63     }
 64     else
 65     {
 66 	XDeleteProperty (screen->dpy (), window->id (), ts->visibleNameAtom);
 67     }
 68 }
 69 
 70 void
 71 TitleinfoWindow::updatePid ()
 72 {
 73     int           pid = -1;
 74     Atom          type;
 75     int           result, format;
 76     unsigned long nItems, bytesAfter;
 77     unsigned char *propVal;
 78 
 79     TITLEINFO_SCREEN (screen);
 80 
 81     owner = -1;
 82 
 83     result = XGetWindowProperty (screen->dpy (), window->id (), ts->wmPidAtom,
 84 				 0L, 1L, False, XA_CARDINAL, &type,
 85 				 &format, &nItems, &bytesAfter, &propVal);
 86 
 87     if (result == Success && propVal)
 88     {
 89 	if (nItems)
 90 	{
 91 	    unsigned long value;
 92 
 93 	    memcpy (&value, propVal, sizeof (unsigned long));
 94 	    pid = value;
 95 	}
 96 
 97 	XFree (propVal);
 98     }
 99 
100     if (pid >= 0)
101     {
102 	char        path[512];
103 	struct stat fileStat;
104 
105 	snprintf (path, 512, "/proc/%d", pid);
106 	if (!lstat (path, &fileStat))
107 	    owner = fileStat.st_uid;
108     }
109 
110     if (ts->optionGetShowRoot ())
111 	updateVisibleName ();
112 }
113 
114 CompString
115 TitleinfoScreen::getUtf8Property (Window      id,
116 				  Atom        atom)
117 {
118     Atom          type;
119     int           result, format;
120     unsigned long nItems, bytesAfter;
121     char          *val = NULL,   *retval_c = NULL;
122     CompString    retval;
123 
124     result = XGetWindowProperty (screen->dpy (), id, atom, 0L, 65536, False,
125 				 Atoms::utf8String, &type, &format, &nItems,
126 				 &bytesAfter, (unsigned char **) &val);
127 
128     if (result != Success)
129 	return retval;
130 
131     if (type == Atoms::utf8String && format == 8 && val && nItems > 0)
132     {
133 	retval_c = (char *) malloc (sizeof (char) * (nItems + 1));
134 	if (retval_c)
135 	{
136 	    strncpy (retval_c, val, nItems);
137 	    retval_c[nItems] = 0;
138 	}
139     }
140 
141     if (retval_c)
142 	retval = CompString (retval_c);
143 
144     if (val)
145 	XFree (val);
146 
147     return retval;
148 }
149 
150 CompString
151 TitleinfoScreen::getTextProperty (Window      id,
152 				  Atom        atom)
153 {
154     XTextProperty text;
155     char          *retval_c = NULL;
156     CompString    retval;
157 
158     text.nitems = 0;
Condition "XGetTextProperty(screen->dpy(), id, &text, atom)", taking true branch
159     if (XGetTextProperty (screen->dpy (), id, &text, atom))
160     {
Condition "text.value", taking true branch
161         if (text.value)
162 	{
CID 12499 - RESOURCE_LEAK
Storage is returned from allocation function "malloc(size_t)".
Assigning: "retval_c" = storage returned from "malloc(1UL * (text.nitems + 1UL))".
163 	    retval_c = (char *) malloc (sizeof (char) * (text.nitems + 1));
Condition "retval_c", taking true branch
164 	    if (retval_c)
165 	    {
CID 12499 - RESOURCE_LEAK
Resource "retval_c" is not freed or pointed-to in function "strncpy(char *, char const *, size_t)".
166 		strncpy (retval_c, (char *) text.value, text.nitems);
167 		retval_c[text.nitems] = 0;
168 	    }
169 
170 	    XFree (text.value);
171 	}
172     }
173 
Condition "retval_c", taking true branch
174     if (retval_c)
CID 12499 - RESOURCE_LEAK
Resource "retval_c" is not freed or pointed-to in function "std::basic_string, std::allocator >::basic_string(char const *, std::allocator const &)".
175 	retval = CompString (retval_c);
176 
CID 12499 - RESOURCE_LEAK
Variable "retval_c" going out of scope leaks the storage it points to.
177     return retval;
178 }
179 
180 void
181 TitleinfoWindow::updateTitle ()
182 {
183     CompString f_title;
184 
185     TITLEINFO_SCREEN (screen);
186 
187     f_title = ts->getUtf8Property (window->id (), Atoms::wmName);
188 
189     if (f_title.empty ())
190 	title = ts->getTextProperty (window->id (), XA_WM_NAME);\
191 
192     title = f_title;
193     updateVisibleName ();
194 }
195 
196 
197 void
198 TitleinfoWindow::updateMachine ()
199 {
200     TITLEINFO_SCREEN (screen);
201 
202     if (remoteMachine.size ())
203 	remoteMachine.clear ();
204 
205     remoteMachine = ts->getTextProperty (window->id (),
206 					 XA_WM_CLIENT_MACHINE);
207 
208     if (ts->optionGetShowRemoteMachine ())
209 	updateVisibleName ();
210 }
211 
212 void
213 TitleinfoScreen::addSupportedAtoms (std::vector<Atom> &atoms)
214 {
215     screen->addSupportedAtoms (atoms);
216     
217     atoms.push_back (visibleNameAtom);
218     atoms.push_back (wmPidAtom);
219 }
220 
221 void
222 TitleinfoScreen::handleEvent (XEvent *event)
223 {
224 
225     screen->handleEvent (event);
226 
227     if (event->type == PropertyNotify)
228     {
229 	CompWindow *w;
230 
231 	if (event->xproperty.atom == XA_WM_CLIENT_MACHINE)
232 	{
233 	    w = screen->findWindow (event->xproperty.window);
234 	    if (w)
235 	    {
236 		TITLEINFO_WINDOW (w);
237 		tw->updateMachine ();
238 	    }
239 	}
240 	else if (event->xproperty.atom == wmPidAtom)
241 	{
242 	    w = screen->findWindow (event->xproperty.window);
243 	    if (w)
244 	    {
245 		TITLEINFO_WINDOW (w);
246 		tw->updatePid ();
247 	    }
248 	}
249 	else if (event->xproperty.atom == Atoms::wmName ||
250 		 event->xproperty.atom == XA_WM_NAME)
251 	{
252 	    w = screen->findWindow (event->xproperty.window);
253 	    if (w)
254 	    {
255 		TITLEINFO_WINDOW (w);
256 		tw->updateTitle ();
257 	    }
258 	}
259     }
260 }
261 
262 TitleinfoScreen::TitleinfoScreen (CompScreen *screen) :
263     PluginClassHandler <TitleinfoScreen, CompScreen> (screen),
264     visibleNameAtom (XInternAtom (screen->dpy (), "_NET_WM_VISIBLE_NAME", 0)),
265     wmPidAtom (XInternAtom (screen->dpy (), "_NET_WM_PID", 0))
266 {
267     ScreenInterface::setHandler (screen);
268     
269     screen->updateSupportedWmHints ();
270 };
271 
272 TitleinfoScreen::~TitleinfoScreen ()
273 {
274     screen->addSupportedAtomsSetEnabled (this, false);
275     
276     screen->updateSupportedWmHints ();
277 }
278 
279 TitleinfoWindow::TitleinfoWindow (CompWindow *window) :
280     PluginClassHandler <TitleinfoWindow, CompWindow> (window),
281     window (window),
282     owner (-1)
283 {
284     updateTitle ();
285     updateMachine ();
286     updatePid ();
287     updateVisibleName ();
288 }
289 
290 bool
291 TitleinfoPluginVTable::init ()
292 {
293     if (!CompPlugin::checkPluginABI ("core", CORE_ABIVERSION))
294 	return false;
295 
296     return true;
297 };