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