1 /*
   2  * Copyright (c) 2003, 2008, 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 
  27 package sun.awt.X11;
  28 
  29 import java.awt.*;
  30 import sun.util.logging.PlatformLogger;
  31 
  32 class XWINProtocol extends XProtocol implements XStateProtocol, XLayerProtocol {
  33     final static PlatformLogger log = PlatformLogger.getLogger("sun.awt.X11.XWINProtocol");
  34 
  35 /* Gnome WM spec  */
  36     XAtom XA_WIN_SUPPORTING_WM_CHECK = XAtom.get("_WIN_SUPPORTING_WM_CHECK");
  37     XAtom XA_WIN_PROTOCOLS = XAtom.get("_WIN_PROTOCOLS");
  38     XAtom XA_WIN_STATE = XAtom.get("_WIN_STATE");
  39 
  40     public boolean supportsState(int state) {
  41         return doStateProtocol();   // TODO - check for Frame constants
  42     }
  43 
  44     public void setState(XWindowPeer window, int state) {
  45         if (window.isShowing()) {
  46             /*
  47              * Request state transition from a Gnome WM (_WIN protocol) by sending
  48              * _WIN_STATE ClientMessage to root window.
  49              */
  50             long win_state = 0;
  51 
  52             if ( (state & Frame.MAXIMIZED_VERT) != 0) {
  53                 win_state |= WIN_STATE_MAXIMIZED_VERT;
  54             }
  55             if ( (state & Frame.MAXIMIZED_HORIZ) != 0) {
  56                 win_state |= WIN_STATE_MAXIMIZED_HORIZ;
  57             }
  58 
  59             XClientMessageEvent req = new XClientMessageEvent();
  60             req.set_type(XConstants.ClientMessage);
  61             req.set_window(window.getWindow());
  62             req.set_message_type(XA_WIN_STATE.getAtom());
  63             req.set_format(32);
  64             req.set_data(0, (WIN_STATE_MAXIMIZED_HORIZ | WIN_STATE_MAXIMIZED_VERT));
  65             req.set_data(1, win_state);
  66             if (log.isLoggable(PlatformLogger.FINE)) log.fine("Sending WIN_STATE to root to change the state to " + win_state);
  67             try {
  68                 XToolkit.awtLock();
  69                 XlibWrapper.XSendEvent(XToolkit.getDisplay(),
  70                         XlibWrapper.RootWindow(XToolkit.getDisplay(),
  71                             window.getScreenNumber()),
  72                         false,
  73                         XConstants.SubstructureRedirectMask | XConstants.SubstructureNotifyMask,
  74                         req.pData);
  75             }
  76             finally {
  77                 XToolkit.awtUnlock();
  78             }
  79             req.dispose();
  80         } else {
  81             /*
  82              * Specify initial state for a Gnome WM (_WIN protocol) by setting
  83              * WIN_STATE property on the window to the desired state before
  84              * mapping it.
  85              */
  86             /* Be careful to not wipe out state bits we don't understand */
  87             long win_state = XA_WIN_STATE.getCard32Property(window);
  88             long old_win_state = win_state;
  89 
  90             /*
  91              * In their stupid quest of reinventing every wheel, Gnome WM spec
  92              * have its own "minimized" hint (instead of using initial state
  93              * and WM_STATE hints).  This is bogus, but, apparently, some WMs
  94              * pay attention.
  95              */
  96             if ((state & Frame.ICONIFIED) != 0) {
  97                 win_state |= WIN_STATE_MINIMIZED;
  98             } else {
  99                 win_state &= ~WIN_STATE_MINIMIZED;
 100             }
 101 
 102             if ((state & Frame.MAXIMIZED_VERT) != 0) {
 103                 win_state |= WIN_STATE_MAXIMIZED_VERT;
 104             } else {
 105                 win_state &= ~WIN_STATE_MAXIMIZED_VERT;
 106             }
 107 
 108             if ((state & Frame.MAXIMIZED_HORIZ) != 0) {
 109                 win_state |= WIN_STATE_MAXIMIZED_HORIZ;
 110             } else {
 111                 win_state &= ~WIN_STATE_MAXIMIZED_HORIZ;
 112             }
 113             if ((old_win_state ^ win_state) != 0) {
 114                 if (log.isLoggable(PlatformLogger.FINE)) log.fine("Setting WIN_STATE on " + window + " to change the state to " + win_state);
 115                 XA_WIN_STATE.setCard32Property(window, win_state);
 116             }
 117         }
 118     }
 119 
 120     public int getState(XWindowPeer window) {
 121         long win_state = XA_WIN_STATE.getCard32Property(window);
 122         int java_state = Frame.NORMAL;
 123         if ((win_state & WIN_STATE_MAXIMIZED_VERT) != 0) {
 124             java_state |= Frame.MAXIMIZED_VERT;
 125         }
 126         if ((win_state & WIN_STATE_MAXIMIZED_HORIZ) != 0) {
 127             java_state |= Frame.MAXIMIZED_HORIZ;
 128         }
 129         return java_state;
 130     }
 131 
 132     public boolean isStateChange(XPropertyEvent e) {
 133         return doStateProtocol() && e.get_atom() == XA_WIN_STATE.getAtom();
 134     }
 135 
 136     public void unshadeKludge(XWindowPeer window) {
 137         long win_state = XA_WIN_STATE.getCard32Property(window);
 138         if ((win_state & WIN_STATE_SHADED) == 0) {
 139             return;
 140         }
 141         win_state &= ~WIN_STATE_SHADED;
 142         XA_WIN_STATE.setCard32Property(window, win_state);
 143     }
 144 
 145     public boolean supportsLayer(int layer) {
 146         return ((layer == LAYER_ALWAYS_ON_TOP) || (layer == LAYER_NORMAL)) && doLayerProtocol();
 147     }
 148 
 149     public void setLayer(XWindowPeer window, int layer) {
 150         if (window.isShowing()) {
 151             XClientMessageEvent req = new XClientMessageEvent();
 152             req.set_type(XConstants.ClientMessage);
 153             req.set_window(window.getWindow());
 154             req.set_message_type(XA_WIN_LAYER.getAtom());
 155             req.set_format(32);
 156             req.set_data(0, layer == LAYER_NORMAL ? WIN_LAYER_NORMAL : WIN_LAYER_ONTOP);
 157             req.set_data(1, 0);
 158             req.set_data(2, 0);
 159             if (log.isLoggable(PlatformLogger.FINE)) log.fine("Setting layer " + layer + " by root message : " + req);
 160             XToolkit.awtLock();
 161             try {
 162                 XlibWrapper.XSendEvent(XToolkit.getDisplay(),
 163                         XlibWrapper.RootWindow(XToolkit.getDisplay(),
 164                             window.getScreenNumber()),
 165                         false,
 166                         /*XConstants.SubstructureRedirectMask | */XConstants.SubstructureNotifyMask,
 167                         req.pData);
 168             }
 169             finally {
 170                 XToolkit.awtUnlock();
 171             }
 172             req.dispose();
 173         } else {
 174             if (log.isLoggable(PlatformLogger.FINE)) log.fine("Setting layer property to " + layer);
 175             XA_WIN_LAYER.setCard32Property(window, layer == LAYER_NORMAL ? WIN_LAYER_NORMAL : WIN_LAYER_ONTOP);
 176         }
 177     }
 178 
 179     XAtom XA_WIN_LAYER = XAtom.get("_WIN_LAYER");
 180 
 181 /* _WIN_STATE bits */
 182     final static int WIN_STATE_STICKY          =(1<<0); /* everyone knows sticky            */
 183     final static int WIN_STATE_MINIMIZED       =(1<<1); /* Reserved - definition is unclear */
 184     final static int WIN_STATE_MAXIMIZED_VERT  =(1<<2); /* window in maximized V state      */
 185     final static int WIN_STATE_MAXIMIZED_HORIZ =(1<<3); /* window in maximized H state      */
 186     final static int WIN_STATE_HIDDEN          =(1<<4); /* not on taskbar but window visible*/
 187     final static int WIN_STATE_SHADED          =(1<<5); /* shaded (MacOS / Afterstep style) */
 188 /* _WIN_LAYER values */
 189     final static int WIN_LAYER_ONTOP = 6;
 190     final static int WIN_LAYER_NORMAL = 4;
 191 
 192     long WinWindow = 0;
 193     boolean supportChecked = false;
 194     void detect() {
 195         if (supportChecked) {
 196             return;
 197         }
 198         WinWindow = checkAnchor(XA_WIN_SUPPORTING_WM_CHECK, XAtom.XA_CARDINAL);
 199         supportChecked = true;
 200         if (log.isLoggable(PlatformLogger.FINE)) log.fine("### " + this + " is active: " + (WinWindow != 0));
 201     }
 202 
 203     boolean active() {
 204         detect();
 205         return WinWindow != 0;
 206     }
 207     boolean doStateProtocol() {
 208         boolean res = active() && checkProtocol(XA_WIN_PROTOCOLS, XA_WIN_STATE);
 209         if (log.isLoggable(PlatformLogger.FINE)) log.fine("### " + this + " supports state: " + res);
 210         return res;
 211     }
 212 
 213     boolean doLayerProtocol() {
 214         boolean res = active() && checkProtocol(XA_WIN_PROTOCOLS, XA_WIN_LAYER);
 215         if (log.isLoggable(PlatformLogger.FINE)) log.fine("### " + this + " supports layer: " + res);
 216         return res;
 217     }
 218 }