1 /*
2  * Oroborus Window Manager
3  * X11 Hints Utility Library
4  *
5  * Copyright (C) 2001 Ken Lynch
6  * Copyright (C) 2002-2005 Stefan Pfetzing
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2, or (at your option)
11  * any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software Foundation,
20  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21  */
22 
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26 
27 #include <X11/Xlib.h>
28 #include <X11/Xutil.h>
29 #include <X11/Xmd.h>
30 #include <X11/Xatom.h>
31 #include <stdlib.h>
32 #include <string.h>
33 
34 #ifdef DEBUG
35 #include <stdio.h>
36 #endif
37 
38 #include "hints.h"
39 
40 Atom wm_state, wm_change_state, wm_delete_window, wm_protocols;
41 Atom motif_wm_hints;
42 Atom win_hints, win_state, win_client_list, win_layer, win_workspace,
43   win_workspace_count, win_desktop_button_proxy, win_supporting_wm_check,
44   gnome_panel_desktop_area;
45 Atom net_atoms[NET_ATOM_COUNT];
46 extern Display *dpy;
47 
48 void
initHints(Display * d)49 initHints (Display * d)
50 {
51   dpy = d;
52   initICCCMHints ();
53   initMotifHints ();
54   initGnomeHints ();
55   initNETHints ();
56 }
57 
58 void
initICCCMHints()59 initICCCMHints ()
60 {
61 #ifdef DEBUG
62   printf ("entering initICCCMHints\n");
63 #endif
64 
65   wm_state = XInternAtom (dpy, "WM_STATE", False);
66   wm_change_state = XInternAtom (dpy, "WM_CHANGE_STATE", False);
67   wm_delete_window = XInternAtom (dpy, "WM_DELETE_WINDOW", False);
68   wm_protocols = XInternAtom (dpy, "WM_PROTOCOLS", False);
69 }
70 
71 void
initNETHints()72 initNETHints ()
73 {
74   Window root;
75 #ifdef DEBUG
76   printf ("entering initNETHints\n");
77 #endif
78 
79   root = XDefaultRootWindow (dpy);
80 
81   net_atoms[NET_CLIENT_LIST] = XInternAtom (dpy, "_NET_CLIENT_LIST", False);
82   net_atoms[NET_CLIENT_LIST_STACKING] =
83     XInternAtom (dpy, "_NET_CLIENT_LIST_STACKING", False);
84   net_atoms[NET_WM_WINDOW_TYPE] =
85     XInternAtom (dpy, "_NET_WM_WINDOW_TYPE", False);
86   net_atoms[NET_WM_WINDOW_TYPE_DESKTOP] =
87     XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_DESKTOP", False);
88   net_atoms[NET_WM_WINDOW_TYPE_DOCK] =
89     XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_DOCK", False);
90   net_atoms[NET_WM_WINDOW_TYPE_TOOLBAR] =
91     XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_TOOLBAR", False);
92   net_atoms[NET_WM_WINDOW_TYPE_MENU] =
93     XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_MENU", False);
94   net_atoms[NET_WM_WINDOW_TYPE_UTILITY] =
95     XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_UTILITY", False);
96   net_atoms[NET_WM_WINDOW_TYPE_SPLASH] =
97     XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_SPLASH", False);
98   net_atoms[NET_WM_WINDOW_TYPE_DIALOG] =
99     XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_DIALOG", False);
100   net_atoms[NET_WM_WINDOW_TYPE_NORMAL] =
101     XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_NORMAL", False);
102   net_atoms[NET_WM_STATE] = XInternAtom (dpy, "_NET_WM_STATE", False);
103   net_atoms[NET_WM_STATE_MODAL] =
104     XInternAtom (dpy, "_NET_WM_STATE_MODAL", False);
105   net_atoms[NET_WM_STATE_STICKY] =
106     XInternAtom (dpy, "_NET_WM_STATE_STICKY", False);
107   net_atoms[NET_WM_STATE_SHADED] =
108     XInternAtom (dpy, "_NET_WM_STATE_SHADED", False);
109   net_atoms[NET_WM_STATE_SKIP_TASKBAR] =
110     XInternAtom (dpy, "_NET_WM_STATE_SKIP_TASKBAR", False);
111   net_atoms[NET_WM_STATE_SKIP_PAGER] =
112     XInternAtom (dpy, "_NET_WM_STATE_SKIP_PAGER", False);
113   net_atoms[NET_WM_STATE_HIDDEN] =
114     XInternAtom (dpy, "_NET_WM_STATE_HIDDEN", False);
115   net_atoms[NET_WM_STATE_ABOVE] =
116     XInternAtom (dpy, "_NET_WM_STATE_ABOVE", False);
117   net_atoms[NET_WM_STATE_FULLSCREEN] =
118     XInternAtom (dpy, "_NET_WM_STATE_FULLSCREEN", False);
119   net_atoms[NET_WM_NAME] = XInternAtom (dpy, "_NET_WM_NAME", False);
120   net_atoms[NET_WM_DESKTOP] = XInternAtom (dpy, "_NET_WM_DESKTOP", False);
121   net_atoms[NET_NUMBER_OF_DESKTOPS] =
122     XInternAtom (dpy, "_NET_NUMBER_OF_DESKTOPS", False);
123   net_atoms[NET_CURRENT_DESKTOP] =
124     XInternAtom (dpy, "_NET_CURRENT_DESKTOP", False);
125   net_atoms[NET_ACTIVE_WINDOW] =
126     XInternAtom (dpy, "_NET_ACTIVE_WINDOW", False);
127   net_atoms[NET_SUPPORTING_WM_CHECK] =
128     XInternAtom (dpy, "_NET_SUPPORTING_WM_CHECK", False);
129   net_atoms[NET_WORKAREA] = XInternAtom (dpy, "_NET_WORKAREA", False);
130   net_atoms[NET_WM_WORKAREA] = XInternAtom (dpy, "_NET_WM_WORKAREA", False);
131   net_atoms[NET_CLOSE_WINDOW] = XInternAtom (dpy, "_NET_CLOSE_WINDOW", False);
132   net_atoms[NET_WM_PID] = XInternAtom (dpy, "_NET_WM_PID", False);
133   net_atoms[NET_WM_STRUT] = XInternAtom (dpy, "_NET_WM_STRUT", False);
134   XChangeProperty (dpy, root, XInternAtom (dpy, "_NET_SUPPORTED", False),
135 		   XA_ATOM, 32, PropModeReplace, (unsigned char *) net_atoms,
136 		   NET_ATOM_COUNT);
137 }
138 
139 void
initMotifHints()140 initMotifHints ()
141 {
142 #ifdef DEBUG
143   printf ("entering initMotifHints\n");
144 #endif
145 
146   motif_wm_hints = XInternAtom (dpy, "_MOTIF_WM_HINTS", False);
147 }
148 
149 void
initGnomeHints()150 initGnomeHints ()
151 {
152   Window root;
153 
154 #ifdef DEBUG
155   printf ("entering initGnomeHints\n");
156 #endif
157 
158   root = XDefaultRootWindow (dpy);
159   win_hints = XInternAtom (dpy, "_WIN_HINTS", False);
160   win_state = XInternAtom (dpy, "_WIN_STATE", False);
161   win_client_list = XInternAtom (dpy, "_WIN_CLIENT_LIST", False);
162   win_layer = XInternAtom (dpy, "_WIN_LAYER", False);
163   win_workspace = XInternAtom (dpy, "_WIN_WORKSPACE", False);
164   win_workspace_count = XInternAtom (dpy, "_WIN_WORKSPACE_COUNT", False);
165   win_desktop_button_proxy =
166     XInternAtom (dpy, "_WIN_DESKTOP_BUTTON_PROXY", False);
167   win_supporting_wm_check =
168     XInternAtom (dpy, "_WIN_SUPPORTING_WM_CHECK", False);
169   gnome_panel_desktop_area =
170     XInternAtom (dpy, "GNOME_PANEL_DESKTOP_AREA", False);
171 }
172 
173 long
getWMState(Window w)174 getWMState (Window w)
175 {
176   unsigned long *data = NULL, state = WithdrawnState;
177 
178 #ifdef DEBUG
179   printf ("entering getWmState\n");
180 #endif
181 
182   data = getPropData (w, wm_state, wm_state, NULL);
183   if (data)
184     {
185       state = *data;
186       XFree (data);
187     }
188   return state;
189 }
190 
191 void
setWMState(Window w,long state)192 setWMState (Window w, long state)
193 {
194   CARD32 data[2];
195 
196 #ifdef DEBUG
197   printf ("entering setWmState\n");
198 #endif
199 
200   data[0] = state;
201   data[1] = None;
202 
203   XChangeProperty (dpy, w, wm_state, wm_state, 32, PropModeReplace,
204 		   (unsigned char *) data, 2);
205 }
206 
207 PropMwmHints *
getMotifHints(Window w)208 getMotifHints (Window w)
209 {
210 #ifdef DEBUG
211   printf ("entering getMotifHints\n");
212 #endif
213 
214   return getPropData (w, motif_wm_hints, motif_wm_hints, NULL);
215 }
216 
217 int
getGnomeHint(Window w,Atom a,long * value)218 getGnomeHint (Window w, Atom a, long *value)
219 {
220   int success = False;
221   long *data = NULL;
222 
223 #ifdef DEBUG
224   printf ("entering getGnomeHint\n");
225 #endif
226 
227   if (a == win_layer)
228     *value = WIN_LAYER_NORMAL;
229   else
230     *value = 0;
231 
232   data = getPropData (w, a, XA_CARDINAL, NULL);
233   if (data)
234     {
235       *value = *data;
236       success = True;
237       XFree (data);
238     }
239   return success;
240 }
241 
242 void
setGnomeHint(Window w,Atom a,long value)243 setGnomeHint (Window w, Atom a, long value)
244 {
245 #ifdef DEBUG
246   printf ("entering setGnomeHint\n");
247 #endif
248 
249   XChangeProperty (dpy, w, a, XA_CARDINAL, 32, PropModeReplace,
250 		   (unsigned char *) &value, 1);
251 }
252 
253 void
setNetWmName(Window w,Atom a,char * value)254 setNetWmName (Window w, Atom a, char *value)
255 {
256 #ifdef DEBUG
257   printf ("entering setNetWmName\n");
258 #endif
259 
260   XChangeProperty (dpy, w, a, XA_STRING, 8, PropModeReplace,
261 		   (unsigned char *) value, strlen (value));
262 }
263 
264 void
setSupportingWmCheck(Window w,Window w2)265 setSupportingWmCheck (Window w, Window w2)
266 {
267 #ifdef DEBUG
268   printf ("entering setSupportingWmCheck\n");
269 #endif
270 
271   XChangeProperty (dpy, w, net_atoms[NET_SUPPORTING_WM_CHECK], XA_WINDOW, 32,
272 		   PropModeReplace, (unsigned char *) &w2, 1);
273 }
274 
275 void
getEWMHState(Window w,long * value)276 getEWMHState (Window w, long *value)
277 {
278   unsigned long *data;
279   unsigned long items = 0;
280   unsigned long i;
281 
282   data = getPropData (w, net_atoms[NET_WM_STATE], XA_ATOM, &items);
283   if (data)
284     {
285       for (i = 0; i < items; i++)
286 	{
287 	  char *currentName = XGetAtomName (dpy, data[i]);
288 	  char *configuredName =
289 	    XGetAtomName (dpy, net_atoms[NET_WM_STATE_STICKY]);
290 	  if (equals (currentName, configuredName))
291 	    *value |= WIN_STATE_STICKY;
292 	  XFree (currentName);
293 	  XFree (configuredName);
294 	}
295       XFree (data);
296     }
297 }
298 
299 void
getGnomeDesktopMargins(CARD32 * margins)300 getGnomeDesktopMargins (CARD32 * margins)
301 {
302   unsigned long items_read;
303   CARD32 *data = NULL;
304 
305 #ifdef DEBUG
306   printf ("entering getGnomeDesktopMargins\n");
307 #endif
308 
309   data =
310     getPropData (XDefaultRootWindow (dpy), gnome_panel_desktop_area,
311 		 XA_CARDINAL, &items_read);
312   if (data && items_read >= 4)
313     {
314       margins[0] = data[0];
315       margins[1] = data[1];
316       margins[2] = data[2];
317       margins[3] = data[3];
318       XFree (data);
319     }
320   else
321     {
322       margins[0] = 0;
323       margins[1] = 0;
324       margins[2] = 0;
325       margins[3] = 0;
326     }
327 }
328 
329 int
getNetWMPid(Window w)330 getNetWMPid (Window w)
331 {
332   int val;
333   int *data = NULL;
334   unsigned long items_read;
335 
336   data = getPropData (w, net_atoms[NET_WM_PID], XA_CARDINAL, &items_read);
337 
338   if (items_read >= 1)
339     {
340       val = *data;
341       XFree(data);
342 
343       return val;
344     }
345   else
346     return 0;
347 }
348 
349 void
getNetWMStrut(Window win,CARD32 * margins,CARD32 * window_margins)350 getNetWMStrut (Window win, CARD32 * margins, CARD32 * window_margins)
351 {
352   unsigned long items_read;
353   CARD32 *data = NULL;
354 
355 #ifdef DEBUG
356   printf ("entering getGnomeDesktopMargins\n");
357 #endif
358 
359   data = getPropData (win, net_atoms[NET_WM_STRUT], XA_CARDINAL, &items_read);
360   if (data && items_read >= 4)
361     {
362       window_margins[0] = data[0];
363       window_margins[1] = data[1];
364       window_margins[2] = data[2];
365       window_margins[3] = data[3];
366       margins[0] += data[0];
367       margins[1] += data[1];
368       margins[2] += data[2];
369       margins[3] += data[3];
370       XFree (data);
371     }
372   else
373     {
374       window_margins[0] = 0;
375       window_margins[1] = 0;
376       window_margins[2] = 0;
377       window_margins[3] = 0;
378     }
379 }
380 
381 void
delNetWMStrut(CARD32 * margins,CARD32 * data)382 delNetWMStrut (CARD32 * margins, CARD32 * data)
383 {
384 #ifdef DEBUG
385   printf ("entering delNetWMStrut\n");
386 #endif
387 
388   if (data[0] || data[1] || data[2] || data[3])
389     {
390       margins[0] -= data[0];
391       margins[1] -= data[1];
392       margins[2] -= data[2];
393       margins[3] -= data[3];
394     }
395 }
396 
397 void
setNetWorkarea(CARD32 * margins,int workspaces)398 setNetWorkarea (CARD32 * margins, int workspaces)
399 {
400   struct workarea
401   {
402     CARD32 left, top, right, bottom;
403   }
404    *workarea;
405   int i;
406 
407   if (workspaces <= 0)
408     return;
409 
410   workarea = calloc (workspaces, sizeof (struct workarea));
411 
412   for (i = 0; i < workspaces; i++)
413     {
414       workarea[i].left = margins[0];
415       workarea[i].top = margins[1];
416       workarea[i].right =
417 	XDisplayWidth (dpy, XDefaultScreen (dpy)) - margins[1];
418       workarea[i].bottom =
419 	XDisplayHeight (dpy, XDefaultScreen (dpy)) - margins[3];
420     }
421 
422   XChangeProperty (dpy, XDefaultRootWindow (dpy),
423 		   net_atoms[NET_WORKAREA], XA_CARDINAL, 32,
424 		   PropModeReplace, (unsigned char *) workarea,
425 		   4 * workspaces);
426   XChangeProperty (dpy, XDefaultRootWindow (dpy), net_atoms[NET_WM_WORKAREA],
427 		   XA_CARDINAL, 32, PropModeReplace,
428 		   (unsigned char *) workarea, 4 * workspaces);
429   free (workarea);
430 }
431 
432 int
typeDesktop(Window w)433 typeDesktop (Window w)
434 {
435   return typeEWMH (w, "_NET_WM_WINDOW_TYPE_DESKTOP");
436 }
437 
438 int
typeDock(Window w)439 typeDock (Window w)
440 {
441   return typeEWMH (w, "_NET_WM_WINDOW_TYPE_DOCK");
442 }
443 
444 int
typeAbove(Window w)445 typeAbove (Window w)
446 {
447   return typeEWMH (w, "_NET_WM_STATE_ABOVE");
448 }
449 
450 int
typeEWMH(Window w,char * type)451 typeEWMH (Window w, char *type)
452 {
453   unsigned long *data;
454   unsigned long items = 0;
455   unsigned long item = 0;
456   int ret = 0;
457 
458 #ifdef DEBUG
459   printf ("entering typeEWMH\n");
460 #endif
461 
462   data = getPropData (w, net_atoms[NET_WM_WINDOW_TYPE], XA_ATOM, &items);
463   while (data && items && item < items && !ret)
464     {
465       char *name;
466       name = XGetAtomName (dpy, data[item]);
467 #ifdef DEBUG
468       printf ("%s\n", name);
469 #endif
470       ret = equals (name, type);
471       XFree (name);
472       item++;
473     }
474   if (data)
475     XFree (data);
476 
477   return ret;
478 }
479 
480 void *
getPropData(Window w,Atom prop,Atom type,unsigned long * items_ret)481 getPropData (Window w, Atom prop, Atom type, unsigned long *items_ret)
482 {
483   Atom type_ret;
484   int format_ret;
485   unsigned long after_ret;
486   unsigned char *prop_data;
487 
488 #ifdef DEBUG
489   printf ("entering getPropData\n");
490 #endif
491   prop_data = NULL;
492 
493   if (items_ret == NULL)
494     {
495       items_ret = (unsigned long *) malloc (sizeof (unsigned long));
496       XGetWindowProperty (dpy, w, prop, 0, 0x7fffffff, False,
497 			  type, &type_ret, &format_ret, items_ret,
498 			  &after_ret, &prop_data);
499       if (prop_data && *items_ret)
500 	{
501 	  free (items_ret);
502 	  return prop_data;
503 	}
504       else
505 	{
506 	  free (items_ret);
507 	  return NULL;
508 	}
509     }
510   else
511     {
512       XGetWindowProperty (dpy, w, prop, 0, 0x7fffffff, False,
513 			  type, &type_ret, &format_ret, items_ret,
514 			  &after_ret, &prop_data);
515       if (prop_data && *items_ret)
516 	return prop_data;
517       else
518 	return NULL;
519     }
520 }
521 
522 void
setFocusHint(Window w)523 setFocusHint (Window w)
524 {
525 #ifdef DEBUG
526   printf ("entering setFocusHint\n");
527 #endif
528 
529   XChangeProperty (dpy, XDefaultRootWindow (dpy),
530 		   net_atoms[NET_ACTIVE_WINDOW], XA_WINDOW, 32,
531 		   PropModeReplace, (unsigned char *) &w, 1);
532 }
533 
534 int
equals(char * left,char * right)535 equals (char *left, char *right)
536 {
537   if (left && right && (strcmp (left, right) == 0))
538     return 1;
539   else
540     return 0;
541 }
542 
543 /***This must remain at the end of the file.***********************************************
544  * vi:set sw=2 cindent cinoptions={1s,>2s,^-1s,n-1s foldmethod=marker foldmarker=���,���: *
545  * arch-tag: x11_hints handling for oroborus-wm                                           *
546  ******************************************************************************************/
547