Spaces:
Runtime error
Runtime error
# Xlib.ext.res -- X-Resource extension module | |
# | |
# Copyright (C) 2021 Aleksei Bavshin <alebastr89@gmail.com> | |
# | |
# This library is free software; you can redistribute it and/or | |
# modify it under the terms of the GNU Lesser General Public License | |
# as published by the Free Software Foundation; either version 2.1 | |
# of the License, or (at your option) any later version. | |
# | |
# This library is distributed in the hope that it will be useful, | |
# but WITHOUT ANY WARRANTY; without even the implied warranty of | |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | |
# See the GNU Lesser General Public License for more details. | |
# | |
# You should have received a copy of the GNU Lesser General Public | |
# License along with this library; if not, write to the | |
# Free Software Foundation, Inc., | |
# 51 Franklin Street, | |
# Fifth Floor, | |
# Boston, MA 02110-1301 USA | |
"""X-Resource extension allows a client to query the X server about its usage | |
of various resources. | |
For detailed description see any of the following documents. | |
Protocol specification: | |
https://www.x.org/releases/current/doc/resourceproto/resproto.txt | |
XCB Protocol specification: | |
https://cgit.freedesktop.org/xcb/proto/tree/src/res.xml | |
""" | |
from Xlib.protocol import rq | |
RES_MAJOR_VERSION = 1 | |
RES_MINOR_VERSION = 2 | |
extname = "X-Resource" | |
# v1.0 | |
ResQueryVersion = 0 | |
ResQueryClients = 1 | |
ResQueryClientResources = 2 | |
ResQueryClientPixmapBytes = 3 | |
# v1.2 | |
ResQueryClientIds = 4 | |
ResQueryResourceBytes = 5 | |
class QueryVersion(rq.ReplyRequest): | |
_request = rq.Struct( | |
rq.Card8("opcode"), | |
rq.Opcode(ResQueryVersion), | |
rq.RequestLength(), | |
rq.Card8("client_major"), | |
rq.Card8("client_minor"), | |
rq.Pad(2)) | |
_reply = rq.Struct( | |
rq.ReplyCode(), | |
rq.Pad(1), | |
rq.Card16("sequence_number"), | |
rq.ReplyLength(), | |
rq.Card16("server_major"), | |
rq.Card16("server_minor"), | |
rq.Pad(20)) | |
def query_version(self, client_major=RES_MAJOR_VERSION, | |
client_minor=RES_MINOR_VERSION): | |
""" Query the protocol version supported by the X server. | |
The client sends the highest supported version to the server and the | |
server sends the highest version it supports, but no higher than the | |
requested version.""" | |
return QueryVersion( | |
display=self.display, | |
opcode=self.display.get_extension_major(extname), | |
client_major=client_major, | |
client_minor=client_minor) | |
Client = rq.Struct( | |
rq.Card32("resource_base"), | |
rq.Card32("resource_mask")) | |
class QueryClients(rq.ReplyRequest): | |
_request = rq.Struct( | |
rq.Card8("opcode"), | |
rq.Opcode(ResQueryClients), | |
rq.RequestLength()) | |
_reply = rq.Struct( | |
rq.ReplyCode(), | |
rq.Pad(1), | |
rq.Card16("sequence_number"), | |
rq.ReplyLength(), | |
rq.LengthOf("clients", 4), | |
rq.Pad(20), | |
rq.List("clients", Client)) | |
def query_clients(self): | |
"""Request the list of all currently connected clients.""" | |
return QueryClients( | |
display=self.display, | |
opcode=self.display.get_extension_major(extname)) | |
Type = rq.Struct( | |
rq.Card32("resource_type"), | |
rq.Card32("count")) | |
class QueryClientResources(rq.ReplyRequest): | |
_request = rq.Struct( | |
rq.Card8("opcode"), | |
rq.Opcode(ResQueryClientResources), | |
rq.RequestLength(), | |
rq.Card32("client")) | |
_reply = rq.Struct( | |
rq.ReplyCode(), | |
rq.Pad(1), | |
rq.Card16("sequence_number"), | |
rq.ReplyLength(), | |
rq.LengthOf("types", 4), | |
rq.Pad(20), | |
rq.List("types", Type)) | |
def query_client_resources(self, client): | |
"""Request the number of resources owned by a client. | |
The server will return the counts of each type of resource. | |
""" | |
return QueryClientResources( | |
display=self.display, | |
opcode=self.display.get_extension_major(extname), | |
client=client) | |
class QueryClientPixmapBytes(rq.ReplyRequest): | |
_request = rq.Struct( | |
rq.Card8("opcode"), | |
rq.Opcode(ResQueryClientPixmapBytes), | |
rq.RequestLength(), | |
rq.Card32("client")) | |
_reply = rq.Struct( | |
rq.ReplyCode(), | |
rq.Pad(1), | |
rq.Card16("sequence_number"), | |
rq.ReplyLength(), | |
rq.Card32("bytes"), | |
rq.Card32("bytes_overflow"), | |
rq.Pad(16)) | |
def query_client_pixmap_bytes(self, client): | |
"""Query the pixmap usage of some client. | |
The returned number is a sum of memory usage of each pixmap that can be | |
attributed to the given client. | |
""" | |
return QueryClientPixmapBytes( | |
display=self.display, | |
opcode=self.display.get_extension_major(extname), | |
client=client) | |
class SizeOf(rq.LengthOf): | |
"""A SizeOf stores the size in bytes of some other Field whose size | |
may vary, e.g. List | |
""" | |
def __init__(self, name, size, item_size): | |
rq.LengthOf.__init__(self, name, size) | |
self.item_size = item_size | |
def parse_value(self, length, display): | |
return length // self.item_size | |
ClientXIDMask = 1 << 0 | |
LocalClientPIDMask = 1 << 1 | |
ClientIdSpec = rq.Struct( | |
rq.Card32("client"), | |
rq.Card32("mask")) | |
ClientIdValue = rq.Struct( | |
rq.Object("spec", ClientIdSpec), | |
SizeOf("value", 4, 4), | |
rq.List("value", rq.Card32Obj)) | |
class QueryClientIds(rq.ReplyRequest): | |
_request = rq.Struct( | |
rq.Card8("opcode"), | |
rq.Opcode(ResQueryClientIds), | |
rq.RequestLength(), | |
rq.LengthOf("specs", 4), | |
rq.List("specs", ClientIdSpec)) | |
_reply = rq.Struct( | |
rq.ReplyCode(), | |
rq.Pad(1), | |
rq.Card16("sequence_number"), | |
rq.ReplyLength(), | |
rq.LengthOf("ids", 4), | |
rq.Pad(20), | |
rq.List("ids", ClientIdValue)) | |
def query_client_ids(self, specs): | |
"""Request to identify a given set of clients with some identification method. | |
The request sends a list of specifiers that select clients and | |
identification methods to server. The server then tries to identify the | |
chosen clients using the identification methods specified for each client. | |
The server returns IDs for those clients that were successfully identified. | |
""" | |
return QueryClientIds( | |
display=self.display, | |
opcode=self.display.get_extension_major(extname), | |
specs=specs) | |
ResourceIdSpec = rq.Struct( | |
rq.Card32("resource"), | |
rq.Card32("type")) | |
ResourceSizeSpec = rq.Struct( | |
# inline struct ResourceIdSpec to work around | |
# a parser bug with nested objects | |
rq.Card32("resource"), | |
rq.Card32("type"), | |
rq.Card32("bytes"), | |
rq.Card32("ref_count"), | |
rq.Card32("use_count")) | |
ResourceSizeValue = rq.Struct( | |
rq.Object("size", ResourceSizeSpec), | |
rq.LengthOf("cross_references", 4), | |
rq.List("cross_references", ResourceSizeSpec)) | |
class QueryResourceBytes(rq.ReplyRequest): | |
_request = rq.Struct( | |
rq.Card8("opcode"), | |
rq.Opcode(ResQueryResourceBytes), | |
rq.RequestLength(), | |
rq.Card32("client"), | |
rq.LengthOf("specs", 4), | |
rq.List("specs", ResourceIdSpec)) | |
_reply = rq.Struct( | |
rq.ReplyCode(), | |
rq.Pad(1), | |
rq.Card16("sequence_number"), | |
rq.ReplyLength(), | |
rq.LengthOf("sizes", 4), | |
rq.Pad(20), | |
rq.List("sizes", ResourceSizeValue)) | |
def query_resource_bytes(self, client, specs): | |
"""Query the sizes of resources from X server. | |
The request sends a list of specifiers that selects resources for size | |
calculation. The server tries to calculate the sizes of chosen resources | |
and returns an estimate for a resource only if the size could be determined | |
""" | |
return QueryResourceBytes( | |
display=self.display, | |
opcode=self.display.get_extension_major(extname), | |
client=client, | |
specs=specs) | |
def init(disp, info): | |
disp.extension_add_method("display", "res_query_version", query_version) | |
disp.extension_add_method("display", "res_query_clients", query_clients) | |
disp.extension_add_method("display", "res_query_client_resources", | |
query_client_resources) | |
disp.extension_add_method("display", "res_query_client_pixmap_bytes", | |
query_client_pixmap_bytes) | |
disp.extension_add_method("display", "res_query_client_ids", | |
query_client_ids) | |
disp.extension_add_method("display", "res_query_resource_bytes", | |
query_resource_bytes) | |