Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

- Handle WM close events (new 'delete_event' signal)

- expose internal 'owner' flag as a python property
- new method X11Window.draw_rectangle() to draw filled rectangles in the window
- provide a default window size to allow X11Window to be constructed with no
  arguments
- fix automatic mouse cursor hiding bugs (should no longer flicker when
  moving the mouse around)
- Make move() and resize() take 2 arguments instead of 1 tuple.


git-svn-id: svn://svn.freevo.org/kaa/trunk/display@4319 a8f5125c-1e01-0410-8897-facf34644b8e
  • Loading branch information...
commit 105b2f668abc1421958cd743f3a5f06181a95e61 1 parent 91fcc05
@jtackaberry jtackaberry authored
View
56 src/x11.py
@@ -101,6 +101,7 @@ class X11Display(object):
XEVENT_UNMAP_NOTIFY = 18
XEVENT_MAP_NOTIFY = 19
XEVENT_CONFIGURE_NOTIFY = 22
+ XEVENT_CLIENT_MESSAGE = 33
#XEVENT_WINDOW_EVENTS = (6, 12, 4, 2, 22, 18, 19)
@@ -224,18 +225,21 @@ def __init__(self, display = None, window = None, **kwargs):
else:
raise ValueError, "window parameter must be an integer."
else:
- assert("size" in kwargs)
if "title" in kwargs:
assert(type(kwargs["title"]) == str)
if "parent" in kwargs:
assert(isinstance(kwargs["parent"], X11Window))
kwargs["parent"] = kwargs["parent"]._window
+ if 'size' not in kwargs:
+ # Dummy size. Don't want to make it 0,0 since we'll barf
+ # if we try to map it.
+ kwargs['size'] = 1, 1
self._window = _X11.X11Window(display._display, kwargs["size"], **kwargs)
self._display = display
display._windows[self._window.wid] = weakref.ref(self)
- self._cursor_hide_timeout = -1
+ self._cursor_hide_timeout = 1
self._cursor_hide_timer = kaa.WeakOneShotTimer(self._cursor_hide_cb)
self._cursor_visible = True
self._fs_size_save = None
@@ -249,6 +253,7 @@ def __init__(self, display = None, window = None, **kwargs):
"map_event", # ?
"unmap_event", # ?
"resize_event", # window resized
+ "delete_event",
"configure_event") # ?
def __str__(self):
@@ -300,10 +305,10 @@ def handle_events(self, events):
for event, data in events:
if event == X11Display.XEVENT_MOTION_NOTIFY:
# Mouse moved, so show cursor.
- if self._cursor_hide_timeout != 0 and not self._cursor_visible:
- self.set_cursor_visible(True)
-
- self._cursor_hide_timer.start(self._cursor_hide_timeout)
+ if not self._cursor_visible:
+ if self._cursor_hide_timeout != 0:
+ self.set_cursor_visible(True)
+ self._cursor_hide_timer.start(self._cursor_hide_timeout)
elif event == X11Display.XEVENT_KEY_PRESS:
key = data["key"]
@@ -338,17 +343,30 @@ def handle_events(self, events):
self.signals["focus_in_event"].emit()
elif event == X11Display.XEVENT_FOCUS_OUT:
self.signals["focus_out_event"].emit()
+ elif event == X11Display.XEVENT_CLIENT_MESSAGE:
+ if data['type'] == 'delete':
+ if len(self.signals['delete_event']) == 0:
+ # Default action on a delete event: just unmap it.
+ self.hide()
+ else:
+ self.signals['delete_event'].emit()
if len(expose_regions) > 0:
self.signals["expose_event"].emit(expose_regions)
- def move(self, pos, force = False):
- return self.set_geometry(pos, (-1, -1))
+ def move(self, x, y=None, force=False):
+ if y is None:
+ log.warning('X11Window.move() now takes 2 arguments instead of 1 tuple')
+ x, y = x
+ return self.set_geometry((x, y), (-1, -1), force=force)
- def resize(self, size, force = False):
- return self.set_geometry((-1, -1), size, force)
+ def resize(self, width, height=None, force=False):
+ if height is None:
+ log.warning('X11Window.resize() now takes 2 arguments instead of 1 tuple')
+ width, height = width
+ return self.set_geometry((-1, -1), (width, height), force)
def set_geometry(self, pos, size, force = False):
if self.get_fullscreen() and not force:
@@ -430,6 +448,19 @@ def get_id(self):
def id(self):
return self._window.wid
+ @property
+ def owner(self):
+ """
+ True if the X11Window python object owns the underlying X11 Window
+ construct. If True, the window will be destroyed when the python
+ wrapper object is deallocated.
+ """
+ return self._window.owner
+
+ @owner.setter
+ def owner(self, value):
+ self._window.owner = value
+
def focus(self):
return self._window.focus()
@@ -536,3 +567,8 @@ def set_decorated(self, setting):
@param setting: True if the window should be decorated, false if not.
"""
self._window.set_decorated(setting)
+
+ def draw_rectangle(self, pos, size, color):
+ if isinstance(color, basestring) and color[0] == '#' and len(color) == 7:
+ color = int(color[1:3], 16), int(color[3:5], 16), int(color[5:], 16)
+ self._window.draw_rectangle(pos, size, color)
View
12 src/x11display.c
@@ -69,6 +69,7 @@ X11Display_PyObject__new(PyTypeObject *type, PyObject * args,
self = (X11Display_PyObject *)type->tp_alloc(type, 0);
self->display = display;
+ self->wmDeleteMessage = XInternAtom(self->display, "WM_DELETE_WINDOW", False);
return (PyObject *)self;
}
@@ -99,7 +100,6 @@ X11Display_PyObject__handle_events(X11Display_PyObject * self, PyObject * args)
PyObject *events = PyList_New(0), *o;
XEvent ev;
-// printf("START HANDLE EVENTS\n");
XLockDisplay(self->display);
XSync(self->display, False);
while (XPending(self->display)) {
@@ -145,6 +145,16 @@ X11Display_PyObject__handle_events(X11Display_PyObject * self, PyObject * args)
PyList_Append(events, o);
Py_DECREF(o);
}
+ else if (ev.type == ClientMessage) {
+ char *msgtype = "unknown";
+ if (ev.xclient.data.l[0] == self->wmDeleteMessage)
+ msgtype = "delete";
+ o = Py_BuildValue("(i{s:i,s:s})", ClientMessage,
+ "window", ev.xclient.window,
+ "type", msgtype);
+ PyList_Append(events, o);
+ Py_DECREF(o);
+ }
else if (ev.type == MapNotify) {
o = Py_BuildValue("(i{s:i})", MapNotify,
"window", ev.xmap.window);
View
1  src/x11display.h
@@ -39,6 +39,7 @@ typedef struct {
Display *display;
PyObject *socket;
+ Atom wmDeleteMessage;
} X11Display_PyObject;
extern PyTypeObject X11Display_PyObject_Type;
View
40 src/x11window.c
@@ -149,6 +149,7 @@ X11Window_PyObject__new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
last_error = NULL;
XSetErrorHandler(old_handler);
+ self->owner = Py_False;
} else {
screen = DefaultScreen(self->display);
attr.backing_store = NotUseful;
@@ -168,9 +169,12 @@ X11Window_PyObject__new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
if (window_title)
XStoreName(self->display, self->window, window_title);
- self->owner = True;
+ self->owner = Py_True;
}
self->wid = PyLong_FromUnsignedLong(self->window);
+ Py_INCREF(self->owner);
+ // Needed to handle event for window close via window manager
+ XSetWMProtocols(self->display, self->window, &display->wmDeleteMessage, 1);
XUnlockDisplay(self->display);
return (PyObject *)self;
}
@@ -185,15 +189,16 @@ X11Window_PyObject__init(X11Window_PyObject *self, PyObject *args,
void
X11Window_PyObject__dealloc(X11Window_PyObject * self)
{
- if (self->window ) {
+ if (self->window) {
XLockDisplay(self->display);
- if (self->owner)
+ if (self->owner == Py_True)
XDestroyWindow(self->display, self->window);
Py_XDECREF(self->wid);
if (self->invisible_cursor)
XFreeCursor(self->display, self->invisible_cursor);
XUnlockDisplay(self->display);
}
+ Py_DECREF(self->owner);
Py_XDECREF(self->display_pyobject);
X11Window_PyObject__clear(self);
self->ob_type->tp_free((PyObject*)self);
@@ -644,6 +649,33 @@ X11Window_PyObject__set_decorated(X11Window_PyObject * self, PyObject * args)
return Py_None;
}
+PyObject *
+X11Window_PyObject__draw_rectangle(X11Window_PyObject * self, PyObject * args)
+{
+ int x, y, width, height;
+ unsigned long color;
+ int depth, r, g, b;
+ GC gc;
+
+ if (!PyArg_ParseTuple(args, "(ii)(ii)(iii)", &x, &y, &width, &height, &r, &g, &b))
+ return NULL;
+
+ XLockDisplay(self->display);
+ depth = DefaultDepth(self->display, DefaultScreen(self->display));
+ if (depth == 16)
+ color = ((r & 248) << 8) + ((g & 252) << 3) + ((b & 248) >> 3);
+ else
+ color = (r << 16) + (g << 8) + b;
+ gc = XCreateGC(self->display, self->window, 0, 0);
+ XSetForeground(self->display, gc, color);
+ XFillRectangle(self->display, self->window, gc, x, y, width, height);
+ XFreeGC(self->display, gc);
+ XUnlockDisplay(self->display);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
PyMethodDef X11Window_PyObject_methods[] = {
{ "show", (PyCFunction)X11Window_PyObject__show, METH_VARARGS },
{ "hide", (PyCFunction)X11Window_PyObject__hide, METH_VARARGS },
@@ -664,6 +696,7 @@ PyMethodDef X11Window_PyObject_methods[] = {
{ "set_shape_mask", (PyCFunction)X11Window_PyObject__set_shape_mask, METH_VARARGS },
{ "reset_shape_mask", (PyCFunction)X11Window_PyObject__reset_shape_mask, METH_VARARGS },
{ "set_decorated", (PyCFunction)X11Window_PyObject__set_decorated, METH_VARARGS },
+ { "draw_rectangle", (PyCFunction)X11Window_PyObject__draw_rectangle, METH_VARARGS },
{ NULL, NULL }
};
@@ -720,6 +753,7 @@ int x11window_object_decompose(X11Window_PyObject *win, Window *window, Display
static PyMemberDef X11Window_PyObject_members[] = {
{"wid", T_OBJECT_EX, offsetof(X11Window_PyObject, wid), 0, ""},
+ {"owner", T_OBJECT_EX, offsetof(X11Window_PyObject, owner), 0, ""},
{NULL} /* Sentinel */
};
View
4 src/x11window.h
@@ -49,8 +49,8 @@ typedef struct {
Window window;
Cursor invisible_cursor;
- PyObject *wid;
- int owner;
+ PyObject *wid,
+ *owner;
} X11Window_PyObject;
extern PyTypeObject X11Window_PyObject_Type;
Please sign in to comment.
Something went wrong with that request. Please try again.