From 2a52f27b9db3433bb5e3864f0d1a78b242fc1f3c Mon Sep 17 00:00:00 2001 From: Antoine Martin Date: Mon, 1 Apr 2019 09:16:10 +0000 Subject: [PATCH] #2243: replace many None dereference bugs with default values or placeholders: dpi, mouse position, transparency support check, icon theme is MIA, keymap cannot be queried?, better to call Gtk.init() early, root window size, X11 display check, etc git-svn-id: https://xpra.org/svn/Xpra/trunk@22239 3bb7dfac-3a0b-4e04-842a-767bc560f471 --- src/xpra/client/gtk3/client.py | 18 +++++-- src/xpra/client/gtk_base/gtk_client_base.py | 48 +++++++++++-------- .../client/gtk_base/gtk_keyboard_helper.py | 6 ++- src/xpra/gtk_common/gobject_compat.py | 1 + src/xpra/gtk_common/gtk_util.py | 26 ++++++---- src/xpra/gtk_common/keymap.py | 2 + src/xpra/x11/gtk3/gdk_bindings.pyx | 9 +++- 7 files changed, 73 insertions(+), 37 deletions(-) diff --git a/src/xpra/client/gtk3/client.py b/src/xpra/client/gtk3/client.py index 4751380934..4ffb3355f8 100644 --- a/src/xpra/client/gtk3/client.py +++ b/src/xpra/client/gtk3/client.py @@ -8,9 +8,8 @@ gi.require_version('Gdk', '3.0') #@UndefinedVariable from gi.repository import GObject #@UnresolvedImport from gi.repository import Gdk #@UnresolvedImport -from gi.repository import GLib #@UnresolvedImport -from xpra.os_util import OSX, POSIX +from xpra.os_util import OSX 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 @@ -47,18 +46,24 @@ def get_notifier_classes(self): log.warn(" %s", e) return ncs + def get_screen_resolution(self): + screen = Gdk.Screen.get_default() + if not screen: + #wayland? + return -1 + return screen.get_resolution() def get_xdpi(self): xdpi = get_xdpi() if xdpi>0: return xdpi - return Gdk.Screen.get_default().get_resolution() + return self.get_screen_resolution() def get_ydpi(self): ydpi = get_ydpi() if ydpi>0: return ydpi - return Gdk.Screen.get_default().get_resolution() + return self.get_screen_resolution() def get_tray_menu_helper_class(self): @@ -68,7 +73,10 @@ def get_tray_menu_helper_class(self): def get_mouse_position(self): #with GTK3, we can get None values! - p = self.get_root_window().get_pointer()[-3:-1] + root = self.get_root_window() + if not root: + return -1, -1 + p = root.get_pointer()[-3:-1] return self.sp(p[0] or 0, p[1] or 0) diff --git a/src/xpra/client/gtk_base/gtk_client_base.py b/src/xpra/client/gtk_base/gtk_client_base.py index 604fb557cf..7ae1a7d7d1 100644 --- a/src/xpra/client/gtk_base/gtk_client_base.py +++ b/src/xpra/client/gtk_base/gtk_client_base.py @@ -15,7 +15,10 @@ updict, pver, iround, flatten_dict, envbool, repr_ellipsized, csv, first_time, DEFAULT_METADATA_SUPPORTED, XPRA_OPENGL_NOTIFICATION_ID, ) -from xpra.os_util import bytestostr, strtobytes, hexstr, monotonic_time, WIN32, OSX, POSIX +from xpra.os_util import ( + bytestostr, strtobytes, hexstr, monotonic_time, + WIN32, OSX, POSIX, is_Wayland, + ) from xpra.simple_stats import std_unit from xpra.exit_codes import EXIT_PASSWORD_REQUIRED from xpra.scripts.config import TRUE_OPTIONS, FALSE_OPTIONS @@ -673,7 +676,10 @@ def get_mouse_position(self): return self.cp(p[0], p[1]) def get_current_modifiers(self): - modifiers_mask = self.get_root_window().get_pointer()[-1] + root = self.get_root_window() + if root is None: + return () + modifiers_mask = root.get_pointer()[-1] return self.mask_to_names(modifiers_mask) @@ -685,22 +691,23 @@ def make_hello(self): #tell the server which icons GTK can use #so it knows when it should supply one as fallback it = icon_theme_get_default() - #this would add our bundled icon directory - #to the search path, but I don't think we have - #any extra icons that matter in there: - #from xpra.platform.paths import get_icon_dir - #d = get_icon_dir() - #if d not in it.get_search_path(): - # it.append_search_path(d) - # it.rescan_if_needed() - log("default icon theme: %s", it) - log("icon search path: %s", it.get_search_path()) - log("contexts: %s", it.list_contexts()) - icons = [] - for context in it.list_contexts(): - icons += it.list_icons(context) - log("icons: %s", icons) - capabilities["theme.default.icons"] = tuple(set(icons)) + if it: + #this would add our bundled icon directory + #to the search path, but I don't think we have + #any extra icons that matter in there: + #from xpra.platform.paths import get_icon_dir + #d = get_icon_dir() + #if d not in it.get_search_path(): + # it.append_search_path(d) + # it.rescan_if_needed() + log("default icon theme: %s", it) + log("icon search path: %s", it.get_search_path()) + log("contexts: %s", it.list_contexts()) + icons = [] + for context in it.list_contexts(): + icons += it.list_icons(context) + log("icons: %s", icons) + capabilities["theme.default.icons"] = tuple(set(icons)) if METADATA_SUPPORTED: ms = [x.strip() for x in METADATA_SUPPORTED.split(",")] else: @@ -758,7 +765,10 @@ def make_hello(self): def has_transparency(self): - return screen_get_default().get_rgba_visual() is not None + screen = screen_get_default() + if screen is None: + return is_Wayland() + return screen.get_rgba_visual() is not None def get_screen_sizes(self, xscale=1, yscale=1): diff --git a/src/xpra/client/gtk_base/gtk_keyboard_helper.py b/src/xpra/client/gtk_base/gtk_keyboard_helper.py index 99b433c202..0edb00e983 100644 --- a/src/xpra/client/gtk_base/gtk_keyboard_helper.py +++ b/src/xpra/client/gtk_base/gtk_keyboard_helper.py @@ -23,8 +23,10 @@ def __init__(self, *args): #(as we may be getting dozens of such events at a time) self._keymap_changing = False self._keymap_change_handler_id = None + self._keymap = None display = display_get_default() - self._keymap = keymap_get_for_display(display) + if display: + self._keymap = keymap_get_for_display(display) self.update() if self._keymap: self._keymap_change_handler_id = self._keymap.connect("keys-changed", self.keymap_changed) @@ -67,7 +69,7 @@ def update(self): return old_hash!=self.hash def get_full_keymap(self): - return get_gtk_keymap() + return get_gtk_keymap() def cleanup(self): KeyboardHelper.cleanup(self) diff --git a/src/xpra/gtk_common/gobject_compat.py b/src/xpra/gtk_common/gobject_compat.py index c1a13eaaf8..e4fa5cf6fc 100644 --- a/src/xpra/gtk_common/gobject_compat.py +++ b/src/xpra/gtk_common/gobject_compat.py @@ -126,6 +126,7 @@ def import_gtk3(): gi_gtk() from gi.repository import Gtk #@UnresolvedImport try_import_GdkX11() + Gtk.init() return Gtk def import_gtk(): return _try_import(import_gtk3, import_gtk2) diff --git a/src/xpra/gtk_common/gtk_util.py b/src/xpra/gtk_common/gtk_util.py index f486b874ef..cc4e2cec0b 100644 --- a/src/xpra/gtk_common/gtk_util.py +++ b/src/xpra/gtk_common/gtk_util.py @@ -8,7 +8,10 @@ import array from xpra.util import iround, first_time -from xpra.os_util import strtobytes, bytestostr, WIN32, OSX, PYTHON2 +from xpra.os_util import ( + strtobytes, bytestostr, + WIN32, OSX, PYTHON2, POSIX, is_Wayland, + ) from xpra.gtk_common.gobject_compat import ( import_gtk, import_gdk, import_glib, import_pixbufloader, import_pango, import_cairo, import_gobject, import_pixbuf, is_gtk3, @@ -195,20 +198,21 @@ def color_parse(*args): def get_xwindow(w): return w.get_xid() def get_default_root_window(): - return gdk.Screen.get_default().get_root_window() + screen = gdk.Screen.get_default() + if screen is None: + return None + return screen.get_root_window() def get_root_size(): - if WIN32: + if WIN32 or (POSIX and not OSX): #FIXME: hopefully, we can remove this code once GTK3 on win32 is fixed? #we do it the hard way because the root window geometry is invalid on win32: #and even just querying it causes this warning: #"GetClientRect failed: Invalid window handle." - display = gdk.Display.get_default() - n = display.get_n_screens() - w, h = 0, 0 - for i in range(n): - screen = display.get_screen(i) - w += screen.get_width() - h += screen.get_height() + screen = gdk.Screen.get_default() + if screen is None: + return 1920, 1024 + w = screen.get_width() + h = screen.get_height() else: #the easy way for platforms that work out of the box: root = get_default_root_window() @@ -913,6 +917,8 @@ def ys(v): def swork(*workarea): return xs(workarea[0]), ys(workarea[1]), xs(workarea[2]), ys(workarea[3]) display = display_get_default() + if not display: + return () n_screens = display.get_n_screens() get_n_monitors = getattr(display, "get_n_monitors", None) if get_n_monitors: diff --git a/src/xpra/gtk_common/keymap.py b/src/xpra/gtk_common/keymap.py index 1f0568edf3..3c80f76612 100755 --- a/src/xpra/gtk_common/keymap.py +++ b/src/xpra/gtk_common/keymap.py @@ -24,6 +24,8 @@ def get_gtk_keymap(ignore_keys=(None, "VoidSymbol", "0xffffff")): from xpra.gtk_common.gtk_util import keymap_get_for_display, display_get_default, import_gdk, is_gtk3 gdk = import_gdk() display = display_get_default() + if not display: + return () keymap = keymap_get_for_display(display) log("keymap_get_for_display(%s)=%s, direction=%s, bidirectional layouts: %s", display, keymap, keymap.get_direction(), keymap.have_bidi_layouts()) diff --git a/src/xpra/x11/gtk3/gdk_bindings.pyx b/src/xpra/x11/gtk3/gdk_bindings.pyx index f88549fd98..7061a5a80b 100644 --- a/src/xpra/x11/gtk3/gdk_bindings.pyx +++ b/src/xpra/x11/gtk3/gdk_bindings.pyx @@ -48,10 +48,17 @@ cdef extern from "gdk_x11_macros.h": int is_x11_display(void *) def is_X11_Display(display=None): + cdef GdkDisplay *gdk_display if display is None: manager = Gdk.DisplayManager.get() display = manager.get_default_display() - return bool(is_x11_display(get_raw_display_for(display))) + if display is None: + return False + try: + gdk_display = get_raw_display_for(display) + except TypeError: + return False + return bool(is_x11_display(gdk_display)) ################################### # Headers, python magic