40 import java.awt.im.InputMethodHighlight;
41 import java.awt.im.spi.InputMethodDescriptor;
42 import java.awt.image.ColorModel;
43 import java.awt.peer.*;
44 import java.beans.PropertyChangeListener;
45 import java.security.AccessController;
46 import java.security.PrivilegedAction;
47 import java.util.*;
48 import javax.swing.LookAndFeel;
49 import javax.swing.UIDefaults;
50 import sun.awt.*;
51 import sun.awt.datatransfer.DataTransferer;
52 import sun.font.FontConfigManager;
53 import sun.java2d.SunGraphicsEnvironment;
54 import sun.misc.*;
55 import sun.awt.util.ThreadGroupUtils;
56 import sun.print.PrintJob2D;
57 import sun.security.action.GetPropertyAction;
58 import sun.security.action.GetBooleanAction;
59 import sun.util.logging.PlatformLogger;
60
61 public final class XToolkit extends UNIXToolkit implements Runnable {
62 private static final PlatformLogger log = PlatformLogger.getLogger("sun.awt.X11.XToolkit");
63 private static final PlatformLogger eventLog = PlatformLogger.getLogger("sun.awt.X11.event.XToolkit");
64 private static final PlatformLogger timeoutTaskLog = PlatformLogger.getLogger("sun.awt.X11.timeoutTask.XToolkit");
65 private static final PlatformLogger keyEventLog = PlatformLogger.getLogger("sun.awt.X11.kye.XToolkit");
66 private static final PlatformLogger backingStoreLog = PlatformLogger.getLogger("sun.awt.X11.backingStore.XToolkit");
67
68 //There is 400 ms is set by default on Windows and 500 by default on KDE and GNOME.
69 //We use the same hardcoded constant.
70 private static final int AWT_MULTICLICK_DEFAULT_TIME = 500;
71
72 static final boolean PRIMARY_LOOP = false;
73 static final boolean SECONDARY_LOOP = true;
74
75 private static String awtAppClassName = null;
76
77 // the system clipboard - CLIPBOARD selection
78 XClipboard clipboard;
79 // the system selection - PRIMARY selection
405 /**
406 * Returns whether there is last remembered cursor position. The
407 * position is remembered from X mouse events on our peers. The
408 * position is stored in <code>p</code>.
409 * @return true, if there is remembered last cursor position,
410 * false otherwise
411 */
412 boolean getLastCursorPos(Point p) {
413 awtLock();
414 try {
415 if (lastCursorPos == null) {
416 return false;
417 }
418 p.setLocation(lastCursorPos);
419 return true;
420 } finally {
421 awtUnlock();
422 }
423 }
424
425 private void processGlobalMotionEvent(XEvent e) {
426 // Only our windows guaranteely generate MotionNotify, so we
427 // should track enter/leave, to catch the moment when to
428 // switch to XQueryPointer
429 if (e.get_type() == XConstants.MotionNotify) {
430 XMotionEvent ev = e.get_xmotion();
431 awtLock();
432 try {
433 if (lastCursorPos == null) {
434 lastCursorPos = new Point(ev.get_x_root(), ev.get_y_root());
435 } else {
436 lastCursorPos.setLocation(ev.get_x_root(), ev.get_y_root());
437 }
438 } finally {
439 awtUnlock();
440 }
441 } else if (e.get_type() == XConstants.LeaveNotify) {
442 // Leave from our window
443 awtLock();
444 try {
445 lastCursorPos = null;
446 } finally {
447 awtUnlock();
448 }
449 } else if (e.get_type() == XConstants.EnterNotify) {
450 // Entrance into our window
451 XCrossingEvent ev = e.get_xcrossing();
452 awtLock();
453 try {
454 if (lastCursorPos == null) {
455 lastCursorPos = new Point(ev.get_x_root(), ev.get_y_root());
456 } else {
457 lastCursorPos.setLocation(ev.get_x_root(), ev.get_y_root());
458 }
459 } finally {
460 awtUnlock();
461 }
462 }
463 }
464
465 public interface XEventListener {
466 public void eventProcessed(XEvent e);
467 }
468
469 private Collection<XEventListener> listeners = new LinkedList<XEventListener>();
470
471 public void addXEventListener(XEventListener listener) {
472 synchronized (listeners) {
473 listeners.add(listener);
474 }
475 }
476
477 private void notifyListeners(XEvent xev) {
478 synchronized (listeners) {
479 if (listeners.size() == 0) return;
480
481 XEvent copy = xev.clone();
482 try {
483 for (XEventListener listener : listeners) {
484 listener.eventProcessed(copy);
485 }
486 } finally {
487 copy.dispose();
488 }
489 }
490 }
491
492 private void dispatchEvent(XEvent ev) {
493 final XAnyEvent xany = ev.get_xany();
494
495 if (windowToXWindow(xany.get_window()) != null &&
496 (ev.get_type() == XConstants.MotionNotify || ev.get_type() == XConstants.EnterNotify || ev.get_type() == XConstants.LeaveNotify))
497 {
498 processGlobalMotionEvent(ev);
499 }
500
501 if( ev.get_type() == XConstants.MappingNotify ) {
502 // The 'window' field in this event is unused.
503 // This application itself does nothing to initiate such an event
504 // (no calls of XChangeKeyboardMapping etc.).
505 // SunRay server sends this event to the application once on every
506 // keyboard (not just layout) change which means, quite seldom.
507 XlibWrapper.XRefreshKeyboardMapping(ev.pData);
508 resetKeyboardSniffer();
509 setupModifierMap();
510 }
511 XBaseWindow.dispatchToWindow(ev);
512
513 Collection<XEventDispatcher> dispatchers = null;
514 synchronized(winToDispatcher) {
515 Long key = Long.valueOf(xany.get_window());
516 dispatchers = winToDispatcher.get(key);
517 if (dispatchers != null) { // Clone it to avoid synchronization during dispatching
518 dispatchers = new Vector<>(dispatchers);
653 }
654 };
655
656 static {
657 GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
658 if (ge instanceof SunGraphicsEnvironment) {
659 ((SunGraphicsEnvironment) ge).addDisplayChangedListener(
660 displayChangedHandler);
661 }
662 }
663
664 private static void initScreenSize() {
665 if (screenWidth == -1 || screenHeight == -1) {
666 awtLock();
667 try {
668 XWindowAttributes pattr = new XWindowAttributes();
669 try {
670 XlibWrapper.XGetWindowAttributes(XToolkit.getDisplay(),
671 XToolkit.getDefaultRootWindow(),
672 pattr.pData);
673 screenWidth = pattr.get_width();
674 screenHeight = pattr.get_height();
675 } finally {
676 pattr.dispose();
677 }
678 } finally {
679 awtUnlock();
680 }
681 }
682 }
683
684 static int getDefaultScreenWidth() {
685 initScreenSize();
686 return screenWidth;
687 }
688
689 static int getDefaultScreenHeight() {
690 initScreenSize();
691 return screenHeight;
692 }
693
694 @Override
695 protected int getScreenWidth() {
696 return getDefaultScreenWidth();
697 }
698
699 @Override
700 protected int getScreenHeight() {
701 return getDefaultScreenHeight();
702 }
703
704 private static Rectangle getWorkArea(long root)
705 {
706 XAtom XA_NET_WORKAREA = XAtom.get("_NET_WORKAREA");
707
708 long native_ptr = Native.allocateLongArray(4);
709 try
710 {
711 boolean workareaPresent = XA_NET_WORKAREA.getAtomData(root,
712 XAtom.XA_CARDINAL, native_ptr, 4);
713 if (workareaPresent)
714 {
715 int rootX = (int)Native.getLong(native_ptr, 0);
716 int rootY = (int)Native.getLong(native_ptr, 1);
717 int rootWidth = (int)Native.getLong(native_ptr, 2);
718 int rootHeight = (int)Native.getLong(native_ptr, 3);
719
720 return new Rectangle(rootX, rootY, rootWidth, rootHeight);
721 }
722 }
723 finally
724 {
725 XlibWrapper.unsafe.freeMemory(native_ptr);
726 }
727
728 return null;
729 }
730
731 /*
732 * If we're running in non-Xinerama environment and the current
733 * window manager supports _NET protocol then the screen insets
734 * are calculated using _NET_WM_WORKAREA property of the root
735 * window.
736 * Otherwise, i. e. if Xinerama is on or _NET_WM_WORKAREA is
737 * not set, we try to calculate the insets ourselves using
738 * getScreenInsetsManually method.
739 */
740 @Override
741 public Insets getScreenInsets(GraphicsConfiguration gc)
742 {
743 XNETProtocol netProto = XWM.getWM().getNETProtocol();
744 if ((netProto == null) || !netProto.active())
745 {
746 return super.getScreenInsets(gc);
747 }
748
749 XToolkit.awtLock();
750 try
751 {
752 X11GraphicsConfig x11gc = (X11GraphicsConfig)gc;
753 X11GraphicsDevice x11gd = (X11GraphicsDevice)x11gc.getDevice();
754 long root = XlibUtil.getRootWindow(x11gd.getScreen());
755 Rectangle rootBounds = XlibUtil.getWindowGeometry(root);
756
757 X11GraphicsEnvironment x11ge = (X11GraphicsEnvironment)
758 GraphicsEnvironment.getLocalGraphicsEnvironment();
759 if (!x11ge.runningXinerama())
760 {
761 Rectangle workArea = XToolkit.getWorkArea(root);
762 if (workArea != null)
763 {
764 return new Insets(workArea.y,
765 workArea.x,
766 rootBounds.height - workArea.height - workArea.y,
767 rootBounds.width - workArea.width - workArea.x);
768 }
769 }
770
771 return getScreenInsetsManually(root, rootBounds, gc.getBounds());
772 }
773 finally
774 {
775 XToolkit.awtUnlock();
776 }
777 }
778
779 /*
780 * Manual calculation of screen insets: get all the windows with
781 * _NET_WM_STRUT/_NET_WM_STRUT_PARTIAL hints and add these
782 * hints' values to screen insets.
783 *
784 * This method should be called under XToolkit.awtLock()
785 */
786 private Insets getScreenInsetsManually(long root, Rectangle rootBounds, Rectangle screenBounds)
787 {
788 /*
789 * During the manual calculation of screen insets we iterate
790 * all the X windows hierarchy starting from root window. This
791 * constant is the max level inspected in this hierarchy.
792 * 3 is a heuristic value: I suppose any the toolbar-like
793 * window is a child of either root or desktop window.
794 */
795 final int MAX_NESTED_LEVEL = 3;
796
797 XAtom XA_NET_WM_STRUT = XAtom.get("_NET_WM_STRUT");
798 XAtom XA_NET_WM_STRUT_PARTIAL = XAtom.get("_NET_WM_STRUT_PARTIAL");
799
800 Insets insets = new Insets(0, 0, 0, 0);
801
802 java.util.List<Object> search = new LinkedList<>();
803 search.add(root);
804 search.add(0);
805 while (!search.isEmpty())
806 {
814 * are not included to the screen insets.
815 */
816 if (XlibUtil.getWindowMapState(window) == XConstants.IsUnmapped)
817 {
818 continue;
819 }
820
821 long native_ptr = Native.allocateLongArray(4);
822 try
823 {
824 // first, check if _NET_WM_STRUT or _NET_WM_STRUT_PARTIAL are present
825 // if both are set on the window, _NET_WM_STRUT_PARTIAL is used (see _NET spec)
826 boolean strutPresent = XA_NET_WM_STRUT_PARTIAL.getAtomData(window, XAtom.XA_CARDINAL, native_ptr, 4);
827 if (!strutPresent)
828 {
829 strutPresent = XA_NET_WM_STRUT.getAtomData(window, XAtom.XA_CARDINAL, native_ptr, 4);
830 }
831 if (strutPresent)
832 {
833 // second, verify that window is located on the proper screen
834 Rectangle windowBounds = XlibUtil.getWindowGeometry(window);
835 if (windowLevel > 1)
836 {
837 windowBounds = XlibUtil.translateCoordinates(window, root, windowBounds);
838 }
839 // if _NET_WM_STRUT_PARTIAL is present, we should use its values to detect
840 // if the struts area intersects with screenBounds, however some window
841 // managers don't set this hint correctly, so we just get intersection with windowBounds
842 if (windowBounds != null && windowBounds.intersects(screenBounds))
843 {
844 int left = (int)Native.getLong(native_ptr, 0);
845 int right = (int)Native.getLong(native_ptr, 1);
846 int top = (int)Native.getLong(native_ptr, 2);
847 int bottom = (int)Native.getLong(native_ptr, 3);
848
849 /*
850 * struts could be relative to root window bounds, so
851 * make them relative to the screen bounds in this case
852 */
853 left = rootBounds.x + left > screenBounds.x ?
854 rootBounds.x + left - screenBounds.x : 0;
855 right = rootBounds.x + rootBounds.width - right <
856 screenBounds.x + screenBounds.width ?
857 screenBounds.x + screenBounds.width -
858 (rootBounds.x + rootBounds.width - right) : 0;
859 top = rootBounds.y + top > screenBounds.y ?
860 rootBounds.y + top - screenBounds.y : 0;
861 bottom = rootBounds.y + rootBounds.height - bottom <
862 screenBounds.y + screenBounds.height ?
863 screenBounds.y + screenBounds.height -
864 (rootBounds.y + rootBounds.height - bottom) : 0;
865
866 insets.left = Math.max(left, insets.left);
867 insets.right = Math.max(right, insets.right);
2470 if (oops_waiter == null) {
2471 oops_waiter = new XEventDispatcher() {
2472 @Override
2473 public void dispatchEvent(XEvent e) {
2474 if (e.get_type() == XConstants.ConfigureNotify) {
2475 // OOPS ConfigureNotify event catched
2476 oops_updated = true;
2477 awtLockNotifyAll();
2478 }
2479 }
2480 };
2481 }
2482
2483 awtLock();
2484 try {
2485 addEventDispatcher(win.getWindow(), oops_waiter);
2486
2487 oops_updated = false;
2488 long event_number = getEventNumber();
2489 // Generate OOPS ConfigureNotify event
2490 XlibWrapper.XMoveWindow(getDisplay(), win.getWindow(), ++oops_position, 0);
2491 // Change win position each time to avoid system optimization
2492 if (oops_position > 50) {
2493 oops_position = 0;
2494 }
2495
2496 XSync();
2497
2498 eventLog.finer("Generated OOPS ConfigureNotify event");
2499
2500 long start = System.currentTimeMillis();
2501 while (!oops_updated) {
2502 try {
2503 // Wait for OOPS ConfigureNotify event
2504 awtLockWait(timeout);
2505 } catch (InterruptedException e) {
2506 throw new RuntimeException(e);
2507 }
2508 // This "while" is a protection from spurious
2509 // wake-ups. However, we shouldn't wait for too long
2510 if ((System.currentTimeMillis() - start > timeout) && timeout >= 0) {
|
40 import java.awt.im.InputMethodHighlight;
41 import java.awt.im.spi.InputMethodDescriptor;
42 import java.awt.image.ColorModel;
43 import java.awt.peer.*;
44 import java.beans.PropertyChangeListener;
45 import java.security.AccessController;
46 import java.security.PrivilegedAction;
47 import java.util.*;
48 import javax.swing.LookAndFeel;
49 import javax.swing.UIDefaults;
50 import sun.awt.*;
51 import sun.awt.datatransfer.DataTransferer;
52 import sun.font.FontConfigManager;
53 import sun.java2d.SunGraphicsEnvironment;
54 import sun.misc.*;
55 import sun.awt.util.ThreadGroupUtils;
56 import sun.print.PrintJob2D;
57 import sun.security.action.GetPropertyAction;
58 import sun.security.action.GetBooleanAction;
59 import sun.util.logging.PlatformLogger;
60 import static sun.awt.X11.XlibUtil.scaleDown;
61
62 public final class XToolkit extends UNIXToolkit implements Runnable {
63 private static final PlatformLogger log = PlatformLogger.getLogger("sun.awt.X11.XToolkit");
64 private static final PlatformLogger eventLog = PlatformLogger.getLogger("sun.awt.X11.event.XToolkit");
65 private static final PlatformLogger timeoutTaskLog = PlatformLogger.getLogger("sun.awt.X11.timeoutTask.XToolkit");
66 private static final PlatformLogger keyEventLog = PlatformLogger.getLogger("sun.awt.X11.kye.XToolkit");
67 private static final PlatformLogger backingStoreLog = PlatformLogger.getLogger("sun.awt.X11.backingStore.XToolkit");
68
69 //There is 400 ms is set by default on Windows and 500 by default on KDE and GNOME.
70 //We use the same hardcoded constant.
71 private static final int AWT_MULTICLICK_DEFAULT_TIME = 500;
72
73 static final boolean PRIMARY_LOOP = false;
74 static final boolean SECONDARY_LOOP = true;
75
76 private static String awtAppClassName = null;
77
78 // the system clipboard - CLIPBOARD selection
79 XClipboard clipboard;
80 // the system selection - PRIMARY selection
406 /**
407 * Returns whether there is last remembered cursor position. The
408 * position is remembered from X mouse events on our peers. The
409 * position is stored in <code>p</code>.
410 * @return true, if there is remembered last cursor position,
411 * false otherwise
412 */
413 boolean getLastCursorPos(Point p) {
414 awtLock();
415 try {
416 if (lastCursorPos == null) {
417 return false;
418 }
419 p.setLocation(lastCursorPos);
420 return true;
421 } finally {
422 awtUnlock();
423 }
424 }
425
426 private void processGlobalMotionEvent(XEvent e, XBaseWindow win) {
427 // Only our windows guaranteely generate MotionNotify, so we
428 // should track enter/leave, to catch the moment when to
429 // switch to XQueryPointer
430 if (e.get_type() == XConstants.MotionNotify) {
431 XMotionEvent ev = e.get_xmotion();
432 awtLock();
433 try {
434 if (lastCursorPos == null) {
435 lastCursorPos = new Point(win.scaleDown(ev.get_x_root()),
436 win.scaleDown(ev.get_y_root()));
437 } else {
438 lastCursorPos.setLocation(win.scaleDown(ev.get_x_root()),
439 win.scaleDown(ev.get_y_root()));
440 }
441 } finally {
442 awtUnlock();
443 }
444 } else if (e.get_type() == XConstants.LeaveNotify) {
445 // Leave from our window
446 awtLock();
447 try {
448 lastCursorPos = null;
449 } finally {
450 awtUnlock();
451 }
452 } else if (e.get_type() == XConstants.EnterNotify) {
453 // Entrance into our window
454 XCrossingEvent ev = e.get_xcrossing();
455 awtLock();
456 try {
457 if (lastCursorPos == null) {
458 lastCursorPos = new Point(win.scaleDown(ev.get_x_root()),
459 win.scaleDown(ev.get_y_root()));
460 } else {
461 lastCursorPos.setLocation(win.scaleDown(ev.get_x_root()),
462 win.scaleDown(ev.get_y_root()));
463 }
464 } finally {
465 awtUnlock();
466 }
467 }
468 }
469
470 public interface XEventListener {
471 public void eventProcessed(XEvent e);
472 }
473
474 private Collection<XEventListener> listeners = new LinkedList<XEventListener>();
475
476 public void addXEventListener(XEventListener listener) {
477 synchronized (listeners) {
478 listeners.add(listener);
479 }
480 }
481
482 private void notifyListeners(XEvent xev) {
483 synchronized (listeners) {
484 if (listeners.size() == 0) return;
485
486 XEvent copy = xev.clone();
487 try {
488 for (XEventListener listener : listeners) {
489 listener.eventProcessed(copy);
490 }
491 } finally {
492 copy.dispose();
493 }
494 }
495 }
496
497 private void dispatchEvent(XEvent ev) {
498 final XAnyEvent xany = ev.get_xany();
499
500 XBaseWindow baseWindow = windowToXWindow(xany.get_window());
501 if (baseWindow != null && (ev.get_type() == XConstants.MotionNotify
502 || ev.get_type() == XConstants.EnterNotify
503 || ev.get_type() == XConstants.LeaveNotify)) {
504 processGlobalMotionEvent(ev, baseWindow);
505 }
506
507 if( ev.get_type() == XConstants.MappingNotify ) {
508 // The 'window' field in this event is unused.
509 // This application itself does nothing to initiate such an event
510 // (no calls of XChangeKeyboardMapping etc.).
511 // SunRay server sends this event to the application once on every
512 // keyboard (not just layout) change which means, quite seldom.
513 XlibWrapper.XRefreshKeyboardMapping(ev.pData);
514 resetKeyboardSniffer();
515 setupModifierMap();
516 }
517 XBaseWindow.dispatchToWindow(ev);
518
519 Collection<XEventDispatcher> dispatchers = null;
520 synchronized(winToDispatcher) {
521 Long key = Long.valueOf(xany.get_window());
522 dispatchers = winToDispatcher.get(key);
523 if (dispatchers != null) { // Clone it to avoid synchronization during dispatching
524 dispatchers = new Vector<>(dispatchers);
659 }
660 };
661
662 static {
663 GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
664 if (ge instanceof SunGraphicsEnvironment) {
665 ((SunGraphicsEnvironment) ge).addDisplayChangedListener(
666 displayChangedHandler);
667 }
668 }
669
670 private static void initScreenSize() {
671 if (screenWidth == -1 || screenHeight == -1) {
672 awtLock();
673 try {
674 XWindowAttributes pattr = new XWindowAttributes();
675 try {
676 XlibWrapper.XGetWindowAttributes(XToolkit.getDisplay(),
677 XToolkit.getDefaultRootWindow(),
678 pattr.pData);
679 screenWidth = config.scaleDown(pattr.get_width());
680 screenHeight = config.scaleDown(pattr.get_height());
681 } finally {
682 pattr.dispose();
683 }
684 } finally {
685 awtUnlock();
686 }
687 }
688 }
689
690 static int getDefaultScreenWidth() {
691 initScreenSize();
692 return screenWidth;
693 }
694
695 static int getDefaultScreenHeight() {
696 initScreenSize();
697 return screenHeight;
698 }
699
700 @Override
701 protected int getScreenWidth() {
702 return getDefaultScreenWidth();
703 }
704
705 @Override
706 protected int getScreenHeight() {
707 return getDefaultScreenHeight();
708 }
709
710 private static Rectangle getWorkArea(long root, int scale)
711 {
712 XAtom XA_NET_WORKAREA = XAtom.get("_NET_WORKAREA");
713
714 long native_ptr = Native.allocateLongArray(4);
715 try
716 {
717 boolean workareaPresent = XA_NET_WORKAREA.getAtomData(root,
718 XAtom.XA_CARDINAL, native_ptr, 4);
719 if (workareaPresent)
720 {
721 int rootX = (int)Native.getLong(native_ptr, 0);
722 int rootY = (int)Native.getLong(native_ptr, 1);
723 int rootWidth = (int)Native.getLong(native_ptr, 2);
724 int rootHeight = (int)Native.getLong(native_ptr, 3);
725
726 return new Rectangle(scaleDown(rootX, scale),
727 scaleDown(rootY, scale),
728 scaleDown(rootWidth, scale),
729 scaleDown(rootHeight, scale));
730 }
731 }
732 finally
733 {
734 XlibWrapper.unsafe.freeMemory(native_ptr);
735 }
736
737 return null;
738 }
739
740 /*
741 * If we're running in non-Xinerama environment and the current
742 * window manager supports _NET protocol then the screen insets
743 * are calculated using _NET_WM_WORKAREA property of the root
744 * window.
745 * Otherwise, i. e. if Xinerama is on or _NET_WM_WORKAREA is
746 * not set, we try to calculate the insets ourselves using
747 * getScreenInsetsManually method.
748 */
749 @Override
750 public Insets getScreenInsets(GraphicsConfiguration gc)
751 {
752 XNETProtocol netProto = XWM.getWM().getNETProtocol();
753 if ((netProto == null) || !netProto.active())
754 {
755 return super.getScreenInsets(gc);
756 }
757
758 XToolkit.awtLock();
759 try
760 {
761 X11GraphicsConfig x11gc = (X11GraphicsConfig)gc;
762 X11GraphicsDevice x11gd = x11gc.getDevice();
763 long root = XlibUtil.getRootWindow(x11gd.getScreen());
764 int scale = x11gc.getScale();
765 Rectangle rootBounds = XlibUtil.getWindowGeometry(root, scale);
766
767 X11GraphicsEnvironment x11ge = (X11GraphicsEnvironment)
768 GraphicsEnvironment.getLocalGraphicsEnvironment();
769 if (!x11ge.runningXinerama())
770 {
771 Rectangle workArea = XToolkit.getWorkArea(root, scale);
772 if (workArea != null)
773 {
774 return new Insets(workArea.y,
775 workArea.x,
776 rootBounds.height - workArea.height - workArea.y,
777 rootBounds.width - workArea.width - workArea.x);
778 }
779 }
780
781 return getScreenInsetsManually(root, rootBounds, gc.getBounds(), scale);
782 }
783 finally
784 {
785 XToolkit.awtUnlock();
786 }
787 }
788
789 /*
790 * Manual calculation of screen insets: get all the windows with
791 * _NET_WM_STRUT/_NET_WM_STRUT_PARTIAL hints and add these
792 * hints' values to screen insets.
793 *
794 * This method should be called under XToolkit.awtLock()
795 */
796 private Insets getScreenInsetsManually(long root, Rectangle rootBounds,
797 Rectangle screenBounds, int scale)
798 {
799 /*
800 * During the manual calculation of screen insets we iterate
801 * all the X windows hierarchy starting from root window. This
802 * constant is the max level inspected in this hierarchy.
803 * 3 is a heuristic value: I suppose any the toolbar-like
804 * window is a child of either root or desktop window.
805 */
806 final int MAX_NESTED_LEVEL = 3;
807
808 XAtom XA_NET_WM_STRUT = XAtom.get("_NET_WM_STRUT");
809 XAtom XA_NET_WM_STRUT_PARTIAL = XAtom.get("_NET_WM_STRUT_PARTIAL");
810
811 Insets insets = new Insets(0, 0, 0, 0);
812
813 java.util.List<Object> search = new LinkedList<>();
814 search.add(root);
815 search.add(0);
816 while (!search.isEmpty())
817 {
825 * are not included to the screen insets.
826 */
827 if (XlibUtil.getWindowMapState(window) == XConstants.IsUnmapped)
828 {
829 continue;
830 }
831
832 long native_ptr = Native.allocateLongArray(4);
833 try
834 {
835 // first, check if _NET_WM_STRUT or _NET_WM_STRUT_PARTIAL are present
836 // if both are set on the window, _NET_WM_STRUT_PARTIAL is used (see _NET spec)
837 boolean strutPresent = XA_NET_WM_STRUT_PARTIAL.getAtomData(window, XAtom.XA_CARDINAL, native_ptr, 4);
838 if (!strutPresent)
839 {
840 strutPresent = XA_NET_WM_STRUT.getAtomData(window, XAtom.XA_CARDINAL, native_ptr, 4);
841 }
842 if (strutPresent)
843 {
844 // second, verify that window is located on the proper screen
845 Rectangle windowBounds = XlibUtil.getWindowGeometry(window,
846 scale);
847 if (windowLevel > 1)
848 {
849 windowBounds = XlibUtil.translateCoordinates(window, root,
850 windowBounds,
851 scale);
852 }
853 // if _NET_WM_STRUT_PARTIAL is present, we should use its values to detect
854 // if the struts area intersects with screenBounds, however some window
855 // managers don't set this hint correctly, so we just get intersection with windowBounds
856 if (windowBounds != null && windowBounds.intersects(screenBounds))
857 {
858 int left = scaleDown((int)Native.getLong(native_ptr, 0), scale);
859 int right = scaleDown((int)Native.getLong(native_ptr, 1), scale);
860 int top = scaleDown((int)Native.getLong(native_ptr, 2), scale);
861 int bottom = scaleDown((int)Native.getLong(native_ptr, 3), scale);
862
863 /*
864 * struts could be relative to root window bounds, so
865 * make them relative to the screen bounds in this case
866 */
867 left = rootBounds.x + left > screenBounds.x ?
868 rootBounds.x + left - screenBounds.x : 0;
869 right = rootBounds.x + rootBounds.width - right <
870 screenBounds.x + screenBounds.width ?
871 screenBounds.x + screenBounds.width -
872 (rootBounds.x + rootBounds.width - right) : 0;
873 top = rootBounds.y + top > screenBounds.y ?
874 rootBounds.y + top - screenBounds.y : 0;
875 bottom = rootBounds.y + rootBounds.height - bottom <
876 screenBounds.y + screenBounds.height ?
877 screenBounds.y + screenBounds.height -
878 (rootBounds.y + rootBounds.height - bottom) : 0;
879
880 insets.left = Math.max(left, insets.left);
881 insets.right = Math.max(right, insets.right);
2484 if (oops_waiter == null) {
2485 oops_waiter = new XEventDispatcher() {
2486 @Override
2487 public void dispatchEvent(XEvent e) {
2488 if (e.get_type() == XConstants.ConfigureNotify) {
2489 // OOPS ConfigureNotify event catched
2490 oops_updated = true;
2491 awtLockNotifyAll();
2492 }
2493 }
2494 };
2495 }
2496
2497 awtLock();
2498 try {
2499 addEventDispatcher(win.getWindow(), oops_waiter);
2500
2501 oops_updated = false;
2502 long event_number = getEventNumber();
2503 // Generate OOPS ConfigureNotify event
2504 XlibWrapper.XMoveWindow(getDisplay(), win.getWindow(),
2505 win.scaleUp(++oops_position), 0);
2506 // Change win position each time to avoid system optimization
2507 if (oops_position > 50) {
2508 oops_position = 0;
2509 }
2510
2511 XSync();
2512
2513 eventLog.finer("Generated OOPS ConfigureNotify event");
2514
2515 long start = System.currentTimeMillis();
2516 while (!oops_updated) {
2517 try {
2518 // Wait for OOPS ConfigureNotify event
2519 awtLockWait(timeout);
2520 } catch (InterruptedException e) {
2521 throw new RuntimeException(e);
2522 }
2523 // This "while" is a protection from spurious
2524 // wake-ups. However, we shouldn't wait for too long
2525 if ((System.currentTimeMillis() - start > timeout) && timeout >= 0) {
|