mirror of https://github.com/seebye/ueberzug
drop python-xlib
Python-xlib misses some essential features like shm support. This is why the Xshm module was written, but this leads to redundant dependencies. So this commit removes python-xlib as dependency. During the translation of the code the determination of the pid of a window was also improved. The XRes extension is now used to determine the pid of a window.pull/146/head
parent
08fb245467
commit
11aad51903
@ -1 +1,3 @@
|
||||
include ueberzug/lib/lib.sh
|
||||
include ueberzug/X/*.h
|
||||
include ueberzug/X/*.c
|
||||
|
@ -0,0 +1,36 @@
|
||||
#include "python.h"
|
||||
#include "display.h"
|
||||
#include "window.h"
|
||||
#include "Xshm.h"
|
||||
|
||||
|
||||
static PyModuleDef module = {
|
||||
PyModuleDef_HEAD_INIT,
|
||||
.m_name = "ueberzug.X",
|
||||
.m_doc = "Modul which implements the interaction with the Xshm extension.",
|
||||
.m_size = -1,
|
||||
};
|
||||
|
||||
|
||||
PyMODINIT_FUNC
|
||||
PyInit_X(void) {
|
||||
PyObject *module_instance;
|
||||
if (PyType_Ready(&DisplayType) < 0 ||
|
||||
PyType_Ready(&WindowType) < 0 ||
|
||||
PyType_Ready(&ImageType) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
module_instance = PyModule_Create(&module);
|
||||
if (module_instance == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Py_INCREF(&DisplayType);
|
||||
Py_INCREF(&WindowType);
|
||||
Py_INCREF(&ImageType);
|
||||
PyModule_AddObject(module_instance, "Display", (PyObject*)&DisplayType);
|
||||
PyModule_AddObject(module_instance, "OverlayWindow", (PyObject*)&WindowType);
|
||||
PyModule_AddObject(module_instance, "Image", (PyObject*)&ImageType);
|
||||
return module_instance;
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
#ifndef __X_H__
|
||||
#define __X_H__
|
||||
#include "python.h"
|
||||
|
||||
|
||||
PyModuleDef module;
|
||||
#endif
|
@ -0,0 +1,7 @@
|
||||
#ifndef __XSHM_H__
|
||||
#define __XSHM_H__
|
||||
#include "python.h"
|
||||
|
||||
|
||||
PyTypeObject ImageType;
|
||||
#endif
|
@ -0,0 +1,276 @@
|
||||
#include "python.h"
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/extensions/XRes.h>
|
||||
#include <X11/extensions/XShm.h>
|
||||
|
||||
#include "util.h"
|
||||
#include "display.h"
|
||||
|
||||
|
||||
#define INVALID_PID (pid_t)-1
|
||||
|
||||
|
||||
#define REOPEN_DISPLAY(display) \
|
||||
if (display != NULL) { \
|
||||
XCloseDisplay(display); \
|
||||
} \
|
||||
display = XOpenDisplay(NULL);
|
||||
|
||||
#define CLOSE_DISPLAY(display) \
|
||||
if (display != NULL) { \
|
||||
XCloseDisplay(display); \
|
||||
display = NULL; \
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
Display_init(DisplayObject *self, PyObject *args, PyObject *kwds) {
|
||||
// Two connections are opened as
|
||||
// a death lock can occur
|
||||
// if you listen for events
|
||||
// (this will happen in parallel in asyncio worker threads)
|
||||
// and request information (e.g. XGetGeometry)
|
||||
// simultaneously.
|
||||
REOPEN_DISPLAY(self->event_display);
|
||||
REOPEN_DISPLAY(self->info_display);
|
||||
|
||||
if (self->event_display == NULL ||
|
||||
self->info_display == NULL) {
|
||||
raiseInit(OSError, "could not open a connection to the X server");
|
||||
}
|
||||
|
||||
int _;
|
||||
if (!XResQueryExtension(self->info_display, &_, &_)) {
|
||||
raiseInit(OSError, "the extension XRes is required");
|
||||
}
|
||||
|
||||
if (!XShmQueryExtension(self->event_display)) {
|
||||
raiseInit(OSError, "the extension Xext is required");
|
||||
}
|
||||
|
||||
int screen = XDefaultScreen(self->info_display);
|
||||
self->screen_width = XDisplayWidth(self->info_display, screen);
|
||||
self->screen_height = XDisplayHeight(self->info_display, screen);
|
||||
self->bitmap_pad = XBitmapPad(self->info_display);
|
||||
self->bitmap_unit = XBitmapUnit(self->info_display);
|
||||
|
||||
self->wm_class = XInternAtom(self->info_display, "WM_CLASS", False);
|
||||
self->wm_name = XInternAtom(self->info_display, "WM_NAME", False);
|
||||
self->wm_locale_name = XInternAtom(self->info_display, "WM_LOCALE_NAME", False);
|
||||
self->wm_normal_hints = XInternAtom(self->info_display, "WM_NORMAL_HINTS", False);
|
||||
|
||||
Py_INIT_RETURN_SUCCESS;
|
||||
}
|
||||
|
||||
static void
|
||||
Display_dealloc(DisplayObject *self) {
|
||||
CLOSE_DISPLAY(self->event_display);
|
||||
CLOSE_DISPLAY(self->info_display);
|
||||
Py_TYPE(self)->tp_free((PyObject*)self);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
has_property(DisplayObject *self, Window window, Atom property) {
|
||||
Atom actual_type_return;
|
||||
int actual_format_return;
|
||||
unsigned long bytes_after_return;
|
||||
unsigned char* prop_to_return = NULL;
|
||||
unsigned long nitems_return;
|
||||
|
||||
int status = XGetWindowProperty(
|
||||
self->info_display, window, property, 0,
|
||||
0L, False,
|
||||
AnyPropertyType,
|
||||
&actual_type_return,
|
||||
&actual_format_return,
|
||||
&nitems_return, &bytes_after_return, &prop_to_return);
|
||||
if (status == Success && prop_to_return) {
|
||||
XFree(prop_to_return);
|
||||
}
|
||||
return status == Success && !(actual_type_return == None && actual_format_return == 0);
|
||||
}
|
||||
|
||||
|
||||
static PyObject *
|
||||
Display_get_child_window_ids(DisplayObject *self, PyObject *args, PyObject *kwds) {
|
||||
static char *kwlist[] = {"parent_id", NULL};
|
||||
Window parent = XDefaultRootWindow(self->info_display);
|
||||
Window _, *children;
|
||||
unsigned int children_count;
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(
|
||||
args, kwds, "|k", kwlist,
|
||||
&parent)) {
|
||||
Py_RETURN_ERROR;
|
||||
}
|
||||
|
||||
if (!XQueryTree(
|
||||
self->info_display, parent,
|
||||
&_, &_, &children, &children_count)) {
|
||||
raise(OSError, "failed to query child windows of %lu", parent);
|
||||
}
|
||||
|
||||
PyObject *child_ids = PyList_New(0);
|
||||
if (children) {
|
||||
for (unsigned int i = 0; i < children_count; i++) {
|
||||
// assume that windows without essential properties
|
||||
// like the window title aren't shown to the user
|
||||
int is_helper_window = (
|
||||
!has_property(self, children[i], self->wm_class) &&
|
||||
!has_property(self, children[i], self->wm_name) &&
|
||||
!has_property(self, children[i], self->wm_locale_name) &&
|
||||
!has_property(self, children[i], self->wm_normal_hints));
|
||||
if (is_helper_window) {
|
||||
continue;
|
||||
}
|
||||
PyObject *py_window_id = Py_BuildValue("k", children[i]);
|
||||
PyList_Append(child_ids, py_window_id);
|
||||
Py_XDECREF(py_window_id);
|
||||
}
|
||||
XFree(children);
|
||||
}
|
||||
|
||||
return child_ids;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
Display_get_window_pid(DisplayObject *self, PyObject *args, PyObject *kwds) {
|
||||
static char *kwlist[] = {"window_id", NULL};
|
||||
Window window;
|
||||
long num_ids;
|
||||
int num_specs = 1;
|
||||
XResClientIdValue *client_ids;
|
||||
XResClientIdSpec client_specs[1];
|
||||
pid_t window_creator_pid = INVALID_PID;
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(
|
||||
args, kwds, "k", kwlist,
|
||||
&window)) {
|
||||
Py_RETURN_ERROR;
|
||||
}
|
||||
|
||||
client_specs[0].client = window;
|
||||
client_specs[0].mask = XRES_CLIENT_ID_PID_MASK;
|
||||
if (Success != XResQueryClientIds(
|
||||
self->info_display, num_specs, client_specs,
|
||||
&num_ids, &client_ids)) {
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
for(int i = 0; i < num_ids; i++) {
|
||||
XResClientIdValue *value = client_ids + i;
|
||||
XResClientIdType type = XResGetClientIdType(value);
|
||||
|
||||
if (type == XRES_CLIENT_ID_PID) {
|
||||
window_creator_pid = XResGetClientPid(value);
|
||||
}
|
||||
}
|
||||
|
||||
XFree(client_ids);
|
||||
|
||||
if (window_creator_pid != INVALID_PID) {
|
||||
return Py_BuildValue("i", window_creator_pid);
|
||||
}
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
Display_wait_for_event(DisplayObject *self) {
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
XEvent event;
|
||||
XPeekEvent(self->event_display, &event);
|
||||
Py_END_ALLOW_THREADS
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
Display_discard_event(DisplayObject *self) {
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
XEvent event;
|
||||
XNextEvent(self->event_display, &event);
|
||||
Py_END_ALLOW_THREADS
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
Display_get_bitmap_format_scanline_pad(DisplayObject *self, void *closure) {
|
||||
return Py_BuildValue("i", self->bitmap_pad);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
Display_get_bitmap_format_scanline_unit(DisplayObject *self, void *closure) {
|
||||
return Py_BuildValue("i", self->bitmap_unit);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
Display_get_screen_width(DisplayObject *self, void *closure) {
|
||||
return Py_BuildValue("i", self->screen_width);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
Display_get_screen_height(DisplayObject *self, void *closure) {
|
||||
return Py_BuildValue("i", self->screen_height);
|
||||
}
|
||||
|
||||
|
||||
static PyGetSetDef Display_properties[] = {
|
||||
{"bitmap_format_scanline_pad", (getter)Display_get_bitmap_format_scanline_pad,
|
||||
.doc = "int: Each scanline must be padded to a multiple of bits of this value."},
|
||||
{"bitmap_format_scanline_unit", (getter)Display_get_bitmap_format_scanline_unit,
|
||||
.doc = "int:\n"
|
||||
" The size of a bitmap's scanline unit in bits.\n"
|
||||
" The scanline is calculated in multiples of this value."},
|
||||
{"screen_width", (getter)Display_get_screen_width,
|
||||
.doc = "int: The width of the default screen at the time the connection to X11 was opened."},
|
||||
{"screen_height", (getter)Display_get_screen_width,
|
||||
.doc = "int: The height of the default screen at the time the connection to X11 was opened."},
|
||||
{NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
|
||||
static PyMethodDef Display_methods[] = {
|
||||
{"wait_for_event", (PyCFunction)Display_wait_for_event,
|
||||
METH_NOARGS,
|
||||
"Waits for an event to occur. till an event occur."},
|
||||
{"discard_event", (PyCFunction)Display_discard_event,
|
||||
METH_NOARGS,
|
||||
"Discards the first event from the event queue."},
|
||||
{"get_child_window_ids", (PyCFunction)Display_get_child_window_ids,
|
||||
METH_VARARGS | METH_KEYWORDS,
|
||||
"Queries for the ids of the children of the window with the passed identifier.\n"
|
||||
"\n"
|
||||
"Args:\n"
|
||||
" parent_id (int): optional\n"
|
||||
" the id of the window for which to query for the ids of its children\n"
|
||||
" if it's not specified the id of the default root window will be used\n"
|
||||
"\n"
|
||||
"Returns:\n"
|
||||
" list of ints: the ids of the child windows"},
|
||||
{"get_window_pid", (PyCFunction)Display_get_window_pid,
|
||||
METH_VARARGS | METH_KEYWORDS,
|
||||
"Tries to figure out the pid of the process which created the window with the passed id.\n"
|
||||
"\n"
|
||||
"Args:\n"
|
||||
" window_id (int): the window id for which to retrieve information\n"
|
||||
"\n"
|
||||
"Returns:\n"
|
||||
" int or None: the pid of the creator of the window"},
|
||||
{NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
PyTypeObject DisplayType = {
|
||||
PyVarObject_HEAD_INIT(NULL, 0)
|
||||
.tp_name = "ueberzug.X.Display",
|
||||
.tp_doc = "X11 display\n",
|
||||
.tp_basicsize = sizeof(DisplayObject),
|
||||
.tp_itemsize = 0,
|
||||
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
|
||||
.tp_new = PyType_GenericNew,
|
||||
.tp_init = (initproc)Display_init,
|
||||
.tp_dealloc = (destructor)Display_dealloc,
|
||||
.tp_getset = Display_properties,
|
||||
.tp_methods = Display_methods,
|
||||
};
|
@ -0,0 +1,29 @@
|
||||
#ifndef __DISPLAY_H__
|
||||
#define __DISPLAY_H__
|
||||
|
||||
#include "python.h"
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
// Always use the event_display
|
||||
// except for functions which return information
|
||||
// e.g. XGetGeometry.
|
||||
Display *event_display;
|
||||
Display *info_display;
|
||||
int bitmap_pad;
|
||||
int bitmap_unit;
|
||||
int screen;
|
||||
int screen_width;
|
||||
int screen_height;
|
||||
|
||||
Atom wm_class;
|
||||
Atom wm_name;
|
||||
Atom wm_locale_name;
|
||||
Atom wm_normal_hints;
|
||||
} DisplayObject;
|
||||
PyTypeObject DisplayType;
|
||||
|
||||
#endif
|
@ -0,0 +1,7 @@
|
||||
#ifndef __MATH_H__
|
||||
#define __MATH_H__
|
||||
|
||||
#define min(a,b) (((a) < (b)) ? (a) : (b))
|
||||
#define max(a,b) (((a) > (b)) ? (a) : (b))
|
||||
|
||||
#endif
|
@ -0,0 +1,11 @@
|
||||
#ifndef __PYTHON_H__
|
||||
#define __PYTHON_H__
|
||||
|
||||
#ifndef __linux__
|
||||
#error OS unsupported
|
||||
#endif
|
||||
|
||||
#define PY_SSIZE_T_CLEAN // Make "s#" use Py_ssize_t rather than int.
|
||||
#include <Python.h>
|
||||
|
||||
#endif
|
@ -0,0 +1,28 @@
|
||||
#ifndef __UTIL_H__
|
||||
#define __UTIL_H__
|
||||
|
||||
#define Py_INIT_ERROR -1
|
||||
#define Py_INIT_SUCCESS 0
|
||||
#define Py_ERROR NULL
|
||||
#define Py_RETURN_ERROR return Py_ERROR
|
||||
#define Py_INIT_RETURN_ERROR return Py_INIT_ERROR
|
||||
#define Py_INIT_RETURN_SUCCESS return Py_INIT_SUCCESS
|
||||
|
||||
#define __raise(return_value, Exception, message...) { \
|
||||
char errorMessage[500]; \
|
||||
snprintf(errorMessage, 500, message); \
|
||||
PyErr_SetString( \
|
||||
PyExc_##Exception, \
|
||||
errorMessage); \
|
||||
return return_value; \
|
||||
}
|
||||
#define raise(Exception, message...) __raise(Py_ERROR, Exception, message)
|
||||
#define raiseInit(Exception, message...) __raise(Py_INIT_ERROR, Exception, message)
|
||||
|
||||
#define ARRAY_LENGTH(stack_array) \
|
||||
(sizeof stack_array \
|
||||
? sizeof stack_array / sizeof *stack_array \
|
||||
: 0)
|
||||
|
||||
|
||||
#endif
|
@ -0,0 +1,316 @@
|
||||
#include "python.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xutil.h>
|
||||
#include <X11/extensions/shape.h>
|
||||
|
||||
#include "util.h"
|
||||
#include "display.h"
|
||||
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
DisplayObject *display_pyobject;
|
||||
Window parent;
|
||||
Window window;
|
||||
unsigned int width;
|
||||
unsigned int height;
|
||||
} WindowObject;
|
||||
|
||||
|
||||
static inline Display *
|
||||
get_event_display(WindowObject *self) {
|
||||
return self->display_pyobject->event_display;
|
||||
}
|
||||
|
||||
static inline Display *
|
||||
get_info_display(WindowObject *self) {
|
||||
return self->display_pyobject->info_display;
|
||||
}
|
||||
|
||||
static void
|
||||
Window_create(WindowObject *self) {
|
||||
Window _0; int _1; unsigned int _2;
|
||||
XGetGeometry(
|
||||
get_info_display(self),
|
||||
self->parent,
|
||||
&_0, &_1, &_1,
|
||||
&self->width, &self->height,
|
||||
&_2, &_2);
|
||||
|
||||
Display *display = get_event_display(self);
|
||||
int screen = XDefaultScreen(display);
|
||||
Visual *visual = XDefaultVisual(display, screen);
|
||||
unsigned long attributes_mask =
|
||||
CWEventMask | CWBackPixel | CWColormap | CWBorderPixel;
|
||||
XSetWindowAttributes attributes;
|
||||
attributes.event_mask = ExposureMask;
|
||||
attributes.colormap = XCreateColormap(
|
||||
display, XDefaultRootWindow(display),
|
||||
visual, AllocNone);
|
||||
attributes.background_pixel = 0;
|
||||
attributes.border_pixel = 0;
|
||||
|
||||
self->window = XCreateWindow(
|
||||
display, self->parent,
|
||||
0, 0, self->width, self->height, 0,
|
||||
DefaultDepth(display, screen),
|
||||
InputOutput, visual,
|
||||
attributes_mask, &attributes);
|
||||
}
|
||||
|
||||
static void
|
||||
set_subscribed_events(Display *display, Window window, long event_mask) {
|
||||
XSetWindowAttributes attributes;
|
||||
attributes.event_mask = event_mask;
|
||||
XChangeWindowAttributes(
|
||||
display, window,
|
||||
CWEventMask , &attributes);
|
||||
}
|
||||
|
||||
static void
|
||||
Window_finalise(WindowObject *self) {
|
||||
if (self->window) {
|
||||
Display *display = get_event_display(self);
|
||||
set_subscribed_events(
|
||||
display, self->parent, NoEventMask);
|
||||
XDestroyWindow(display, self->window);
|
||||
XFlush(display);
|
||||
}
|
||||
|
||||
Py_CLEAR(self->display_pyobject);
|
||||
self->window = 0;
|
||||
}
|
||||
|
||||
static inline void
|
||||
set_xshape_mask(Display *display, Window window, int kind, XRectangle area[], int area_length) {
|
||||
XShapeCombineRectangles(
|
||||
display, window,
|
||||
kind,
|
||||
0, 0, area, area_length,
|
||||
ShapeSet, 0);
|
||||
}
|
||||
|
||||
static inline void
|
||||
set_input_mask(Display *display, Window window, XRectangle area[], int area_length) {
|
||||
set_xshape_mask(
|
||||
display, window, ShapeInput, area, area_length);
|
||||
}
|
||||
|
||||
static inline void
|
||||
set_visibility_mask(Display *display, Window window, XRectangle area[], int area_length) {
|
||||
set_xshape_mask(
|
||||
display, window, ShapeBounding, area, area_length);
|
||||
}
|
||||
|
||||
static int
|
||||
Window_init(WindowObject *self, PyObject *args, PyObject *kwds) {
|
||||
static XRectangle empty_area[0] = {};
|
||||
static char *kwlist[] = {"display", "parent", NULL};
|
||||
PyObject *display_pyobject;
|
||||
Window parent;
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(
|
||||
args, kwds, "O!k", kwlist,
|
||||
&DisplayType, &display_pyobject, &parent)) {
|
||||
Py_INIT_RETURN_ERROR;
|
||||
}
|
||||
|
||||
if (self->display_pyobject) {
|
||||
Window_finalise(self);
|
||||
}
|
||||
|
||||
Py_INCREF(display_pyobject);
|
||||
self->display_pyobject = (DisplayObject*)display_pyobject;
|
||||
Display *display = get_event_display(self);
|
||||
self->parent = parent;
|
||||
Window_create(self);
|
||||
set_subscribed_events(
|
||||
display, self->parent, StructureNotifyMask);
|
||||
set_input_mask(
|
||||
display, self->window,
|
||||
empty_area, ARRAY_LENGTH(empty_area));
|
||||
set_visibility_mask(
|
||||
display, self->window,
|
||||
empty_area, ARRAY_LENGTH(empty_area));
|
||||
XMapWindow(display, self->window);
|
||||
|
||||
Py_INIT_RETURN_SUCCESS;
|
||||
}
|
||||
|
||||
static void
|
||||
Window_dealloc(WindowObject *self) {
|
||||
Window_finalise(self);
|
||||
Py_TYPE(self)->tp_free((PyObject*)self);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
Window_set_visibility_mask(WindowObject *self, PyObject *args, PyObject *kwds) {
|
||||
static char *kwlist[] = {"area", NULL};
|
||||
PyObject *py_area;
|
||||
Py_ssize_t area_length;
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(
|
||||
args, kwds, "O!", kwlist,
|
||||
&PyList_Type, &py_area)) {
|
||||
Py_RETURN_ERROR;
|
||||
}
|
||||
|
||||
area_length = PyList_Size(py_area);
|
||||
XRectangle area[area_length];
|
||||
|
||||
for (Py_ssize_t i = 0; i < area_length; i++) {
|
||||
short x, y;
|
||||
unsigned short width, height;
|
||||
PyObject *py_rectangle = PyList_GetItem(py_area, i);
|
||||
|
||||
if (!PyObject_TypeCheck(py_rectangle, &PyTuple_Type)) {
|
||||
raise(ValueError, "Expected a list of a tuple of ints!");
|
||||
}
|
||||
if (!PyArg_ParseTuple(
|
||||
py_rectangle, "hhHH",
|
||||
&x, &y, &width, &height)) {
|
||||
raise(ValueError,
|
||||
"Expected a rectangle to be a "
|
||||
"tuple of (x: int, y: int, width: int, height: int)!");
|
||||
}
|
||||
|
||||
area[i].x = x;
|
||||
area[i].y = y;
|
||||
area[i].width = width;
|
||||
area[i].height = height;
|
||||
}
|
||||
|
||||
set_visibility_mask(
|
||||
get_event_display(self),
|
||||
self->window,
|
||||
area, area_length);
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
Window_draw(WindowObject *self) {
|
||||
XFlush(get_event_display(self));
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
Window_get_id(WindowObject *self, void *closure) {
|
||||
return Py_BuildValue("k", self->window);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
Window_get_parent_id(WindowObject *self, void *closure) {
|
||||
return Py_BuildValue("k", self->parent);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
Window_get_width(WindowObject *self, void *closure) {
|
||||
return Py_BuildValue("I", self->width);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
Window_get_height(WindowObject *self, void *closure) {
|
||||
return Py_BuildValue("I", self->height);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
Window_process_event(WindowObject *self) {
|
||||
XEvent event;
|
||||
XAnyEvent *metadata = &event.xany;
|
||||
Display *display = get_event_display(self);
|
||||
|
||||
if (!XPending(display)) {
|
||||
Py_RETURN_FALSE;
|
||||
}
|
||||
|
||||
XPeekEvent(display, &event);
|
||||
|
||||
if (! (event.type == Expose && metadata->window == self->window) &&
|
||||
! (event.type == ConfigureNotify && metadata->window == self->parent)) {
|
||||
Py_RETURN_FALSE;
|
||||
}
|
||||
|
||||
XNextEvent(display, &event);
|
||||
|
||||
switch (event.type) {
|
||||
case Expose:
|
||||
if(event.xexpose.count == 0) {
|
||||
Py_XDECREF(PyObject_CallMethod(
|
||||
(PyObject*)self, "draw", NULL));
|
||||
}
|
||||
break;
|
||||
case ConfigureNotify: {
|
||||
unsigned int delta_width =
|
||||
((unsigned int)event.xconfigure.width) - self->width;
|
||||
unsigned int delta_height =
|
||||
((unsigned int)event.xconfigure.height) - self->height;
|
||||
|
||||
if (delta_width != 0 || delta_height != 0) {
|
||||
self->width = (unsigned int)event.xconfigure.width;
|
||||
self->height = (unsigned int)event.xconfigure.height;
|
||||
XResizeWindow(display, self->window, self->width, self->height);
|
||||
}
|
||||
|
||||
if (delta_width > 0 || delta_height > 0) {
|
||||
Py_XDECREF(PyObject_CallMethod(
|
||||
(PyObject*)self, "draw", NULL));
|
||||
}
|
||||
else {
|
||||
XFlush(display);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
Py_RETURN_TRUE;
|
||||
}
|
||||
|
||||
static PyGetSetDef Window_properties[] = {
|
||||
{"id", (getter)Window_get_id, .doc = "int: the X11 id of this window."},
|
||||
{"parent_id", (getter)Window_get_parent_id, .doc = "int: the X11 id of the parent window."},
|
||||
{"width", (getter)Window_get_width, .doc = "int: the width of this window."},
|
||||
{"height", (getter)Window_get_height, .doc = "int: the height of this window."},
|
||||
{NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
static PyMethodDef Window_methods[] = {
|
||||
{"draw", (PyCFunction)Window_draw,
|
||||
METH_NOARGS,
|
||||
"Redraws the window."},
|
||||
{"set_visibility_mask", (PyCFunction)Window_set_visibility_mask,
|
||||
METH_VARARGS | METH_KEYWORDS,
|
||||
"Specifies the part of the window which should be visible.\n"
|
||||
"\n"
|
||||
"Args:\n"
|
||||
" area (tuple of (tuple of (x: int, y: int, width: int, height: int))):\n"
|
||||
" the visible area specified by rectangles"},
|
||||
{"process_event", (PyCFunction)Window_process_event,
|
||||
METH_NOARGS,
|
||||
"Processes the next X11 event if it targets this window.\n"
|
||||
"\n"
|
||||
"Returns:\n"
|
||||
" bool: True if an event was processed"},
|
||||
{NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
PyTypeObject WindowType = {
|
||||
PyVarObject_HEAD_INIT(NULL, 0)
|
||||
.tp_name = "ueberzug.X.OverlayWindow",
|
||||
.tp_doc =
|
||||
"Basic implementation of an overlay window\n"
|
||||
"\n"
|
||||
"Args:\n"
|
||||
" display (ueberzug.X.Display): the X11 display\n"
|
||||
" parent (int): the parent window of this window",
|
||||
.tp_basicsize = sizeof(WindowObject),
|
||||
.tp_itemsize = 0,
|
||||
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
|
||||
.tp_new = PyType_GenericNew,
|
||||
.tp_init = (initproc)Window_init,
|
||||
.tp_dealloc = (destructor)Window_dealloc,
|
||||
.tp_getset = Window_properties,
|
||||
.tp_methods = Window_methods,
|
||||
};
|
@ -0,0 +1,7 @@
|
||||
#ifndef __WINDOW_H__
|
||||
#define __WINDOW_H__
|
||||
#include "python.h"
|
||||
|
||||
|
||||
PyTypeObject WindowType;
|
||||
#endif
|
Loading…
Reference in New Issue