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