Skip to content

Commit

Permalink
#3251 replace _NET_WM_PID with XResGetClientPid
Browse files Browse the repository at this point in the history
  • Loading branch information
totaam committed Aug 29, 2021
1 parent c6b1b49 commit 234ec06
Show file tree
Hide file tree
Showing 7 changed files with 175 additions and 16 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ tests/unittests/test-file*
/xpra/x11/bindings/display_source.c
/xpra/x11/bindings/keyboard_bindings.c
/xpra/x11/bindings/randr_bindings.c
/xpra/x11/bindings/res_bindings.c
/xpra/x11/bindings/wait_for_x_server.c
/xpra/x11/bindings/window_bindings.c
/xpra/x11/bindings/ximage.c
Expand Down
1 change: 1 addition & 0 deletions packaging/debian/xpra/control
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ Build-Depends: debhelper (>= 8)
,libxdamage-dev
,libxtst-dev
,libxkbfile-dev
,libxres-dev
,libnvidia-fbc1
,libvpx-dev
,libx264-dev
Expand Down
6 changes: 6 additions & 0 deletions packaging/rpm/xpra.spec
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,12 @@ BuildRequires: libxkbfile-devel
BuildRequires: libXtst-devel
BuildRequires: libXcomposite-devel
BuildRequires: libXdamage-devel
BuildRequires: libXres-devel
Requires: libxkbfile
Requires: libXtst
Requires: libXcomposite
Requires: libXdamage
Requires: libXres
#once the server is fully ported over to python3:
#Recommends: python3-uinput
%description -n python3-xpra-server
Expand Down
5 changes: 5 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -937,6 +937,7 @@ def clean():
"xpra/x11/bindings/display_source.c",
"xpra/x11/bindings/window_bindings.c",
"xpra/x11/bindings/randr_bindings.c",
"xpra/x11/bindings/res_bindings.c",
"xpra/x11/bindings/core_bindings.c",
"xpra/x11/bindings/posix_display_source.c",
"xpra/x11/bindings/ximage.c",
Expand Down Expand Up @@ -1876,6 +1877,10 @@ def osx_pkgconfig(*pkgs_options, **ekw):
["xpra/x11/bindings/ximage.pyx"],
**pkgconfig("x11", "xext", "xcomposite")
)
add_cython_ext("xpra.x11.bindings.res_bindings",
["xpra/x11/bindings/res_bindings.pyx"],
**pkgconfig("x11", "xres")
)
if xinput_ENABLED:
add_cython_ext("xpra.x11.bindings.xi2_bindings",
["xpra/x11/bindings/xi2_bindings.pyx"],
Expand Down
3 changes: 2 additions & 1 deletion xpra/server/window/metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,12 @@ def raw():
return {}
return {propname: ""}
return {propname: v}
if propname in ("pid", "workspace", "bypass-compositor", "depth", "opacity", "quality", "speed"):
if propname in ("pid", "wm-pid", "workspace", "bypass-compositor", "depth", "opacity", "quality", "speed"):
v = raw()
assert v is not None, "%s is None!" % propname
default_value = {
"pid" : 0,
"wm-pid" : 0,
"workspace" : WORKSPACE_UNSET,
"bypass-compositor" : 0,
"depth" : 24,
Expand Down
121 changes: 121 additions & 0 deletions xpra/x11/bindings/res_bindings.pyx
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
# This file is part of Xpra.
# Copyright (C) 2021 Antoine Martin <antoine@xpra.org>
# Xpra is released under the terms of the GNU GPL v2, or, at your option, any
# later version. See the file COPYING for details.

from xpra.x11.bindings.core_bindings cimport X11CoreBindingsInstance

from xpra.log import Logger
log = Logger("x11", "bindings")

ctypedef int pid_t
ctypedef unsigned long CARD32

cdef extern from "X11/X.h":
unsigned long Success

######
# Xlib primitives and constants
######
cdef extern from "X11/Xlib.h":
ctypedef struct Display:
pass
ctypedef CARD32 XID
ctypedef unsigned long int Atom
ctypedef int Bool
ctypedef int Status
ctypedef int Window


###################################
# XRes
###################################
cdef extern from "X11/extensions/XRes.h":
ctypedef enum XResClientIdType:
XRES_CLIENT_ID_XID
XRES_CLIENT_ID_PID
XRES_CLIENT_ID_NR

ctypedef enum XResClientIdMask:
XRES_CLIENT_ID_XID_MASK = 1 << XRES_CLIENT_ID_XID
XRES_CLIENT_ID_PID_MASK = 1 << XRES_CLIENT_ID_PID

ctypedef struct XResClientIdSpec:
XID client
unsigned int mask

ctypedef struct XResResourceIdSpec:
XID resource
Atom type

ctypedef struct XResClientIdValue:
XResClientIdSpec spec
long length
void *value

ctypedef struct XResClient:
XID resource_base
XID resource_mask

ctypedef struct XResType:
Atom resource_type
unsigned int count

Status XResQueryClientIds(Display *dpy, long num_specs, XResClientIdSpec *client_specs,
long *num_ids, XResClientIdValue **client_ids)
void XResClientIdsDestroy(long num_ids, XResClientIdValue *client_ids)
XResClientIdType XResGetClientIdType(XResClientIdValue* value)
pid_t XResGetClientPid(XResClientIdValue* value)

Bool XResQueryExtension(Display *dpy, int *event_base_return, int *error_base_return)
Status XResQueryVersion(Display *dpy, int *major_version_return, int *minor_version_return)



cdef ResBindingsInstance singleton = None
def ResBindings():
global singleton
if singleton is None:
singleton = ResBindingsInstance()
return singleton

cdef class ResBindingsInstance(X11CoreBindingsInstance):

def __init__(self):
pass

def __repr__(self):
return "XResBindings(%s)" % self.display_name

def check_xres(self, min_version=(1, 2)):
cdef int event_base = 0, ignored = 0, cmajor = 0, cminor = 0
cdef Bool r = XResQueryExtension(self.display, &event_base, &ignored)
log("XResQueryExtension()=%i", r)
if not r:
return False
log("found XRes extension")
if not XResQueryVersion(self.display, &cmajor, &cminor):
return False
log("found XRes extension version %i.%i", cmajor, cminor)
return (cmajor, cminor) >= min_version

def get_pid(self, Window xid):
cdef XResClientIdSpec client_spec
client_spec.client = xid
client_spec.mask = XRES_CLIENT_ID_PID_MASK

cdef long num_ids
cdef XResClientIdValue *client_ids
if XResQueryClientIds(self.display, 1, &client_spec, &num_ids, &client_ids):
log.error("Error: failed to query pid for window %i", xid)
return 0

cdef int pid = 0
for i in range(num_ids):
if client_ids[i].spec.mask == XRES_CLIENT_ID_PID_MASK:
pid = XResGetClientPid(&client_ids[i])
if pid>=0:
break
if num_ids:
XResClientIdsDestroy(num_ids, client_ids)
return pid
54 changes: 39 additions & 15 deletions xpra/x11/models/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
from xpra.gtk_common.gobject_util import one_arg_signal, two_arg_signal
from xpra.gtk_common.error import XError, xsync, xswallow
from xpra.x11.bindings.window_bindings import X11WindowBindings, constants, SHAPE_KIND #@UnresolvedImport
from xpra.x11.bindings.res_bindings import ResBindings #@UnresolvedImport
from xpra.x11.models.model_stub import WindowModelStub
from xpra.x11.gtk_x11.composite import CompositeHelper
from xpra.x11.gtk_x11.prop import prop_get, prop_set, prop_type_get, PYTHON_TYPES
Expand All @@ -34,6 +35,11 @@
em = Gdk.EventMask
ADDMASK = em.STRUCTURE_MASK | em.PROPERTY_CHANGE_MASK | em.FOCUS_CHANGE_MASK | em.POINTER_MOTION_MASK

XRes = ResBindings()
if not XRes.check_xres():
log.warn("Warning: X Resource Extension missing or too old")
XRes = None

FORCE_QUIT = envbool("XPRA_FORCE_QUIT", True)
XSHAPE = envbool("XPRA_XSHAPE", True)
FRAME_EXTENTS = envbool("XPRA_FRAME_EXTENTS", True)
Expand Down Expand Up @@ -128,11 +134,16 @@ class CoreX11WindowModel(WindowModelStub):
"client-machine": (GObject.TYPE_PYOBJECT,
"Host where client process is running", "",
GObject.ParamFlags.READABLE),
#from _NET_WM_PID
#from XResGetClientPid
"pid": (GObject.TYPE_INT,
"PID of owning process", "",
-1, 65535, -1,
GObject.ParamFlags.READABLE),
#from _NET_WM_PID
"wm-pid": (GObject.TYPE_INT,
"PID of owning process", "",
-1, 65535, -1,
GObject.ParamFlags.READABLE),
#from _NET_WM_NAME or WM_NAME
"title": (GObject.TYPE_PYOBJECT,
"Window title (unicode or None)", "",
Expand Down Expand Up @@ -193,7 +204,7 @@ class CoreX11WindowModel(WindowModelStub):
#things that we expose:
_property_names = [
"xid", "depth", "has-alpha",
"client-machine", "pid",
"client-machine", "pid", "wm-pid",
"title", "role",
"command", "shape",
"class-instance", "protocols",
Expand Down Expand Up @@ -371,9 +382,11 @@ def _read_initial_X11_properties(self):
metalog("read_initial_X11_properties() core")
#immutable ones:
depth = X11Window.get_depth(self.xid)
metalog("initial X11 properties: xid=%#x, depth=%i", self.xid, depth)
pid = XRes.get_pid(self.xid) if XRes else -1
metalog("initial X11 properties: xid=%#x, depth=%i, pid=%i", self.xid, depth, pid)
self._updateprop("depth", depth)
self._updateprop("xid", self.xid)
self._updateprop("pid", pid)
self._updateprop("has-alpha", depth==32)
self._updateprop("allowed-actions", self._DEFAULT_NET_WM_ALLOWED_ACTIONS)
self._updateprop("shape", self._read_xshape())
Expand Down Expand Up @@ -552,7 +565,7 @@ def _handle_property_change(self, name):
def _handle_pid_change(self):
pid = self.prop_get("_NET_WM_PID", "u32") or -1
metalog("_NET_WM_PID=%s", pid)
self._updateprop("pid", pid)
self._updateprop("wm-pid", pid)

def _handle_client_machine_change(self):
client_machine = self.prop_get("WM_CLIENT_MACHINE", "latin1")
Expand Down Expand Up @@ -759,7 +772,7 @@ def request_close(self):
xid = self.get_property("xid")
if FORCE_QUIT:
log.info("window %#x ('%s') does not support WM_DELETE_WINDOW", xid, title)
log.info(" using force_quit")
log.info(" using force quit")
# You don't wanna play ball? Then no more Mr. Nice Guy!
self.force_quit()
else:
Expand All @@ -771,18 +784,29 @@ def send_delete(self):
with xswallow:
send_wm_delete_window(self.client_window)

def XKill(self):
with xswallow:
X11Window.XKillClient(self.xid)

def force_quit(self):
pid = self.get_property("pid")
machine = self.get_property("client-machine")
pid = self.get_property("pid")
if pid<=0:
#we could fallback to _NET_WM_PID
#but that would be unsafe
log.warn("Warning: cannot terminate window %#x, no pid found", self.xid)
if machine:
log.warn(" WM_CLIENT_MACHINE=%s", machine)
pid = self.get_property("wm-pid")
if pid>0:
log.warn(" _NET_WM_PID=%s", pid)
return
if pid==os.getpid():
log.warn("Warning: force_quit is refusing to kill ourselves!")
return
localhost = gethostname()
log("force_quit() pid=%s, machine=%s, localhost=%s", pid, machine, localhost)
def XKill():
with xswallow:
X11Window.XKillClient(self.xid)
if pid > 0 and machine is not None and machine == localhost:
if pid==os.getpid():
log.warn("Warning: force_quit is refusing to kill ourselves!")
return
if machine is not None and machine == localhost:
if self._kill_count==0:
#first time around: just send a SIGINT and hope for the best
try:
Expand All @@ -797,7 +821,7 @@ def XKill():
except OSError as e:
log.warn("Warning: failed to kill(SIGKILL) client with pid %s", pid)
log.warn(" %s", e)
XKill()
self.XKill()
self._kill_count += 1
return
XKill()
self.XKill()

0 comments on commit 234ec06

Please sign in to comment.