1 /* |
|
2 * Copyright (c) 2001, 2006, Oracle and/or its affiliates. All rights reserved. |
|
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
|
4 * |
|
5 * This code is free software; you can redistribute it and/or modify it |
|
6 * under the terms of the GNU General Public License version 2 only, as |
|
7 * published by the Free Software Foundation. Oracle designates this |
|
8 * particular file as subject to the "Classpath" exception as provided |
|
9 * by Oracle in the LICENSE file that accompanied this code. |
|
10 * |
|
11 * This code is distributed in the hope that it will be useful, but WITHOUT |
|
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
14 * version 2 for more details (a copy is included in the LICENSE file that |
|
15 * accompanied this code). |
|
16 * |
|
17 * You should have received a copy of the GNU General Public License version |
|
18 * 2 along with this work; if not, write to the Free Software Foundation, |
|
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
|
20 * |
|
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
|
22 * or visit www.oracle.com if you need additional information or have any |
|
23 * questions. |
|
24 */ |
|
25 |
|
26 #ifdef HEADLESS |
|
27 #error This file should not be included in headless library |
|
28 #endif |
|
29 |
|
30 /* |
|
31 * Some SCIENCE stuff happens, and it is CONFUSING |
|
32 */ |
|
33 |
|
34 #include "awt_p.h" |
|
35 |
|
36 #include <X11/Xproto.h> |
|
37 #include <X11/Xlib.h> |
|
38 #include <X11/Xatom.h> |
|
39 #include <Xm/MwmUtil.h> |
|
40 |
|
41 /* JNI headers */ |
|
42 #include "java_awt_Frame.h" /* for frame state constants */ |
|
43 |
|
44 #include "awt_wm.h" |
|
45 #include "awt_util.h" /* for X11 error handling macros */ |
|
46 |
|
47 /* |
|
48 * NB: 64 bit awareness. |
|
49 * |
|
50 * Since this code reads/writes window properties heavily, one thing |
|
51 * should be noted well. Xlib uses C type 'long' for properties of |
|
52 * format 32. Fortunately, typedef for Atom is 'long' as well, so |
|
53 * passing property data as or casting returned property data to |
|
54 * arrays of atoms is safe. |
|
55 */ |
|
56 |
|
57 |
|
58 /* |
|
59 * Atoms used to communicate with window manager(s). |
|
60 * Naming convention: |
|
61 * o for atom "FOO" the variable is "XA_FOO" |
|
62 * o for atom "_BAR" the variable is "_XA_BAR" |
|
63 * Don't forget to add initialization to awt_wm_initAtoms below. |
|
64 */ |
|
65 |
|
66 /* |
|
67 * Before WM rototill JDK used to check for running WM by just testing |
|
68 * if certain atom is interned or not. We'd better not confuse older |
|
69 * JDK by interning these atoms. Use awt_wm_atomInterned() to intern |
|
70 * them lazily. |
|
71 * |
|
72 * ENLIGHTENMENT_COMMS |
|
73 * _ICEWM_WINOPTHINT |
|
74 * _SAWMILL_TIMESTAMP |
|
75 * _DT_SM_WINDOW_INFO |
|
76 * _MOTIF_WM_INFO |
|
77 * _SUN_WM_PROTOCOLS |
|
78 */ |
|
79 |
|
80 /* Good old ICCCM */ |
|
81 static Atom XA_WM_STATE; |
|
82 |
|
83 /* New "netwm" spec from www.freedesktop.org */ |
|
84 static Atom XA_UTF8_STRING; /* like STRING but encoding is UTF-8 */ |
|
85 static Atom _XA_NET_SUPPORTING_WM_CHECK; |
|
86 static Atom _XA_NET_SUPPORTED; /* list of protocols (property of root) */ |
|
87 static Atom _XA_NET_WM_NAME; /* window property */ |
|
88 static Atom _XA_NET_WM_STATE; /* both window property and request */ |
|
89 |
|
90 /* |
|
91 * _NET_WM_STATE is a list of atoms. |
|
92 * NB: Standard spelling is "HORZ" (yes, without an 'I'), but KDE2 |
|
93 * uses misspelled "HORIZ" (see KDE bug #20229). This was fixed in |
|
94 * KDE 2.2. Under earlier versions of KDE2 horizontal and full |
|
95 * maximization doesn't work . |
|
96 */ |
|
97 static Atom _XA_NET_WM_STATE_MAXIMIZED_HORZ; |
|
98 static Atom _XA_NET_WM_STATE_MAXIMIZED_VERT; |
|
99 static Atom _XA_NET_WM_STATE_SHADED; |
|
100 static Atom _XA_NET_WM_STATE_ABOVE; |
|
101 static Atom _XA_NET_WM_STATE_BELOW; |
|
102 static Atom _XA_NET_WM_STATE_HIDDEN; |
|
103 |
|
104 /* Currently we only care about max_v and max_h in _NET_WM_STATE */ |
|
105 #define AWT_NET_N_KNOWN_STATES 2 |
|
106 |
|
107 /* Gnome WM spec (superseded by "netwm" above, but still in use) */ |
|
108 static Atom _XA_WIN_SUPPORTING_WM_CHECK; |
|
109 static Atom _XA_WIN_PROTOCOLS; |
|
110 static Atom _XA_WIN_STATE; |
|
111 static Atom _XA_WIN_LAYER; |
|
112 |
|
113 /* Enlightenment */ |
|
114 static Atom _XA_E_FRAME_SIZE; |
|
115 |
|
116 /* KWin (KDE2) */ |
|
117 static Atom _XA_KDE_NET_WM_FRAME_STRUT; |
|
118 |
|
119 /* KWM (KDE 1.x) OBSOLETE??? */ |
|
120 static Atom XA_KWM_WIN_ICONIFIED; |
|
121 static Atom XA_KWM_WIN_MAXIMIZED; |
|
122 |
|
123 /* OpenLook */ |
|
124 static Atom _XA_OL_DECOR_DEL; |
|
125 static Atom _XA_OL_DECOR_HEADER; |
|
126 static Atom _XA_OL_DECOR_RESIZE; |
|
127 static Atom _XA_OL_DECOR_PIN; |
|
128 static Atom _XA_OL_DECOR_CLOSE; |
|
129 |
|
130 /* For _NET_WM_STATE ClientMessage requests */ |
|
131 #define _NET_WM_STATE_REMOVE 0 /* remove/unset property */ |
|
132 #define _NET_WM_STATE_ADD 1 /* add/set property */ |
|
133 #define _NET_WM_STATE_TOGGLE 2 /* toggle property */ |
|
134 |
|
135 /* _WIN_STATE bits */ |
|
136 #define WIN_STATE_STICKY (1<<0) /* everyone knows sticky */ |
|
137 #define WIN_STATE_MINIMIZED (1<<1) /* Reserved - definition is unclear */ |
|
138 #define WIN_STATE_MAXIMIZED_VERT (1<<2) /* window in maximized V state */ |
|
139 #define WIN_STATE_MAXIMIZED_HORIZ (1<<3) /* window in maximized H state */ |
|
140 #define WIN_STATE_HIDDEN (1<<4) /* not on taskbar but window visible*/ |
|
141 #define WIN_STATE_SHADED (1<<5) /* shaded (MacOS / Afterstep style) */ |
|
142 #define WIN_LAYER_ONTOP 6 |
|
143 #define WIN_LAYER_NORMAL 4 |
|
144 |
|
145 #define URGENCY_HINT (1<<8) |
|
146 #define LAYER_ALWAYS_ON_TOP 1 |
|
147 #define LAYER_NORMAL 0 |
|
148 |
|
149 |
|
150 /* |
|
151 * Intern a bunch of atoms we are going use. |
|
152 */ |
|
153 static void |
|
154 awt_wm_initAtoms(void) |
|
155 { |
|
156 /* Minimize X traffic by creating atoms en mass... This requires |
|
157 slightly more code but reduces number of server requests. */ |
|
158 struct atominit { |
|
159 Atom *atomptr; |
|
160 const char *name; |
|
161 }; |
|
162 |
|
163 /* Just add new atoms to this list */ |
|
164 static struct atominit atom_list[] = { |
|
165 { &XA_WM_STATE, "WM_STATE" }, |
|
166 |
|
167 { &XA_UTF8_STRING, "UTF8_STRING" }, |
|
168 |
|
169 { &_XA_NET_SUPPORTING_WM_CHECK, "_NET_SUPPORTING_WM_CHECK" }, |
|
170 { &_XA_NET_SUPPORTED, "_NET_SUPPORTED" }, |
|
171 { &_XA_NET_WM_STATE, "_NET_WM_STATE" }, |
|
172 { &_XA_NET_WM_STATE_MAXIMIZED_VERT, "_NET_WM_STATE_MAXIMIZED_VERT" }, |
|
173 { &_XA_NET_WM_STATE_MAXIMIZED_HORZ, "_NET_WM_STATE_MAXIMIZED_HORZ" }, |
|
174 { &_XA_NET_WM_STATE_SHADED, "_NET_WM_STATE_SHADED" }, |
|
175 { &_XA_NET_WM_STATE_ABOVE, "_NET_WM_STATE_ABOVE" }, |
|
176 { &_XA_NET_WM_STATE_BELOW, "_NET_WM_STATE_BELOW" }, |
|
177 { &_XA_NET_WM_STATE_HIDDEN, "_NET_WM_STATE_HIDDEN" }, |
|
178 { &_XA_NET_WM_NAME, "_NET_WM_NAME" }, |
|
179 |
|
180 { &_XA_WIN_SUPPORTING_WM_CHECK, "_WIN_SUPPORTING_WM_CHECK" }, |
|
181 { &_XA_WIN_PROTOCOLS, "_WIN_PROTOCOLS" }, |
|
182 { &_XA_WIN_STATE, "_WIN_STATE" }, |
|
183 { &_XA_WIN_LAYER, "_WIN_LAYER" }, |
|
184 |
|
185 { &_XA_KDE_NET_WM_FRAME_STRUT, "_KDE_NET_WM_FRAME_STRUT" }, |
|
186 |
|
187 { &_XA_E_FRAME_SIZE, "_E_FRAME_SIZE" }, |
|
188 |
|
189 { &XA_KWM_WIN_ICONIFIED, "KWM_WIN_ICONIFIED" }, |
|
190 { &XA_KWM_WIN_MAXIMIZED, "KWM_WIN_MAXIMIZED" }, |
|
191 |
|
192 { &_XA_OL_DECOR_DEL, "_OL_DECOR_DEL" }, |
|
193 { &_XA_OL_DECOR_HEADER, "_OL_DECOR_HEADER" }, |
|
194 { &_XA_OL_DECOR_RESIZE, "_OL_DECOR_RESIZE" }, |
|
195 { &_XA_OL_DECOR_PIN, "_OL_DECOR_PIN" }, |
|
196 { &_XA_OL_DECOR_CLOSE, "_OL_DECOR_CLOSE" } |
|
197 }; |
|
198 #define ATOM_LIST_LENGTH (sizeof(atom_list)/sizeof(atom_list[0])) |
|
199 |
|
200 const char *names[ATOM_LIST_LENGTH]; |
|
201 Atom atoms[ATOM_LIST_LENGTH]; |
|
202 Status status; |
|
203 size_t i; |
|
204 |
|
205 /* Fill the array of atom names */ |
|
206 for (i = 0; i < ATOM_LIST_LENGTH; ++i) { |
|
207 names[i] = atom_list[i].name; |
|
208 } |
|
209 |
|
210 DTRACE_PRINT("WM: initializing atoms ... "); |
|
211 status = XInternAtoms(awt_display, (char**)names, ATOM_LIST_LENGTH, |
|
212 False, atoms); |
|
213 if (status == 0) { |
|
214 DTRACE_PRINTLN("failed"); |
|
215 return; |
|
216 } |
|
217 |
|
218 /* Store returned atoms into corresponding global variables */ |
|
219 DTRACE_PRINTLN("ok"); |
|
220 for (i = 0; i < ATOM_LIST_LENGTH; ++i) { |
|
221 *atom_list[i].atomptr = atoms[i]; |
|
222 } |
|
223 #undef ATOM_LIST_LENGTH |
|
224 } |
|
225 |
|
226 |
|
227 /* |
|
228 * When checking for various WMs don't intern certain atoms we use to |
|
229 * distinguish those WMs. Rather check if the atom is interned first. |
|
230 * If it's not, further tests are not necessary anyway. |
|
231 * This also saves older JDK a great deal of confusion (4487993). |
|
232 */ |
|
233 static Boolean |
|
234 awt_wm_atomInterned(Atom *pa, const char *name) |
|
235 { |
|
236 DASSERT(pa != NULL); |
|
237 if (*pa == None) { |
|
238 DASSERT(name != NULL); |
|
239 *pa = XInternAtom(awt_display, name, True); |
|
240 if (*pa == None) { |
|
241 DTRACE_PRINTLN1("\"%s\" is not interned", name); |
|
242 return False; |
|
243 } else { |
|
244 return True; |
|
245 } |
|
246 } else { |
|
247 return True; |
|
248 } |
|
249 } |
|
250 |
|
251 |
|
252 |
|
253 /*****************************************************************************\ |
|
254 * |
|
255 * DTRACE utils for various states ... |
|
256 * |
|
257 \*****************************************************************************/ |
|
258 |
|
259 |
|
260 static void |
|
261 awt_wm_dtraceWMState(uint32_t wm_state) |
|
262 { |
|
263 #ifdef DEBUG |
|
264 DTRACE_PRINT("WM_STATE = "); |
|
265 switch (wm_state) { |
|
266 case WithdrawnState: |
|
267 DTRACE_PRINTLN("Withdrawn"); |
|
268 break; |
|
269 case NormalState: |
|
270 DTRACE_PRINTLN("Normal"); |
|
271 break; |
|
272 case IconicState: |
|
273 DTRACE_PRINTLN("Iconic"); |
|
274 break; |
|
275 default: |
|
276 DTRACE_PRINTLN1("unknown state %d", wm_state); |
|
277 break; |
|
278 } |
|
279 #endif /* DEBUG */ |
|
280 } |
|
281 |
|
282 static void |
|
283 awt_wm_dtraceStateNet(Atom *net_wm_state, unsigned long nitems) |
|
284 { |
|
285 #ifdef DEBUG |
|
286 unsigned long i; |
|
287 |
|
288 DTRACE_PRINT("_NET_WM_STATE = {"); |
|
289 for (i = 0; i < nitems; ++i) { |
|
290 char *name, *print_name; |
|
291 name = XGetAtomName(awt_display, net_wm_state[i]); |
|
292 if (name == NULL) { |
|
293 print_name = "???"; |
|
294 } else if (strncmp(name, "_NET_WM_STATE", 13) == 0) { |
|
295 print_name = name + 13; /* skip common prefix to reduce noice */ |
|
296 } else { |
|
297 print_name = name; |
|
298 } |
|
299 DTRACE_PRINT1(" %s", print_name); |
|
300 if (name) { |
|
301 XFree(name); |
|
302 } |
|
303 } |
|
304 DTRACE_PRINTLN(" }"); |
|
305 #endif |
|
306 } |
|
307 |
|
308 |
|
309 static void |
|
310 awt_wm_dtraceStateWin(uint32_t win_state) |
|
311 { |
|
312 #ifdef DEBUG |
|
313 DTRACE_PRINT("_WIN_STATE = {"); |
|
314 if (win_state & WIN_STATE_STICKY) { |
|
315 DTRACE_PRINT(" STICKY"); |
|
316 } |
|
317 if (win_state & WIN_STATE_MINIMIZED) { |
|
318 DTRACE_PRINT(" MINIMIZED"); |
|
319 } |
|
320 if (win_state & WIN_STATE_MAXIMIZED_VERT) { |
|
321 DTRACE_PRINT(" MAXIMIZED_VERT"); |
|
322 } |
|
323 if (win_state & WIN_STATE_MAXIMIZED_HORIZ) { |
|
324 DTRACE_PRINT(" MAXIMIZED_HORIZ"); |
|
325 } |
|
326 if (win_state & WIN_STATE_HIDDEN) { |
|
327 DTRACE_PRINT(" HIDDEN"); |
|
328 } |
|
329 if (win_state & WIN_STATE_SHADED) { |
|
330 DTRACE_PRINT(" SHADED"); |
|
331 } |
|
332 DTRACE_PRINTLN(" }"); |
|
333 #endif |
|
334 } |
|
335 |
|
336 |
|
337 static void |
|
338 awt_wm_dtraceStateJava(jint java_state) |
|
339 { |
|
340 #ifdef DEBUG |
|
341 DTRACE_PRINT("java state = "); |
|
342 if (java_state == java_awt_Frame_NORMAL) { |
|
343 DTRACE_PRINTLN("NORMAL"); |
|
344 } |
|
345 else { |
|
346 DTRACE_PRINT("{"); |
|
347 if (java_state & java_awt_Frame_ICONIFIED) { |
|
348 DTRACE_PRINT(" ICONIFIED"); |
|
349 } |
|
350 if ((java_state & java_awt_Frame_MAXIMIZED_BOTH) |
|
351 == java_awt_Frame_MAXIMIZED_BOTH) |
|
352 { |
|
353 DTRACE_PRINT(" MAXIMIZED_BOTH"); |
|
354 } |
|
355 else if (java_state & java_awt_Frame_MAXIMIZED_HORIZ) { |
|
356 DTRACE_PRINT(" MAXIMIZED_HORIZ"); |
|
357 } |
|
358 else if (java_state & java_awt_Frame_MAXIMIZED_VERT) { |
|
359 DTRACE_PRINT(" MAXIMIZED_VERT"); |
|
360 } |
|
361 DTRACE_PRINTLN(" }"); |
|
362 } |
|
363 #endif /* DEBUG */ |
|
364 } |
|
365 |
|
366 |
|
367 |
|
368 /*****************************************************************************\ |
|
369 * |
|
370 * Utility functions ... |
|
371 * |
|
372 \*****************************************************************************/ |
|
373 |
|
374 /* |
|
375 * Instead of validating window id, we simply call XGetWindowProperty, |
|
376 * but temporary install this function as the error handler to ignore |
|
377 * BadWindow error. |
|
378 */ |
|
379 int /* but ingored */ |
|
380 xerror_ignore_bad_window(Display *dpy, XErrorEvent *err) |
|
381 { |
|
382 XERROR_SAVE(err); |
|
383 if (err->error_code == BadWindow) { |
|
384 DTRACE_PRINTLN("IGNORING BadWindow"); |
|
385 return 0; /* ok to fail */ |
|
386 } |
|
387 else { |
|
388 return (*xerror_saved_handler)(dpy, err); |
|
389 } |
|
390 } |
|
391 |
|
392 |
|
393 /* |
|
394 * Convenience wrapper for XGetWindowProperty for XA_ATOM properties. |
|
395 * E.g. WM_PROTOCOLS, _NET_WM_STATE, _OL_DECOR_DEL. |
|
396 * It's up to caller to XFree returned value. |
|
397 * Number of items returned is stored to nitems_ptr (if non-null). |
|
398 */ |
|
399 static Atom * |
|
400 awt_getAtomListProperty(Window w, Atom property, unsigned long *nitems_ptr) |
|
401 { |
|
402 /* Request status */ |
|
403 int status; |
|
404 |
|
405 /* Returns of XGetWindowProperty */ |
|
406 Atom actual_type; |
|
407 int actual_format; |
|
408 unsigned long nitems_stub; |
|
409 unsigned long bytes_after; |
|
410 Atom *list; |
|
411 |
|
412 if (nitems_ptr == NULL) { |
|
413 /* Caller is not interested in the number of items, |
|
414 provide a stub for XGetWindowProperty */ |
|
415 nitems_ptr = &nitems_stub; |
|
416 } |
|
417 |
|
418 status = XGetWindowProperty(awt_display, w, |
|
419 property, 0, 0xFFFF, False, XA_ATOM, |
|
420 &actual_type, &actual_format, nitems_ptr, &bytes_after, |
|
421 (unsigned char **)&list); |
|
422 |
|
423 if (status != Success || list == NULL) { |
|
424 *nitems_ptr = 0; |
|
425 return NULL; |
|
426 } |
|
427 |
|
428 if (actual_type != XA_ATOM || actual_format != 32) { |
|
429 XFree(list); |
|
430 *nitems_ptr = 0; |
|
431 return NULL; |
|
432 } |
|
433 |
|
434 if (*nitems_ptr == 0) { |
|
435 XFree(list); |
|
436 return NULL; |
|
437 } |
|
438 |
|
439 return list; |
|
440 } |
|
441 |
|
442 |
|
443 /* |
|
444 * Auxiliary function that returns the value of 'property' of type |
|
445 * 'property_type' on window 'w'. Format of the property must be 8. |
|
446 * Terminating zero added by XGetWindowProperty is preserved. |
|
447 * It's up to caller to XFree the result. |
|
448 */ |
|
449 static unsigned char * |
|
450 awt_getProperty8(Window w, Atom property, Atom property_type) |
|
451 { |
|
452 /* Request status */ |
|
453 int status; |
|
454 |
|
455 /* Returns of XGetWindowProperty */ |
|
456 Atom actual_type; |
|
457 int actual_format; |
|
458 unsigned long nitems; |
|
459 unsigned long bytes_after; |
|
460 unsigned char *string; |
|
461 |
|
462 /* BadWindow is ok and will be blocked by our special handler */ |
|
463 WITH_XERROR_HANDLER(xerror_ignore_bad_window); |
|
464 { |
|
465 status = XGetWindowProperty(awt_display, w, |
|
466 property, 0, 0xFFFF, False, property_type, |
|
467 &actual_type, &actual_format, &nitems, &bytes_after, |
|
468 &string); |
|
469 } |
|
470 RESTORE_XERROR_HANDLER; |
|
471 |
|
472 if (status != Success || string == NULL) { |
|
473 return NULL; |
|
474 } |
|
475 |
|
476 if (actual_type != property_type || actual_format != 8) { |
|
477 XFree(string); |
|
478 return NULL; |
|
479 } |
|
480 |
|
481 /* XGetWindowProperty kindly supplies terminating zero */ |
|
482 return string; |
|
483 } |
|
484 |
|
485 |
|
486 /* |
|
487 * Auxiliary function that returns the value of 'property' of type |
|
488 * 'property_type' on window 'w'. Format of the property must be 32. |
|
489 */ |
|
490 static int32_t |
|
491 awt_getProperty32(Window w, Atom property, Atom property_type) |
|
492 { |
|
493 /* Property value*/ |
|
494 int32_t value; |
|
495 |
|
496 /* Request status */ |
|
497 int status; |
|
498 |
|
499 /* Returns of XGetWindowProperty */ |
|
500 Atom actual_type; |
|
501 int actual_format; |
|
502 unsigned long nitems; |
|
503 unsigned long bytes_after; |
|
504 long *data; /* NB: 64 bit: Format 32 props are 'long' */ |
|
505 |
|
506 /* BadWindow is ok and will be blocked by our special handler */ |
|
507 WITH_XERROR_HANDLER(xerror_ignore_bad_window); |
|
508 { |
|
509 status = XGetWindowProperty(awt_display, w, |
|
510 property, 0, 1, False, property_type, |
|
511 &actual_type, &actual_format, &nitems, &bytes_after, |
|
512 (unsigned char **)&data); |
|
513 } |
|
514 RESTORE_XERROR_HANDLER; |
|
515 |
|
516 if (status != Success || data == NULL) { |
|
517 return 0; |
|
518 } |
|
519 |
|
520 if (actual_type != property_type || actual_format != 32) { |
|
521 XFree(data); /* NULL data already catched above */ |
|
522 return 0; |
|
523 } |
|
524 |
|
525 value = (int32_t)*data; |
|
526 XFree(data); |
|
527 |
|
528 return value; |
|
529 } |
|
530 |
|
531 |
|
532 |
|
533 /*****************************************************************************\ |
|
534 * |
|
535 * Detecting WM ... |
|
536 * |
|
537 \*****************************************************************************/ |
|
538 |
|
539 |
|
540 |
|
541 /* |
|
542 * Check for anchor_prop(anchor_type) on root, take the value as the |
|
543 * window id and check if that window exists and has anchor_prop(anchor_type) |
|
544 * with the same value (i.e. pointing back to self). |
|
545 * |
|
546 * Returns the anchor window, as some WM may put interesting stuff in |
|
547 * its properties (e.g. sawfish). |
|
548 */ |
|
549 static Window |
|
550 awt_wm_checkAnchor(Atom anchor_prop, Atom anchor_type) |
|
551 { |
|
552 Window root_xref; |
|
553 Window self_xref; |
|
554 |
|
555 root_xref = (Window)awt_getProperty32(DefaultRootWindow(awt_display), |
|
556 anchor_prop, anchor_type); |
|
557 if (root_xref == None) { |
|
558 DTRACE_PRINTLN("no"); |
|
559 return None; |
|
560 } |
|
561 |
|
562 DTRACE_PRINT1("0x%x ... ", (unsigned int)root_xref); |
|
563 self_xref = (Window)awt_getProperty32(root_xref, |
|
564 anchor_prop, anchor_type); |
|
565 if (self_xref != root_xref) { |
|
566 DTRACE_PRINTLN("stale"); |
|
567 return None; |
|
568 } |
|
569 |
|
570 DTRACE_PRINTLN("ok"); |
|
571 return self_xref; |
|
572 } |
|
573 |
|
574 |
|
575 /* |
|
576 * New WM spec: KDE 2.0.1, sawfish 0.3x, ... |
|
577 * <http://www.freedesktop.org/standards/wm-spec.html> |
|
578 */ |
|
579 static Window |
|
580 awt_wm_isNetSupporting(void) |
|
581 { |
|
582 static Boolean checked = False; |
|
583 static Window isNetSupporting = None; |
|
584 |
|
585 if (checked) { |
|
586 return isNetSupporting; |
|
587 } |
|
588 |
|
589 DTRACE_PRINT("WM: checking for _NET_SUPPORTING ... "); |
|
590 isNetSupporting = awt_wm_checkAnchor(_XA_NET_SUPPORTING_WM_CHECK, |
|
591 XA_WINDOW); |
|
592 checked = True; |
|
593 return isNetSupporting; |
|
594 } |
|
595 |
|
596 |
|
597 /* |
|
598 * Old Gnome WM spec: WindowMaker, Enlightenment, IceWM ... |
|
599 * <http://developer.gnome.org/doc/standards/wm/book1.html> |
|
600 */ |
|
601 static Window |
|
602 awt_wm_isWinSupporting(void) |
|
603 { |
|
604 static Boolean checked = False; |
|
605 static Window isWinSupporting = None; |
|
606 |
|
607 if (checked) { |
|
608 return isWinSupporting; |
|
609 } |
|
610 |
|
611 DTRACE_PRINT("WM: checking for _WIN_SUPPORTING ... "); |
|
612 isWinSupporting = awt_wm_checkAnchor(_XA_WIN_SUPPORTING_WM_CHECK, |
|
613 XA_CARDINAL); |
|
614 checked = True; |
|
615 return isWinSupporting; |
|
616 } |
|
617 |
|
618 |
|
619 /* |
|
620 * Check that that the list of protocols specified by WM in property |
|
621 * named LIST_NAME on the root window contains protocol PROTO. |
|
622 */ |
|
623 static Boolean |
|
624 awt_wm_checkProtocol(Atom list_name, Atom proto) |
|
625 { |
|
626 Atom *protocols; |
|
627 unsigned long nproto; |
|
628 Boolean found; |
|
629 unsigned long i; |
|
630 |
|
631 protocols = awt_getAtomListProperty(DefaultRootWindow(awt_display), |
|
632 list_name, &nproto); |
|
633 if (protocols == NULL) { |
|
634 return False; |
|
635 } |
|
636 |
|
637 found = False; |
|
638 for (i = 0; i < nproto; ++i) { |
|
639 if (protocols[i] == proto) { |
|
640 found = True; |
|
641 break; |
|
642 } |
|
643 } |
|
644 |
|
645 if (protocols != NULL) { |
|
646 XFree(protocols); |
|
647 } |
|
648 return found; |
|
649 } |
|
650 |
|
651 static Boolean |
|
652 awt_wm_doStateProtocolNet(void) |
|
653 { |
|
654 static Boolean checked = False; |
|
655 static Boolean supported = False; |
|
656 |
|
657 if (checked) { |
|
658 return supported; |
|
659 } |
|
660 |
|
661 if (awt_wm_isNetSupporting()) { |
|
662 DTRACE_PRINT("WM: checking for _NET_WM_STATE in _NET_SUPPORTED ... "); |
|
663 supported = awt_wm_checkProtocol(_XA_NET_SUPPORTED, _XA_NET_WM_STATE); |
|
664 DTRACE_PRINTLN1("%s", supported ? "yes" : "no"); |
|
665 } |
|
666 |
|
667 checked = True; |
|
668 return supported; |
|
669 } |
|
670 |
|
671 static Boolean |
|
672 awt_wm_doStateProtocolWin(void) |
|
673 { |
|
674 static Boolean checked = False; |
|
675 static Boolean supported = False; |
|
676 |
|
677 if (checked) { |
|
678 return supported; |
|
679 } |
|
680 |
|
681 if (awt_wm_isWinSupporting()) { |
|
682 DTRACE_PRINT("WM: checking for _WIN_STATE in _WIN_PROTOCOLS ... "); |
|
683 supported = awt_wm_checkProtocol(_XA_WIN_PROTOCOLS, _XA_WIN_STATE); |
|
684 DTRACE_PRINTLN1("%s", supported ? "yes" : "no"); |
|
685 } |
|
686 checked = True; |
|
687 return supported; |
|
688 } |
|
689 |
|
690 |
|
691 |
|
692 /* |
|
693 * Helper function for awt_wm_isEnlightenment. |
|
694 * Enlightenment uses STRING property for its comms window id. Gaaa! |
|
695 * The property is ENLIGHTENMENT_COMMS, STRING/8 and the string format |
|
696 * is "WINID %8x". Gee, I haven't been using scanf for *ages*... :-) |
|
697 */ |
|
698 static Window |
|
699 awt_getECommsWindowIDProperty(Window w) |
|
700 { |
|
701 static Atom XA_ENLIGHTENMENT_COMMS = None; |
|
702 |
|
703 /* Property value*/ |
|
704 Window value; |
|
705 |
|
706 /* Request status */ |
|
707 int status; |
|
708 |
|
709 /* Returns of XGetWindowProperty */ |
|
710 Atom actual_type; |
|
711 int actual_format; |
|
712 unsigned long nitems; |
|
713 unsigned long bytes_after; |
|
714 unsigned char *data; |
|
715 |
|
716 if (!awt_wm_atomInterned(&XA_ENLIGHTENMENT_COMMS, "ENLIGHTENMENT_COMMS")) { |
|
717 return False; |
|
718 } |
|
719 |
|
720 /* BadWindow is ok and will be blocked by our special handler */ |
|
721 WITH_XERROR_HANDLER(xerror_ignore_bad_window); |
|
722 { |
|
723 status = XGetWindowProperty(awt_display, w, |
|
724 XA_ENLIGHTENMENT_COMMS, 0, 14, False, XA_STRING, |
|
725 &actual_type, &actual_format, &nitems, &bytes_after, |
|
726 &data); |
|
727 } |
|
728 RESTORE_XERROR_HANDLER; |
|
729 |
|
730 if (status != Success || data == NULL) { |
|
731 DTRACE_PRINTLN("no ENLIGHTENMENT_COMMS"); |
|
732 return None; |
|
733 } |
|
734 |
|
735 if (actual_type != XA_STRING || actual_format != 8 |
|
736 || nitems != 14 || bytes_after != 0) |
|
737 { |
|
738 DTRACE_PRINTLN("malformed ENLIGHTENMENT_COMMS"); |
|
739 XFree(data); /* NULL data already catched above */ |
|
740 return None; |
|
741 } |
|
742 |
|
743 value = None; |
|
744 sscanf((char *)data, "WINID %8lx", &value); /* NB: 64 bit: XID is long */ |
|
745 XFree(data); |
|
746 |
|
747 return value; |
|
748 } |
|
749 |
|
750 |
|
751 /* |
|
752 * Is Enlightenment WM running? Congruent to awt_wm_checkAnchor, but |
|
753 * uses STRING property peculiar to Enlightenment. |
|
754 */ |
|
755 static Boolean |
|
756 awt_wm_isEnlightenment(void) |
|
757 { |
|
758 Window root_xref; |
|
759 Window self_xref; |
|
760 |
|
761 DTRACE_PRINT("WM: checking for Enlightenment ... "); |
|
762 root_xref = awt_getECommsWindowIDProperty(DefaultRootWindow(awt_display)); |
|
763 if (root_xref == None) { |
|
764 return False; |
|
765 } |
|
766 |
|
767 DTRACE_PRINT1("0x%x ... ", root_xref); |
|
768 self_xref = awt_getECommsWindowIDProperty(root_xref); |
|
769 if (self_xref != root_xref) { |
|
770 return False; |
|
771 } |
|
772 |
|
773 DTRACE_PRINTLN("ok"); |
|
774 return True; |
|
775 } |
|
776 |
|
777 |
|
778 /* |
|
779 * Is CDE running? |
|
780 * |
|
781 * XXX: This is hairy... CDE is MWM as well. It seems we simply test |
|
782 * for default setup and will be bitten if user changes things... |
|
783 * |
|
784 * Check for _DT_SM_WINDOW_INFO(_DT_SM_WINDOW_INFO) on root. Take the |
|
785 * second element of the property and check for presence of |
|
786 * _DT_SM_STATE_INFO(_DT_SM_STATE_INFO) on that window. |
|
787 * |
|
788 * XXX: Any header that defines this structures??? |
|
789 */ |
|
790 static Boolean |
|
791 awt_wm_isCDE(void) |
|
792 { |
|
793 static Atom _XA_DT_SM_WINDOW_INFO = None; |
|
794 static Atom _XA_DT_SM_STATE_INFO = None; |
|
795 |
|
796 /* Property value*/ |
|
797 Window wmwin; |
|
798 |
|
799 /* Request status */ |
|
800 int status; |
|
801 |
|
802 /* Returns of XGetWindowProperty */ |
|
803 Atom actual_type; |
|
804 int actual_format; |
|
805 unsigned long nitems; |
|
806 unsigned long bytes_after; |
|
807 long *data; /* NB: 64 bit: Format 32 props are 'long' */ |
|
808 |
|
809 DTRACE_PRINT("WM: checking for CDE ... "); |
|
810 |
|
811 if (!awt_wm_atomInterned(&_XA_DT_SM_WINDOW_INFO, "_DT_SM_WINDOW_INFO")) { |
|
812 return False; |
|
813 } |
|
814 |
|
815 status = XGetWindowProperty(awt_display, DefaultRootWindow(awt_display), |
|
816 _XA_DT_SM_WINDOW_INFO, 0, 2, False, _XA_DT_SM_WINDOW_INFO, |
|
817 &actual_type, &actual_format, &nitems, &bytes_after, |
|
818 (unsigned char **)&data); |
|
819 |
|
820 if (status != Success || data == NULL) { |
|
821 DTRACE_PRINTLN("no _DT_SM_WINDOW_INFO on root"); |
|
822 return False; |
|
823 } |
|
824 |
|
825 if (actual_type != _XA_DT_SM_WINDOW_INFO || actual_format != 32 |
|
826 || nitems != 2 || bytes_after != 0) |
|
827 { |
|
828 DTRACE_PRINTLN("malformed _DT_SM_WINDOW_INFO on root"); |
|
829 XFree(data); /* NULL data already catched above */ |
|
830 return False; |
|
831 } |
|
832 |
|
833 wmwin = (Window)data[1]; |
|
834 XFree(data); |
|
835 |
|
836 /* Now check that this window has _DT_SM_STATE_INFO (ignore contents) */ |
|
837 |
|
838 if (!awt_wm_atomInterned(&_XA_DT_SM_STATE_INFO, "_DT_SM_STATE_INFO")) { |
|
839 return False; |
|
840 } |
|
841 |
|
842 /* BadWindow is ok and will be blocked by our special handler */ |
|
843 WITH_XERROR_HANDLER(xerror_ignore_bad_window); |
|
844 { |
|
845 status = XGetWindowProperty(awt_display, wmwin, |
|
846 _XA_DT_SM_STATE_INFO, 0, 1, False, _XA_DT_SM_STATE_INFO, |
|
847 &actual_type, &actual_format, &nitems, &bytes_after, |
|
848 (unsigned char **)&data); |
|
849 } |
|
850 RESTORE_XERROR_HANDLER; |
|
851 |
|
852 if (status != Success || data == NULL) { |
|
853 DTRACE_PRINTLN("no _DT_SM_STATE_INFO"); |
|
854 return False; |
|
855 } |
|
856 |
|
857 if (actual_type != _XA_DT_SM_STATE_INFO || actual_format != 32) { |
|
858 DTRACE_PRINTLN("malformed _DT_SM_STATE_INFO"); |
|
859 XFree(data); /* NULL data already catched above */ |
|
860 return False; |
|
861 } |
|
862 |
|
863 DTRACE_PRINTLN("yes"); |
|
864 XFree(data); |
|
865 return True; |
|
866 } |
|
867 |
|
868 /* |
|
869 * Is MWM running? (Note that CDE will test positive as well). |
|
870 * |
|
871 * Check for _MOTIF_WM_INFO(_MOTIF_WM_INFO) on root. Take the |
|
872 * second element of the property and check for presence of |
|
873 * _DT_SM_STATE_INFO(_DT_SM_STATE_INFO) on that window. |
|
874 */ |
|
875 static Boolean |
|
876 awt_wm_isMotif(void) |
|
877 { |
|
878 /* |
|
879 * Grr. Motif just had to be different, ain't it!? Everyone use |
|
880 * "XA" for things of type Atom, but motif folks chose to define |
|
881 * _XA_MOTIF_* to be atom *names*. How pathetic... |
|
882 */ |
|
883 #undef _XA_MOTIF_WM_INFO |
|
884 static Atom _XA_MOTIF_WM_INFO = None; |
|
885 static Atom _XA_DT_WORKSPACE_CURRENT = None; |
|
886 |
|
887 /* Property value */ |
|
888 Window wmwin; |
|
889 Atom *curws; |
|
890 |
|
891 /* Request status */ |
|
892 int status; |
|
893 |
|
894 /* Returns of XGetWindowProperty */ |
|
895 Atom actual_type; |
|
896 int actual_format; |
|
897 unsigned long nitems; |
|
898 unsigned long bytes_after; |
|
899 long *data; /* NB: 64 bit: Format 32 props are 'long' */ |
|
900 |
|
901 DTRACE_PRINT("WM: checking for MWM ... "); |
|
902 |
|
903 if (!awt_wm_atomInterned(&_XA_MOTIF_WM_INFO, "_MOTIF_WM_INFO") |
|
904 || !awt_wm_atomInterned(&_XA_DT_WORKSPACE_CURRENT, "_DT_WORKSPACE_CURRENT")) |
|
905 { |
|
906 return False; |
|
907 } |
|
908 |
|
909 |
|
910 status = XGetWindowProperty(awt_display, DefaultRootWindow(awt_display), |
|
911 _XA_MOTIF_WM_INFO, 0, PROP_MOTIF_WM_INFO_ELEMENTS, False, |
|
912 _XA_MOTIF_WM_INFO, &actual_type, |
|
913 &actual_format, &nitems, &bytes_after, |
|
914 (unsigned char **)&data); |
|
915 |
|
916 if (status != Success || data == NULL) { |
|
917 DTRACE_PRINTLN("no _MOTIF_WM_INFO on root"); |
|
918 return False; |
|
919 } |
|
920 |
|
921 if (actual_type != _XA_MOTIF_WM_INFO || actual_format != 32 |
|
922 || nitems != PROP_MOTIF_WM_INFO_ELEMENTS || bytes_after != 0) |
|
923 { |
|
924 DTRACE_PRINTLN("malformed _MOTIF_WM_INFO on root"); |
|
925 XFree(data); /* NULL data already catched above */ |
|
926 return False; |
|
927 } |
|
928 |
|
929 /* NB: 64 bit: Cannot cast data to MotifWmInfo */ |
|
930 wmwin = (Window)data[1]; |
|
931 XFree(data); |
|
932 |
|
933 /* Now check that this window has _DT_WORKSPACE_CURRENT */ |
|
934 curws = awt_getAtomListProperty(wmwin, _XA_DT_WORKSPACE_CURRENT, NULL); |
|
935 if (curws == NULL) { |
|
936 DTRACE_PRINTLN("no _DT_WORKSPACE_CURRENT"); |
|
937 return False; |
|
938 } |
|
939 |
|
940 DTRACE_PRINTLN("yes"); |
|
941 XFree(curws); |
|
942 return True; |
|
943 } |
|
944 |
|
945 |
|
946 static Boolean |
|
947 awt_wm_isNetWMName(char *name) |
|
948 { |
|
949 Window anchor; |
|
950 unsigned char *net_wm_name; |
|
951 Boolean matched; |
|
952 |
|
953 anchor = awt_wm_isNetSupporting(); |
|
954 if (anchor == None) { |
|
955 return False; |
|
956 } |
|
957 |
|
958 DTRACE_PRINT1("WM: checking for %s by _NET_WM_NAME ... ", name); |
|
959 |
|
960 /* |
|
961 * Check both UTF8_STRING and STRING. We only call this function |
|
962 * with ASCII names and UTF8 preserves ASCII bit-wise. wm-spec |
|
963 * mandates UTF8_STRING for _NET_WM_NAME but at least sawfish-1.0 |
|
964 * still uses STRING. (mmm, moving targets...). |
|
965 */ |
|
966 net_wm_name = awt_getProperty8(anchor, _XA_NET_WM_NAME, XA_UTF8_STRING); |
|
967 if (net_wm_name == NULL) { |
|
968 net_wm_name = awt_getProperty8(anchor, _XA_NET_WM_NAME, XA_STRING); |
|
969 } |
|
970 |
|
971 if (net_wm_name == NULL) { |
|
972 DTRACE_PRINTLN("no (missing _NET_WM_NAME)"); |
|
973 return False; |
|
974 } |
|
975 |
|
976 matched = (strcmp((char *)net_wm_name, name) == 0); |
|
977 if (matched) { |
|
978 DTRACE_PRINTLN("yes"); |
|
979 } else { |
|
980 DTRACE_PRINTLN1("no (_NET_WM_NAME = \"%s\")", net_wm_name); |
|
981 } |
|
982 XFree(net_wm_name); |
|
983 return matched; |
|
984 } |
|
985 |
|
986 /* |
|
987 * Is Sawfish running? |
|
988 */ |
|
989 static Boolean |
|
990 awt_wm_isSawfish(void) |
|
991 { |
|
992 return awt_wm_isNetWMName("Sawfish"); |
|
993 } |
|
994 |
|
995 /* |
|
996 * Is KDE2 (KWin) running? |
|
997 */ |
|
998 static Boolean |
|
999 awt_wm_isKDE2(void) |
|
1000 { |
|
1001 return awt_wm_isNetWMName("KWin"); |
|
1002 } |
|
1003 |
|
1004 |
|
1005 /* |
|
1006 * Is Metacity running? |
|
1007 */ |
|
1008 static Boolean |
|
1009 awt_wm_isMetacity(void) |
|
1010 { |
|
1011 return awt_wm_isNetWMName("Metacity"); |
|
1012 } |
|
1013 |
|
1014 |
|
1015 /* |
|
1016 * Temporary error handler that ensures that we know if |
|
1017 * XChangeProperty succeeded or not. |
|
1018 */ |
|
1019 static int /* but ignored */ |
|
1020 xerror_verify_change_property(Display *dpy, XErrorEvent *err) |
|
1021 { |
|
1022 XERROR_SAVE(err); |
|
1023 if (err->request_code == X_ChangeProperty) { |
|
1024 return 0; |
|
1025 } |
|
1026 else { |
|
1027 return (*xerror_saved_handler)(dpy, err); |
|
1028 } |
|
1029 } |
|
1030 |
|
1031 |
|
1032 /* |
|
1033 * Prepare IceWM check. |
|
1034 * |
|
1035 * The only way to detect IceWM, seems to be by setting |
|
1036 * _ICEWM_WINOPTHINT(_ICEWM_WINOPTHINT/8) on root and checking if it |
|
1037 * was immediately deleted by IceWM. |
|
1038 * |
|
1039 * But messing with PropertyNotify here is way too much trouble, so |
|
1040 * approximate the check by setting the property in this function and |
|
1041 * checking if it still exists later on. |
|
1042 * |
|
1043 * Gaa, dirty dances... |
|
1044 */ |
|
1045 static Boolean |
|
1046 awt_wm_prepareIsIceWM(void) |
|
1047 { |
|
1048 static Atom _XA_ICEWM_WINOPTHINT = None; |
|
1049 |
|
1050 /* |
|
1051 * Choose something innocuous: "AWT_ICEWM_TEST allWorkspaces 0". |
|
1052 * IceWM expects "class\0option\0arg\0" with zero bytes as delimiters. |
|
1053 */ |
|
1054 static unsigned char opt[] = { |
|
1055 'A','W','T','_','I','C','E','W','M','_','T','E','S','T','\0', |
|
1056 'a','l','l','W','o','r','k','s','p','a','c','e','s','\0', |
|
1057 '0','\0' |
|
1058 }; |
|
1059 |
|
1060 DTRACE_PRINT("WM: scheduling check for IceWM ... "); |
|
1061 |
|
1062 if (!awt_wm_atomInterned(&_XA_ICEWM_WINOPTHINT, "_ICEWM_WINOPTHINT")) { |
|
1063 return False; |
|
1064 } |
|
1065 |
|
1066 WITH_XERROR_HANDLER(xerror_verify_change_property); |
|
1067 { |
|
1068 XChangeProperty(awt_display, DefaultRootWindow(awt_display), |
|
1069 _XA_ICEWM_WINOPTHINT, _XA_ICEWM_WINOPTHINT, 8, |
|
1070 PropModeReplace, opt, sizeof(opt)); |
|
1071 } |
|
1072 RESTORE_XERROR_HANDLER; |
|
1073 |
|
1074 if (xerror_code != Success) { |
|
1075 DTRACE_PRINTLN1("can't set _ICEWM_WINOPTHINT, error = %d", |
|
1076 xerror_code); |
|
1077 return False; |
|
1078 } |
|
1079 else { |
|
1080 DTRACE_PRINTLN("scheduled"); |
|
1081 return True; |
|
1082 } |
|
1083 } |
|
1084 |
|
1085 /* |
|
1086 * Is IceWM running? |
|
1087 * |
|
1088 * Note well: Only call this if awt_wm_prepareIsIceWM succeeded, or a |
|
1089 * false positive will be reported. |
|
1090 */ |
|
1091 static Boolean |
|
1092 awt_wm_isIceWM(void) |
|
1093 { |
|
1094 static Atom _XA_ICEWM_WINOPTHINT = None; |
|
1095 |
|
1096 /* Request status */ |
|
1097 int status; |
|
1098 |
|
1099 /* Returns of XGetWindowProperty */ |
|
1100 Atom actual_type; |
|
1101 int actual_format; |
|
1102 unsigned long nitems; |
|
1103 unsigned long bytes_after; |
|
1104 unsigned char *data; |
|
1105 |
|
1106 DTRACE_PRINT("WM: checking for IceWM ... "); |
|
1107 |
|
1108 if (!awt_wm_atomInterned(&_XA_ICEWM_WINOPTHINT, "_ICEWM_WINOPTHINT")) { |
|
1109 return False; |
|
1110 } |
|
1111 |
|
1112 XGetWindowProperty(awt_display, DefaultRootWindow(awt_display), |
|
1113 _XA_ICEWM_WINOPTHINT, 0, 0xFFFF, True, /* NB: deleting! */ |
|
1114 _XA_ICEWM_WINOPTHINT, &actual_type, |
|
1115 &actual_format, &nitems, &bytes_after, |
|
1116 &data); |
|
1117 |
|
1118 if (data != NULL) { |
|
1119 XFree(data); |
|
1120 } |
|
1121 |
|
1122 if (actual_type == None) { |
|
1123 DTRACE_PRINTLN("yes"); |
|
1124 return True; |
|
1125 } |
|
1126 else { |
|
1127 DTRACE_PRINTLN("no"); |
|
1128 return False; |
|
1129 } |
|
1130 } |
|
1131 |
|
1132 /* |
|
1133 * Is OpenLook WM running? |
|
1134 * |
|
1135 * This one is pretty lame, but the only property peculiar to OLWM is |
|
1136 * _SUN_WM_PROTOCOLS(ATOM[]). Fortunately, olwm deletes it on exit. |
|
1137 */ |
|
1138 static Boolean |
|
1139 awt_wm_isOpenLook(void) |
|
1140 { |
|
1141 static Atom _XA_SUN_WM_PROTOCOLS = None; |
|
1142 Atom *list; |
|
1143 |
|
1144 DTRACE_PRINT("WM: checking for OpenLook WM ... "); |
|
1145 |
|
1146 if (!awt_wm_atomInterned(&_XA_SUN_WM_PROTOCOLS, "_SUN_WM_PROTOCOLS")) { |
|
1147 return False; |
|
1148 } |
|
1149 |
|
1150 list = awt_getAtomListProperty(DefaultRootWindow(awt_display), |
|
1151 _XA_SUN_WM_PROTOCOLS, NULL); |
|
1152 if (list == NULL) { |
|
1153 DTRACE_PRINTLN("no _SUN_WM_PROTOCOLS on root"); |
|
1154 return False; |
|
1155 } |
|
1156 |
|
1157 DTRACE_PRINTLN("yes"); |
|
1158 XFree(list); |
|
1159 return True; |
|
1160 } |
|
1161 |
|
1162 |
|
1163 |
|
1164 static Boolean winmgr_running = False; |
|
1165 |
|
1166 /* |
|
1167 * Temporary error handler that checks if selecting for |
|
1168 * SubstructureRedirect failed. |
|
1169 */ |
|
1170 static int /* but ignored */ |
|
1171 xerror_detect_wm(Display *dpy, XErrorEvent *err) |
|
1172 { |
|
1173 XERROR_SAVE(err); |
|
1174 if (err->request_code == X_ChangeWindowAttributes |
|
1175 && err->error_code == BadAccess) |
|
1176 { |
|
1177 DTRACE_PRINTLN("some WM is running (hmm, we'll see)"); |
|
1178 winmgr_running = True; |
|
1179 return 0; |
|
1180 } |
|
1181 else { |
|
1182 return (*xerror_saved_handler)(dpy, err); |
|
1183 } |
|
1184 } |
|
1185 |
|
1186 |
|
1187 /* |
|
1188 * Make an educated guess about running window manager. |
|
1189 * XXX: ideally, we should detect wm restart. |
|
1190 */ |
|
1191 enum wmgr_t |
|
1192 awt_wm_getRunningWM(void) |
|
1193 { |
|
1194 /* |
|
1195 * Ideally, we should support cases when a different WM is started |
|
1196 * during a Java app lifetime. |
|
1197 */ |
|
1198 static enum wmgr_t awt_wmgr = UNDETERMINED_WM; |
|
1199 |
|
1200 XSetWindowAttributes substruct; |
|
1201 const char *vendor_string; |
|
1202 Boolean doIsIceWM; |
|
1203 |
|
1204 if (awt_wmgr != UNDETERMINED_WM) { |
|
1205 return awt_wmgr; |
|
1206 } |
|
1207 |
|
1208 /* |
|
1209 * Quick checks for specific servers. |
|
1210 */ |
|
1211 vendor_string = ServerVendor(awt_display); |
|
1212 if (strstr(vendor_string, "eXcursion") != NULL) { |
|
1213 /* |
|
1214 * Use NO_WM since in all other aspects eXcursion is like not |
|
1215 * having a window manager running. I.e. it does not reparent |
|
1216 * top level shells. |
|
1217 */ |
|
1218 DTRACE_PRINTLN("WM: eXcursion detected - treating as NO_WM"); |
|
1219 awt_wmgr = NO_WM; |
|
1220 return awt_wmgr; |
|
1221 } |
|
1222 |
|
1223 /* |
|
1224 * If *any* window manager is running? |
|
1225 * |
|
1226 * Try selecting for SubstructureRedirect, that only one client |
|
1227 * can select for, and if the request fails, than some other WM is |
|
1228 * already running. |
|
1229 */ |
|
1230 winmgr_running = 0; |
|
1231 substruct.event_mask = SubstructureRedirectMask; |
|
1232 |
|
1233 DTRACE_PRINT("WM: trying SubstructureRedirect ... "); |
|
1234 WITH_XERROR_HANDLER(xerror_detect_wm); |
|
1235 { |
|
1236 XChangeWindowAttributes(awt_display, DefaultRootWindow(awt_display), |
|
1237 CWEventMask, &substruct); |
|
1238 } |
|
1239 RESTORE_XERROR_HANDLER; |
|
1240 |
|
1241 /* |
|
1242 * If no WM is running than our selection for SubstructureRedirect |
|
1243 * succeeded and needs to be undone (hey we are *not* a WM ;-). |
|
1244 */ |
|
1245 if (!winmgr_running) { |
|
1246 DTRACE_PRINTLN("no WM is running"); |
|
1247 awt_wmgr = NO_WM; |
|
1248 substruct.event_mask = 0; |
|
1249 XChangeWindowAttributes(awt_display, DefaultRootWindow(awt_display), |
|
1250 CWEventMask, &substruct); |
|
1251 return NO_WM; |
|
1252 } |
|
1253 |
|
1254 /* actual check for IceWM to follow below */ |
|
1255 doIsIceWM = awt_wm_prepareIsIceWM(); /* and let IceWM to act */ |
|
1256 |
|
1257 if (awt_wm_isNetSupporting()) { |
|
1258 awt_wm_doStateProtocolNet(); |
|
1259 } |
|
1260 if (awt_wm_isWinSupporting()) { |
|
1261 awt_wm_doStateProtocolWin(); |
|
1262 } |
|
1263 |
|
1264 /* |
|
1265 * Ok, some WM is out there. Check which one by testing for |
|
1266 * "distinguishing" atoms. |
|
1267 */ |
|
1268 if (doIsIceWM && awt_wm_isIceWM()) { |
|
1269 awt_wmgr = ICE_WM; |
|
1270 } |
|
1271 else if (awt_wm_isEnlightenment()) { |
|
1272 awt_wmgr = ENLIGHTEN_WM; |
|
1273 } |
|
1274 else if (awt_wm_isMetacity()) { |
|
1275 awt_wmgr = METACITY_WM; |
|
1276 } |
|
1277 else if (awt_wm_isSawfish()) { |
|
1278 awt_wmgr = SAWFISH_WM; |
|
1279 } |
|
1280 else if (awt_wm_isKDE2()) { |
|
1281 awt_wmgr = KDE2_WM; |
|
1282 } |
|
1283 /* |
|
1284 * We don't check for legacy WM when we already know that WM |
|
1285 * supports WIN or _NET wm spec. |
|
1286 */ |
|
1287 else if (awt_wm_isNetSupporting()) { |
|
1288 DTRACE_PRINTLN("WM: other WM (supports _NET)"); |
|
1289 awt_wmgr = OTHER_WM; |
|
1290 } |
|
1291 else if (awt_wm_isWinSupporting()) { |
|
1292 DTRACE_PRINTLN("WM: other WM (supports _WIN)"); |
|
1293 awt_wmgr = OTHER_WM; |
|
1294 } |
|
1295 /* |
|
1296 * Check for legacy WMs. |
|
1297 */ |
|
1298 else if (awt_wm_isCDE()) { /* XXX: must come before isMotif */ |
|
1299 awt_wmgr = CDE_WM; |
|
1300 } |
|
1301 else if (awt_wm_isMotif()) { |
|
1302 awt_wmgr = MOTIF_WM; |
|
1303 } |
|
1304 else if (awt_wm_isOpenLook()) { |
|
1305 awt_wmgr = OPENLOOK_WM; |
|
1306 } |
|
1307 else { |
|
1308 DTRACE_PRINTLN("WM: some other legacy WM"); |
|
1309 awt_wmgr = OTHER_WM; |
|
1310 } |
|
1311 |
|
1312 return awt_wmgr; |
|
1313 } |
|
1314 |
|
1315 |
|
1316 /* |
|
1317 * Some buggy WMs ignore window gravity when processing |
|
1318 * ConfigureRequest and position window as if the gravity is Static. |
|
1319 * We work around this in MWindowPeer.pReshape(). |
|
1320 */ |
|
1321 Boolean |
|
1322 awt_wm_configureGravityBuggy(void) |
|
1323 { |
|
1324 static int env_not_checked = 1; |
|
1325 static int env_buggy = 0; |
|
1326 |
|
1327 if (env_not_checked) { |
|
1328 DTRACE_PRINT("WM: checking for _JAVA_AWT_WM_STATIC_GRAVITY in environment ... "); |
|
1329 if (getenv("_JAVA_AWT_WM_STATIC_GRAVITY") != NULL) { |
|
1330 DTRACE_PRINTLN("set"); |
|
1331 env_buggy = 1; |
|
1332 } else { |
|
1333 DTRACE_PRINTLN("no"); |
|
1334 } |
|
1335 env_not_checked = 0; |
|
1336 } |
|
1337 |
|
1338 if (env_buggy) { |
|
1339 return True; |
|
1340 } |
|
1341 |
|
1342 switch (awt_wm_getRunningWM()) { |
|
1343 case ICE_WM: |
|
1344 /* |
|
1345 * See bug #228981 at IceWM's SourceForge pages. |
|
1346 * Latest stable version 1.0.8-6 still has this problem. |
|
1347 */ |
|
1348 return True; |
|
1349 |
|
1350 case ENLIGHTEN_WM: |
|
1351 /* At least E16 is buggy. */ |
|
1352 return True; |
|
1353 |
|
1354 default: |
|
1355 return False; |
|
1356 } |
|
1357 } |
|
1358 |
|
1359 /** |
|
1360 * Check if state is supported. |
|
1361 * Note that a compound state is always reported as not supported. |
|
1362 * Note also that MAXIMIZED_BOTH is considered not a compound state. |
|
1363 * Therefore, a compound state is just ICONIFIED | anything else. |
|
1364 * |
|
1365 */ |
|
1366 Boolean |
|
1367 awt_wm_supportsExtendedState(jint state) |
|
1368 { |
|
1369 switch (state) { |
|
1370 case java_awt_Frame_MAXIMIZED_VERT: |
|
1371 case java_awt_Frame_MAXIMIZED_HORIZ: |
|
1372 /* |
|
1373 * WMs that talk NET/WIN protocol, but do not support |
|
1374 * unidirectional maximization. |
|
1375 */ |
|
1376 if (awt_wm_getRunningWM() == METACITY_WM) { |
|
1377 /* "This is a deliberate policy decision." -hp */ |
|
1378 return JNI_FALSE; |
|
1379 } |
|
1380 /* FALLTROUGH */ |
|
1381 case java_awt_Frame_MAXIMIZED_BOTH: |
|
1382 return (awt_wm_doStateProtocolNet() || awt_wm_doStateProtocolWin()); |
|
1383 default: |
|
1384 return JNI_FALSE; |
|
1385 } |
|
1386 } |
|
1387 |
|
1388 |
|
1389 |
|
1390 |
|
1391 /*****************************************************************************\ |
|
1392 * |
|
1393 * Size and decoration hints ... |
|
1394 * |
|
1395 \*****************************************************************************/ |
|
1396 |
|
1397 |
|
1398 /* |
|
1399 * Remove size hints specified by the mask. |
|
1400 * XXX: Why do we need this in the first place??? |
|
1401 */ |
|
1402 void |
|
1403 awt_wm_removeSizeHints(Widget shell, long mask) |
|
1404 { |
|
1405 Display *dpy = XtDisplay(shell); |
|
1406 Window shell_win = XtWindow(shell); |
|
1407 XSizeHints *hints = XAllocSizeHints(); |
|
1408 long ignore = 0; |
|
1409 |
|
1410 if (hints == NULL) { |
|
1411 DTRACE_PRINTLN("WM: removeSizeHints FAILED to allocate XSizeHints"); |
|
1412 return; |
|
1413 } |
|
1414 |
|
1415 /* sanitize the mask, only do these hints */ |
|
1416 mask &= (PMaxSize|PMinSize|USPosition|PPosition); |
|
1417 |
|
1418 XGetWMNormalHints(dpy, shell_win, hints, &ignore); |
|
1419 if ((hints->flags & mask) == 0) { |
|
1420 XFree(hints); |
|
1421 return; |
|
1422 } |
|
1423 |
|
1424 #ifdef DEBUG |
|
1425 DTRACE_PRINT("WM: removing hints"); |
|
1426 |
|
1427 if (mask & PMaxSize) { |
|
1428 DTRACE_PRINT(" Max = "); |
|
1429 if (hints->flags & PMaxSize) { |
|
1430 DTRACE_PRINT2("%d x %d;", hints->max_width, hints->max_height); |
|
1431 } else { |
|
1432 DTRACE_PRINT("none;"); |
|
1433 } |
|
1434 } |
|
1435 |
|
1436 if (mask & PMinSize) { |
|
1437 DTRACE_PRINT(" Min = "); |
|
1438 if (hints->flags & PMinSize) { |
|
1439 DTRACE_PRINT2("%d x %d;", hints->min_width, hints->min_height); |
|
1440 } else { |
|
1441 DTRACE_PRINT("none;"); |
|
1442 } |
|
1443 } |
|
1444 |
|
1445 DTRACE_PRINTLN(""); |
|
1446 #endif |
|
1447 |
|
1448 hints->flags &= ~mask; |
|
1449 XSetWMNormalHints(dpy, shell_win, hints); |
|
1450 XFree(hints); |
|
1451 } |
|
1452 |
|
1453 /* |
|
1454 * |
|
1455 * |
|
1456 */ |
|
1457 static void |
|
1458 awt_wm_proclaimUrgency(struct FrameData *wdata) |
|
1459 { |
|
1460 Display *dpy = XtDisplay(wdata->winData.shell); |
|
1461 Window shell_win = XtWindow(wdata->winData.shell); |
|
1462 |
|
1463 XWMHints *hints = XGetWMHints(dpy, shell_win); |
|
1464 if( hints == NULL ) { |
|
1465 /* For now just */ return; |
|
1466 } |
|
1467 if ((hints->flags & URGENCY_HINT) != 0) { |
|
1468 /* it's here already */ |
|
1469 XFree(hints); |
|
1470 return; |
|
1471 } |
|
1472 hints->flags |= URGENCY_HINT; |
|
1473 XSetWMHints(dpy, shell_win, hints); |
|
1474 XFree(hints); |
|
1475 } |
|
1476 |
|
1477 /* |
|
1478 * If MWM_DECOR_ALL bit is set, then the rest of the bit-mask is taken |
|
1479 * to be subtracted from the decorations. Normalize decoration spec |
|
1480 * so that we can map motif decor to something else bit-by-bit in the |
|
1481 * rest of the code. |
|
1482 */ |
|
1483 static int |
|
1484 awt_wm_normalizeMotifDecor(int decorations) |
|
1485 { |
|
1486 int d; |
|
1487 |
|
1488 if (!(decorations & MWM_DECOR_ALL)) |
|
1489 return decorations; /* already normalized */ |
|
1490 |
|
1491 d = MWM_DECOR_BORDER |MWM_DECOR_RESIZEH | MWM_DECOR_TITLE |
|
1492 | MWM_DECOR_MENU | MWM_DECOR_MINIMIZE | MWM_DECOR_MAXIMIZE; |
|
1493 d &= ~decorations; |
|
1494 return d; |
|
1495 } |
|
1496 |
|
1497 |
|
1498 /* |
|
1499 * Infer OL properties from MWM decorations. |
|
1500 * Use _OL_DECOR_DEL(ATOM[]) to remove unwanted ones. |
|
1501 */ |
|
1502 static void |
|
1503 awt_wm_setOLDecor(struct FrameData *wdata, Boolean resizable, int decorations) |
|
1504 { |
|
1505 Window shell_win = XtWindow(wdata->winData.shell); |
|
1506 Atom decorDel[3]; |
|
1507 int nitems; |
|
1508 |
|
1509 if (shell_win == None) { |
|
1510 DTRACE_PRINTLN("WM: setOLDecor - no window, returning"); |
|
1511 return; |
|
1512 } |
|
1513 |
|
1514 decorations = awt_wm_normalizeMotifDecor(decorations); |
|
1515 DTRACE_PRINT("WM: _OL_DECOR_DEL = {"); |
|
1516 |
|
1517 nitems = 0; |
|
1518 if (!(decorations & MWM_DECOR_TITLE)) { |
|
1519 DTRACE_PRINT(" _OL_DECOR_HEADER"); |
|
1520 decorDel[nitems++] = _XA_OL_DECOR_HEADER; |
|
1521 } |
|
1522 if (!(decorations & (MWM_DECOR_RESIZEH | MWM_DECOR_MAXIMIZE))) { |
|
1523 DTRACE_PRINT(" _OL_DECOR_RESIZE"); |
|
1524 decorDel[nitems++] = _XA_OL_DECOR_RESIZE; |
|
1525 } |
|
1526 if (!(decorations & (MWM_DECOR_MENU | MWM_DECOR_MAXIMIZE |
|
1527 | MWM_DECOR_MINIMIZE))) |
|
1528 { |
|
1529 DTRACE_PRINT(" _OL_DECOR_CLOSE"); |
|
1530 decorDel[nitems++] = _XA_OL_DECOR_CLOSE; |
|
1531 } |
|
1532 DTRACE_PRINT(" }"); |
|
1533 |
|
1534 if (nitems == 0) { |
|
1535 DTRACE_PRINTLN(" ... removing"); |
|
1536 XDeleteProperty(awt_display, shell_win, _XA_OL_DECOR_DEL); |
|
1537 } |
|
1538 else { |
|
1539 DTRACE_PRINTLN(" ... setting"); |
|
1540 XChangeProperty(awt_display, shell_win, |
|
1541 _XA_OL_DECOR_DEL, XA_ATOM, 32, |
|
1542 PropModeReplace, (unsigned char *)decorDel, nitems); |
|
1543 } |
|
1544 } |
|
1545 |
|
1546 /* |
|
1547 * Set MWM decorations. Infer MWM functions from decorations. |
|
1548 */ |
|
1549 static void |
|
1550 awt_wm_setMotifDecor(struct FrameData *wdata, Boolean resizable, int decorations) |
|
1551 { |
|
1552 int functions; |
|
1553 |
|
1554 /* Apparently some WMs don't implement MWM_*_ALL semantic correctly */ |
|
1555 if ((decorations & MWM_DECOR_ALL) && (decorations != MWM_DECOR_ALL)) { |
|
1556 decorations = awt_wm_normalizeMotifDecor(decorations); |
|
1557 DTRACE_PRINTLN1("WM: setMotifDecor normalize exclusions, decor = 0x%X", |
|
1558 decorations); |
|
1559 } |
|
1560 |
|
1561 DTRACE_PRINT("WM: setMotifDecor functions = {"); |
|
1562 functions = 0; |
|
1563 |
|
1564 if (decorations & MWM_DECOR_ALL) { |
|
1565 DTRACE_PRINT(" ALL"); |
|
1566 functions |= MWM_FUNC_ALL; |
|
1567 } |
|
1568 else { |
|
1569 /* |
|
1570 * Functions we always want to be enabled as mwm(1) and |
|
1571 * descendants not only hide disabled functions away from |
|
1572 * user, but also ignore corresponding requests from the |
|
1573 * program itself (e.g. 4442047). |
|
1574 */ |
|
1575 DTRACE_PRINT(" CLOSE MOVE MINIMIZE"); |
|
1576 functions |= (MWM_FUNC_CLOSE | MWM_FUNC_MOVE | MWM_FUNC_MINIMIZE); |
|
1577 |
|
1578 if (resizable) { |
|
1579 DTRACE_PRINT(" RESIZE MAXIMIZE"); |
|
1580 functions |= MWM_FUNC_RESIZE | MWM_FUNC_MAXIMIZE; |
|
1581 } |
|
1582 } |
|
1583 |
|
1584 DTRACE_PRINTLN(" }"); |
|
1585 |
|
1586 XtVaSetValues(wdata->winData.shell, |
|
1587 XmNmwmDecorations, decorations, |
|
1588 XmNmwmFunctions, functions, |
|
1589 NULL); |
|
1590 } |
|
1591 |
|
1592 |
|
1593 /* |
|
1594 * Under some window managers if shell is already mapped, we MUST |
|
1595 * unmap and later remap in order to effect the changes we make in the |
|
1596 * window manager decorations. |
|
1597 * |
|
1598 * N.B. This unmapping / remapping of the shell exposes a bug in |
|
1599 * X/Motif or the Motif Window Manager. When you attempt to map a |
|
1600 * widget which is positioned (partially) off-screen, the window is |
|
1601 * relocated to be entirely on screen. Good idea. But if both the x |
|
1602 * and the y coordinates are less than the origin (0,0), the first |
|
1603 * (re)map will move the window to the origin, and any subsequent |
|
1604 * (re)map will relocate the window at some other point on the screen. |
|
1605 * I have written a short Motif test program to discover this bug. |
|
1606 * This should occur infrequently and it does not cause any real |
|
1607 * problem. So for now we'll let it be. |
|
1608 */ |
|
1609 static Boolean |
|
1610 awt_wm_needRemap() |
|
1611 { |
|
1612 switch (awt_wm_getRunningWM()) { |
|
1613 #if 0 /* XXX */ |
|
1614 case OPENLOOK_WM: |
|
1615 case MOTIF_WM: |
|
1616 case CDE_WM: |
|
1617 case ICE_WM: |
|
1618 case ENLIGHTEN_WM: |
|
1619 return True; |
|
1620 #endif |
|
1621 default: |
|
1622 return True; |
|
1623 } |
|
1624 } |
|
1625 |
|
1626 /* |
|
1627 * Set decoration hints on the shell to wdata->decor adjusted |
|
1628 * appropriately if not resizable. |
|
1629 */ |
|
1630 void |
|
1631 awt_wm_setShellDecor(struct FrameData *wdata, Boolean resizable) |
|
1632 { |
|
1633 int decorations = wdata->decor; |
|
1634 |
|
1635 DTRACE_PRINTLN3("WM: setShellDecor(0x%x/0x%x, %s)", |
|
1636 wdata->winData.shell, XtWindow(wdata->winData.shell), |
|
1637 resizable ? "resizable" : "not resizable"); |
|
1638 |
|
1639 if (!resizable) { |
|
1640 if (decorations & MWM_DECOR_ALL) { |
|
1641 decorations |= (MWM_DECOR_RESIZEH | MWM_DECOR_MAXIMIZE); |
|
1642 } |
|
1643 else { |
|
1644 decorations &= ~(MWM_DECOR_RESIZEH | MWM_DECOR_MAXIMIZE); |
|
1645 } |
|
1646 } |
|
1647 |
|
1648 DTRACE_PRINTLN1("WM: decorations = 0x%X", decorations); |
|
1649 awt_wm_setMotifDecor(wdata, resizable, decorations); |
|
1650 awt_wm_setOLDecor(wdata, resizable, decorations); |
|
1651 |
|
1652 /* Some WMs need remap to redecorate the window */ |
|
1653 if (wdata->isShowing && awt_wm_needRemap()) { |
|
1654 /* |
|
1655 * Do the re/mapping at the Xlib level. Since we essentially |
|
1656 * work around a WM bug we don't want this hack to be exposed |
|
1657 * to Intrinsics (i.e. don't mess with grabs, callbacks etc). |
|
1658 */ |
|
1659 Display *dpy = XtDisplay(wdata->winData.shell); |
|
1660 Window shell_win = XtWindow(wdata->winData.shell); |
|
1661 |
|
1662 DTRACE_PRINT("WM: setShellDecor REMAPPING ... "); |
|
1663 XUnmapWindow(dpy, shell_win); |
|
1664 XSync(dpy, False); /* give WM a chance to catch up */ |
|
1665 XMapWindow(dpy, shell_win); |
|
1666 DTRACE_PRINTLN("done"); |
|
1667 } |
|
1668 } |
|
1669 |
|
1670 |
|
1671 /* |
|
1672 * Make specified shell resizable. |
|
1673 */ |
|
1674 void |
|
1675 awt_wm_setShellResizable(struct FrameData *wdata) |
|
1676 { |
|
1677 DTRACE_PRINTLN2("WM: setShellResizable(0x%x/0x%x)", |
|
1678 wdata->winData.shell, XtWindow(wdata->winData.shell)); |
|
1679 |
|
1680 XtVaSetValues(wdata->winData.shell, |
|
1681 XmNallowShellResize, True, |
|
1682 XmNminWidth, XtUnspecifiedShellInt, |
|
1683 XmNminHeight, XtUnspecifiedShellInt, |
|
1684 XmNmaxWidth, XtUnspecifiedShellInt, |
|
1685 XmNmaxHeight, XtUnspecifiedShellInt, |
|
1686 NULL); |
|
1687 |
|
1688 /* REMINDER: will need to revisit when setExtendedStateBounds is added */ |
|
1689 awt_wm_removeSizeHints(wdata->winData.shell, PMinSize|PMaxSize); |
|
1690 |
|
1691 /* Restore decorations */ |
|
1692 awt_wm_setShellDecor(wdata, True); |
|
1693 } |
|
1694 |
|
1695 |
|
1696 /* |
|
1697 * Make specified shell non-resizable. |
|
1698 * If justChangeSize is false, update decorations as well. |
|
1699 */ |
|
1700 void |
|
1701 awt_wm_setShellNotResizable(struct FrameData *wdata, |
|
1702 int32_t width, int32_t height, |
|
1703 Boolean justChangeSize) |
|
1704 { |
|
1705 DTRACE_PRINTLN5("WM: setShellNotResizable(0x%x/0x%x, %d, %d, %s)", |
|
1706 wdata->winData.shell, XtWindow(wdata->winData.shell), |
|
1707 width, height, |
|
1708 justChangeSize ? "size only" : "redecorate"); |
|
1709 |
|
1710 /* Fix min/max size hints at the specified values */ |
|
1711 if ((width > 0) && (height > 0)) { |
|
1712 XtVaSetValues(wdata->winData.shell, |
|
1713 XmNwidth, (XtArgVal)width, |
|
1714 XmNheight, (XtArgVal)height, |
|
1715 XmNminWidth, (XtArgVal)width, |
|
1716 XmNminHeight, (XtArgVal)height, |
|
1717 XmNmaxWidth, (XtArgVal)width, |
|
1718 XmNmaxHeight, (XtArgVal)height, |
|
1719 NULL); |
|
1720 } |
|
1721 |
|
1722 if (!justChangeSize) { /* update decorations */ |
|
1723 awt_wm_setShellDecor(wdata, False); |
|
1724 } |
|
1725 } |
|
1726 |
|
1727 |
|
1728 /* |
|
1729 * Helper function for awt_wm_getInsetsFromProp. |
|
1730 * Read property of type CARDINAL[4] = { left, right, top, bottom } |
|
1731 */ |
|
1732 static Boolean |
|
1733 awt_wm_readInsetsArray(Window shell_win, Atom insets_property, |
|
1734 int32_t *top, int32_t *left, int32_t *bottom, int32_t *right) |
|
1735 { |
|
1736 /* Request status */ |
|
1737 int status; |
|
1738 |
|
1739 /* Returns of XGetWindowProperty */ |
|
1740 Atom actual_type; |
|
1741 int actual_format; |
|
1742 unsigned long nitems; |
|
1743 unsigned long bytes_after; |
|
1744 long *insets = NULL; /* NB: 64 bit: Format 32 props are 'long' */ |
|
1745 |
|
1746 status = XGetWindowProperty (awt_display, shell_win, |
|
1747 insets_property, 0, 4, False, XA_CARDINAL, |
|
1748 &actual_type, &actual_format, &nitems, &bytes_after, |
|
1749 (unsigned char **)&insets); |
|
1750 |
|
1751 if (status != Success || insets == NULL) { |
|
1752 DTRACE_PRINTLN("failed"); |
|
1753 return False; |
|
1754 } |
|
1755 |
|
1756 if (actual_type != XA_CARDINAL || actual_format != 32) { |
|
1757 DTRACE_PRINTLN("type/format mismatch"); |
|
1758 XFree(insets); |
|
1759 return False; |
|
1760 } |
|
1761 |
|
1762 *left = (int32_t)insets[0]; |
|
1763 *right = (int32_t)insets[1]; |
|
1764 *top = (int32_t)insets[2]; |
|
1765 *bottom = (int32_t)insets[3]; |
|
1766 XFree(insets); |
|
1767 |
|
1768 /* Order is that of java.awt.Insets.toString */ |
|
1769 DTRACE_PRINTLN4("[top=%d,left=%d,bottom=%d,right=%d]", |
|
1770 *top, *left, *bottom, *right); |
|
1771 return True; |
|
1772 } |
|
1773 |
|
1774 /* |
|
1775 * If WM implements the insets property - fill insets with values |
|
1776 * specified in that property. |
|
1777 */ |
|
1778 Boolean |
|
1779 awt_wm_getInsetsFromProp(Window shell_win, |
|
1780 int32_t *top, int32_t *left, int32_t *bottom, int32_t *right) |
|
1781 { |
|
1782 switch (awt_wm_getRunningWM()) { |
|
1783 |
|
1784 case ENLIGHTEN_WM: |
|
1785 DTRACE_PRINT("WM: reading _E_FRAME_SIZE ... "); |
|
1786 return awt_wm_readInsetsArray(shell_win, _XA_E_FRAME_SIZE, |
|
1787 top, left, bottom, right); |
|
1788 |
|
1789 #if 0 |
|
1790 /* |
|
1791 * uwe: disabled for now, as KDE seems to supply bogus values |
|
1792 * when we maximize iconified frame. Need to verify with KDE2.1. |
|
1793 * NB: Also note, that "external" handles (e.g. in laptop decor) |
|
1794 * are also included in the frame strut, which is probably not |
|
1795 * what we want. |
|
1796 */ |
|
1797 case KDE2_WM: |
|
1798 DTRACE_PRINT("WM: reading _KDE_NET_WM_FRAME_STRUT ... "); |
|
1799 return awt_wm_readInsetsArray(shell_win, _XA_KDE_NET_WM_FRAME_STRUT, |
|
1800 top, left, bottom, right); |
|
1801 #endif |
|
1802 |
|
1803 default: |
|
1804 return False; |
|
1805 } |
|
1806 } |
|
1807 |
|
1808 /* |
|
1809 * XmNiconic and Map/UnmapNotify (that XmNiconic relies on) are |
|
1810 * unreliable, since mapping changes can happen for a virtual desktop |
|
1811 * switch or MacOS style shading that became quite popular under X as |
|
1812 * well. Yes, it probably should not be this way, as it violates |
|
1813 * ICCCM, but reality is that quite a lot of window managers abuse |
|
1814 * mapping state. |
|
1815 */ |
|
1816 int |
|
1817 awt_wm_getWMState(Window shell_win) |
|
1818 { |
|
1819 /* Request status */ |
|
1820 int status; |
|
1821 |
|
1822 /* Returns of XGetWindowProperty */ |
|
1823 Atom actual_type; |
|
1824 int actual_format; |
|
1825 unsigned long nitems; |
|
1826 unsigned long bytes_after; |
|
1827 long *data; /* NB: 64 bit: Format 32 props are 'long' */ |
|
1828 |
|
1829 int wm_state; |
|
1830 |
|
1831 status = XGetWindowProperty(awt_display, shell_win, |
|
1832 XA_WM_STATE, 0, 1, False, XA_WM_STATE, |
|
1833 &actual_type, &actual_format, &nitems, &bytes_after, |
|
1834 (unsigned char **)&data); |
|
1835 |
|
1836 if (status != Success || data == NULL) { |
|
1837 return WithdrawnState; |
|
1838 } |
|
1839 |
|
1840 if (actual_type != XA_WM_STATE) { |
|
1841 DTRACE_PRINTLN1("WM: WM_STATE(0x%x) - wrong type", shell_win); |
|
1842 XFree(data); |
|
1843 return WithdrawnState; |
|
1844 } |
|
1845 |
|
1846 wm_state = (int)*data; |
|
1847 XFree(data); |
|
1848 return wm_state; |
|
1849 } |
|
1850 |
|
1851 |
|
1852 |
|
1853 /*****************************************************************************\ |
|
1854 * |
|
1855 * Reading state from properties WM puts on our window ... |
|
1856 * |
|
1857 \*****************************************************************************/ |
|
1858 |
|
1859 /* |
|
1860 * New "NET" WM spec: _NET_WM_STATE/Atom[] |
|
1861 */ |
|
1862 static jint |
|
1863 awt_wm_getStateNet(Window shell_win) |
|
1864 { |
|
1865 Atom *net_wm_state; |
|
1866 jint java_state; |
|
1867 unsigned long nitems; |
|
1868 unsigned long i; |
|
1869 |
|
1870 net_wm_state = awt_getAtomListProperty(shell_win, _XA_NET_WM_STATE, &nitems); |
|
1871 if (nitems == 0) { |
|
1872 DTRACE_PRINTLN("WM: _NET_WM_STATE = { }"); |
|
1873 if (net_wm_state) { |
|
1874 XFree(net_wm_state); |
|
1875 } |
|
1876 return java_awt_Frame_NORMAL; |
|
1877 } |
|
1878 #ifdef DEBUG |
|
1879 DTRACE_PRINT("WM: "); |
|
1880 awt_wm_dtraceStateNet(net_wm_state, nitems); |
|
1881 #endif |
|
1882 |
|
1883 java_state = java_awt_Frame_NORMAL; |
|
1884 for (i = 0; i < nitems; ++i) { |
|
1885 if (net_wm_state[i] == _XA_NET_WM_STATE_MAXIMIZED_VERT) { |
|
1886 java_state |= java_awt_Frame_MAXIMIZED_VERT; |
|
1887 } |
|
1888 else if (net_wm_state[i] == _XA_NET_WM_STATE_MAXIMIZED_HORZ) { |
|
1889 java_state |= java_awt_Frame_MAXIMIZED_HORIZ; |
|
1890 } |
|
1891 } |
|
1892 XFree(net_wm_state); |
|
1893 return java_state; |
|
1894 } |
|
1895 |
|
1896 Boolean |
|
1897 awt_wm_isStateNetHidden(Window shell_win) |
|
1898 { |
|
1899 Atom *net_wm_state; |
|
1900 Boolean result = False; |
|
1901 unsigned long nitems; |
|
1902 unsigned long i; |
|
1903 |
|
1904 net_wm_state = awt_getAtomListProperty(shell_win, _XA_NET_WM_STATE, &nitems); |
|
1905 if (nitems == 0) { |
|
1906 DTRACE_PRINTLN("WM: _NET_WM_STATE = { }"); |
|
1907 if (net_wm_state) { |
|
1908 XFree(net_wm_state); |
|
1909 } |
|
1910 return False; |
|
1911 } |
|
1912 #ifdef DEBUG |
|
1913 DTRACE_PRINT("WM: "); |
|
1914 awt_wm_dtraceStateNet(net_wm_state, nitems); |
|
1915 #endif |
|
1916 |
|
1917 for (i = 0; i < nitems; ++i) { |
|
1918 if (net_wm_state[i] == _XA_NET_WM_STATE_HIDDEN) { |
|
1919 result = True; |
|
1920 } |
|
1921 } |
|
1922 XFree(net_wm_state); |
|
1923 return result; |
|
1924 } |
|
1925 |
|
1926 /* |
|
1927 * Similar code to getStateNet, to get layer state. |
|
1928 */ |
|
1929 static int |
|
1930 awt_wm_getLayerNet(Window shell_win) |
|
1931 { |
|
1932 Atom *net_wm_state; |
|
1933 int java_state; |
|
1934 unsigned long nitems; |
|
1935 unsigned long i; |
|
1936 |
|
1937 net_wm_state = awt_getAtomListProperty(shell_win, _XA_NET_WM_STATE, &nitems); |
|
1938 if (nitems == 0) { |
|
1939 DTRACE_PRINTLN("WM: _NET_WM_STATE = { }"); |
|
1940 if (net_wm_state) { |
|
1941 XFree(net_wm_state); |
|
1942 } |
|
1943 return LAYER_NORMAL; |
|
1944 } |
|
1945 #ifdef DEBUG |
|
1946 DTRACE_PRINT("WM: "); |
|
1947 awt_wm_dtraceStateNet(net_wm_state, nitems); |
|
1948 #endif |
|
1949 |
|
1950 java_state = LAYER_NORMAL; |
|
1951 for (i = 0; i < nitems; ++i) { |
|
1952 if (net_wm_state[i] == _XA_NET_WM_STATE_ABOVE) { |
|
1953 java_state = LAYER_ALWAYS_ON_TOP; |
|
1954 } |
|
1955 } |
|
1956 XFree(net_wm_state); |
|
1957 return java_state; |
|
1958 } |
|
1959 |
|
1960 /* |
|
1961 * Old Gnome spec: _WIN_STATE/CARDINAL |
|
1962 */ |
|
1963 static jint |
|
1964 awt_wm_getStateWin(Window shell_win) |
|
1965 { |
|
1966 long win_state; |
|
1967 jint java_state; |
|
1968 |
|
1969 win_state = awt_getProperty32(shell_win, _XA_WIN_STATE, XA_CARDINAL); |
|
1970 #ifdef DEBUG |
|
1971 DTRACE_PRINT("WM: "); |
|
1972 awt_wm_dtraceStateWin(win_state); |
|
1973 #endif |
|
1974 |
|
1975 java_state = java_awt_Frame_NORMAL; |
|
1976 if (win_state & WIN_STATE_MAXIMIZED_VERT) { |
|
1977 java_state |= java_awt_Frame_MAXIMIZED_VERT; |
|
1978 } |
|
1979 if (win_state & WIN_STATE_MAXIMIZED_HORIZ) { |
|
1980 java_state |= java_awt_Frame_MAXIMIZED_HORIZ; |
|
1981 } |
|
1982 return java_state; |
|
1983 } |
|
1984 |
|
1985 /* |
|
1986 * Code similar to getStateWin, to get layer state. |
|
1987 */ |
|
1988 static int |
|
1989 awt_wm_getLayerWin(Window shell_win) |
|
1990 { |
|
1991 long win_state; |
|
1992 jint java_state; |
|
1993 |
|
1994 win_state = awt_getProperty32(shell_win, _XA_WIN_LAYER, XA_CARDINAL); |
|
1995 #ifdef DEBUG |
|
1996 DTRACE_PRINT("WM: "); |
|
1997 awt_wm_dtraceStateWin(win_state); |
|
1998 #endif |
|
1999 |
|
2000 java_state = LAYER_NORMAL; |
|
2001 if (win_state == WIN_LAYER_ONTOP) { |
|
2002 java_state = LAYER_ALWAYS_ON_TOP; |
|
2003 } |
|
2004 return java_state; |
|
2005 } |
|
2006 |
|
2007 |
|
2008 static jint |
|
2009 awt_wm_getExtendedState(Window shell_win) |
|
2010 { |
|
2011 if (awt_wm_doStateProtocolNet()) { |
|
2012 return awt_wm_getStateNet(shell_win); |
|
2013 } |
|
2014 else if (awt_wm_doStateProtocolWin()) { |
|
2015 return awt_wm_getStateWin(shell_win); |
|
2016 } |
|
2017 else { |
|
2018 return java_awt_Frame_NORMAL; |
|
2019 } |
|
2020 } |
|
2021 |
|
2022 jint |
|
2023 awt_wm_getState(struct FrameData *wdata) |
|
2024 { |
|
2025 Window shell_win = XtWindow(wdata->winData.shell); |
|
2026 jint java_state; |
|
2027 |
|
2028 DTRACE_PRINTLN2("WM: getState(0x%x/0x%x)", |
|
2029 wdata->winData.shell, shell_win); |
|
2030 |
|
2031 if (shell_win == None) { |
|
2032 DTRACE_PRINTLN("WM: no window, use wdata"); |
|
2033 java_state = wdata->state; |
|
2034 } |
|
2035 else { |
|
2036 int wm_state = awt_wm_getWMState(shell_win); |
|
2037 if (wm_state == WithdrawnState) { |
|
2038 DTRACE_PRINTLN("WM: window withdrawn, use wdata"); |
|
2039 java_state = wdata->state; |
|
2040 } |
|
2041 else { |
|
2042 #ifdef DEBUG |
|
2043 DTRACE_PRINT("WM: "); |
|
2044 awt_wm_dtraceWMState(wm_state); |
|
2045 #endif |
|
2046 if (wm_state == IconicState) { |
|
2047 java_state = java_awt_Frame_ICONIFIED; |
|
2048 } else { |
|
2049 java_state = java_awt_Frame_NORMAL; |
|
2050 } |
|
2051 java_state |= awt_wm_getExtendedState(shell_win); |
|
2052 } |
|
2053 } |
|
2054 |
|
2055 #ifdef DEBUG |
|
2056 DTRACE_PRINT("WM: "); |
|
2057 awt_wm_dtraceStateJava(java_state); |
|
2058 #endif |
|
2059 |
|
2060 return java_state; |
|
2061 } |
|
2062 |
|
2063 |
|
2064 |
|
2065 /*****************************************************************************\ |
|
2066 * |
|
2067 * Notice window state change when WM changes a property on the window ... |
|
2068 * |
|
2069 \*****************************************************************************/ |
|
2070 |
|
2071 |
|
2072 /* |
|
2073 * Check if property change is a window state protocol message. |
|
2074 * If it is - return True and return the new state in *pstate. |
|
2075 */ |
|
2076 Boolean |
|
2077 awt_wm_isStateChange(struct FrameData *wdata, XPropertyEvent *e, jint *pstate) |
|
2078 { |
|
2079 Window shell_win = XtWindow(wdata->winData.shell); |
|
2080 Boolean is_state_change = False; |
|
2081 int wm_state; |
|
2082 |
|
2083 if (!wdata->isShowing) { |
|
2084 return False; |
|
2085 } |
|
2086 |
|
2087 wm_state = awt_wm_getWMState(shell_win); |
|
2088 if (wm_state == WithdrawnState) { |
|
2089 return False; |
|
2090 } |
|
2091 |
|
2092 if (e->atom == XA_WM_STATE) { |
|
2093 is_state_change = True; |
|
2094 } |
|
2095 else if (e->atom == _XA_NET_WM_STATE) { |
|
2096 is_state_change = awt_wm_doStateProtocolNet(); |
|
2097 } |
|
2098 else if (e->atom == _XA_WIN_STATE) { |
|
2099 is_state_change = awt_wm_doStateProtocolWin(); |
|
2100 } |
|
2101 |
|
2102 if (is_state_change) { |
|
2103 #ifdef DEBUG |
|
2104 Widget shell = wdata->winData.shell; |
|
2105 char *name = XGetAtomName(XtDisplay(shell), e->atom); |
|
2106 DTRACE_PRINTLN4("WM: PropertyNotify(0x%x/0x%x) %s %s", |
|
2107 shell, XtWindow(shell), |
|
2108 name != NULL ? name : "???", |
|
2109 e->state == PropertyNewValue ? "changed" : "deleted"); |
|
2110 if (name != NULL) { |
|
2111 XFree(name); |
|
2112 } |
|
2113 DTRACE_PRINT("WM: "); |
|
2114 awt_wm_dtraceWMState(wm_state); |
|
2115 #endif |
|
2116 if (wm_state == IconicState) { |
|
2117 *pstate = java_awt_Frame_ICONIFIED; |
|
2118 } else { |
|
2119 *pstate = java_awt_Frame_NORMAL; |
|
2120 } |
|
2121 *pstate |= awt_wm_getExtendedState(shell_win); |
|
2122 |
|
2123 #ifdef DEBUG |
|
2124 DTRACE_PRINT("WM: "); |
|
2125 awt_wm_dtraceStateJava(*pstate); |
|
2126 #endif |
|
2127 } |
|
2128 |
|
2129 return is_state_change; |
|
2130 } |
|
2131 |
|
2132 |
|
2133 |
|
2134 |
|
2135 /*****************************************************************************\ |
|
2136 * |
|
2137 * Setting/changing window state ... |
|
2138 * |
|
2139 \*****************************************************************************/ |
|
2140 |
|
2141 /* |
|
2142 * Request a state transition from a _NET supporting WM by sending |
|
2143 * _NET_WM_STATE ClientMessage to root window. |
|
2144 */ |
|
2145 static void |
|
2146 awt_wm_requestStateNet(struct FrameData *wdata, jint state) |
|
2147 { |
|
2148 Widget shell = wdata->winData.shell; |
|
2149 Window shell_win = XtWindow(shell); |
|
2150 XClientMessageEvent req; |
|
2151 jint old_net_state; |
|
2152 jint max_changed; |
|
2153 |
|
2154 /* must use awt_wm_setInitialStateNet for withdrawn windows */ |
|
2155 DASSERT(wdata->isShowing); |
|
2156 |
|
2157 /* |
|
2158 * We have to use toggle for maximization because of transitions |
|
2159 * from maximization in one direction only to maximization in the |
|
2160 * other direction only. |
|
2161 */ |
|
2162 old_net_state = awt_wm_getStateNet(shell_win); |
|
2163 max_changed = (state ^ old_net_state) & java_awt_Frame_MAXIMIZED_BOTH; |
|
2164 |
|
2165 switch (max_changed) { |
|
2166 case 0: |
|
2167 DTRACE_PRINTLN("WM: requestStateNet - maximization unchanged"); |
|
2168 return; |
|
2169 |
|
2170 case java_awt_Frame_MAXIMIZED_HORIZ: |
|
2171 DTRACE_PRINTLN("WM: requestStateNet - toggling MAX_HORZ"); |
|
2172 req.data.l[1] = _XA_NET_WM_STATE_MAXIMIZED_HORZ; |
|
2173 req.data.l[2] = 0; |
|
2174 break; |
|
2175 |
|
2176 case java_awt_Frame_MAXIMIZED_VERT: |
|
2177 DTRACE_PRINTLN("WM: requestStateNet - toggling MAX_VERT"); |
|
2178 req.data.l[1] = _XA_NET_WM_STATE_MAXIMIZED_VERT; |
|
2179 req.data.l[2] = 0; |
|
2180 break; |
|
2181 |
|
2182 default: /* both */ |
|
2183 DTRACE_PRINTLN("WM: requestStateNet - toggling HORZ + VERT"); |
|
2184 req.data.l[1] = _XA_NET_WM_STATE_MAXIMIZED_HORZ; |
|
2185 req.data.l[2] = _XA_NET_WM_STATE_MAXIMIZED_VERT; |
|
2186 break; |
|
2187 } |
|
2188 |
|
2189 req.type = ClientMessage; |
|
2190 req.window = XtWindow(shell); |
|
2191 req.message_type = _XA_NET_WM_STATE; |
|
2192 req.format = 32; |
|
2193 req.data.l[0] = _NET_WM_STATE_TOGGLE; |
|
2194 |
|
2195 XSendEvent(XtDisplay(shell), RootWindowOfScreen(XtScreen(shell)), False, |
|
2196 (SubstructureRedirectMask | SubstructureNotifyMask), |
|
2197 (XEvent *)&req); |
|
2198 } |
|
2199 |
|
2200 |
|
2201 /* |
|
2202 * Request state transition from a Gnome WM (_WIN protocol) by sending |
|
2203 * _WIN_STATE ClientMessage to root window. |
|
2204 */ |
|
2205 static void |
|
2206 awt_wm_requestStateWin(struct FrameData *wdata, jint state) |
|
2207 { |
|
2208 Widget shell = wdata->winData.shell; |
|
2209 XClientMessageEvent req; |
|
2210 long win_state; /* typeof(XClientMessageEvent.data.l) */ |
|
2211 |
|
2212 /* must use awt_wm_setInitialStateWin for withdrawn windows */ |
|
2213 DASSERT(wdata->isShowing); |
|
2214 |
|
2215 win_state = 0; |
|
2216 if (state & java_awt_Frame_MAXIMIZED_VERT) { |
|
2217 win_state |= WIN_STATE_MAXIMIZED_VERT; |
|
2218 } |
|
2219 if (state & java_awt_Frame_MAXIMIZED_HORIZ) { |
|
2220 win_state |= WIN_STATE_MAXIMIZED_HORIZ; |
|
2221 } |
|
2222 |
|
2223 req.type = ClientMessage; |
|
2224 req.window = XtWindow(shell); |
|
2225 req.message_type = _XA_WIN_STATE; |
|
2226 req.format = 32; |
|
2227 req.data.l[0] = (WIN_STATE_MAXIMIZED_HORIZ | WIN_STATE_MAXIMIZED_VERT); |
|
2228 req.data.l[1] = win_state; |
|
2229 |
|
2230 XSendEvent(XtDisplay(shell), RootWindowOfScreen(XtScreen(shell)), False, |
|
2231 (SubstructureRedirectMask | SubstructureNotifyMask), |
|
2232 (XEvent *)&req); |
|
2233 } |
|
2234 |
|
2235 |
|
2236 /* |
|
2237 * Specify initial state for _NET supporting WM by setting |
|
2238 * _NET_WM_STATE property on the window to the desired state before |
|
2239 * mapping it. |
|
2240 */ |
|
2241 static void |
|
2242 awt_wm_setInitialStateNet(struct FrameData *wdata, jint state) |
|
2243 { |
|
2244 Widget shell = wdata->winData.shell; |
|
2245 Window shell_win = XtWindow(shell); |
|
2246 Display *dpy = XtDisplay(shell); |
|
2247 |
|
2248 Atom *old_state; |
|
2249 unsigned long nitems; |
|
2250 |
|
2251 /* must use awt_wm_requestStateNet for managed windows */ |
|
2252 DASSERT(!wdata->isShowing); |
|
2253 |
|
2254 /* Be careful to not wipe out state bits we don't understand */ |
|
2255 old_state = awt_getAtomListProperty(shell_win, _XA_NET_WM_STATE, &nitems); |
|
2256 |
|
2257 if (nitems == 0) { |
|
2258 /* |
|
2259 * Empty or absent _NET_WM_STATE - set a new one if necessary. |
|
2260 */ |
|
2261 Atom net_wm_state[AWT_NET_N_KNOWN_STATES]; |
|
2262 |
|
2263 if (old_state != NULL) { |
|
2264 XFree(old_state); |
|
2265 } |
|
2266 |
|
2267 if (state & java_awt_Frame_MAXIMIZED_VERT) { |
|
2268 net_wm_state[nitems++] = _XA_NET_WM_STATE_MAXIMIZED_VERT; |
|
2269 } |
|
2270 if (state & java_awt_Frame_MAXIMIZED_HORIZ) { |
|
2271 net_wm_state[nitems++] = _XA_NET_WM_STATE_MAXIMIZED_HORZ; |
|
2272 } |
|
2273 DASSERT(nitems <= AWT_NET_N_KNOWN_STATES); |
|
2274 |
|
2275 if (nitems == 0) { |
|
2276 DTRACE_PRINTLN("WM: initial _NET_WM_STATE not necessary"); |
|
2277 return; |
|
2278 } |
|
2279 |
|
2280 #ifdef DEBUG |
|
2281 DTRACE_PRINT("WM: setting initial "); |
|
2282 awt_wm_dtraceStateNet(net_wm_state, nitems); |
|
2283 #endif |
|
2284 XChangeProperty(dpy, shell_win, |
|
2285 _XA_NET_WM_STATE, XA_ATOM, 32, PropModeReplace, |
|
2286 (unsigned char *)net_wm_state, nitems); |
|
2287 } |
|
2288 else { |
|
2289 /* |
|
2290 * Tweak existing _NET_WM_STATE, preserving bits we don't use. |
|
2291 */ |
|
2292 jint want= state /* which flags we want */ |
|
2293 & (java_awt_Frame_MAXIMIZED_HORIZ | java_awt_Frame_MAXIMIZED_VERT); |
|
2294 |
|
2295 jint has = 0; /* which flags the window already has */ |
|
2296 int mode; /* property mode: replace/append */ |
|
2297 |
|
2298 Atom *new_state; /* new _net_wm_state value */ |
|
2299 int new_nitems; |
|
2300 unsigned long i; |
|
2301 |
|
2302 #ifdef DEBUG |
|
2303 DTRACE_PRINT("WM: already has "); |
|
2304 awt_wm_dtraceStateNet(old_state, nitems); |
|
2305 #endif |
|
2306 |
|
2307 for (i = 0; i < nitems; ++i) { |
|
2308 if (old_state[i] == _XA_NET_WM_STATE_MAXIMIZED_HORZ) { |
|
2309 has |= java_awt_Frame_MAXIMIZED_HORIZ; |
|
2310 } |
|
2311 else if (old_state[i] == _XA_NET_WM_STATE_MAXIMIZED_VERT) { |
|
2312 has |= java_awt_Frame_MAXIMIZED_VERT; |
|
2313 } |
|
2314 } |
|
2315 |
|
2316 if ((has ^ want) == 0) { |
|
2317 DTRACE_PRINTLN("WM: no changes to _NET_WM_STATE necessary"); |
|
2318 XFree(old_state); |
|
2319 return; |
|
2320 } |
|
2321 |
|
2322 new_nitems = 0; |
|
2323 if (has == 0) { /* only adding flags */ |
|
2324 new_state = calloc(AWT_NET_N_KNOWN_STATES, sizeof(Atom)); |
|
2325 mode = PropModeAppend; |
|
2326 } |
|
2327 else { |
|
2328 new_state = calloc(nitems + AWT_NET_N_KNOWN_STATES, sizeof(Atom)); |
|
2329 mode = PropModeReplace; |
|
2330 } |
|
2331 |
|
2332 if (has != 0) { /* copy existing flags */ |
|
2333 DTRACE_PRINT("WM: "); |
|
2334 for (i = 0; i < nitems; ++i) { |
|
2335 if (old_state[i] == _XA_NET_WM_STATE_MAXIMIZED_HORZ) { |
|
2336 if (want & java_awt_Frame_MAXIMIZED_HORIZ) { |
|
2337 DTRACE_PRINT(" keep _HORZ"); |
|
2338 } else { |
|
2339 DTRACE_PRINT(" drop _HORZ"); |
|
2340 continue; |
|
2341 } |
|
2342 } |
|
2343 else if (old_state[i] == _XA_NET_WM_STATE_MAXIMIZED_VERT) { |
|
2344 if (want & java_awt_Frame_MAXIMIZED_VERT) { |
|
2345 DTRACE_PRINT(" keep _VERT"); |
|
2346 } else { |
|
2347 DTRACE_PRINT(" drop _VERT"); |
|
2348 continue; |
|
2349 } |
|
2350 } |
|
2351 new_state[new_nitems++] = old_state[i]; |
|
2352 } |
|
2353 } |
|
2354 |
|
2355 /* Add missing flags */ |
|
2356 if ((want & java_awt_Frame_MAXIMIZED_HORIZ) |
|
2357 && !(has & java_awt_Frame_MAXIMIZED_HORIZ)) |
|
2358 { |
|
2359 DTRACE_PRINT(" add _HORZ"); |
|
2360 new_state[new_nitems] = _XA_NET_WM_STATE_MAXIMIZED_HORZ; |
|
2361 ++new_nitems; |
|
2362 } |
|
2363 if ((want & java_awt_Frame_MAXIMIZED_VERT) |
|
2364 && !(has & java_awt_Frame_MAXIMIZED_VERT)) |
|
2365 { |
|
2366 DTRACE_PRINT(" add _VERT"); |
|
2367 new_state[new_nitems] = _XA_NET_WM_STATE_MAXIMIZED_VERT; |
|
2368 ++new_nitems; |
|
2369 } |
|
2370 |
|
2371 DTRACE_PRINTLN(mode == PropModeReplace ? |
|
2372 " ... replacing" : " ... appending"); |
|
2373 XChangeProperty(dpy, shell_win, |
|
2374 _XA_NET_WM_STATE, XA_ATOM, 32, mode, |
|
2375 (unsigned char *)new_state, new_nitems); |
|
2376 XFree(old_state); |
|
2377 XFree(new_state); |
|
2378 } |
|
2379 } |
|
2380 |
|
2381 |
|
2382 /* |
|
2383 * Specify initial state for a Gnome WM (_WIN protocol) by setting |
|
2384 * WIN_STATE property on the window to the desired state before |
|
2385 * mapping it. |
|
2386 */ |
|
2387 static void |
|
2388 awt_wm_setInitialStateWin(struct FrameData *wdata, jint state) |
|
2389 { |
|
2390 Display *dpy = XtDisplay(wdata->winData.shell); |
|
2391 Window shell_win = XtWindow(wdata->winData.shell); |
|
2392 long win_state, old_win_state; |
|
2393 |
|
2394 /* must use awt_wm_requestStateWin for managed windows */ |
|
2395 DASSERT(!wdata->isShowing); |
|
2396 |
|
2397 /* Be careful to not wipe out state bits we don't understand */ |
|
2398 win_state = awt_getProperty32(shell_win, _XA_WIN_STATE, XA_CARDINAL); |
|
2399 old_win_state = win_state; |
|
2400 #ifdef DEBUG |
|
2401 if (win_state != 0) { |
|
2402 DTRACE_PRINT("WM: already has "); |
|
2403 awt_wm_dtraceStateWin(win_state); |
|
2404 } |
|
2405 #endif |
|
2406 |
|
2407 /* |
|
2408 * In their stupid quest of reinventing every wheel, Gnome WM spec |
|
2409 * have its own "minimized" hint (instead of using initial state |
|
2410 * and WM_STATE hints). This is bogus, but, apparently, some WMs |
|
2411 * pay attention. |
|
2412 */ |
|
2413 if (state & java_awt_Frame_ICONIFIED) { |
|
2414 win_state |= WIN_STATE_MINIMIZED; |
|
2415 } else { |
|
2416 win_state &= ~WIN_STATE_MINIMIZED; |
|
2417 } |
|
2418 |
|
2419 if (state & java_awt_Frame_MAXIMIZED_VERT) { |
|
2420 win_state |= WIN_STATE_MAXIMIZED_VERT; |
|
2421 } else { |
|
2422 win_state &= ~WIN_STATE_MAXIMIZED_VERT; |
|
2423 } |
|
2424 |
|
2425 if (state & java_awt_Frame_MAXIMIZED_HORIZ) { |
|
2426 win_state |= WIN_STATE_MAXIMIZED_HORIZ; |
|
2427 } else { |
|
2428 win_state &= ~WIN_STATE_MAXIMIZED_HORIZ; |
|
2429 } |
|
2430 |
|
2431 if (old_win_state ^ win_state) { |
|
2432 #ifdef DEBUG |
|
2433 DTRACE_PRINT("WM: setting initial "); |
|
2434 awt_wm_dtraceStateWin(win_state); |
|
2435 #endif |
|
2436 XChangeProperty(dpy, shell_win, |
|
2437 _XA_WIN_STATE, XA_CARDINAL, 32, PropModeReplace, |
|
2438 (unsigned char *)&win_state, 1); |
|
2439 } |
|
2440 #ifdef DEBUG |
|
2441 else { |
|
2442 DTRACE_PRINTLN("WM: no changes to _WIN_STATE necessary"); |
|
2443 } |
|
2444 #endif |
|
2445 } |
|
2446 |
|
2447 /* |
|
2448 * Request a layer change from a _NET supporting WM by sending |
|
2449 * _NET_WM_STATE ClientMessage to root window. |
|
2450 */ |
|
2451 static void |
|
2452 awt_wm_requestLayerNet(struct FrameData *wdata, int state) |
|
2453 { |
|
2454 Widget shell = wdata->winData.shell; |
|
2455 Window shell_win = XtWindow(shell); |
|
2456 XClientMessageEvent req; |
|
2457 int currentLayer; |
|
2458 long cmd; |
|
2459 |
|
2460 /* must use awt_wm_setInitialLayerNet for withdrawn windows */ |
|
2461 DASSERT(wdata->isShowing); |
|
2462 |
|
2463 currentLayer = awt_wm_getLayerNet(shell_win); |
|
2464 if(state == currentLayer) { |
|
2465 return; |
|
2466 } |
|
2467 cmd = currentLayer == LAYER_ALWAYS_ON_TOP && state == LAYER_NORMAL ? |
|
2468 _NET_WM_STATE_REMOVE : |
|
2469 currentLayer == LAYER_NORMAL && state == LAYER_ALWAYS_ON_TOP ? |
|
2470 _NET_WM_STATE_ADD : |
|
2471 _NET_WM_STATE_ADD; |
|
2472 req.type = ClientMessage; |
|
2473 req.window = XtWindow(shell); |
|
2474 req.message_type = _XA_NET_WM_STATE; |
|
2475 req.format = 32; |
|
2476 req.data.l[0] = cmd; |
|
2477 req.data.l[1] = _XA_NET_WM_STATE_ABOVE; |
|
2478 req.data.l[2] = 0L; |
|
2479 |
|
2480 XSendEvent(XtDisplay(shell), RootWindowOfScreen(XtScreen(shell)), False, |
|
2481 (SubstructureRedirectMask | SubstructureNotifyMask), |
|
2482 (XEvent *)&req); |
|
2483 } |
|
2484 |
|
2485 /* |
|
2486 * Request a layer change from a Gnome WM (_WIN protocol) by sending |
|
2487 * _WIN_LAYER ClientMessage to root window. |
|
2488 */ |
|
2489 static void |
|
2490 awt_wm_requestLayerWin(struct FrameData *wdata, int state) |
|
2491 { |
|
2492 Widget shell = wdata->winData.shell; |
|
2493 XClientMessageEvent req; |
|
2494 Display *dpy = XtDisplay(shell); |
|
2495 |
|
2496 /* must use awt_wm_setInitialLayerWin for withdrawn windows */ |
|
2497 DASSERT(wdata->isShowing); |
|
2498 |
|
2499 req.type = ClientMessage; |
|
2500 req.window = XtWindow(shell); |
|
2501 req.message_type = _XA_WIN_LAYER; |
|
2502 req.format = 32; |
|
2503 req.data.l[0] = state == LAYER_NORMAL ? WIN_LAYER_NORMAL : WIN_LAYER_ONTOP; |
|
2504 req.data.l[1] = 0L; |
|
2505 req.data.l[2] = 0L; |
|
2506 |
|
2507 XSendEvent(XtDisplay(shell), RootWindowOfScreen(XtScreen(shell)), False, |
|
2508 /*(SubstructureRedirectMask |*/ |
|
2509 SubstructureNotifyMask, |
|
2510 (XEvent *)&req); |
|
2511 } |
|
2512 /* |
|
2513 * Specify initial layer for _NET supporting WM by setting |
|
2514 * _NET_WM_STATE property on the window to the desired state before |
|
2515 * mapping it. |
|
2516 * NB: looks like it doesn't have any effect. |
|
2517 */ |
|
2518 static void |
|
2519 awt_wm_setInitialLayerNet(struct FrameData *wdata, int state) |
|
2520 { |
|
2521 Widget shell = wdata->winData.shell; |
|
2522 Window shell_win = XtWindow(shell); |
|
2523 Display *dpy = XtDisplay(shell); |
|
2524 |
|
2525 Atom *old_state; |
|
2526 unsigned long nitems; |
|
2527 Atom new_state = _XA_NET_WM_STATE_ABOVE; |
|
2528 |
|
2529 /* must use awt_wm_requestLayerNet for managed windows */ |
|
2530 DASSERT(!wdata->isShowing); |
|
2531 |
|
2532 /* Be careful to not wipe out state bits we don't understand */ |
|
2533 old_state = awt_getAtomListProperty(shell_win, _XA_NET_WM_STATE, &nitems); |
|
2534 |
|
2535 if (nitems == 0 && state != LAYER_ALWAYS_ON_TOP) { |
|
2536 if (old_state != NULL) { |
|
2537 XFree(old_state); |
|
2538 } |
|
2539 return; |
|
2540 }else if( nitems == 0 && state == LAYER_ALWAYS_ON_TOP) { |
|
2541 unsigned long data[2]; |
|
2542 /* create new state */ |
|
2543 if (old_state != NULL) { |
|
2544 XFree(old_state); |
|
2545 } |
|
2546 nitems = 1; |
|
2547 data[0] = new_state; |
|
2548 data[1] = 0; |
|
2549 XChangeProperty(dpy, shell_win, |
|
2550 _XA_NET_WM_STATE, XA_ATOM, 32, PropModeReplace, |
|
2551 (unsigned char *)data, nitems); |
|
2552 XSync(dpy, False); |
|
2553 }else { /* nitems > 0 */ |
|
2554 unsigned long i; |
|
2555 Boolean bShift = False; |
|
2556 int mode; |
|
2557 for(i = 0; i < nitems; i++) { |
|
2558 if( bShift ) { |
|
2559 old_state[i-1] = old_state[i]; |
|
2560 }else if( old_state[i] == _XA_NET_WM_STATE_ABOVE ) { |
|
2561 if(state == LAYER_ALWAYS_ON_TOP) { |
|
2562 /* no change necessary */ |
|
2563 XFree(old_state); |
|
2564 return; |
|
2565 }else{ |
|
2566 /* wipe off this atom */ |
|
2567 bShift = True; |
|
2568 } |
|
2569 } |
|
2570 } |
|
2571 |
|
2572 if( bShift ) { |
|
2573 /* atom was found and removed: change property */ |
|
2574 mode = PropModeReplace; |
|
2575 nitems--; |
|
2576 }else if( state != LAYER_ALWAYS_ON_TOP ) { |
|
2577 /* atom was not found and not needed */ |
|
2578 XFree( old_state); |
|
2579 return; |
|
2580 }else { |
|
2581 /* must add new atom */ |
|
2582 mode = PropModeAppend; |
|
2583 nitems = 1; |
|
2584 } |
|
2585 |
|
2586 XChangeProperty(dpy, shell_win, |
|
2587 _XA_NET_WM_STATE, XA_ATOM, 32, mode, |
|
2588 mode == PropModeAppend ? |
|
2589 (unsigned char *)(&new_state) : |
|
2590 (unsigned char *)old_state, nitems); |
|
2591 XFree(old_state); |
|
2592 XSync(dpy, False); |
|
2593 } |
|
2594 } |
|
2595 |
|
2596 /* |
|
2597 * Specify initial layer for a Gnome WM (_WIN protocol) by setting |
|
2598 * WIN_LAYER property on the window to the desired state before |
|
2599 * mapping it. |
|
2600 */ |
|
2601 static void |
|
2602 awt_wm_setInitialLayerWin(struct FrameData *wdata, int state) |
|
2603 { |
|
2604 Display *dpy = XtDisplay(wdata->winData.shell); |
|
2605 Window shell_win = XtWindow(wdata->winData.shell); |
|
2606 long win_state, old_win_state; |
|
2607 int currentLayer; |
|
2608 |
|
2609 /* must use awt_wm_requestLayerWin for managed windows */ |
|
2610 DASSERT(!wdata->isShowing); |
|
2611 |
|
2612 currentLayer = awt_wm_getLayerWin(shell_win); |
|
2613 if( currentLayer == state ) { |
|
2614 /* no change necessary */ |
|
2615 return; |
|
2616 } |
|
2617 if( state == LAYER_ALWAYS_ON_TOP ) { |
|
2618 win_state = WIN_LAYER_ONTOP; |
|
2619 }else { |
|
2620 win_state = WIN_LAYER_NORMAL; |
|
2621 } |
|
2622 |
|
2623 XChangeProperty(dpy, shell_win, |
|
2624 _XA_WIN_LAYER, XA_CARDINAL, 32, PropModeReplace, |
|
2625 (unsigned char *)&win_state, 1); |
|
2626 } |
|
2627 |
|
2628 void |
|
2629 awt_wm_setExtendedState(struct FrameData *wdata, jint state) |
|
2630 { |
|
2631 Display *dpy = XtDisplay(wdata->winData.shell); |
|
2632 Window shell_win = XtWindow(wdata->winData.shell); |
|
2633 |
|
2634 #ifdef DEBUG |
|
2635 DTRACE_PRINT2("WM: setExtendedState(0x%x/0x%x) ", |
|
2636 wdata->winData.shell, shell_win); |
|
2637 awt_wm_dtraceStateJava(state); |
|
2638 #endif |
|
2639 |
|
2640 if (wdata->isShowing) { |
|
2641 /* |
|
2642 * If the window is managed by WM, we should send |
|
2643 * ClientMessage requests. |
|
2644 */ |
|
2645 if (awt_wm_doStateProtocolNet()) { |
|
2646 awt_wm_requestStateNet(wdata, state); |
|
2647 } |
|
2648 else if (awt_wm_doStateProtocolWin()) { |
|
2649 awt_wm_requestStateWin(wdata, state); |
|
2650 } |
|
2651 XSync(dpy, False); |
|
2652 } |
|
2653 else { |
|
2654 /* |
|
2655 * If the window is withdrawn we should set necessary |
|
2656 * properties directly to the window before mapping it. |
|
2657 */ |
|
2658 if (awt_wm_doStateProtocolNet()) { |
|
2659 awt_wm_setInitialStateNet(wdata, state); |
|
2660 } |
|
2661 else if (awt_wm_doStateProtocolWin()) { |
|
2662 awt_wm_setInitialStateWin(wdata, state); |
|
2663 } |
|
2664 #if 1 |
|
2665 /* |
|
2666 * Purge KWM bits. |
|
2667 * Not really tested with KWM, only with WindowMaker. |
|
2668 */ |
|
2669 XDeleteProperty(dpy, shell_win, XA_KWM_WIN_ICONIFIED); |
|
2670 XDeleteProperty(dpy, shell_win, XA_KWM_WIN_MAXIMIZED); |
|
2671 #endif /* 1 */ |
|
2672 } |
|
2673 } |
|
2674 |
|
2675 static Boolean |
|
2676 awt_wm_supportsLayersNet() { |
|
2677 Boolean supported = awt_wm_doStateProtocolNet(); |
|
2678 |
|
2679 /* |
|
2680 In fact, WM may report this not supported but do support. |
|
2681 */ |
|
2682 supported &= awt_wm_checkProtocol(_XA_NET_SUPPORTED, _XA_NET_WM_STATE_ABOVE); |
|
2683 return supported; |
|
2684 } |
|
2685 |
|
2686 static Boolean |
|
2687 awt_wm_supportsLayersWin() { |
|
2688 Boolean supported = awt_wm_doStateProtocolWin(); |
|
2689 /* |
|
2690 * In fact, WM may report this supported but do not support. |
|
2691 */ |
|
2692 supported &= awt_wm_checkProtocol(_XA_WIN_PROTOCOLS, _XA_WIN_LAYER); |
|
2693 return supported; |
|
2694 } |
|
2695 |
|
2696 void |
|
2697 awt_wm_updateAlwaysOnTop(struct FrameData *wdata, jboolean bLayerState) { |
|
2698 Display *dpy = XtDisplay(wdata->winData.shell); |
|
2699 Window shell_win = XtWindow(wdata->winData.shell); |
|
2700 int layerState = bLayerState ? LAYER_ALWAYS_ON_TOP : LAYER_NORMAL; |
|
2701 |
|
2702 if (wdata->isShowing) { |
|
2703 /** |
|
2704 We don't believe anyone, and now send both ClientMessage requests. |
|
2705 And eg Metacity under RH 6.1 required both to work. |
|
2706 **/ |
|
2707 awt_wm_requestLayerNet(wdata, layerState); |
|
2708 awt_wm_requestLayerWin(wdata, layerState); |
|
2709 } else { |
|
2710 /** |
|
2711 We don't believe anyone, and now set both atoms. |
|
2712 And eg Metacity under RH 6.1 required both to work. |
|
2713 **/ |
|
2714 awt_wm_setInitialLayerNet(wdata, layerState); |
|
2715 awt_wm_setInitialLayerWin(wdata, layerState); |
|
2716 } |
|
2717 XSync(dpy, False); |
|
2718 } |
|
2719 |
|
2720 /* |
|
2721 * Work around for 4775545. _NET version. |
|
2722 */ |
|
2723 static void |
|
2724 awt_wm_unshadeKludgeNet(struct FrameData *wdata) |
|
2725 { |
|
2726 Display *dpy = XtDisplay(wdata->winData.shell); |
|
2727 Window shell_win = XtWindow(wdata->winData.shell); |
|
2728 Atom *net_wm_state; |
|
2729 Boolean shaded; |
|
2730 unsigned long nitems; |
|
2731 unsigned long i; |
|
2732 |
|
2733 net_wm_state = awt_getAtomListProperty(shell_win, |
|
2734 _XA_NET_WM_STATE, &nitems); |
|
2735 if (nitems == 0) { |
|
2736 DTRACE_PRINTLN("WM: _NET_WM_STATE = { }"); |
|
2737 if (net_wm_state) { |
|
2738 XFree(net_wm_state); |
|
2739 } |
|
2740 return; |
|
2741 } |
|
2742 #ifdef DEBUG |
|
2743 DTRACE_PRINT("WM: "); |
|
2744 awt_wm_dtraceStateNet(net_wm_state, nitems); |
|
2745 #endif |
|
2746 |
|
2747 shaded = False; |
|
2748 for (i = 0; i < nitems; ++i) { |
|
2749 if (net_wm_state[i] == _XA_NET_WM_STATE_SHADED) { |
|
2750 shaded = True; |
|
2751 break; |
|
2752 } |
|
2753 } |
|
2754 |
|
2755 if (!shaded) { |
|
2756 DTRACE_PRINTLN("WM: not _SHADED, no workaround necessary"); |
|
2757 return; |
|
2758 } |
|
2759 |
|
2760 DTRACE_PRINTLN("WM: removing _SHADED"); |
|
2761 ++i; /* skip _SHADED */ |
|
2762 while (i < nitems) { /* copy the rest */ |
|
2763 net_wm_state[i-1] = net_wm_state[i]; |
|
2764 ++i; |
|
2765 } |
|
2766 --nitems; /* _SHADED has been removed */ |
|
2767 |
|
2768 #ifdef DEBUG |
|
2769 DTRACE_PRINT("WM: "); |
|
2770 awt_wm_dtraceStateNet(net_wm_state, nitems); |
|
2771 #endif |
|
2772 |
|
2773 WITH_XERROR_HANDLER(xerror_verify_change_property); |
|
2774 { |
|
2775 XChangeProperty(dpy, shell_win, |
|
2776 _XA_NET_WM_STATE, XA_ATOM, 32, PropModeReplace, |
|
2777 (unsigned char *)net_wm_state, nitems); |
|
2778 } |
|
2779 RESTORE_XERROR_HANDLER; |
|
2780 |
|
2781 if (xerror_code != Success) { |
|
2782 DTRACE_PRINTLN1("WM: XChangeProperty failed, error = %d", |
|
2783 xerror_code); |
|
2784 } |
|
2785 |
|
2786 XFree(net_wm_state); |
|
2787 } |
|
2788 |
|
2789 |
|
2790 /* |
|
2791 * Work around for 4775545. _WIN version. |
|
2792 */ |
|
2793 static void |
|
2794 awt_wm_unshadeKludgeWin(struct FrameData *wdata) |
|
2795 { |
|
2796 Display *dpy = XtDisplay(wdata->winData.shell); |
|
2797 Window shell_win = XtWindow(wdata->winData.shell); |
|
2798 long win_state; |
|
2799 |
|
2800 win_state = awt_getProperty32(shell_win, _XA_WIN_STATE, XA_CARDINAL); |
|
2801 #ifdef DEBUG |
|
2802 DTRACE_PRINT("WM: "); |
|
2803 awt_wm_dtraceStateWin(win_state); |
|
2804 #endif |
|
2805 |
|
2806 if ((win_state & WIN_STATE_SHADED) == 0) { |
|
2807 DTRACE_PRINTLN("WM: not _SHADED, no workaround necessary"); |
|
2808 return; |
|
2809 } |
|
2810 |
|
2811 win_state &= ~WIN_STATE_SHADED; |
|
2812 XChangeProperty(dpy, shell_win, |
|
2813 _XA_WIN_STATE, XA_CARDINAL, 32, PropModeReplace, |
|
2814 (unsigned char *)&win_state, 1); |
|
2815 } |
|
2816 |
|
2817 |
|
2818 /* |
|
2819 * Work around for 4775545. |
|
2820 * |
|
2821 * If WM exits while the top-level is shaded, the shaded hint remains |
|
2822 * on the top-level properties. When WM restarts and sees the shaded |
|
2823 * window it can reparent it into a "pre-shaded" decoration frame |
|
2824 * (Metacity does), and our insets logic will go crazy, b/c it will |
|
2825 * see a huge nagative bottom inset. There's no clean solution for |
|
2826 * this, so let's just be weasels and drop the shaded hint if we |
|
2827 * detect that WM exited. NB: we are in for a race condition with WM |
|
2828 * restart here. NB2: e.g. WindowMaker saves the state in a private |
|
2829 * property that this code knows nothing about, so this workaround is |
|
2830 * not effective; other WMs might play similar tricks. |
|
2831 */ |
|
2832 void |
|
2833 awt_wm_unshadeKludge(struct FrameData *wdata) |
|
2834 { |
|
2835 DTRACE_PRINTLN("WM: unshade kludge"); |
|
2836 DASSERT(wdata->isShowing); |
|
2837 |
|
2838 if (awt_wm_doStateProtocolNet()) { |
|
2839 awt_wm_unshadeKludgeNet(wdata); |
|
2840 } |
|
2841 else if (awt_wm_doStateProtocolWin()) { |
|
2842 awt_wm_unshadeKludgeWin(wdata); |
|
2843 } |
|
2844 #ifdef DEBUG |
|
2845 else { |
|
2846 DTRACE_PRINTLN("WM: not a _NET or _WIN supporting WM"); |
|
2847 } |
|
2848 #endif |
|
2849 |
|
2850 XSync(XtDisplay(wdata->winData.shell), False); |
|
2851 } |
|
2852 |
|
2853 |
|
2854 void |
|
2855 awt_wm_init(void) |
|
2856 { |
|
2857 static Boolean inited = False; |
|
2858 if (inited) { |
|
2859 return; |
|
2860 } |
|
2861 |
|
2862 awt_wm_initAtoms(); |
|
2863 awt_wm_getRunningWM(); |
|
2864 inited = True; |
|
2865 } |
|
2866 |
|
2867 Boolean awt_wm_supportsAlwaysOnTop() { |
|
2868 return awt_wm_supportsLayersNet() || awt_wm_supportsLayersWin(); |
|
2869 } |
|