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 }