131 case LG3D_WM:
132 return "LookingGlass";
133 case CWM_WM:
134 return "CWM";
135 case MUTTER_WM:
136 return "Mutter";
137 case UNDETERMINED_WM:
138 default:
139 return "Undetermined WM";
140 }
141 }
142
143
144 int WMID;
145 static final Insets zeroInsets = new Insets(0, 0, 0, 0);
146 static final Insets defaultInsets = new Insets(25, 5, 5, 5);
147
148 XWM(int WMID) {
149 this.WMID = WMID;
150 initializeProtocols();
151 if (log.isLoggable(PlatformLogger.FINE)) log.fine("Window manager: " + toString());
152 }
153 int getID() {
154 return WMID;
155 }
156
157
158 static Insets normalize(Insets insets) {
159 if (insets.top > 64 || insets.top < 0) {
160 insets.top = 28;
161 }
162 if (insets.left > 32 || insets.left < 0) {
163 insets.left = 6;
164 }
165 if (insets.right > 32 || insets.right < 0) {
166 insets.right = 6;
167 }
168 if (insets.bottom > 32 || insets.bottom < 0) {
169 insets.bottom = 6;
170 }
171 return insets;
235 *
236 * No selection owner, but, perhaps it is not ICCCM compliant WM
237 * (e.g. CDE/Sawfish).
238 * Try selecting for SubstructureRedirect, that only one client
239 * can select for, and if the request fails, than some other WM is
240 * already running.
241 *
242 * We also treat eXcursion as NO_WM.
243 */
244 private static boolean isNoWM() {
245 /*
246 * Quick checks for specific servers.
247 */
248 String vendor_string = XlibWrapper.ServerVendor(XToolkit.getDisplay());
249 if (vendor_string.indexOf("eXcursion") != -1) {
250 /*
251 * Use NO_WM since in all other aspects eXcursion is like not
252 * having a window manager running. I.e. it does not reparent
253 * top level shells.
254 */
255 if (insLog.isLoggable(PlatformLogger.FINE)) {
256 insLog.finer("eXcursion means NO_WM");
257 }
258 return true;
259 }
260
261 XSetWindowAttributes substruct = new XSetWindowAttributes();
262 try {
263 /*
264 * Let's check an owner of WM_Sn selection for the default screen.
265 */
266 final long default_screen_number =
267 XlibWrapper.DefaultScreen(XToolkit.getDisplay());
268 final String selection_name = "WM_S" + default_screen_number;
269
270 long selection_owner =
271 XlibWrapper.XGetSelectionOwner(XToolkit.getDisplay(),
272 XAtom.get(selection_name).getAtom());
273 if (insLog.isLoggable(PlatformLogger.FINE)) {
274 insLog.finer("selection owner of " + selection_name
275 + " is " + selection_owner);
276 }
277
278 if (selection_owner != XConstants.None) {
279 return false;
280 }
281
282 winmgr_running = false;
283 substruct.set_event_mask(XConstants.SubstructureRedirectMask);
284
285 XToolkit.WITH_XERROR_HANDLER(detectWMHandler);
286 XlibWrapper.XChangeWindowAttributes(XToolkit.getDisplay(),
287 XToolkit.getDefaultRootWindow(),
288 XConstants.CWEventMask,
289 substruct.pData);
290 XToolkit.RESTORE_XERROR_HANDLER();
291
292 /*
293 * If no WM is running then our selection for SubstructureRedirect
294 * succeeded and needs to be undone (hey we are *not* a WM ;-).
295 */
296 if (!winmgr_running) {
297 substruct.set_event_mask(0);
298 XlibWrapper.XChangeWindowAttributes(XToolkit.getDisplay(),
299 XToolkit.getDefaultRootWindow(),
300 XConstants.CWEventMask,
301 substruct.pData);
302 if (insLog.isLoggable(PlatformLogger.FINE)) {
303 insLog.finer("It looks like there is no WM thus NO_WM");
304 }
305 }
306
307 return !winmgr_running;
308 } finally {
309 substruct.dispose();
310 }
311 }
312
313 static XAtom XA_ENLIGHTENMENT_COMMS = new XAtom("ENLIGHTENMENT_COMMS", false);
314 /*
315 * Helper function for isEnlightenment().
316 * Enlightenment uses STRING property for its comms window id. Gaaa!
317 * The property is ENLIGHTENMENT_COMMS, STRING/8 and the string format
318 * is "WINID %8x". Gee, I haven't been using scanf for *ages*... :-)
319 */
320 static long getECommsWindowIDProperty(long window) {
321
322 if (!XA_ENLIGHTENMENT_COMMS.isInterned()) {
326 WindowPropertyGetter getter =
327 new WindowPropertyGetter(window, XA_ENLIGHTENMENT_COMMS, 0, 14, false,
328 XAtom.XA_STRING);
329 try {
330 int status = getter.execute(XErrorHandler.IgnoreBadWindowHandler.getInstance());
331 if (status != XConstants.Success || getter.getData() == 0) {
332 return 0;
333 }
334
335 if (getter.getActualType() != XAtom.XA_STRING
336 || getter.getActualFormat() != 8
337 || getter.getNumberOfItems() != 14 || getter.getBytesAfter() != 0)
338 {
339 return 0;
340 }
341
342 // Convert data to String, ASCII
343 byte[] bytes = XlibWrapper.getStringBytes(getter.getData());
344 String id = new String(bytes);
345
346 log.finer("ENLIGHTENMENT_COMMS is " + id);
347
348 // Parse WINID
349 Pattern winIdPat = Pattern.compile("WINID\\s+(\\p{XDigit}{0,8})");
350 try {
351 Matcher match = winIdPat.matcher(id);
352 if (match.matches()) {
353 log.finest("Match group count: " + match.groupCount());
354 String longId = match.group(1);
355 log.finest("Match group 1 " + longId);
356 long winid = Long.parseLong(longId, 16);
357 log.finer("Enlightenment communication window " + winid);
358 return winid;
359 } else {
360 log.finer("ENLIGHTENMENT_COMMS has wrong format");
361 return 0;
362 }
363 } catch (Exception e) {
364 if (log.isLoggable(PlatformLogger.FINER)) {
365 e.printStackTrace();
366 }
367 return 0;
368 }
369 } finally {
370 getter.dispose();
371 }
372 }
373
374 /*
375 * Is Enlightenment WM running? Congruent to awt_wm_checkAnchor, but
376 * uses STRING property peculiar to Enlightenment.
377 */
637
638 /*
639 * Is IceWM running?
640 *
641 * Note well: Only call this if awt_wm_prepareIsIceWM succeeded, or a
642 * false positive will be reported.
643 */
644 static boolean isIceWM() {
645 if (!XA_ICEWM_WINOPTHINT.isInterned()) {
646 log.finer("{0} is not interned", XA_ICEWM_WINOPTHINT);
647 return false;
648 }
649
650 WindowPropertyGetter getter =
651 new WindowPropertyGetter(XToolkit.getDefaultRootWindow(),
652 XA_ICEWM_WINOPTHINT, 0, 0xFFFF,
653 true, XA_ICEWM_WINOPTHINT);
654 try {
655 int status = getter.execute();
656 boolean res = (status == XConstants.Success && getter.getActualType() != 0);
657 log.finer("Status getting XA_ICEWM_WINOPTHINT: " + !res);
658 return !res || isNetWMName("IceWM");
659 } finally {
660 getter.dispose();
661 }
662 }
663
664 /*
665 * Is OpenLook WM running?
666 *
667 * This one is pretty lame, but the only property peculiar to OLWM is
668 * _SUN_WM_PROTOCOLS(ATOM[]). Fortunately, olwm deletes it on exit.
669 */
670 static final XAtom XA_SUN_WM_PROTOCOLS = new XAtom("_SUN_WM_PROTOCOLS", false);
671 static boolean isOpenLook() {
672 if (!XA_SUN_WM_PROTOCOLS.isInterned()) {
673 return false;
674 }
675
676 XAtom[] list = XA_SUN_WM_PROTOCOLS.getAtomListProperty(XToolkit.getDefaultRootWindow());
677 return (list.length != 0);
799 * Size and decoration hints ...
800 *
801 \*****************************************************************************/
802
803
804 /*
805 * Remove size hints specified by the mask.
806 * XXX: Why do we need this in the first place???
807 */
808 static void removeSizeHints(XDecoratedPeer window, long mask) {
809 mask &= XUtilConstants.PMaxSize | XUtilConstants.PMinSize;
810
811 XToolkit.awtLock();
812 try {
813 XSizeHints hints = window.getHints();
814 if ((hints.get_flags() & mask) == 0) {
815 return;
816 }
817
818 hints.set_flags(hints.get_flags() & ~mask);
819 if (insLog.isLoggable(PlatformLogger.FINER)) insLog.finer("Setting hints, flags " + XlibWrapper.hintsToString(hints.get_flags()));
820 XlibWrapper.XSetWMNormalHints(XToolkit.getDisplay(),
821 window.getWindow(),
822 hints.pData);
823 } finally {
824 XToolkit.awtUnlock();
825 }
826 }
827
828 /*
829 * If MWM_DECOR_ALL bit is set, then the rest of the bit-mask is taken
830 * to be subtracted from the decorations. Normalize decoration spec
831 * so that we can map motif decor to something else bit-by-bit in the
832 * rest of the code.
833 */
834 static int normalizeMotifDecor(int decorations) {
835 if ((decorations & MWMConstants.MWM_DECOR_ALL) == 0) {
836 return decorations;
837 }
838 int d = MWMConstants.MWM_DECOR_BORDER | MWMConstants.MWM_DECOR_RESIZEH
839 | MWMConstants.MWM_DECOR_TITLE
856 int f = MWMConstants.MWM_FUNC_RESIZE |
857 MWMConstants.MWM_FUNC_MOVE |
858 MWMConstants.MWM_FUNC_MAXIMIZE |
859 MWMConstants.MWM_FUNC_MINIMIZE |
860 MWMConstants.MWM_FUNC_CLOSE;
861 f &= ~functions;
862 return f;
863 }
864
865 /*
866 * Infer OL properties from MWM decorations.
867 * Use _OL_DECOR_DEL(ATOM[]) to remove unwanted ones.
868 */
869 static void setOLDecor(XWindow window, boolean resizable, int decorations) {
870 if (window == null) {
871 return;
872 }
873
874 XAtomList decorDel = new XAtomList();
875 decorations = normalizeMotifDecor(decorations);
876 if (insLog.isLoggable(PlatformLogger.FINER)) insLog.finer("Setting OL_DECOR to " + Integer.toBinaryString(decorations));
877 if ((decorations & MWMConstants.MWM_DECOR_TITLE) == 0) {
878 decorDel.add(XA_OL_DECOR_HEADER);
879 }
880 if ((decorations & (MWMConstants.MWM_DECOR_RESIZEH | MWMConstants.MWM_DECOR_MAXIMIZE)) == 0) {
881 decorDel.add(XA_OL_DECOR_RESIZE);
882 }
883 if ((decorations & (MWMConstants.MWM_DECOR_MENU |
884 MWMConstants.MWM_DECOR_MAXIMIZE |
885 MWMConstants.MWM_DECOR_MINIMIZE)) == 0)
886 {
887 decorDel.add(XA_OL_DECOR_CLOSE);
888 }
889 if (decorDel.size() == 0) {
890 insLog.finer("Deleting OL_DECOR");
891 XA_OL_DECOR_DEL.DeleteProperty(window);
892 } else {
893 if (insLog.isLoggable(PlatformLogger.FINER)) insLog.finer("Setting OL_DECOR to " + decorDel);
894 XA_OL_DECOR_DEL.setAtomListProperty(window, decorDel);
895 }
896 }
897
898 /*
899 * Set MWM decorations. Set MWM functions depending on resizability.
900 */
901 static void setMotifDecor(XWindow window, boolean resizable, int decorations, int functions) {
902 /* Apparently some WMs don't implement MWM_*_ALL semantic correctly */
903 if ((decorations & MWMConstants.MWM_DECOR_ALL) != 0
904 && (decorations != MWMConstants.MWM_DECOR_ALL))
905 {
906 decorations = normalizeMotifDecor(decorations);
907 }
908 if ((functions & MWMConstants.MWM_FUNC_ALL) != 0
909 && (functions != MWMConstants.MWM_FUNC_ALL))
910 {
911 functions = normalizeMotifFunc(functions);
912 }
913
914 PropMwmHints hints = window.getMWMHints();
915 hints.set_flags(hints.get_flags() |
916 MWMConstants.MWM_HINTS_FUNCTIONS |
917 MWMConstants.MWM_HINTS_DECORATIONS);
918 hints.set_functions(functions);
919 hints.set_decorations(decorations);
920
921 if (stateLog.isLoggable(PlatformLogger.FINER)) stateLog.finer("Setting MWM_HINTS to " + hints);
922 window.setMWMHints(hints);
923 }
924
925 /*
926 * Under some window managers if shell is already mapped, we MUST
927 * unmap and later remap in order to effect the changes we make in the
928 * window manager decorations.
929 *
930 * N.B. This unmapping / remapping of the shell exposes a bug in
931 * X/Motif or the Motif Window Manager. When you attempt to map a
932 * widget which is positioned (partially) off-screen, the window is
933 * relocated to be entirely on screen. Good idea. But if both the x
934 * and the y coordinates are less than the origin (0,0), the first
935 * (re)map will move the window to the origin, and any subsequent
936 * (re)map will relocate the window at some other point on the screen.
937 * I have written a short Motif test program to discover this bug.
938 * This should occur infrequently and it does not cause any real
939 * problem. So for now we'll let it be.
940 */
941 static boolean needRemap(XDecoratedPeer window) {
963 setMotifDecor(window, resizable, decorations, functions);
964 setOLDecor(window, resizable, decorations);
965
966 /* Some WMs need remap to redecorate the window */
967 if (window.isShowing() && needRemap(window)) {
968 /*
969 * Do the re/mapping at the Xlib level. Since we essentially
970 * work around a WM bug we don't want this hack to be exposed
971 * to Intrinsics (i.e. don't mess with grabs, callbacks etc).
972 */
973 window.xSetVisible(false);
974 XToolkit.XSync();
975 window.xSetVisible(true);
976 }
977 }
978
979 /*
980 * Make specified shell resizable.
981 */
982 static void setShellResizable(XDecoratedPeer window) {
983 if (insLog.isLoggable(PlatformLogger.FINE)) insLog.fine("Setting shell resizable " + window);
984 XToolkit.awtLock();
985 try {
986 Rectangle shellBounds = window.getShellBounds();
987 shellBounds.translate(-window.currentInsets.left, -window.currentInsets.top);
988 window.updateSizeHints(window.getDimensions());
989 requestWMExtents(window.getWindow());
990 XlibWrapper.XMoveResizeWindow(XToolkit.getDisplay(), window.getShell(),
991 shellBounds.x, shellBounds.y, shellBounds.width, shellBounds.height);
992 /* REMINDER: will need to revisit when setExtendedStateBounds is added */
993 //Fix for 4320050: Minimum size for java.awt.Frame is not being enforced.
994 //We need to update frame's minimum size, not to reset it
995 removeSizeHints(window, XUtilConstants.PMaxSize);
996 window.updateMinimumSize();
997
998 /* Restore decorations */
999 setShellDecor(window);
1000 } finally {
1001 XToolkit.awtUnlock();
1002 }
1003 }
1004
1005 /*
1006 * Make specified shell non-resizable.
1007 * If justChangeSize is false, update decorations as well.
1008 * @param shellBounds bounds of the shell window
1009 */
1010 static void setShellNotResizable(XDecoratedPeer window, WindowDimensions newDimensions, Rectangle shellBounds,
1011 boolean justChangeSize)
1012 {
1013 if (insLog.isLoggable(PlatformLogger.FINE)) insLog.fine("Setting non-resizable shell " + window + ", dimensions " + newDimensions +
1014 ", shellBounds " + shellBounds +", just change size: " + justChangeSize);
1015 XToolkit.awtLock();
1016 try {
1017 /* Fix min/max size hints at the specified values */
1018 if (!shellBounds.isEmpty()) {
1019 window.updateSizeHints(newDimensions);
1020 requestWMExtents(window.getWindow());
1021 XToolkit.XSync();
1022 XlibWrapper.XMoveResizeWindow(XToolkit.getDisplay(), window.getShell(),
1023 shellBounds.x, shellBounds.y, shellBounds.width, shellBounds.height);
1024 }
1025 if (!justChangeSize) { /* update decorations */
1026 setShellDecor(window);
1027 }
1028 } finally {
1029 XToolkit.awtUnlock();
1030 }
1031 }
1032
1033 /*****************************************************************************\
1034 * Protocols support
1125 *
1126 * Notice window state change when WM changes a property on the window ...
1127 *
1128 \*****************************************************************************/
1129
1130
1131 /*
1132 * Check if property change is a window state protocol message.
1133 */
1134 boolean isStateChange(XDecoratedPeer window, XPropertyEvent e) {
1135 if (!window.isShowing()) {
1136 stateLog.finer("Window is not showing");
1137 return false;
1138 }
1139
1140 int wm_state = window.getWMState();
1141 if (wm_state == XUtilConstants.WithdrawnState) {
1142 stateLog.finer("WithdrawnState");
1143 return false;
1144 } else {
1145 stateLog.finer("Window WM_STATE is " + wm_state);
1146 }
1147 boolean is_state_change = false;
1148 if (e.get_atom() == XA_WM_STATE.getAtom()) {
1149 is_state_change = true;
1150 }
1151
1152 for (XStateProtocol proto : getProtocols(XStateProtocol.class)) {
1153 is_state_change |= proto.isStateChange(e);
1154 stateLog.finest(proto + ": is state changed = " + is_state_change);
1155 }
1156 return is_state_change;
1157 }
1158
1159 /*
1160 * Returns current state (including extended) of a given window.
1161 */
1162 int getState(XDecoratedPeer window) {
1163 int res = 0;
1164 final int wm_state = window.getWMState();
1165 if (wm_state == XUtilConstants.IconicState) {
1166 res = Frame.ICONIFIED;
1167 } else {
1168 res = Frame.NORMAL;
1169 }
1170 res |= getExtendedState(window);
1171 return res;
1172 }
1173
1174 /*****************************************************************************\
1175 *
1286 Insets guessInsets(XDecoratedPeer window) {
1287 Insets res = (Insets)storedInsets.get(window.getClass());
1288 if (res == null) {
1289 switch (WMID) {
1290 case ENLIGHTEN_WM:
1291 res = new Insets(19, 4, 4, 4);
1292 break;
1293 case CDE_WM:
1294 res = new Insets(28, 6, 6, 6);
1295 break;
1296 case NO_WM:
1297 case LG3D_WM:
1298 res = zeroInsets;
1299 break;
1300 case MOTIF_WM:
1301 case OPENLOOK_WM:
1302 default:
1303 res = defaultInsets;
1304 }
1305 }
1306 if (insLog.isLoggable(PlatformLogger.FINEST)) insLog.finest("WM guessed insets: " + res);
1307 return res;
1308 }
1309 /*
1310 * Some buggy WMs ignore window gravity when processing
1311 * ConfigureRequest and position window as if the gravity is Static.
1312 * We work around this in MWindowPeer.pReshape().
1313 *
1314 * Starting with 1.5 we have introduced an Environment variable
1315 * _JAVA_AWT_WM_STATIC_GRAVITY that can be set to indicate to Java
1316 * explicitly that the WM has this behaviour, example is FVWM.
1317 */
1318
1319 static int awtWMStaticGravity = -1;
1320 static boolean configureGravityBuggy() {
1321
1322 if (awtWMStaticGravity == -1) {
1323 awtWMStaticGravity = (XToolkit.getEnv("_JAVA_AWT_WM_STATIC_GRAVITY") != null) ? 1 : 0;
1324 }
1325
1326 if (awtWMStaticGravity == 1) {
|
131 case LG3D_WM:
132 return "LookingGlass";
133 case CWM_WM:
134 return "CWM";
135 case MUTTER_WM:
136 return "Mutter";
137 case UNDETERMINED_WM:
138 default:
139 return "Undetermined WM";
140 }
141 }
142
143
144 int WMID;
145 static final Insets zeroInsets = new Insets(0, 0, 0, 0);
146 static final Insets defaultInsets = new Insets(25, 5, 5, 5);
147
148 XWM(int WMID) {
149 this.WMID = WMID;
150 initializeProtocols();
151 if (log.isLoggable(PlatformLogger.FINE)) {
152 log.fine("Window manager: " + toString());
153 }
154 }
155 int getID() {
156 return WMID;
157 }
158
159
160 static Insets normalize(Insets insets) {
161 if (insets.top > 64 || insets.top < 0) {
162 insets.top = 28;
163 }
164 if (insets.left > 32 || insets.left < 0) {
165 insets.left = 6;
166 }
167 if (insets.right > 32 || insets.right < 0) {
168 insets.right = 6;
169 }
170 if (insets.bottom > 32 || insets.bottom < 0) {
171 insets.bottom = 6;
172 }
173 return insets;
237 *
238 * No selection owner, but, perhaps it is not ICCCM compliant WM
239 * (e.g. CDE/Sawfish).
240 * Try selecting for SubstructureRedirect, that only one client
241 * can select for, and if the request fails, than some other WM is
242 * already running.
243 *
244 * We also treat eXcursion as NO_WM.
245 */
246 private static boolean isNoWM() {
247 /*
248 * Quick checks for specific servers.
249 */
250 String vendor_string = XlibWrapper.ServerVendor(XToolkit.getDisplay());
251 if (vendor_string.indexOf("eXcursion") != -1) {
252 /*
253 * Use NO_WM since in all other aspects eXcursion is like not
254 * having a window manager running. I.e. it does not reparent
255 * top level shells.
256 */
257 if (insLog.isLoggable(PlatformLogger.FINER)) {
258 insLog.finer("eXcursion means NO_WM");
259 }
260 return true;
261 }
262
263 XSetWindowAttributes substruct = new XSetWindowAttributes();
264 try {
265 /*
266 * Let's check an owner of WM_Sn selection for the default screen.
267 */
268 final long default_screen_number =
269 XlibWrapper.DefaultScreen(XToolkit.getDisplay());
270 final String selection_name = "WM_S" + default_screen_number;
271
272 long selection_owner =
273 XlibWrapper.XGetSelectionOwner(XToolkit.getDisplay(),
274 XAtom.get(selection_name).getAtom());
275 if (insLog.isLoggable(PlatformLogger.FINER)) {
276 insLog.finer("selection owner of " + selection_name
277 + " is " + selection_owner);
278 }
279
280 if (selection_owner != XConstants.None) {
281 return false;
282 }
283
284 winmgr_running = false;
285 substruct.set_event_mask(XConstants.SubstructureRedirectMask);
286
287 XToolkit.WITH_XERROR_HANDLER(detectWMHandler);
288 XlibWrapper.XChangeWindowAttributes(XToolkit.getDisplay(),
289 XToolkit.getDefaultRootWindow(),
290 XConstants.CWEventMask,
291 substruct.pData);
292 XToolkit.RESTORE_XERROR_HANDLER();
293
294 /*
295 * If no WM is running then our selection for SubstructureRedirect
296 * succeeded and needs to be undone (hey we are *not* a WM ;-).
297 */
298 if (!winmgr_running) {
299 substruct.set_event_mask(0);
300 XlibWrapper.XChangeWindowAttributes(XToolkit.getDisplay(),
301 XToolkit.getDefaultRootWindow(),
302 XConstants.CWEventMask,
303 substruct.pData);
304 if (insLog.isLoggable(PlatformLogger.FINER)) {
305 insLog.finer("It looks like there is no WM thus NO_WM");
306 }
307 }
308
309 return !winmgr_running;
310 } finally {
311 substruct.dispose();
312 }
313 }
314
315 static XAtom XA_ENLIGHTENMENT_COMMS = new XAtom("ENLIGHTENMENT_COMMS", false);
316 /*
317 * Helper function for isEnlightenment().
318 * Enlightenment uses STRING property for its comms window id. Gaaa!
319 * The property is ENLIGHTENMENT_COMMS, STRING/8 and the string format
320 * is "WINID %8x". Gee, I haven't been using scanf for *ages*... :-)
321 */
322 static long getECommsWindowIDProperty(long window) {
323
324 if (!XA_ENLIGHTENMENT_COMMS.isInterned()) {
328 WindowPropertyGetter getter =
329 new WindowPropertyGetter(window, XA_ENLIGHTENMENT_COMMS, 0, 14, false,
330 XAtom.XA_STRING);
331 try {
332 int status = getter.execute(XErrorHandler.IgnoreBadWindowHandler.getInstance());
333 if (status != XConstants.Success || getter.getData() == 0) {
334 return 0;
335 }
336
337 if (getter.getActualType() != XAtom.XA_STRING
338 || getter.getActualFormat() != 8
339 || getter.getNumberOfItems() != 14 || getter.getBytesAfter() != 0)
340 {
341 return 0;
342 }
343
344 // Convert data to String, ASCII
345 byte[] bytes = XlibWrapper.getStringBytes(getter.getData());
346 String id = new String(bytes);
347
348 if (log.isLoggable(PlatformLogger.FINER)) {
349 log.finer("ENLIGHTENMENT_COMMS is " + id);
350 }
351
352 // Parse WINID
353 Pattern winIdPat = Pattern.compile("WINID\\s+(\\p{XDigit}{0,8})");
354 try {
355 Matcher match = winIdPat.matcher(id);
356 if (match.matches()) {
357 if (log.isLoggable(PlatformLogger.FINEST)) {
358 log.finest("Match group count: " + match.groupCount());
359 }
360 String longId = match.group(1);
361 if (log.isLoggable(PlatformLogger.FINEST)) {
362 log.finest("Match group 1 " + longId);
363 }
364 long winid = Long.parseLong(longId, 16);
365 if (log.isLoggable(PlatformLogger.FINER)) {
366 log.finer("Enlightenment communication window " + winid);
367 }
368 return winid;
369 } else {
370 log.finer("ENLIGHTENMENT_COMMS has wrong format");
371 return 0;
372 }
373 } catch (Exception e) {
374 if (log.isLoggable(PlatformLogger.FINER)) {
375 e.printStackTrace();
376 }
377 return 0;
378 }
379 } finally {
380 getter.dispose();
381 }
382 }
383
384 /*
385 * Is Enlightenment WM running? Congruent to awt_wm_checkAnchor, but
386 * uses STRING property peculiar to Enlightenment.
387 */
647
648 /*
649 * Is IceWM running?
650 *
651 * Note well: Only call this if awt_wm_prepareIsIceWM succeeded, or a
652 * false positive will be reported.
653 */
654 static boolean isIceWM() {
655 if (!XA_ICEWM_WINOPTHINT.isInterned()) {
656 log.finer("{0} is not interned", XA_ICEWM_WINOPTHINT);
657 return false;
658 }
659
660 WindowPropertyGetter getter =
661 new WindowPropertyGetter(XToolkit.getDefaultRootWindow(),
662 XA_ICEWM_WINOPTHINT, 0, 0xFFFF,
663 true, XA_ICEWM_WINOPTHINT);
664 try {
665 int status = getter.execute();
666 boolean res = (status == XConstants.Success && getter.getActualType() != 0);
667 if (log.isLoggable(PlatformLogger.FINER)) {
668 log.finer("Status getting XA_ICEWM_WINOPTHINT: " + !res);
669 }
670 return !res || isNetWMName("IceWM");
671 } finally {
672 getter.dispose();
673 }
674 }
675
676 /*
677 * Is OpenLook WM running?
678 *
679 * This one is pretty lame, but the only property peculiar to OLWM is
680 * _SUN_WM_PROTOCOLS(ATOM[]). Fortunately, olwm deletes it on exit.
681 */
682 static final XAtom XA_SUN_WM_PROTOCOLS = new XAtom("_SUN_WM_PROTOCOLS", false);
683 static boolean isOpenLook() {
684 if (!XA_SUN_WM_PROTOCOLS.isInterned()) {
685 return false;
686 }
687
688 XAtom[] list = XA_SUN_WM_PROTOCOLS.getAtomListProperty(XToolkit.getDefaultRootWindow());
689 return (list.length != 0);
811 * Size and decoration hints ...
812 *
813 \*****************************************************************************/
814
815
816 /*
817 * Remove size hints specified by the mask.
818 * XXX: Why do we need this in the first place???
819 */
820 static void removeSizeHints(XDecoratedPeer window, long mask) {
821 mask &= XUtilConstants.PMaxSize | XUtilConstants.PMinSize;
822
823 XToolkit.awtLock();
824 try {
825 XSizeHints hints = window.getHints();
826 if ((hints.get_flags() & mask) == 0) {
827 return;
828 }
829
830 hints.set_flags(hints.get_flags() & ~mask);
831 if (insLog.isLoggable(PlatformLogger.FINER)) {
832 insLog.finer("Setting hints, flags " + XlibWrapper.hintsToString(hints.get_flags()));
833 }
834 XlibWrapper.XSetWMNormalHints(XToolkit.getDisplay(),
835 window.getWindow(),
836 hints.pData);
837 } finally {
838 XToolkit.awtUnlock();
839 }
840 }
841
842 /*
843 * If MWM_DECOR_ALL bit is set, then the rest of the bit-mask is taken
844 * to be subtracted from the decorations. Normalize decoration spec
845 * so that we can map motif decor to something else bit-by-bit in the
846 * rest of the code.
847 */
848 static int normalizeMotifDecor(int decorations) {
849 if ((decorations & MWMConstants.MWM_DECOR_ALL) == 0) {
850 return decorations;
851 }
852 int d = MWMConstants.MWM_DECOR_BORDER | MWMConstants.MWM_DECOR_RESIZEH
853 | MWMConstants.MWM_DECOR_TITLE
870 int f = MWMConstants.MWM_FUNC_RESIZE |
871 MWMConstants.MWM_FUNC_MOVE |
872 MWMConstants.MWM_FUNC_MAXIMIZE |
873 MWMConstants.MWM_FUNC_MINIMIZE |
874 MWMConstants.MWM_FUNC_CLOSE;
875 f &= ~functions;
876 return f;
877 }
878
879 /*
880 * Infer OL properties from MWM decorations.
881 * Use _OL_DECOR_DEL(ATOM[]) to remove unwanted ones.
882 */
883 static void setOLDecor(XWindow window, boolean resizable, int decorations) {
884 if (window == null) {
885 return;
886 }
887
888 XAtomList decorDel = new XAtomList();
889 decorations = normalizeMotifDecor(decorations);
890 if (insLog.isLoggable(PlatformLogger.FINER)) {
891 insLog.finer("Setting OL_DECOR to " + Integer.toBinaryString(decorations));
892 }
893 if ((decorations & MWMConstants.MWM_DECOR_TITLE) == 0) {
894 decorDel.add(XA_OL_DECOR_HEADER);
895 }
896 if ((decorations & (MWMConstants.MWM_DECOR_RESIZEH | MWMConstants.MWM_DECOR_MAXIMIZE)) == 0) {
897 decorDel.add(XA_OL_DECOR_RESIZE);
898 }
899 if ((decorations & (MWMConstants.MWM_DECOR_MENU |
900 MWMConstants.MWM_DECOR_MAXIMIZE |
901 MWMConstants.MWM_DECOR_MINIMIZE)) == 0)
902 {
903 decorDel.add(XA_OL_DECOR_CLOSE);
904 }
905 if (decorDel.size() == 0) {
906 insLog.finer("Deleting OL_DECOR");
907 XA_OL_DECOR_DEL.DeleteProperty(window);
908 } else {
909 if (insLog.isLoggable(PlatformLogger.FINER)) {
910 insLog.finer("Setting OL_DECOR to " + decorDel);
911 }
912 XA_OL_DECOR_DEL.setAtomListProperty(window, decorDel);
913 }
914 }
915
916 /*
917 * Set MWM decorations. Set MWM functions depending on resizability.
918 */
919 static void setMotifDecor(XWindow window, boolean resizable, int decorations, int functions) {
920 /* Apparently some WMs don't implement MWM_*_ALL semantic correctly */
921 if ((decorations & MWMConstants.MWM_DECOR_ALL) != 0
922 && (decorations != MWMConstants.MWM_DECOR_ALL))
923 {
924 decorations = normalizeMotifDecor(decorations);
925 }
926 if ((functions & MWMConstants.MWM_FUNC_ALL) != 0
927 && (functions != MWMConstants.MWM_FUNC_ALL))
928 {
929 functions = normalizeMotifFunc(functions);
930 }
931
932 PropMwmHints hints = window.getMWMHints();
933 hints.set_flags(hints.get_flags() |
934 MWMConstants.MWM_HINTS_FUNCTIONS |
935 MWMConstants.MWM_HINTS_DECORATIONS);
936 hints.set_functions(functions);
937 hints.set_decorations(decorations);
938
939 if (stateLog.isLoggable(PlatformLogger.FINER)) {
940 stateLog.finer("Setting MWM_HINTS to " + hints);
941 }
942 window.setMWMHints(hints);
943 }
944
945 /*
946 * Under some window managers if shell is already mapped, we MUST
947 * unmap and later remap in order to effect the changes we make in the
948 * window manager decorations.
949 *
950 * N.B. This unmapping / remapping of the shell exposes a bug in
951 * X/Motif or the Motif Window Manager. When you attempt to map a
952 * widget which is positioned (partially) off-screen, the window is
953 * relocated to be entirely on screen. Good idea. But if both the x
954 * and the y coordinates are less than the origin (0,0), the first
955 * (re)map will move the window to the origin, and any subsequent
956 * (re)map will relocate the window at some other point on the screen.
957 * I have written a short Motif test program to discover this bug.
958 * This should occur infrequently and it does not cause any real
959 * problem. So for now we'll let it be.
960 */
961 static boolean needRemap(XDecoratedPeer window) {
983 setMotifDecor(window, resizable, decorations, functions);
984 setOLDecor(window, resizable, decorations);
985
986 /* Some WMs need remap to redecorate the window */
987 if (window.isShowing() && needRemap(window)) {
988 /*
989 * Do the re/mapping at the Xlib level. Since we essentially
990 * work around a WM bug we don't want this hack to be exposed
991 * to Intrinsics (i.e. don't mess with grabs, callbacks etc).
992 */
993 window.xSetVisible(false);
994 XToolkit.XSync();
995 window.xSetVisible(true);
996 }
997 }
998
999 /*
1000 * Make specified shell resizable.
1001 */
1002 static void setShellResizable(XDecoratedPeer window) {
1003 if (insLog.isLoggable(PlatformLogger.FINE)) {
1004 insLog.fine("Setting shell resizable " + window);
1005 }
1006 XToolkit.awtLock();
1007 try {
1008 Rectangle shellBounds = window.getShellBounds();
1009 shellBounds.translate(-window.currentInsets.left, -window.currentInsets.top);
1010 window.updateSizeHints(window.getDimensions());
1011 requestWMExtents(window.getWindow());
1012 XlibWrapper.XMoveResizeWindow(XToolkit.getDisplay(), window.getShell(),
1013 shellBounds.x, shellBounds.y, shellBounds.width, shellBounds.height);
1014 /* REMINDER: will need to revisit when setExtendedStateBounds is added */
1015 //Fix for 4320050: Minimum size for java.awt.Frame is not being enforced.
1016 //We need to update frame's minimum size, not to reset it
1017 removeSizeHints(window, XUtilConstants.PMaxSize);
1018 window.updateMinimumSize();
1019
1020 /* Restore decorations */
1021 setShellDecor(window);
1022 } finally {
1023 XToolkit.awtUnlock();
1024 }
1025 }
1026
1027 /*
1028 * Make specified shell non-resizable.
1029 * If justChangeSize is false, update decorations as well.
1030 * @param shellBounds bounds of the shell window
1031 */
1032 static void setShellNotResizable(XDecoratedPeer window, WindowDimensions newDimensions, Rectangle shellBounds,
1033 boolean justChangeSize)
1034 {
1035 if (insLog.isLoggable(PlatformLogger.FINE)) {
1036 insLog.fine("Setting non-resizable shell " + window + ", dimensions " + newDimensions +
1037 ", shellBounds " + shellBounds +", just change size: " + justChangeSize);
1038 }
1039 XToolkit.awtLock();
1040 try {
1041 /* Fix min/max size hints at the specified values */
1042 if (!shellBounds.isEmpty()) {
1043 window.updateSizeHints(newDimensions);
1044 requestWMExtents(window.getWindow());
1045 XToolkit.XSync();
1046 XlibWrapper.XMoveResizeWindow(XToolkit.getDisplay(), window.getShell(),
1047 shellBounds.x, shellBounds.y, shellBounds.width, shellBounds.height);
1048 }
1049 if (!justChangeSize) { /* update decorations */
1050 setShellDecor(window);
1051 }
1052 } finally {
1053 XToolkit.awtUnlock();
1054 }
1055 }
1056
1057 /*****************************************************************************\
1058 * Protocols support
1149 *
1150 * Notice window state change when WM changes a property on the window ...
1151 *
1152 \*****************************************************************************/
1153
1154
1155 /*
1156 * Check if property change is a window state protocol message.
1157 */
1158 boolean isStateChange(XDecoratedPeer window, XPropertyEvent e) {
1159 if (!window.isShowing()) {
1160 stateLog.finer("Window is not showing");
1161 return false;
1162 }
1163
1164 int wm_state = window.getWMState();
1165 if (wm_state == XUtilConstants.WithdrawnState) {
1166 stateLog.finer("WithdrawnState");
1167 return false;
1168 } else {
1169 if (stateLog.isLoggable(PlatformLogger.FINER)) {
1170 stateLog.finer("Window WM_STATE is " + wm_state);
1171 }
1172 }
1173 boolean is_state_change = false;
1174 if (e.get_atom() == XA_WM_STATE.getAtom()) {
1175 is_state_change = true;
1176 }
1177
1178 for (XStateProtocol proto : getProtocols(XStateProtocol.class)) {
1179 is_state_change |= proto.isStateChange(e);
1180 if (stateLog.isLoggable(PlatformLogger.FINEST)) {
1181 stateLog.finest(proto + ": is state changed = " + is_state_change);
1182 }
1183 }
1184 return is_state_change;
1185 }
1186
1187 /*
1188 * Returns current state (including extended) of a given window.
1189 */
1190 int getState(XDecoratedPeer window) {
1191 int res = 0;
1192 final int wm_state = window.getWMState();
1193 if (wm_state == XUtilConstants.IconicState) {
1194 res = Frame.ICONIFIED;
1195 } else {
1196 res = Frame.NORMAL;
1197 }
1198 res |= getExtendedState(window);
1199 return res;
1200 }
1201
1202 /*****************************************************************************\
1203 *
1314 Insets guessInsets(XDecoratedPeer window) {
1315 Insets res = (Insets)storedInsets.get(window.getClass());
1316 if (res == null) {
1317 switch (WMID) {
1318 case ENLIGHTEN_WM:
1319 res = new Insets(19, 4, 4, 4);
1320 break;
1321 case CDE_WM:
1322 res = new Insets(28, 6, 6, 6);
1323 break;
1324 case NO_WM:
1325 case LG3D_WM:
1326 res = zeroInsets;
1327 break;
1328 case MOTIF_WM:
1329 case OPENLOOK_WM:
1330 default:
1331 res = defaultInsets;
1332 }
1333 }
1334 if (insLog.isLoggable(PlatformLogger.FINEST)) {
1335 insLog.finest("WM guessed insets: " + res);
1336 }
1337 return res;
1338 }
1339 /*
1340 * Some buggy WMs ignore window gravity when processing
1341 * ConfigureRequest and position window as if the gravity is Static.
1342 * We work around this in MWindowPeer.pReshape().
1343 *
1344 * Starting with 1.5 we have introduced an Environment variable
1345 * _JAVA_AWT_WM_STATIC_GRAVITY that can be set to indicate to Java
1346 * explicitly that the WM has this behaviour, example is FVWM.
1347 */
1348
1349 static int awtWMStaticGravity = -1;
1350 static boolean configureGravityBuggy() {
1351
1352 if (awtWMStaticGravity == -1) {
1353 awtWMStaticGravity = (XToolkit.getEnv("_JAVA_AWT_WM_STATIC_GRAVITY") != null) ? 1 : 0;
1354 }
1355
1356 if (awtWMStaticGravity == 1) {
|