Skip to content

Commit

Permalink
#4335 replace gtk with pure-x11 calls
Browse files Browse the repository at this point in the history
minimal backport of 61c94c2
  • Loading branch information
totaam committed Aug 20, 2024
1 parent 0c9612f commit ebfad4e
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 44 deletions.
15 changes: 15 additions & 0 deletions xpra/x11/bindings/window.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ from xpra.gtk.error import XError
from xpra.x11.bindings.xlib cimport (
Display, Drawable, Visual, Window, Bool, Pixmap, XID, Status, Atom, Time, CurrentTime, Cursor, XPointer,
GrabModeAsync, XGrabPointer,
Expose,
XRectangle, XEvent, XClassHint,
XWMHints, XSizeHints,
XCreateWindow, XDestroyWindow, XIfEvent, PropertyNotify,
Expand Down Expand Up @@ -858,6 +859,20 @@ cdef class X11WindowBindingsInstance(X11CoreBindingsInstance):
if s == 0:
raise ValueError("failed to serialize XEmbed Message")

def send_expose(self, Window xwindow, int x, int y, int width, int height, int count=0):
cdef XEvent e
e.xany.display = self.display
e.xany.window = xwindow
e.xany.type = Expose
e.xexpose.x = x
e.xexpose.y = y
e.xexpose.width = width
e.xexpose.height = height
e.xexpose.count = count
s = XSendEvent(self.display, xwindow, False, NoEventMask, &e)
if s == 0:
raise ValueError("failed to serialize XExpose Message")

###################################
# Clipboard
###################################
Expand Down
9 changes: 9 additions & 0 deletions xpra/x11/bindings/xlib.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ cdef extern from "X11/X.h":
unsigned long AnyPropertyType
unsigned int PropModeReplace
unsigned int PropertyNotify
unsigned int Expose


cdef extern from "X11/Xutil.h":
Expand Down Expand Up @@ -493,6 +494,12 @@ cdef extern from "X11/Xlib.h":
unsigned int state
unsigned int keycode

ctypedef struct XExposeEvent:
Window window
int x, y
int width, height
int count

ctypedef union XEvent:
int type
XAnyEvent xany
Expand All @@ -517,3 +524,5 @@ cdef extern from "X11/Xlib.h":
XDestroyWindowEvent xdestroywindow
XPropertyEvent xproperty
XGenericEventCookie xcookie
XExposeEvent xexpose

77 changes: 34 additions & 43 deletions xpra/x11/gtk/tray.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@

XNone = constants["XNone"]
StructureNotifyMask = constants["StructureNotifyMask"]
ExposureMask = constants["ExposureMask"]
PropertyChangeMask = constants["PropertyChangeMask"]

XEMBED_VERSION = 0

Expand Down Expand Up @@ -83,12 +85,8 @@ class TRAY_ORIENTATION(IntEnum):
MAX_TRAY_SIZE = envint("XPRA_MAX_TRAY_SIZE", 64)


def get_tray_window(tray_window) -> int:
return getattr(tray_window, XPRA_TRAY_WINDOW_PROPERTY, 0)


def set_tray_window(tray_window, xid: int):
setattr(tray_window, XPRA_TRAY_WINDOW_PROPERTY, xid)
def get_tray_window(xid):
return prop_get(xid, XPRA_TRAY_WINDOW_PROPERTY, "u32")


def set_tray_visual(xid: int, gdk_visual):
Expand Down Expand Up @@ -118,10 +116,8 @@ def __init__(self):
# the window where we embed all the tray icons:
self.tray_window: GdkX11.X11Window | None = None
self.xid: int = 0
# map xid to the gdk window:
self.window_trays: dict[int, Gdk.Window] = {}
# map gdk windows to their corral window:
self.tray_windows: dict[GdkX11.X11Window, GdkX11.X11Window] = {}
# map client tray windows to their corral window:
self.tray_windows: dict[int, int] = {}
self.setup_tray_window()

def cleanup(self) -> None:
Expand All @@ -137,14 +133,14 @@ def cleanup(self) -> None:
remove_event_receiver(self.xid, self)
tray_windows = self.tray_windows
self.tray_windows = {}
for window, tray_window in tray_windows.items():
for xid, xtray in tray_windows.items():
with xlog:
self.undock(window)
tray_window.destroy()
self.undock(xid)
X11Window.Unmap(xtray)
tw = self.tray_window
if tw:
self.tray_window = None
tw.destroy()
tw.hide()
log("SystemTray.cleanup() done")

def setup_tray_window(self) -> None:
Expand All @@ -161,7 +157,7 @@ def setup_tray_window(self) -> None:
if TRANSPARENCY:
visual = screen.get_rgba_visual()
if visual is None:
log.warn("setup tray: using system visual fallback")
log.warn("setup tray: using rgb visual fallback")
visual = screen.get_system_visual()
assert visual is not None, "failed to obtain visual"
self.tray_window = GDKX11Window(root, width=1, height=1,
Expand Down Expand Up @@ -225,10 +221,9 @@ def do_x11_client_message_event(self, event) -> None:
else:
log.info("do_x11_client_message_event(%s)", event)

def undock(self, window) -> None:
log("undock(%s)", window)
def undock(self, xid) -> None:
log("undock(%s)", xid)
rxid = X11Window.get_root_xid()
xid = window.get_xid()
X11Window.Unmap(xid)
X11Window.Reparent(xid, rxid, 0, 0)

Expand All @@ -246,27 +241,26 @@ def dock_tray(self, xid: int) -> None:

def do_dock_tray(self, xid: int) -> None:
root = get_default_root_window()
window = self.get_pywindow(xid)
if window is None:
log.warn(f"Warning: could not find gdk window for tray window {xid:x}")
return
w, h = window.get_geometry()[2:4]
w, h = X11Window.getGeometry(xid)[2:4]
log(f"tray geometry={w}x{h}")
if w == 0 and h == 0:
log(f"invalid tray geometry {w}x{h}, ignoring this request")
return
em = Gdk.EventMask
event_mask = em.STRUCTURE_MASK | em.EXPOSURE_MASK | em.PROPERTY_CHANGE_MASK
window.set_events(event_mask=event_mask)
window = self.get_pywindow(xid)
if window is None:
log.warn(f"Warning: could not find gdk window for tray window {xid:x}")
return
event_mask = StructureNotifyMask | ExposureMask | PropertyChangeMask
X11Window.setEventMask(xid, event_mask)
add_event_receiver(xid, self)
w = max(1, min(MAX_TRAY_SIZE, w))
h = max(1, min(MAX_TRAY_SIZE, h))
title = prop_get(xid, "_NET_WM_NAME", "utf8", ignore_errors=True)
if title is None:
if not title:
title = prop_get(xid, "WM_NAME", "latin1", ignore_errors=True)
if title is None:
if not title:
title = ""
log(f"adjusted geometry={window.get_geometry()}, title={title!r}")
log(f"adjusted geometry={X11Window.getGeometry(xid)}, title={title!r}")
visual = window.get_visual()
tray_window = GDKX11Window(root, width=w, height=h,
event_mask=event_mask,
Expand All @@ -276,29 +270,26 @@ def do_dock_tray(self, xid: int) -> None:
visual=visual)
xtray = tray_window.get_xid()
log(f"tray: recording corral window {xtray:x}, setting tray properties")
set_tray_window(tray_window, xid)
self.tray_windows[window] = tray_window
self.window_trays[xid] = window
prop_set(xtray, XPRA_TRAY_WINDOW_PROPERTY, "u32", xid)
self.tray_windows[xid] = xtray
log("showing tray window, resizing and reparenting")
tray_window.show()
window.resize(w, h)
X11Window.MapWindow(xtray)
X11Window.ResizeWindow(xtray, w, h)
X11Window.Withdraw(xid)
X11Window.Reparent(xid, xtray, 0, 0)
X11Window.MapRaised(xid)
log(f"redrawing new tray container window {xtray:x}")
rect = Gdk.Rectangle()
rect.width = w
rect.height = h
tray_window.invalidate_rect(rect, True)
X11Window.send_expose(xtray, 0, 0, w, h)
log(f"dock_tray({xid:x}) done, sending xembed notification")
X11Window.send_xembed_message(xid, XEMBED.EMBEDDED_NOTIFY, 0, xtray, XEMBED_VERSION)

def do_x11_unmap_event(self, event) -> None:
gdk_window = self.window_trays.pop(event.window, None)
tray_window = self.tray_windows.pop(gdk_window, None)
log(f"SystemTray.do_x11_unmap_event({event}) gdk window={gdk_window}, container window={tray_window}")
if tray_window:
tray_window.destroy()
xid = event.window
xtray = self.tray_windows.pop(xid, None)
log(f"SystemTray.do_x11_unmap_event({event}) window={xid}, container window={xtray}")
if xtray:
with xlog:
X11Window.Unmap(xtray)


GObject.type_register(SystemTray)
2 changes: 1 addition & 1 deletion xpra/x11/server/seamless.py
Original file line number Diff line number Diff line change
Expand Up @@ -618,7 +618,7 @@ def _add_new_or_window(self, xid: int) -> None:
return
try:
# pylint: disable=import-outside-toplevel
tray_xid: int = get_tray_window(gdk_window)
tray_xid: int = get_tray_window(xid)
if tray_xid:
assert self._tray
from xpra.x11.models.systray import SystemTrayWindowModel
Expand Down

0 comments on commit ebfad4e

Please sign in to comment.