35 import java.awt.Frame; |
35 import java.awt.Frame; |
36 import java.awt.Rectangle; |
36 import java.awt.Rectangle; |
37 import java.util.Collection; |
37 import java.util.Collection; |
38 import java.util.HashMap; |
38 import java.util.HashMap; |
39 import java.util.LinkedList; |
39 import java.util.LinkedList; |
40 import java.util.logging.Level; |
|
41 import java.util.logging.Logger; |
|
42 import java.util.regex.Matcher; |
40 import java.util.regex.Matcher; |
43 import java.util.regex.Pattern; |
41 import java.util.regex.Pattern; |
|
42 import sun.util.logging.PlatformLogger; |
|
43 |
44 |
44 |
45 /** |
45 /** |
46 * Class incapsulating knowledge about window managers in general |
46 * Class incapsulating knowledge about window managers in general |
47 * Descendants should provide some information about specific window manager. |
47 * Descendants should provide some information about specific window manager. |
48 */ |
48 */ |
49 final class XWM |
49 final class XWM |
50 { |
50 { |
51 |
51 |
52 private final static Logger log = Logger.getLogger("sun.awt.X11.XWM"); |
52 private final static PlatformLogger log = PlatformLogger.getLogger("sun.awt.X11.XWM"); |
53 private final static Logger insLog = Logger.getLogger("sun.awt.X11.insets.XWM"); |
53 private final static PlatformLogger insLog = PlatformLogger.getLogger("sun.awt.X11.insets.XWM"); |
54 private final static Logger stateLog = Logger.getLogger("sun.awt.X11.states.XWM"); |
54 private final static PlatformLogger stateLog = PlatformLogger.getLogger("sun.awt.X11.states.XWM"); |
55 |
55 |
56 static final XAtom XA_MWM_HINTS = new XAtom(); |
56 static final XAtom XA_MWM_HINTS = new XAtom(); |
57 |
57 |
58 private static Unsafe unsafe = XlibWrapper.unsafe; |
58 private static Unsafe unsafe = XlibWrapper.unsafe; |
59 |
59 |
262 final String selection_name = "WM_S" + default_screen_number; |
262 final String selection_name = "WM_S" + default_screen_number; |
263 |
263 |
264 long selection_owner = |
264 long selection_owner = |
265 XlibWrapper.XGetSelectionOwner(XToolkit.getDisplay(), |
265 XlibWrapper.XGetSelectionOwner(XToolkit.getDisplay(), |
266 XAtom.get(selection_name).getAtom()); |
266 XAtom.get(selection_name).getAtom()); |
267 if (insLog.isLoggable(Level.FINE)) { |
267 if (insLog.isLoggable(PlatformLogger.FINE)) { |
268 insLog.finer("selection owner of " + selection_name |
268 insLog.finer("selection owner of " + selection_name |
269 + " is " + selection_owner); |
269 + " is " + selection_owner); |
270 } |
270 } |
271 |
271 |
272 if (selection_owner != XConstants.None) { |
272 if (selection_owner != XConstants.None) { |
291 substruct.set_event_mask(0); |
291 substruct.set_event_mask(0); |
292 XlibWrapper.XChangeWindowAttributes(XToolkit.getDisplay(), |
292 XlibWrapper.XChangeWindowAttributes(XToolkit.getDisplay(), |
293 XToolkit.getDefaultRootWindow(), |
293 XToolkit.getDefaultRootWindow(), |
294 XConstants.CWEventMask, |
294 XConstants.CWEventMask, |
295 substruct.pData); |
295 substruct.pData); |
296 if (insLog.isLoggable(Level.FINE)) { |
296 if (insLog.isLoggable(PlatformLogger.FINE)) { |
297 insLog.finer("It looks like there is no WM thus NO_WM"); |
297 insLog.finer("It looks like there is no WM thus NO_WM"); |
298 } |
298 } |
299 } |
299 } |
300 |
300 |
301 return !winmgr_running; |
301 return !winmgr_running; |
399 static final XAtom XA_DT_SM_WINDOW_INFO = new XAtom("_DT_SM_WINDOW_INFO", false); |
399 static final XAtom XA_DT_SM_WINDOW_INFO = new XAtom("_DT_SM_WINDOW_INFO", false); |
400 static final XAtom XA_DT_SM_STATE_INFO = new XAtom("_DT_SM_STATE_INFO", false); |
400 static final XAtom XA_DT_SM_STATE_INFO = new XAtom("_DT_SM_STATE_INFO", false); |
401 static boolean isCDE() { |
401 static boolean isCDE() { |
402 |
402 |
403 if (!XA_DT_SM_WINDOW_INFO.isInterned()) { |
403 if (!XA_DT_SM_WINDOW_INFO.isInterned()) { |
404 log.log(Level.FINER, "{0} is not interned", new Object[] {XA_DT_SM_WINDOW_INFO}); |
404 log.finer("{0} is not interned", XA_DT_SM_WINDOW_INFO); |
405 return false; |
405 return false; |
406 } |
406 } |
407 |
407 |
408 WindowPropertyGetter getter = |
408 WindowPropertyGetter getter = |
409 new WindowPropertyGetter(XToolkit.getDefaultRootWindow(), |
409 new WindowPropertyGetter(XToolkit.getDefaultRootWindow(), |
430 return false; |
430 return false; |
431 } |
431 } |
432 |
432 |
433 /* Now check that this window has _DT_SM_STATE_INFO (ignore contents) */ |
433 /* Now check that this window has _DT_SM_STATE_INFO (ignore contents) */ |
434 if (!XA_DT_SM_STATE_INFO.isInterned()) { |
434 if (!XA_DT_SM_STATE_INFO.isInterned()) { |
435 log.log(Level.FINER, "{0} is not interned", new Object[] {XA_DT_SM_STATE_INFO}); |
435 log.finer("{0} is not interned", XA_DT_SM_STATE_INFO); |
436 return false; |
436 return false; |
437 } |
437 } |
438 WindowPropertyGetter getter2 = |
438 WindowPropertyGetter getter2 = |
439 new WindowPropertyGetter(wmwin, XA_DT_SM_STATE_INFO, 0, 1, |
439 new WindowPropertyGetter(wmwin, XA_DT_SM_STATE_INFO, 0, 1, |
440 false, XA_DT_SM_STATE_INFO); |
440 false, XA_DT_SM_STATE_INFO); |
594 * Choose something innocuous: "AWT_ICEWM_TEST allWorkspaces 0". |
594 * Choose something innocuous: "AWT_ICEWM_TEST allWorkspaces 0". |
595 * IceWM expects "class\0option\0arg\0" with zero bytes as delimiters. |
595 * IceWM expects "class\0option\0arg\0" with zero bytes as delimiters. |
596 */ |
596 */ |
597 |
597 |
598 if (!XA_ICEWM_WINOPTHINT.isInterned()) { |
598 if (!XA_ICEWM_WINOPTHINT.isInterned()) { |
599 log.log(Level.FINER, "{0} is not interned", new Object[] {XA_ICEWM_WINOPTHINT}); |
599 log.finer("{0} is not interned", XA_ICEWM_WINOPTHINT); |
600 return false; |
600 return false; |
601 } |
601 } |
602 |
602 |
603 XToolkit.awtLock(); |
603 XToolkit.awtLock(); |
604 try { |
604 try { |
627 * Note well: Only call this if awt_wm_prepareIsIceWM succeeded, or a |
627 * Note well: Only call this if awt_wm_prepareIsIceWM succeeded, or a |
628 * false positive will be reported. |
628 * false positive will be reported. |
629 */ |
629 */ |
630 static boolean isIceWM() { |
630 static boolean isIceWM() { |
631 if (!XA_ICEWM_WINOPTHINT.isInterned()) { |
631 if (!XA_ICEWM_WINOPTHINT.isInterned()) { |
632 log.log(Level.FINER, "{0} is not interned", new Object[] {XA_ICEWM_WINOPTHINT}); |
632 log.finer("{0} is not interned", XA_ICEWM_WINOPTHINT); |
633 return false; |
633 return false; |
634 } |
634 } |
635 |
635 |
636 WindowPropertyGetter getter = |
636 WindowPropertyGetter getter = |
637 new WindowPropertyGetter(XToolkit.getDefaultRootWindow(), |
637 new WindowPropertyGetter(XToolkit.getDefaultRootWindow(), |
692 wm = new XWM(awt_wmgr = getWMID()/*XWM.OTHER_WM*/); |
692 wm = new XWM(awt_wmgr = getWMID()/*XWM.OTHER_WM*/); |
693 } |
693 } |
694 return wm; |
694 return wm; |
695 } |
695 } |
696 static int getWMID() { |
696 static int getWMID() { |
697 if (insLog.isLoggable(Level.FINEST)) { |
697 if (insLog.isLoggable(PlatformLogger.FINEST)) { |
698 insLog.finest("awt_wmgr = " + awt_wmgr); |
698 insLog.finest("awt_wmgr = " + awt_wmgr); |
699 } |
699 } |
700 /* |
700 /* |
701 * Ideally, we should support cases when a different WM is started |
701 * Ideally, we should support cases when a different WM is started |
702 * during a Java app lifetime. |
702 * during a Java app lifetime. |
716 |
716 |
717 // Initialize _NET protocol - used to detect Window Manager. |
717 // Initialize _NET protocol - used to detect Window Manager. |
718 // Later, WM will initialize its own version of protocol |
718 // Later, WM will initialize its own version of protocol |
719 XNETProtocol l_net_protocol = g_net_protocol = new XNETProtocol(); |
719 XNETProtocol l_net_protocol = g_net_protocol = new XNETProtocol(); |
720 l_net_protocol.detect(); |
720 l_net_protocol.detect(); |
721 if (log.isLoggable(Level.FINE) && l_net_protocol.active()) { |
721 if (log.isLoggable(PlatformLogger.FINE) && l_net_protocol.active()) { |
722 log.fine("_NET_WM_NAME is " + l_net_protocol.getWMName()); |
722 log.fine("_NET_WM_NAME is " + l_net_protocol.getWMName()); |
723 } |
723 } |
724 XWINProtocol win = g_win_protocol = new XWINProtocol(); |
724 XWINProtocol win = g_win_protocol = new XWINProtocol(); |
725 win.detect(); |
725 win.detect(); |
726 |
726 |
796 if ((hints.get_flags() & mask) == 0) { |
796 if ((hints.get_flags() & mask) == 0) { |
797 return; |
797 return; |
798 } |
798 } |
799 |
799 |
800 hints.set_flags(hints.get_flags() & ~mask); |
800 hints.set_flags(hints.get_flags() & ~mask); |
801 if (insLog.isLoggable(Level.FINER)) insLog.finer("Setting hints, flags " + XlibWrapper.hintsToString(hints.get_flags())); |
801 if (insLog.isLoggable(PlatformLogger.FINER)) insLog.finer("Setting hints, flags " + XlibWrapper.hintsToString(hints.get_flags())); |
802 XlibWrapper.XSetWMNormalHints(XToolkit.getDisplay(), |
802 XlibWrapper.XSetWMNormalHints(XToolkit.getDisplay(), |
803 window.getWindow(), |
803 window.getWindow(), |
804 hints.pData); |
804 hints.pData); |
805 } finally { |
805 } finally { |
806 XToolkit.awtUnlock(); |
806 XToolkit.awtUnlock(); |
853 return; |
853 return; |
854 } |
854 } |
855 |
855 |
856 XAtomList decorDel = new XAtomList(); |
856 XAtomList decorDel = new XAtomList(); |
857 decorations = normalizeMotifDecor(decorations); |
857 decorations = normalizeMotifDecor(decorations); |
858 if (insLog.isLoggable(Level.FINER)) insLog.finer("Setting OL_DECOR to " + Integer.toBinaryString(decorations)); |
858 if (insLog.isLoggable(PlatformLogger.FINER)) insLog.finer("Setting OL_DECOR to " + Integer.toBinaryString(decorations)); |
859 if ((decorations & MWMConstants.MWM_DECOR_TITLE) == 0) { |
859 if ((decorations & MWMConstants.MWM_DECOR_TITLE) == 0) { |
860 decorDel.add(XA_OL_DECOR_HEADER); |
860 decorDel.add(XA_OL_DECOR_HEADER); |
861 } |
861 } |
862 if ((decorations & (MWMConstants.MWM_DECOR_RESIZEH | MWMConstants.MWM_DECOR_MAXIMIZE)) == 0) { |
862 if ((decorations & (MWMConstants.MWM_DECOR_RESIZEH | MWMConstants.MWM_DECOR_MAXIMIZE)) == 0) { |
863 decorDel.add(XA_OL_DECOR_RESIZE); |
863 decorDel.add(XA_OL_DECOR_RESIZE); |
870 } |
870 } |
871 if (decorDel.size() == 0) { |
871 if (decorDel.size() == 0) { |
872 insLog.finer("Deleting OL_DECOR"); |
872 insLog.finer("Deleting OL_DECOR"); |
873 XA_OL_DECOR_DEL.DeleteProperty(window); |
873 XA_OL_DECOR_DEL.DeleteProperty(window); |
874 } else { |
874 } else { |
875 if (insLog.isLoggable(Level.FINER)) insLog.finer("Setting OL_DECOR to " + decorDel); |
875 if (insLog.isLoggable(PlatformLogger.FINER)) insLog.finer("Setting OL_DECOR to " + decorDel); |
876 XA_OL_DECOR_DEL.setAtomListProperty(window, decorDel); |
876 XA_OL_DECOR_DEL.setAtomListProperty(window, decorDel); |
877 } |
877 } |
878 } |
878 } |
879 |
879 |
880 /* |
880 /* |
898 MWMConstants.MWM_HINTS_FUNCTIONS | |
898 MWMConstants.MWM_HINTS_FUNCTIONS | |
899 MWMConstants.MWM_HINTS_DECORATIONS); |
899 MWMConstants.MWM_HINTS_DECORATIONS); |
900 hints.set_functions(functions); |
900 hints.set_functions(functions); |
901 hints.set_decorations(decorations); |
901 hints.set_decorations(decorations); |
902 |
902 |
903 if (stateLog.isLoggable(Level.FINER)) stateLog.finer("Setting MWM_HINTS to " + hints); |
903 if (stateLog.isLoggable(PlatformLogger.FINER)) stateLog.finer("Setting MWM_HINTS to " + hints); |
904 window.setMWMHints(hints); |
904 window.setMWMHints(hints); |
905 } |
905 } |
906 |
906 |
907 /* |
907 /* |
908 * Under some window managers if shell is already mapped, we MUST |
908 * Under some window managers if shell is already mapped, we MUST |
960 |
960 |
961 /* |
961 /* |
962 * Make specified shell resizable. |
962 * Make specified shell resizable. |
963 */ |
963 */ |
964 static void setShellResizable(XDecoratedPeer window) { |
964 static void setShellResizable(XDecoratedPeer window) { |
965 if (insLog.isLoggable(Level.FINE)) insLog.fine("Setting shell resizable " + window); |
965 if (insLog.isLoggable(PlatformLogger.FINE)) insLog.fine("Setting shell resizable " + window); |
966 XToolkit.awtLock(); |
966 XToolkit.awtLock(); |
967 try { |
967 try { |
968 Rectangle shellBounds = window.getShellBounds(); |
968 Rectangle shellBounds = window.getShellBounds(); |
969 shellBounds.translate(-window.currentInsets.left, -window.currentInsets.top); |
969 shellBounds.translate(-window.currentInsets.left, -window.currentInsets.top); |
970 window.updateSizeHints(window.getDimensions()); |
970 window.updateSizeHints(window.getDimensions()); |
990 * @param shellBounds bounds of the shell window |
990 * @param shellBounds bounds of the shell window |
991 */ |
991 */ |
992 static void setShellNotResizable(XDecoratedPeer window, WindowDimensions newDimensions, Rectangle shellBounds, |
992 static void setShellNotResizable(XDecoratedPeer window, WindowDimensions newDimensions, Rectangle shellBounds, |
993 boolean justChangeSize) |
993 boolean justChangeSize) |
994 { |
994 { |
995 if (insLog.isLoggable(Level.FINE)) insLog.fine("Setting non-resizable shell " + window + ", dimensions " + newDimensions + |
995 if (insLog.isLoggable(PlatformLogger.FINE)) insLog.fine("Setting non-resizable shell " + window + ", dimensions " + newDimensions + |
996 ", shellBounds " + shellBounds +", just change size: " + justChangeSize); |
996 ", shellBounds " + shellBounds +", just change size: " + justChangeSize); |
997 XToolkit.awtLock(); |
997 XToolkit.awtLock(); |
998 try { |
998 try { |
999 /* Fix min/max size hints at the specified values */ |
999 /* Fix min/max size hints at the specified values */ |
1000 if (!shellBounds.isEmpty()) { |
1000 if (!shellBounds.isEmpty()) { |
1352 return null; |
1352 return null; |
1353 } |
1353 } |
1354 XNETProtocol net_protocol = getWM().getNETProtocol(); |
1354 XNETProtocol net_protocol = getWM().getNETProtocol(); |
1355 if (net_protocol != null && net_protocol.active()) { |
1355 if (net_protocol != null && net_protocol.active()) { |
1356 Insets insets = getInsetsFromProp(window, XA_NET_FRAME_EXTENTS); |
1356 Insets insets = getInsetsFromProp(window, XA_NET_FRAME_EXTENTS); |
1357 insLog.log(Level.FINE, "_NET_FRAME_EXTENTS: {0}", insets); |
1357 insLog.fine("_NET_FRAME_EXTENTS: {0}", insets); |
1358 |
1358 |
1359 if (insets != null) { |
1359 if (insets != null) { |
1360 return insets; |
1360 return insets; |
1361 } |
1361 } |
1362 } |
1362 } |
1493 * parent is a lining exactly the size of the client |
1493 * parent is a lining exactly the size of the client |
1494 * grandpa is the WM frame |
1494 * grandpa is the WM frame |
1495 * [mwm, e!, kwin, fvwm2 ... ] |
1495 * [mwm, e!, kwin, fvwm2 ... ] |
1496 */ |
1496 */ |
1497 Insets correctWM = XWM.getInsetsFromExtents(window); |
1497 Insets correctWM = XWM.getInsetsFromExtents(window); |
1498 insLog.log(Level.FINER, "Got insets from property: {0}", correctWM); |
1498 insLog.finer("Got insets from property: {0}", correctWM); |
1499 |
1499 |
1500 if (correctWM == null) { |
1500 if (correctWM == null) { |
1501 correctWM = new Insets(0,0,0,0); |
1501 correctWM = new Insets(0,0,0,0); |
1502 |
1502 |
1503 correctWM.top = -1; |
1503 correctWM.top = -1; |
1554 correctWM.bottom = correctWM.left; |
1554 correctWM.bottom = correctWM.left; |
1555 break; |
1555 break; |
1556 } |
1556 } |
1557 case XWM.OTHER_WM: |
1557 case XWM.OTHER_WM: |
1558 default: { /* this is very similar to the E! case above */ |
1558 default: { /* this is very similar to the E! case above */ |
1559 insLog.log(Level.FINEST, "Getting correct insets for OTHER_WM/default, parent: {0}", parent); |
1559 insLog.finest("Getting correct insets for OTHER_WM/default, parent: {0}", parent); |
1560 syncTopLevelPos(parent, lwinAttr); |
1560 syncTopLevelPos(parent, lwinAttr); |
1561 int status = XlibWrapper.XGetWindowAttributes(XToolkit.getDisplay(), |
1561 int status = XlibWrapper.XGetWindowAttributes(XToolkit.getDisplay(), |
1562 window, lwinAttr.pData); |
1562 window, lwinAttr.pData); |
1563 status = XlibWrapper.XGetWindowAttributes(XToolkit.getDisplay(), |
1563 status = XlibWrapper.XGetWindowAttributes(XToolkit.getDisplay(), |
1564 parent, pattr.pData); |
1564 parent, pattr.pData); |
1581 */ |
1581 */ |
1582 if (lwinAttr.get_x() == 0 && lwinAttr.get_y() == 0 |
1582 if (lwinAttr.get_x() == 0 && lwinAttr.get_y() == 0 |
1583 && lwinAttr.get_width()+2*lwinAttr.get_border_width() == pattr.get_width() |
1583 && lwinAttr.get_width()+2*lwinAttr.get_border_width() == pattr.get_width() |
1584 && lwinAttr.get_height()+2*lwinAttr.get_border_width() == pattr.get_height()) |
1584 && lwinAttr.get_height()+2*lwinAttr.get_border_width() == pattr.get_height()) |
1585 { |
1585 { |
1586 insLog.log(Level.FINEST, "Double reparenting detected, pattr({2})={0}, lwinAttr({3})={1}", |
1586 insLog.finest("Double reparenting detected, pattr({2})={0}, lwinAttr({3})={1}", |
1587 new Object[] {lwinAttr, pattr, parent, window}); |
1587 lwinAttr, pattr, parent, window); |
1588 lwinAttr.set_x(pattr.get_x()); |
1588 lwinAttr.set_x(pattr.get_x()); |
1589 lwinAttr.set_y(pattr.get_y()); |
1589 lwinAttr.set_y(pattr.get_y()); |
1590 lwinAttr.set_border_width(lwinAttr.get_border_width()+pattr.get_border_width()); |
1590 lwinAttr.set_border_width(lwinAttr.get_border_width()+pattr.get_border_width()); |
1591 |
1591 |
1592 final long grand_parent = XlibUtil.getParentWindow(parent); |
1592 final long grand_parent = XlibUtil.getParentWindow(parent); |
1609 * parent's border-width into account too, but the |
1609 * parent's border-width into account too, but the |
1610 * rest of the code is happily unaware about border |
1610 * rest of the code is happily unaware about border |
1611 * widths and inner/outer distinction, so for the time |
1611 * widths and inner/outer distinction, so for the time |
1612 * being, just ignore it. |
1612 * being, just ignore it. |
1613 */ |
1613 */ |
1614 insLog.log(Level.FINEST, "Attrs before calculation: pattr({2})={0}, lwinAttr({3})={1}", |
1614 insLog.finest("Attrs before calculation: pattr({2})={0}, lwinAttr({3})={1}", |
1615 new Object[] {lwinAttr, pattr, parent, window}); |
1615 lwinAttr, pattr, parent, window); |
1616 correctWM = new Insets(lwinAttr.get_y() + lwinAttr.get_border_width(), |
1616 correctWM = new Insets(lwinAttr.get_y() + lwinAttr.get_border_width(), |
1617 lwinAttr.get_x() + lwinAttr.get_border_width(), |
1617 lwinAttr.get_x() + lwinAttr.get_border_width(), |
1618 pattr.get_height() - (lwinAttr.get_y() + lwinAttr.get_height() + 2*lwinAttr.get_border_width()), |
1618 pattr.get_height() - (lwinAttr.get_y() + lwinAttr.get_height() + 2*lwinAttr.get_border_width()), |
1619 pattr.get_width() - (lwinAttr.get_x() + lwinAttr.get_width() + 2*lwinAttr.get_border_width())); |
1619 pattr.get_width() - (lwinAttr.get_x() + lwinAttr.get_width() + 2*lwinAttr.get_border_width())); |
1620 break; |
1620 break; |