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 }