blob: aaefa796a0a0d151d247a6d75721bd1c8e00b2ed [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2001-2006 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any 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 */
81static Atom XA_WM_STATE;
82
83/* New "netwm" spec from www.freedesktop.org */
84static Atom XA_UTF8_STRING; /* like STRING but encoding is UTF-8 */
85static Atom _XA_NET_SUPPORTING_WM_CHECK;
86static Atom _XA_NET_SUPPORTED; /* list of protocols (property of root) */
87static Atom _XA_NET_WM_NAME; /* window property */
88static 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 */
97static Atom _XA_NET_WM_STATE_MAXIMIZED_HORZ;
98static Atom _XA_NET_WM_STATE_MAXIMIZED_VERT;
99static Atom _XA_NET_WM_STATE_SHADED;
100static Atom _XA_NET_WM_STATE_ABOVE;
101static Atom _XA_NET_WM_STATE_BELOW;
102static 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) */
108static Atom _XA_WIN_SUPPORTING_WM_CHECK;
109static Atom _XA_WIN_PROTOCOLS;
110static Atom _XA_WIN_STATE;
111static Atom _XA_WIN_LAYER;
112
113/* Enlightenment */
114static Atom _XA_E_FRAME_SIZE;
115
116/* KWin (KDE2) */
117static Atom _XA_KDE_NET_WM_FRAME_STRUT;
118
119/* KWM (KDE 1.x) OBSOLETE??? */
120static Atom XA_KWM_WIN_ICONIFIED;
121static Atom XA_KWM_WIN_MAXIMIZED;
122
123/* OpenLook */
124static Atom _XA_OL_DECOR_DEL;
125static Atom _XA_OL_DECOR_HEADER;
126static Atom _XA_OL_DECOR_RESIZE;
127static Atom _XA_OL_DECOR_PIN;
128static 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 */
153static void
154awt_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 */
233static Boolean
234awt_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
260static void
261awt_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
282static void
283awt_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
309static void
310awt_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
337static void
338awt_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 */
379int /* but ingored */
380xerror_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 */
399static Atom *
400awt_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 */
449static unsigned char *
450awt_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 */
490static int32_t
491awt_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 */
549static Window
550awt_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 */
579static Window
580awt_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 */
601static Window
602awt_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 */
623static Boolean
624awt_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
651static Boolean
652awt_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
671static Boolean
672awt_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 */
698static Window
699awt_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 */
755static Boolean
756awt_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 */
790static Boolean
791awt_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 */
875static Boolean
876awt_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
946static Boolean
947awt_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 */
989static Boolean
990awt_wm_isSawfish(void)
991{
992 return awt_wm_isNetWMName("Sawfish");
993}
994
995/*
996 * Is KDE2 (KWin) running?
997 */
998static Boolean
999awt_wm_isKDE2(void)
1000{
1001 return awt_wm_isNetWMName("KWin");
1002}
1003
1004
1005/*
1006 * Is Metacity running?
1007 */
1008static Boolean
1009awt_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 */
1019static int /* but ignored */
1020xerror_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 */
1045static Boolean
1046awt_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 */
1091static Boolean
1092awt_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 */
1138static Boolean
1139awt_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
1164static Boolean winmgr_running = False;
1165
1166/*
1167 * Temporary error handler that checks if selecting for
1168 * SubstructureRedirect failed.
1169 */
1170static int /* but ignored */
1171xerror_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 */
1191enum wmgr_t
1192awt_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 */
1321Boolean
1322awt_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 */
1366Boolean
1367awt_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 */
1402void
1403awt_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 */
1457static void
1458awt_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 */
1483static int
1484awt_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 */
1502static void
1503awt_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 */
1549static void
1550awt_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 */
1609static Boolean
1610awt_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 */
1630void
1631awt_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 */
1674void
1675awt_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 */
1700void
1701awt_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 */
1732static Boolean
1733awt_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 */
1778Boolean
1779awt_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 */
1816int
1817awt_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 */
1862static jint
1863awt_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
1896Boolean
1897awt_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 */
1929static int
1930awt_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 */
1963static jint
1964awt_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 */
1988static int
1989awt_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
2008static jint
2009awt_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
2022jint
2023awt_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 */
2076Boolean
2077awt_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 */
2145static void
2146awt_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 */
2205static void
2206awt_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 */
2241static void
2242awt_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 */
2387static void
2388awt_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 */
2451static void
2452awt_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 */
2489static void
2490awt_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 */
2518static void
2519awt_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 */
2601static void
2602awt_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
2628void
2629awt_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
2675static Boolean
2676awt_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
2686static Boolean
2687awt_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
2696void
2697awt_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 */
2723static void
2724awt_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 */
2793static void
2794awt_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 */
2832void
2833awt_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
2854void
2855awt_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
2867Boolean awt_wm_supportsAlwaysOnTop() {
2868 return awt_wm_supportsLayersNet() || awt_wm_supportsLayersWin();
2869}