1 /* $Id: props.c,v 1.2 2007/09/12 20:05:58 jwrdegoede Exp $ */
2 /*****************************************************************************/
3 /** Copyright 1988 by Evans & Sutherland Computer Corporation, **/
4 /** Salt Lake City, Utah **/
5 /** Portions Copyright 1989 by the Massachusetts Institute of Technology **/
6 /** Cambridge, Massachusetts **/
7 /** **/
8 /** All Rights Reserved **/
9 /** **/
10 /** Permission to use, copy, modify, and distribute this software and **/
11 /** its documentation for any purpose and without fee is hereby **/
12 /** granted, provided that the above copyright notice appear in all **/
13 /** copies and that both that copyright notice and this permis- **/
14 /** sion notice appear in supporting documentation, and that the **/
15 /** names of Evans & Sutherland and M.I.T. not be used in advertising **/
16 /** in publicity pertaining to distribution of the software without **/
17 /** specific, written prior permission. **/
18 /** **/
19 /** EVANS & SUTHERLAND AND M.I.T. DISCLAIM ALL WARRANTIES WITH REGARD **/
20 /** TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT- **/
21 /** ABILITY AND FITNESS, IN NO EVENT SHALL EVANS & SUTHERLAND OR **/
22 /** M.I.T. BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAM- **/
23 /** AGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA **/
24 /** OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER **/
25 /** TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE **/
26 /** OR PERFORMANCE OF THIS SOFTWARE. **/
27 /*****************************************************************************/
28 /****************************************************************************
29 * This module is based on Twm, but has been siginificantly modified
30 * by Rob Nation
31 ****************************************************************************/
32 /***********************************************************************
33 * The rest of it is all my fault -- MLM
34 * mwm - "LessTif Window Manager"
35 ***********************************************************************/
36
37
38 #include <LTconfig.h>
39
40 #include <stdio.h>
41
42 #include <Xm/Xm.h>
43 #include <Xm/MwmUtil.h>
44 #include "mwm.h"
45
46
47 Atom XA_MIT_PRIORITY_COLORS;
48 Atom XA_WM_CHANGE_STATE;
49 Atom XA_WM_STATE;
50 Atom XA_WM_COLORMAP_WINDOWS;
51 Atom XA_WM_PROTOCOLS;
52 Atom XA_WM_TAKE_FOCUS;
53 Atom XA_WM_DELETE_WINDOW;
54 Atom XA_WM_SAVE_YOURSELF;
55 Atom XA_WM_DESKTOP;
56 Atom XA_MWM_HINTS;
57 Atom XA_MWM_MESSAGES;
58 Atom XA_MWM_MENU;
59 Atom XA_MWM_INFO;
60
61 /***********************************************************************
62 *
63 * <Properties description>
64 *
65 ***********************************************************************/
66
67 /*
68 * Intern some commonly used atoms
69 */
70 void
PROP_Initialize(void)71 PROP_Initialize(void)
72 {
73 XA_MIT_PRIORITY_COLORS = XInternAtom(dpy, "_MIT_PRIORITY_COLORS", False);
74 XA_WM_CHANGE_STATE = XInternAtom(dpy, "WM_CHANGE_STATE", False);
75 XA_WM_STATE = XInternAtom(dpy, "WM_STATE", False);
76 XA_WM_COLORMAP_WINDOWS = XInternAtom(dpy, "WM_COLORMAP_WINDOWS", False);
77 XA_WM_PROTOCOLS = XInternAtom(dpy, "WM_PROTOCOLS", False);
78 XA_WM_TAKE_FOCUS = XInternAtom(dpy, "WM_TAKE_FOCUS", False);
79 XA_WM_DELETE_WINDOW = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
80 XA_WM_SAVE_YOURSELF = XInternAtom(dpy, "WM_SAVE_YOURSELF", False);
81 XA_WM_DESKTOP = XInternAtom(dpy, "WM_DESKTOP", False);
82 XA_MWM_HINTS = XInternAtom(dpy, _XA_MWM_HINTS, False);
83 XA_MWM_MESSAGES = XInternAtom(dpy, _XA_MWM_MESSAGES, False);
84 XA_MWM_MENU = XInternAtom(dpy, _XA_MWM_MENU, False);
85 XA_MWM_INFO = XInternAtom(dpy, _XA_MWM_INFO, False);
86 }
87
88 /*
89 * set the behavior property on the root window. This will be used for the
90 * f.set_behavior function
91 */
92 void
PROP_SetBehavior(ScreenInfo * scr,Boolean custom)93 PROP_SetBehavior(ScreenInfo *scr, Boolean custom)
94 {
95 long info[PROP_MWM_INFO_ELEMENTS];
96
97 /* set the MWM_INFO property on the Root, notice that we
98 use an array of longs here and not the PropMotifWmInfo struct,
99 this is because this struct looks like this in lesstif:
100
101 typedef struct {
102 CARD32 flags;
103 CARD32 wmWindow;
104 } PropMotifWmInfo;
105
106 But when setting 32 bit properties XChangeProperty expects an array of
107 longs, which it will convert to 32 bit values if need. Thus passing an
108 actual PropMotifWmInfo struct will mess things up on archs where longs
109 are 64 bit. */
110
111 if (custom)
112 info[0] = MWM_INFO_STARTUP_CUSTOM; /* set flags "member" */
113 else
114 info[0] = MWM_INFO_STARTUP_STANDARD; /* set flags "member" */
115
116 info[1] = scr->root_win; /* set wmWindow "member" */
117
118 XChangeProperty(dpy, scr->root_win, XA_MWM_INFO, XA_MWM_INFO,
119 32, PropModeReplace,
120 (unsigned char *)&info, PROP_MWM_INFO_ELEMENTS);
121 }
122
123 /*
124 * clear the behavior property on the root window.
125 */
126 void
PROP_ClearBehavior(ScreenInfo * scr)127 PROP_ClearBehavior(ScreenInfo *scr)
128 {
129 /* set the MWM_INFO property on the Root */
130 XChangeProperty(dpy, scr->root_win, XA_MWM_INFO, XA_MWM_INFO,
131 32, PropModeReplace,
132 NULL, 0);
133 }
134
135 /*
136 * get the current state of the behavior property. This also will be used
137 * by f.set_behavior
138 */
139 int
PROP_GetBehavior(ScreenInfo * scr)140 PROP_GetBehavior(ScreenInfo *scr)
141 {
142 int actual_format, ret;
143 Atom actual_type;
144 unsigned long nitems, bytesafter;
145 /* We use a long pointer here and not a PropMotifWmInfo pointer,
146 this is because this type looks like this in lesstif:
147
148 typedef struct {
149 CARD32 flags;
150 CARD32 wmWindow;
151 } PropMotifWmInfo;
152
153 But when getting 32 bit properties XGetWindowProperty returns an array
154 of longs. Thus interpreting the returned data as PropMotifWmInfo will
155 mess things up on archs where longs are 64 bit. */
156 unsigned long *info;
157
158 if (XGetWindowProperty(dpy, scr->root_win, XA_MWM_INFO, 0L,
159 PROP_MOTIF_WM_INFO_ELEMENTS, False,
160 XA_MWM_INFO, &actual_type, &actual_format,
161 &nitems, &bytesafter,
162 (unsigned char **)&info) == Success)
163 {
164 if (nitems > 0 && info)
165 ret = info[0]; /* Return flags "member" */
166 else
167 ret = 0;
168 XFree((char *)info);
169 return ret;
170 }
171
172 return 0;
173 }
174
175 /*
176 * Make sure property priority colors is empty
177 */
178 void
PROP_SetPriorityColors(ScreenInfo * scr)179 PROP_SetPriorityColors(ScreenInfo *scr)
180 {
181 XChangeProperty(dpy, scr->root_win, XA_MIT_PRIORITY_COLORS,
182 XA_CARDINAL, 32, PropModeReplace, NULL, 0);
183 }
184
185 /*
186 * check the desktop.
187 */
188 Boolean
PROP_CheckDesktop(ScreenInfo * scr)189 PROP_CheckDesktop(ScreenInfo *scr)
190 {
191 Atom atype;
192 int aformat;
193 unsigned long nitems, bytes_remain;
194 unsigned char *prop;
195 Boolean restart = False;
196
197 /*
198 * Set the current desktop number to zero
199 * Multiple desks are available even in non-virtual
200 * compilations
201 */
202 scr->current_desk = 0;
203 if ((XGetWindowProperty(dpy, scr->root_win, XA_WM_DESKTOP, 0L, 1L, True,
204 XA_WM_DESKTOP, &atype, &aformat, &nitems,
205 &bytes_remain, &prop)) == Success)
206 {
207 if (prop != NULL)
208 {
209 restart = True;
210 scr->current_desk = *(unsigned long *)prop;
211 }
212 }
213
214 return restart;
215 }
216
217 /*
218 * This is used to tell applications which windows on the screen are
219 * top level appication windows, and which windows are the icon windows
220 * that go with them.
221 */
222 void
PROP_SetState(MwmWindow * tmp_win,int state)223 PROP_SetState(MwmWindow *tmp_win, int state)
224 {
225 unsigned long data[2]; /* "suggested" by ICCCM version 1 */
226
227 data[0] = (unsigned long)state;
228 data[1] = (unsigned long)tmp_win->icon_w;
229 /* data[2] = (unsigned long) tmp_win->icon_pixmap_w; */
230
231 XChangeProperty(dpy, tmp_win->w, XA_WM_STATE, XA_WM_STATE, 32,
232 PropModeReplace, (unsigned char *)data, 2);
233 }
234
235 /*
236 * ICCCM Client Messages - Section 4.2.8 of the ICCCM dictates that all
237 * client messages will have the following form:
238 *
239 * event type ClientMessage
240 * message type XA_WM_PROTOCOLS
241 * window tmp->w
242 * format 32
243 * data[0] message atom
244 * data[1] time stamp
245 */
246 void
PROP_SendClientMessage(Window w,Atom a,Time timestamp)247 PROP_SendClientMessage(Window w, Atom a, Time timestamp)
248 {
249 XClientMessageEvent ev;
250
251 ev.type = ClientMessage;
252 ev.window = w;
253 ev.message_type = XA_WM_PROTOCOLS;
254 ev.format = 32;
255 ev.data.l[0] = a;
256 ev.data.l[1] = timestamp;
257 XSendEvent(dpy, w, False, 0L, (XEvent *)&ev);
258 }
259
260 /*
261 * verify that a client is expecting to receive a ClientMessage from mwm
262 */
263 Boolean
PROP_VerifyMwmMessage(MwmWindow * win,Atom message)264 PROP_VerifyMwmMessage(MwmWindow *win, Atom message)
265 {
266 unsigned int i;
267
268 for (i = 0; i < win->num_messages; i++)
269 {
270 if (win->mwm_messages[i] == message)
271 return True;
272 }
273
274 return False;
275 }
276
277 /*
278 * send a mwm specific message
279 */
280 void
PROP_SendMwmMessage(Window w,Atom a,Time timestamp)281 PROP_SendMwmMessage(Window w, Atom a, Time timestamp)
282 {
283 XClientMessageEvent ev;
284
285 ev.type = ClientMessage;
286 ev.window = w;
287 ev.message_type = XA_MWM_MESSAGES;
288 ev.format = 32;
289 ev.data.l[0] = a;
290 ev.data.l[1] = timestamp;
291 XSendEvent(dpy, w, False, 0L, (XEvent *)&ev);
292 }
293
294 /*
295 * Reads the property MOTIF_WM_HINTS
296 */
297 void
PROP_GetMwmHints(MwmWindow * win)298 PROP_GetMwmHints(MwmWindow *win)
299 {
300 int actual_format;
301 Atom actual_type;
302 unsigned long nitems, bytesafter;
303
304 if (XGetWindowProperty(dpy, win->w, XA_MWM_HINTS, 0L,
305 PROP_MOTIF_WM_HINTS_ELEMENTS, False, XA_MWM_HINTS,
306 &actual_type, &actual_format, &nitems, &bytesafter,
307 (unsigned char **)&win->mwm_hints) == Success)
308 {
309
310 if (nitems >= PROP_MOTIF_WM_HINTS_ELEMENTS)
311 {
312 /* Fixup X*Property long == 32 bits confusion if needed */
313 if (sizeof(long) != 4)
314 {
315 long *prop_hints = (long *)win->mwm_hints;
316 win->mwm_hints = XtMalloc(sizeof(MwmHints));
317 win->mwm_hints->flags = prop_hints[0];
318 win->mwm_hints->functions = prop_hints[1];
319 win->mwm_hints->decorations = prop_hints[2];
320 win->mwm_hints->input_mode = prop_hints[3];
321 win->mwm_hints->status = prop_hints[4];
322 XFree(prop_hints);
323 }
324 return;
325 }
326
327 XFree((char *)win->mwm_hints);
328 }
329
330 win->mwm_hints = NULL;
331 }
332
333 /*
334 * Reads the property MOTIF_WM_MENU
335 */
336 void
PROP_GetMwmMenu(MwmWindow * win)337 PROP_GetMwmMenu(MwmWindow *win)
338 {
339 int actual_format;
340 Atom actual_type;
341 unsigned long nitems, bytesafter;
342
343 if (XGetWindowProperty(dpy, win->w, XA_MWM_MENU,
344 0L, 1024L, False,
345 XA_MWM_MENU, &actual_type, &actual_format,
346 &nitems, &bytesafter,
347 (unsigned char **)&win->mwm_menu) == Success)
348 {
349
350 if (bytesafter)
351 fprintf(stderr, "Maximum size of MWM_MENU exceeded\n");
352
353 return;
354 }
355
356 win->mwm_menu = NULL;
357 }
358
359 /*
360 * Reads the property MOTIF_WM_MESSAGES
361 */
362 void
PROP_GetMwmMessages(MwmWindow * win)363 PROP_GetMwmMessages(MwmWindow *win)
364 {
365 int actual_format;
366 Atom actual_type;
367 unsigned long bytesafter;
368
369 if (XGetWindowProperty(dpy, win->w, XA_MWM_MESSAGES, 0L, 1024L, False,
370 AnyPropertyType, &actual_type, &actual_format,
371 &win->num_messages, &bytesafter,
372 (unsigned char **)&win->mwm_messages) == Success)
373 {
374
375 if (bytesafter)
376 fprintf(stderr, "Maximum size of MWM_MESSAGES exceeded: %ld.\n", bytesafter);
377
378 return;
379 }
380
381 win->mwm_messages = NULL;
382 }
383
384 /*
385 * gets application supplied size info
386 */
387 void
PROP_GetWindowSizeHints(MwmWindow * win)388 PROP_GetWindowSizeHints(MwmWindow *win)
389 {
390 long supplied = 0;
391
392 if (!XGetWMNormalHints(dpy, win->w, &win->hints, &supplied))
393 win->hints.flags = 0;
394
395 /* Beat up our copy of the hints, so that all important field are
396 * filled in! */
397 if (win->hints.flags & PResizeInc)
398 {
399 if (win->hints.width_inc == 0)
400 win->hints.width_inc = 1;
401 if (win->hints.height_inc == 0)
402 win->hints.height_inc = 1;
403 }
404 else
405 {
406 win->hints.width_inc = 1;
407 win->hints.height_inc = 1;
408 }
409
410 /*
411 * ICCCM says that PMinSize is the default if no PBaseSize is given,
412 * and vice-versa.
413 */
414
415 if (!(win->hints.flags & PBaseSize))
416 {
417 if (win->hints.flags & PMinSize)
418 {
419 win->hints.base_width = win->hints.min_width;
420 win->hints.base_height = win->hints.min_height;
421 }
422 else
423 {
424 win->hints.base_width = 0;
425 win->hints.base_height = 0;
426 }
427 }
428 if (!(win->hints.flags & PMinSize))
429 {
430 win->hints.min_width = win->hints.base_width;
431 win->hints.min_height = win->hints.base_height;
432 }
433 if (!(win->hints.flags & PMaxSize))
434 {
435 win->hints.max_width = MAX_WINDOW_WIDTH;
436 win->hints.max_height = MAX_WINDOW_HEIGHT;
437 }
438 if (win->hints.max_width < win->hints.min_width)
439 win->hints.max_width = MAX_WINDOW_WIDTH;
440 if (win->hints.max_height < win->hints.min_height)
441 win->hints.max_height = MAX_WINDOW_HEIGHT;
442
443 /* Zero width/height windows are bad news! */
444 if (win->hints.min_height <= 0)
445 win->hints.min_height = 1;
446 if (win->hints.min_width <= 0)
447 win->hints.min_width = 1;
448
449 if (!(win->hints.flags & PWinGravity))
450 {
451 win->hints.win_gravity = NorthWestGravity;
452 win->hints.flags |= PWinGravity;
453 }
454 }
455
456 /*
457 * finds out which protocols the window supports
458 */
459 void
PROP_GetWmProtocols(MwmWindow * win)460 PROP_GetWmProtocols(MwmWindow *win)
461 {
462 unsigned long flags = 0L;
463 Atom *protocols = NULL, *ap;
464 int i, n;
465 Atom atype;
466 int aformat;
467 unsigned long bytes_remain, nitems;
468
469 if (win == NULL)
470 return;
471
472 /*
473 * First, try the Xlib function to read the protocols.
474 * This is what Twm uses.
475 */
476 if (XGetWMProtocols(dpy, win->w, &protocols, &n))
477 {
478 win->flags &= ~(WM_TAKES_FOCUS | WM_DELS_WINDOW | WM_SAVE_SELF | MWM_MESSAGES);
479 for (i = 0, ap = protocols; i < n; i++, ap++)
480 {
481 if (*ap == (Atom)XA_WM_TAKE_FOCUS)
482 flags |= WM_TAKES_FOCUS;
483 if (*ap == (Atom)XA_WM_DELETE_WINDOW)
484 flags |= WM_DELS_WINDOW;
485 if (*ap == (Atom)XA_WM_SAVE_YOURSELF)
486 flags |= WM_SAVE_SELF;
487 if (*ap == (Atom)XA_MWM_MESSAGES)
488 flags |= MWM_MESSAGES;
489 }
490 if (protocols)
491 XFree((char *)protocols);
492 }
493 /*
494 * Next, read it the hard way. mosaic from Coreldraw needs to
495 * be read in this way.
496 */
497 else if ((XGetWindowProperty(dpy, win->w, XA_WM_PROTOCOLS, 0L, 10L, False,
498 XA_WM_PROTOCOLS, &atype, &aformat, &nitems,
499 &bytes_remain,
500 (unsigned char **)&protocols)) == Success)
501 {
502 win->flags &= ~(WM_TAKES_FOCUS | WM_DELS_WINDOW | WM_SAVE_SELF | MWM_MESSAGES);
503 for (i = 0, ap = protocols; (unsigned long)i < nitems; i++, ap++)
504 {
505 if (*ap == (Atom)XA_WM_TAKE_FOCUS)
506 flags |= WM_TAKES_FOCUS;
507 if (*ap == (Atom)XA_WM_DELETE_WINDOW)
508 flags |= WM_DELS_WINDOW;
509 if (*ap == (Atom)XA_WM_SAVE_YOURSELF)
510 flags |= WM_SAVE_SELF;
511 if (*ap == (Atom)XA_MWM_MESSAGES)
512 flags |= MWM_MESSAGES;
513 }
514 if (protocols)
515 XFree((char *)protocols);
516 }
517 win->flags |= flags;
518 }
519
520 /*
521 * Gets the WM_COLORMAP_WINDOWS property from the window
522 * This property typically doesn't exist, but a few applications
523 * use it. These seem to occur mostly on SGI machines.
524 */
525 void
PROP_GetWmColormapWindows(MwmWindow * tmp)526 PROP_GetWmColormapWindows(MwmWindow *tmp)
527 {
528 if (tmp->cmap_windows != (Window *)NULL)
529 XFree((void *)tmp->cmap_windows);
530
531 if (!XGetWMColormapWindows(dpy, tmp->w, &tmp->cmap_windows,
532 &tmp->number_cmap_windows))
533 {
534 tmp->number_cmap_windows = 0;
535 tmp->cmap_windows = NULL;
536 }
537 }
538
539 /*
540 * get the icon name
541 */
542 void
PROP_GetWmIconName(MwmWindow * tmp)543 PROP_GetWmIconName(MwmWindow *tmp)
544 {
545 Atom actual_type;
546 int actual_format;
547 unsigned long nitems, bytesafter;
548 unsigned char *prop;
549
550 if (XGetWindowProperty(dpy, tmp->w, XA_WM_ICON_NAME, 0L, 200L, False,
551 XA_STRING, &actual_type, &actual_format, &nitems,
552 &bytesafter, &prop)
553 == Success && prop != NULL)
554 {
555 tmp->icon_label = (char *)prop; /* FIXME */
556 }
557 }
558