From cd1c1cdfcb63149f3cd635e3d251071841775241 Mon Sep 17 00:00:00 2001 From: Antoine Martin Date: Thu, 25 Jul 2019 13:01:28 +0000 Subject: [PATCH] #2243 for wayland, we have to use a widget within the window to get the correct coordinates for events (otherwise the window context is actually much bigger than the window and includes the window title bar, so there is a large offset): create a DrawingArea widget, and replace it with the actual widget if we do end up creating one (ie: GL windows use a GL widget) git-svn-id: https://xpra.org/svn/Xpra/trunk@23305 3bb7dfac-3a0b-4e04-842a-767bc560f471 --- src/xpra/client/client_window_base.py | 6 +-- src/xpra/client/gl/gtk2/gl_client_window.py | 4 ++ src/xpra/client/gl/gtk3/gl_client_window.py | 4 ++ src/xpra/client/gtk2/gtk2_window_base.py | 7 +++ src/xpra/client/gtk3/client.py | 6 ++- src/xpra/client/gtk3/client_window.py | 45 +++++++++---------- .../client/gtk_base/gtk_client_window_base.py | 37 ++++++++++++--- src/xpra/platform/xposix/gui.py | 10 ++--- 8 files changed, 81 insertions(+), 38 deletions(-) diff --git a/src/xpra/client/client_window_base.py b/src/xpra/client/client_window_base.py index d9b8e0a1ac..c78f5d068e 100644 --- a/src/xpra/client/client_window_base.py +++ b/src/xpra/client/client_window_base.py @@ -9,7 +9,7 @@ import re from xpra.client.client_widget_base import ClientWidgetBase -from xpra.os_util import bytestostr, PYTHON2, PYTHON3, OSX, WIN32 +from xpra.os_util import bytestostr, PYTHON2, PYTHON3, OSX, WIN32, is_Wayland from xpra.util import typedict, envbool, WORKSPACE_UNSET, WORKSPACE_NAMES from xpra.log import Logger @@ -649,7 +649,7 @@ def after_draw_refresh(success, message=""): return backing = self._backing if backing and (backing.draw_needs_refresh or REPAINT_ALL): - if REPAINT_ALL=="1" or self._client.xscale!=1 or self._client.yscale!=1: + if REPAINT_ALL=="1" or self._client.xscale!=1 or self._client.yscale!=1 or is_Wayland(): rw, rh = self.get_size() rx, ry = 0, 0 else: @@ -740,7 +740,7 @@ def get_mouse_event_wid(self, _x, _y): #overriden in GTKClientWindowBase return self._id - def do_motion_notify_event(self, event): + def _do_motion_notify_event(self, event): if self._client.readonly or self._client.server_readonly or not self._client.server_pointer: return pointer, relative_pointer, modifiers, buttons = self._pointer_modifiers(event) diff --git a/src/xpra/client/gl/gtk2/gl_client_window.py b/src/xpra/client/gl/gtk2/gl_client_window.py index 96b70ad3a9..71df3ab48a 100644 --- a/src/xpra/client/gl/gtk2/gl_client_window.py +++ b/src/xpra/client/gl/gtk2/gl_client_window.py @@ -40,7 +40,11 @@ def new_backing(self, bw, bh): self.remove_backing() widget = GTK2WindowBase.new_backing(self, bw, bh) log("new_backing(%s, %s)=%s", bw, bh, widget) + if self.drawing_area: + self.remove(self.drawing_area) + self.init_widget_events(widget) self.add(widget) + self.drawing_area = widget def freeze(self): self.remove_backing() diff --git a/src/xpra/client/gl/gtk3/gl_client_window.py b/src/xpra/client/gl/gtk3/gl_client_window.py index dafa941240..9de65ccbc5 100644 --- a/src/xpra/client/gl/gtk3/gl_client_window.py +++ b/src/xpra/client/gl/gtk3/gl_client_window.py @@ -29,4 +29,8 @@ def destroy(self): def new_backing(self, bw, bh): widget = ClientWindow.new_backing(self, bw, bh) + if self.drawing_area: + self.remove(self.drawing_area) + self.init_widget_events(widget) self.add(widget) + self.drawing_area = widget diff --git a/src/xpra/client/gtk2/gtk2_window_base.py b/src/xpra/client/gtk2/gtk2_window_base.py index 4fc531e58e..4bea056e4b 100644 --- a/src/xpra/client/gtk2/gtk2_window_base.py +++ b/src/xpra/client/gtk2/gtk2_window_base.py @@ -72,6 +72,10 @@ def do_init_window(self, window_type=gtk.WINDOW_TOPLEVEL): # see: https://bugs.kde.org/show_bug.cgi?id=274485 self.set_data("_kde_no_window_grab", 1) + def init_drawing_area(self): + GTKClientWindowBase.init_drawing_area(self) + self.drawing_area.connect("expose-event", self.do_drawing_area_expose_event) + def xget_u32_property(self, target, name): try: @@ -116,6 +120,9 @@ def queue_draw_area(self, x, y, width, height): event = DrawEvent(area=rect) self.do_expose_event(event) + def do_drawing_area_expose_event(self, drawing_area, event): + self.do_expose_event(event) + def do_expose_event(self, event): #cannot use self eventslog("do_expose_event(%s) area=%s", event, event.area) diff --git a/src/xpra/client/gtk3/client.py b/src/xpra/client/gtk3/client.py index 594bad3feb..8b1a8e8269 100644 --- a/src/xpra/client/gtk3/client.py +++ b/src/xpra/client/gtk3/client.py @@ -9,7 +9,7 @@ from gi.repository import GObject #@UnresolvedImport from gi.repository import Gdk #@UnresolvedImport -from xpra.os_util import OSX +from xpra.os_util import OSX, POSIX, is_Wayland from xpra.gtk_common.gobject_compat import register_os_signals from xpra.client.gtk_base.gtk_client_base import GTKXpraClient from xpra.client.gtk3.client_window import ClientWindow @@ -27,6 +27,10 @@ def client_type(self): return "Python/GTK3" def client_toolkit(self): + if POSIX and not OSX: + if is_Wayland(): + return "GTK3 Wayland" + return "GTK3 X11" return "GTK3" diff --git a/src/xpra/client/gtk3/client_window.py b/src/xpra/client/gtk3/client_window.py index df3b33963e..99f57fdf50 100644 --- a/src/xpra/client/gtk3/client_window.py +++ b/src/xpra/client/gtk3/client_window.py @@ -60,28 +60,10 @@ class ClientWindow(GTKClientWindowBase): def do_init_window(self, window_type): Gtk.Window.__init__(self, type = window_type) - # tell KDE/oxygen not to intercept clicks - # see: https://bugs.kde.org/show_bug.cgi?id=274485 - # does not work with gtk3? what the?? - # they moved it gobject, then removed it, unbelievable: - # https://bugzilla.gnome.org/show_bug.cgi?id=641944 - #self.set_data("_kde_no_window_grab", 1) - def motion(_w, event): - self.do_motion_notify_event(event) - return True - self.connect("motion-notify-event", motion) - def press(_w, event): - self.do_button_press_event(event) - return True - self.connect("button-press-event", press) - def release(_w, event): - self.do_button_release_event(event) - return True - self.connect("button-release-event", release) - def scroll(_w, event): - self.do_scroll_event(event) - return True - self.connect("scroll-event", scroll) + + def init_drawing_area(self): + GTKClientWindowBase.init_drawing_area(self) + self.drawing_area.connect("draw", self.drawing_area_draw) def get_backing_class(self): return CairoBacking @@ -106,7 +88,7 @@ def is_mapped(self): return self.get_mapped() def get_window_geometry(self): - gdkwindow = self.get_window() + gdkwindow = self.drawing_area.get_window() x, y = gdkwindow.get_origin()[1:] w, h = self.get_size() return (x, y, w, h) @@ -153,10 +135,25 @@ def apply_geometry_hints(self, hints): metalog("apply_geometry_hints(%s) geometry=%s, hints=%s", hints, geom, gdk_hints) self.set_geometry_hints(None, geom, gdk_hints) + def queue_draw_area(self, x, y, width, height): + window = self.get_window() + if not window: + log.warn("Warning: ignoring draw packet,") + log.warn(" received for a window which is not realized yet or gone already") + return + rect = Gdk.Rectangle() + rect.x = x + rect.y = y + rect.width = width + rect.height = height + self.drawing_area.get_window().invalidate_rect(rect, False) def do_draw(self, context): - Gtk.Window.do_draw(self, context) paintlog("do_draw(%s)", context) + Gtk.Window.do_draw(self, context) + + def drawing_area_draw(self, widget, context): + paintlog("drawing_area_draw(%s, %s)", widget, context) backing = self._backing if self.get_mapped() and backing: self.paint_backing_offset_border(backing, context) diff --git a/src/xpra/client/gtk_base/gtk_client_window_base.py b/src/xpra/client/gtk_base/gtk_client_window_base.py index bb71965cb7..85b8e8359d 100644 --- a/src/xpra/client/gtk_base/gtk_client_window_base.py +++ b/src/xpra/client/gtk_base/gtk_client_window_base.py @@ -208,6 +208,7 @@ def init_window(self, metadata): window_type = WINDOW_TOPLEVEL self.on_realize_cb = {} self.do_init_window(window_type) + self.init_drawing_area() self.set_decorated(self._is_decorated(metadata)) self.set_app_paintable(True) self._window_state = {} @@ -231,6 +232,32 @@ def init_window(self, metadata): self.init_focus() ClientWindowBase.init_window(self, metadata) + def init_drawing_area(self): + widget = gtk.DrawingArea() + widget.show() + self.drawing_area = widget + self.init_widget_events(widget) + self.add(widget) + + def init_widget_events(self, widget): + widget.add_events(self.WINDOW_EVENT_MASK) + def motion(_w, event): + self._do_motion_notify_event(event) + return True + widget.connect("motion-notify-event", motion) + def press(_w, event): + self._do_button_press_event(event) + return True + widget.connect("button-press-event", press) + def release(_w, event): + self._do_button_release_event(event) + return True + widget.connect("button-release-event", release) + def scroll(_w, event): + self._do_scroll_event(event) + return True + widget.connect("scroll-event", scroll) + ###################################################################### # drag and drop: @@ -1416,22 +1443,22 @@ def remove_pointer_overlay(): self.queue_draw_area(x, y, w, h) - def do_button_press_event(self, event): + def _do_button_press_event(self, event): #gtk.Window.do_button_press_event(self, event) self._button_action(event.button, event, True) - def do_button_release_event(self, event): + def _do_button_release_event(self, event): #gtk.Window.do_button_release_event(self, event) self._button_action(event.button, event, False) ###################################################################### # pointer motion - def do_motion_notify_event(self, event): + def _do_motion_notify_event(self, event): #gtk.Window.do_motion_notify_event(self, event) if self.moveresize_event: self.motion_moveresize(event) - ClientWindowBase.do_motion_notify_event(self, event) + ClientWindowBase._do_motion_notify_event(self, event) def motion_moveresize(self, event): x_root, y_root, direction, button, start_buttons, wx, wy, ww, wh = self.moveresize_event @@ -2038,7 +2065,7 @@ def get_mouse_event_wid(self, x, y): return ClientWindowBase.get_mouse_event_wid(self, x, y) - def do_scroll_event(self, event): + def _do_scroll_event(self, event): if self._client.readonly: return button_mapping = GDK_SCROLL_MAP.get(event.direction, -1) diff --git a/src/xpra/platform/xposix/gui.py b/src/xpra/platform/xposix/gui.py index dfad7d89f2..9185238851 100644 --- a/src/xpra/platform/xposix/gui.py +++ b/src/xpra/platform/xposix/gui.py @@ -550,11 +550,11 @@ def __init__(self, window): window.connect("configure-event", self.configured) self.configured() #replace event handlers with XI2 version: - self.do_motion_notify_event = window.do_motion_notify_event - window.do_motion_notify_event = self.noop - window.do_button_press_event = self.noop - window.do_button_release_event = self.noop - window.do_scroll_event = self.noop + self._do_motion_notify_event = window._do_motion_notify_event + window._do_motion_notify_event = self.noop + window._do_button_press_event = self.noop + window._do_button_release_event = self.noop + window._do_scroll_event = self.noop window.connect("destroy", self.cleanup) def noop(self, *args):