jdk/src/solaris/classes/sun/awt/X11/XWM.java
changeset 2 90ce3da70b43
child 107 ed0c7cfb3666
equal deleted inserted replaced
0:fd16c54261b3 2:90ce3da70b43
       
     1 /*
       
     2  * Copyright 2003-2006 Sun Microsystems, Inc.  All Rights Reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.  Sun designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Sun in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
       
    22  * CA 95054 USA or visit www.sun.com if you need additional information or
       
    23  * have any questions.
       
    24  */
       
    25 
       
    26 
       
    27 /**
       
    28  * Ported from awt_wm.c, SCCS v1.11, author Valeriy Ushakov
       
    29  * Author: Denis Mikhalkin
       
    30  */
       
    31 package sun.awt.X11;
       
    32 
       
    33 import sun.misc.Unsafe;
       
    34 import java.util.regex.*;
       
    35 import java.awt.Frame;
       
    36 import java.awt.Rectangle;
       
    37 import java.util.*;
       
    38 import java.util.logging.Level;
       
    39 import java.util.logging.LogManager;
       
    40 import java.util.logging.Logger;
       
    41 import java.awt.Insets;
       
    42 
       
    43 /**
       
    44  * Class incapsulating knowledge about window managers in general
       
    45  * Descendants should provide some information about specific window manager.
       
    46  */
       
    47 class XWM implements MWMConstants, XUtilConstants {
       
    48 
       
    49     private final static Logger log = Logger.getLogger("sun.awt.X11.XWM");
       
    50     private final static Logger insLog = Logger.getLogger("sun.awt.X11.insets.XWM");
       
    51     private final static Logger stateLog = Logger.getLogger("sun.awt.X11.states.XWM");
       
    52 
       
    53     static final XAtom XA_MWM_HINTS = new XAtom();
       
    54 
       
    55     private static Unsafe unsafe = XlibWrapper.unsafe;
       
    56 
       
    57 
       
    58 /* Good old ICCCM */
       
    59     static XAtom XA_WM_STATE = new XAtom();
       
    60 
       
    61 
       
    62     XAtom XA_UTF8_STRING = XAtom.get("UTF8_STRING");    /* like STRING but encoding is UTF-8 */
       
    63 
       
    64 /* Currently we only care about max_v and max_h in _NET_WM_STATE */
       
    65     final static int AWT_NET_N_KNOWN_STATES=2;
       
    66 
       
    67 /* Enlightenment */
       
    68     final static XAtom XA_E_FRAME_SIZE = new XAtom();
       
    69 
       
    70 /* KWin (KDE2) */
       
    71     final static XAtom XA_KDE_NET_WM_FRAME_STRUT = new XAtom();
       
    72 
       
    73 /* KWM (KDE 1.x) OBSOLETE??? */
       
    74     final static XAtom XA_KWM_WIN_ICONIFIED = new XAtom();
       
    75     final static XAtom XA_KWM_WIN_MAXIMIZED = new XAtom();
       
    76 
       
    77 /* OpenLook */
       
    78     final static XAtom XA_OL_DECOR_DEL = new XAtom();
       
    79     final static XAtom XA_OL_DECOR_HEADER = new XAtom();
       
    80     final static XAtom XA_OL_DECOR_RESIZE = new XAtom();
       
    81     final static XAtom XA_OL_DECOR_PIN = new XAtom();
       
    82     final static XAtom XA_OL_DECOR_CLOSE = new XAtom();
       
    83 
       
    84 /* EWMH */
       
    85     final static XAtom XA_NET_FRAME_EXTENTS = new XAtom();
       
    86     final static XAtom XA_NET_REQUEST_FRAME_EXTENTS = new XAtom();
       
    87 
       
    88     final static int
       
    89         UNDETERMINED_WM = 1,
       
    90         NO_WM = 2,
       
    91         OTHER_WM = 3,
       
    92         OPENLOOK_WM = 4,
       
    93         MOTIF_WM = 5,
       
    94         CDE_WM = 6,
       
    95         ENLIGHTEN_WM = 7,
       
    96         KDE2_WM = 8,
       
    97         SAWFISH_WM = 9,
       
    98         ICE_WM = 10,
       
    99         METACITY_WM = 11,
       
   100         COMPIZ_WM = 12,
       
   101         LG3D_WM = 13;
       
   102     public String toString() {
       
   103         switch  (WMID) {
       
   104           case NO_WM:
       
   105               return "NO WM";
       
   106           case OTHER_WM:
       
   107               return "Other WM";
       
   108           case OPENLOOK_WM:
       
   109               return "OPENLOOK";
       
   110           case MOTIF_WM:
       
   111               return "MWM";
       
   112           case CDE_WM:
       
   113               return "DTWM";
       
   114           case ENLIGHTEN_WM:
       
   115               return "Enlightenment";
       
   116           case KDE2_WM:
       
   117               return "KWM2";
       
   118           case SAWFISH_WM:
       
   119               return "Sawfish";
       
   120           case ICE_WM:
       
   121               return "IceWM";
       
   122           case METACITY_WM:
       
   123               return "Metacity";
       
   124           case COMPIZ_WM:
       
   125               return "Compiz";
       
   126           case LG3D_WM:
       
   127               return "LookingGlass";
       
   128           case UNDETERMINED_WM:
       
   129           default:
       
   130               return "Undetermined WM";
       
   131         }
       
   132     }
       
   133 
       
   134 
       
   135     int WMID;
       
   136     static final Insets zeroInsets = new Insets(0, 0, 0, 0);
       
   137     static final Insets defaultInsets = new Insets(25, 5, 5, 5);
       
   138 
       
   139     XWM(int WMID) {
       
   140         this.WMID = WMID;
       
   141         initializeProtocols();
       
   142         if (log.isLoggable(Level.FINE)) log.fine("Window manager: " + toString());
       
   143     }
       
   144     int getID() {
       
   145         return WMID;
       
   146     }
       
   147 
       
   148 
       
   149     static Insets normalize(Insets insets) {
       
   150         if (insets.top > 64 || insets.top < 0) {
       
   151             insets.top = 28;
       
   152         }
       
   153         if (insets.left > 32 || insets.left < 0) {
       
   154             insets.left = 6;
       
   155         }
       
   156         if (insets.right > 32 || insets.right < 0) {
       
   157             insets.right = 6;
       
   158         }
       
   159         if (insets.bottom > 32 || insets.bottom < 0) {
       
   160             insets.bottom = 6;
       
   161         }
       
   162         return insets;
       
   163     }
       
   164 
       
   165     static XNETProtocol g_net_protocol = null;
       
   166     static XWINProtocol g_win_protocol = null;
       
   167     static boolean isNetWMName(String name) {
       
   168         if (g_net_protocol != null) {
       
   169             return g_net_protocol.isWMName(name);
       
   170         } else {
       
   171             return false;
       
   172         }
       
   173     }
       
   174 
       
   175     static void initAtoms() {
       
   176         final Object[][] atomInitList ={
       
   177             { XA_WM_STATE,                      "WM_STATE"                  },
       
   178 
       
   179             { XA_KDE_NET_WM_FRAME_STRUT,    "_KDE_NET_WM_FRAME_STRUT"       },
       
   180 
       
   181             { XA_E_FRAME_SIZE,              "_E_FRAME_SIZE"                 },
       
   182 
       
   183             { XA_KWM_WIN_ICONIFIED,          "KWM_WIN_ICONIFIED"             },
       
   184             { XA_KWM_WIN_MAXIMIZED,          "KWM_WIN_MAXIMIZED"             },
       
   185 
       
   186             { XA_OL_DECOR_DEL,               "_OL_DECOR_DEL"                 },
       
   187             { XA_OL_DECOR_HEADER,            "_OL_DECOR_HEADER"              },
       
   188             { XA_OL_DECOR_RESIZE,            "_OL_DECOR_RESIZE"              },
       
   189             { XA_OL_DECOR_PIN,               "_OL_DECOR_PIN"                 },
       
   190             { XA_OL_DECOR_CLOSE,             "_OL_DECOR_CLOSE"               },
       
   191             { XA_MWM_HINTS,                  "_MOTIF_WM_HINTS"               },
       
   192             { XA_NET_FRAME_EXTENTS,          "_NET_FRAME_EXTENTS"            },
       
   193             { XA_NET_REQUEST_FRAME_EXTENTS,  "_NET_REQUEST_FRAME_EXTENTS"    },
       
   194         };
       
   195 
       
   196         String[] names = new String[atomInitList.length];
       
   197         for (int index = 0; index < names.length; index++) {
       
   198             names[index] = (String)atomInitList[index][1];
       
   199         }
       
   200 
       
   201         int atomSize = XAtom.getAtomSize();
       
   202         long atoms = unsafe.allocateMemory(names.length*atomSize);
       
   203         XToolkit.awtLock();
       
   204         try {
       
   205             int status = XlibWrapper.XInternAtoms(XToolkit.getDisplay(), names, false, atoms);
       
   206             if (status == 0) {
       
   207                 return;
       
   208             }
       
   209             for (int atom = 0, atomPtr = 0; atom < names.length; atom++, atomPtr += atomSize) {
       
   210                 ((XAtom)(atomInitList[atom][0])).setValues(XToolkit.getDisplay(), names[atom], XAtom.getAtom(atoms + atomPtr));
       
   211             }
       
   212         } finally {
       
   213             XToolkit.awtUnlock();
       
   214             unsafe.freeMemory(atoms);
       
   215         }
       
   216     }
       
   217 
       
   218     /*
       
   219      * MUST BE CALLED UNDER AWTLOCK.
       
   220      *
       
   221      * If *any* window manager is running?
       
   222      *
       
   223      * According to ICCCM 2.0 section 4.3.
       
   224      * WM will acquire ownership of a selection named WM_Sn, where n is
       
   225      * the screen number.
       
   226      *
       
   227      * No selection owner, but, perhaps it is not ICCCM compliant WM
       
   228      * (e.g. CDE/Sawfish).
       
   229      * Try selecting for SubstructureRedirect, that only one client
       
   230      * can select for, and if the request fails, than some other WM is
       
   231      * already running.
       
   232      *
       
   233      * We also treat eXcursion as NO_WM.
       
   234      */
       
   235     private static boolean isNoWM() {
       
   236         /*
       
   237          * Quick checks for specific servers.
       
   238          */
       
   239         String vendor_string = XlibWrapper.ServerVendor(XToolkit.getDisplay());
       
   240         if (vendor_string.indexOf("eXcursion") != -1) {
       
   241             /*
       
   242              * Use NO_WM since in all other aspects eXcursion is like not
       
   243              * having a window manager running. I.e. it does not reparent
       
   244              * top level shells.
       
   245              */
       
   246             if (insLog.isLoggable(Level.FINE)) {
       
   247                 insLog.finer("eXcursion means NO_WM");
       
   248             }
       
   249             return true;
       
   250         }
       
   251 
       
   252         XSetWindowAttributes substruct = new XSetWindowAttributes();
       
   253         try {
       
   254             /*
       
   255              * Let's check an owner of WM_Sn selection for the default screen.
       
   256              */
       
   257             final long default_screen_number =
       
   258                 XlibWrapper.DefaultScreen(XToolkit.getDisplay());
       
   259             final String selection_name = "WM_S" + default_screen_number;
       
   260 
       
   261             long selection_owner =
       
   262                 XlibWrapper.XGetSelectionOwner(XToolkit.getDisplay(),
       
   263                                                XAtom.get(selection_name).getAtom());
       
   264             if (insLog.isLoggable(Level.FINE)) {
       
   265                 insLog.finer("selection owner of " + selection_name
       
   266                              + " is " + selection_owner);
       
   267             }
       
   268 
       
   269             if (selection_owner != XConstants.None) {
       
   270                 return false;
       
   271             }
       
   272 
       
   273             winmgr_running = false;
       
   274             substruct.set_event_mask(XlibWrapper.SubstructureRedirectMask);
       
   275 
       
   276             XToolkit.WITH_XERROR_HANDLER(DetectWMHandler);
       
   277             XlibWrapper.XChangeWindowAttributes(XToolkit.getDisplay(),
       
   278                                                 XToolkit.getDefaultRootWindow(),
       
   279                                                 XlibWrapper.CWEventMask,
       
   280                                                 substruct.pData);
       
   281             XToolkit.RESTORE_XERROR_HANDLER();
       
   282 
       
   283             /*
       
   284              * If no WM is running then our selection for SubstructureRedirect
       
   285              * succeeded and needs to be undone (hey we are *not* a WM ;-).
       
   286              */
       
   287             if (!winmgr_running) {
       
   288                 substruct.set_event_mask(0);
       
   289                 XlibWrapper.XChangeWindowAttributes(XToolkit.getDisplay(),
       
   290                                                     XToolkit.getDefaultRootWindow(),
       
   291                                                     XlibWrapper.CWEventMask,
       
   292                                                     substruct.pData);
       
   293                 if (insLog.isLoggable(Level.FINE)) {
       
   294                     insLog.finer("It looks like there is no WM thus NO_WM");
       
   295                 }
       
   296             }
       
   297 
       
   298             return !winmgr_running;
       
   299         } finally {
       
   300             substruct.dispose();
       
   301         }
       
   302     }
       
   303 
       
   304     static XAtom XA_ENLIGHTENMENT_COMMS = new XAtom("ENLIGHTENMENT_COMMS", false);
       
   305     /*
       
   306      * Helper function for isEnlightenment().
       
   307      * Enlightenment uses STRING property for its comms window id.  Gaaa!
       
   308      * The property is ENLIGHTENMENT_COMMS, STRING/8 and the string format
       
   309      * is "WINID %8x".  Gee, I haven't been using scanf for *ages*... :-)
       
   310      */
       
   311     static long getECommsWindowIDProperty(long window) {
       
   312 
       
   313         if (!XA_ENLIGHTENMENT_COMMS.isInterned()) {
       
   314             return 0;
       
   315         }
       
   316 
       
   317         WindowPropertyGetter getter =
       
   318             new WindowPropertyGetter(window, XA_ENLIGHTENMENT_COMMS, 0, 14, false,
       
   319                                      XAtom.XA_STRING);
       
   320         try {
       
   321             int status = getter.execute(XToolkit.IgnoreBadWindowHandler);
       
   322             if (status != XlibWrapper.Success || getter.getData() == 0) {
       
   323                 return 0;
       
   324             }
       
   325 
       
   326             if (getter.getActualType() != XAtom.XA_STRING
       
   327                 || getter.getActualFormat() != 8
       
   328                 || getter.getNumberOfItems() != 14 || getter.getBytesAfter() != 0)
       
   329             {
       
   330                 return 0;
       
   331             }
       
   332 
       
   333             // Convert data to String, ASCII
       
   334             byte[] bytes = XlibWrapper.getStringBytes(getter.getData());
       
   335             String id = new String(bytes);
       
   336 
       
   337             log.finer("ENLIGHTENMENT_COMMS is " + id);
       
   338 
       
   339             // Parse WINID
       
   340             Pattern winIdPat = Pattern.compile("WINID\\s+(\\p{XDigit}{0,8})");
       
   341             try {
       
   342                 Matcher match = winIdPat.matcher(id);
       
   343                 if (match.matches()) {
       
   344                     log.finest("Match group count: " + match.groupCount());
       
   345                     String longId = match.group(1);
       
   346                     log.finest("Match group 1 " + longId);
       
   347                     long winid = Long.parseLong(longId, 16);
       
   348                     log.finer("Enlightenment communication window " + winid);
       
   349                     return winid;
       
   350                 } else {
       
   351                     log.finer("ENLIGHTENMENT_COMMS has wrong format");
       
   352                     return 0;
       
   353                 }
       
   354             } catch (Exception e) {
       
   355                 if (log.isLoggable(Level.FINER)) {
       
   356                     e.printStackTrace();
       
   357                 }
       
   358                 return 0;
       
   359             }
       
   360         } finally {
       
   361             getter.dispose();
       
   362         }
       
   363     }
       
   364 
       
   365     /*
       
   366      * Is Enlightenment WM running?  Congruent to awt_wm_checkAnchor, but
       
   367      * uses STRING property peculiar to Enlightenment.
       
   368      */
       
   369     static boolean isEnlightenment() {
       
   370 
       
   371         long root_xref = getECommsWindowIDProperty(XToolkit.getDefaultRootWindow());
       
   372         if (root_xref == 0) {
       
   373             return false;
       
   374         }
       
   375 
       
   376         long self_xref = getECommsWindowIDProperty(root_xref);
       
   377         if (self_xref != root_xref) {
       
   378             return false;
       
   379         }
       
   380 
       
   381         return true;
       
   382     }
       
   383 
       
   384     /*
       
   385      * Is CDE running?
       
   386      *
       
   387      * XXX: This is hairy...  CDE is MWM as well.  It seems we simply test
       
   388      * for default setup and will be bitten if user changes things...
       
   389      *
       
   390      * Check for _DT_SM_WINDOW_INFO(_DT_SM_WINDOW_INFO) on root.  Take the
       
   391      * second element of the property and check for presence of
       
   392      * _DT_SM_STATE_INFO(_DT_SM_STATE_INFO) on that window.
       
   393      *
       
   394      * XXX: Any header that defines this structures???
       
   395      */
       
   396     static final XAtom XA_DT_SM_WINDOW_INFO = new XAtom("_DT_SM_WINDOW_INFO", false);
       
   397     static final XAtom XA_DT_SM_STATE_INFO = new XAtom("_DT_SM_STATE_INFO", false);
       
   398     static boolean isCDE() {
       
   399 
       
   400         if (!XA_DT_SM_WINDOW_INFO.isInterned()) {
       
   401             log.log(Level.FINER, "{0} is not interned", new Object[] {XA_DT_SM_WINDOW_INFO});
       
   402             return false;
       
   403         }
       
   404 
       
   405         WindowPropertyGetter getter =
       
   406             new WindowPropertyGetter(XToolkit.getDefaultRootWindow(),
       
   407                                      XA_DT_SM_WINDOW_INFO, 0, 2,
       
   408                                      false, XA_DT_SM_WINDOW_INFO);
       
   409         try {
       
   410             int status = getter.execute();
       
   411             if (status != XlibWrapper.Success || getter.getData() == 0) {
       
   412                 log.finer("Getting of _DT_SM_WINDOW_INFO is not successfull");
       
   413                 return false;
       
   414             }
       
   415             if (getter.getActualType() != XA_DT_SM_WINDOW_INFO.getAtom()
       
   416                 || getter.getActualFormat() != 32
       
   417                 || getter.getNumberOfItems() != 2 || getter.getBytesAfter() != 0)
       
   418             {
       
   419                 log.finer("Wrong format of _DT_SM_WINDOW_INFO");
       
   420                 return false;
       
   421             }
       
   422 
       
   423             long wmwin = Native.getWindow(getter.getData(), 1); //unsafe.getInt(getter.getData()+4);
       
   424 
       
   425             if (wmwin == 0) {
       
   426                 log.fine("WARNING: DT_SM_WINDOW_INFO exists but returns zero windows");
       
   427                 return false;
       
   428             }
       
   429 
       
   430             /* Now check that this window has _DT_SM_STATE_INFO (ignore contents) */
       
   431             if (!XA_DT_SM_STATE_INFO.isInterned()) {
       
   432                 log.log(Level.FINER, "{0} is not interned", new Object[] {XA_DT_SM_STATE_INFO});
       
   433                 return false;
       
   434             }
       
   435             WindowPropertyGetter getter2 =
       
   436                 new WindowPropertyGetter(wmwin, XA_DT_SM_STATE_INFO, 0, 1,
       
   437                                          false, XA_DT_SM_STATE_INFO);
       
   438             try {
       
   439                 status = getter2.execute(XToolkit.IgnoreBadWindowHandler);
       
   440 
       
   441 
       
   442                 if (status != XlibWrapper.Success || getter2.getData() == 0) {
       
   443                     log.finer("Getting of _DT_SM_STATE_INFO is not successfull");
       
   444                     return false;
       
   445                 }
       
   446                 if (getter2.getActualType() != XA_DT_SM_STATE_INFO.getAtom()
       
   447                     || getter2.getActualFormat() != 32)
       
   448                 {
       
   449                     log.finer("Wrong format of _DT_SM_STATE_INFO");
       
   450                     return false;
       
   451                 }
       
   452 
       
   453                 return true;
       
   454             } finally {
       
   455                 getter2.dispose();
       
   456             }
       
   457         } finally {
       
   458             getter.dispose();
       
   459         }
       
   460     }
       
   461 
       
   462     /*
       
   463      * Is MWM running?  (Note that CDE will test positive as well).
       
   464      *
       
   465      * Check for _MOTIF_WM_INFO(_MOTIF_WM_INFO) on root.  Take the
       
   466      * second element of the property and check for presence of
       
   467      * _DT_SM_STATE_INFO(_DT_SM_STATE_INFO) on that window.
       
   468      */
       
   469     static final XAtom XA_MOTIF_WM_INFO = new XAtom("_MOTIF_WM_INFO", false);
       
   470     static final XAtom XA_DT_WORKSPACE_CURRENT = new XAtom("_DT_WORKSPACE_CURRENT", false);
       
   471     static boolean isMotif() {
       
   472 
       
   473         if (!(XA_MOTIF_WM_INFO.isInterned()/* && XA_DT_WORKSPACE_CURRENT.isInterned()*/) ) {
       
   474             return false;
       
   475         }
       
   476 
       
   477         WindowPropertyGetter getter =
       
   478             new WindowPropertyGetter(XToolkit.getDefaultRootWindow(),
       
   479                                      XA_MOTIF_WM_INFO, 0,
       
   480                                      PROP_MOTIF_WM_INFO_ELEMENTS,
       
   481                                      false, XA_MOTIF_WM_INFO);
       
   482         try {
       
   483             int status = getter.execute();
       
   484 
       
   485             if (status != XlibWrapper.Success || getter.getData() == 0) {
       
   486                 return false;
       
   487             }
       
   488 
       
   489             if (getter.getActualType() != XA_MOTIF_WM_INFO.getAtom()
       
   490                 || getter.getActualFormat() != 32
       
   491                 || getter.getNumberOfItems() != PROP_MOTIF_WM_INFO_ELEMENTS
       
   492                 || getter.getBytesAfter() != 0)
       
   493             {
       
   494                 return false;
       
   495             }
       
   496 
       
   497             long wmwin = Native.getLong(getter.getData(), 1);
       
   498             if (wmwin != 0) {
       
   499                 if (XA_DT_WORKSPACE_CURRENT.isInterned()) {
       
   500                     /* Now check that this window has _DT_WORKSPACE_CURRENT */
       
   501                     XAtom[] curws = XA_DT_WORKSPACE_CURRENT.getAtomListProperty(wmwin);
       
   502                     if (curws.length == 0) {
       
   503                         return false;
       
   504                     }
       
   505                     return true;
       
   506                 } else {
       
   507                     // No DT_WORKSPACE, however in our tests MWM sometimes can be without desktop -
       
   508                     // and that is still MWM.  So simply check for the validity of this window
       
   509                     // (through WM_STATE property).
       
   510                     WindowPropertyGetter state_getter =
       
   511                         new WindowPropertyGetter(wmwin,
       
   512                                                  XA_WM_STATE,
       
   513                                                  0, 1, false,
       
   514                                                  XA_WM_STATE);
       
   515                     try {
       
   516                         if (state_getter.execute() == XlibWrapper.Success &&
       
   517                             state_getter.getData() != 0 &&
       
   518                             state_getter.getActualType() == XA_WM_STATE.getAtom())
       
   519                         {
       
   520                             return true;
       
   521                         }
       
   522                     } finally {
       
   523                         state_getter.dispose();
       
   524                     }
       
   525                 }
       
   526             }
       
   527         } finally {
       
   528             getter.dispose();
       
   529         }
       
   530         return false;
       
   531     }
       
   532 
       
   533     /*
       
   534      * Is Sawfish running?
       
   535      */
       
   536     static boolean isSawfish() {
       
   537         return isNetWMName("Sawfish");
       
   538     }
       
   539 
       
   540     /*
       
   541      * Is KDE2 (KWin) running?
       
   542      */
       
   543     static boolean isKDE2() {
       
   544         return isNetWMName("KWin");
       
   545     }
       
   546 
       
   547     static boolean isCompiz() {
       
   548         return isNetWMName("compiz");
       
   549     }
       
   550 
       
   551     static boolean isLookingGlass() {
       
   552         return isNetWMName("LG3D");
       
   553     }
       
   554 
       
   555     /*
       
   556      * Is Metacity running?
       
   557      */
       
   558     static boolean isMetacity() {
       
   559         return isNetWMName("Metacity");
       
   560 //         || (
       
   561 //             XA_NET_SUPPORTING_WM_CHECK.
       
   562 //             getIntProperty(XToolkit.getDefaultRootWindow(), XA_NET_SUPPORTING_WM_CHECK.
       
   563 //                            getIntProperty(XToolkit.getDefaultRootWindow(), XAtom.XA_CARDINAL)) == 0);
       
   564     }
       
   565 
       
   566     static boolean isNonReparentingWM() {
       
   567         return (XWM.getWMID() == XWM.COMPIZ_WM || XWM.getWMID() == XWM.LG3D_WM);
       
   568     }
       
   569 
       
   570     /*
       
   571      * Temporary error handler that ensures that we know if
       
   572      * XChangeProperty succeeded or not.
       
   573      */
       
   574     static XToolkit.XErrorHandler VerifyChangePropertyHandler = new XToolkit.XErrorHandler() {
       
   575             public int handleError(long display, XErrorEvent err) {
       
   576                 XToolkit.XERROR_SAVE(err);
       
   577                 if (err.get_request_code() == XlibWrapper.X_ChangeProperty) {
       
   578                     return 0;
       
   579                 } else {
       
   580                     return XToolkit.SAVED_ERROR_HANDLER(display, err);
       
   581                 }
       
   582             }
       
   583         };
       
   584 
       
   585     /*
       
   586      * Prepare IceWM check.
       
   587      *
       
   588      * The only way to detect IceWM, seems to be by setting
       
   589      * _ICEWM_WINOPTHINT(_ICEWM_WINOPTHINT/8) on root and checking if it
       
   590      * was immediately deleted by IceWM.
       
   591      *
       
   592      * But messing with PropertyNotify here is way too much trouble, so
       
   593      * approximate the check by setting the property in this function and
       
   594      * checking if it still exists later on.
       
   595      *
       
   596      * Gaa, dirty dances...
       
   597      */
       
   598     static final XAtom XA_ICEWM_WINOPTHINT = new XAtom("_ICEWM_WINOPTHINT", false);
       
   599     static final char opt[] = {
       
   600         'A','W','T','_','I','C','E','W','M','_','T','E','S','T','\0',
       
   601         'a','l','l','W','o','r','k','s','p','a','c','e','s','\0',
       
   602         '0','\0'
       
   603     };
       
   604     static boolean prepareIsIceWM() {
       
   605         /*
       
   606          * Choose something innocuous: "AWT_ICEWM_TEST allWorkspaces 0".
       
   607          * IceWM expects "class\0option\0arg\0" with zero bytes as delimiters.
       
   608          */
       
   609 
       
   610         if (!XA_ICEWM_WINOPTHINT.isInterned()) {
       
   611             log.log(Level.FINER, "{0} is not interned", new Object[] {XA_ICEWM_WINOPTHINT});
       
   612             return false;
       
   613         }
       
   614 
       
   615         XToolkit.awtLock();
       
   616         try {
       
   617             XToolkit.WITH_XERROR_HANDLER(VerifyChangePropertyHandler);
       
   618             XlibWrapper.XChangePropertyS(XToolkit.getDisplay(), XToolkit.getDefaultRootWindow(),
       
   619                                          XA_ICEWM_WINOPTHINT.getAtom(),
       
   620                                          XA_ICEWM_WINOPTHINT.getAtom(),
       
   621                                          8, XlibWrapper.PropModeReplace,
       
   622                                          new String(opt));
       
   623             XToolkit.RESTORE_XERROR_HANDLER();
       
   624 
       
   625             if (XToolkit.saved_error != null && XToolkit.saved_error.get_error_code() != XlibWrapper.Success) {
       
   626                 log.finer("Erorr getting XA_ICEWM_WINOPTHINT property");
       
   627                 return false;
       
   628             }
       
   629             log.finer("Prepared for IceWM detection");
       
   630             return true;
       
   631         } finally {
       
   632             XToolkit.awtUnlock();
       
   633         }
       
   634     }
       
   635 
       
   636     /*
       
   637      * Is IceWM running?
       
   638      *
       
   639      * Note well: Only call this if awt_wm_prepareIsIceWM succeeded, or a
       
   640      * false positive will be reported.
       
   641      */
       
   642     static boolean isIceWM() {
       
   643         if (!XA_ICEWM_WINOPTHINT.isInterned()) {
       
   644             log.log(Level.FINER, "{0} is not interned", new Object[] {XA_ICEWM_WINOPTHINT});
       
   645             return false;
       
   646         }
       
   647 
       
   648         WindowPropertyGetter getter =
       
   649             new WindowPropertyGetter(XToolkit.getDefaultRootWindow(),
       
   650                                      XA_ICEWM_WINOPTHINT, 0, 0xFFFF,
       
   651                                      true, XA_ICEWM_WINOPTHINT);
       
   652         try {
       
   653             int status = getter.execute();
       
   654             boolean res = (status == XlibWrapper.Success && getter.getActualType() != 0);
       
   655             log.finer("Status getting XA_ICEWM_WINOPTHINT: " + !res);
       
   656             return !res || isNetWMName("IceWM");
       
   657         } finally {
       
   658             getter.dispose();
       
   659         }
       
   660     }
       
   661 
       
   662     /*
       
   663      * Is OpenLook WM running?
       
   664      *
       
   665      * This one is pretty lame, but the only property peculiar to OLWM is
       
   666      * _SUN_WM_PROTOCOLS(ATOM[]).  Fortunately, olwm deletes it on exit.
       
   667      */
       
   668     static final XAtom XA_SUN_WM_PROTOCOLS = new XAtom("_SUN_WM_PROTOCOLS", false);
       
   669     static boolean isOpenLook() {
       
   670         if (!XA_SUN_WM_PROTOCOLS.isInterned()) {
       
   671             return false;
       
   672         }
       
   673 
       
   674         XAtom[] list = XA_SUN_WM_PROTOCOLS.getAtomListProperty(XToolkit.getDefaultRootWindow());
       
   675         return (list.length != 0);
       
   676     }
       
   677 
       
   678     /*
       
   679      * Temporary error handler that checks if selecting for
       
   680      * SubstructureRedirect failed.
       
   681      */
       
   682     static boolean winmgr_running = false;
       
   683     static XToolkit.XErrorHandler DetectWMHandler = new XToolkit.XErrorHandler() {
       
   684             public int handleError(long display, XErrorEvent err) {
       
   685                 XToolkit.XERROR_SAVE(err);
       
   686                 if (err.get_request_code() == XlibWrapper.X_ChangeWindowAttributes
       
   687                     && err.get_error_code() == XlibWrapper.BadAccess)
       
   688                 {
       
   689                     winmgr_running = true;
       
   690                     return 0;
       
   691                 } else {
       
   692                     return XToolkit.SAVED_ERROR_HANDLER(display, err);
       
   693                 }
       
   694             }
       
   695         };
       
   696 
       
   697     /*
       
   698      * Make an educated guess about running window manager.
       
   699      * XXX: ideally, we should detect wm restart.
       
   700      */
       
   701     static int awt_wmgr = XWM.UNDETERMINED_WM;
       
   702     static XWM wm;
       
   703     static XWM getWM() {
       
   704         if (wm == null) {
       
   705             wm = new XWM(awt_wmgr = getWMID()/*XWM.OTHER_WM*/);
       
   706         }
       
   707         return wm;
       
   708     }
       
   709     static int getWMID() {
       
   710         if (insLog.isLoggable(Level.FINEST)) {
       
   711             insLog.finest("awt_wmgr = " + awt_wmgr);
       
   712         }
       
   713         /*
       
   714          * Ideally, we should support cases when a different WM is started
       
   715          * during a Java app lifetime.
       
   716          */
       
   717 
       
   718         if (awt_wmgr != XWM.UNDETERMINED_WM) {
       
   719             return awt_wmgr;
       
   720         }
       
   721 
       
   722         XSetWindowAttributes substruct = new XSetWindowAttributes();
       
   723         XToolkit.awtLock();
       
   724         try {
       
   725             if (isNoWM()) {
       
   726                 awt_wmgr = XWM.NO_WM;
       
   727                 return awt_wmgr;
       
   728             }
       
   729 
       
   730             // Initialize _NET protocol - used to detect Window Manager.
       
   731             // Later, WM will initialize its own version of protocol
       
   732             XNETProtocol l_net_protocol = g_net_protocol = new XNETProtocol();
       
   733             l_net_protocol.detect();
       
   734             if (log.isLoggable(Level.FINE) && l_net_protocol.active()) {
       
   735                 log.fine("_NET_WM_NAME is " + l_net_protocol.getWMName());
       
   736             }
       
   737             XWINProtocol win = g_win_protocol = new XWINProtocol();
       
   738             win.detect();
       
   739 
       
   740             /* actual check for IceWM to follow below */
       
   741             boolean doIsIceWM = prepareIsIceWM(); /* and let IceWM to act */
       
   742 
       
   743             /*
       
   744              * Ok, some WM is out there.  Check which one by testing for
       
   745              * "distinguishing" atoms.
       
   746              */
       
   747             if (isEnlightenment()) {
       
   748                 awt_wmgr = XWM.ENLIGHTEN_WM;
       
   749             } else if (isMetacity()) {
       
   750                 awt_wmgr = XWM.METACITY_WM;
       
   751             } else if (isSawfish()) {
       
   752                 awt_wmgr = XWM.SAWFISH_WM;
       
   753             } else if (isKDE2()) {
       
   754                 awt_wmgr =XWM.KDE2_WM;
       
   755             } else if (isCompiz()) {
       
   756                 awt_wmgr = XWM.COMPIZ_WM;
       
   757             } else if (isLookingGlass()) {
       
   758                 awt_wmgr = LG3D_WM;
       
   759             } else if (doIsIceWM && isIceWM()) {
       
   760                 awt_wmgr = XWM.ICE_WM;
       
   761             }
       
   762             /*
       
   763              * We don't check for legacy WM when we already know that WM
       
   764              * supports WIN or _NET wm spec.
       
   765              */
       
   766             else if (l_net_protocol.active()) {
       
   767                 awt_wmgr = XWM.OTHER_WM;
       
   768             } else if (win.active()) {
       
   769                 awt_wmgr = XWM.OTHER_WM;
       
   770             }
       
   771             /*
       
   772              * Check for legacy WMs.
       
   773              */
       
   774             else if (isCDE()) { /* XXX: must come before isMotif */
       
   775                 awt_wmgr = XWM.CDE_WM;
       
   776             } else if (isMotif()) {
       
   777                 awt_wmgr = XWM.MOTIF_WM;
       
   778             } else if (isOpenLook()) {
       
   779                 awt_wmgr = XWM.OPENLOOK_WM;
       
   780             } else {
       
   781                 awt_wmgr = XWM.OTHER_WM;
       
   782             }
       
   783 
       
   784             return awt_wmgr;
       
   785         } finally {
       
   786             XToolkit.awtUnlock();
       
   787             substruct.dispose();
       
   788         }
       
   789     }
       
   790 
       
   791 
       
   792 /*****************************************************************************\
       
   793  *
       
   794  * Size and decoration hints ...
       
   795  *
       
   796 \*****************************************************************************/
       
   797 
       
   798 
       
   799     /*
       
   800      * Remove size hints specified by the mask.
       
   801      * XXX: Why do we need this in the first place???
       
   802      */
       
   803     static void removeSizeHints(XDecoratedPeer window, long mask) {
       
   804         mask &= PMaxSize | PMinSize;
       
   805 
       
   806         XToolkit.awtLock();
       
   807         try {
       
   808             XSizeHints hints = window.getHints();
       
   809             if ((hints.get_flags() & mask) == 0) {
       
   810                 return;
       
   811             }
       
   812 
       
   813             hints.set_flags(hints.get_flags() & ~mask);
       
   814             if (insLog.isLoggable(Level.FINER)) insLog.finer("Setting hints, flags " + XlibWrapper.hintsToString(hints.get_flags()));
       
   815             XlibWrapper.XSetWMNormalHints(XToolkit.getDisplay(),
       
   816                                           window.getWindow(),
       
   817                                           hints.pData);
       
   818         } finally {
       
   819             XToolkit.awtUnlock();
       
   820         }
       
   821     }
       
   822 
       
   823     /*
       
   824      * If MWM_DECOR_ALL bit is set, then the rest of the bit-mask is taken
       
   825      * to be subtracted from the decorations.  Normalize decoration spec
       
   826      * so that we can map motif decor to something else bit-by-bit in the
       
   827      * rest of the code.
       
   828      */
       
   829     static int normalizeMotifDecor(int decorations) {
       
   830         if ((decorations & MWM_DECOR_ALL) == 0) {
       
   831             return decorations;
       
   832         }
       
   833         int d = MWM_DECOR_BORDER | MWM_DECOR_RESIZEH
       
   834             | MWM_DECOR_TITLE
       
   835             | MWM_DECOR_MENU | MWM_DECOR_MINIMIZE
       
   836             | MWM_DECOR_MAXIMIZE;
       
   837         d &= ~decorations;
       
   838         return d;
       
   839     }
       
   840 
       
   841     /*
       
   842      * If MWM_FUNC_ALL bit is set, then the rest of the bit-mask is taken
       
   843      * to be subtracted from the functions.  Normalize function spec
       
   844      * so that we can map motif func to something else bit-by-bit in the
       
   845      * rest of the code.
       
   846      */
       
   847     static int normalizeMotifFunc(int functions) {
       
   848         if ((functions & MWM_FUNC_ALL) == 0) {
       
   849             return functions;
       
   850         }
       
   851         int f = MWM_FUNC_RESIZE |
       
   852                 MWM_FUNC_MOVE |
       
   853                 MWM_FUNC_MAXIMIZE |
       
   854                 MWM_FUNC_MINIMIZE |
       
   855                 MWM_FUNC_CLOSE;
       
   856         f &= ~functions;
       
   857         return f;
       
   858     }
       
   859 
       
   860     /*
       
   861      * Infer OL properties from MWM decorations.
       
   862      * Use _OL_DECOR_DEL(ATOM[]) to remove unwanted ones.
       
   863      */
       
   864     static void setOLDecor(XWindow window, boolean resizable, int decorations) {
       
   865         if (window == null) {
       
   866             return;
       
   867         }
       
   868 
       
   869         XAtomList decorDel = new XAtomList();
       
   870         decorations = normalizeMotifDecor(decorations);
       
   871         if (insLog.isLoggable(Level.FINER)) insLog.finer("Setting OL_DECOR to " + Integer.toBinaryString(decorations));
       
   872         if ((decorations & MWM_DECOR_TITLE) == 0) {
       
   873             decorDel.add(XA_OL_DECOR_HEADER);
       
   874         }
       
   875         if ((decorations & (MWM_DECOR_RESIZEH | MWM_DECOR_MAXIMIZE)) == 0) {
       
   876             decorDel.add(XA_OL_DECOR_RESIZE);
       
   877         }
       
   878         if ((decorations & (MWM_DECOR_MENU |
       
   879                             MWM_DECOR_MAXIMIZE |
       
   880                             MWM_DECOR_MINIMIZE)) == 0)
       
   881         {
       
   882             decorDel.add(XA_OL_DECOR_CLOSE);
       
   883         }
       
   884         if (decorDel.size() == 0) {
       
   885             insLog.finer("Deleting OL_DECOR");
       
   886             XA_OL_DECOR_DEL.DeleteProperty(window);
       
   887         } else {
       
   888             if (insLog.isLoggable(Level.FINER)) insLog.finer("Setting OL_DECOR to " + decorDel);
       
   889             XA_OL_DECOR_DEL.setAtomListProperty(window, decorDel);
       
   890         }
       
   891     }
       
   892 
       
   893     /*
       
   894      * Set MWM decorations.  Set MWM functions depending on resizability.
       
   895      */
       
   896     static void setMotifDecor(XWindowPeer window, boolean resizable, int decorations, int functions) {
       
   897         /* Apparently some WMs don't implement MWM_*_ALL semantic correctly */
       
   898         if ((decorations & MWM_DECOR_ALL) != 0
       
   899             && (decorations != MWM_DECOR_ALL))
       
   900         {
       
   901             decorations = normalizeMotifDecor(decorations);
       
   902         }
       
   903         if ((functions & MWM_FUNC_ALL) != 0
       
   904             && (functions != MWM_FUNC_ALL))
       
   905         {
       
   906             functions = normalizeMotifFunc(functions);
       
   907         }
       
   908 
       
   909         PropMwmHints hints = window.getMWMHints();
       
   910         hints.set_flags(hints.get_flags() | MWM_HINTS_FUNCTIONS | MWM_HINTS_DECORATIONS);
       
   911         hints.set_functions(functions);
       
   912         hints.set_decorations(decorations);
       
   913 
       
   914         if (stateLog.isLoggable(Level.FINER)) stateLog.finer("Setting MWM_HINTS to " + hints);
       
   915         window.setMWMHints(hints);
       
   916     }
       
   917 
       
   918     /*
       
   919      * Under some window managers if shell is already mapped, we MUST
       
   920      * unmap and later remap in order to effect the changes we make in the
       
   921      * window manager decorations.
       
   922      *
       
   923      * N.B.  This unmapping / remapping of the shell exposes a bug in
       
   924      * X/Motif or the Motif Window Manager.  When you attempt to map a
       
   925      * widget which is positioned (partially) off-screen, the window is
       
   926      * relocated to be entirely on screen. Good idea.  But if both the x
       
   927      * and the y coordinates are less than the origin (0,0), the first
       
   928      * (re)map will move the window to the origin, and any subsequent
       
   929      * (re)map will relocate the window at some other point on the screen.
       
   930      * I have written a short Motif test program to discover this bug.
       
   931      * This should occur infrequently and it does not cause any real
       
   932      * problem.  So for now we'll let it be.
       
   933      */
       
   934     static boolean needRemap(XDecoratedPeer window) {
       
   935         // Don't remap EmbeddedFrame,
       
   936         // e.g. for TrayIcon it causes problems.
       
   937         return !window.isEmbedded();
       
   938     }
       
   939 
       
   940     /*
       
   941      * Set decoration hints on the shell to wdata->decor adjusted
       
   942      * appropriately if not resizable.
       
   943      */
       
   944     static void setShellDecor(XDecoratedPeer window) {
       
   945         int decorations = window.getDecorations();
       
   946         int functions = window.getFunctions();
       
   947         boolean resizable = window.isResizable();
       
   948 
       
   949         if (!resizable) {
       
   950             if ((decorations & MWM_DECOR_ALL) != 0) {
       
   951                 decorations |= MWM_DECOR_RESIZEH | MWM_DECOR_MAXIMIZE;
       
   952             } else {
       
   953                 decorations &= ~(MWM_DECOR_RESIZEH | MWM_DECOR_MAXIMIZE);
       
   954             }
       
   955         }
       
   956         setMotifDecor(window, resizable, decorations, functions);
       
   957         setOLDecor(window, resizable, decorations);
       
   958 
       
   959         /* Some WMs need remap to redecorate the window */
       
   960         if (window.isShowing() && needRemap(window)) {
       
   961             /*
       
   962              * Do the re/mapping at the Xlib level.  Since we essentially
       
   963              * work around a WM bug we don't want this hack to be exposed
       
   964              * to Intrinsics (i.e. don't mess with grabs, callbacks etc).
       
   965              */
       
   966             window.xSetVisible(false);
       
   967             XToolkit.XSync();
       
   968             window.xSetVisible(true);
       
   969         }
       
   970     }
       
   971 
       
   972     /*
       
   973      * Make specified shell resizable.
       
   974      */
       
   975     static void setShellResizable(XDecoratedPeer window) {
       
   976         if (insLog.isLoggable(Level.FINE)) insLog.fine("Setting shell resizable " + window);
       
   977         XToolkit.awtLock();
       
   978         try {
       
   979             Rectangle shellBounds = window.getShellBounds();
       
   980             shellBounds.translate(-window.currentInsets.left, -window.currentInsets.top);
       
   981             window.updateSizeHints(window.getDimensions());
       
   982             requestWMExtents(window.getWindow());
       
   983             XlibWrapper.XMoveResizeWindow(XToolkit.getDisplay(), window.getShell(),
       
   984                                           shellBounds.x, shellBounds.y, shellBounds.width, shellBounds.height);
       
   985             /* REMINDER: will need to revisit when setExtendedStateBounds is added */
       
   986             //Fix for 4320050: Minimum size for java.awt.Frame is not being enforced.
       
   987             //We need to update frame's minimum size, not to reset it
       
   988             removeSizeHints(window, PMaxSize);
       
   989             window.updateMinimumSize();
       
   990 
       
   991             /* Restore decorations */
       
   992             setShellDecor(window);
       
   993         } finally {
       
   994             XToolkit.awtUnlock();
       
   995         }
       
   996     }
       
   997 
       
   998     /*
       
   999      * Make specified shell non-resizable.
       
  1000      * If justChangeSize is false, update decorations as well.
       
  1001      * @param shellBounds bounds of the shell window
       
  1002      */
       
  1003     static void setShellNotResizable(XDecoratedPeer window, WindowDimensions newDimensions, Rectangle shellBounds,
       
  1004                                      boolean justChangeSize)
       
  1005     {
       
  1006         if (insLog.isLoggable(Level.FINE)) insLog.fine("Setting non-resizable shell " + window + ", dimensions " + newDimensions +
       
  1007                                                        ", shellBounds " + shellBounds +", just change size: " + justChangeSize);
       
  1008         XToolkit.awtLock();
       
  1009         try {
       
  1010             /* Fix min/max size hints at the specified values */
       
  1011             if (!shellBounds.isEmpty()) {
       
  1012                 window.updateSizeHints(newDimensions);
       
  1013                 requestWMExtents(window.getWindow());
       
  1014                 XToolkit.XSync();
       
  1015                 XlibWrapper.XMoveResizeWindow(XToolkit.getDisplay(), window.getShell(),
       
  1016                                               shellBounds.x, shellBounds.y, shellBounds.width, shellBounds.height);
       
  1017             }
       
  1018             if (!justChangeSize) {  /* update decorations */
       
  1019                 setShellDecor(window);
       
  1020             }
       
  1021         } finally {
       
  1022             XToolkit.awtUnlock();
       
  1023         }
       
  1024     }
       
  1025 
       
  1026 /*****************************************************************************\
       
  1027  * Protocols support
       
  1028  */
       
  1029     HashMap<Class<?>, Collection<XProtocol>> protocolsMap = new HashMap<Class<?>, Collection<XProtocol>>();
       
  1030     /**
       
  1031      * Returns all protocols supporting given protocol interface
       
  1032      */
       
  1033     Collection<XProtocol> getProtocols(Class protocolInterface) {
       
  1034         Collection<XProtocol> res = protocolsMap.get(protocolInterface);
       
  1035         if (res != null) {
       
  1036             return (Collection<XProtocol>)res;
       
  1037         } else {
       
  1038             return new LinkedList<XProtocol>();
       
  1039         }
       
  1040     }
       
  1041 
       
  1042     void addProtocol(Class protocolInterface, XProtocol protocol) {
       
  1043         Collection<XProtocol> protocols = getProtocols(protocolInterface);
       
  1044         protocols.add(protocol);
       
  1045         protocolsMap.put(protocolInterface, protocols);
       
  1046     }
       
  1047 
       
  1048     boolean supportsDynamicLayout() {
       
  1049         int wm = getWMID();
       
  1050         switch (wm) {
       
  1051           case XWM.ENLIGHTEN_WM:
       
  1052           case XWM.KDE2_WM:
       
  1053           case XWM.SAWFISH_WM:
       
  1054           case XWM.ICE_WM:
       
  1055           case XWM.METACITY_WM:
       
  1056               return true;
       
  1057           case XWM.OPENLOOK_WM:
       
  1058           case XWM.MOTIF_WM:
       
  1059           case XWM.CDE_WM:
       
  1060               return false;
       
  1061           default:
       
  1062               return false;
       
  1063         }
       
  1064     }
       
  1065 
       
  1066 
       
  1067     /**
       
  1068      * Check if state is supported.
       
  1069      * Note that a compound state is always reported as not supported.
       
  1070      * Note also that MAXIMIZED_BOTH is considered not a compound state.
       
  1071      * Therefore, a compound state is just ICONIFIED | anything else.
       
  1072      *
       
  1073      */
       
  1074     boolean supportsExtendedState(int state) {
       
  1075         switch (state) {
       
  1076           case Frame.MAXIMIZED_VERT:
       
  1077           case Frame.MAXIMIZED_HORIZ:
       
  1078               /*
       
  1079                * WMs that talk NET/WIN protocol, but do not support
       
  1080                * unidirectional maximization.
       
  1081                */
       
  1082               if (getWMID() == METACITY_WM) {
       
  1083                   /* "This is a deliberate policy decision." -hp */
       
  1084                   return false;
       
  1085               }
       
  1086               /* FALLTROUGH */
       
  1087           case Frame.MAXIMIZED_BOTH:
       
  1088               Iterator iter = getProtocols(XStateProtocol.class).iterator();
       
  1089               while (iter.hasNext()) {
       
  1090                   XStateProtocol proto = (XStateProtocol)iter.next();
       
  1091                   if (proto.supportsState(state)) {
       
  1092                       return true;
       
  1093                   }
       
  1094               }
       
  1095           default:
       
  1096               return false;
       
  1097         }
       
  1098     }
       
  1099 
       
  1100 /*****************************************************************************\
       
  1101  *
       
  1102  * Reading state from different protocols
       
  1103  *
       
  1104 \*****************************************************************************/
       
  1105 
       
  1106 
       
  1107     int getExtendedState(XWindowPeer window) {
       
  1108         Iterator iter = getProtocols(XStateProtocol.class).iterator();
       
  1109         int state = 0;
       
  1110         while (iter.hasNext()) {
       
  1111             XStateProtocol proto = (XStateProtocol)iter.next();
       
  1112             state |= proto.getState(window);
       
  1113         }
       
  1114         if (state != 0) {
       
  1115             return state;
       
  1116         } else {
       
  1117             return Frame.NORMAL;
       
  1118         }
       
  1119     }
       
  1120 
       
  1121 /*****************************************************************************\
       
  1122  *
       
  1123  * Notice window state change when WM changes a property on the window ...
       
  1124  *
       
  1125 \*****************************************************************************/
       
  1126 
       
  1127 
       
  1128     /*
       
  1129      * Check if property change is a window state protocol message.
       
  1130      * If it is - return the new state as Integer, otherwise return null
       
  1131      */
       
  1132     Integer isStateChange(XDecoratedPeer window, XPropertyEvent e) {
       
  1133         if (!window.isShowing()) {
       
  1134             stateLog.finer("Window is not showing");
       
  1135             return null;
       
  1136         }
       
  1137 
       
  1138         int wm_state = window.getWMState();
       
  1139         if (wm_state == XlibWrapper.WithdrawnState) {
       
  1140             stateLog.finer("WithdrawnState");
       
  1141             return null;
       
  1142         } else {
       
  1143             stateLog.finer("Window WM_STATE is " + wm_state);
       
  1144         }
       
  1145         boolean is_state_change = false;
       
  1146         if (e.get_atom() == XA_WM_STATE.getAtom()) {
       
  1147             is_state_change = true;
       
  1148         }
       
  1149 
       
  1150         Iterator iter = getProtocols(XStateProtocol.class).iterator();
       
  1151         while (iter.hasNext()) {
       
  1152             XStateProtocol proto = (XStateProtocol)iter.next();
       
  1153             is_state_change |= proto.isStateChange(e);
       
  1154         }
       
  1155         int res = 0;
       
  1156 
       
  1157         if (is_state_change) {
       
  1158             if (wm_state == XlibWrapper.IconicState) {
       
  1159                 res = Frame.ICONIFIED;
       
  1160             } else {
       
  1161                 res = Frame.NORMAL;
       
  1162             }
       
  1163             res |= getExtendedState(window);
       
  1164         }
       
  1165         if (is_state_change) {
       
  1166             return Integer.valueOf(res);
       
  1167         } else {
       
  1168             return null;
       
  1169         }
       
  1170     }
       
  1171 
       
  1172 /*****************************************************************************\
       
  1173  *
       
  1174  * Setting/changing window state ...
       
  1175  *
       
  1176 \*****************************************************************************/
       
  1177 
       
  1178     /**
       
  1179      * Moves window to the specified layer, layer is one of the constants defined
       
  1180      * in XLayerProtocol
       
  1181      */
       
  1182     void setLayer(XWindowPeer window, int layer) {
       
  1183         Iterator iter = getProtocols(XLayerProtocol.class).iterator();
       
  1184         while (iter.hasNext()) {
       
  1185             XLayerProtocol proto = (XLayerProtocol)iter.next();
       
  1186             if (proto.supportsLayer(layer)) {
       
  1187                 proto.setLayer(window, layer);
       
  1188             }
       
  1189         }
       
  1190         XToolkit.XSync();
       
  1191     }
       
  1192 
       
  1193     void setExtendedState(XWindowPeer window, int state) {
       
  1194         Iterator iter = getProtocols(XStateProtocol.class).iterator();
       
  1195         while (iter.hasNext()) {
       
  1196             XStateProtocol proto = (XStateProtocol)iter.next();
       
  1197             if (proto.supportsState(state)) {
       
  1198                 proto.setState(window, state);
       
  1199                 break;
       
  1200             }
       
  1201         }
       
  1202 
       
  1203         if (!window.isShowing()) {
       
  1204             /*
       
  1205              * Purge KWM bits.
       
  1206              * Not really tested with KWM, only with WindowMaker.
       
  1207              */
       
  1208             XToolkit.awtLock();
       
  1209             try {
       
  1210                 XlibWrapper.XDeleteProperty(XToolkit.getDisplay(),
       
  1211                                             window.getWindow(),
       
  1212                                             XA_KWM_WIN_ICONIFIED.getAtom());
       
  1213                 XlibWrapper.XDeleteProperty(XToolkit.getDisplay(),
       
  1214                                             window.getWindow(),
       
  1215                                             XA_KWM_WIN_MAXIMIZED.getAtom());
       
  1216             }
       
  1217             finally {
       
  1218                 XToolkit.awtUnlock();
       
  1219             }
       
  1220         }
       
  1221         XToolkit.XSync();
       
  1222     }
       
  1223 
       
  1224 
       
  1225     /*
       
  1226      * Work around for 4775545.
       
  1227      *
       
  1228      * If WM exits while the top-level is shaded, the shaded hint remains
       
  1229      * on the top-level properties.  When WM restarts and sees the shaded
       
  1230      * window it can reparent it into a "pre-shaded" decoration frame
       
  1231      * (Metacity does), and our insets logic will go crazy, b/c it will
       
  1232      * see a huge nagative bottom inset.  There's no clean solution for
       
  1233      * this, so let's just be weasels and drop the shaded hint if we
       
  1234      * detect that WM exited.  NB: we are in for a race condition with WM
       
  1235      * restart here.  NB2: e.g. WindowMaker saves the state in a private
       
  1236      * property that this code knows nothing about, so this workaround is
       
  1237      * not effective; other WMs might play similar tricks.
       
  1238      */
       
  1239     void unshadeKludge(XDecoratedPeer window) {
       
  1240         assert(window.isShowing());
       
  1241 
       
  1242         Iterator iter = getProtocols(XStateProtocol.class).iterator();
       
  1243         while (iter.hasNext()) {
       
  1244             XStateProtocol proto = (XStateProtocol)iter.next();
       
  1245             proto.unshadeKludge(window);
       
  1246         }
       
  1247         XToolkit.XSync();
       
  1248     }
       
  1249 
       
  1250     static boolean inited = false;
       
  1251     static void init() {
       
  1252         if (inited) {
       
  1253             return;
       
  1254         }
       
  1255 
       
  1256         initAtoms();
       
  1257         getWM();
       
  1258         inited = true;
       
  1259     }
       
  1260 
       
  1261     void initializeProtocols() {
       
  1262         XNETProtocol net_protocol = g_net_protocol;
       
  1263         if (net_protocol != null) {
       
  1264             if (!net_protocol.active()) {
       
  1265                 net_protocol = null;
       
  1266             } else {
       
  1267                 if (net_protocol.doStateProtocol()) {
       
  1268                     addProtocol(XStateProtocol.class, net_protocol);
       
  1269                 }
       
  1270                 if (net_protocol.doLayerProtocol()) {
       
  1271                     addProtocol(XLayerProtocol.class, net_protocol);
       
  1272                 }
       
  1273             }
       
  1274         }
       
  1275 
       
  1276         XWINProtocol win = g_win_protocol;
       
  1277         if (win != null) {
       
  1278             if (win.active()) {
       
  1279                 if (win.doStateProtocol()) {
       
  1280                     addProtocol(XStateProtocol.class, win);
       
  1281                 }
       
  1282                 if (win.doLayerProtocol()) {
       
  1283                     addProtocol(XLayerProtocol.class, win);
       
  1284                 }
       
  1285             }
       
  1286         }
       
  1287     }
       
  1288 
       
  1289     HashMap storedInsets = new HashMap();
       
  1290     Insets guessInsets(XDecoratedPeer window) {
       
  1291         Insets res = (Insets)storedInsets.get(window.getClass());
       
  1292         if (res == null) {
       
  1293             switch (WMID) {
       
  1294               case ENLIGHTEN_WM:
       
  1295                   res = new Insets(19, 4, 4, 4);
       
  1296                   break;
       
  1297               case CDE_WM:
       
  1298                   res = new Insets(28, 6, 6, 6);
       
  1299                   break;
       
  1300               case NO_WM:
       
  1301               case LG3D_WM:
       
  1302                   res = zeroInsets;
       
  1303                   break;
       
  1304               case MOTIF_WM:
       
  1305               case OPENLOOK_WM:
       
  1306               default:
       
  1307                   res = defaultInsets;
       
  1308             }
       
  1309         }
       
  1310         if (insLog.isLoggable(Level.FINEST)) insLog.finest("WM guessed insets: " + res);
       
  1311         return res;
       
  1312     }
       
  1313     /*
       
  1314      * Some buggy WMs ignore window gravity when processing
       
  1315      * ConfigureRequest and position window as if the gravity is Static.
       
  1316      * We work around this in MWindowPeer.pReshape().
       
  1317      *
       
  1318      * Starting with 1.5 we have introduced an Environment variable
       
  1319      * _JAVA_AWT_WM_STATIC_GRAVITY that can be set to indicate to Java
       
  1320      * explicitly that the WM has this behaviour, example is FVWM.
       
  1321      */
       
  1322 
       
  1323     static int awtWMStaticGravity = -1;
       
  1324     static boolean configureGravityBuggy() {
       
  1325 
       
  1326         if (awtWMStaticGravity == -1) {
       
  1327             awtWMStaticGravity = (XToolkit.getEnv("_JAVA_AWT_WM_STATIC_GRAVITY") != null) ? 1 : 0;
       
  1328         }
       
  1329 
       
  1330         if (awtWMStaticGravity == 1) {
       
  1331             return true;
       
  1332         }
       
  1333 
       
  1334         switch(getWMID()) {
       
  1335           case XWM.ICE_WM:
       
  1336               /*
       
  1337                * See bug #228981 at IceWM's SourceForge pages.
       
  1338                * Latest stable version 1.0.8-6 still has this problem.
       
  1339                */
       
  1340               /**
       
  1341                * Version 1.2.2 doesn't have this problem
       
  1342                */
       
  1343               // Detect IceWM version
       
  1344               if (g_net_protocol != null) {
       
  1345                   String wm_name = g_net_protocol.getWMName();
       
  1346                   Pattern pat = Pattern.compile("^IceWM (\\d+)\\.(\\d+)\\.(\\d+).*$");
       
  1347                   try {
       
  1348                       Matcher match = pat.matcher(wm_name);
       
  1349                       if (match.matches()) {
       
  1350                           int v1 = Integer.parseInt(match.group(1));
       
  1351                           int v2 = Integer.parseInt(match.group(2));
       
  1352                           int v3 = Integer.parseInt(match.group(3));
       
  1353                           return !(v1 > 1 || (v1 == 1 && (v2 > 2 || (v2 == 2 && v3 >=2))));
       
  1354                       }
       
  1355                   } catch (Exception e) {
       
  1356                       return true;
       
  1357                   }
       
  1358               }
       
  1359               return true;
       
  1360           case XWM.ENLIGHTEN_WM:
       
  1361               /* At least E16 is buggy. */
       
  1362               return true;
       
  1363           default:
       
  1364               return false;
       
  1365         }
       
  1366     }
       
  1367 
       
  1368     /*
       
  1369      * @return if WM implements the insets property - returns insets with values
       
  1370      * specified in that property, null otherwise.
       
  1371      */
       
  1372     public static Insets getInsetsFromExtents(long window) {
       
  1373         if (window == XConstants.None) {
       
  1374             return null;
       
  1375         }
       
  1376         XNETProtocol net_protocol = getWM().getNETProtocol();
       
  1377         if (net_protocol != null && net_protocol.active()) {
       
  1378             Insets insets = getInsetsFromProp(window, XA_NET_FRAME_EXTENTS);
       
  1379             insLog.log(Level.FINE, "_NET_FRAME_EXTENTS: {0}", insets);
       
  1380 
       
  1381             if (insets != null) {
       
  1382                 return insets;
       
  1383             }
       
  1384         }
       
  1385         switch(getWMID()) {
       
  1386           case XWM.KDE2_WM:
       
  1387               return getInsetsFromProp(window, XA_KDE_NET_WM_FRAME_STRUT);
       
  1388           case XWM.ENLIGHTEN_WM:
       
  1389               return getInsetsFromProp(window, XA_E_FRAME_SIZE);
       
  1390           default:
       
  1391               return null;
       
  1392         }
       
  1393     }
       
  1394 
       
  1395     /**
       
  1396      * Helper function reads property of type CARDINAL[4] = { left, right, top, bottom }
       
  1397      * and converts it to Insets object.
       
  1398      */
       
  1399     public static Insets getInsetsFromProp(long window, XAtom atom) {
       
  1400         if (window == XConstants.None) {
       
  1401             return null;
       
  1402         }
       
  1403 
       
  1404         WindowPropertyGetter getter =
       
  1405             new WindowPropertyGetter(window, atom,
       
  1406                                      0, 4, false, XAtom.XA_CARDINAL);
       
  1407         try {
       
  1408             if (getter.execute() != XlibWrapper.Success
       
  1409                 || getter.getData() == 0
       
  1410                 || getter.getActualType() != XAtom.XA_CARDINAL
       
  1411                 || getter.getActualFormat() != 32)
       
  1412             {
       
  1413                 return null;
       
  1414             } else {
       
  1415                 return new Insets((int)Native.getCard32(getter.getData(), 2), // top
       
  1416                                   (int)Native.getCard32(getter.getData(), 0), // left
       
  1417                                   (int)Native.getCard32(getter.getData(), 3), // bottom
       
  1418                                   (int)Native.getCard32(getter.getData(), 1)); // right
       
  1419             }
       
  1420         } finally {
       
  1421             getter.dispose();
       
  1422         }
       
  1423     }
       
  1424 
       
  1425     /**
       
  1426      * Asks WM to fill Frame Extents (insets) for the window.
       
  1427      */
       
  1428     public static void requestWMExtents(long window) {
       
  1429         if (window == XConstants.None) { // not initialized
       
  1430             return;
       
  1431         }
       
  1432 
       
  1433         log.fine("Requesting FRAME_EXTENTS");
       
  1434 
       
  1435         XClientMessageEvent msg = new XClientMessageEvent();
       
  1436         msg.zero();
       
  1437         msg.set_type(XlibWrapper.ClientMessage);
       
  1438         msg.set_display(XToolkit.getDisplay());
       
  1439         msg.set_window(window);
       
  1440         msg.set_format(32);
       
  1441         XToolkit.awtLock();
       
  1442         try {
       
  1443             XNETProtocol net_protocol = getWM().getNETProtocol();
       
  1444             if (net_protocol != null && net_protocol.active()) {
       
  1445                 msg.set_message_type(XA_NET_REQUEST_FRAME_EXTENTS.getAtom());
       
  1446                 XlibWrapper.XSendEvent(XToolkit.getDisplay(), XToolkit.getDefaultRootWindow(),
       
  1447                                        false, XlibWrapper.SubstructureRedirectMask | XlibWrapper.SubstructureNotifyMask,
       
  1448                                        msg.getPData());
       
  1449             }
       
  1450             if (getWMID() == XWM.KDE2_WM) {
       
  1451                 msg.set_message_type(XA_KDE_NET_WM_FRAME_STRUT.getAtom());
       
  1452                 XlibWrapper.XSendEvent(XToolkit.getDisplay(), XToolkit.getDefaultRootWindow(),
       
  1453                                        false, XlibWrapper.SubstructureRedirectMask | XlibWrapper.SubstructureNotifyMask,
       
  1454                                        msg.getPData());
       
  1455             }
       
  1456             // XXX: should we wait for response? XIfEvent() would be useful here :)
       
  1457         } finally {
       
  1458             XToolkit.awtUnlock();
       
  1459             msg.dispose();
       
  1460         }
       
  1461     }
       
  1462 
       
  1463     /* syncTopLEvelPos() is necessary to insure that the window manager has in
       
  1464      * fact moved us to our final position relative to the reParented WM window.
       
  1465      * We have noted a timing window which our shell has not been moved so we
       
  1466      * screw up the insets thinking they are 0,0.  Wait (for a limited period of
       
  1467      * time to let the WM hava a chance to move us.
       
  1468      * @param window window ID of the shell, assuming it is the window
       
  1469      * which will NOT have zero coordinates after the complete
       
  1470      * reparenting
       
  1471      */
       
  1472     boolean syncTopLevelPos(long window, XWindowAttributes attrs) {
       
  1473         int tries = 0;
       
  1474         XToolkit.awtLock();
       
  1475         try {
       
  1476             do {
       
  1477                 XlibWrapper.XGetWindowAttributes(XToolkit.getDisplay(), window, attrs.pData);
       
  1478                 if (attrs.get_x() != 0 || attrs.get_y() != 0) {
       
  1479                     return true;
       
  1480                 }
       
  1481                 tries++;
       
  1482                 XToolkit.XSync();
       
  1483             } while (tries < 50);
       
  1484         }
       
  1485         finally {
       
  1486             XToolkit.awtUnlock();
       
  1487         }
       
  1488         return false;
       
  1489     }
       
  1490 
       
  1491     Insets getInsets(XDecoratedPeer win, long window, long parent) {
       
  1492         /*
       
  1493          * Unfortunately the concept of "insets" borrowed to AWT
       
  1494          * from Win32 is *absolutely*, *unbelievably* foreign to
       
  1495          * X11.  Few WMs provide the size of frame decor
       
  1496          * (i.e. insets) in a property they set on the client
       
  1497          * window, so we check if we can get away with just
       
  1498          * peeking at it.  [Future versions of wm-spec might add a
       
  1499          * standardized hint for this].
       
  1500          *
       
  1501          * Otherwise we do some special casing.  Actually the
       
  1502          * fallback code ("default" case) seems to cover most of
       
  1503          * the existing WMs (modulo Reparent/Configure order
       
  1504          * perhaps?).
       
  1505          *
       
  1506          * Fallback code tries to account for the two most common cases:
       
  1507          *
       
  1508          * . single reparenting
       
  1509          *       parent window is the WM frame
       
  1510          *       [twm, olwm, sawfish]
       
  1511          *
       
  1512          * . double reparenting
       
  1513          *       parent is a lining exactly the size of the client
       
  1514          *       grandpa is the WM frame
       
  1515          *       [mwm, e!, kwin, fvwm2 ... ]
       
  1516          */
       
  1517         Insets correctWM = XWM.getInsetsFromExtents(window);
       
  1518         insLog.log(Level.FINER, "Got insets from property: {0}", correctWM);
       
  1519 
       
  1520         if (correctWM == null) {
       
  1521             correctWM = new Insets(0,0,0,0);
       
  1522 
       
  1523             correctWM.top = -1;
       
  1524             correctWM.left = -1;
       
  1525 
       
  1526             XWindowAttributes lwinAttr = new XWindowAttributes();
       
  1527             XWindowAttributes pattr = new XWindowAttributes();
       
  1528             try {
       
  1529                 switch (XWM.getWMID()) {
       
  1530                   /* should've been done in awt_wm_getInsetsFromProp */
       
  1531                   case XWM.ENLIGHTEN_WM: {
       
  1532                       /* enlightenment does double reparenting */
       
  1533                       syncTopLevelPos(parent, lwinAttr);
       
  1534                       correctWM.left = lwinAttr.get_x();
       
  1535                       correctWM.top = lwinAttr.get_y();
       
  1536                       /*
       
  1537                        * Now get the actual dimensions of the parent window
       
  1538                        * resolve the difference.  We can't rely on the left
       
  1539                        * to be equal to right or bottom...  Enlightment
       
  1540                        * breaks that assumption.
       
  1541                        */
       
  1542                       XlibWrapper.XGetWindowAttributes(XToolkit.getDisplay(),
       
  1543                                                        XlibUtil.getParentWindow(parent),
       
  1544                                                        pattr.pData);
       
  1545                       correctWM.right = pattr.get_width() -
       
  1546                           (lwinAttr.get_width() + correctWM.left);
       
  1547                       correctWM.bottom = pattr.get_height() -
       
  1548                           (lwinAttr.get_height() + correctWM.top);
       
  1549 
       
  1550                       break;
       
  1551                   }
       
  1552                   case XWM.ICE_WM: // for 1.2.2.
       
  1553                   case XWM.KDE2_WM: /* should've been done in getInsetsFromProp */
       
  1554                   case XWM.CDE_WM:
       
  1555                   case XWM.MOTIF_WM: {
       
  1556                       /* these are double reparenting too */
       
  1557                       if (syncTopLevelPos(parent, lwinAttr)) {
       
  1558                           correctWM.top = lwinAttr.get_y();
       
  1559                           correctWM.left = lwinAttr.get_x();
       
  1560                           correctWM.right = correctWM.left;
       
  1561                           correctWM.bottom = correctWM.left;
       
  1562                       } else {
       
  1563                           return null;
       
  1564                       }
       
  1565                       break;
       
  1566                   }
       
  1567                   case XWM.SAWFISH_WM:
       
  1568                   case XWM.OPENLOOK_WM: {
       
  1569                       /* single reparenting */
       
  1570                       syncTopLevelPos(window, lwinAttr);
       
  1571                       correctWM.top    = lwinAttr.get_y();
       
  1572                       correctWM.left   = lwinAttr.get_x();
       
  1573                       correctWM.right  = correctWM.left;
       
  1574                       correctWM.bottom = correctWM.left;
       
  1575                       break;
       
  1576                   }
       
  1577                   case XWM.OTHER_WM:
       
  1578                   default: {                /* this is very similar to the E! case above */
       
  1579                       insLog.log(Level.FINEST, "Getting correct insets for OTHER_WM/default, parent: {0}", parent);
       
  1580                       syncTopLevelPos(parent, lwinAttr);
       
  1581                       int status = XlibWrapper.XGetWindowAttributes(XToolkit.getDisplay(),
       
  1582                                                                     window, lwinAttr.pData);
       
  1583                       status = XlibWrapper.XGetWindowAttributes(XToolkit.getDisplay(),
       
  1584                                                                 parent, pattr.pData);
       
  1585                       if (lwinAttr.get_root() == parent) {
       
  1586                           insLog.finest("our parent is root so insets should be zero");
       
  1587                           correctWM = new Insets(0, 0, 0, 0);
       
  1588                           break;
       
  1589                       }
       
  1590 
       
  1591                       /*
       
  1592                        * Check for double-reparenting WM.
       
  1593                        *
       
  1594                        * If the parent is exactly the same size as the
       
  1595                        * top-level assume taht it's the "lining" window and
       
  1596                        * that the grandparent is the actual frame (NB: we
       
  1597                        * have already handled undecorated windows).
       
  1598                        *
       
  1599                        * XXX: what about timing issues that syncTopLevelPos
       
  1600                        * is supposed to work around?
       
  1601                        */
       
  1602                       if (lwinAttr.get_x() == 0 && lwinAttr.get_y() == 0
       
  1603                           && lwinAttr.get_width()+2*lwinAttr.get_border_width() == pattr.get_width()
       
  1604                           && lwinAttr.get_height()+2*lwinAttr.get_border_width() == pattr.get_height())
       
  1605                       {
       
  1606                           insLog.log(Level.FINEST, "Double reparenting detected, pattr({2})={0}, lwinAttr({3})={1}",
       
  1607                                      new Object[] {lwinAttr, pattr, parent, window});
       
  1608                           lwinAttr.set_x(pattr.get_x());
       
  1609                           lwinAttr.set_y(pattr.get_y());
       
  1610                           lwinAttr.set_border_width(lwinAttr.get_border_width()+pattr.get_border_width());
       
  1611 
       
  1612                           final long grand_parent = XlibUtil.getParentWindow(parent);
       
  1613 
       
  1614                           if (grand_parent == lwinAttr.get_root()) {
       
  1615                               // This is not double-reparenting in a
       
  1616                               // general sense - we simply don't have
       
  1617                               // correct insets - return null to try to
       
  1618                               // get insets later
       
  1619                               return null;
       
  1620                           } else {
       
  1621                               parent = grand_parent;
       
  1622                               XlibWrapper.XGetWindowAttributes(XToolkit.getDisplay(),
       
  1623                                                                parent,
       
  1624                                                                pattr.pData);
       
  1625                           }
       
  1626                       }
       
  1627                       /*
       
  1628                        * XXX: To be absolutely correct, we'd need to take
       
  1629                        * parent's border-width into account too, but the
       
  1630                        * rest of the code is happily unaware about border
       
  1631                        * widths and inner/outer distinction, so for the time
       
  1632                        * being, just ignore it.
       
  1633                        */
       
  1634                       insLog.log(Level.FINEST, "Attrs before calculation: pattr({2})={0}, lwinAttr({3})={1}",
       
  1635                                  new Object[] {lwinAttr, pattr, parent, window});
       
  1636                       correctWM = new Insets(lwinAttr.get_y() + lwinAttr.get_border_width(),
       
  1637                                              lwinAttr.get_x() + lwinAttr.get_border_width(),
       
  1638                                              pattr.get_height() - (lwinAttr.get_y() + lwinAttr.get_height() + 2*lwinAttr.get_border_width()),
       
  1639                                              pattr.get_width() -  (lwinAttr.get_x() + lwinAttr.get_width() + 2*lwinAttr.get_border_width()));
       
  1640                       break;
       
  1641                   } /* default */
       
  1642                 } /* switch (runningWM) */
       
  1643             } finally {
       
  1644                 lwinAttr.dispose();
       
  1645                 pattr.dispose();
       
  1646             }
       
  1647         }
       
  1648         if (storedInsets.get(win.getClass()) == null) {
       
  1649             storedInsets.put(win.getClass(), correctWM);
       
  1650         }
       
  1651         return correctWM;
       
  1652     }
       
  1653     boolean isDesktopWindow( long w ) {
       
  1654         if (g_net_protocol != null) {
       
  1655             XAtomList wtype = XAtom.get("_NET_WM_WINDOW_TYPE").getAtomListPropertyList( w );
       
  1656             return wtype.contains( XAtom.get("_NET_WM_WINDOW_TYPE_DESKTOP") );
       
  1657         } else {
       
  1658             return false;
       
  1659         }
       
  1660     }
       
  1661 
       
  1662     public XNETProtocol getNETProtocol() {
       
  1663         return g_net_protocol;
       
  1664     }
       
  1665 
       
  1666     /**
       
  1667      * Sets _NET_WN_ICON property on the window using the arrays of
       
  1668      * raster-data for icons. If icons is null, removes _NET_WM_ICON
       
  1669      * property.
       
  1670      * This method invokes XNETProtocol.setWMIcon() for WMs that
       
  1671      * support NET protocol.
       
  1672      *
       
  1673      * @return true if hint was modified successfully, false otherwise
       
  1674      */
       
  1675     public boolean setNetWMIcon(XWindowPeer window, java.util.List<XIconInfo> icons) {
       
  1676         if (g_net_protocol != null && g_net_protocol.active()) {
       
  1677             g_net_protocol.setWMIcons(window, icons);
       
  1678             return getWMID() != ICE_WM;
       
  1679         }
       
  1680         return false;
       
  1681     }
       
  1682 }