Skip to content

Commit

Permalink
#907: move size-hints to base window class, add docstrings to quickly…
Browse files Browse the repository at this point in the history
… get an overview of which X11 properties relate to the python gobject properties

git-svn-id: https://xpra.org/svn/Xpra/trunk@10656 3bb7dfac-3a0b-4e04-842a-767bc560f471
  • Loading branch information
totaam committed Sep 17, 2015
1 parent 9d93381 commit 13410eb
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 45 deletions.
56 changes: 51 additions & 5 deletions src/xpra/x11/gtk2/models/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from xpra.x11.gtk2.models.core import CoreX11WindowModel, gobject, xswallow, gdk
from xpra.x11.bindings.window_bindings import X11WindowBindings, constants #@UnresolvedImport
from xpra.x11.gtk2.gdk_bindings import get_pywindow, get_pyatom, calc_constrained_size #@UnresolvedImport
from xpra.x11.gtk2.models.size_hints_util import sanitize_size_hints

from xpra.log import Logger
log = Logger("x11", "window")
Expand Down Expand Up @@ -47,45 +48,58 @@ class BaseWindowModel(CoreX11WindowModel):
"""
__common_properties__ = CoreX11WindowModel.__common_properties__.copy()
__common_properties__.update({
#from WM_TRANSIENT_FOR
"transient-for": (gobject.TYPE_PYOBJECT,
"Transient for (or None)", "",
gobject.PARAM_READABLE),
#from _NET_WM_WINDOW_OPACITY
"opacity": (gobject.TYPE_INT64,
"Opacity", "",
-1, 0xffffffff, -1,
gobject.PARAM_READABLE),
#from WM_HINTS.window_group
"group-leader": (gobject.TYPE_PYOBJECT,
"Window group leader as a pair: (xid, gdk window)", "",
gobject.PARAM_READABLE),
#from WM_HINTS.urgency or _NET_WM_STATE
"attention-requested": (gobject.TYPE_BOOLEAN,
"Urgency hint from client, or us", "",
False,
gobject.PARAM_READWRITE),
#from WM_HINTS.input or WM_TAKE_FOCUS
"can-focus": (gobject.TYPE_BOOLEAN,
"Does this window ever accept keyboard input?", "",
True,
gobject.PARAM_READWRITE),
#
"size-hints": (gobject.TYPE_PYOBJECT,
"Client hints on constraining its size", "",
gobject.PARAM_READABLE),
#from _NET_WM_BYPASS_COMPOSITOR
"bypass-compositor": (gobject.TYPE_INT,
"hint that the window would benefit from running uncomposited ", "",
0, 2, 0,
gobject.PARAM_READABLE),
#from _NET_WM_FULLSCREEN_MONITORS
"fullscreen-monitors": (gobject.TYPE_PYOBJECT,
"List of 4 monitor indices indicating the top, bottom, left, and right edges of the window when the fullscreen state is enabled", "",
gobject.PARAM_READABLE),
#from _NET_WM_STRUT_PARTIAL or _NET_WM_STRUT
"strut": (gobject.TYPE_PYOBJECT,
"Struts requested by window, or None", "",
gobject.PARAM_READABLE),
#from _NET_WM_DESKTOP
"workspace": (gobject.TYPE_UINT,
"The workspace this window is on", "",
0, 2**32-1, WORKSPACE_UNSET,
gobject.PARAM_READWRITE),
#set initially only by the window model class
#(derived from XGetWindowAttributes.override_redirect)
"override-redirect": (gobject.TYPE_BOOLEAN,
"Is the window of type override-redirect", "",
False,
gobject.PARAM_READABLE),
"modal": (gobject.TYPE_PYOBJECT,
"Modal (boolean)", "",
gobject.PARAM_READWRITE),
#from _NET_WM_WINDOW_TYPE
"window-type": (gobject.TYPE_PYOBJECT,
"Window type",
"NB, most preferred comes first, then fallbacks",
Expand All @@ -95,6 +109,9 @@ class BaseWindowModel(CoreX11WindowModel):
"State, as per _NET_WM_STATE", "",
gobject.PARAM_READABLE),
#all the attributes below are virtual attributes from WM_STATE:
"modal": (gobject.TYPE_PYOBJECT,
"Modal (boolean)", "",
gobject.PARAM_READWRITE),
"fullscreen": (gobject.TYPE_BOOLEAN,
"Fullscreen-ness of window", "",
False,
Expand Down Expand Up @@ -133,11 +150,11 @@ class BaseWindowModel(CoreX11WindowModel):
gobject.PARAM_READWRITE),
})
_property_names = CoreX11WindowModel._property_names + [
"transient-for", "fullscreen-monitors", "bypass-compositor", "group-leader", "window-type", "workspace", "strut",
"size-hints", "transient-for", "fullscreen-monitors", "bypass-compositor", "group-leader", "window-type", "workspace", "strut",
#virtual attributes:
"fullscreen", "focused", "maximized", "above", "below", "shaded", "skip-taskbar", "skip-pager", "sticky"]
_dynamic_property_names = CoreX11WindowModel._dynamic_property_names + [
"attention-requested",
"size-hints", "attention-requested",
"fullscreen", "focused", "maximized", "above", "below", "shaded", "skip-taskbar", "skip-pager", "sticky"]
_internal_property_names = CoreX11WindowModel._internal_property_names+["state"]
_initial_x11_properties = CoreX11WindowModel._initial_x11_properties + [
Expand Down Expand Up @@ -313,6 +330,34 @@ def _update_can_focus(self, *args):
self._updateprop("can-focus", can_focus)


def _handle_wm_normal_hints_change(self):
with xswallow:
size_hints = X11Window.getSizeHints(self.xid)
metalog("WM_NORMAL_HINTS=%s", size_hints)
#getSizeHints exports fields using their X11 names as defined in the "XSizeHints" structure,
#but we use a different naming (for historical reason and backwards compatibility)
#so rename the fields:
hints = {}
if size_hints:
for k,v in size_hints.items():
hints[{"min_size" : "minimum-size",
"max_size" : "maximum-size",
"base_size" : "base-size",
"resize_inc" : "increment",
"win_gravity" : "gravity",
}.get(k, k)] = v
sanitize_size_hints(hints)
# Don't send out notify and ConfigureNotify events when this property
# gets no-op updated -- some apps like FSF Emacs 21 like to update
# their properties every time they see a ConfigureNotify, and this
# reduces the chance for us to get caught in loops:
old_hints = self.get_property("size-hints")
if hints and hints!=old_hints:
self._internal_set_property("size-hints", hints)
if self._setup_done:
self._update_client_geometry()


_x11_property_handlers = CoreX11WindowModel._x11_property_handlers.copy()
_x11_property_handlers.update({
"WM_TRANSIENT_FOR" : _handle_transient_for_change,
Expand All @@ -324,6 +369,7 @@ def _update_can_focus(self, *args):
"_NET_WM_STRUT_PARTIAL" : _handle_wm_strut_change,
"_NET_WM_WINDOW_OPACITY" : _handle_opacity_change,
"WM_HINTS" : _handle_wm_hints_change,
"WM_NORMAL_HINTS" : _handle_wm_normal_hints_change,
})


Expand Down
16 changes: 14 additions & 2 deletions src/xpra/x11/gtk2/models/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,50 +77,62 @@ class CoreX11WindowModel(AutoPropGObjectMixin, gobject.GObject):
the py_property_handlers do it in the other direction.
"""
__common_properties__ = {
#the actual X11 client window
"client-window": (gobject.TYPE_PYOBJECT,
"gtk.gdk.Window representing the client toplevel", "",
gobject.PARAM_READABLE),
#the X11 window id
"xid": (gobject.TYPE_INT,
"X11 window id", "",
-1, 65535, -1,
gobject.PARAM_READABLE),
#FIXME: this is an ugly virtual property
"geometry": (gobject.TYPE_PYOBJECT,
"current (border-corrected, relative to parent) coordinates (x, y, w, h) for the window", "",
gobject.PARAM_READABLE),
#if the window depth is 32 bit
"has-alpha": (gobject.TYPE_BOOLEAN,
"Does the window use transparency", "",
False,
gobject.PARAM_READABLE),
#from WM_CLIENT_MACHINE
"client-machine": (gobject.TYPE_PYOBJECT,
"Host where client process is running", "",
gobject.PARAM_READABLE),
#from _NET_WM_PID
"pid": (gobject.TYPE_INT,
"PID of owning process", "",
-1, 65535, -1,
gobject.PARAM_READABLE),
#from _NET_WM_NAME or WM_NAME
"title": (gobject.TYPE_PYOBJECT,
"Window title (unicode or None)", "",
gobject.PARAM_READABLE),
#from WM_WINDOW_ROLE
"role" : (gobject.TYPE_PYOBJECT,
"The window's role (ICCCM session management)", "",
gobject.PARAM_READABLE),
#from WM_PROTOCOLS via XGetWMProtocols
"protocols": (gobject.TYPE_PYOBJECT,
"Supported WM protocols", "",
gobject.PARAM_READABLE),
#from WM_COMMAND
"command": (gobject.TYPE_PYOBJECT,
"Command used to start or restart the client", "",
gobject.PARAM_READABLE),
#from WM_CLASS via getClassHint
"class-instance": (gobject.TYPE_PYOBJECT,
"Classic X 'class' and 'instance'", "",
gobject.PARAM_READABLE),
#ShapeNotify events will populate this using XShapeQueryExtents
"shape": (gobject.TYPE_PYOBJECT,
"Window XShape data", "",
gobject.PARAM_READABLE),
#this is synced to "_NET_FRAME_EXTENTS"
#synced to "_NET_FRAME_EXTENTS"
"frame": (gobject.TYPE_PYOBJECT,
"Size of the window frame, as per _NET_FRAME_EXTENTS", "",
gobject.PARAM_READWRITE),
#this is ssynced to "_NET_WM_ALLOWED_ACTIONS"
#synced to "_NET_WM_ALLOWED_ACTIONS"
"allowed-actions": (gobject.TYPE_PYOBJECT,
"Supported WM actions", "",
gobject.PARAM_READWRITE),
Expand Down
47 changes: 9 additions & 38 deletions src/xpra/x11/gtk2/models/window.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
from xpra.x11.gtk_x11.prop import prop_set, prop_get, MotifWMHints
from xpra.x11.bindings.window_bindings import X11WindowBindings #@UnresolvedImport
from xpra.x11.gtk2.models import Unmanageable, MAX_WINDOW_SIZE
from xpra.x11.gtk2.models.size_hints_util import sanitize_size_hints
from xpra.x11.gtk2.models.base import BaseWindowModel, constants
from xpra.x11.gtk2.models.core import sanestr, gobject, xswallow, xsync
from xpra.x11.gtk2.gdk_bindings import (
Expand Down Expand Up @@ -74,6 +73,9 @@ class WindowModel(BaseWindowModel):

__gproperties__ = dict(BaseWindowModel.__common_properties__)
__gproperties__.update({
"owner": (gobject.TYPE_PYOBJECT,
"Owner", "",
gobject.PARAM_READABLE),
# Interesting properties of the client window, that will be
# automatically kept up to date:
"actual-size": (gobject.TYPE_PYOBJECT,
Expand All @@ -88,9 +90,6 @@ class WindowModel(BaseWindowModel):
"requested-size": (gobject.TYPE_PYOBJECT,
"Client-requested size on screen", "",
gobject.PARAM_READABLE),
"size-hints": (gobject.TYPE_PYOBJECT,
"Client hints on constraining its size", "",
gobject.PARAM_READABLE),
# Toggling this property does not actually make the window iconified,
# i.e. make it appear or disappear from the screen -- it merely
# updates the various window manager properties that inform the world
Expand All @@ -99,18 +98,19 @@ class WindowModel(BaseWindowModel):
"ICCCM 'iconic' state -- any sort of 'not on desktop'.", "",
False,
gobject.PARAM_READWRITE),
#from _NET_WM_ICON_NAME or WM_ICON_NAME
"icon-title": (gobject.TYPE_PYOBJECT,
"Icon title (unicode or None)", "",
gobject.PARAM_READABLE),
#from _NET_WM_ICON
"icon": (gobject.TYPE_PYOBJECT,
"Icon (local Cairo surface)", "",
gobject.PARAM_READABLE),
#from _NET_WM_ICON
"icon-pixmap": (gobject.TYPE_PYOBJECT,
"Icon (server Pixmap)", "",
gobject.PARAM_READABLE),
"owner": (gobject.TYPE_PYOBJECT,
"Owner", "",
gobject.PARAM_READABLE),
#from _MOTIF_WM_HINTS.decorations
"decorations": (gobject.TYPE_BOOLEAN,
"Should the window decorations be shown", "",
True,
Expand All @@ -125,9 +125,9 @@ class WindowModel(BaseWindowModel):
})

_property_names = BaseWindowModel._property_names + [
"size-hints", "icon-title", "icon", "decorations"]
"icon-title", "icon", "decorations"]
_dynamic_property_names = BaseWindowModel._dynamic_property_names + [
"size-hints", "icon-title", "icon", "decorations"]
"icon-title", "icon", "decorations"]
_initial_x11_properties = BaseWindowModel._initial_x11_properties + [
"WM_HINTS", "WM_NORMAL_HINTS", "_MOTIF_WM_HINTS",
"WM_ICON_NAME", "_NET_WM_ICON_NAME", "_NET_WM_ICON",
Expand Down Expand Up @@ -194,7 +194,6 @@ def setup(self):
w,h = X11Window.getGeometry(self.xid)[2:4]
hints = self.get_property("size-hints")
log("setup() hints=%s size=%ix%i", hints, w, h)
sanitize_size_hints(hints)
nw, nh = calc_constrained_size(w, h, hints)[:2]
if nw>=MAX_WINDOW_SIZE or nh>=MAX_WINDOW_SIZE:
#we can't handle windows that big!
Expand Down Expand Up @@ -501,33 +500,6 @@ def do_child_configure_request_event(self, event):
# X11 properties synced to Python objects
#########################################

def _handle_wm_normal_hints_change(self):
with xswallow:
size_hints = X11Window.getSizeHints(self.xid)
metalog("WM_NORMAL_HINTS=%s", size_hints)
#getSizeHints exports fields using their X11 names as defined in the "XSizeHints" structure,
#but we use a different naming (for historical reason and backwards compatibility)
#so rename the fields:
hints = {}
if size_hints:
for k,v in size_hints.items():
hints[{"min_size" : "minimum-size",
"max_size" : "maximum-size",
"base_size" : "base-size",
"resize_inc" : "increment",
"win_gravity" : "gravity",
}.get(k, k)] = v
sanitize_size_hints(hints)
# Don't send out notify and ConfigureNotify events when this property
# gets no-op updated -- some apps like FSF Emacs 21 like to update
# their properties every time they see a ConfigureNotify, and this
# reduces the chance for us to get caught in loops:
old_hints = self.get_property("size-hints")
if hints and hints!=old_hints:
self._internal_set_property("size-hints", hints)
if self._setup_done:
self._update_client_geometry()

def _handle_icon_title_change(self):
icon_name = self.prop_get("_NET_WM_ICON_NAME", "utf8", True)
iconlog("_NET_WM_ICON_NAME=%s", icon_name)
Expand Down Expand Up @@ -569,7 +541,6 @@ def _handle_net_wm_icon_change(self):

_x11_property_handlers = dict(BaseWindowModel._x11_property_handlers)
_x11_property_handlers.update({
"WM_NORMAL_HINTS" : _handle_wm_normal_hints_change,
"WM_ICON_NAME" : _handle_icon_title_change,
"_NET_WM_ICON_NAME" : _handle_icon_title_change,
"_MOTIF_WM_HINTS" : _handle_motif_wm_hints_change,
Expand Down

0 comments on commit 13410eb

Please sign in to comment.