| 1 | # This file is part of Parti. |
| 2 | # Copyright (C) 2010-2012 Antoine Martin <antoine@devloop.org.uk> |
| 3 | # Copyright (C) 2008, 2009 Nathaniel Smith <njs@pobox.com> |
| 4 | # Parti is released under the terms of the GNU GPL v2, or, at your option, any |
| 5 | # later version. See the file COPYING for details. |
| 6 | |
| 7 | # This file duplicates the code from wimpiggy/lowlevel/bindings.pyx |
| 8 | # TODO: As noted in said file, the proper solution is to split it up |
| 9 | |
| 10 | import struct |
| 11 | |
| 12 | import gobject |
| 13 | import gtk |
| 14 | import gtk.gdk |
| 15 | |
| 16 | from wimpiggy.log import Logger |
| 17 | log = Logger("wimpiggy.bell_bindings") |
| 18 | |
| 19 | ################################### |
| 20 | # Headers, python magic |
| 21 | ################################### |
| 22 | cdef extern from "gdk/gdk.h": |
| 23 | pass |
| 24 | cdef extern from "gdk/gdkx.h": |
| 25 | pass |
| 26 | |
| 27 | # Serious black magic happens here (I owe these guys beers): |
| 28 | cdef extern from "pygobject.h": |
| 29 | void init_pygobject() |
| 30 | init_pygobject() |
| 31 | |
| 32 | cdef extern from "pygtk/pygtk.h": |
| 33 | void init_pygtk() |
| 34 | init_pygtk() |
| 35 | # Now all the macros in those header files will work. |
| 36 | |
| 37 | ################################### |
| 38 | # GObject |
| 39 | ################################### |
| 40 | |
| 41 | cdef extern from "glib-2.0/glib-object.h": |
| 42 | ctypedef struct cGObject "GObject": |
| 43 | pass |
| 44 | |
| 45 | cdef extern from "pygtk-2.0/pygobject.h": |
| 46 | cGObject * pygobject_get(object box) |
| 47 | ctypedef void** const_void_pp "const void**" |
| 48 | |
| 49 | # I am naughty; the exposed accessor for PyGBoxed objects is a macro that |
| 50 | # takes a type name as one of its arguments, and thus is impossible to |
| 51 | # wrap from Pyrex; so I just peek into the object directly: |
| 52 | ctypedef struct PyGBoxed: |
| 53 | void * boxed |
| 54 | |
| 55 | cdef cGObject * unwrap(box, pyclass) except? NULL: |
| 56 | # Extract a raw GObject* from a PyGObject wrapper. |
| 57 | assert issubclass(pyclass, gobject.GObject) |
| 58 | if not isinstance(box, pyclass): |
| 59 | raise TypeError, ("object %r is not a %r" % (box, pyclass)) |
| 60 | return pygobject_get(box) |
| 61 | |
| 62 | ################################### |
| 63 | # Raw Xlib and GDK |
| 64 | ################################### |
| 65 | |
| 66 | include "../../wimpiggy/lowlevel/constants.pxi" |
| 67 | ctypedef unsigned long CARD32 |
| 68 | |
| 69 | cdef extern from "X11/Xlib.h": |
| 70 | ctypedef struct Display: |
| 71 | pass |
| 72 | ctypedef CARD32 XID |
| 73 | ctypedef int Bool |
| 74 | ctypedef XID Window |
| 75 | ctypedef CARD32 Atom |
| 76 | |
| 77 | # gdk_region_get_rectangles (pygtk bug #517099) |
| 78 | cdef extern from "gtk-2.0/gdk/gdktypes.h": |
| 79 | ctypedef struct cGdkWindow "GdkWindow": |
| 80 | pass |
| 81 | Window GDK_WINDOW_XID(cGdkWindow *) |
| 82 | |
| 83 | ctypedef struct cGdkDisplay "GdkDisplay": |
| 84 | pass |
| 85 | Display * GDK_DISPLAY_XDISPLAY(cGdkDisplay *) |
| 86 | |
| 87 | ctypedef void * GdkAtom |
| 88 | GdkAtom PyGdkAtom_Get(object) |
| 89 | Atom gdk_x11_atom_to_xatom_for_display(cGdkDisplay *, GdkAtom) |
| 90 | |
| 91 | def get_xwindow(pywindow): |
| 92 | return GDK_WINDOW_XID(<cGdkWindow*>unwrap(pywindow, gtk.gdk.Window)) |
| 93 | |
| 94 | def get_display_for(obj): |
| 95 | if isinstance(obj, gtk.gdk.Display): |
| 96 | return obj |
| 97 | elif isinstance(obj, (gtk.gdk.Drawable, |
| 98 | gtk.Widget, |
| 99 | gtk.Clipboard)): |
| 100 | return obj.get_display() |
| 101 | else: |
| 102 | raise TypeError, "Don't know how to get a display from %r" % (obj,) |
| 103 | |
| 104 | def get_xatom(display_source, str_or_xatom): |
| 105 | """Returns the X atom corresponding to the given Python string or Python |
| 106 | integer (assumed to already be an X atom).""" |
| 107 | if isinstance(str_or_xatom, (int, long)): |
| 108 | return str_or_xatom |
| 109 | assert isinstance(str_or_xatom, str) |
| 110 | gdkatom = gtk.gdk.atom_intern(str_or_xatom) |
| 111 | return gdk_x11_atom_to_xatom_for_display( |
| 112 | get_raw_display_for(display_source), |
| 113 | PyGdkAtom_Get(gdkatom), |
| 114 | ) |
| 115 | |
| 116 | cdef cGdkDisplay * get_raw_display_for(obj) except? NULL: |
| 117 | return <cGdkDisplay*> unwrap(get_display_for(obj), gtk.gdk.Display) |
| 118 | |
| 119 | cdef Display * get_xdisplay_for(obj) except? NULL: |
| 120 | return GDK_DISPLAY_XDISPLAY(get_raw_display_for(obj)) |
| 121 | |
| 122 | cdef extern from "X11/XKBlib.h": |
| 123 | Bool XkbDeviceBell(Display *, Window w, int deviceSpec, int bellClass, int bellID, int percent, Atom name) |
| 124 | Bool XkbGetAutoRepeatRate(Display *, unsigned int deviceSpec, unsigned int *delayRtrn, unsigned int *intervalRtrn) |
| 125 | |
| 126 | cdef extern from "X11/extensions/XKB.h": |
| 127 | unsigned int XkbUseCoreKbd |
| 128 | |
| 129 | def get_key_repeat_rate(): |
| 130 | cdef Display * display |
| 131 | cdef unsigned int deviceSpec = XkbUseCoreKbd |
| 132 | cdef unsigned int delay = 0 |
| 133 | cdef unsigned int interval = 0 |
| 134 | display = get_xdisplay_for(gtk.gdk.get_default_root_window()) |
| 135 | if not XkbGetAutoRepeatRate(display, deviceSpec, &delay, &interval): |
| 136 | return None |
| 137 | return (delay, interval) |
| 138 | |
| 139 | def device_bell(pywindow, deviceSpec, bellClass, bellID, percent, name): |
| 140 | cdef Display * display |
| 141 | cdef Window window |
| 142 | display = get_xdisplay_for(pywindow) |
| 143 | window = get_xwindow(pywindow) |
| 144 | name_atom = get_xatom(pywindow, name) |
| 145 | return XkbDeviceBell(display, window, deviceSpec, bellClass, bellID, percent, name_atom) |