summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--Xlib/ChangeLog123
-rw-r--r--Xlib/X.py421
-rw-r--r--Xlib/XK.py88
-rw-r--r--Xlib/Xatom.py89
-rw-r--r--Xlib/Xcursorfont.py98
-rw-r--r--Xlib/Xutil.py77
-rw-r--r--Xlib/__init__.py40
-rw-r--r--Xlib/display.py916
-rw-r--r--Xlib/error.py162
-rw-r--r--Xlib/ext/__init__.py32
-rw-r--r--Xlib/ext/record.py280
-rw-r--r--Xlib/ext/shape.py334
-rw-r--r--Xlib/ext/xinerama.py221
-rw-r--r--Xlib/ext/xtest.py121
-rw-r--r--Xlib/keysymdef/__init__.py40
-rw-r--r--Xlib/keysymdef/apl.py19
-rw-r--r--Xlib/keysymdef/arabic.py50
-rw-r--r--Xlib/keysymdef/cyrillic.py107
-rw-r--r--Xlib/keysymdef/greek.py74
-rw-r--r--Xlib/keysymdef/hebrew.py40
-rw-r--r--Xlib/keysymdef/katakana.py70
-rw-r--r--Xlib/keysymdef/korean.py107
-rw-r--r--Xlib/keysymdef/latin1.py195
-rw-r--r--Xlib/keysymdef/latin2.py57
-rw-r--r--Xlib/keysymdef/latin3.py22
-rw-r--r--Xlib/keysymdef/latin4.py36
-rw-r--r--Xlib/keysymdef/miscellany.py169
-rw-r--r--Xlib/keysymdef/publishing.py83
-rw-r--r--Xlib/keysymdef/special.py24
-rw-r--r--Xlib/keysymdef/technical.py49
-rw-r--r--Xlib/keysymdef/thai.py84
-rw-r--r--Xlib/keysymdef/xk3270.py30
-rw-r--r--Xlib/keysymdef/xkb.py100
-rw-r--r--Xlib/protocol/ChangeLog124
-rw-r--r--Xlib/protocol/__init__.py27
-rw-r--r--Xlib/protocol/display.py983
-rw-r--r--Xlib/protocol/event.py433
-rw-r--r--Xlib/protocol/request.py1898
-rw-r--r--Xlib/protocol/rq.py1513
-rw-r--r--Xlib/protocol/structs.py160
-rw-r--r--Xlib/rdb.py706
-rw-r--r--Xlib/support/__init__.py25
-rw-r--r--Xlib/support/connect.py96
-rw-r--r--Xlib/support/lock.py43
-rw-r--r--Xlib/support/unix_connect.py149
-rw-r--r--Xlib/support/vms_connect.py73
-rw-r--r--Xlib/threaded.py27
-rw-r--r--Xlib/xauth.py129
-rw-r--r--Xlib/xobject/__init__.py28
-rw-r--r--Xlib/xobject/colormap.py141
-rw-r--r--Xlib/xobject/cursor.py45
-rw-r--r--Xlib/xobject/drawable.py824
-rw-r--r--Xlib/xobject/fontable.py108
-rw-r--r--Xlib/xobject/icccm.py74
-rw-r--r--Xlib/xobject/resource.py53
-rw-r--r--clMonty.py3
-rw-r--r--montypc.py15
58 files changed, 12023 insertions, 13 deletions
diff --git a/.gitignore b/.gitignore
index d08a050..65d9461 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,3 +3,4 @@
.vimsession
settings.txt
layout
+*.cover
diff --git a/Xlib/ChangeLog b/Xlib/ChangeLog
new file mode 100644
index 0000000..52bfb93
--- /dev/null
+++ b/Xlib/ChangeLog
@@ -0,0 +1,123 @@
+2007-06-10 Mike Grant <mgg@nobodymuch.org>
+
+ * (many files): (mgg) Converted tabs to spaces throughout the
+ codebase, using reindent.py (SF id: 1559082)
+
+2007-03-18 Mike Grant <mgg@nobodymuch.org>
+
+ * Xlib/display.py: (mgg) Added a get_atom alias that uses the
+ internal cache
+ * Xlib/xobject/drawable.py: (mgg) Added a raise_window() alias
+ to the Window class
+
+2007-02-15 Mike Grant <mgg@nobodymuch.org>
+
+ * Xlib/xauth.py: (mgg) Python 2.5 didn't like the way the buffer
+ type was used, resulting in X authorisation failure, so
+ reverted to using slices
+
+2006-11-22 Mike Grant <mgg@nobodymuch.org>
+
+ * Xlib/ext/record.py: Addition of RECORD extension by Alex Badea
+ <decampos@users.sourceforge.net>, SF patch id #1538663 (demo
+ program in python-xlib/examples/record_demo.py)
+
+2006-09-20 Mike Meyer <mwm@mired.org>
+
+ * Xlib/ext/xinerama.py: (mwm) Addition of Xinerama extension
+
+2006-07-22 Mike Grant <mgg@nobodymuch.org>
+
+ Various typo fixes, general updates.
+
+ Changelog hasn't been maintained since 2002, but some of the more
+ significant comments from cvs logs follow:
+
+ * Xlib/display.py: (petli) Fix bug in refresh_keyboard_mapping:
+ ignore modifier and pointer remappings. Plays nice with pydoc.
+ Copied some text from the docs to __doc__ strings in
+ Xlib/display.py so that they appear when you use pydoc.
+ Completed documentation for Display objects.
+ * Xlib/XK.py: (calroc99) Minor doc string changes. Called
+ load_keysym_group() for miscellany and latin1 keysyms, rather
+ than importing the modules.
+ * Xlib/keysymdef/*: (calroc99) Small change to keysym loading.
+ Works the same way.
+ * Xlib/support/*, Xlib/xauth.py, Xlib/error.py: (petli) Added
+ ~/.Xauthority parsing by Python code instead of relying on
+ /usr/X11R6/bin/xauth. Not activated yet in all cases yet?
+ Activated in unix_support.py.
+ * Xlib/xobject/drawable.py: (petli) Fix bugs in definition and
+ method of GrabButton/Pointer
+ * Xlib/xobject/icccm.py: (petli) Add WithdrawnState to WMHints
+ * doc/*: (petli) documentation updates, typos and completing
+ documentation for Display objects
+
+
+2002-03-30 Peter Liljenberg <peter.liljenberg@esdgkonsult.com>
+
+ * support/unix_connect.py: Handle fcntl/FCNTL changes in Python
+ 2.2.
+
+2002-03-11 Peter Liljenberg <peter.liljenberg@esdgkonsult.com>
+
+ * xobject/drawable.py (Drawable.fill_arc): This should be a
+ PolyFillArc.
+
+Fri Jan 19 17:49:45 2001 Peter Liljenberg <petli@cendio.se>
+
+ * XK.py: Moved all keysyms into separate modules, based on their
+ category. By default only the miscellany and latin1 keysyms are
+ loaded, and other have to be loaded by importing the
+ Xlib.keysymdef.<category> module, or calling
+ load_keysym_group('category').
+
+ * display.py (Display.lookup_string):
+ (Display.rebind_string):
+
+ Functions to translate keysyms to strings, and binding keysyms to
+ new strings.
+
+
+2001-01-16 <petli@cendio.se>
+
+ * xobject/drawable.py (Window.send_event):
+ * display.py (Display.send_event): Changed the order of the
+ event_mask and propagate arguments.
+
+2001-01-10 <petli@cendio.se>
+
+ * display.py (Display._update_keymap): The first half of the
+ update algorithm operated on an earlier type of code->sym map than
+ the second half. Stupid, stupid. It would have been nice with a
+ type-checker now.
+
+Tue Jan 9 13:03:19 2001 Peter Liljenberg <petli@cendio.se>
+
+ * display.py (Display._update_keymap): Fixed call to append with
+ 1.5.2 semantics, broke in newer Pythons.
+
+2000-12-22 <petli@cendio.se>
+
+ * display.py (Display.keycode_to_keysym):
+ (Display.keysym_to_keycode):
+ (Display.keysym_to_keycodes):
+ (Display.refresh_keyboard_mapping):
+ (Display._update_keymap):
+ Added keymap cache implementation.
+
+2000-12-21 <petli@cendio.se>
+
+ * xobject/colormap.py (Colormap.alloc_named_color): Extended to
+ handle #000000 style color specifications.
+
+ * xobject/drawable.py (Window.reparent): Renamed from
+ reparent_window.
+
+ * display.py (Display.set_error_handler): Added.
+
+2000-12-20 <petli@cendio.se>
+
+ * display.py (_BaseDisplay):
+ Implement a cache of atom names.
+
diff --git a/Xlib/X.py b/Xlib/X.py
new file mode 100644
index 0000000..702cc98
--- /dev/null
+++ b/Xlib/X.py
@@ -0,0 +1,421 @@
+# $Id: X.py,v 1.3 2007/06/10 14:11:58 mggrant Exp $
+#
+# Xlib.X -- basic X constants
+#
+# Copyright (C) 2000 Peter Liljenberg <petli@ctrl-c.liu.se>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+# Avoid overwriting None if doing "from Xlib.X import *"
+NONE = 0
+
+ParentRelative = 1 # background pixmap in CreateWindow
+ # and ChangeWindowAttributes
+
+CopyFromParent = 0 # border pixmap in CreateWindow
+ # and ChangeWindowAttributes
+ # special VisualID and special window
+ # class passed to CreateWindow
+
+PointerWindow = 0 # destination window in SendEvent
+InputFocus = 1 # destination window in SendEvent
+PointerRoot = 1 # focus window in SetInputFocus
+AnyPropertyType = 0 # special Atom, passed to GetProperty
+AnyKey = 0 # special Key Code, passed to GrabKey
+AnyButton = 0 # special Button Code, passed to GrabButton
+AllTemporary = 0 # special Resource ID passed to KillClient
+CurrentTime = 0 # special Time
+NoSymbol = 0 # special KeySym
+
+
+#-----------------------------------------------------------------------
+# Event masks:
+#
+NoEventMask = 0
+KeyPressMask = (1<<0)
+KeyReleaseMask = (1<<1)
+ButtonPressMask = (1<<2)
+ButtonReleaseMask = (1<<3)
+EnterWindowMask = (1<<4)
+LeaveWindowMask = (1<<5)
+PointerMotionMask = (1<<6)
+PointerMotionHintMask = (1<<7)
+Button1MotionMask = (1<<8)
+Button2MotionMask = (1<<9)
+Button3MotionMask = (1<<10)
+Button4MotionMask = (1<<11)
+Button5MotionMask = (1<<12)
+ButtonMotionMask = (1<<13)
+KeymapStateMask = (1<<14)
+ExposureMask = (1<<15)
+VisibilityChangeMask = (1<<16)
+StructureNotifyMask = (1<<17)
+ResizeRedirectMask = (1<<18)
+SubstructureNotifyMask = (1<<19)
+SubstructureRedirectMask = (1<<20)
+FocusChangeMask = (1<<21)
+PropertyChangeMask = (1<<22)
+ColormapChangeMask = (1<<23)
+OwnerGrabButtonMask = (1<<24)
+
+#-----------------------------------------------------------------------
+# Event names:
+#
+# Used in "type" field in XEvent structures. Not to be confused with event
+# masks above. They start from 2 because 0 and 1 are reserved in the
+# protocol for errors and replies.
+#
+KeyPress = 2
+KeyRelease = 3
+ButtonPress = 4
+ButtonRelease = 5
+MotionNotify = 6
+EnterNotify = 7
+LeaveNotify = 8
+FocusIn = 9
+FocusOut = 10
+KeymapNotify = 11
+Expose = 12
+GraphicsExpose = 13
+NoExpose = 14
+VisibilityNotify = 15
+CreateNotify = 16
+DestroyNotify = 17
+UnmapNotify = 18
+MapNotify = 19
+MapRequest = 20
+ReparentNotify = 21
+ConfigureNotify = 22
+ConfigureRequest = 23
+GravityNotify = 24
+ResizeRequest = 25
+CirculateNotify = 26
+CirculateRequest = 27
+PropertyNotify = 28
+SelectionClear = 29
+SelectionRequest = 30
+SelectionNotify = 31
+ColormapNotify = 32
+ClientMessage = 33
+MappingNotify = 34
+LASTEvent = 35 # must be bigger than any event
+
+
+#-----------------------------------------------------------------------
+# Key masks:
+#
+# Used as modifiers to GrabButton and GrabKey, results of QueryPointer,
+# state in various key-, mouse-, and button-related events.
+#
+ShiftMask = (1<<0)
+LockMask = (1<<1)
+ControlMask = (1<<2)
+Mod1Mask = (1<<3)
+Mod2Mask = (1<<4)
+Mod3Mask = (1<<5)
+Mod4Mask = (1<<6)
+Mod5Mask = (1<<7)
+
+
+#-----------------------------------------------------------------------
+# Modifier names:
+#
+# Used to build a SetModifierMapping request or to read a
+# GetModifierMapping request. These correspond to the masks defined above.
+#
+ShiftMapIndex = 0
+LockMapIndex = 1
+ControlMapIndex = 2
+Mod1MapIndex = 3
+Mod2MapIndex = 4
+Mod3MapIndex = 5
+Mod4MapIndex = 6
+Mod5MapIndex = 7
+
+#-----------------------------------------------------------------------
+# Button masks:
+#
+# Used in same manner as Key masks above. Not to be confused with button
+# names below. Note that 0 is already defined above as "AnyButton".
+#
+Button1Mask = (1<<8)
+Button2Mask = (1<<9)
+Button3Mask = (1<<10)
+Button4Mask = (1<<11)
+Button5Mask = (1<<12)
+
+AnyModifier = (1<<15) # used in GrabButton, GrabKey
+
+#-----------------------------------------------------------------------
+# Button names:
+#
+# Used as arguments to GrabButton and as detail in ButtonPress and
+# ButtonRelease events. Not to be confused with button masks above.
+# Note that 0 is already defined above as "AnyButton".
+#
+Button1 = 1
+Button2 = 2
+Button3 = 3
+Button4 = 4
+Button5 = 5
+
+
+#-----------------------------------------------------------------------
+# XXX These still need documentation -- for now, read <X11/X.h>
+#
+NotifyNormal = 0
+NotifyGrab = 1
+NotifyUngrab = 2
+NotifyWhileGrabbed = 3
+NotifyHint = 1
+NotifyAncestor = 0
+NotifyVirtual = 1
+NotifyInferior = 2
+NotifyNonlinear = 3
+NotifyNonlinearVirtual = 4
+NotifyPointer = 5
+NotifyPointerRoot = 6
+NotifyDetailNone = 7
+VisibilityUnobscured = 0
+VisibilityPartiallyObscured = 1
+VisibilityFullyObscured = 2
+PlaceOnTop = 0
+PlaceOnBottom = 1
+FamilyInternet = 0
+FamilyDECnet = 1
+FamilyChaos = 2
+PropertyNewValue = 0
+PropertyDelete = 1
+ColormapUninstalled = 0
+ColormapInstalled = 1
+GrabModeSync = 0
+GrabModeAsync = 1
+GrabSuccess = 0
+AlreadyGrabbed = 1
+GrabInvalidTime = 2
+GrabNotViewable = 3
+GrabFrozen = 4
+AsyncPointer = 0
+SyncPointer = 1
+ReplayPointer = 2
+AsyncKeyboard = 3
+SyncKeyboard = 4
+ReplayKeyboard = 5
+AsyncBoth = 6
+SyncBoth = 7
+RevertToNone = 0
+RevertToPointerRoot = PointerRoot
+RevertToParent = 2
+Success = 0
+BadRequest = 1
+BadValue = 2
+BadWindow = 3
+BadPixmap = 4
+BadAtom = 5
+BadCursor = 6
+BadFont = 7
+BadMatch = 8
+BadDrawable = 9
+BadAccess = 10
+BadAlloc = 11
+BadColor = 12
+BadGC = 13
+BadIDChoice = 14
+BadName = 15
+BadLength = 16
+BadImplementation = 17
+FirstExtensionError = 128
+LastExtensionError = 255
+InputOutput = 1
+InputOnly = 2
+CWBackPixmap = (1<<0)
+CWBackPixel = (1<<1)
+CWBorderPixmap = (1<<2)
+CWBorderPixel = (1<<3)
+CWBitGravity = (1<<4)
+CWWinGravity = (1<<5)
+CWBackingStore = (1<<6)
+CWBackingPlanes = (1<<7)
+CWBackingPixel = (1<<8)
+CWOverrideRedirect = (1<<9)
+CWSaveUnder = (1<<10)
+CWEventMask = (1<<11)
+CWDontPropagate = (1<<12)
+CWColormap = (1<<13)
+CWCursor = (1<<14)
+CWX = (1<<0)
+CWY = (1<<1)
+CWWidth = (1<<2)
+CWHeight = (1<<3)
+CWBorderWidth = (1<<4)
+CWSibling = (1<<5)
+CWStackMode = (1<<6)
+ForgetGravity = 0
+NorthWestGravity = 1
+NorthGravity = 2
+NorthEastGravity = 3
+WestGravity = 4
+CenterGravity = 5
+EastGravity = 6
+SouthWestGravity = 7
+SouthGravity = 8
+SouthEastGravity = 9
+StaticGravity = 10
+UnmapGravity = 0
+NotUseful = 0
+WhenMapped = 1
+Always = 2
+IsUnmapped = 0
+IsUnviewable = 1
+IsViewable = 2
+SetModeInsert = 0
+SetModeDelete = 1
+DestroyAll = 0
+RetainPermanent = 1
+RetainTemporary = 2
+Above = 0
+Below = 1
+TopIf = 2
+BottomIf = 3
+Opposite = 4
+RaiseLowest = 0
+LowerHighest = 1
+PropModeReplace = 0
+PropModePrepend = 1
+PropModeAppend = 2
+GXclear = 0x0
+GXand = 0x1
+GXandReverse = 0x2
+GXcopy = 0x3
+GXandInverted = 0x4
+GXnoop = 0x5
+GXxor = 0x6
+GXor = 0x7
+GXnor = 0x8
+GXequiv = 0x9
+GXinvert = 0xa
+GXorReverse = 0xb
+GXcopyInverted = 0xc
+GXorInverted = 0xd
+GXnand = 0xe
+GXset = 0xf
+LineSolid = 0
+LineOnOffDash = 1
+LineDoubleDash = 2
+CapNotLast = 0
+CapButt = 1
+CapRound = 2
+CapProjecting = 3
+JoinMiter = 0
+JoinRound = 1
+JoinBevel = 2
+FillSolid = 0
+FillTiled = 1
+FillStippled = 2
+FillOpaqueStippled = 3
+EvenOddRule = 0
+WindingRule = 1
+ClipByChildren = 0
+IncludeInferiors = 1
+Unsorted = 0
+YSorted = 1
+YXSorted = 2
+YXBanded = 3
+CoordModeOrigin = 0
+CoordModePrevious = 1
+Complex = 0
+Nonconvex = 1
+Convex = 2
+ArcChord = 0
+ArcPieSlice = 1
+GCFunction = (1<<0)
+GCPlaneMask = (1<<1)
+GCForeground = (1<<2)
+GCBackground = (1<<3)
+GCLineWidth = (1<<4)
+GCLineStyle = (1<<5)
+GCCapStyle = (1<<6)
+GCJoinStyle = (1<<7)
+GCFillStyle = (1<<8)
+GCFillRule = (1<<9)
+GCTile = (1<<10)
+GCStipple = (1<<11)
+GCTileStipXOrigin = (1<<12)
+GCTileStipYOrigin = (1<<13)
+GCFont = (1<<14)
+GCSubwindowMode = (1<<15)
+GCGraphicsExposures = (1<<16)
+GCClipXOrigin = (1<<17)
+GCClipYOrigin = (1<<18)
+GCClipMask = (1<<19)
+GCDashOffset = (1<<20)
+GCDashList = (1<<21)
+GCArcMode = (1<<22)
+GCLastBit = 22
+FontLeftToRight = 0
+FontRightToLeft = 1
+FontChange = 255
+XYBitmap = 0
+XYPixmap = 1
+ZPixmap = 2
+AllocNone = 0
+AllocAll = 1
+DoRed = (1<<0)
+DoGreen = (1<<1)
+DoBlue = (1<<2)
+CursorShape = 0
+TileShape = 1
+StippleShape = 2
+AutoRepeatModeOff = 0
+AutoRepeatModeOn = 1
+AutoRepeatModeDefault = 2
+LedModeOff = 0
+LedModeOn = 1
+KBKeyClickPercent = (1<<0)
+KBBellPercent = (1<<1)
+KBBellPitch = (1<<2)
+KBBellDuration = (1<<3)
+KBLed = (1<<4)
+KBLedMode = (1<<5)
+KBKey = (1<<6)
+KBAutoRepeatMode = (1<<7)
+MappingSuccess = 0
+MappingBusy = 1
+MappingFailed = 2
+MappingModifier = 0
+MappingKeyboard = 1
+MappingPointer = 2
+DontPreferBlanking = 0
+PreferBlanking = 1
+DefaultBlanking = 2
+DisableScreenSaver = 0
+DisableScreenInterval = 0
+DontAllowExposures = 0
+AllowExposures = 1
+DefaultExposures = 2
+ScreenSaverReset = 0
+ScreenSaverActive = 1
+HostInsert = 0
+HostDelete = 1
+EnableAccess = 1
+DisableAccess = 0
+StaticGray = 0
+GrayScale = 1
+StaticColor = 2
+PseudoColor = 3
+TrueColor = 4
+DirectColor = 5
+LSBFirst = 0
+MSBFirst = 1
diff --git a/Xlib/XK.py b/Xlib/XK.py
new file mode 100644
index 0000000..8b76038
--- /dev/null
+++ b/Xlib/XK.py
@@ -0,0 +1,88 @@
+# $Id: XK.py,v 1.7 2007/06/10 14:11:58 mggrant Exp $
+#
+# Xlib.XK -- X keysym defs
+#
+# Copyright (C) 2000 Peter Liljenberg <petli@ctrl-c.liu.se>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+# This module defines some functions for working with X keysyms as well
+# as a modular keysym definition and loading mechanism. See the keysym
+# definition modules in the Xlib/keysymdef directory.
+
+from X import NoSymbol
+
+def string_to_keysym(keysym):
+ '''Return the (16 bit) numeric code of keysym.
+
+ Given the name of a keysym as a string, return its numeric code.
+ Don't include the 'XK_' prefix, just use the base, i.e. 'Delete'
+ instead of 'XK_Delete'.'''
+ return globals().get('XK_' + keysym, NoSymbol)
+
+def load_keysym_group(group):
+ '''Load all the keysyms in group.
+
+ Given a group name such as 'latin1' or 'katakana' load the keysyms
+ defined in module 'Xlib.keysymdef.group-name' into this XK module.'''
+ if '.' in group:
+ raise ValueError('invalid keysym group name: %s' % group)
+
+ G = globals() #Get a reference to XK.__dict__ a.k.a. globals
+
+ #Import just the keysyms module.
+ mod = __import__('Xlib.keysymdef.%s' % group, G, locals(), [group])
+
+ #Extract names of just the keysyms.
+ keysyms = [n for n in dir(mod) if n.startswith('XK_')]
+
+ #Copy the named keysyms into XK.__dict__
+ for keysym in keysyms:
+ ## k = mod.__dict__[keysym]; assert k == int(k) #probably too much.
+ G[keysym] = mod.__dict__[keysym]
+
+ #And get rid of the keysym module.
+ del mod
+
+def _load_keysyms_into_XK(mod):
+ '''keysym definition modules need no longer call Xlib.XK._load_keysyms_into_XK().
+ You should remove any calls to that function from your keysym modules.'''
+ pass
+
+# Always import miscellany and latin1 keysyms
+load_keysym_group('miscellany')
+load_keysym_group('latin1')
+
+
+def keysym_to_string(keysym):
+ '''Translate a keysym (16 bit number) into a python string.
+
+ This will pass 0 to 0xff as well as XK_BackSpace, XK_Tab, XK_Clear,
+ XK_Return, XK_Pause, XK_Scroll_Lock, XK_Escape, XK_Delete. For other
+ values it returns None.'''
+
+ # ISO latin 1, LSB is the code
+ if keysym & 0xff00 == 0:
+ return chr(keysym & 0xff)
+
+ if keysym in [XK_BackSpace, XK_Tab, XK_Clear, XK_Return,
+ XK_Pause, XK_Scroll_Lock, XK_Escape, XK_Delete]:
+ return chr(keysym & 0xff)
+
+ # We should be able to do these things quite automatically
+ # for latin2, latin3, etc, in Python 2.0 using the Unicode,
+ # but that will have to wait.
+
+ return None
diff --git a/Xlib/Xatom.py b/Xlib/Xatom.py
new file mode 100644
index 0000000..9a3ab80
--- /dev/null
+++ b/Xlib/Xatom.py
@@ -0,0 +1,89 @@
+# $Id: Xatom.py,v 1.3 2007/06/10 14:11:58 mggrant Exp $
+#
+# Xlib.Xatom -- Standard X atoms
+#
+# Copyright (C) 2000 Peter Liljenberg <petli@ctrl-c.liu.se>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+PRIMARY = 1
+SECONDARY = 2
+ARC = 3
+ATOM = 4
+BITMAP = 5
+CARDINAL = 6
+COLORMAP = 7
+CURSOR = 8
+CUT_BUFFER0 = 9
+CUT_BUFFER1 = 10
+CUT_BUFFER2 = 11
+CUT_BUFFER3 = 12
+CUT_BUFFER4 = 13
+CUT_BUFFER5 = 14
+CUT_BUFFER6 = 15
+CUT_BUFFER7 = 16
+DRAWABLE = 17
+FONT = 18
+INTEGER = 19
+PIXMAP = 20
+POINT = 21
+RECTANGLE = 22
+RESOURCE_MANAGER = 23
+RGB_COLOR_MAP = 24
+RGB_BEST_MAP = 25
+RGB_BLUE_MAP = 26
+RGB_DEFAULT_MAP = 27
+RGB_GRAY_MAP = 28
+RGB_GREEN_MAP = 29
+RGB_RED_MAP = 30
+STRING = 31
+VISUALID = 32
+WINDOW = 33
+WM_COMMAND = 34
+WM_HINTS = 35
+WM_CLIENT_MACHINE = 36
+WM_ICON_NAME = 37
+WM_ICON_SIZE = 38
+WM_NAME = 39
+WM_NORMAL_HINTS = 40
+WM_SIZE_HINTS = 41
+WM_ZOOM_HINTS = 42
+MIN_SPACE = 43
+NORM_SPACE = 44
+MAX_SPACE = 45
+END_SPACE = 46
+SUPERSCRIPT_X = 47
+SUPERSCRIPT_Y = 48
+SUBSCRIPT_X = 49
+SUBSCRIPT_Y = 50
+UNDERLINE_POSITION = 51
+UNDERLINE_THICKNESS = 52
+STRIKEOUT_ASCENT = 53
+STRIKEOUT_DESCENT = 54
+ITALIC_ANGLE = 55
+X_HEIGHT = 56
+QUAD_WIDTH = 57
+WEIGHT = 58
+POINT_SIZE = 59
+RESOLUTION = 60
+COPYRIGHT = 61
+NOTICE = 62
+FONT_NAME = 63
+FAMILY_NAME = 64
+FULL_NAME = 65
+CAP_HEIGHT = 66
+WM_CLASS = 67
+WM_TRANSIENT_FOR = 68
+LAST_PREDEFINED = 68
diff --git a/Xlib/Xcursorfont.py b/Xlib/Xcursorfont.py
new file mode 100644
index 0000000..94a3ac2
--- /dev/null
+++ b/Xlib/Xcursorfont.py
@@ -0,0 +1,98 @@
+# $Id: Xcursorfont.py,v 1.2 2000/08/22 14:06:22 petli Exp $
+#
+# Xlib.Xcursorfont -- standard cursors
+#
+# Copyright (C) 2000 Peter Liljenberg <petli@ctrl-c.liu.se>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+num_glyphs = 154
+X_cursor = 0
+arrow = 2
+based_arrow_down = 4
+based_arrow_up = 6
+boat = 8
+bogosity = 10
+bottom_left_corner = 12
+bottom_right_corner = 14
+bottom_side = 16
+bottom_tee = 18
+box_spiral = 20
+center_ptr = 22
+circle = 24
+clock = 26
+coffee_mug = 28
+cross = 30
+cross_reverse = 32
+crosshair = 34
+diamond_cross = 36
+dot = 38
+dotbox = 40
+double_arrow = 42
+draft_large = 44
+draft_small = 46
+draped_box = 48
+exchange = 50
+fleur = 52
+gobbler = 54
+gumby = 56
+hand1 = 58
+hand2 = 60
+heart = 62
+icon = 64
+iron_cross = 66
+left_ptr = 68
+left_side = 70
+left_tee = 72
+leftbutton = 74
+ll_angle = 76
+lr_angle = 78
+man = 80
+middlebutton = 82
+mouse = 84
+pencil = 86
+pirate = 88
+plus = 90
+question_arrow = 92
+right_ptr = 94
+right_side = 96
+right_tee = 98
+rightbutton = 100
+rtl_logo = 102
+sailboat = 104
+sb_down_arrow = 106
+sb_h_double_arrow = 108
+sb_left_arrow = 110
+sb_right_arrow = 112
+sb_up_arrow = 114
+sb_v_double_arrow = 116
+shuttle = 118
+sizing = 120
+spider = 122
+spraycan = 124
+star = 126
+target = 128
+tcross = 130
+top_left_arrow = 132
+top_left_corner = 134
+top_right_corner = 136
+top_side = 138
+top_tee = 140
+trek = 142
+ul_angle = 144
+umbrella = 146
+ur_angle = 148
+watch = 150
+xterm = 152
diff --git a/Xlib/Xutil.py b/Xlib/Xutil.py
new file mode 100644
index 0000000..5ded309
--- /dev/null
+++ b/Xlib/Xutil.py
@@ -0,0 +1,77 @@
+# $Id: Xutil.py,v 1.3 2007/06/10 14:11:58 mggrant Exp $
+#
+# Xlib.Xutil -- ICCCM definitions and similar stuff
+#
+# Copyright (C) 2000 Peter Liljenberg <petli@ctrl-c.liu.se>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+NoValue = 0x0000
+XValue = 0x0001
+YValue = 0x0002
+WidthValue = 0x0004
+HeightValue = 0x0008
+AllValues = 0x000F
+XNegative = 0x0010
+YNegative = 0x0020
+USPosition = (1 << 0)
+USSize = (1 << 1)
+PPosition = (1 << 2)
+PSize = (1 << 3)
+PMinSize = (1 << 4)
+PMaxSize = (1 << 5)
+PResizeInc = (1 << 6)
+PAspect = (1 << 7)
+PBaseSize = (1 << 8)
+PWinGravity = (1 << 9)
+PAllHints = (PPosition|PSize|PMinSize|PMaxSize|PResizeInc|PAspect)
+InputHint = (1 << 0)
+StateHint = (1 << 1)
+IconPixmapHint = (1 << 2)
+IconWindowHint = (1 << 3)
+IconPositionHint = (1 << 4)
+IconMaskHint = (1 << 5)
+WindowGroupHint = (1 << 6)
+AllHints = (InputHint|StateHint|IconPixmapHint|IconWindowHint|
+ IconPositionHint|IconMaskHint|WindowGroupHint)
+WithdrawnState = 0
+NormalState = 1
+IconicState = 3
+DontCareState = 0
+ZoomState = 2
+InactiveState = 4
+RectangleOut = 0
+RectangleIn = 1
+RectanglePart = 2
+VisualNoMask = 0x0
+VisualIDMask = 0x1
+VisualScreenMask = 0x2
+VisualDepthMask = 0x4
+VisualClassMask = 0x8
+VisualRedMaskMask = 0x10
+VisualGreenMaskMask = 0x20
+VisualBlueMaskMask = 0x40
+VisualColormapSizeMask = 0x80
+VisualBitsPerRGBMask = 0x100
+VisualAllMask = 0x1FF
+ReleaseByFreeingColormap = 1
+BitmapSuccess = 0
+BitmapOpenFailed = 1
+BitmapFileInvalid = 2
+BitmapNoMemory = 3
+XCSUCCESS = 0
+XCNOMEM = 1
+XCNOENT = 2
diff --git a/Xlib/__init__.py b/Xlib/__init__.py
new file mode 100644
index 0000000..88716c3
--- /dev/null
+++ b/Xlib/__init__.py
@@ -0,0 +1,40 @@
+# $Id: __init__.py,v 1.15 2007/06/10 14:11:58 mggrant Exp $
+#
+# Xlib.__init__ -- glue for Xlib package
+#
+# Copyright (C) 2000-2002 Peter Liljenberg <petli@ctrl-c.liu.se>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+import string
+
+__version__ = (0, 12)
+
+__version_extra__ = ''
+
+__version_string__ = string.join(map(str, __version__), '.') + __version_extra__
+
+__all__ = [
+ 'X',
+ 'XK',
+ 'Xatom',
+ 'Xcursorfont',
+ 'Xutil',
+ 'display',
+ 'error',
+ 'rdb',
+ # Explicitly exclude threaded, so that it isn't imported by
+ # from Xlib import *
+ ]
diff --git a/Xlib/display.py b/Xlib/display.py
new file mode 100644
index 0000000..5fab121
--- /dev/null
+++ b/Xlib/display.py
@@ -0,0 +1,916 @@
+# $Id: display.py,v 1.23 2007/06/10 14:11:58 mggrant Exp $
+#
+# Xlib.display -- high level display object
+#
+# Copyright (C) 2000 Peter Liljenberg <petli@ctrl-c.liu.se>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+# Python modules
+import new
+
+# Xlib modules
+import error
+import ext
+import X
+
+# Xlib.protocol modules
+import protocol.display
+from protocol import request, event, rq
+
+# Xlib.xobjects modules
+import xobject.resource
+import xobject.drawable
+import xobject.fontable
+import xobject.colormap
+import xobject.cursor
+
+_resource_baseclasses = {
+ 'resource': xobject.resource.Resource,
+ 'drawable': xobject.drawable.Drawable,
+ 'window': xobject.drawable.Window,
+ 'pixmap': xobject.drawable.Pixmap,
+ 'fontable': xobject.fontable.Fontable,
+ 'font': xobject.fontable.Font,
+ 'gc': xobject.fontable.GC,
+ 'colormap': xobject.colormap.Colormap,
+ 'cursor': xobject.cursor.Cursor,
+ }
+
+_resource_hierarchy = {
+ 'resource': ('drawable', 'window', 'pixmap',
+ 'fontable', 'font', 'gc',
+ 'colormap', 'cursor'),
+ 'drawable': ('window', 'pixmap'),
+ 'fontable': ('font', 'gc')
+ }
+
+class _BaseDisplay(protocol.display.Display):
+ resource_classes = _resource_baseclasses.copy()
+
+ # Implement a cache of atom names, used by Window objects when
+ # dealing with some ICCCM properties not defined in Xlib.Xatom
+
+ def __init__(self, *args, **keys):
+ apply(protocol.display.Display.__init__, (self, ) + args, keys)
+ self._atom_cache = {}
+
+ def get_atom(self, atomname, only_if_exists=0):
+ if self._atom_cache.has_key(atomname):
+ return self._atom_cache[atomname]
+
+ r = request.InternAtom(display = self, name = atomname, only_if_exists = only_if_exists)
+
+ # don't cache NONE responses in case someone creates this later
+ if r.atom != X.NONE:
+ self._atom_cache[atomname] = r.atom
+
+ return r.atom
+
+
+class Display:
+ def __init__(self, display = None):
+ self.display = _BaseDisplay(display)
+
+ # Create the keymap cache
+ self._keymap_codes = [()] * 256
+ self._keymap_syms = {}
+ self._update_keymap(self.display.info.min_keycode,
+ (self.display.info.max_keycode
+ - self.display.info.min_keycode + 1))
+
+ # Translations for keysyms to strings.
+ self.keysym_translations = {}
+
+ # Find all supported extensions
+ self.extensions = []
+ self.class_extension_dicts = {}
+ self.display_extension_methods = {}
+
+ self.extension_event = rq.DictWrapper({})
+
+ exts = self.list_extensions()
+
+ # Go through all extension modules
+ for extname, modname in ext.__extensions__:
+ if extname in exts:
+
+ # Import the module and fetch it
+ __import__('Xlib.ext.' + modname)
+ mod = getattr(ext, modname)
+
+ info = self.query_extension(extname)
+ self.display.set_extension_major(extname, info.major_opcode)
+
+ # Call initialiasation function
+ mod.init(self, info)
+
+ self.extensions.append(extname)
+
+
+ # Finalize extensions by creating new classes
+ for type, dict in self.class_extension_dicts.items():
+ origcls = self.display.resource_classes[type]
+ self.display.resource_classes[type] = new.classobj(origcls.__name__,
+ (origcls,),
+ dict)
+
+ # Problem: we have already created some objects without the
+ # extensions: the screen roots and default colormaps.
+ # Fix that by reinstantiating them.
+ for screen in self.display.info.roots:
+ screen.root = self.display.resource_classes['window'](self.display, screen.root.id)
+ screen.default_colormap = self.display.resource_classes['colormap'](self.display, screen.default_colormap.id)
+
+
+ def get_display_name(self):
+ """Returns the name used to connect to the server, either
+ provided when creating the Display object, or fetched from the
+ environmental variable $DISPLAY."""
+ return self.display.get_display_name()
+
+ def fileno(self):
+ """Returns the file descriptor number of the underlying socket.
+ This method is provided to allow Display objects to be passed
+ select.select()."""
+ return self.display.fileno()
+
+ def close(self):
+ """Close the display, freeing the resources that it holds."""
+ self.display.close()
+
+ def set_error_handler(self, handler):
+ """Set the default error handler which will be called for all
+ unhandled errors. handler should take two arguments as a normal
+ request error handler, but the second argument (the request) will
+ be None. See section Error Handling."""
+ self.display.set_error_handler(handler)
+
+ def flush(self):
+ """Flush the request queue, building and sending the queued
+ requests. This can be necessary in applications that never wait
+ for events, and in threaded applications."""
+ self.display.flush()
+
+ def sync(self):
+ """Flush the queue and wait until the server has processed all
+ the queued requests. Use this e.g. when it is important that
+ errors caused by a certain request is trapped."""
+ # Do a light-weight replyrequest to sync. There must
+ # be a better way to do it...
+ self.get_pointer_control()
+
+ def next_event(self):
+ """Return the next event. If there are no events queued, it will
+ block until the next event is fetched from the server."""
+ return self.display.next_event()
+
+ def pending_events(self):
+ """Return the number of events queued, i.e. the number of times
+ that Display.next_event() can be called without blocking."""
+ return self.display.pending_events()
+
+ def has_extension(self, extension):
+ """Check if both the server and the client library support the X
+ extension named extension."""
+ return extension in self.extensions
+
+ def create_resource_object(self, type, id):
+ """Create a resource object of type for the integer id. type
+ should be one of the following strings:
+
+ resource
+ drawable
+ window
+ pixmap
+ fontable
+ font
+ gc
+ colormap
+ cursor
+
+ This function can be used when a resource ID has been fetched
+ e.g. from an resource or a command line argument. Resource
+ objects should never be created by instantiating the appropriate
+ class directly, since any X extensions dynamically added by the
+ library will not be available.
+ """
+ return self.display.resource_classes[type](self.display, id)
+
+ # We need this to handle display extension methods
+ def __getattr__(self, attr):
+ try:
+ function = self.display_extension_methods[attr]
+ return new.instancemethod(function, self, self.__class__)
+ except KeyError:
+ raise AttributeError(attr)
+
+ ###
+ ### display information retrieval
+ ###
+
+ def screen(self, sno = None):
+ if sno is None:
+ return self.display.info.roots[self.display.default_screen]
+ else:
+ return self.display.info.roots[sno]
+
+ def screen_count(self):
+ """Return the total number of screens on the display."""
+ return len(self.display.info.roots)
+
+ def get_default_screen(self):
+ """Return the number of the default screen, extracted from the
+ display name."""
+ return self.display.get_default_screen()
+
+ ###
+ ### Extension module interface
+ ###
+
+ def extension_add_method(self, object, name, function):
+ """extension_add_method(object, name, function)
+
+ Add an X extension module method. OBJECT is the type of
+ object to add the function to, a string from this list:
+
+ display
+ resource
+ drawable
+ window
+ pixmap
+ fontable
+ font
+ gc
+ colormap
+ cursor
+
+ NAME is the name of the method, a string. FUNCTION is a
+ normal function whose first argument is a 'self'.
+ """
+
+ if object == 'display':
+ if hasattr(self, name):
+ raise error.MethodOverrideError('attempting to replace display method: %s' % name)
+
+ self.display_extension_methods[name] = function
+
+ else:
+ types = (object, ) + _resource_hierarchy.get(object, ())
+ for type in types:
+ cls = _resource_baseclasses[type]
+ if hasattr(cls, name):
+ raise error.MethodOverrideError('attempting to replace %s method: %s' % (type, name))
+
+ method = new.instancemethod(function, None, cls)
+
+ # Maybe should check extension overrides too
+ try:
+ self.class_extension_dicts[type][name] = method
+ except KeyError:
+ self.class_extension_dicts[type] = { name: method }
+
+ def extension_add_event(self, code, evt, name = None):
+ """extension_add_event(code, evt, [name])
+
+ Add an extension event. CODE is the numeric code, and EVT is
+ the event class. EVT will be cloned, and the attribute _code
+ of the new event class will be set to CODE.
+
+ If NAME is ommitted, it will be set to the name of EVT. This
+ name is used to insert an entry in the DictWrapper
+ extension_event.
+ """
+
+ newevt = new.classobj(evt.__name__, evt.__bases__,
+ evt.__dict__.copy())
+ newevt._code = code
+
+ self.display.add_extension_event(code, newevt)
+
+ if name is None:
+ name = evt.__name__
+
+ setattr(self.extension_event, name, code)
+
+
+ def add_extension_error(self, code, err):
+ """add_extension_error(code, err)
+
+ Add an extension error. CODE is the numeric code, and ERR is
+ the error class.
+ """
+
+ self.display.add_extension_error(code, err)
+
+ ###
+ ### keymap cache implementation
+ ###
+
+ # The keycode->keysym map is stored in a list with 256 elements.
+ # Each element represents a keycode, and the tuple elements are
+ # the keysyms bound to the key.
+
+ # The keysym->keycode map is stored in a mapping, where the keys
+ # are keysyms. The values are a sorted list of tuples with two
+ # elements each: (index, keycode)
+ # keycode is the code for a key to which this keysym is bound, and
+ # index is the keysyms index in the map for that keycode.
+
+ def keycode_to_keysym(self, keycode, index):
+ """Convert a keycode to a keysym, looking in entry index.
+ Normally index 0 is unshifted, 1 is shifted, 2 is alt grid, and 3
+ is shift+alt grid. If that key entry is not bound, X.NoSymbol is
+ returned."""
+ try:
+ return self._keymap_codes[keycode][index]
+ except IndexError:
+ return X.NoSymbol
+
+ def keysym_to_keycode(self, keysym):
+ """Look up the primary keycode that is bound to keysym. If
+ several keycodes are found, the one with the lowest index and
+ lowest code is returned. If keysym is not bound to any key, 0 is
+ returned."""
+ try:
+ return self._keymap_syms[keysym][0][1]
+ except (KeyError, IndexError):
+ return 0
+
+ def keysym_to_keycodes(self, keysym):
+ """Look up all the keycodes that is bound to keysym. A list of
+ tuples (keycode, index) is returned, sorted primarily on the
+ lowest index and secondarily on the lowest keycode."""
+ try:
+ # Copy the map list, reversing the arguments
+ return map(lambda x: (x[1], x[0]), self._keymap_syms[keysym])
+ except KeyError:
+ return []
+
+ def refresh_keyboard_mapping(self, evt):
+ """This method should be called once when a MappingNotify event
+ is received, to update the keymap cache. evt should be the event
+ object."""
+ if isinstance(evt, event.MappingNotify):
+ if evt.request == X.MappingKeyboard:
+ self._update_keymap(evt.first_keycode, evt.count)
+ else:
+ raise TypeError('expected a MappingNotify event')
+
+ def _update_keymap(self, first_keycode, count):
+ """Internal function, called to refresh the keymap cache.
+ """
+
+ # Delete all sym->code maps for the changed codes
+
+ lastcode = first_keycode + count
+ for keysym, codes in self._keymap_syms.items():
+ i = 0
+ while i < len(codes):
+ code = codes[i][1]
+ if code >= first_keycode and code < lastcode:
+ del codes[i]
+ else:
+ i = i + 1
+
+ # Get the new keyboard mapping
+ keysyms = self.get_keyboard_mapping(first_keycode, count)
+
+ # Replace code->sym map with the new map
+ self._keymap_codes[first_keycode:lastcode] = keysyms
+
+ # Update sym->code map
+ code = first_keycode
+ for syms in keysyms:
+ index = 0
+ for sym in syms:
+ if sym != X.NoSymbol:
+ if self._keymap_syms.has_key(sym):
+ symcodes = self._keymap_syms[sym]
+ symcodes.append((index, code))
+ symcodes.sort()
+ else:
+ self._keymap_syms[sym] = [(index, code)]
+
+ index = index + 1
+ code = code + 1
+
+ ###
+ ### client-internal keysym to string translations
+ ###
+
+ def lookup_string(self, keysym):
+ """Return a string corresponding to KEYSYM, or None if no
+ reasonable translation is found.
+ """
+ s = self.keysym_translations.get(keysym)
+ if s is not None:
+ return s
+
+ import Xlib.XK
+ return Xlib.XK.keysym_to_string(keysym)
+
+ def rebind_string(self, keysym, newstring):
+ """Change the translation of KEYSYM to NEWSTRING.
+ If NEWSTRING is None, remove old translation if any.
+ """
+ if newstring is None:
+ try:
+ del self.keysym_translations[keysym]
+ except KeyError:
+ pass
+ else:
+ self.keysym_translations[keysym] = newstring
+
+
+ ###
+ ### X requests
+ ###
+
+ def intern_atom(self, name, only_if_exists = 0):
+ """Intern the string name, returning its atom number. If
+ only_if_exists is true and the atom does not already exist, it
+ will not be created and X.NONE is returned."""
+ r = request.InternAtom(display = self.display,
+ name = name,
+ only_if_exists = only_if_exists)
+ return r.atom
+
+ def get_atom(self, atom, only_if_exists = 0):
+ """Alias for intern_atom, using internal cache"""
+ return self.display.get_atom(atom, only_if_exists)
+
+
+ def get_atom_name(self, atom):
+ """Look up the name of atom, returning it as a string. Will raise
+ BadAtom if atom does not exist."""
+ r = request.GetAtomName(display = self.display,
+ atom = atom)
+ return r.name
+
+ def get_selection_owner(self, selection):
+ """Return the window that owns selection (an atom), or X.NONE if
+ there is no owner for the selection. Can raise BadAtom."""
+ r = request.GetSelectionOwner(display = self.display,
+ selection = selection)
+ return r.owner
+
+ def send_event(self, destination, event, event_mask = 0, propagate = 0,
+ onerror = None):
+ """Send a synthetic event to the window destination which can be
+ a window object, or X.PointerWindow or X.InputFocus. event is the
+ event object to send, instantiated from one of the classes in
+ protocol.events. See XSendEvent(3X11) for details.
+
+ There is also a Window.send_event() method."""
+ request.SendEvent(display = self.display,
+ onerror = onerror,
+ propagate = propagate,
+ destination = destination,
+ event_mask = event_mask,
+ event = event)
+
+ def ungrab_pointer(self, time, onerror = None):
+ """elease a grabbed pointer and any queued events. See
+ XUngrabPointer(3X11)."""
+ request.UngrabPointer(display = self.display,
+ onerror = onerror,
+ time = time)
+
+ def change_active_pointer_grab(self, event_mask, cursor, time, onerror = None):
+ """Change the dynamic parameters of a pointer grab. See
+ XChangeActivePointerGrab(3X11)."""
+ request.ChangeActivePointerGrab(display = self.display,
+ onerror = onerror,
+ cursor = cursor,
+ time = time,
+ event_mask = event_mask)
+
+ def ungrab_keyboard(self, time, onerror = None):
+ """Ungrab a grabbed keyboard and any queued events. See
+ XUngrabKeyboard(3X11)."""
+ request.UngrabKeyboard(display = self.display,
+ onerror = onerror,
+ time = time)
+
+ def allow_events(self, mode, time, onerror = None):
+ """Release some queued events. mode should be one of
+ X.AsyncPointer, X.SyncPointer, X.AsyncKeyboard, X.SyncKeyboard,
+ X.ReplayPointer, X.ReplayKeyboard, X.AsyncBoth, or X.SyncBoth.
+ time should be a timestamp or X.CurrentTime."""
+ request.AllowEvents(display = self.display,
+ onerror = onerror,
+ mode = mode,
+ time = time)
+
+ def grab_server(self, onerror = None):
+ """Disable processing of requests on all other client connections
+ until the server is ungrabbed. Server grabbing should be avoided
+ as much as possible."""
+ request.GrabServer(display = self.display,
+ onerror = onerror)
+
+ def ungrab_server(self, onerror = None):
+ """Release the server if it was previously grabbed by this client."""
+ request.UngrabServer(display = self.display,
+ onerror = onerror)
+
+ def warp_pointer(self, x, y, src_window = X.NONE, src_x = 0, src_y = 0,
+ src_width = 0, src_height = 0, onerror = None):
+ """Move the pointer relative its current position by the offsets
+ (x, y). However, if src_window is a window the pointer is only
+ moved if the specified rectangle in src_window contains it. If
+ src_width is 0 it will be replaced with the width of src_window -
+ src_x. src_height is treated in a similar way.
+
+ To move the pointer to absolute coordinates, use Window.warp_pointer()."""
+ request.WarpPointer(display = self.display,
+ onerror = onerror,
+ src_window = src_window,
+ dst_window = X.NONE,
+ src_x = src_x,
+ src_y = src_y,
+ src_width = src_width,
+ src_height = src_height,
+ dst_x = x,
+ dst_y = y)
+
+ def set_input_focus(self, focus, revert_to, time, onerror = None):
+ """Set input focus to focus, which should be a window,
+ X.PointerRoot or X.NONE. revert_to specifies where the focus
+ reverts to if the focused window becomes not visible, and should
+ be X.RevertToParent, RevertToPointerRoot, or RevertToNone. See
+ XSetInputFocus(3X11) for details.
+
+ There is also a Window.set_input_focus()."""
+ request.SetInputFocus(display = self.display,
+ onerror = onerror,
+ revert_to = revert_to,
+ focus = focus,
+ time = time)
+
+ def get_input_focus(self):
+ """Return an object with the following attributes:
+
+ focus
+ The window which currently holds the input
+ focus, X.NONE or X.PointerRoot.
+ revert_to
+ Where the focus will revert, one of X.RevertToParent,
+ RevertToPointerRoot, or RevertToNone. """
+ return request.GetInputFocus(display = self.display)
+
+ def query_keymap(self):
+ """Return a bit vector for the logical state of the keyboard,
+ where each bit set to 1 indicates that the corresponding key is
+ currently pressed down. The vector is represented as a list of 32
+ integers. List item N contains the bits for keys 8N to 8N + 7
+ with the least significant bit in the byte representing key 8N."""
+ r = request.QueryKeymap(display = self.display)
+ return r.map
+
+ def open_font(self, name):
+ """Open the font identifed by the pattern name and return its
+ font object. If name does not match any font, None is returned."""
+ fid = self.display.allocate_resource_id()
+ ec = error.CatchError(error.BadName)
+
+ request.OpenFont(display = self.display,
+ onerror = ec,
+ fid = fid,
+ name = name)
+ self.sync()
+
+ if ec.get_error():
+ self.display.free_resource_id(fid)
+ return None
+ else:
+ cls = self.display.get_resource_class('font', xobject.fontable.Font)
+ return cls(self.display, fid, owner = 1)
+
+ def list_fonts(self, pattern, max_names):
+ """Return a list of font names matching pattern. No more than
+ max_names will be returned."""
+ r = request.ListFonts(display = self.display,
+ max_names = max_names,
+ pattern = pattern)
+ return r.fonts
+
+ def list_fonts_with_info(self, pattern, max_names):
+ """Return a list of fonts matching pattern. No more than
+ max_names will be returned. Each list item represents one font
+ and has the following properties:
+
+ name
+ The name of the font.
+ min_bounds
+ max_bounds
+ min_char_or_byte2
+ max_char_or_byte2
+ default_char
+ draw_direction
+ min_byte1
+ max_byte1
+ all_chars_exist
+ font_ascent
+ font_descent
+ replies_hint
+ See the descripton of XFontStruct in XGetFontProperty(3X11)
+ for details on these values.
+ properties
+ A list of properties. Each entry has two attributes:
+
+ name
+ The atom identifying this property.
+ value
+ A 32-bit unsigned value.
+ """
+ return request.ListFontsWithInfo(display = self.display,
+ max_names = max_names,
+ pattern = pattern)
+
+ def set_font_path(self, path, onerror = None):
+ """Set the font path to path, which should be a list of strings.
+ If path is empty, the default font path of the server will be
+ restored."""
+ request.SetFontPath(display = self.display,
+ onerror = onerror,
+ path = path)
+
+ def get_font_path(self):
+ """Return the current font path as a list of strings."""
+ r = request.GetFontPath(display = self.display)
+ return r.paths
+
+ def query_extension(self, name):
+ """Ask the server if it supports the extension name. If it is
+ supported an object with the following attributes is returned:
+
+ major_opcode
+ The major opcode that the requests of this extension uses.
+ first_event
+ The base event code if the extension have additional events, or 0.
+ first_error
+ The base error code if the extension have additional errors, or 0.
+
+ If the extension is not supported, None is returned."""
+ r = request.QueryExtension(display = self.display,
+ name = name)
+ if r.present:
+ return r
+ else:
+ return None
+
+ def list_extensions(self):
+ """Return a list of all the extensions provided by the server."""
+ r = request.ListExtensions(display = self.display)
+ return r.names
+
+ def change_keyboard_mapping(self, first_keycode, keysyms, onerror = None):
+ """Modify the keyboard mapping, starting with first_keycode.
+ keysyms is a list of tuples of keysyms. keysyms[n][i] will be
+ assigned to keycode first_keycode+n at index i."""
+ request.ChangeKeyboardMapping(display = self.display,
+ onerror = onerror,
+ first_keycode = first_keycode,
+ keysyms = keysyms)
+
+ def get_keyboard_mapping(self, first_keycode, count):
+ """Return the current keyboard mapping as a list of tuples,
+ starting at first_keycount and no more than count."""
+ r = request.GetKeyboardMapping(display = self.display,
+ first_keycode = first_keycode,
+ count = count)
+ return r.keysyms
+
+ def change_keyboard_control(self, onerror = None, **keys):
+ """Change the parameters provided as keyword arguments:
+
+ key_click_percent
+ The volume of key clicks between 0 (off) and 100 (load).
+ -1 will restore default setting.
+ bell_percent
+ The base volume of the bell, coded as above.
+ bell_pitch
+ The pitch of the bell in Hz, -1 restores the default.
+ bell_duration
+ The duration of the bell in milliseconds, -1 restores
+ the default.
+ led
+
+ led_mode
+ led_mode should be X.LedModeOff or X.LedModeOn. If led is
+ provided, it should be a 32-bit mask listing the LEDs that
+ should change. If led is not provided, all LEDs are changed.
+ key
+
+ auto_repeat_mode
+ auto_repeat_mode should be one of X.AutoRepeatModeOff,
+ X.AutoRepeatModeOn, or X.AutoRepeatModeDefault. If key is
+ provided, that key will be modified, otherwise the global
+ state for the entire keyboard will be modified."""
+ request.ChangeKeyboardControl(display = self.display,
+ onerror = onerror,
+ attrs = keys)
+
+ def get_keyboard_control(self):
+ """Return an object with the following attributes:
+
+ global_auto_repeat
+ X.AutoRepeatModeOn or X.AutoRepeatModeOff.
+
+ auto_repeats
+ A list of 32 integers. List item N contains the bits for keys
+ 8N to 8N + 7 with the least significant bit in the byte
+ representing key 8N. If a bit is on, autorepeat is enabled
+ for the corresponding key.
+
+ led_mask
+ A 32-bit mask indicating which LEDs are on.
+
+ key_click_percent
+ The volume of key click, from 0 to 100.
+
+ bell_percent
+
+ bell_pitch
+
+ bell_duration
+ The volume, pitch and duration of the bell. """
+ return request.GetKeyboardControl(display = self.display)
+
+ def bell(self, percent = 0, onerror = None):
+ """Ring the bell at the volume percent which is relative the base
+ volume. See XBell(3X11)."""
+ request.Bell(display = self.display,
+ onerror = onerror,
+ percent = percent)
+
+ def change_pointer_control(self, accel = None, threshold = None, onerror = None):
+ """To change the pointer acceleration, set accel to a tuple (num,
+ denum). The pointer will then move num/denum times the normal
+ speed if it moves beyond the threshold number of pixels at once.
+ To change the threshold, set it to the number of pixels. -1
+ restores the default."""
+ if accel is None:
+ do_accel = 0
+ accel_num = 0
+ accel_denum = 0
+ else:
+ do_accel = 1
+ accel_num, accel_denum = accel
+
+ if threshold is None:
+ do_threshold = 0
+ else:
+ do_threshold = 1
+
+ request.ChangePointerControl(display = self.display,
+ onerror = onerror,
+ do_accel = do_accel,
+ do_thres = do_threshold,
+ accel_num = accel_num,
+ accel_denum = accel_denum,
+ threshold = threshold)
+
+ def get_pointer_control(self):
+ """Return an object with the following attributes:
+
+ accel_num
+
+ accel_denom
+ The acceleration as numerator/denumerator.
+
+ threshold
+ The number of pixels the pointer must move before the
+ acceleration kicks in."""
+ return request.GetPointerControl(display = self.display)
+
+ def set_screen_saver(self, timeout, interval, prefer_blank, allow_exposures, onerror = None):
+ """See XSetScreenSaver(3X11)."""
+ request.SetScreenSaver(display = self.display,
+ onerror = onerror,
+ timeout = timeout,
+ interval = interval,
+ prefer_blank = prefer_blank,
+ allow_exposures = allow_exposures)
+
+ def get_screen_saver(self):
+ """Return an object with the attributes timeout, interval,
+ prefer_blanking, allow_exposures. See XGetScreenSaver(3X11) for
+ details."""
+ return request.GetScreenSaver(display = self.display)
+
+ def change_hosts(self, mode, host_family, host, onerror = None):
+ """mode is either X.HostInsert or X.HostDelete. host_family is
+ one of X.FamilyInternet, X.FamilyDECnet or X.FamilyChaos.
+
+ host is a list of bytes. For the Internet family, it should be the
+ four bytes of an IPv4 address."""
+ request.ChangeHosts(display = self.display,
+ onerror = onerror,
+ mode = mode,
+ host_family = host_family,
+ host = host)
+
+ def list_hosts(self):
+ """Return an object with the following attributes:
+
+mode
+ X.EnableAccess if the access control list is used, X.DisableAccess otherwise.
+hosts
+ The hosts on the access list. Each entry has the following attributes:
+
+ family
+ X.FamilyInternet, X.FamilyDECnet, or X.FamilyChaos.
+ name
+ A list of byte values, the coding depends on family. For the Internet family, it is the 4 bytes of an IPv4 address.
+
+"""
+ return request.ListHosts(display = self.display)
+
+ def set_access_control(self, mode, onerror = None):
+ """Enable use of access control lists at connection setup if mode
+ is X.EnableAccess, disable if it is X.DisableAccess."""
+ request.SetAccessControl(display = self.display,
+ onerror = onerror,
+ mode = mode)
+
+ def set_close_down_mode(self, mode, onerror = None):
+ """Control what will happen with the client's resources at
+ connection close. The default is X.DestroyAll, the other values
+ are X.RetainPermanent and X.RetainTemporary."""
+ request.SetCloseDownMode(display = self.display,
+ onerror = onerror,
+ mode = mode)
+
+ def force_screen_saver(self, mode, onerror = None):
+ """If mode is X.ScreenSaverActive the screen saver is activated.
+ If it is X.ScreenSaverReset, the screen saver is deactivated as
+ if device input had been received."""
+ request.ForceScreenSaver(display = self.display,
+ onerror = onerror,
+ mode = mode)
+
+ def set_pointer_mapping(self, map):
+ """Set the mapping of the pointer buttons. map is a list of
+ logical button numbers. map must be of the same length as the
+ list returned by Display.get_pointer_mapping().
+
+ map[n] sets the
+ logical number for the physical button n+1. Logical number 0
+ disables the button. Two physical buttons cannot be mapped to the
+ same logical number.
+
+ If one of the buttons to be altered are
+ logically in the down state, X.MappingBusy is returned and the
+ mapping is not changed. Otherwise the mapping is changed and
+ X.MappingSuccess is returned."""
+ r = request.SetPointerMapping(display = self.display,
+ map = map)
+ return r.status
+
+ def get_pointer_mapping(self):
+ """Return a list of the pointer button mappings. Entry N in the
+ list sets the logical button number for the physical button N+1."""
+ r = request.GetPointerMapping(display = self.display)
+ return r.map
+
+ def set_modifier_mapping(self, keycodes):
+ """Set the keycodes for the eight modifiers X.Shift, X.Lock,
+ X.Control, X.Mod1, X.Mod2, X.Mod3, X.Mod4 and X.Mod5. keycodes
+ should be a eight-element list where each entry is a list of the
+ keycodes that should be bound to that modifier.
+
+ If any changed
+ key is logically in the down state, X.MappingBusy is returned and
+ the mapping is not changed. If the mapping violates some server
+ restriction, X.MappingFailed is returned. Otherwise the mapping
+ is changed and X.MappingSuccess is returned."""
+ r = request.SetModifierMapping(display = self.display,
+ keycodes = keycodes)
+ return r.status
+
+ def get_modifier_mapping(self):
+ """Return a list of eight lists, one for each modifier. The list
+ can be indexed using X.ShiftMapIndex, X.Mod1MapIndex, and so on.
+ The sublists list the keycodes bound to that modifier."""
+ r = request.GetModifierMapping(display = self.display)
+ return r.keycodes
+
+ def no_operation(self, onerror = None):
+ """Do nothing but send a request to the server."""
+ request.NoOperation(display = self.display,
+ onerror = onerror)
diff --git a/Xlib/error.py b/Xlib/error.py
new file mode 100644
index 0000000..a40f6cf
--- /dev/null
+++ b/Xlib/error.py
@@ -0,0 +1,162 @@
+# $Id: error.py,v 1.6 2007/06/10 14:11:58 mggrant Exp $
+#
+# Xlib.error -- basic error classes
+#
+# Copyright (C) 2000 Peter Liljenberg <petli@ctrl-c.liu.se>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+# Standard modules
+import string
+
+# Xlib modules
+import X
+
+# Xlib.protocol modules
+from Xlib.protocol import rq
+
+
+class DisplayError(Exception):
+ def __init__(self, display):
+ self.display = display
+
+ def __str__(self):
+ return 'Display error "%s"' % self.display
+
+class DisplayNameError(DisplayError):
+ def __str__(self):
+ return 'Bad display name "%s"' % self.display
+
+class DisplayConnectionError(DisplayError):
+ def __init__(self, display, msg):
+ self.display = display
+ self.msg = msg
+
+ def __str__(self):
+ return 'Can\'t connect to display "%s": %s' % (self.display, self.msg)
+
+class ConnectionClosedError(Exception):
+ def __init__(self, whom):
+ self.whom = whom
+
+ def __str__(self):
+ return 'Display connection closed by %s' % self.whom
+
+
+class XauthError(Exception): pass
+class XNoAuthError(Exception): pass
+
+class ResourceIDError(Exception): pass
+
+
+class XError(rq.GetAttrData, Exception):
+ _fields = rq.Struct( rq.Card8('type'), # Always 0
+ rq.Card8('code'),
+ rq.Card16('sequence_number'),
+ rq.Card32('resource_id'),
+ rq.Card16('minor_opcode'),
+ rq.Card8('major_opcode'),
+ rq.Pad(21)
+ )
+
+ def __init__(self, display, data):
+ self._data, data = self._fields.parse_binary(data, display, rawdict = 1)
+
+ def __str__(self):
+ s = []
+ for f in ('code', 'resource_id', 'sequence_number',
+ 'major_opcode', 'minor_opcode'):
+ s.append('%s = %s' % (f, self._data[f]))
+
+ return '%s: %s' % (self.__class__, string.join(s, ', '))
+
+class XResourceError(XError):
+ _fields = rq.Struct( rq.Card8('type'), # Always 0
+ rq.Card8('code'),
+ rq.Card16('sequence_number'),
+ rq.Resource('resource_id'),
+ rq.Card16('minor_opcode'),
+ rq.Card8('major_opcode'),
+ rq.Pad(21)
+ )
+
+class BadRequest(XError): pass
+class BadValue(XError): pass
+class BadWindow(XResourceError): pass
+class BadPixmap(XResourceError): pass
+class BadAtom(XError): pass
+class BadCursor(XResourceError): pass
+class BadFont(XResourceError): pass
+class BadMatch(XError): pass
+class BadDrawable(XResourceError): pass
+class BadAccess(XError): pass
+class BadAlloc(XError): pass
+class BadColor(XResourceError): pass
+class BadGC(XResourceError): pass
+class BadIDChoice(XResourceError): pass
+class BadName(XError): pass
+class BadLength(XError): pass
+class BadImplementation(XError): pass
+
+xerror_class = {
+ X.BadRequest: BadRequest,
+ X.BadValue: BadValue,
+ X.BadWindow: BadWindow,
+ X.BadPixmap: BadPixmap,
+ X.BadAtom: BadAtom,
+ X.BadCursor: BadCursor,
+ X.BadFont: BadFont,
+ X.BadMatch: BadMatch,
+ X.BadDrawable: BadDrawable,
+ X.BadAccess: BadAccess,
+ X.BadAlloc: BadAlloc,
+ X.BadColor: BadColor,
+ X.BadGC: BadGC,
+ X.BadIDChoice: BadIDChoice,
+ X.BadName: BadName,
+ X.BadLength: BadLength,
+ X.BadImplementation: BadImplementation,
+ }
+
+
+class CatchError:
+ def __init__(self, *errors):
+ self.error_types = errors
+ self.error = None
+ self.request = None
+
+ def __call__(self, error, request):
+ if self.error_types:
+ for etype in self.error_types:
+ if isinstance(error, etype):
+ self.error = error
+ self.request = request
+ return 1
+
+ return 0
+ else:
+ self.error = error
+ self.request = request
+ return 1
+
+ def get_error(self):
+ return self.error
+
+ def get_request(self):
+ return self.request
+
+ def reset(self):
+ self.error = None
+ self.request = None
diff --git a/Xlib/ext/__init__.py b/Xlib/ext/__init__.py
new file mode 100644
index 0000000..79e5ed9
--- /dev/null
+++ b/Xlib/ext/__init__.py
@@ -0,0 +1,32 @@
+# $Id: __init__.py,v 1.5 2007/06/10 14:11:58 mggrant Exp $
+#
+# Xlib.ext.__init__ -- X extension modules
+#
+# Copyright (C) 2000 Peter Liljenberg <petli@ctrl-c.liu.se>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+# __extensions__ is a list of tuples: (extname, extmod)
+# extname is the name of the extension according to the X
+# protocol. extmod is the name of the module in this package.
+
+__extensions__ = [
+ ('XTEST', 'xtest'),
+ ('SHAPE', 'shape'),
+ ('XINERAMA', 'xinerama'),
+ ('RECORD', 'record'),
+ ]
+
+__all__ = map(lambda x: x[1], __extensions__)
diff --git a/Xlib/ext/record.py b/Xlib/ext/record.py
new file mode 100644
index 0000000..1cb6ac5
--- /dev/null
+++ b/Xlib/ext/record.py
@@ -0,0 +1,280 @@
+# $Id: record.py,v 1.2 2007/06/10 14:11:58 mggrant Exp $
+#
+# Xlib.ext.record -- RECORD extension module
+#
+# Copyright (C) 2006 Alex Badea <vamposdecampos@gmail.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+from Xlib import X
+from Xlib.protocol import rq
+
+extname = 'RECORD'
+
+FromServerTime = 0x01
+FromClientTime = 0x02
+FromClientSequence = 0x04
+
+CurrentClients = 1
+FutureClients = 2
+AllClients = 3
+
+FromServer = 0
+FromClient = 1
+ClientStarted = 2
+ClientDied = 3
+StartOfData = 4
+EndOfData = 5
+
+Record_Range8 = rq.Struct(
+ rq.Card8('first'),
+ rq.Card8('last'))
+Record_Range16 = rq.Struct(
+ rq.Card16('first'),
+ rq.Card16('last'))
+Record_ExtRange = rq.Struct(
+ rq.Object('major_range', Record_Range8),
+ rq.Object('minor_range', Record_Range16))
+Record_Range = rq.Struct(
+ rq.Object('core_requests', Record_Range8),
+ rq.Object('core_replies', Record_Range8),
+ rq.Object('ext_requests', Record_ExtRange),
+ rq.Object('ext_replies', Record_ExtRange),
+ rq.Object('delivered_events', Record_Range8),
+ rq.Object('device_events', Record_Range8),
+ rq.Object('errors', Record_Range8),
+ rq.Bool('client_started'),
+ rq.Bool('client_died'))
+
+Record_ClientInfo = rq.Struct(
+ rq.Card32('client_resource'),
+ rq.LengthOf('ranges', 4),
+ rq.List('ranges', Record_Range))
+
+
+class RawField(rq.ValueField):
+ """A field with raw data, stored as a string"""
+
+ structcode = None
+
+ def pack_value(self, val):
+ return val, len(val), None
+
+ def parse_binary_value(self, data, display, length, format):
+ return str(data), ''
+
+
+class GetVersion(rq.ReplyRequest):
+ _request = rq.Struct(
+ rq.Card8('opcode'),
+ rq.Opcode(0),
+ rq.RequestLength(),
+ rq.Card16('major_version'),
+ rq.Card16('minor_version'))
+ _reply = rq.Struct(
+ rq.Pad(2),
+ rq.Card16('sequence_number'),
+ rq.ReplyLength(),
+ rq.Card16('major_version'),
+ rq.Card16('minor_version'),
+ rq.Pad(20))
+
+def get_version(self, major, minor):
+ return GetVersion(
+ display = self.display,
+ opcode = self.display.get_extension_major(extname),
+ major_version = major,
+ minor_version = minor)
+
+
+class CreateContext(rq.Request):
+ _request = rq.Struct(
+ rq.Card8('opcode'),
+ rq.Opcode(1),
+ rq.RequestLength(),
+ rq.Card32('context'), # Record_RC
+ rq.Card8('element_header'), # Record_Element_Header
+ rq.Pad(3),
+ rq.LengthOf('clients', 4),
+ rq.LengthOf('ranges', 4),
+ rq.List('clients', rq.Card32Obj),
+ rq.List('ranges', Record_Range))
+
+def create_context(self, datum_flags, clients, ranges):
+ context = self.display.allocate_resource_id()
+ CreateContext(
+ display = self.display,
+ opcode = self.display.get_extension_major(extname),
+ context = context,
+ element_header = datum_flags,
+ clients = clients,
+ ranges = ranges)
+ return context
+
+
+class RegisterClients(rq.Request):
+ _request = rq.Struct(
+ rq.Card8('opcode'),
+ rq.Opcode(2),
+ rq.RequestLength(),
+ rq.Card32('context'), # Record_RC
+ rq.Card8('element_header'), # Record_Element_Header
+ rq.Pad(3),
+ rq.LengthOf('clients', 4),
+ rq.LengthOf('ranges', 4),
+ rq.List('clients', rq.Card32Obj),
+ rq.List('ranges', Record_Range))
+
+def register_clients(self, context, element_header, clients, ranges):
+ RegisterClients(
+ display = self.display,
+ opcode = self.display.get_extension_major(extname),
+ context = context,
+ element_header = element_header,
+ clients = clients,
+ ranges = ranges)
+
+
+class UnregisterClients(rq.Request):
+ _request = rq.Struct(
+ rq.Card8('opcode'),
+ rq.Opcode(3),
+ rq.RequestLength(),
+ rq.Card32('context'), # Record_RC
+ rq.LengthOf('clients', 4),
+ rq.List('clients', rq.Card32Obj))
+
+def unregister_clients(self, context, clients):
+ UnregisterClients(
+ display = self.display,
+ opcode = self.display.get_extension_major(extname),
+ context = context,
+ clients = clients)
+
+
+class GetContext(rq.ReplyRequest):
+ _request = rq.Struct(
+ rq.Card8('opcode'),
+ rq.Opcode(4),
+ rq.RequestLength(),
+ rq.Card32('context')) # Record_RC
+ _reply = rq.Struct(
+ rq.Pad(2),
+ rq.Card16('sequence_number'),
+ rq.ReplyLength(),
+ rq.Card8('element_header'), # Record_Element_Header
+ rq.Pad(3),
+ rq.LengthOf('client_info', 4),
+ rq.Pad(16),
+ rq.List('client_info', Record_ClientInfo))
+
+def get_context(self, context):
+ return GetContext(
+ display = self.display,
+ opcode = self.display.get_extension_major(extname),
+ context = context)
+
+
+class EnableContext(rq.ReplyRequest):
+ _request = rq.Struct(
+ rq.Card8('opcode'),
+ rq.Opcode(5),
+ rq.RequestLength(),
+ rq.Card32('context')) # Record_RC
+ _reply = rq.Struct(
+ rq.Pad(1),
+ rq.Card8('category'),
+ rq.Card16('sequence_number'),
+ rq.ReplyLength(),
+ rq.Card8('element_header'), # Record_Element_Header
+ rq.Bool('client_swapped'),
+ rq.Pad(2),
+ rq.Card32('id_base'), # Record_XIDBase
+ rq.Card32('server_time'),
+ rq.Card32('recorded_sequence_number'),
+ rq.Pad(8),
+ RawField('data'))
+
+ # This request receives multiple responses, so we need to keep
+ # ourselves in the 'sent_requests' list in order to receive them all.
+
+ # See the discussion on ListFonstsWithInfo in request.py
+
+ def __init__(self, callback, *args, **keys):
+ self._callback = callback
+ apply(rq.ReplyRequest.__init__, (self, ) + args, keys)
+
+ def _parse_response(self, data):
+ r, d = self._reply.parse_binary(data, self._display)
+ self._callback(r)
+
+ if r.category == StartOfData:
+ # Hack ourselves a sequence number, used by the code in
+ # Xlib.protocol.display.Display.parse_request_response()
+ self.sequence_number = r.sequence_number
+
+ if r.category == EndOfData:
+ self._response_lock.acquire()
+ self._data = r
+ self._response_lock.release()
+ else:
+ self._display.sent_requests.insert(0, self)
+
+def enable_context(self, context, callback):
+ EnableContext(
+ callback = callback,
+ display = self.display,
+ opcode = self.display.get_extension_major(extname),
+ context = context)
+
+
+class DisableContext(rq.Request):
+ _request = rq.Struct(
+ rq.Card8('opcode'),
+ rq.Opcode(6),
+ rq.RequestLength(),
+ rq.Card32('context')) # Record_RC
+
+def disable_context(self, context):
+ DisableContext(
+ display = self.display,
+ opcode = self.display.get_extension_major(extname),
+ context = context)
+
+
+class FreeContext(rq.Request):
+ _request = rq.Struct(
+ rq.Card8('opcode'),
+ rq.Opcode(7),
+ rq.RequestLength(),
+ rq.Card32('context')) # Record_RC
+
+def free_context(self, context):
+ FreeContext(
+ display = self.display,
+ opcode = self.display.get_extension_major(extname),
+ context = context)
+ self.display.free_resource_id(context)
+
+
+def init(disp, info):
+ disp.extension_add_method('display', 'record_get_version', get_version)
+ disp.extension_add_method('display', 'record_create_context', create_context)
+ disp.extension_add_method('display', 'record_register_clients', register_clients)
+ disp.extension_add_method('display', 'record_unregister_clients', unregister_clients)
+ disp.extension_add_method('display', 'record_get_context', get_context)
+ disp.extension_add_method('display', 'record_enable_context', enable_context)
+ disp.extension_add_method('display', 'record_disable_context', disable_context)
+ disp.extension_add_method('display', 'record_free_context', free_context)
diff --git a/Xlib/ext/shape.py b/Xlib/ext/shape.py
new file mode 100644
index 0000000..fd0d157
--- /dev/null
+++ b/Xlib/ext/shape.py
@@ -0,0 +1,334 @@
+# Xlib.ext.shape -- SHAPE extension module
+#
+# Copyright (C) 2002 Jeffrey Boser <verin@lvcm.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+# Constants to use
+#
+# Regions of a window
+ShapeBounding = 0 # the 'edge' of a shaped window
+ShapeClip = 1 # the clipping region
+# Shape Operations
+ShapeSet = 0 # Set the region unmodified (dest=src)
+ShapeUnion = 1 # Add the new region to the old (dest=src|dest)
+ShapeIntersect = 2 # Use the intersection (dest=src&dest)
+ShapeSubtract = 3 # remove region (dest = dest - intersect)
+ShapeInvert = 4 # opposite of subtract (dest = src - intersect)
+# Events
+ShapeNotifyMask = (1<<0) #a keypress mask?
+ShapeNotify = 0 #still unsure of these values
+
+# How to Use
+# The basic functions that change the shapes of things are:
+# shape_rectangles (uses a set of rectangles as the source)
+# operation, region, ordering, rects
+# shape_mask (uses a bitmap as the source)
+# operation, region, x_offset, y_offset, bitmap
+# shape_combine (uses a window as the source)
+# operation, src_region, dest_region, x_offset, y_offset, src_window
+# shape_offset (moves the region)
+# region, x_offset, y_offset
+# The functions to find stuff out (these three return mappings of field/values):
+# shape_query_version (shape extension version)
+# major_version, minor_version
+# shape_query_extents (rectangle boundaries of a window's regions)
+# clip_shaped, clip_x, clip_y, clip_width, clip_height,
+# bounding_shaped, bounding_x, bounding_y, bounding_width, bounding_height
+# shape_input_selected (if the window products shapenotify events)
+# enabled
+# shape_get_rectangles (the rectangles set by shape_rectangles)
+# ordering, rects
+# And to turn on shape notify events:
+# shape_select_input
+# enable
+
+
+
+from Xlib import X
+from Xlib.protocol import rq, structs
+
+extname = 'SHAPE'
+
+class QueryVersion(rq.ReplyRequest):
+ _request = rq.Struct(
+ rq.Card8('opcode'),
+ rq.Opcode(0),
+ rq.RequestLength(),
+ )
+ _reply = rq.Struct(
+ rq.ReplyCode(),
+ rq.Pad(1),
+ rq.Card16('sequence_number'),
+ rq.ReplyLength(),
+ rq.Card16('major_version'),
+ rq.Card16('minor_version'),
+ rq.Pad(20),
+ )
+
+def query_version(self):
+ return QueryVersion(
+ display = self.display,
+ opcode = self.display.get_extension_major(extname),
+ )
+
+
+
+class Rectangles(rq.Request):
+ _request = rq.Struct(
+ rq.Card8('opcode'),
+ rq.Opcode(1),
+ rq.RequestLength(),
+ rq.Card8('operation'),
+ rq.Set('region', 1, (ShapeBounding, ShapeClip)),
+ rq.Card8('ordering'),
+ rq.Pad(1),
+ rq.Window('window'),
+ rq.Int16('x'),
+ rq.Int16('y'),
+ rq.List('rectangles', structs.Rectangle),
+ )
+
+def rectangles(self, region, operation, ordering, x, y, rectangles):
+ Rectangles(
+ display = self.display,
+ opcode = self.display.get_extension_major(extname),
+ operation = operation,
+ region = region,
+ ordering = ordering,
+ window = self.id,
+ x = x,
+ y = y,
+ rectangles = rectangles,
+ )
+
+
+
+class Mask(rq.Request):
+ _request = rq.Struct(
+ rq.Card8('opcode'),
+ rq.Opcode(2),
+ rq.RequestLength(),
+ rq.Card8('operation'),
+ rq.Set('region', 1, (ShapeBounding, ShapeClip)),
+ rq.Pad(2),
+ rq.Window('window'),
+ rq.Int16('x'),
+ rq.Int16('y'),
+ rq.Pixmap('source', (X.NONE, )),
+ )
+
+def mask(self, operation, region, x, y, source):
+ Mask(display = self.display,
+ opcode = self.display.get_extension_major(extname),
+ window = self.id,
+ operation = operation,
+ region = region,
+ x = x,
+ y = y,
+ source = source,
+ )
+
+
+class Combine(rq.Request):
+ _request = rq.Struct(
+ rq.Card8('opcode'),
+ rq.Opcode(3),
+ rq.RequestLength(),
+ rq.Card8('operation'),
+ rq.Set('dest_region', 1, (ShapeBounding, ShapeClip)),
+ rq.Set('source_region', 1, (ShapeBounding, ShapeClip)),
+ rq.Pad(1),
+ rq.Window('dest'),
+ rq.Int16('x'),
+ rq.Int16('y'),
+ rq.Window('source'),
+ )
+
+def combine(self, operation, region, source, source_region, x, y):
+ Combine(
+ display = self.display,
+ opcode = self.display.get_extension_major(extname),
+ operation = operation,
+ dest_region = region,
+ source_region = source_region,
+ dest = self.id,
+ x = x,
+ y = y,
+ source = source,
+ )
+
+
+
+class Offset(rq.Request):
+ _request = rq.Struct(
+ rq.Card8('opcode'),
+ rq.Opcode(4),
+ rq.RequestLength(),
+ rq.Set('region', 1, (ShapeBounding, ShapeClip)),
+ rq.Pad(3),
+ rq.Window('window'),
+ rq.Int16('x'),
+ rq.Int16('y'),
+ )
+
+def offset(self, region, x, y):
+ Offset(
+ display = self.display,
+ opcode = self.display.get_extension_major(extname),
+ region = region,
+ window = self.id,
+ x = x,
+ y = y,
+ )
+
+
+
+class QueryExtents(rq.ReplyRequest):
+ _request = rq.Struct(
+ rq.Card8('opcode'),
+ rq.Opcode(5),
+ rq.RequestLength(),
+ rq.Window('window'),
+ )
+
+ _reply = rq.Struct(
+ rq.ReplyCode(),
+ rq.Pad(1),
+ rq.Card16('sequence_number'),
+ rq.ReplyLength(),
+ rq.Bool('bounding_shaped'),
+ rq.Bool('clip_shaped'),
+ rq.Pad(2),
+ rq.Int16('bounding_x'),
+ rq.Int16('bounding_y'),
+ rq.Card16('bounding_width'),
+ rq.Card16('bounding_height'),
+ rq.Int16('clip_x'),
+ rq.Int16('clip_y'),
+ rq.Card16('clip_width'),
+ rq.Card16('clip_height'),
+ rq.Pad(4),
+ )
+
+def query_extents(self):
+ return QueryExtents(
+ display = self.display,
+ opcode = self.display.get_extension_major(extname),
+ window = self.id,
+ )
+
+
+class SelectInput(rq.Request):
+ _request = rq.Struct(
+ rq.Card8('opcode'),
+ rq.Opcode(6),
+ rq.RequestLength(),
+ rq.Window('window'),
+ rq.Bool('enable'),
+ rq.Pad(3),
+ )
+
+def select_input(self, enable = 1):
+ SelectInput(
+ display = self.display,
+ opcode = self.display.get_extension_major(extname),
+ window = self.id,
+ enable = enable,
+ )
+
+
+class InputSelected(rq.ReplyRequest):
+ _request = rq.Struct(
+ rq.Card8('opcode'),
+ rq.Opcode(7),
+ rq.RequestLength(),
+ rq.Window('window'),
+ )
+
+ _reply = rq.Struct(
+ rq.ReplyCode(),
+ rq.Bool('enabled'),
+ rq.Card16('sequence_number'),
+ rq.ReplyLength(),
+ rq.Pad(24),
+ )
+
+def input_selected(self):
+ reply = InputSelected(
+ display = self.display,
+ opcode = self.display.get_extension_major(extname),
+ window = self.id,
+ )
+ return reply.enabled
+
+
+class GetRectangles(rq.ReplyRequest):
+ _request = rq.Struct(
+ rq.Card8('opcode'),
+ rq.Opcode(8),
+ rq.RequestLength(),
+ rq.Window('window'),
+ rq.Set('region', 1, (ShapeBounding, ShapeClip)),
+ rq.Pad(3),
+ )
+
+ _reply = rq.Struct(
+ rq.ReplyCode(),
+ rq.Card8('ordering'),
+ rq.Card16('sequence_number'),
+ rq.ReplyLength(),
+ rq.LengthOf('rectangles', 4),
+ rq.Pad(20),
+ rq.List('rectangles', structs.Rectangle),
+ )
+
+def get_rectangles(self, region):
+ return GetRectangles(
+ display = self.display,
+ opcode = self.display.get_extension_major(extname),
+ window = self.id,
+ region = region,
+ )
+
+
+class ShapeNotify(rq.Event):
+ _code = None
+ _fields = rq.Struct( rq.Card8('type'),
+ rq.Set('region', 1, (ShapeBounding, ShapeClip)),
+ rq.Card16('sequence_number'),
+ rq.Window('window'),
+ rq.Int16('x'),
+ rq.Int16('y'),
+ rq.Card16('width'),
+ rq.Card16('height'),
+ rq.Card32('time'),
+ rq.Bool('shaped'),
+ rq.Pad(11),
+ )
+
+def init(disp, info):
+ disp.extension_add_method('display', 'shape_query_version', query_version )
+ disp.extension_add_method('window', 'shape_rectangles', rectangles )
+ disp.extension_add_method('window', 'shape_mask', mask )
+ disp.extension_add_method('window', 'shape_combine', combine )
+ disp.extension_add_method('window', 'shape_offset', offset )
+ disp.extension_add_method('window', 'shape_query_extents', query_extents )
+ disp.extension_add_method('window', 'shape_select_input', select_input )
+ disp.extension_add_method('window', 'shape_input_selected', input_selected )
+ disp.extension_add_method('window', 'shape_get_rectangles', get_rectangles )
+
+ disp.extension_add_event(info.first_event, ShapeNotify)
diff --git a/Xlib/ext/xinerama.py b/Xlib/ext/xinerama.py
new file mode 100644
index 0000000..65d7bd4
--- /dev/null
+++ b/Xlib/ext/xinerama.py
@@ -0,0 +1,221 @@
+# Xlib.ext.xinerama -- Xinerama extension module
+#
+# Copyright (C) 2006 Mike Meyer <mwm@mired.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+
+"""Xinerama - provide access to the Xinerama extension information.
+
+There are at least there different - and mutually incomparable -
+Xinerama extensions available. This uses the one bundled with XFree86
+4.6 and/or Xorg 6.9 in the ati/radeon driver. It uses the include
+files from that X distribution, so should work with it as well. I
+provide code for the lone Sun 1.0 request that isn't part of 1.1, but
+this is untested because I don't have a server that implements it.
+
+The functions loosely follow the libXineram functions. Mostly, they
+return an rq.Struct in lieue of passing in pointers that get data from
+the rq.Struct crammed into them. The exception is isActive, which
+returns the state information - because that's what libXinerama does."""
+
+
+from Xlib import X
+from Xlib.protocol import rq, structs
+
+extname = 'XINERAMA'
+
+
+class QueryVersion(rq.ReplyRequest):
+ _request = rq.Struct(
+ rq.Card8('opcode'),
+ rq.Opcode(0),
+ rq.RequestLength(),
+ rq.Card8('major_version'),
+ rq.Card8('minor_version'),
+ rq.Pad(2),
+ )
+
+ _reply = rq.Struct(
+ rq.ReplyCode(),
+ rq.Pad(1),
+ rq.Card16('sequence_number'),
+ rq.ReplyLength(),
+ rq.Card16('major_version'),
+ rq.Card16('minor_version'),
+ rq.Pad(20),
+ )
+
+def query_version(self):
+ return QueryVersion(display=self.display,
+ opcode=self.display.get_extension_major(extname),
+ major_version=1,
+ minor_version=1)
+
+
+class GetState(rq.ReplyRequest):
+ _request = rq.Struct(
+ rq.Card8('opcode'),
+ rq.Opcode(1),
+ rq.RequestLength(),
+ rq.Window('window'),
+ )
+ _reply = rq.Struct(
+ rq.ReplyCode(),
+ rq.Bool('state'),
+ rq.Card16('sequence_number'),
+ rq.ReplyLength(),
+ rq.Window('window'),
+ rq.Pad(20),
+ )
+
+def get_state(self):
+ return GetState(display=self.display,
+ opcode=self.display.get_extension_major(extname),
+ window=self.id,
+ )
+
+
+class GetScreenCount(rq.ReplyRequest):
+ _request = rq.Struct(
+ rq.Card8('opcode'),
+ rq.Opcode(2),
+ rq.RequestLength(),
+ rq.Window('window'),
+ )
+ _reply = rq.Struct(
+ rq.ReplyCode(),
+ rq.Card8('screen_count'),
+ rq.Card16('sequence_number'),
+ rq.ReplyLength(),
+ rq.Window('window'),
+ rq.Pad(20),
+ )
+
+def get_screen_count(self):
+ return GetScreenCount(display=self.display,
+ opcode=self.display.get_extension_major(extname),
+ window=self.id,
+ )
+
+
+class GetScreenSize(rq.ReplyRequest):
+ _request = rq.Struct(
+ rq.Card8('opcode'),
+ rq.Opcode(3),
+ rq.RequestLength(),
+ rq.Window('window'),
+ rq.Card32('screen'),
+ )
+ _reply = rq.Struct(
+ rq.ReplyCode(),
+ rq.Pad(1),
+ rq.Card16('sequence_number'),
+ rq.Card32('length'),
+ rq.Card32('width'),
+ rq.Card32('height'),
+ rq.Window('window'),
+ rq.Card32('screen'),
+ rq.Pad(8),
+ )
+
+def get_screen_size(self, screen_no):
+ """Returns the size of the given screen number"""
+ return GetScreenSize(display=self.display,
+ opcode=self.display.get_extension_major(extname),
+ window=self.id,
+ screen=screen_no,
+ )
+
+
+# IsActive is only available from Xinerama 1.1 and later.
+# It should be used in preference to GetState.
+class IsActive(rq.ReplyRequest):
+ _request = rq.Struct(
+ rq.Card8('opcode'),
+ rq.Opcode(4),
+ rq.RequestLength(),
+ )
+ _reply = rq.Struct(
+ rq.ReplyCode(),
+ rq.Pad(1),
+ rq.Card16('sequence_number'),
+ rq.ReplyLength(),
+ rq.Card32('state'),
+ rq.Pad(20),
+ )
+
+def is_active(self):
+ r = IsActive(display=self.display,
+ opcode=self.display.get_extension_major(extname),
+ )
+ return r.state
+
+
+# QueryScreens is only available from Xinerama 1.1 and later
+class QueryScreens(rq.ReplyRequest):
+ _request = rq.Struct(
+ rq.Card8('opcode'),
+ rq.Opcode(5),
+ rq.RequestLength(),
+ )
+ _reply = rq.Struct(
+ rq.ReplyCode(),
+ rq.Pad(1),
+ rq.Card16('sequence_number'),
+ rq.ReplyLength(),
+ rq.Card32('number'),
+ rq.Pad(20),
+ rq.List('screens', structs.Rectangle),
+ )
+
+def query_screens(self):
+ # Hmm. This one needs to read the screen data from the socket. Ooops...
+ return QueryScreens(display=self.display,
+ opcode=self.display.get_extension_major(extname),
+ )
+
+
+# GetInfo is only available from some Xinerama 1.0, and *NOT* later! Untested
+class GetInfo(rq.ReplyRequest):
+ _request = rq.Struct(
+ rq.Card8('opcode'),
+ rq.Opcode(4),
+ rq.RequestLength(),
+ rq.Card32('visual'),
+ )
+ _reply = rq.Struct(
+ rq.ReplyCode(),
+ rq.Pad(1),
+ rq.Card16('sequence_number'),
+ rq.ReplyLength(),
+ rq.Window('window'),
+ # An array of subwindow slots goes here. Bah.
+ )
+
+def get_info(self, visual):
+ r = GetInfo(display=self.display,
+ opcode=self.display.get_extension_major(extname),
+ visual=visual)
+
+def init(disp, info):
+ disp.extension_add_method('display', 'xinerama_query_version', query_version)
+ disp.extension_add_method('window', 'xinerama_get_state', get_state)
+ disp.extension_add_method('window', 'xinerama_get_screen_count', get_screen_count)
+ disp.extension_add_method('window', 'xinerama_get_screen_size', get_screen_size)
+ disp.extension_add_method('display', 'xinerama_is_active', is_active)
+ disp.extension_add_method('display', 'xinerama_query_screens', query_screens)
+ disp.extension_add_method('display', 'xinerama_get_info', get_info)
diff --git a/Xlib/ext/xtest.py b/Xlib/ext/xtest.py
new file mode 100644
index 0000000..71bcac9
--- /dev/null
+++ b/Xlib/ext/xtest.py
@@ -0,0 +1,121 @@
+# $Id: xtest.py,v 1.2 2007/06/10 14:11:58 mggrant Exp $
+#
+# Xlib.ext.xtest -- XTEST extension module
+#
+# Copyright (C) 2000 Peter Liljenberg <petli@ctrl-c.liu.se>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+from Xlib import X
+from Xlib.protocol import rq
+
+extname = 'XTEST'
+
+CurrentCursor = 1
+
+class GetVersion(rq.ReplyRequest):
+ _request = rq.Struct(rq.Card8('opcode'),
+ rq.Opcode(0),
+ rq.RequestLength(),
+ rq.Card8('major_version'),
+ rq.Pad(1),
+ rq.Card16('minor_version')
+ )
+
+ _reply = rq.Struct(rq.Pad(1),
+ rq.Card8('major_version'),
+ rq.Card16('sequence_number'),
+ rq.Pad(4),
+ rq.Card16('minor_version'),
+ rq.Pad(22)
+ )
+
+def get_version(self, major, minor):
+ return GetVersion(display = self.display,
+ opcode = self.display.get_extension_major(extname),
+ major_version = major,
+ minor_version = minor)
+
+
+class CompareCursor(rq.ReplyRequest):
+ _request = rq.Struct(rq.Card8('opcode'),
+ rq.Opcode(1),
+ rq.RequestLength(),
+ rq.Window('window'),
+ rq.Cursor('cursor', (X.NONE, CurrentCursor)),
+ )
+
+ _reply = rq.Struct(rq.Pad(1),
+ rq.Card8('same'),
+ rq.Card16('sequence_number'),
+ rq.Pad(28),
+ )
+
+def compare_cursor(self, cursor):
+ r = CompareCursor(display = self.display,
+ opcode = self.display.get_extension_major(extname),
+ window = self.id,
+ cursor = cursor)
+ return r.same
+
+class FakeInput(rq.Request):
+ _request = rq.Struct(rq.Card8('opcode'),
+ rq.Opcode(2),
+ rq.RequestLength(),
+ rq.Set('event_type', 1, (X.KeyPress,
+ X.KeyRelease,
+ X.ButtonPress,
+ X.ButtonRelease,
+ X.MotionNotify)),
+ rq.Card8('detail'),
+ rq.Pad(2),
+ rq.Card32('time'),
+ rq.Window('root', (X.NONE, )),
+ rq.Pad(8),
+ rq.Int16('x'),
+ rq.Int16('y'),
+ rq.Pad(8)
+ )
+
+def fake_input(self, event_type, detail = 0, time = X.CurrentTime,
+ root = X.NONE, x = 0, y = 0):
+
+ FakeInput(display = self.display,
+ opcode = self.display.get_extension_major(extname),
+ event_type = event_type,
+ detail = detail,
+ time = time,
+ root = root,
+ x = x,
+ y = y)
+
+class GrabControl(rq.Request):
+ _request = rq.Struct(rq.Card8('opcode'),
+ rq.Opcode(3),
+ rq.RequestLength(),
+ rq.Bool('impervious'),
+ rq.Pad(3)
+ )
+
+def grab_control(self, impervious):
+ GrabControl(display = self.display,
+ opcode = self.display.get_extension_major(extname),
+ impervious = impervious)
+
+def init(disp, info):
+ disp.extension_add_method('display', 'xtest_get_version', get_version)
+ disp.extension_add_method('window', 'xtest_compare_cursor', compare_cursor)
+ disp.extension_add_method('display', 'xtest_fake_input', fake_input)
+ disp.extension_add_method('display', 'xtest_grab_control', grab_control)
diff --git a/Xlib/keysymdef/__init__.py b/Xlib/keysymdef/__init__.py
new file mode 100644
index 0000000..ce6d5e7
--- /dev/null
+++ b/Xlib/keysymdef/__init__.py
@@ -0,0 +1,40 @@
+# $Id: __init__.py,v 1.1 2001/01/19 18:59:37 petli Exp $
+#
+# Xlib.keysymdef -- X keysym defs
+#
+# Copyright (C) 2001 Peter Liljenberg <petli@ctrl-c.liu.se>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+__all__ = [
+ 'apl',
+ 'arabic',
+ 'cyrillic',
+ 'greek',
+ 'hebrew',
+ 'katakana',
+ 'korean',
+ 'latin1',
+ 'latin2',
+ 'latin3',
+ 'latin4',
+ 'miscellany',
+ 'publishing',
+ 'special',
+ 'technical',
+ 'thai',
+ 'xk3270',
+ 'xkb',
+ ]
diff --git a/Xlib/keysymdef/apl.py b/Xlib/keysymdef/apl.py
new file mode 100644
index 0000000..81ed9e0
--- /dev/null
+++ b/Xlib/keysymdef/apl.py
@@ -0,0 +1,19 @@
+XK_leftcaret = 0xba3
+XK_rightcaret = 0xba6
+XK_downcaret = 0xba8
+XK_upcaret = 0xba9
+XK_overbar = 0xbc0
+XK_downtack = 0xbc2
+XK_upshoe = 0xbc3
+XK_downstile = 0xbc4
+XK_underbar = 0xbc6
+XK_jot = 0xbca
+XK_quad = 0xbcc
+XK_uptack = 0xbce
+XK_circle = 0xbcf
+XK_upstile = 0xbd3
+XK_downshoe = 0xbd6
+XK_rightshoe = 0xbd8
+XK_leftshoe = 0xbda
+XK_lefttack = 0xbdc
+XK_righttack = 0xbfc
diff --git a/Xlib/keysymdef/arabic.py b/Xlib/keysymdef/arabic.py
new file mode 100644
index 0000000..2b59e90
--- /dev/null
+++ b/Xlib/keysymdef/arabic.py
@@ -0,0 +1,50 @@
+XK_Arabic_comma = 0x5ac
+XK_Arabic_semicolon = 0x5bb
+XK_Arabic_question_mark = 0x5bf
+XK_Arabic_hamza = 0x5c1
+XK_Arabic_maddaonalef = 0x5c2
+XK_Arabic_hamzaonalef = 0x5c3
+XK_Arabic_hamzaonwaw = 0x5c4
+XK_Arabic_hamzaunderalef = 0x5c5
+XK_Arabic_hamzaonyeh = 0x5c6
+XK_Arabic_alef = 0x5c7
+XK_Arabic_beh = 0x5c8
+XK_Arabic_tehmarbuta = 0x5c9
+XK_Arabic_teh = 0x5ca
+XK_Arabic_theh = 0x5cb
+XK_Arabic_jeem = 0x5cc
+XK_Arabic_hah = 0x5cd
+XK_Arabic_khah = 0x5ce
+XK_Arabic_dal = 0x5cf
+XK_Arabic_thal = 0x5d0
+XK_Arabic_ra = 0x5d1
+XK_Arabic_zain = 0x5d2
+XK_Arabic_seen = 0x5d3
+XK_Arabic_sheen = 0x5d4
+XK_Arabic_sad = 0x5d5
+XK_Arabic_dad = 0x5d6
+XK_Arabic_tah = 0x5d7
+XK_Arabic_zah = 0x5d8
+XK_Arabic_ain = 0x5d9
+XK_Arabic_ghain = 0x5da
+XK_Arabic_tatweel = 0x5e0
+XK_Arabic_feh = 0x5e1
+XK_Arabic_qaf = 0x5e2
+XK_Arabic_kaf = 0x5e3
+XK_Arabic_lam = 0x5e4
+XK_Arabic_meem = 0x5e5
+XK_Arabic_noon = 0x5e6
+XK_Arabic_ha = 0x5e7
+XK_Arabic_heh = 0x5e7
+XK_Arabic_waw = 0x5e8
+XK_Arabic_alefmaksura = 0x5e9
+XK_Arabic_yeh = 0x5ea
+XK_Arabic_fathatan = 0x5eb
+XK_Arabic_dammatan = 0x5ec
+XK_Arabic_kasratan = 0x5ed
+XK_Arabic_fatha = 0x5ee
+XK_Arabic_damma = 0x5ef
+XK_Arabic_kasra = 0x5f0
+XK_Arabic_shadda = 0x5f1
+XK_Arabic_sukun = 0x5f2
+XK_Arabic_switch = 0xFF7E
diff --git a/Xlib/keysymdef/cyrillic.py b/Xlib/keysymdef/cyrillic.py
new file mode 100644
index 0000000..ceecbfb
--- /dev/null
+++ b/Xlib/keysymdef/cyrillic.py
@@ -0,0 +1,107 @@
+XK_Serbian_dje = 0x6a1
+XK_Macedonia_gje = 0x6a2
+XK_Cyrillic_io = 0x6a3
+XK_Ukrainian_ie = 0x6a4
+XK_Ukranian_je = 0x6a4
+XK_Macedonia_dse = 0x6a5
+XK_Ukrainian_i = 0x6a6
+XK_Ukranian_i = 0x6a6
+XK_Ukrainian_yi = 0x6a7
+XK_Ukranian_yi = 0x6a7
+XK_Cyrillic_je = 0x6a8
+XK_Serbian_je = 0x6a8
+XK_Cyrillic_lje = 0x6a9
+XK_Serbian_lje = 0x6a9
+XK_Cyrillic_nje = 0x6aa
+XK_Serbian_nje = 0x6aa
+XK_Serbian_tshe = 0x6ab
+XK_Macedonia_kje = 0x6ac
+XK_Byelorussian_shortu = 0x6ae
+XK_Cyrillic_dzhe = 0x6af
+XK_Serbian_dze = 0x6af
+XK_numerosign = 0x6b0
+XK_Serbian_DJE = 0x6b1
+XK_Macedonia_GJE = 0x6b2
+XK_Cyrillic_IO = 0x6b3
+XK_Ukrainian_IE = 0x6b4
+XK_Ukranian_JE = 0x6b4
+XK_Macedonia_DSE = 0x6b5
+XK_Ukrainian_I = 0x6b6
+XK_Ukranian_I = 0x6b6
+XK_Ukrainian_YI = 0x6b7
+XK_Ukranian_YI = 0x6b7
+XK_Cyrillic_JE = 0x6b8
+XK_Serbian_JE = 0x6b8
+XK_Cyrillic_LJE = 0x6b9
+XK_Serbian_LJE = 0x6b9
+XK_Cyrillic_NJE = 0x6ba
+XK_Serbian_NJE = 0x6ba
+XK_Serbian_TSHE = 0x6bb
+XK_Macedonia_KJE = 0x6bc
+XK_Byelorussian_SHORTU = 0x6be
+XK_Cyrillic_DZHE = 0x6bf
+XK_Serbian_DZE = 0x6bf
+XK_Cyrillic_yu = 0x6c0
+XK_Cyrillic_a = 0x6c1
+XK_Cyrillic_be = 0x6c2
+XK_Cyrillic_tse = 0x6c3
+XK_Cyrillic_de = 0x6c4
+XK_Cyrillic_ie = 0x6c5
+XK_Cyrillic_ef = 0x6c6
+XK_Cyrillic_ghe = 0x6c7
+XK_Cyrillic_ha = 0x6c8
+XK_Cyrillic_i = 0x6c9
+XK_Cyrillic_shorti = 0x6ca
+XK_Cyrillic_ka = 0x6cb
+XK_Cyrillic_el = 0x6cc
+XK_Cyrillic_em = 0x6cd
+XK_Cyrillic_en = 0x6ce
+XK_Cyrillic_o = 0x6cf
+XK_Cyrillic_pe = 0x6d0
+XK_Cyrillic_ya = 0x6d1
+XK_Cyrillic_er = 0x6d2
+XK_Cyrillic_es = 0x6d3
+XK_Cyrillic_te = 0x6d4
+XK_Cyrillic_u = 0x6d5
+XK_Cyrillic_zhe = 0x6d6
+XK_Cyrillic_ve = 0x6d7
+XK_Cyrillic_softsign = 0x6d8
+XK_Cyrillic_yeru = 0x6d9
+XK_Cyrillic_ze = 0x6da
+XK_Cyrillic_sha = 0x6db
+XK_Cyrillic_e = 0x6dc
+XK_Cyrillic_shcha = 0x6dd
+XK_Cyrillic_che = 0x6de
+XK_Cyrillic_hardsign = 0x6df
+XK_Cyrillic_YU = 0x6e0
+XK_Cyrillic_A = 0x6e1
+XK_Cyrillic_BE = 0x6e2
+XK_Cyrillic_TSE = 0x6e3
+XK_Cyrillic_DE = 0x6e4
+XK_Cyrillic_IE = 0x6e5
+XK_Cyrillic_EF = 0x6e6
+XK_Cyrillic_GHE = 0x6e7
+XK_Cyrillic_HA = 0x6e8
+XK_Cyrillic_I = 0x6e9
+XK_Cyrillic_SHORTI = 0x6ea
+XK_Cyrillic_KA = 0x6eb
+XK_Cyrillic_EL = 0x6ec
+XK_Cyrillic_EM = 0x6ed
+XK_Cyrillic_EN = 0x6ee
+XK_Cyrillic_O = 0x6ef
+XK_Cyrillic_PE = 0x6f0
+XK_Cyrillic_YA = 0x6f1
+XK_Cyrillic_ER = 0x6f2
+XK_Cyrillic_ES = 0x6f3
+XK_Cyrillic_TE = 0x6f4
+XK_Cyrillic_U = 0x6f5
+XK_Cyrillic_ZHE = 0x6f6
+XK_Cyrillic_VE = 0x6f7
+XK_Cyrillic_SOFTSIGN = 0x6f8
+XK_Cyrillic_YERU = 0x6f9
+XK_Cyrillic_ZE = 0x6fa
+XK_Cyrillic_SHA = 0x6fb
+XK_Cyrillic_E = 0x6fc
+XK_Cyrillic_SHCHA = 0x6fd
+XK_Cyrillic_CHE = 0x6fe
+XK_Cyrillic_HARDSIGN = 0x6ff
diff --git a/Xlib/keysymdef/greek.py b/Xlib/keysymdef/greek.py
new file mode 100644
index 0000000..4aa4418
--- /dev/null
+++ b/Xlib/keysymdef/greek.py
@@ -0,0 +1,74 @@
+XK_Greek_ALPHAaccent = 0x7a1
+XK_Greek_EPSILONaccent = 0x7a2
+XK_Greek_ETAaccent = 0x7a3
+XK_Greek_IOTAaccent = 0x7a4
+XK_Greek_IOTAdiaeresis = 0x7a5
+XK_Greek_OMICRONaccent = 0x7a7
+XK_Greek_UPSILONaccent = 0x7a8
+XK_Greek_UPSILONdieresis = 0x7a9
+XK_Greek_OMEGAaccent = 0x7ab
+XK_Greek_accentdieresis = 0x7ae
+XK_Greek_horizbar = 0x7af
+XK_Greek_alphaaccent = 0x7b1
+XK_Greek_epsilonaccent = 0x7b2
+XK_Greek_etaaccent = 0x7b3
+XK_Greek_iotaaccent = 0x7b4
+XK_Greek_iotadieresis = 0x7b5
+XK_Greek_iotaaccentdieresis = 0x7b6
+XK_Greek_omicronaccent = 0x7b7
+XK_Greek_upsilonaccent = 0x7b8
+XK_Greek_upsilondieresis = 0x7b9
+XK_Greek_upsilonaccentdieresis = 0x7ba
+XK_Greek_omegaaccent = 0x7bb
+XK_Greek_ALPHA = 0x7c1
+XK_Greek_BETA = 0x7c2
+XK_Greek_GAMMA = 0x7c3
+XK_Greek_DELTA = 0x7c4
+XK_Greek_EPSILON = 0x7c5
+XK_Greek_ZETA = 0x7c6
+XK_Greek_ETA = 0x7c7
+XK_Greek_THETA = 0x7c8
+XK_Greek_IOTA = 0x7c9
+XK_Greek_KAPPA = 0x7ca
+XK_Greek_LAMDA = 0x7cb
+XK_Greek_LAMBDA = 0x7cb
+XK_Greek_MU = 0x7cc
+XK_Greek_NU = 0x7cd
+XK_Greek_XI = 0x7ce
+XK_Greek_OMICRON = 0x7cf
+XK_Greek_PI = 0x7d0
+XK_Greek_RHO = 0x7d1
+XK_Greek_SIGMA = 0x7d2
+XK_Greek_TAU = 0x7d4
+XK_Greek_UPSILON = 0x7d5
+XK_Greek_PHI = 0x7d6
+XK_Greek_CHI = 0x7d7
+XK_Greek_PSI = 0x7d8
+XK_Greek_OMEGA = 0x7d9
+XK_Greek_alpha = 0x7e1
+XK_Greek_beta = 0x7e2
+XK_Greek_gamma = 0x7e3
+XK_Greek_delta = 0x7e4
+XK_Greek_epsilon = 0x7e5
+XK_Greek_zeta = 0x7e6
+XK_Greek_eta = 0x7e7
+XK_Greek_theta = 0x7e8
+XK_Greek_iota = 0x7e9
+XK_Greek_kappa = 0x7ea
+XK_Greek_lamda = 0x7eb
+XK_Greek_lambda = 0x7eb
+XK_Greek_mu = 0x7ec
+XK_Greek_nu = 0x7ed
+XK_Greek_xi = 0x7ee
+XK_Greek_omicron = 0x7ef
+XK_Greek_pi = 0x7f0
+XK_Greek_rho = 0x7f1
+XK_Greek_sigma = 0x7f2
+XK_Greek_finalsmallsigma = 0x7f3
+XK_Greek_tau = 0x7f4
+XK_Greek_upsilon = 0x7f5
+XK_Greek_phi = 0x7f6
+XK_Greek_chi = 0x7f7
+XK_Greek_psi = 0x7f8
+XK_Greek_omega = 0x7f9
+XK_Greek_switch = 0xFF7E
diff --git a/Xlib/keysymdef/hebrew.py b/Xlib/keysymdef/hebrew.py
new file mode 100644
index 0000000..e00e9e2
--- /dev/null
+++ b/Xlib/keysymdef/hebrew.py
@@ -0,0 +1,40 @@
+XK_hebrew_doublelowline = 0xcdf
+XK_hebrew_aleph = 0xce0
+XK_hebrew_bet = 0xce1
+XK_hebrew_beth = 0xce1
+XK_hebrew_gimel = 0xce2
+XK_hebrew_gimmel = 0xce2
+XK_hebrew_dalet = 0xce3
+XK_hebrew_daleth = 0xce3
+XK_hebrew_he = 0xce4
+XK_hebrew_waw = 0xce5
+XK_hebrew_zain = 0xce6
+XK_hebrew_zayin = 0xce6
+XK_hebrew_chet = 0xce7
+XK_hebrew_het = 0xce7
+XK_hebrew_tet = 0xce8
+XK_hebrew_teth = 0xce8
+XK_hebrew_yod = 0xce9
+XK_hebrew_finalkaph = 0xcea
+XK_hebrew_kaph = 0xceb
+XK_hebrew_lamed = 0xcec
+XK_hebrew_finalmem = 0xced
+XK_hebrew_mem = 0xcee
+XK_hebrew_finalnun = 0xcef
+XK_hebrew_nun = 0xcf0
+XK_hebrew_samech = 0xcf1
+XK_hebrew_samekh = 0xcf1
+XK_hebrew_ayin = 0xcf2
+XK_hebrew_finalpe = 0xcf3
+XK_hebrew_pe = 0xcf4
+XK_hebrew_finalzade = 0xcf5
+XK_hebrew_finalzadi = 0xcf5
+XK_hebrew_zade = 0xcf6
+XK_hebrew_zadi = 0xcf6
+XK_hebrew_qoph = 0xcf7
+XK_hebrew_kuf = 0xcf7
+XK_hebrew_resh = 0xcf8
+XK_hebrew_shin = 0xcf9
+XK_hebrew_taw = 0xcfa
+XK_hebrew_taf = 0xcfa
+XK_Hebrew_switch = 0xFF7E
diff --git a/Xlib/keysymdef/katakana.py b/Xlib/keysymdef/katakana.py
new file mode 100644
index 0000000..2d46eed
--- /dev/null
+++ b/Xlib/keysymdef/katakana.py
@@ -0,0 +1,70 @@
+XK_overline = 0x47e
+XK_kana_fullstop = 0x4a1
+XK_kana_openingbracket = 0x4a2
+XK_kana_closingbracket = 0x4a3
+XK_kana_comma = 0x4a4
+XK_kana_conjunctive = 0x4a5
+XK_kana_middledot = 0x4a5
+XK_kana_WO = 0x4a6
+XK_kana_a = 0x4a7
+XK_kana_i = 0x4a8
+XK_kana_u = 0x4a9
+XK_kana_e = 0x4aa
+XK_kana_o = 0x4ab
+XK_kana_ya = 0x4ac
+XK_kana_yu = 0x4ad
+XK_kana_yo = 0x4ae
+XK_kana_tsu = 0x4af
+XK_kana_tu = 0x4af
+XK_prolongedsound = 0x4b0
+XK_kana_A = 0x4b1
+XK_kana_I = 0x4b2
+XK_kana_U = 0x4b3
+XK_kana_E = 0x4b4
+XK_kana_O = 0x4b5
+XK_kana_KA = 0x4b6
+XK_kana_KI = 0x4b7
+XK_kana_KU = 0x4b8
+XK_kana_KE = 0x4b9
+XK_kana_KO = 0x4ba
+XK_kana_SA = 0x4bb
+XK_kana_SHI = 0x4bc
+XK_kana_SU = 0x4bd
+XK_kana_SE = 0x4be
+XK_kana_SO = 0x4bf
+XK_kana_TA = 0x4c0
+XK_kana_CHI = 0x4c1
+XK_kana_TI = 0x4c1
+XK_kana_TSU = 0x4c2
+XK_kana_TU = 0x4c2
+XK_kana_TE = 0x4c3
+XK_kana_TO = 0x4c4
+XK_kana_NA = 0x4c5
+XK_kana_NI = 0x4c6
+XK_kana_NU = 0x4c7
+XK_kana_NE = 0x4c8
+XK_kana_NO = 0x4c9
+XK_kana_HA = 0x4ca
+XK_kana_HI = 0x4cb
+XK_kana_FU = 0x4cc
+XK_kana_HU = 0x4cc
+XK_kana_HE = 0x4cd
+XK_kana_HO = 0x4ce
+XK_kana_MA = 0x4cf
+XK_kana_MI = 0x4d0
+XK_kana_MU = 0x4d1
+XK_kana_ME = 0x4d2
+XK_kana_MO = 0x4d3
+XK_kana_YA = 0x4d4
+XK_kana_YU = 0x4d5
+XK_kana_YO = 0x4d6
+XK_kana_RA = 0x4d7
+XK_kana_RI = 0x4d8
+XK_kana_RU = 0x4d9
+XK_kana_RE = 0x4da
+XK_kana_RO = 0x4db
+XK_kana_WA = 0x4dc
+XK_kana_N = 0x4dd
+XK_voicedsound = 0x4de
+XK_semivoicedsound = 0x4df
+XK_kana_switch = 0xFF7E
diff --git a/Xlib/keysymdef/korean.py b/Xlib/keysymdef/korean.py
new file mode 100644
index 0000000..1383cde
--- /dev/null
+++ b/Xlib/keysymdef/korean.py
@@ -0,0 +1,107 @@
+XK_Hangul = 0xff31
+XK_Hangul_Start = 0xff32
+XK_Hangul_End = 0xff33
+XK_Hangul_Hanja = 0xff34
+XK_Hangul_Jamo = 0xff35
+XK_Hangul_Romaja = 0xff36
+XK_Hangul_Codeinput = 0xff37
+XK_Hangul_Jeonja = 0xff38
+XK_Hangul_Banja = 0xff39
+XK_Hangul_PreHanja = 0xff3a
+XK_Hangul_PostHanja = 0xff3b
+XK_Hangul_SingleCandidate = 0xff3c
+XK_Hangul_MultipleCandidate = 0xff3d
+XK_Hangul_PreviousCandidate = 0xff3e
+XK_Hangul_Special = 0xff3f
+XK_Hangul_switch = 0xFF7E
+XK_Hangul_Kiyeog = 0xea1
+XK_Hangul_SsangKiyeog = 0xea2
+XK_Hangul_KiyeogSios = 0xea3
+XK_Hangul_Nieun = 0xea4
+XK_Hangul_NieunJieuj = 0xea5
+XK_Hangul_NieunHieuh = 0xea6
+XK_Hangul_Dikeud = 0xea7
+XK_Hangul_SsangDikeud = 0xea8
+XK_Hangul_Rieul = 0xea9
+XK_Hangul_RieulKiyeog = 0xeaa
+XK_Hangul_RieulMieum = 0xeab
+XK_Hangul_RieulPieub = 0xeac
+XK_Hangul_RieulSios = 0xead
+XK_Hangul_RieulTieut = 0xeae
+XK_Hangul_RieulPhieuf = 0xeaf
+XK_Hangul_RieulHieuh = 0xeb0
+XK_Hangul_Mieum = 0xeb1
+XK_Hangul_Pieub = 0xeb2
+XK_Hangul_SsangPieub = 0xeb3
+XK_Hangul_PieubSios = 0xeb4
+XK_Hangul_Sios = 0xeb5
+XK_Hangul_SsangSios = 0xeb6
+XK_Hangul_Ieung = 0xeb7
+XK_Hangul_Jieuj = 0xeb8
+XK_Hangul_SsangJieuj = 0xeb9
+XK_Hangul_Cieuc = 0xeba
+XK_Hangul_Khieuq = 0xebb
+XK_Hangul_Tieut = 0xebc
+XK_Hangul_Phieuf = 0xebd
+XK_Hangul_Hieuh = 0xebe
+XK_Hangul_A = 0xebf
+XK_Hangul_AE = 0xec0
+XK_Hangul_YA = 0xec1
+XK_Hangul_YAE = 0xec2
+XK_Hangul_EO = 0xec3
+XK_Hangul_E = 0xec4
+XK_Hangul_YEO = 0xec5
+XK_Hangul_YE = 0xec6
+XK_Hangul_O = 0xec7
+XK_Hangul_WA = 0xec8
+XK_Hangul_WAE = 0xec9
+XK_Hangul_OE = 0xeca
+XK_Hangul_YO = 0xecb
+XK_Hangul_U = 0xecc
+XK_Hangul_WEO = 0xecd
+XK_Hangul_WE = 0xece
+XK_Hangul_WI = 0xecf
+XK_Hangul_YU = 0xed0
+XK_Hangul_EU = 0xed1
+XK_Hangul_YI = 0xed2
+XK_Hangul_I = 0xed3
+XK_Hangul_J_Kiyeog = 0xed4
+XK_Hangul_J_SsangKiyeog = 0xed5
+XK_Hangul_J_KiyeogSios = 0xed6
+XK_Hangul_J_Nieun = 0xed7
+XK_Hangul_J_NieunJieuj = 0xed8
+XK_Hangul_J_NieunHieuh = 0xed9
+XK_Hangul_J_Dikeud = 0xeda
+XK_Hangul_J_Rieul = 0xedb
+XK_Hangul_J_RieulKiyeog = 0xedc
+XK_Hangul_J_RieulMieum = 0xedd
+XK_Hangul_J_RieulPieub = 0xede
+XK_Hangul_J_RieulSios = 0xedf
+XK_Hangul_J_RieulTieut = 0xee0
+XK_Hangul_J_RieulPhieuf = 0xee1
+XK_Hangul_J_RieulHieuh = 0xee2
+XK_Hangul_J_Mieum = 0xee3
+XK_Hangul_J_Pieub = 0xee4
+XK_Hangul_J_PieubSios = 0xee5
+XK_Hangul_J_Sios = 0xee6
+XK_Hangul_J_SsangSios = 0xee7
+XK_Hangul_J_Ieung = 0xee8
+XK_Hangul_J_Jieuj = 0xee9
+XK_Hangul_J_Cieuc = 0xeea
+XK_Hangul_J_Khieuq = 0xeeb
+XK_Hangul_J_Tieut = 0xeec
+XK_Hangul_J_Phieuf = 0xeed
+XK_Hangul_J_Hieuh = 0xeee
+XK_Hangul_RieulYeorinHieuh = 0xeef
+XK_Hangul_SunkyeongeumMieum = 0xef0
+XK_Hangul_SunkyeongeumPieub = 0xef1
+XK_Hangul_PanSios = 0xef2
+XK_Hangul_KkogjiDalrinIeung = 0xef3
+XK_Hangul_SunkyeongeumPhieuf = 0xef4
+XK_Hangul_YeorinHieuh = 0xef5
+XK_Hangul_AraeA = 0xef6
+XK_Hangul_AraeAE = 0xef7
+XK_Hangul_J_PanSios = 0xef8
+XK_Hangul_J_KkogjiDalrinIeung = 0xef9
+XK_Hangul_J_YeorinHieuh = 0xefa
+XK_Korean_Won = 0xeff
diff --git a/Xlib/keysymdef/latin1.py b/Xlib/keysymdef/latin1.py
new file mode 100644
index 0000000..92af9b1
--- /dev/null
+++ b/Xlib/keysymdef/latin1.py
@@ -0,0 +1,195 @@
+XK_space = 0x020
+XK_exclam = 0x021
+XK_quotedbl = 0x022
+XK_numbersign = 0x023
+XK_dollar = 0x024
+XK_percent = 0x025
+XK_ampersand = 0x026
+XK_apostrophe = 0x027
+XK_quoteright = 0x027
+XK_parenleft = 0x028
+XK_parenright = 0x029
+XK_asterisk = 0x02a
+XK_plus = 0x02b
+XK_comma = 0x02c
+XK_minus = 0x02d
+XK_period = 0x02e
+XK_slash = 0x02f
+XK_0 = 0x030
+XK_1 = 0x031
+XK_2 = 0x032
+XK_3 = 0x033
+XK_4 = 0x034
+XK_5 = 0x035
+XK_6 = 0x036
+XK_7 = 0x037
+XK_8 = 0x038
+XK_9 = 0x039
+XK_colon = 0x03a
+XK_semicolon = 0x03b
+XK_less = 0x03c
+XK_equal = 0x03d
+XK_greater = 0x03e
+XK_question = 0x03f
+XK_at = 0x040
+XK_A = 0x041
+XK_B = 0x042
+XK_C = 0x043
+XK_D = 0x044
+XK_E = 0x045
+XK_F = 0x046
+XK_G = 0x047
+XK_H = 0x048
+XK_I = 0x049
+XK_J = 0x04a
+XK_K = 0x04b
+XK_L = 0x04c
+XK_M = 0x04d
+XK_N = 0x04e
+XK_O = 0x04f
+XK_P = 0x050
+XK_Q = 0x051
+XK_R = 0x052
+XK_S = 0x053
+XK_T = 0x054
+XK_U = 0x055
+XK_V = 0x056
+XK_W = 0x057
+XK_X = 0x058
+XK_Y = 0x059
+XK_Z = 0x05a
+XK_bracketleft = 0x05b
+XK_backslash = 0x05c
+XK_bracketright = 0x05d
+XK_asciicircum = 0x05e
+XK_underscore = 0x05f
+XK_grave = 0x060
+XK_quoteleft = 0x060
+XK_a = 0x061
+XK_b = 0x062
+XK_c = 0x063
+XK_d = 0x064
+XK_e = 0x065
+XK_f = 0x066
+XK_g = 0x067
+XK_h = 0x068
+XK_i = 0x069
+XK_j = 0x06a
+XK_k = 0x06b
+XK_l = 0x06c
+XK_m = 0x06d
+XK_n = 0x06e
+XK_o = 0x06f
+XK_p = 0x070
+XK_q = 0x071
+XK_r = 0x072
+XK_s = 0x073
+XK_t = 0x074
+XK_u = 0x075
+XK_v = 0x076
+XK_w = 0x077
+XK_x = 0x078
+XK_y = 0x079
+XK_z = 0x07a
+XK_braceleft = 0x07b
+XK_bar = 0x07c
+XK_braceright = 0x07d
+XK_asciitilde = 0x07e
+XK_nobreakspace = 0x0a0
+XK_exclamdown = 0x0a1
+XK_cent = 0x0a2
+XK_sterling = 0x0a3
+XK_currency = 0x0a4
+XK_yen = 0x0a5
+XK_brokenbar = 0x0a6
+XK_section = 0x0a7
+XK_diaeresis = 0x0a8
+XK_copyright = 0x0a9
+XK_ordfeminine = 0x0aa
+XK_guillemotleft = 0x0ab
+XK_notsign = 0x0ac
+XK_hyphen = 0x0ad
+XK_registered = 0x0ae
+XK_macron = 0x0af
+XK_degree = 0x0b0
+XK_plusminus = 0x0b1
+XK_twosuperior = 0x0b2
+XK_threesuperior = 0x0b3
+XK_acute = 0x0b4
+XK_mu = 0x0b5
+XK_paragraph = 0x0b6
+XK_periodcentered = 0x0b7
+XK_cedilla = 0x0b8
+XK_onesuperior = 0x0b9
+XK_masculine = 0x0ba
+XK_guillemotright = 0x0bb
+XK_onequarter = 0x0bc
+XK_onehalf = 0x0bd
+XK_threequarters = 0x0be
+XK_questiondown = 0x0bf
+XK_Agrave = 0x0c0
+XK_Aacute = 0x0c1
+XK_Acircumflex = 0x0c2
+XK_Atilde = 0x0c3
+XK_Adiaeresis = 0x0c4
+XK_Aring = 0x0c5
+XK_AE = 0x0c6
+XK_Ccedilla = 0x0c7
+XK_Egrave = 0x0c8
+XK_Eacute = 0x0c9
+XK_Ecircumflex = 0x0ca
+XK_Ediaeresis = 0x0cb
+XK_Igrave = 0x0cc
+XK_Iacute = 0x0cd
+XK_Icircumflex = 0x0ce
+XK_Idiaeresis = 0x0cf
+XK_ETH = 0x0d0
+XK_Eth = 0x0d0
+XK_Ntilde = 0x0d1
+XK_Ograve = 0x0d2
+XK_Oacute = 0x0d3
+XK_Ocircumflex = 0x0d4
+XK_Otilde = 0x0d5
+XK_Odiaeresis = 0x0d6
+XK_multiply = 0x0d7
+XK_Ooblique = 0x0d8
+XK_Ugrave = 0x0d9
+XK_Uacute = 0x0da
+XK_Ucircumflex = 0x0db
+XK_Udiaeresis = 0x0dc
+XK_Yacute = 0x0dd
+XK_THORN = 0x0de
+XK_Thorn = 0x0de
+XK_ssharp = 0x0df
+XK_agrave = 0x0e0
+XK_aacute = 0x0e1
+XK_acircumflex = 0x0e2
+XK_atilde = 0x0e3
+XK_adiaeresis = 0x0e4
+XK_aring = 0x0e5
+XK_ae = 0x0e6
+XK_ccedilla = 0x0e7
+XK_egrave = 0x0e8
+XK_eacute = 0x0e9
+XK_ecircumflex = 0x0ea
+XK_ediaeresis = 0x0eb
+XK_igrave = 0x0ec
+XK_iacute = 0x0ed
+XK_icircumflex = 0x0ee
+XK_idiaeresis = 0x0ef
+XK_eth = 0x0f0
+XK_ntilde = 0x0f1
+XK_ograve = 0x0f2
+XK_oacute = 0x0f3
+XK_ocircumflex = 0x0f4
+XK_otilde = 0x0f5
+XK_odiaeresis = 0x0f6
+XK_division = 0x0f7
+XK_oslash = 0x0f8
+XK_ugrave = 0x0f9
+XK_uacute = 0x0fa
+XK_ucircumflex = 0x0fb
+XK_udiaeresis = 0x0fc
+XK_yacute = 0x0fd
+XK_thorn = 0x0fe
+XK_ydiaeresis = 0x0ff
diff --git a/Xlib/keysymdef/latin2.py b/Xlib/keysymdef/latin2.py
new file mode 100644
index 0000000..d0a151c
--- /dev/null
+++ b/Xlib/keysymdef/latin2.py
@@ -0,0 +1,57 @@
+XK_Aogonek = 0x1a1
+XK_breve = 0x1a2
+XK_Lstroke = 0x1a3
+XK_Lcaron = 0x1a5
+XK_Sacute = 0x1a6
+XK_Scaron = 0x1a9
+XK_Scedilla = 0x1aa
+XK_Tcaron = 0x1ab
+XK_Zacute = 0x1ac
+XK_Zcaron = 0x1ae
+XK_Zabovedot = 0x1af
+XK_aogonek = 0x1b1
+XK_ogonek = 0x1b2
+XK_lstroke = 0x1b3
+XK_lcaron = 0x1b5
+XK_sacute = 0x1b6
+XK_caron = 0x1b7
+XK_scaron = 0x1b9
+XK_scedilla = 0x1ba
+XK_tcaron = 0x1bb
+XK_zacute = 0x1bc
+XK_doubleacute = 0x1bd
+XK_zcaron = 0x1be
+XK_zabovedot = 0x1bf
+XK_Racute = 0x1c0
+XK_Abreve = 0x1c3
+XK_Lacute = 0x1c5
+XK_Cacute = 0x1c6
+XK_Ccaron = 0x1c8
+XK_Eogonek = 0x1ca
+XK_Ecaron = 0x1cc
+XK_Dcaron = 0x1cf
+XK_Dstroke = 0x1d0
+XK_Nacute = 0x1d1
+XK_Ncaron = 0x1d2
+XK_Odoubleacute = 0x1d5
+XK_Rcaron = 0x1d8
+XK_Uring = 0x1d9
+XK_Udoubleacute = 0x1db
+XK_Tcedilla = 0x1de
+XK_racute = 0x1e0
+XK_abreve = 0x1e3
+XK_lacute = 0x1e5
+XK_cacute = 0x1e6
+XK_ccaron = 0x1e8
+XK_eogonek = 0x1ea
+XK_ecaron = 0x1ec
+XK_dcaron = 0x1ef
+XK_dstroke = 0x1f0
+XK_nacute = 0x1f1
+XK_ncaron = 0x1f2
+XK_odoubleacute = 0x1f5
+XK_udoubleacute = 0x1fb
+XK_rcaron = 0x1f8
+XK_uring = 0x1f9
+XK_tcedilla = 0x1fe
+XK_abovedot = 0x1ff
diff --git a/Xlib/keysymdef/latin3.py b/Xlib/keysymdef/latin3.py
new file mode 100644
index 0000000..7c64ca1
--- /dev/null
+++ b/Xlib/keysymdef/latin3.py
@@ -0,0 +1,22 @@
+XK_Hstroke = 0x2a1
+XK_Hcircumflex = 0x2a6
+XK_Iabovedot = 0x2a9
+XK_Gbreve = 0x2ab
+XK_Jcircumflex = 0x2ac
+XK_hstroke = 0x2b1
+XK_hcircumflex = 0x2b6
+XK_idotless = 0x2b9
+XK_gbreve = 0x2bb
+XK_jcircumflex = 0x2bc
+XK_Cabovedot = 0x2c5
+XK_Ccircumflex = 0x2c6
+XK_Gabovedot = 0x2d5
+XK_Gcircumflex = 0x2d8
+XK_Ubreve = 0x2dd
+XK_Scircumflex = 0x2de
+XK_cabovedot = 0x2e5
+XK_ccircumflex = 0x2e6
+XK_gabovedot = 0x2f5
+XK_gcircumflex = 0x2f8
+XK_ubreve = 0x2fd
+XK_scircumflex = 0x2fe
diff --git a/Xlib/keysymdef/latin4.py b/Xlib/keysymdef/latin4.py
new file mode 100644
index 0000000..3a5924b
--- /dev/null
+++ b/Xlib/keysymdef/latin4.py
@@ -0,0 +1,36 @@
+XK_kra = 0x3a2
+XK_kappa = 0x3a2
+XK_Rcedilla = 0x3a3
+XK_Itilde = 0x3a5
+XK_Lcedilla = 0x3a6
+XK_Emacron = 0x3aa
+XK_Gcedilla = 0x3ab
+XK_Tslash = 0x3ac
+XK_rcedilla = 0x3b3
+XK_itilde = 0x3b5
+XK_lcedilla = 0x3b6
+XK_emacron = 0x3ba
+XK_gcedilla = 0x3bb
+XK_tslash = 0x3bc
+XK_ENG = 0x3bd
+XK_eng = 0x3bf
+XK_Amacron = 0x3c0
+XK_Iogonek = 0x3c7
+XK_Eabovedot = 0x3cc
+XK_Imacron = 0x3cf
+XK_Ncedilla = 0x3d1
+XK_Omacron = 0x3d2
+XK_Kcedilla = 0x3d3
+XK_Uogonek = 0x3d9
+XK_Utilde = 0x3dd
+XK_Umacron = 0x3de
+XK_amacron = 0x3e0
+XK_iogonek = 0x3e7
+XK_eabovedot = 0x3ec
+XK_imacron = 0x3ef
+XK_ncedilla = 0x3f1
+XK_omacron = 0x3f2
+XK_kcedilla = 0x3f3
+XK_uogonek = 0x3f9
+XK_utilde = 0x3fd
+XK_umacron = 0x3fe
diff --git a/Xlib/keysymdef/miscellany.py b/Xlib/keysymdef/miscellany.py
new file mode 100644
index 0000000..fdfefbe
--- /dev/null
+++ b/Xlib/keysymdef/miscellany.py
@@ -0,0 +1,169 @@
+XK_BackSpace = 0xFF08
+XK_Tab = 0xFF09
+XK_Linefeed = 0xFF0A
+XK_Clear = 0xFF0B
+XK_Return = 0xFF0D
+XK_Pause = 0xFF13
+XK_Scroll_Lock = 0xFF14
+XK_Sys_Req = 0xFF15
+XK_Escape = 0xFF1B
+XK_Delete = 0xFFFF
+XK_Multi_key = 0xFF20
+XK_SingleCandidate = 0xFF3C
+XK_MultipleCandidate = 0xFF3D
+XK_PreviousCandidate = 0xFF3E
+XK_Kanji = 0xFF21
+XK_Muhenkan = 0xFF22
+XK_Henkan_Mode = 0xFF23
+XK_Henkan = 0xFF23
+XK_Romaji = 0xFF24
+XK_Hiragana = 0xFF25
+XK_Katakana = 0xFF26
+XK_Hiragana_Katakana = 0xFF27
+XK_Zenkaku = 0xFF28
+XK_Hankaku = 0xFF29
+XK_Zenkaku_Hankaku = 0xFF2A
+XK_Touroku = 0xFF2B
+XK_Massyo = 0xFF2C
+XK_Kana_Lock = 0xFF2D
+XK_Kana_Shift = 0xFF2E
+XK_Eisu_Shift = 0xFF2F
+XK_Eisu_toggle = 0xFF30
+XK_Zen_Koho = 0xFF3D
+XK_Mae_Koho = 0xFF3E
+XK_Home = 0xFF50
+XK_Left = 0xFF51
+XK_Up = 0xFF52
+XK_Right = 0xFF53
+XK_Down = 0xFF54
+XK_Prior = 0xFF55
+XK_Page_Up = 0xFF55
+XK_Next = 0xFF56
+XK_Page_Down = 0xFF56
+XK_End = 0xFF57
+XK_Begin = 0xFF58
+XK_Select = 0xFF60
+XK_Print = 0xFF61
+XK_Execute = 0xFF62
+XK_Insert = 0xFF63
+XK_Undo = 0xFF65
+XK_Redo = 0xFF66
+XK_Menu = 0xFF67
+XK_Find = 0xFF68
+XK_Cancel = 0xFF69
+XK_Help = 0xFF6A
+XK_Break = 0xFF6B
+XK_Mode_switch = 0xFF7E
+XK_script_switch = 0xFF7E
+XK_Num_Lock = 0xFF7F
+XK_KP_Space = 0xFF80
+XK_KP_Tab = 0xFF89
+XK_KP_Enter = 0xFF8D
+XK_KP_F1 = 0xFF91
+XK_KP_F2 = 0xFF92
+XK_KP_F3 = 0xFF93
+XK_KP_F4 = 0xFF94
+XK_KP_Home = 0xFF95
+XK_KP_Left = 0xFF96
+XK_KP_Up = 0xFF97
+XK_KP_Right = 0xFF98
+XK_KP_Down = 0xFF99
+XK_KP_Prior = 0xFF9A
+XK_KP_Page_Up = 0xFF9A
+XK_KP_Next = 0xFF9B
+XK_KP_Page_Down = 0xFF9B
+XK_KP_End = 0xFF9C
+XK_KP_Begin = 0xFF9D
+XK_KP_Insert = 0xFF9E
+XK_KP_Delete = 0xFF9F
+XK_KP_Equal = 0xFFBD
+XK_KP_Multiply = 0xFFAA
+XK_KP_Add = 0xFFAB
+XK_KP_Separator = 0xFFAC
+XK_KP_Subtract = 0xFFAD
+XK_KP_Decimal = 0xFFAE
+XK_KP_Divide = 0xFFAF
+XK_KP_0 = 0xFFB0
+XK_KP_1 = 0xFFB1
+XK_KP_2 = 0xFFB2
+XK_KP_3 = 0xFFB3
+XK_KP_4 = 0xFFB4
+XK_KP_5 = 0xFFB5
+XK_KP_6 = 0xFFB6
+XK_KP_7 = 0xFFB7
+XK_KP_8 = 0xFFB8
+XK_KP_9 = 0xFFB9
+XK_F1 = 0xFFBE
+XK_F2 = 0xFFBF
+XK_F3 = 0xFFC0
+XK_F4 = 0xFFC1
+XK_F5 = 0xFFC2
+XK_F6 = 0xFFC3
+XK_F7 = 0xFFC4
+XK_F8 = 0xFFC5
+XK_F9 = 0xFFC6
+XK_F10 = 0xFFC7
+XK_F11 = 0xFFC8
+XK_L1 = 0xFFC8
+XK_F12 = 0xFFC9
+XK_L2 = 0xFFC9
+XK_F13 = 0xFFCA
+XK_L3 = 0xFFCA
+XK_F14 = 0xFFCB
+XK_L4 = 0xFFCB
+XK_F15 = 0xFFCC
+XK_L5 = 0xFFCC
+XK_F16 = 0xFFCD
+XK_L6 = 0xFFCD
+XK_F17 = 0xFFCE
+XK_L7 = 0xFFCE
+XK_F18 = 0xFFCF
+XK_L8 = 0xFFCF
+XK_F19 = 0xFFD0
+XK_L9 = 0xFFD0
+XK_F20 = 0xFFD1
+XK_L10 = 0xFFD1
+XK_F21 = 0xFFD2
+XK_R1 = 0xFFD2
+XK_F22 = 0xFFD3
+XK_R2 = 0xFFD3
+XK_F23 = 0xFFD4
+XK_R3 = 0xFFD4
+XK_F24 = 0xFFD5
+XK_R4 = 0xFFD5
+XK_F25 = 0xFFD6
+XK_R5 = 0xFFD6
+XK_F26 = 0xFFD7
+XK_R6 = 0xFFD7
+XK_F27 = 0xFFD8
+XK_R7 = 0xFFD8
+XK_F28 = 0xFFD9
+XK_R8 = 0xFFD9
+XK_F29 = 0xFFDA
+XK_R9 = 0xFFDA
+XK_F30 = 0xFFDB
+XK_R10 = 0xFFDB
+XK_F31 = 0xFFDC
+XK_R11 = 0xFFDC
+XK_F32 = 0xFFDD
+XK_R12 = 0xFFDD
+XK_F33 = 0xFFDE
+XK_R13 = 0xFFDE
+XK_F34 = 0xFFDF
+XK_R14 = 0xFFDF
+XK_F35 = 0xFFE0
+XK_R15 = 0xFFE0
+XK_Shift_L = 0xFFE1
+XK_Shift_R = 0xFFE2
+XK_Control_L = 0xFFE3
+XK_Control_R = 0xFFE4
+XK_Caps_Lock = 0xFFE5
+XK_Shift_Lock = 0xFFE6
+XK_Meta_L = 0xFFE7
+XK_Meta_R = 0xFFE8
+XK_Alt_L = 0xFFE9
+XK_Alt_R = 0xFFEA
+XK_Super_L = 0xFFEB
+XK_Super_R = 0xFFEC
+XK_Hyper_L = 0xFFED
+XK_Hyper_R = 0xFFEE
diff --git a/Xlib/keysymdef/publishing.py b/Xlib/keysymdef/publishing.py
new file mode 100644
index 0000000..e26f1be
--- /dev/null
+++ b/Xlib/keysymdef/publishing.py
@@ -0,0 +1,83 @@
+XK_emspace = 0xaa1
+XK_enspace = 0xaa2
+XK_em3space = 0xaa3
+XK_em4space = 0xaa4
+XK_digitspace = 0xaa5
+XK_punctspace = 0xaa6
+XK_thinspace = 0xaa7
+XK_hairspace = 0xaa8
+XK_emdash = 0xaa9
+XK_endash = 0xaaa
+XK_signifblank = 0xaac
+XK_ellipsis = 0xaae
+XK_doubbaselinedot = 0xaaf
+XK_onethird = 0xab0
+XK_twothirds = 0xab1
+XK_onefifth = 0xab2
+XK_twofifths = 0xab3
+XK_threefifths = 0xab4
+XK_fourfifths = 0xab5
+XK_onesixth = 0xab6
+XK_fivesixths = 0xab7
+XK_careof = 0xab8
+XK_figdash = 0xabb
+XK_leftanglebracket = 0xabc
+XK_decimalpoint = 0xabd
+XK_rightanglebracket = 0xabe
+XK_marker = 0xabf
+XK_oneeighth = 0xac3
+XK_threeeighths = 0xac4
+XK_fiveeighths = 0xac5
+XK_seveneighths = 0xac6
+XK_trademark = 0xac9
+XK_signaturemark = 0xaca
+XK_trademarkincircle = 0xacb
+XK_leftopentriangle = 0xacc
+XK_rightopentriangle = 0xacd
+XK_emopencircle = 0xace
+XK_emopenrectangle = 0xacf
+XK_leftsinglequotemark = 0xad0
+XK_rightsinglequotemark = 0xad1
+XK_leftdoublequotemark = 0xad2
+XK_rightdoublequotemark = 0xad3
+XK_prescription = 0xad4
+XK_minutes = 0xad6
+XK_seconds = 0xad7
+XK_latincross = 0xad9
+XK_hexagram = 0xada
+XK_filledrectbullet = 0xadb
+XK_filledlefttribullet = 0xadc
+XK_filledrighttribullet = 0xadd
+XK_emfilledcircle = 0xade
+XK_emfilledrect = 0xadf
+XK_enopencircbullet = 0xae0
+XK_enopensquarebullet = 0xae1
+XK_openrectbullet = 0xae2
+XK_opentribulletup = 0xae3
+XK_opentribulletdown = 0xae4
+XK_openstar = 0xae5
+XK_enfilledcircbullet = 0xae6
+XK_enfilledsqbullet = 0xae7
+XK_filledtribulletup = 0xae8
+XK_filledtribulletdown = 0xae9
+XK_leftpointer = 0xaea
+XK_rightpointer = 0xaeb
+XK_club = 0xaec
+XK_diamond = 0xaed
+XK_heart = 0xaee
+XK_maltesecross = 0xaf0
+XK_dagger = 0xaf1
+XK_doubledagger = 0xaf2
+XK_checkmark = 0xaf3
+XK_ballotcross = 0xaf4
+XK_musicalsharp = 0xaf5
+XK_musicalflat = 0xaf6
+XK_malesymbol = 0xaf7
+XK_femalesymbol = 0xaf8
+XK_telephone = 0xaf9
+XK_telephonerecorder = 0xafa
+XK_phonographcopyright = 0xafb
+XK_caret = 0xafc
+XK_singlelowquotemark = 0xafd
+XK_doublelowquotemark = 0xafe
+XK_cursor = 0xaff
diff --git a/Xlib/keysymdef/special.py b/Xlib/keysymdef/special.py
new file mode 100644
index 0000000..dc76c17
--- /dev/null
+++ b/Xlib/keysymdef/special.py
@@ -0,0 +1,24 @@
+XK_blank = 0x9df
+XK_soliddiamond = 0x9e0
+XK_checkerboard = 0x9e1
+XK_ht = 0x9e2
+XK_ff = 0x9e3
+XK_cr = 0x9e4
+XK_lf = 0x9e5
+XK_nl = 0x9e8
+XK_vt = 0x9e9
+XK_lowrightcorner = 0x9ea
+XK_uprightcorner = 0x9eb
+XK_upleftcorner = 0x9ec
+XK_lowleftcorner = 0x9ed
+XK_crossinglines = 0x9ee
+XK_horizlinescan1 = 0x9ef
+XK_horizlinescan3 = 0x9f0
+XK_horizlinescan5 = 0x9f1
+XK_horizlinescan7 = 0x9f2
+XK_horizlinescan9 = 0x9f3
+XK_leftt = 0x9f4
+XK_rightt = 0x9f5
+XK_bott = 0x9f6
+XK_topt = 0x9f7
+XK_vertbar = 0x9f8
diff --git a/Xlib/keysymdef/technical.py b/Xlib/keysymdef/technical.py
new file mode 100644
index 0000000..00aa7a8
--- /dev/null
+++ b/Xlib/keysymdef/technical.py
@@ -0,0 +1,49 @@
+XK_leftradical = 0x8a1
+XK_topleftradical = 0x8a2
+XK_horizconnector = 0x8a3
+XK_topintegral = 0x8a4
+XK_botintegral = 0x8a5
+XK_vertconnector = 0x8a6
+XK_topleftsqbracket = 0x8a7
+XK_botleftsqbracket = 0x8a8
+XK_toprightsqbracket = 0x8a9
+XK_botrightsqbracket = 0x8aa
+XK_topleftparens = 0x8ab
+XK_botleftparens = 0x8ac
+XK_toprightparens = 0x8ad
+XK_botrightparens = 0x8ae
+XK_leftmiddlecurlybrace = 0x8af
+XK_rightmiddlecurlybrace = 0x8b0
+XK_topleftsummation = 0x8b1
+XK_botleftsummation = 0x8b2
+XK_topvertsummationconnector = 0x8b3
+XK_botvertsummationconnector = 0x8b4
+XK_toprightsummation = 0x8b5
+XK_botrightsummation = 0x8b6
+XK_rightmiddlesummation = 0x8b7
+XK_lessthanequal = 0x8bc
+XK_notequal = 0x8bd
+XK_greaterthanequal = 0x8be
+XK_integral = 0x8bf
+XK_therefore = 0x8c0
+XK_variation = 0x8c1
+XK_infinity = 0x8c2
+XK_nabla = 0x8c5
+XK_approximate = 0x8c8
+XK_similarequal = 0x8c9
+XK_ifonlyif = 0x8cd
+XK_implies = 0x8ce
+XK_identical = 0x8cf
+XK_radical = 0x8d6
+XK_includedin = 0x8da
+XK_includes = 0x8db
+XK_intersection = 0x8dc
+XK_union = 0x8dd
+XK_logicaland = 0x8de
+XK_logicalor = 0x8df
+XK_partialderivative = 0x8ef
+XK_function = 0x8f6
+XK_leftarrow = 0x8fb
+XK_uparrow = 0x8fc
+XK_rightarrow = 0x8fd
+XK_downarrow = 0x8fe
diff --git a/Xlib/keysymdef/thai.py b/Xlib/keysymdef/thai.py
new file mode 100644
index 0000000..2088f8c
--- /dev/null
+++ b/Xlib/keysymdef/thai.py
@@ -0,0 +1,84 @@
+XK_Thai_kokai = 0xda1
+XK_Thai_khokhai = 0xda2
+XK_Thai_khokhuat = 0xda3
+XK_Thai_khokhwai = 0xda4
+XK_Thai_khokhon = 0xda5
+XK_Thai_khorakhang = 0xda6
+XK_Thai_ngongu = 0xda7
+XK_Thai_chochan = 0xda8
+XK_Thai_choching = 0xda9
+XK_Thai_chochang = 0xdaa
+XK_Thai_soso = 0xdab
+XK_Thai_chochoe = 0xdac
+XK_Thai_yoying = 0xdad
+XK_Thai_dochada = 0xdae
+XK_Thai_topatak = 0xdaf
+XK_Thai_thothan = 0xdb0
+XK_Thai_thonangmontho = 0xdb1
+XK_Thai_thophuthao = 0xdb2
+XK_Thai_nonen = 0xdb3
+XK_Thai_dodek = 0xdb4
+XK_Thai_totao = 0xdb5
+XK_Thai_thothung = 0xdb6
+XK_Thai_thothahan = 0xdb7
+XK_Thai_thothong = 0xdb8
+XK_Thai_nonu = 0xdb9
+XK_Thai_bobaimai = 0xdba
+XK_Thai_popla = 0xdbb
+XK_Thai_phophung = 0xdbc
+XK_Thai_fofa = 0xdbd
+XK_Thai_phophan = 0xdbe
+XK_Thai_fofan = 0xdbf
+XK_Thai_phosamphao = 0xdc0
+XK_Thai_moma = 0xdc1
+XK_Thai_yoyak = 0xdc2
+XK_Thai_rorua = 0xdc3
+XK_Thai_ru = 0xdc4
+XK_Thai_loling = 0xdc5
+XK_Thai_lu = 0xdc6
+XK_Thai_wowaen = 0xdc7
+XK_Thai_sosala = 0xdc8
+XK_Thai_sorusi = 0xdc9
+XK_Thai_sosua = 0xdca
+XK_Thai_hohip = 0xdcb
+XK_Thai_lochula = 0xdcc
+XK_Thai_oang = 0xdcd
+XK_Thai_honokhuk = 0xdce
+XK_Thai_paiyannoi = 0xdcf
+XK_Thai_saraa = 0xdd0
+XK_Thai_maihanakat = 0xdd1
+XK_Thai_saraaa = 0xdd2
+XK_Thai_saraam = 0xdd3
+XK_Thai_sarai = 0xdd4
+XK_Thai_saraii = 0xdd5
+XK_Thai_saraue = 0xdd6
+XK_Thai_sarauee = 0xdd7
+XK_Thai_sarau = 0xdd8
+XK_Thai_sarauu = 0xdd9
+XK_Thai_phinthu = 0xdda
+XK_Thai_maihanakat_maitho = 0xdde
+XK_Thai_baht = 0xddf
+XK_Thai_sarae = 0xde0
+XK_Thai_saraae = 0xde1
+XK_Thai_sarao = 0xde2
+XK_Thai_saraaimaimuan = 0xde3
+XK_Thai_saraaimaimalai = 0xde4
+XK_Thai_lakkhangyao = 0xde5
+XK_Thai_maiyamok = 0xde6
+XK_Thai_maitaikhu = 0xde7
+XK_Thai_maiek = 0xde8
+XK_Thai_maitho = 0xde9
+XK_Thai_maitri = 0xdea
+XK_Thai_maichattawa = 0xdeb
+XK_Thai_thanthakhat = 0xdec
+XK_Thai_nikhahit = 0xded
+XK_Thai_leksun = 0xdf0
+XK_Thai_leknung = 0xdf1
+XK_Thai_leksong = 0xdf2
+XK_Thai_leksam = 0xdf3
+XK_Thai_leksi = 0xdf4
+XK_Thai_lekha = 0xdf5
+XK_Thai_lekhok = 0xdf6
+XK_Thai_lekchet = 0xdf7
+XK_Thai_lekpaet = 0xdf8
+XK_Thai_lekkao = 0xdf9
diff --git a/Xlib/keysymdef/xk3270.py b/Xlib/keysymdef/xk3270.py
new file mode 100644
index 0000000..019ba3b
--- /dev/null
+++ b/Xlib/keysymdef/xk3270.py
@@ -0,0 +1,30 @@
+XK_3270_Duplicate = 0xFD01
+XK_3270_FieldMark = 0xFD02
+XK_3270_Right2 = 0xFD03
+XK_3270_Left2 = 0xFD04
+XK_3270_BackTab = 0xFD05
+XK_3270_EraseEOF = 0xFD06
+XK_3270_EraseInput = 0xFD07
+XK_3270_Reset = 0xFD08
+XK_3270_Quit = 0xFD09
+XK_3270_PA1 = 0xFD0A
+XK_3270_PA2 = 0xFD0B
+XK_3270_PA3 = 0xFD0C
+XK_3270_Test = 0xFD0D
+XK_3270_Attn = 0xFD0E
+XK_3270_CursorBlink = 0xFD0F
+XK_3270_AltCursor = 0xFD10
+XK_3270_KeyClick = 0xFD11
+XK_3270_Jump = 0xFD12
+XK_3270_Ident = 0xFD13
+XK_3270_Rule = 0xFD14
+XK_3270_Copy = 0xFD15
+XK_3270_Play = 0xFD16
+XK_3270_Setup = 0xFD17
+XK_3270_Record = 0xFD18
+XK_3270_ChangeScreen = 0xFD19
+XK_3270_DeleteWord = 0xFD1A
+XK_3270_ExSelect = 0xFD1B
+XK_3270_CursorSelect = 0xFD1C
+XK_3270_PrintScreen = 0xFD1D
+XK_3270_Enter = 0xFD1E
diff --git a/Xlib/keysymdef/xkb.py b/Xlib/keysymdef/xkb.py
new file mode 100644
index 0000000..a6bde7d
--- /dev/null
+++ b/Xlib/keysymdef/xkb.py
@@ -0,0 +1,100 @@
+XK_ISO_Lock = 0xFE01
+XK_ISO_Level2_Latch = 0xFE02
+XK_ISO_Level3_Shift = 0xFE03
+XK_ISO_Level3_Latch = 0xFE04
+XK_ISO_Level3_Lock = 0xFE05
+XK_ISO_Group_Shift = 0xFF7E
+XK_ISO_Group_Latch = 0xFE06
+XK_ISO_Group_Lock = 0xFE07
+XK_ISO_Next_Group = 0xFE08
+XK_ISO_Next_Group_Lock = 0xFE09
+XK_ISO_Prev_Group = 0xFE0A
+XK_ISO_Prev_Group_Lock = 0xFE0B
+XK_ISO_First_Group = 0xFE0C
+XK_ISO_First_Group_Lock = 0xFE0D
+XK_ISO_Last_Group = 0xFE0E
+XK_ISO_Last_Group_Lock = 0xFE0F
+XK_ISO_Left_Tab = 0xFE20
+XK_ISO_Move_Line_Up = 0xFE21
+XK_ISO_Move_Line_Down = 0xFE22
+XK_ISO_Partial_Line_Up = 0xFE23
+XK_ISO_Partial_Line_Down = 0xFE24
+XK_ISO_Partial_Space_Left = 0xFE25
+XK_ISO_Partial_Space_Right = 0xFE26
+XK_ISO_Set_Margin_Left = 0xFE27
+XK_ISO_Set_Margin_Right = 0xFE28
+XK_ISO_Release_Margin_Left = 0xFE29
+XK_ISO_Release_Margin_Right = 0xFE2A
+XK_ISO_Release_Both_Margins = 0xFE2B
+XK_ISO_Fast_Cursor_Left = 0xFE2C
+XK_ISO_Fast_Cursor_Right = 0xFE2D
+XK_ISO_Fast_Cursor_Up = 0xFE2E
+XK_ISO_Fast_Cursor_Down = 0xFE2F
+XK_ISO_Continuous_Underline = 0xFE30
+XK_ISO_Discontinuous_Underline = 0xFE31
+XK_ISO_Emphasize = 0xFE32
+XK_ISO_Center_Object = 0xFE33
+XK_ISO_Enter = 0xFE34
+XK_dead_grave = 0xFE50
+XK_dead_acute = 0xFE51
+XK_dead_circumflex = 0xFE52
+XK_dead_tilde = 0xFE53
+XK_dead_macron = 0xFE54
+XK_dead_breve = 0xFE55
+XK_dead_abovedot = 0xFE56
+XK_dead_diaeresis = 0xFE57
+XK_dead_abovering = 0xFE58
+XK_dead_doubleacute = 0xFE59
+XK_dead_caron = 0xFE5A
+XK_dead_cedilla = 0xFE5B
+XK_dead_ogonek = 0xFE5C
+XK_dead_iota = 0xFE5D
+XK_dead_voiced_sound = 0xFE5E
+XK_dead_semivoiced_sound = 0xFE5F
+XK_dead_belowdot = 0xFE60
+XK_First_Virtual_Screen = 0xFED0
+XK_Prev_Virtual_Screen = 0xFED1
+XK_Next_Virtual_Screen = 0xFED2
+XK_Last_Virtual_Screen = 0xFED4
+XK_Terminate_Server = 0xFED5
+XK_AccessX_Enable = 0xFE70
+XK_AccessX_Feedback_Enable = 0xFE71
+XK_RepeatKeys_Enable = 0xFE72
+XK_SlowKeys_Enable = 0xFE73
+XK_BounceKeys_Enable = 0xFE74
+XK_StickyKeys_Enable = 0xFE75
+XK_MouseKeys_Enable = 0xFE76
+XK_MouseKeys_Accel_Enable = 0xFE77
+XK_Overlay1_Enable = 0xFE78
+XK_Overlay2_Enable = 0xFE79
+XK_AudibleBell_Enable = 0xFE7A
+XK_Pointer_Left = 0xFEE0
+XK_Pointer_Right = 0xFEE1
+XK_Pointer_Up = 0xFEE2
+XK_Pointer_Down = 0xFEE3
+XK_Pointer_UpLeft = 0xFEE4
+XK_Pointer_UpRight = 0xFEE5
+XK_Pointer_DownLeft = 0xFEE6
+XK_Pointer_DownRight = 0xFEE7
+XK_Pointer_Button_Dflt = 0xFEE8
+XK_Pointer_Button1 = 0xFEE9
+XK_Pointer_Button2 = 0xFEEA
+XK_Pointer_Button3 = 0xFEEB
+XK_Pointer_Button4 = 0xFEEC
+XK_Pointer_Button5 = 0xFEED
+XK_Pointer_DblClick_Dflt = 0xFEEE
+XK_Pointer_DblClick1 = 0xFEEF
+XK_Pointer_DblClick2 = 0xFEF0
+XK_Pointer_DblClick3 = 0xFEF1
+XK_Pointer_DblClick4 = 0xFEF2
+XK_Pointer_DblClick5 = 0xFEF3
+XK_Pointer_Drag_Dflt = 0xFEF4
+XK_Pointer_Drag1 = 0xFEF5
+XK_Pointer_Drag2 = 0xFEF6
+XK_Pointer_Drag3 = 0xFEF7
+XK_Pointer_Drag4 = 0xFEF8
+XK_Pointer_Drag5 = 0xFEFD
+XK_Pointer_EnableKeys = 0xFEF9
+XK_Pointer_Accelerate = 0xFEFA
+XK_Pointer_DfltBtnNext = 0xFEFB
+XK_Pointer_DfltBtnPrev = 0xFEFC
diff --git a/Xlib/protocol/ChangeLog b/Xlib/protocol/ChangeLog
new file mode 100644
index 0000000..0bb7dac
--- /dev/null
+++ b/Xlib/protocol/ChangeLog
@@ -0,0 +1,124 @@
+2006-07-22 Mike Grant <mgg@nobodymuch.org>
+ * Xlib/protocol/display.py: (mggrant) Fix for 1219457 - flushing
+ was blocking and waiting for a read operation. Added missing
+ "import socket" per bug report #681511. Fix for bug:1098695 &
+ 1098738. The "recv" variable was being used for more than one
+ thing - renamed one.
+
+ Changelog hasn't been maintained since 2002, but some of the more
+ significant comments from cvs logs follow:
+ * Xlib/protocol/request.py: (petli) Fix bugs in definition and
+ method of GrabButton/Pointer
+
+2002-02-22 Peter Liljenberg <peter.liljenberg@esdgkonsult.com>
+
+ * event.py(CirculateNotify, CirculateRequest): These are
+ identical, so subclass the common Circulate.
+
+2002-02-13 Peter Liljenberg <peter.liljenberg@esdgkonsult.com>
+
+ * rq.py (ValueList.parse_binary_value): Use = both for calcsize
+ and unpacking. Caused problems on Alpha.
+
+2002-02-11 Peter Liljenberg <peter.liljenberg@esdgkonsult.com>
+
+ * request.py (GetWindowAttributes): Rename class to win_class.
+ (AllocColorPlanes): Fix Pad(4) to Pad(8) in reply.
+
+ * rq.py (ReplyLength): Add a reply length field, for completeness
+ and easier unit test generation.
+
+2002-02-10 Peter Liljenberg <peter.liljenberg@esdgkonsult.com>
+
+ * rq.py (DictWrapper.__cmp__): Let DictWrapper compare with plain
+ dictionaries.
+ (Event.__init__): Set send_event to 0 when creating new events
+ objects, and allow events to be compared.
+
+ (Struct.parse_binary): Allow LengthFields to have a parse_value method.
+ (OddLength.parse_value): Decode field.
+ (String16.parse_binary_value): Handle OddLength fields.
+
+ (TextElements8.parse_binary_value): Bugfix: return values instead
+ of v.
+ (String8.parse_binary_value): Parse String8 with no LengthOf
+ field.
+
+2002-02-09 Peter Liljenberg <peter.liljenberg@esdgkonsult.com>
+
+ * rq.py (TextElements16): Bugfix: inherit TextElements8 instead of
+ TextElements16. Found while preparing unit tests, whee.
+
+2002-01-14 Peter Liljenberg <peter.liljenberg@esdgkonsult.com>
+
+ * display.py (Display.parse_event_response): Fix bug reported by
+ Ilpo Nyyssönen, whereby ReplyRequests which generates events
+ (e.g. get_property with delete = 1) will get dropped when the
+ event is received.
+
+2001-12-14 Peter Liljenberg <peter.liljenberg@esdgkonsult.com>
+
+ * display.py (Display.parse_event_response):
+ * rq.py (Event.__init__): Fixed bug in event type decoding: bit
+ 0-6 is the event type, and bit 7 is set if the event was sent by
+ SendEvent.
+
+
+2001-01-16 <petli@cendio.se>
+
+ * event.py: Changed some class names so that they correspond
+ exactly to the event type constants.
+
+Tue Jan 9 10:03:25 2001 Peter Liljenberg <petli@cendio.se>
+
+ * display.py (Display.send_request): Fixed a call to append() with
+ multiple arguments, something that modern Pythons don't allow.
+
+
+2001-01-04 <petli@cendio.se>
+
+ * rq.py: The fix for 64-bit platforms didn't work, and close
+ scrutiny of structmodule.c shows why: it turns out that '='
+ translates into '<' or '>', the one the platform would use. This
+ means B is one byte, H is two and L is four, and no extra
+ alignment, always. '@', which is the default, selects native
+ number of bytes, which on Alpha means that 'L' is eight bytes.
+
+ Now the code goes to pains to ensure that '=' encoding is always
+ used, so _now_ it should work on all platforms. Ahem.
+
+
+2000-12-29 <petli@cendio.se>
+
+ * rq.py: Optimizations:
+ + replace calls to Field.get_name() with access to attribute
+ name.
+ (Struct.build_from_args):
+
+Fri Dec 29 17:05:02 2000 Peter Liljenberg <petli@cendio.se>
+
+ * rq.py: Alpha forces us to probe how many bytes each struct code
+ in 'bhil' represents, instead of being able to assume that b is 1,
+ h is 2 and l is 4.
+
+2000-12-21 <petli@cendio.se>
+
+ * request.py (SetClipRectangles): Fixed typo (attribute was
+ "rectangels").
+
+2000-12-20 <petli@cendio.se>
+
+ * rq.py (DictWrapper.__setitem__),
+ (DictWrapper.__delitem__),
+ (DictWrapper.__setattr__),
+ (DictWrapper.__delattr__):
+ Add a few methods to the DictWrapper, to make sure that even if
+ attributes are changed, all attributes can be found in the _data
+ mapping.
+
+ (ValueField.__init__):
+ (Object.__init__):
+ (ValueField.pack_value):
+ (Set.__init__):
+ Added a default parameter, so that structure elements with a
+ default value can be omitted when calling build_from_args.
diff --git a/Xlib/protocol/__init__.py b/Xlib/protocol/__init__.py
new file mode 100644
index 0000000..24edc8d
--- /dev/null
+++ b/Xlib/protocol/__init__.py
@@ -0,0 +1,27 @@
+# $Id: __init__.py,v 1.1 2000/07/21 09:54:49 petli Exp $
+#
+# Xlib.protocol.__init__ -- glue for Xlib.protocol package
+#
+# Copyright (C) 2000 Peter Liljenberg <petli@ctrl-c.liu.se>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+__all__ = [
+ 'display',
+ 'event',
+ 'request',
+ 'rq',
+ 'structs',
+ ]
diff --git a/Xlib/protocol/display.py b/Xlib/protocol/display.py
new file mode 100644
index 0000000..1030f4b
--- /dev/null
+++ b/Xlib/protocol/display.py
@@ -0,0 +1,983 @@
+# $Id: display.py,v 1.25 2007/06/10 14:11:58 mggrant Exp $
+# -*- coding: latin-1 -*-
+#
+# Xlib.protocol.display -- core display communication
+#
+# Copyright (C) 2000-2002 Peter Liljenberg <petli@ctrl-c.liu.se>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+# Standard modules
+import sys
+import select
+import struct
+import errno
+import socket
+
+# Xlib modules
+from Xlib import error
+
+from Xlib.support import lock, connect
+
+# Xlib.protocol modules
+import rq
+import event
+
+class Display:
+ resource_classes = {}
+ extension_major_opcodes = {}
+ error_classes = error.xerror_class.copy()
+ event_classes = event.event_class.copy()
+
+ def __init__(self, display = None):
+ name, host, displayno, screenno = connect.get_display(display)
+
+ self.display_name = name
+ self.default_screen = screenno
+
+ self.socket = connect.get_socket(name, host, displayno)
+
+ auth_name, auth_data = connect.get_auth(self.socket,
+ name, host, displayno)
+
+ # Internal structures for communication, grouped
+ # by their function and locks
+
+ # Socket error indicator, set when the socket is closed
+ # in one way or another
+ self.socket_error_lock = lock.allocate_lock()
+ self.socket_error = None
+
+ # Event queue
+ self.event_queue_read_lock = lock.allocate_lock()
+ self.event_queue_write_lock = lock.allocate_lock()
+ self.event_queue = []
+
+ # Unsent request queue and sequence number counter
+ self.request_queue_lock = lock.allocate_lock()
+ self.request_serial = 1
+ self.request_queue = []
+
+ # Send-and-recieve loop, see function send_and_recive
+ # for a detailed explanation
+ self.send_recv_lock = lock.allocate_lock()
+ self.send_active = 0
+ self.recv_active = 0
+
+ self.event_waiting = 0
+ self.event_wait_lock = lock.allocate_lock()
+ self.request_waiting = 0
+ self.request_wait_lock = lock.allocate_lock()
+
+ # Data used by the send-and-recieve loop
+ self.sent_requests = []
+ self.request_length = 0
+ self.data_send = ''
+ self.data_recv = ''
+ self.data_sent_bytes = 0
+
+ # Resource ID structures
+ self.resource_id_lock = lock.allocate_lock()
+ self.resource_ids = {}
+ self.last_resource_id = 0
+
+ # Use an default error handler, one which just prints the error
+ self.error_handler = None
+
+
+ # Right, now we're all set up for the connection setup
+ # request with the server.
+
+ # Figure out which endianess the hardware uses
+ self.big_endian = struct.unpack('BB', struct.pack('H', 0x0100))[0]
+
+ if self.big_endian:
+ order = 0x42
+ else:
+ order = 0x6c
+
+ # Send connection setup
+ r = ConnectionSetupRequest(self,
+ byte_order = order,
+ protocol_major = 11,
+ protocol_minor = 0,
+ auth_prot_name = auth_name,
+ auth_prot_data = auth_data)
+
+ # Did connection fail?
+ if r.status != 1:
+ raise error.DisplayConnectionError(self.display_name, r.reason)
+
+ # Set up remaining info
+ self.info = r
+ self.default_screen = min(self.default_screen, len(self.info.roots) - 1)
+
+
+ #
+ # Public interface
+ #
+
+ def get_display_name(self):
+ return self.display_name
+
+ def get_default_screen(self):
+ return self.default_screen
+
+ def fileno(self):
+ self.check_for_error()
+ return self.socket.fileno()
+
+ def next_event(self):
+ self.check_for_error()
+
+ # Main lock, so that only one thread at a time performs the
+ # event waiting code. This at least guarantees that the first
+ # thread calling next_event() will get the next event, although
+ # no order is guaranteed among other threads calling next_event()
+ # while the first is blocking.
+
+ self.event_queue_read_lock.acquire()
+
+ # Lock event queue, so we can check if it is empty
+ self.event_queue_write_lock.acquire()
+
+ # We have too loop until we get an event, as
+ # we might be woken up when there is no event.
+
+ while not self.event_queue:
+
+ # Lock send_recv so no send_and_recieve
+ # can start or stop while we're checking
+ # whether there are one active.
+ self.send_recv_lock.acquire()
+
+ # Release event queue to allow an send_and_recv to
+ # insert any now.
+ self.event_queue_write_lock.release()
+
+ # Call send_and_recv, which will return when
+ # something has occured
+ self.send_and_recv(event = 1)
+
+ # Before looping around, lock the event queue against
+ # modifications.
+ self.event_queue_write_lock.acquire()
+
+ # Whiew, we have an event! Remove it from
+ # the event queue and relaese its write lock.
+
+ event = self.event_queue[0]
+ del self.event_queue[0]
+ self.event_queue_write_lock.release()
+
+ # Finally, allow any other threads which have called next_event()
+ # while we were waiting to proceed.
+
+ self.event_queue_read_lock.release()
+
+ # And return the event!
+ return event
+
+ def pending_events(self):
+ self.check_for_error()
+
+ # Make a send_and_recv pass, receiving any events
+ self.send_recv_lock.acquire()
+ self.send_and_recv(recv = 1)
+
+ # Lock the queue, get the event count, and unlock again.
+ self.event_queue_write_lock.acquire()
+ count = len(self.event_queue)
+ self.event_queue_write_lock.release()
+
+ return count
+
+ def flush(self):
+ self.check_for_error()
+ self.send_recv_lock.acquire()
+ self.send_and_recv(flush = 1)
+
+ def close(self):
+ self.flush()
+ self.close_internal('client')
+
+ def set_error_handler(self, handler):
+ self.error_handler = handler
+
+
+ def allocate_resource_id(self):
+ """id = d.allocate_resource_id()
+
+ Allocate a new X resource id number ID.
+
+ Raises ResourceIDError if there are no free resource ids.
+ """
+
+ self.resource_id_lock.acquire()
+ try:
+ i = self.last_resource_id
+ while self.resource_ids.has_key(i):
+ i = i + 1
+ if i > self.info.resource_id_mask:
+ i = 0
+ if i == self.last_resource_id:
+ raise error.ResourceIDError('out of resource ids')
+
+ self.resource_ids[i] = None
+ self.last_resource_id = i
+ return self.info.resource_id_base | i
+ finally:
+ self.resource_id_lock.release()
+
+ def free_resource_id(self, rid):
+ """d.free_resource_id(rid)
+
+ Free resource id RID. Attempts to free a resource id which
+ isn't allocated by us are ignored.
+ """
+
+ self.resource_id_lock.acquire()
+ try:
+ i = rid & self.info.resource_id_mask
+
+ # Attempting to free a resource id outside our range
+ if rid - i != self.info.resource_id_base:
+ return None
+
+ try:
+ del self.resource_ids[i]
+ except KeyError:
+ pass
+ finally:
+ self.resource_id_lock.release()
+
+
+
+ def get_resource_class(self, class_name, default = None):
+ """class = d.get_resource_class(class_name, default = None)
+
+ Return the class to be used for X resource objects of type
+ CLASS_NAME, or DEFAULT if no such class is set.
+ """
+
+ return self.resource_classes.get(class_name, default)
+
+ def set_extension_major(self, extname, major):
+ self.extension_major_opcodes[extname] = major
+
+ def get_extension_major(self, extname):
+ return self.extension_major_opcodes[extname]
+
+ def add_extension_event(self, code, evt):
+ self.event_classes[code] = evt
+
+ def add_extension_error(self, code, err):
+ self.error_classes[code] = err
+
+
+ #
+ # Private functions
+ #
+
+ def check_for_error(self):
+ self.socket_error_lock.acquire()
+ err = self.socket_error
+ self.socket_error_lock.release()
+
+ if err:
+ raise err
+
+ def send_request(self, request, wait_for_response):
+ if self.socket_error:
+ raise self.socket_error
+
+ self.request_queue_lock.acquire()
+
+ request._serial = self.request_serial
+ self.request_serial = (self.request_serial + 1) % 65536
+
+ self.request_queue.append((request, wait_for_response))
+ qlen = len(self.request_queue)
+
+ self.request_queue_lock.release()
+
+# if qlen > 10:
+# self.flush()
+
+ def close_internal(self, whom):
+ # Clear out data structures
+ self.request_queue = None
+ self.sent_requests = None
+ self.event_queue = None
+ self.data_send = None
+ self.data_recv = None
+
+ # Close the connection
+ self.socket.close()
+
+ # Set a connection closed indicator
+ self.socket_error_lock.acquire()
+ self.socket_error = error.ConnectionClosedError(whom)
+ self.socket_error_lock.release()
+
+
+ def send_and_recv(self, flush = None, event = None, request = None, recv = None):
+ """send_and_recv(flush = None, event = None, request = None, recv = None)
+
+ Perform I/O, or wait for some other thread to do it for us.
+
+ send_recv_lock MUST be LOCKED when send_and_recv is called.
+ It will be UNLOCKED at return.
+
+ Exactly or one of the parameters flush, event, request and recv must
+ be set to control the return condition.
+
+ To attempt to send all requests in the queue, flush should
+ be true. Will return immediately if another thread is
+ already doing send_and_recv.
+
+ To wait for an event to be recieved, event should be true.
+
+ To wait for a response to a certain request (either an error
+ or a response), request should be set the that request's
+ serial number.
+
+ To just read any pending data from the server, recv should be true.
+
+ It is not guaranteed that the return condition has been
+ fulfilled when the function returns, so the caller has to loop
+ until it is finished.
+ """
+
+ # We go to sleep if there is already a thread doing what we
+ # want to do:
+
+ # If flushing, we want to send
+ # If waiting for a response to a request, we want to send
+ # (to ensure that the request was sent - we alway recv
+ # when we get to the main loop, but sending is the important
+ # thing here)
+ # If waiting for an event, we want to recv
+ # If just trying to receive anything we can, we want to recv
+
+ if (((flush or request is not None) and self.send_active)
+ or ((event or recv) and self.recv_active)):
+
+ # Signal that we are waiting for something. These locks
+ # together with the *_waiting variables are used as
+ # semaphores. When an event or a request response arrives,
+ # it will zero the *_waiting and unlock the lock. The
+ # locks will also be unlocked when an active send_and_recv
+ # finishes to signal the other waiting threads that one of
+ # them has to take over the send_and_recv function.
+
+ # All this makes these locks and variables a part of the
+ # send_and_recv control logic, and hence must be modified
+ # only when we have the send_recv_lock locked.
+ if event:
+ wait_lock = self.event_wait_lock
+ if not self.event_waiting:
+ self.event_waiting = 1
+ wait_lock.acquire()
+
+ elif request is not None:
+ wait_lock = self.request_wait_lock
+ if not self.request_waiting:
+ self.request_waiting = 1
+ wait_lock.acquire()
+
+ # Release send_recv, allowing a send_and_recive
+ # to terminate or other threads to queue up
+ self.send_recv_lock.release()
+
+ # Return immediately if flushing, even if that
+ # might mean that not necessarily all requests
+ # have been sent.
+ if flush or recv:
+ return
+
+ # Wait for something to happen, as the wait locks are
+ # unlocked either when what we wait for has arrived (not
+ # necessarily the exact object we're waiting for, though),
+ # or when an active send_and_recv exits.
+
+ # Release it immediately afterwards as we're only using
+ # the lock for synchonization. Since we're not modifying
+ # event_waiting or request_waiting here we don't have
+ # to lock send_and_recv_lock. In fact, we can't do that
+ # or we trigger a dead-lock.
+
+ wait_lock.acquire()
+ wait_lock.release()
+
+ # Return to caller to let it check whether it has
+ # got the data it was waiting for
+ return
+
+
+ # There's no thread doing what we need to do. Find out exactly
+ # what to do
+
+ # There must always be some thread recieving data, but it must not
+ # necessarily be us
+
+ if not self.recv_active:
+ recieving = 1
+ self.recv_active = 1
+ else:
+ recieving = 0
+
+ flush_bytes = None
+ sending = 0
+
+ # Loop, recieving and sending data.
+ while 1:
+
+ # We might want to start sending data
+ if sending or not self.send_active:
+
+ # Turn all requests on request queue into binary form
+ # and append them to self.data_send
+
+ self.request_queue_lock.acquire()
+ for req, wait in self.request_queue:
+ self.data_send = self.data_send + req._binary
+ if wait:
+ self.sent_requests.append(req)
+
+ del self.request_queue[:]
+ self.request_queue_lock.release()
+
+ # If there now is data to send, mark us as senders
+
+ if self.data_send:
+ self.send_active = 1
+ sending = 1
+ else:
+ self.send_active = 0
+ sending = 0
+
+ # We've done all setup, so release the lock and start waiting
+ # for the network to fire up
+ self.send_recv_lock.release()
+
+ # If we're flushing, figure out how many bytes we
+ # have to send so that we're not caught in an interminable
+ # loop if other threads continuously append requests.
+ if flush and flush_bytes is None:
+ flush_bytes = self.data_sent_bytes + len(self.data_send)
+
+
+ try:
+ # We're only checking for the socket to be writable
+ # if we're the sending thread. We always check for it
+ # to become readable: either we are the recieving thread
+ # and should take care of the data, or the recieving thread
+ # might finish recieving after having read the data
+
+ if sending:
+ writeset = [self.socket]
+ else:
+ writeset = []
+
+ # Timeout immediately if we're only checking for
+ # something to read or if we're flushing, otherwise block
+
+ if recv or flush:
+ timeout = 0
+ else:
+ timeout = None
+
+ rs, ws, es = select.select([self.socket], writeset, [], timeout)
+
+ # Ignore errors caused by a signal recieved while blocking.
+ # All other errors are re-raised.
+ except select.error, err:
+ if err[0] != errno.EINTR:
+ raise err
+
+ # We must lock send_and_recv before we can loop to
+ # the start of the loop
+
+ self.send_recv_lock.acquire()
+ continue
+
+
+ # Socket is ready for sending data, send as much as possible.
+ if ws:
+ try:
+ i = self.socket.send(self.data_send)
+ except socket.error, err:
+ self.close_internal('server: %s' % err[1])
+ raise self.socket_error
+
+ self.data_send = self.data_send[i:]
+ self.data_sent_bytes = self.data_sent_bytes + i
+
+
+ # There is data to read
+ gotreq = 0
+ if rs:
+
+ # We're the recieving thread, parse the data
+ if recieving:
+ try:
+ bytes_recv = self.socket.recv(2048)
+ except socket.error, err:
+ self.close_internal('server: %s' % err[1])
+ raise self.socket_error
+
+ if not bytes_recv:
+ # Clear up, set a connection closed indicator and raise it
+ self.close_internal('server')
+ raise self.socket_error
+
+ self.data_recv = self.data_recv + bytes_recv
+ gotreq = self.parse_response(request)
+
+ # Otherwise return, allowing the calling thread to figure
+ # out if it has got the data it needs
+ else:
+ # We must be a sending thread if we're here, so reset
+ # that indicator.
+ self.send_recv_lock.acquire()
+ self.send_active = 0
+ self.send_recv_lock.release()
+
+ # And return to the caller
+ return
+
+
+ # There are three different end of send-recv-loop conditions.
+ # However, we don't leave the loop immediately, instead we
+ # try to send and recieve any data that might be left. We
+ # do this by giving a timeout of 0 to select to poll
+ # the socket.
+
+ # When flushing: all requests have been sent
+ if flush and flush_bytes >= self.data_sent_bytes:
+ break
+
+ # When waiting for an event: an event has been read
+ if event and self.event_queue:
+ break
+
+ # When processing a certain request: got its reply
+ if request is not None and gotreq:
+ break
+
+ # Always break if we just want to recieve as much as possible
+ if recv:
+ break
+
+ # Else there's may still data which must be sent, or
+ # we haven't got the data we waited for. Lock and loop
+
+ self.send_recv_lock.acquire()
+
+
+ # We have accomplished the callers request.
+ # Record that there are now no active send_and_recv,
+ # and wake up all waiting thread
+
+ self.send_recv_lock.acquire()
+
+ if sending:
+ self.send_active = 0
+ if recieving:
+ self.recv_active = 0
+
+ if self.event_waiting:
+ self.event_waiting = 0
+ self.event_wait_lock.release()
+
+ if self.request_waiting:
+ self.request_waiting = 0
+ self.request_wait_lock.release()
+
+ self.send_recv_lock.release()
+
+
+ def parse_response(self, request):
+ """Internal method.
+
+ Parse data recieved from server. If REQUEST is not None
+ true is returned if the request with that serial number
+ was recieved, otherwise false is returned.
+
+ If REQUEST is -1, we're parsing the server connection setup
+ response.
+ """
+
+ if request == -1:
+ return self.parse_connection_setup()
+
+ # Parse ordinary server response
+ gotreq = 0
+ while 1:
+ # Are we're waiting for additional data for a request response?
+ if self.request_length:
+ if len(self.data_recv) < self.request_length:
+ return gotreq
+ else:
+ gotreq = self.parse_request_response(request) or gotreq
+
+
+ # Every response is at least 32 bytes long, so don't bother
+ # until we have recieved that much
+ if len(self.data_recv) < 32:
+ return gotreq
+
+ # Check the first byte to find out what kind of response it is
+ rtype = ord(self.data_recv[0])
+
+ # Error resposne
+ if rtype == 0:
+ gotreq = self.parse_error_response(request) or gotreq
+
+ # Request response
+ elif rtype == 1:
+ # Set reply length, and loop around to see if
+ # we have got the full response
+ rlen = int(struct.unpack('=L', self.data_recv[4:8])[0])
+ self.request_length = 32 + rlen * 4
+
+ # Else event response
+ else:
+ self.parse_event_response(rtype)
+
+
+ def parse_error_response(self, request):
+ # Code is second byte
+ code = ord(self.data_recv[1])
+
+ # Fetch error class
+ estruct = self.error_classes.get(code, error.XError)
+
+ e = estruct(self, self.data_recv[:32])
+ self.data_recv = buffer(self.data_recv, 32)
+
+ # print 'recv Error:', e
+
+ req = self.get_waiting_request(e.sequence_number)
+
+ # Error for a request whose response we are waiting for,
+ # or which have an error handler. However, if the error
+ # handler indicates that it hasn't taken care of the
+ # error, pass it on to the default error handler
+
+ if req and req._set_error(e):
+
+ # If this was a ReplyRequest, unlock any threads waiting
+ # for a request to finish
+
+ if isinstance(req, rq.ReplyRequest):
+ self.send_recv_lock.acquire()
+
+ if self.request_waiting:
+ self.request_waiting = 0
+ self.request_wait_lock.release()
+
+ self.send_recv_lock.release()
+
+ return request == e.sequence_number
+
+ # Else call the error handler
+ else:
+ if self.error_handler:
+ rq.call_error_handler(self.error_handler, e, None)
+ else:
+ self.default_error_handler(e)
+
+ return 0
+
+
+ def default_error_handler(self, err):
+ sys.stderr.write('X protocol error:\n%s\n' % err)
+
+
+ def parse_request_response(self, request):
+ req = self.get_waiting_replyrequest()
+
+ # Sequence number is always data[2:4]
+ # Do sanity check before trying to parse the data
+ sno = struct.unpack('=H', self.data_recv[2:4])[0]
+ if sno != req._serial:
+ raise RuntimeError("Expected reply for request %s, but got %s. Can't happen!"
+ % (req._serial, sno))
+
+ req._parse_response(self.data_recv[:self.request_length])
+ # print 'recv Request:', req
+
+ self.data_recv = buffer(self.data_recv, self.request_length)
+ self.request_length = 0
+
+
+ # Unlock any response waiting threads
+
+ self.send_recv_lock.acquire()
+
+ if self.request_waiting:
+ self.request_waiting = 0
+ self.request_wait_lock.release()
+
+ self.send_recv_lock.release()
+
+
+ return req.sequence_number == request
+
+
+ def parse_event_response(self, etype):
+ # Skip bit 8 at lookup, that is set if this event came from an
+ # SendEvent
+ estruct = self.event_classes.get(etype & 0x7f, event.AnyEvent)
+
+ e = estruct(display = self, binarydata = self.data_recv[:32])
+
+ self.data_recv = buffer(self.data_recv, 32)
+
+ # Drop all requests having an error handler,
+ # but which obviously succeded.
+
+ # Decrement it by one, so that we don't remove the request
+ # that generated these events, if there is such a one.
+ # Bug reported by Ilpo Nyyssönen
+ self.get_waiting_request((e.sequence_number - 1) % 65536)
+
+ # print 'recv Event:', e
+
+ # Insert the event into the queue
+ self.event_queue_write_lock.acquire()
+ self.event_queue.append(e)
+ self.event_queue_write_lock.release()
+
+ # Unlock any event waiting threads
+ self.send_recv_lock.acquire()
+
+ if self.event_waiting:
+ self.event_waiting = 0
+ self.event_wait_lock.release()
+
+ self.send_recv_lock.release()
+
+
+ def get_waiting_request(self, sno):
+ if not self.sent_requests:
+ return None
+
+ # Normalize sequence numbers, even if they have wrapped.
+ # This ensures that
+ # sno <= last_serial
+ # and
+ # self.sent_requests[0]._serial <= last_serial
+
+ if self.sent_requests[0]._serial > self.request_serial:
+ last_serial = self.request_serial + 65536
+ if sno < self.request_serial:
+ sno = sno + 65536
+
+ else:
+ last_serial = self.request_serial
+ if sno > self.request_serial:
+ sno = sno - 65536
+
+ # No matching events at all
+ if sno < self.sent_requests[0]._serial:
+ return None
+
+ # Find last req <= sno
+ req = None
+ reqpos = len(self.sent_requests)
+ adj = 0
+ last = 0
+
+ for i in range(0, len(self.sent_requests)):
+ rno = self.sent_requests[i]._serial + adj
+
+ # Did serial numbers just wrap around?
+ if rno < last:
+ adj = 65536
+ rno = rno + adj
+
+ last = rno
+
+ if sno == rno:
+ req = self.sent_requests[i]
+ reqpos = i + 1
+ break
+ elif sno < rno:
+ req = None
+ reqpos = i
+ break
+
+ # Delete all request such as req <= sno
+ del self.sent_requests[:reqpos]
+
+ return req
+
+ def get_waiting_replyrequest(self):
+ for i in range(0, len(self.sent_requests)):
+ if hasattr(self.sent_requests[i], '_reply'):
+ req = self.sent_requests[i]
+ del self.sent_requests[:i + 1]
+ return req
+
+ # Reply for an unknown request? No, that can't happen.
+ else:
+ raise RuntimeError("Request reply to unknown request. Can't happen!")
+
+ def parse_connection_setup(self):
+ """Internal function used to parse connection setup response.
+ """
+
+ # Only the ConnectionSetupRequest has been sent so far
+ r = self.sent_requests[0]
+
+ while 1:
+ # print 'data_send:', repr(self.data_send)
+ # print 'data_recv:', repr(self.data_recv)
+
+ if r._data:
+ alen = r._data['additional_length'] * 4
+
+ # The full response haven't arrived yet
+ if len(self.data_recv) < alen:
+ return 0
+
+ # Connection failed or further authentication is needed.
+ # Set reason to the reason string
+ if r._data['status'] != 1:
+ r._data['reason'] = self.data_recv[:r._data['reason_length']]
+
+ # Else connection succeeded, parse the reply
+ else:
+ x, d = r._success_reply.parse_binary(self.data_recv[:alen],
+ self, rawdict = 1)
+ r._data.update(x)
+
+ del self.sent_requests[0]
+
+ self.data_recv = self.data_recv[alen:]
+
+ return 1
+
+ else:
+ # The base reply is 8 bytes long
+ if len(self.data_recv) < 8:
+ return 0
+
+ r._data, d = r._reply.parse_binary(self.data_recv[:8],
+ self, rawdict = 1)
+ self.data_recv = self.data_recv[8:]
+
+ # Loop around to see if we have got the additional data
+ # already
+
+
+PixmapFormat = rq.Struct( rq.Card8('depth'),
+ rq.Card8('bits_per_pixel'),
+ rq.Card8('scanline_pad'),
+ rq.Pad(5)
+ )
+
+VisualType = rq.Struct ( rq.Card32('visual_id'),
+ rq.Card8('visual_class'),
+ rq.Card8('bits_per_rgb_value'),
+ rq.Card16('colormap_entries'),
+ rq.Card32('red_mask'),
+ rq.Card32('green_mask'),
+ rq.Card32('blue_mask'),
+ rq.Pad(4)
+ )
+
+Depth = rq.Struct( rq.Card8('depth'),
+ rq.Pad(1),
+ rq.LengthOf('visuals', 2),
+ rq.Pad(4),
+ rq.List('visuals', VisualType)
+ )
+
+Screen = rq.Struct( rq.Window('root'),
+ rq.Colormap('default_colormap'),
+ rq.Card32('white_pixel'),
+ rq.Card32('black_pixel'),
+ rq.Card32('current_input_mask'),
+ rq.Card16('width_in_pixels'),
+ rq.Card16('height_in_pixels'),
+ rq.Card16('width_in_mms'),
+ rq.Card16('height_in_mms'),
+ rq.Card16('min_installed_maps'),
+ rq.Card16('max_installed_maps'),
+ rq.Card32('root_visual'),
+ rq.Card8('backing_store'),
+ rq.Card8('save_unders'),
+ rq.Card8('root_depth'),
+ rq.LengthOf('allowed_depths', 1),
+ rq.List('allowed_depths', Depth)
+ )
+
+
+class ConnectionSetupRequest(rq.GetAttrData):
+ _request = rq.Struct( rq.Set('byte_order', 1, (0x42, 0x6c)),
+ rq.Pad(1),
+ rq.Card16('protocol_major'),
+ rq.Card16('protocol_minor'),
+ rq.LengthOf('auth_prot_name', 2),
+ rq.LengthOf('auth_prot_data', 2),
+ rq.Pad(2),
+ rq.String8('auth_prot_name'),
+ rq.String8('auth_prot_data') )
+
+ _reply = rq.Struct ( rq.Card8('status'),
+ rq.Card8('reason_length'),
+ rq.Card16('protocol_major'),
+ rq.Card16('protocol_minor'),
+ rq.Card16('additional_length') )
+
+ _success_reply = rq.Struct( rq.Card32('release_number'),
+ rq.Card32('resource_id_base'),
+ rq.Card32('resource_id_mask'),
+ rq.Card32('motion_buffer_size'),
+ rq.LengthOf('vendor', 2),
+ rq.Card16('max_request_length'),
+ rq.LengthOf('roots', 1),
+ rq.LengthOf('pixmap_formats', 1),
+ rq.Card8('image_byte_order'),
+ rq.Card8('bitmap_format_bit_order'),
+ rq.Card8('bitmap_format_scanline_unit'),
+ rq.Card8('bitmap_format_scanline_pad'),
+ rq.Card8('min_keycode'),
+ rq.Card8('max_keycode'),
+ rq.Pad(4),
+ rq.String8('vendor'),
+ rq.List('pixmap_formats', PixmapFormat),
+ rq.List('roots', Screen),
+ )
+
+
+ def __init__(self, display, *args, **keys):
+ self._binary = apply(self._request.to_binary, args, keys)
+ self._data = None
+
+ # Don't bother about locking, since no other threads have
+ # access to the display yet
+
+ display.request_queue.append((self, 1))
+
+ # However, we must lock send_and_recv, but we don't have
+ # to loop.
+
+ display.send_recv_lock.acquire()
+ display.send_and_recv(request = -1)
diff --git a/Xlib/protocol/event.py b/Xlib/protocol/event.py
new file mode 100644
index 0000000..3894ac0
--- /dev/null
+++ b/Xlib/protocol/event.py
@@ -0,0 +1,433 @@
+# $Id: event.py,v 1.7 2007/06/10 14:11:58 mggrant Exp $
+#
+# Xlib.protocol.event -- definitions of core events
+#
+# Copyright (C) 2000-2002 Peter Liljenberg <petli@ctrl-c.liu.se>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+# Xlib modules
+from Xlib import X
+
+# Xlib.protocol modules
+import rq
+
+
+class AnyEvent(rq.Event):
+ _code = None
+ _fields = rq.Struct( rq.Card8('type'),
+ rq.Card8('detail'),
+ rq.Card16('sequence_number'),
+ rq.FixedString('data', 28),
+ )
+
+class KeyButtonPointer(rq.Event):
+ _code = None
+ _fields = rq.Struct( rq.Card8('type'),
+ rq.Card8('detail'),
+ rq.Card16('sequence_number'),
+ rq.Card32('time'),
+ rq.Window('root'),
+ rq.Window('window'),
+ rq.Window('child', (X.NONE, )),
+ rq.Int16('root_x'),
+ rq.Int16('root_y'),
+ rq.Int16('event_x'),
+ rq.Int16('event_y'),
+ rq.Card16('state'),
+ rq.Card8('same_screen'),
+ rq.Pad(1),
+ )
+
+class KeyPress(KeyButtonPointer):
+ _code = X.KeyPress
+
+class KeyRelease(KeyButtonPointer):
+ _code = X.KeyRelease
+
+class ButtonPress(KeyButtonPointer):
+ _code = X.ButtonPress
+
+class ButtonRelease(KeyButtonPointer):
+ _code = X.ButtonRelease
+
+class MotionNotify(KeyButtonPointer):
+ _code = X.MotionNotify
+
+class EnterLeave(rq.Event):
+ _code = None
+ _fields = rq.Struct( rq.Card8('type'),
+ rq.Card8('detail'),
+ rq.Card16('sequence_number'),
+ rq.Card32('time'),
+ rq.Window('root'),
+ rq.Window('window'),
+ rq.Window('child', (X.NONE, )),
+ rq.Int16('root_x'),
+ rq.Int16('root_y'),
+ rq.Int16('event_x'),
+ rq.Int16('event_y'),
+ rq.Card16('state'),
+ rq.Card8('mode'),
+ rq.Card8('flags'),
+ )
+
+class EnterNotify(EnterLeave):
+ _code = X.EnterNotify
+
+class LeaveNotify(EnterLeave):
+ _code = X.LeaveNotify
+
+
+class Focus(rq.Event):
+ _code = None
+ _fields = rq.Struct( rq.Card8('type'),
+ rq.Card8('detail'),
+ rq.Card16('sequence_number'),
+ rq.Window('window'),
+ rq.Card8('mode'),
+ rq.Pad(23),
+ )
+
+class FocusIn(Focus):
+ _code = X.FocusIn
+
+class FocusOut(Focus):
+ _code = X.FocusOut
+
+class Expose(rq.Event):
+ _code = X.Expose
+ _fields = rq.Struct( rq.Card8('type'),
+ rq.Pad(1),
+ rq.Card16('sequence_number'),
+ rq.Window('window'),
+ rq.Card16('x'),
+ rq.Card16('y'),
+ rq.Card16('width'),
+ rq.Card16('height'),
+ rq.Card16('count'),
+ rq.Pad(14),
+ )
+
+class GraphicsExpose(rq.Event):
+ _code = X.GraphicsExpose
+ _fields = rq.Struct( rq.Card8('type'),
+ rq.Pad(1),
+ rq.Card16('sequence_number'),
+ rq.Drawable('drawable'),
+ rq.Card16('x'),
+ rq.Card16('y'),
+ rq.Card16('width'),
+ rq.Card16('height'),
+ rq.Card16('minor_event'),
+ rq.Card16('count'),
+ rq.Card8('major_event'),
+ rq.Pad(11),
+ )
+
+class NoExpose(rq.Event):
+ _code = X.NoExpose
+ _fields = rq.Struct( rq.Card8('type'),
+ rq.Pad(1),
+ rq.Card16('sequence_number'),
+ rq.Drawable('window'),
+ rq.Card16('minor_event'),
+ rq.Card8('major_event'),
+ rq.Pad(21),
+ )
+
+class VisibilityNotify(rq.Event):
+ _code = X.VisibilityNotify
+ _fields = rq.Struct( rq.Card8('type'),
+ rq.Pad(1),
+ rq.Card16('sequence_number'),
+ rq.Window('window'),
+ rq.Card8('state'),
+ rq.Pad(23),
+ )
+
+class CreateNotify(rq.Event):
+ _code = X.CreateNotify
+ _fields = rq.Struct( rq.Card8('type'),
+ rq.Pad(1),
+ rq.Card16('sequence_number'),
+ rq.Window('parent'),
+ rq.Window('window'),
+ rq.Int16('x'),
+ rq.Int16('y'),
+ rq.Card16('width'),
+ rq.Card16('height'),
+ rq.Card16('border_width'),
+ rq.Card8('override'),
+ rq.Pad(9),
+ )
+
+class DestroyNotify(rq.Event):
+ _code = X.DestroyNotify
+ _fields = rq.Struct( rq.Card8('type'),
+ rq.Pad(1),
+ rq.Card16('sequence_number'),
+ rq.Window('event'),
+ rq.Window('window'),
+ rq.Pad(20),
+ )
+
+class UnmapNotify(rq.Event):
+ _code = X.UnmapNotify
+ _fields = rq.Struct( rq.Card8('type'),
+ rq.Pad(1),
+ rq.Card16('sequence_number'),
+ rq.Window('event'),
+ rq.Window('window'),
+ rq.Card8('from_configure'),
+ rq.Pad(19),
+ )
+
+class MapNotify(rq.Event):
+ _code = X.MapNotify
+ _fields = rq.Struct( rq.Card8('type'),
+ rq.Pad(1),
+ rq.Card16('sequence_number'),
+ rq.Window('event'),
+ rq.Window('window'),
+ rq.Card8('override'),
+ rq.Pad(19),
+ )
+
+class MapRequest(rq.Event):
+ _code = X.MapRequest
+ _fields = rq.Struct( rq.Card8('type'),
+ rq.Pad(1),
+ rq.Card16('sequence_number'),
+ rq.Window('parent'),
+ rq.Window('window'),
+ rq.Pad(20),
+ )
+
+class ReparentNotify(rq.Event):
+ _code = X.ReparentNotify
+ _fields = rq.Struct( rq.Card8('type'),
+ rq.Pad(1),
+ rq.Card16('sequence_number'),
+ rq.Window('event'),
+ rq.Window('window'),
+ rq.Window('parent'),
+ rq.Int16('x'),
+ rq.Int16('y'),
+ rq.Card8('override'),
+ rq.Pad(11),
+ )
+
+class ConfigureNotify(rq.Event):
+ _code = X.ConfigureNotify
+ _fields = rq.Struct( rq.Card8('type'),
+ rq.Pad(1),
+ rq.Card16('sequence_number'),
+ rq.Window('event'),
+ rq.Window('window'),
+ rq.Window('above_sibling', (X.NONE, )),
+ rq.Int16('x'),
+ rq.Int16('y'),
+ rq.Card16('width'),
+ rq.Card16('height'),
+ rq.Card16('border_width'),
+ rq.Card8('override'),
+ rq.Pad(5),
+ )
+
+class ConfigureRequest(rq.Event):
+ _code = X.ConfigureRequest
+ _fields = rq.Struct( rq.Card8('type'),
+ rq.Card8('stack_mode'),
+ rq.Card16('sequence_number'),
+ rq.Window('parent'),
+ rq.Window('window'),
+ rq.Window('sibling', (X.NONE, )),
+ rq.Int16('x'),
+ rq.Int16('y'),
+ rq.Card16('width'),
+ rq.Card16('height'),
+ rq.Card16('border_width'),
+ rq.Card16('value_mask'),
+ rq.Pad(4),
+ )
+
+class GravityNotify(rq.Event):
+ _code = X.GravityNotify
+ _fields = rq.Struct( rq.Card8('type'),
+ rq.Pad(1),
+ rq.Card16('sequence_number'),
+ rq.Window('event'),
+ rq.Window('window'),
+ rq.Int16('x'),
+ rq.Int16('y'),
+ rq.Pad(16),
+ )
+
+class ResizeRequest(rq.Event):
+ _code = X.ResizeRequest
+ _fields = rq.Struct( rq.Card8('type'),
+ rq.Pad(1),
+ rq.Card16('sequence_number'),
+ rq.Window('window'),
+ rq.Card16('width'),
+ rq.Card16('height'),
+ rq.Pad(20),
+ )
+
+class Circulate(rq.Event):
+ _code = None
+ _fields = rq.Struct( rq.Card8('type'),
+ rq.Pad(1),
+ rq.Card16('sequence_number'),
+ rq.Window('event'),
+ rq.Window('window'),
+ rq.Pad(4),
+ rq.Card8('place'),
+ rq.Pad(15),
+ )
+
+class CirculateNotify(Circulate):
+ _code = X.CirculateNotify
+
+class CirculateRequest(Circulate):
+ _code = X.CirculateRequest
+
+class PropertyNotify(rq.Event):
+ _code = X.PropertyNotify
+ _fields = rq.Struct( rq.Card8('type'),
+ rq.Pad(1),
+ rq.Card16('sequence_number'),
+ rq.Window('window'),
+ rq.Card32('atom'),
+ rq.Card32('time'),
+ rq.Card8('state'),
+ rq.Pad(15),
+ )
+
+class SelectionClear(rq.Event):
+ _code = X.SelectionClear
+ _fields = rq.Struct( rq.Card8('type'),
+ rq.Pad(1),
+ rq.Card16('sequence_number'),
+ rq.Card32('time'),
+ rq.Window('window'),
+ rq.Card32('atom'),
+ rq.Pad(16),
+ )
+
+class SelectionRequest(rq.Event):
+ _code = X.SelectionRequest
+ _fields = rq.Struct( rq.Card8('type'),
+ rq.Pad(1),
+ rq.Card16('sequence_number'),
+ rq.Card32('time'),
+ rq.Window('owner'),
+ rq.Window('requestor'),
+ rq.Card32('selection'),
+ rq.Card32('target'),
+ rq.Card32('property'),
+ rq.Pad(4),
+ )
+
+class SelectionNotify(rq.Event):
+ _code = X.SelectionNotify
+ _fields = rq.Struct( rq.Card8('type'),
+ rq.Pad(1),
+ rq.Card16('sequence_number'),
+ rq.Card32('time'),
+ rq.Window('requestor'),
+ rq.Card32('selection'),
+ rq.Card32('target'),
+ rq.Card32('property'),
+ rq.Pad(8),
+ )
+
+class ColormapNotify(rq.Event):
+ _code = X.ColormapNotify
+ _fields = rq.Struct( rq.Card8('type'),
+ rq.Pad(1),
+ rq.Card16('sequence_number'),
+ rq.Window('window'),
+ rq.Colormap('colormap', (X.NONE, )),
+ rq.Card8('new'),
+ rq.Card8('state'),
+ rq.Pad(18),
+ )
+
+class MappingNotify(rq.Event):
+ _code = X.MappingNotify
+ _fields = rq.Struct( rq.Card8('type'),
+ rq.Pad(1),
+ rq.Card16('sequence_number'),
+ rq.Card8('request'),
+ rq.Card8('first_keycode'),
+ rq.Card8('count'),
+ rq.Pad(25),
+ )
+
+class ClientMessage(rq.Event):
+ _code = X.ClientMessage
+ _fields = rq.Struct( rq.Card8('type'),
+ rq.Format('data', 1),
+ rq.Card16('sequence_number'),
+ rq.Window('window'),
+ rq.Card32('client_type'),
+ rq.FixedPropertyData('data', 20),
+ )
+
+class KeymapNotify(rq.Event):
+ _code = X.KeymapNotify
+ _fields = rq.Struct( rq.Card8('type'),
+ rq.FixedList('data', 31, rq.Card8Obj, pad = 0)
+ )
+
+
+event_class = {
+ X.KeyPress: KeyPress,
+ X.KeyRelease: KeyRelease,
+ X.ButtonPress: ButtonPress,
+ X.ButtonRelease: ButtonRelease,
+ X.MotionNotify: MotionNotify,
+ X.EnterNotify: EnterNotify,
+ X.LeaveNotify: LeaveNotify,
+ X.FocusIn: FocusIn,
+ X.FocusOut: FocusOut,
+ X.KeymapNotify: KeymapNotify,
+ X.Expose: Expose,
+ X.GraphicsExpose: GraphicsExpose,
+ X.NoExpose: NoExpose,
+ X.VisibilityNotify: VisibilityNotify,
+ X.CreateNotify: CreateNotify,
+ X.DestroyNotify: DestroyNotify,
+ X.UnmapNotify: UnmapNotify,
+ X.MapNotify: MapNotify,
+ X.MapRequest: MapRequest,
+ X.ReparentNotify: ReparentNotify,
+ X.ConfigureNotify: ConfigureNotify,
+ X.ConfigureRequest: ConfigureRequest,
+ X.GravityNotify: GravityNotify,
+ X.ResizeRequest: ResizeRequest,
+ X.CirculateNotify: CirculateNotify,
+ X.CirculateRequest: CirculateRequest,
+ X.PropertyNotify: PropertyNotify,
+ X.SelectionClear: SelectionClear,
+ X.SelectionRequest: SelectionRequest,
+ X.SelectionNotify: SelectionNotify,
+ X.ColormapNotify: ColormapNotify,
+ X.ClientMessage: ClientMessage,
+ X.MappingNotify: MappingNotify,
+ }
diff --git a/Xlib/protocol/request.py b/Xlib/protocol/request.py
new file mode 100644
index 0000000..4dc3492
--- /dev/null
+++ b/Xlib/protocol/request.py
@@ -0,0 +1,1898 @@
+# $Id: request.py,v 1.13 2007/06/10 14:11:58 mggrant Exp $
+#
+# Xlib.protocol.request -- definitions of core requests
+#
+# Copyright (C) 2000-2002 Peter Liljenberg <petli@ctrl-c.liu.se>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+# Xlib modules
+from Xlib import X
+
+# Xlib.protocol modules
+import rq
+import structs
+
+
+class CreateWindow(rq.Request):
+ _request = rq.Struct(
+ rq.Opcode(1),
+ rq.Card8('depth'),
+ rq.RequestLength(),
+ rq.Window('wid'),
+ rq.Window('parent'),
+ rq.Int16('x'),
+ rq.Int16('y'),
+ rq.Card16('width'),
+ rq.Card16('height'),
+ rq.Card16('border_width'),
+ rq.Set('window_class', 2, (X.CopyFromParent, X.InputOutput, X.InputOnly)),
+ rq.Card32('visual'),
+ structs.WindowValues('attrs'),
+ )
+
+class ChangeWindowAttributes(rq.Request):
+ _request = rq.Struct(
+ rq.Opcode(2),
+ rq.Pad(1),
+ rq.RequestLength(),
+ rq.Window('window'),
+ structs.WindowValues('attrs'),
+ )
+
+class GetWindowAttributes(rq.ReplyRequest):
+ _request = rq.Struct(
+ rq.Opcode(3),
+ rq.Pad(1),
+ rq.RequestLength(),
+ rq.Window('window')
+ )
+
+ _reply = rq.Struct(
+ rq.ReplyCode(),
+ rq.Card8('backing_store'),
+ rq.Card16('sequence_number'),
+ rq.ReplyLength(),
+ rq.Card32('visual'),
+ rq.Card16('win_class'),
+ rq.Card8('bit_gravity'),
+ rq.Card8('win_gravity'),
+ rq.Card32('backing_bit_planes'),
+ rq.Card32('backing_pixel'),
+ rq.Card8('save_under'),
+ rq.Card8('map_is_installed'),
+ rq.Card8('map_state'),
+ rq.Card8('override_redirect'),
+ rq.Colormap('colormap', (X.NONE, )),
+ rq.Card32('all_event_masks'),
+ rq.Card32('your_event_mask'),
+ rq.Card16('do_not_propagate_mask'),
+ rq.Pad(2),
+ )
+
+class DestroyWindow(rq.Request):
+ _request = rq.Struct(
+ rq.Opcode(4),
+ rq.Pad(1),
+ rq.RequestLength(),
+ rq.Window('window')
+ )
+
+class DestroySubWindows(rq.Request):
+ _request = rq.Struct(
+ rq.Opcode(5),
+ rq.Pad(1),
+ rq.RequestLength(),
+ rq.Window('window')
+ )
+
+class ChangeSaveSet(rq.Request):
+ _request = rq.Struct(
+ rq.Opcode(6),
+ rq.Set('mode', 1, (X.SetModeInsert, X.SetModeDelete)),
+ rq.RequestLength(),
+ rq.Window('window'),
+ )
+
+class ReparentWindow(rq.Request):
+ _request = rq.Struct(
+ rq.Opcode(7),
+ rq.Pad(1),
+ rq.RequestLength(),
+ rq.Window('window'),
+ rq.Window('parent'),
+ rq.Int16('x'),
+ rq.Int16('y'),
+ )
+
+class MapWindow(rq.Request):
+ _request = rq.Struct(
+ rq.Opcode(8),
+ rq.Pad(1),
+ rq.RequestLength(),
+ rq.Window('window')
+ )
+
+class MapSubwindows(rq.Request):
+ _request = rq.Struct(
+ rq.Opcode(9),
+ rq.Pad(1),
+ rq.RequestLength(),
+ rq.Window('window')
+ )
+
+class UnmapWindow(rq.Request):
+ _request = rq.Struct(
+ rq.Opcode(10),
+ rq.Pad(1),
+ rq.RequestLength(),
+ rq.Window('window')
+ )
+
+class UnmapSubwindows(rq.Request):
+ _request = rq.Struct(
+ rq.Opcode(11),
+ rq.Pad(1),
+ rq.RequestLength(),
+ rq.Window('window')
+ )
+
+class ConfigureWindow(rq.Request):
+ _request = rq.Struct(
+ rq.Opcode(12),
+ rq.Pad(1),
+ rq.RequestLength(),
+ rq.Window('window'),
+ rq.ValueList( 'attrs', 2, 2,
+ rq.Int16('x'),
+ rq.Int16('y'),
+ rq.Card16('width'),
+ rq.Card16('height'),
+ rq.Int16('border_width'),
+ rq.Window('sibling'),
+ rq.Set('stack_mode', 1,
+ (X.Above, X.Below, X.TopIf,
+ X.BottomIf, X.Opposite))
+ )
+ )
+
+class CirculateWindow(rq.Request):
+ _request = rq.Struct(
+ rq.Opcode(13),
+ rq.Set('direction', 1, (X.RaiseLowest, X.LowerHighest)),
+ rq.RequestLength(),
+ rq.Window('window'),
+ )
+
+class GetGeometry(rq.ReplyRequest):
+ _request = rq.Struct(
+ rq.Opcode(14),
+ rq.Pad(1),
+ rq.RequestLength(),
+ rq.Drawable('drawable')
+ )
+
+ _reply = rq.Struct (
+ rq.ReplyCode(),
+ rq.Card8('depth'),
+ rq.Card16('sequence_number'),
+ rq.ReplyLength(),
+ rq.Window('root'),
+ rq.Int16('x'),
+ rq.Int16('y'),
+ rq.Card16('width'),
+ rq.Card16('height'),
+ rq.Card16('border_width'),
+ rq.Pad(10)
+ )
+
+class QueryTree(rq.ReplyRequest):
+ _request = rq.Struct(
+ rq.Opcode(15),
+ rq.Pad(1),
+ rq.RequestLength(),
+ rq.Window('window')
+ )
+
+ _reply = rq.Struct(
+ rq.ReplyCode(),
+ rq.Pad(1),
+ rq.Card16('sequence_number'),
+ rq.ReplyLength(),
+ rq.Window('root'),
+ rq.Window('parent', (X.NONE, )),
+ rq.LengthOf('children', 2),
+ rq.Pad(14),
+ rq.List('children', rq.WindowObj),
+ )
+
+class InternAtom(rq.ReplyRequest):
+ _request = rq.Struct(
+ rq.Opcode(16),
+ rq.Bool('only_if_exists'),
+ rq.RequestLength(),
+ rq.LengthOf('name', 2),
+ rq.Pad(2),
+ rq.String8('name'),
+ )
+
+ _reply = rq.Struct(
+ rq.ReplyCode(),
+ rq.Pad(1),
+ rq.Card16('sequence_number'),
+ rq.ReplyLength(),
+ rq.Card32('atom'),
+ rq.Pad(20),
+ )
+
+
+class GetAtomName(rq.ReplyRequest):
+ _request = rq.Struct(
+ rq.Opcode(17),
+ rq.Pad(1),
+ rq.RequestLength(),
+ rq.Card32('atom')
+ )
+
+ _reply = rq.Struct(
+ rq.ReplyCode(),
+ rq.Pad(1),
+ rq.Card16('sequence_number'),
+ rq.ReplyLength(),
+ rq.LengthOf('name', 2),
+ rq.Pad(22),
+ rq.String8('name'),
+ )
+
+class ChangeProperty(rq.Request):
+ _request = rq.Struct(
+ rq.Opcode(18),
+ rq.Set('mode', 1, (X.PropModeReplace, X.PropModePrepend, X.PropModeAppend)),
+ rq.RequestLength(),
+ rq.Window('window'),
+ rq.Card32('property'),
+ rq.Card32('type'),
+ rq.Format('data', 1),
+ rq.Pad(3),
+ rq.LengthOf('data', 4),
+ rq.PropertyData('data'),
+ )
+
+class DeleteProperty(rq.Request):
+ _request = rq.Struct(
+ rq.Opcode(19),
+ rq.Pad(1),
+ rq.RequestLength(),
+ rq.Window('window'),
+ rq.Card32('property'),
+ )
+
+class GetProperty(rq.ReplyRequest):
+ _request = rq.Struct(
+ rq.Opcode(20),
+ rq.Bool('delete'),
+ rq.RequestLength(),
+ rq.Window('window'),
+ rq.Card32('property'),
+ rq.Card32('type'),
+ rq.Card32('long_offset'),
+ rq.Card32('long_length'),
+ )
+
+ _reply = rq.Struct(
+ rq.ReplyCode(),
+ rq.Format('value', 1),
+ rq.Card16('sequence_number'),
+ rq.ReplyLength(),
+ rq.Card32('property_type'),
+ rq.Card32('bytes_after'),
+ rq.LengthOf('value', 4),
+ rq.Pad(12),
+ rq.PropertyData('value'),
+ )
+
+class ListProperties(rq.ReplyRequest):
+ _request = rq.Struct(
+ rq.Opcode(21),
+ rq.Pad(1),
+ rq.RequestLength(),
+ rq.Window('window')
+ )
+
+ _reply = rq.Struct(
+ rq.ReplyCode(),
+ rq.Pad(1),
+ rq.Card16('sequence_number'),
+ rq.ReplyLength(),
+ rq.LengthOf('atoms', 2),
+ rq.Pad(22),
+ rq.List('atoms', rq.Card32Obj),
+ )
+
+class SetSelectionOwner(rq.Request):
+ _request = rq.Struct(
+ rq.Opcode(22),
+ rq.Pad(1),
+ rq.RequestLength(),
+ rq.Window('window'),
+ rq.Card32('selection'),
+ rq.Card32('time'),
+ )
+
+class GetSelectionOwner(rq.ReplyRequest):
+ _request = rq.Struct(
+ rq.Opcode(23),
+ rq.Pad(1),
+ rq.RequestLength(),
+ rq.Card32('selection')
+ )
+
+ _reply = rq.Struct(
+ rq.ReplyCode(),
+ rq.Pad(1),
+ rq.Card16('sequence_number'),
+ rq.ReplyLength(),
+ rq.Window('owner', (X.NONE, )),
+ rq.Pad(20),
+ )
+
+class ConvertSelection(rq.Request):
+ _request = rq.Struct(
+ rq.Opcode(24),
+ rq.Pad(1),
+ rq.RequestLength(),
+ rq.Window('requestor'),
+ rq.Card32('selection'),
+ rq.Card32('target'),
+ rq.Card32('property'),
+ rq.Card32('time'),
+ )
+
+class SendEvent(rq.Request):
+ _request = rq.Struct(
+ rq.Opcode(25),
+ rq.Bool('propagate'),
+ rq.RequestLength(),
+ rq.Window('destination'),
+ rq.Card32('event_mask'),
+ rq.EventField('event'),
+ )
+
+class GrabPointer(rq.ReplyRequest):
+ _request = rq.Struct(
+ rq.Opcode(26),
+ rq.Bool('owner_events'),
+ rq.RequestLength(),
+ rq.Window('grab_window'),
+ rq.Card16('event_mask'),
+ rq.Set('pointer_mode', 1, (X.GrabModeSync, X.GrabModeAsync)),
+ rq.Set('keyboard_mode', 1, (X.GrabModeSync, X.GrabModeAsync)),
+ rq.Window('confine_to', (X.NONE, )),
+ rq.Cursor('cursor', (X.NONE, )),
+ rq.Card32('time'),
+ )
+
+ _reply = rq.Struct(
+ rq.ReplyCode(),
+ rq.Card8('status'),
+ rq.Card16('sequence_number'),
+ rq.ReplyLength(),
+ rq.Pad(24),
+ )
+
+class UngrabPointer(rq.Request):
+ _request = rq.Struct(
+ rq.Opcode(27),
+ rq.Pad(1),
+ rq.RequestLength(),
+ rq.Card32('time')
+ )
+
+class GrabButton(rq.Request):
+ _request = rq.Struct(
+ rq.Opcode(28),
+ rq.Bool('owner_events'),
+ rq.RequestLength(),
+ rq.Window('grab_window'),
+ rq.Card16('event_mask'),
+ rq.Set('pointer_mode', 1, (X.GrabModeSync, X.GrabModeAsync)),
+ rq.Set('keyboard_mode', 1, (X.GrabModeSync, X.GrabModeAsync)),
+ rq.Window('confine_to', (X.NONE, )),
+ rq.Cursor('cursor', (X.NONE, )),
+ rq.Card8('button'),
+ rq.Pad(1),
+ rq.Card16('modifiers'),
+ )
+
+class UngrabButton(rq.Request):
+ _request = rq.Struct(
+ rq.Opcode(29),
+ rq.Card8('button'),
+ rq.RequestLength(),
+ rq.Window('grab_window'),
+ rq.Card16('modifiers'),
+ rq.Pad(2),
+ )
+
+class ChangeActivePointerGrab(rq.Request):
+ _request = rq.Struct(
+ rq.Opcode(30),
+ rq.Pad(1),
+ rq.RequestLength(),
+ rq.Cursor('cursor'),
+ rq.Card32('time'),
+ rq.Card16('event_mask'),
+ rq.Pad(2),
+ )
+
+class GrabKeyboard(rq.ReplyRequest):
+ _request = rq.Struct(
+ rq.Opcode(31),
+ rq.Bool('owner_events'),
+ rq.RequestLength(),
+ rq.Window('grab_window'),
+ rq.Card32('time'),
+ rq.Set('pointer_mode', 1, (X.GrabModeSync, X.GrabModeAsync)),
+ rq.Set('keyboard_mode', 1, (X.GrabModeSync, X.GrabModeAsync)),
+ rq.Pad(2),
+ )
+
+ _reply = rq.Struct(
+ rq.ReplyCode(),
+ rq.Card8('status'),
+ rq.Card16('sequence_number'),
+ rq.ReplyLength(),
+ rq.Pad(24),
+ )
+
+class UngrabKeyboard(rq.Request):
+ _request = rq.Struct(
+ rq.Opcode(32),
+ rq.Pad(1),
+ rq.RequestLength(),
+ rq.Card32('time')
+ )
+
+class GrabKey(rq.Request):
+ _request = rq.Struct(
+ rq.Opcode(33),
+ rq.Bool('owner_events'),
+ rq.RequestLength(),
+ rq.Window('grab_window'),
+ rq.Card16('modifiers'),
+ rq.Card8('key'),
+ rq.Set('pointer_mode', 1, (X.GrabModeSync, X.GrabModeAsync)),
+ rq.Set('keyboard_mode', 1, (X.GrabModeSync, X.GrabModeAsync)),
+ rq.Pad(3),
+ )
+
+class UngrabKey(rq.Request):
+ _request = rq.Struct(
+ rq.Opcode(34),
+ rq.Card8('key'),
+ rq.RequestLength(),
+ rq.Window('grab_window'),
+ rq.Card16('modifiers'),
+ rq.Pad(2),
+ )
+
+class AllowEvents(rq.Request):
+ _request = rq.Struct(
+ rq.Opcode(35),
+ rq.Set('mode', 1, (X.AsyncPointer,
+ X.SyncPointer,
+ X.ReplayPointer,
+ X.AsyncKeyboard,
+ X.SyncKeyboard,
+ X.ReplayKeyboard,
+ X.AsyncBoth,
+ X.SyncBoth)),
+ rq.RequestLength(),
+ rq.Card32('time'),
+ )
+
+class GrabServer(rq.Request):
+ _request = rq.Struct(
+ rq.Opcode(36),
+ rq.Pad(1),
+ rq.RequestLength(),
+ )
+
+class UngrabServer(rq.Request):
+ _request = rq.Struct(
+ rq.Opcode(37),
+ rq.Pad(1),
+ rq.RequestLength(),
+ )
+
+class QueryPointer(rq.ReplyRequest):
+ _request = rq.Struct(
+ rq.Opcode(38),
+ rq.Pad(1),
+ rq.RequestLength(),
+ rq.Window('window')
+ )
+
+ _reply = rq.Struct(
+ rq.ReplyCode(),
+ rq.Card8('same_screen'),
+ rq.Card16('sequence_number'),
+ rq.ReplyLength(),
+ rq.Window('root'),
+ rq.Window('child', (X.NONE, )),
+ rq.Int16('root_x'),
+ rq.Int16('root_y'),
+ rq.Int16('win_x'),
+ rq.Int16('win_y'),
+ rq.Card16('mask'),
+ rq.Pad(6),
+ )
+
+class GetMotionEvents(rq.ReplyRequest):
+ _request = rq.Struct(
+ rq.Opcode(39),
+ rq.Pad(1),
+ rq.RequestLength(),
+ rq.Window('window'),
+ rq.Card32('start'),
+ rq.Card32('stop'),
+ )
+
+ _reply = rq.Struct(
+ rq.ReplyCode(),
+ rq.Pad(1),
+ rq.Card16('sequence_number'),
+ rq.ReplyLength(),
+ rq.LengthOf('events', 4),
+ rq.Pad(20),
+ rq.List('events', structs.TimeCoord),
+ )
+
+class TranslateCoords(rq.ReplyRequest):
+ _request = rq.Struct(
+ rq.Opcode(40),
+ rq.Pad(1),
+ rq.RequestLength(),
+ rq.Window('src_wid'),
+ rq.Window('dst_wid'),
+ rq.Int16('src_x'),
+ rq.Int16('src_y'),
+ )
+
+ _reply = rq.Struct(
+ rq.ReplyCode(),
+ rq.Card8('same_screen'),
+ rq.Card16('sequence_number'),
+ rq.ReplyLength(),
+ rq.Window('child', (X.NONE, )),
+ rq.Int16('x'),
+ rq.Int16('y'),
+ rq.Pad(16),
+ )
+
+class WarpPointer(rq.Request):
+ _request = rq.Struct(
+ rq.Opcode(41),
+ rq.Pad(1),
+ rq.RequestLength(),
+ rq.Window('src_window'),
+ rq.Window('dst_window'),
+ rq.Int16('src_x'),
+ rq.Int16('src_y'),
+ rq.Card16('src_width'),
+ rq.Card16('src_height'),
+ rq.Int16('dst_x'),
+ rq.Int16('dst_y'),
+ )
+
+class SetInputFocus(rq.Request):
+ _request = rq.Struct(
+ rq.Opcode(42),
+ rq.Set('revert_to', 1, (X.RevertToNone, X.RevertToPointerRoot,
+ X.RevertToParent)),
+ rq.RequestLength(),
+ rq.Window('focus'),
+ rq.Card32('time'),
+ )
+
+class GetInputFocus(rq.ReplyRequest):
+ _request = rq.Struct(
+ rq.Opcode(43),
+ rq.Pad(1),
+ rq.RequestLength(),
+ )
+
+ _reply = rq.Struct(
+ rq.ReplyCode(),
+ rq.Card8('revert_to'),
+ rq.Card16('sequence_number'),
+ rq.ReplyLength(),
+ rq.Window('focus', (X.NONE, X.PointerRoot)),
+ rq.Pad(20),
+ )
+
+class QueryKeymap(rq.ReplyRequest):
+ _request = rq.Struct(
+ rq.Opcode(44),
+ rq.Pad(1),
+ rq.RequestLength(),
+ )
+
+ _reply = rq.Struct(
+ rq.ReplyCode(),
+ rq.Pad(1),
+ rq.Card16('sequence_number'),
+ rq.ReplyLength(),
+ rq.FixedList('map', 32, rq.Card8Obj),
+ )
+
+
+class OpenFont(rq.Request):
+ _request = rq.Struct(
+ rq.Opcode(45),
+ rq.Pad(1),
+ rq.RequestLength(),
+ rq.Font('fid'),
+ rq.LengthOf('name', 2),
+ rq.Pad(2),
+ rq.String8('name'),
+ )
+
+class CloseFont(rq.Request):
+ _request = rq.Struct(
+ rq.Opcode(46),
+ rq.Pad(1),
+ rq.RequestLength(),
+ rq.Font('font')
+ )
+
+class QueryFont(rq.ReplyRequest):
+ _request = rq.Struct(
+ rq.Opcode(47),
+ rq.Pad(1),
+ rq.RequestLength(),
+ rq.Fontable('font')
+ )
+
+ _reply = rq.Struct(
+ rq.ReplyCode(),
+ rq.Pad(1),
+ rq.Card16('sequence_number'),
+ rq.ReplyLength(),
+ rq.Object('min_bounds', structs.CharInfo),
+ rq.Pad(4),
+ rq.Object('max_bounds', structs.CharInfo),
+ rq.Pad(4),
+ rq.Card16('min_char_or_byte2'),
+ rq.Card16('max_char_or_byte2'),
+ rq.Card16('default_char'),
+ rq.LengthOf('properties', 2),
+ rq.Card8('draw_direction'),
+ rq.Card8('min_byte1'),
+ rq.Card8('max_byte1'),
+ rq.Card8('all_chars_exist'),
+ rq.Int16('font_ascent'),
+ rq.Int16('font_descent'),
+ rq.LengthOf('char_infos', 4),
+ rq.List('properties', structs.FontProp),
+ rq.List('char_infos', structs.CharInfo),
+ )
+
+class QueryTextExtents(rq.ReplyRequest):
+ _request = rq.Struct(
+ rq.Opcode(48),
+ rq.OddLength('string'),
+ rq.RequestLength(),
+ rq.Fontable('font'),
+ rq.String16('string'),
+ )
+
+ _reply = rq.Struct(
+ rq.ReplyCode(),
+ rq.Card8('draw_direction'),
+ rq.Card16('sequence_number'),
+ rq.ReplyLength(),
+ rq.Int16('font_ascent'),
+ rq.Int16('font_descent'),
+ rq.Int16('overall_ascent'),
+ rq.Int16('overall_descent'),
+ rq.Int32('overall_width'),
+ rq.Int32('overall_left'),
+ rq.Int32('overall_right'),
+ rq.Pad(4),
+ )
+
+class ListFonts(rq.ReplyRequest):
+ _request = rq.Struct(
+ rq.Opcode(49),
+ rq.Pad(1),
+ rq.RequestLength(),
+ rq.Card16('max_names'),
+ rq.LengthOf('pattern', 2),
+ rq.String8('pattern'),
+ )
+
+ _reply = rq.Struct(
+ rq.ReplyCode(),
+ rq.Pad(1),
+ rq.Card16('sequence_number'),
+ rq.ReplyLength(),
+ rq.LengthOf('fonts', 2),
+ rq.Pad(22),
+ rq.List('fonts', rq.Str),
+ )
+
+
+class ListFontsWithInfo(rq.ReplyRequest):
+ _request = rq.Struct(
+ rq.Opcode(50),
+ rq.Pad(1),
+ rq.RequestLength(),
+ rq.Card16('max_names'),
+ rq.LengthOf('pattern', 2),
+ rq.String8('pattern'),
+ )
+
+ _reply = rq.Struct(
+ rq.ReplyCode(),
+ rq.LengthOf('name', 1),
+ rq.Card16('sequence_number'),
+ rq.ReplyLength(),
+ rq.Object('min_bounds', structs.CharInfo),
+ rq.Pad(4),
+ rq.Object('max_bounds', structs.CharInfo),
+ rq.Pad(4),
+ rq.Card16('min_char_or_byte2'),
+ rq.Card16('max_char_or_byte2'),
+ rq.Card16('default_char'),
+ rq.LengthOf('properties', 2),
+ rq.Card8('draw_direction'),
+ rq.Card8('min_byte1'),
+ rq.Card8('max_byte1'),
+ rq.Card8('all_chars_exist'),
+ rq.Int16('font_ascent'),
+ rq.Int16('font_descent'),
+ rq.Card32('replies_hint'),
+ rq.List('properties', structs.FontProp),
+ rq.String8('name'),
+ )
+
+
+ # Somebody must have smoked some really wicked weed when they
+ # defined the ListFontsWithInfo request:
+ # The server sends a reply for _each_ matching font...
+ # It then sends a special reply (name length == 0) to indicate
+ # that there are no more fonts in the reply.
+
+ # This means that we have to do some special parsing to see if
+ # we have got the end-of-reply reply. If we haven't, we
+ # have to reinsert the request in the front of the
+ # display.sent_request queue to catch the next response.
+
+ # Bastards.
+
+ def __init__(self, *args, **keys):
+ self._fonts = []
+ apply(ReplyRequest.__init__, (self, ) + args, keys)
+
+ def _parse_response(self, data):
+
+ if ord(data[1]) == 0:
+ self._response_lock.acquire()
+ self._data = self._fonts
+ del self._fonts
+ self._response_lock.release()
+ return
+
+ r, d = self._reply.parse_binary(data)
+ self._fonts.append(r)
+
+ self._display.sent_requests.insert(0, self)
+
+
+ # Override the default __getattr__, since it isn't usable for
+ # the list reply. Instead provide a __getitem__ and a __len__.
+
+ def __getattr__(self, attr):
+ raise AttributeError(attr)
+
+ def __getitem__(self, item):
+ return self._data[item]
+
+ def __len__(self):
+ return len(self._data)
+
+
+class SetFontPath(rq.Request):
+ _request = rq.Struct(
+ rq.Opcode(51),
+ rq.Pad(1),
+ rq.RequestLength(),
+ rq.LengthOf('path', 2),
+ rq.Pad(2),
+ rq.List('path', rq.Str),
+ )
+
+class GetFontPath(rq.ReplyRequest):
+ _request = rq.Struct(
+ rq.Opcode(52),
+ rq.Pad(1),
+ rq.RequestLength(),
+ )
+
+ _reply = rq.Struct(
+ rq.ReplyCode(),
+ rq.Pad(1),
+ rq.Card16('sequence_number'),
+ rq.ReplyLength(),
+ rq.LengthOf('paths', 2),
+ rq.Pad(22),
+ rq.List('paths', rq.Str),
+ )
+
+class CreatePixmap(rq.Request):
+ _request = rq.Struct(
+ rq.Opcode(53),
+ rq.Card8('depth'),
+ rq.RequestLength(),
+ rq.Pixmap('pid'),
+ rq.Drawable('drawable'),
+ rq.Card16('width'),
+ rq.Card16('height'),
+ )
+
+class FreePixmap(rq.Request):
+ _request = rq.Struct(
+ rq.Opcode(54),
+ rq.Pad(1),
+ rq.RequestLength(),
+ rq.Pixmap('pixmap')
+ )
+
+class CreateGC(rq.Request):
+ _request = rq.Struct(
+ rq.Opcode(55),
+ rq.Pad(1),
+ rq.RequestLength(),
+ rq.GC('cid'),
+ rq.Drawable('drawable'),
+ structs.GCValues('attrs'),
+ )
+
+class ChangeGC(rq.Request):
+ _request = rq.Struct(
+ rq.Opcode(56),
+ rq.Pad(1),
+ rq.RequestLength(),
+ rq.GC('gc'),
+ structs.GCValues('attrs'),
+ )
+
+class CopyGC(rq.Request):
+ _request = rq.Struct(
+ rq.Opcode(57),
+ rq.Pad(1),
+ rq.RequestLength(),
+ rq.GC('src_gc'),
+ rq.GC('dst_gc'),
+ rq.Card32('mask'),
+ )
+
+class SetDashes(rq.Request):
+ _request = rq.Struct(
+ rq.Opcode(58),
+ rq.Pad(1),
+ rq.RequestLength(),
+ rq.GC('gc'),
+ rq.Card16('dash_offset'),
+ rq.LengthOf('dashes', 2),
+ rq.List('dashes', rq.Card8Obj),
+ )
+
+class SetClipRectangles(rq.Request):
+ _request = rq.Struct(
+ rq.Opcode(59),
+ rq.Set('ordering', 1, (X.Unsorted, X.YSorted, X.YXSorted, X.YXBanded)),
+ rq.RequestLength(),
+ rq.GC('gc'),
+ rq.Int16('x_origin'),
+ rq.Int16('y_origin'),
+ rq.List('rectangles', structs.Rectangle),
+ )
+
+class FreeGC(rq.Request):
+ _request = rq.Struct(
+ rq.Opcode(60),
+ rq.Pad(1),
+ rq.RequestLength(),
+ rq.GC('gc')
+ )
+
+class ClearArea(rq.Request):
+ _request = rq.Struct(
+ rq.Opcode(61),
+ rq.Bool('exposures'),
+ rq.RequestLength(),
+ rq.Window('window'),
+ rq.Int16('x'),
+ rq.Int16('y'),
+ rq.Card16('width'),
+ rq.Card16('height'),
+ )
+
+class CopyArea(rq.Request):
+ _request = rq.Struct(
+ rq.Opcode(62),
+ rq.Pad(1),
+ rq.RequestLength(),
+ rq.Drawable('src_drawable'),
+ rq.Drawable('dst_drawable'),
+ rq.GC('gc'),
+ rq.Int16('src_x'),
+ rq.Int16('src_y'),
+ rq.Int16('dst_x'),
+ rq.Int16('dst_y'),
+ rq.Card16('width'),
+ rq.Card16('height'),
+ )
+
+class CopyPlane(rq.Request):
+ _request = rq.Struct(
+ rq.Opcode(63),
+ rq.Pad(1),
+ rq.RequestLength(),
+ rq.Drawable('src_drawable'),
+ rq.Drawable('dst_drawable'),
+ rq.GC('gc'),
+ rq.Int16('src_x'),
+ rq.Int16('src_y'),
+ rq.Int16('dst_x'),
+ rq.Int16('dst_y'),
+ rq.Card16('width'),
+ rq.Card16('height'),
+ rq.Card32('bit_plane'),
+ )
+
+class PolyPoint(rq.Request):
+ _request = rq.Struct(
+ rq.Opcode(64),
+ rq.Set('coord_mode', 1, (X.CoordModeOrigin, X.CoordModePrevious)),
+ rq.RequestLength(),
+ rq.Drawable('drawable'),
+ rq.GC('gc'),
+ rq.List('points', structs.Point),
+ )
+
+class PolyLine(rq.Request):
+ _request = rq.Struct(
+ rq.Opcode(65),
+ rq.Set('coord_mode', 1, (X.CoordModeOrigin, X.CoordModePrevious)),
+ rq.RequestLength(),
+ rq.Drawable('drawable'),
+ rq.GC('gc'),
+ rq.List('points', structs.Point),
+ )
+
+
+class PolySegment(rq.Request):
+ _request = rq.Struct(
+ rq.Opcode(66),
+ rq.Pad(1),
+ rq.RequestLength(),
+ rq.Drawable('drawable'),
+ rq.GC('gc'),
+ rq.List('segments', structs.Segment),
+ )
+
+
+class PolyRectangle(rq.Request):
+ _request = rq.Struct(
+ rq.Opcode(67),
+ rq.Pad(1),
+ rq.RequestLength(),
+ rq.Drawable('drawable'),
+ rq.GC('gc'),
+ rq.List('rectangles', structs.Rectangle),
+ )
+
+class PolyArc(rq.Request):
+ _request = rq.Struct(
+ rq.Opcode(68),
+ rq.Pad(1),
+ rq.RequestLength(),
+ rq.Drawable('drawable'),
+ rq.GC('gc'),
+ rq.List('arcs', structs.Arc),
+ )
+
+class FillPoly(rq.Request):
+ _request = rq.Struct(
+ rq.Opcode(69),
+ rq.Pad(1),
+ rq.RequestLength(),
+ rq.Drawable('drawable'),
+ rq.GC('gc'),
+ rq.Set('shape', 1, (X.Complex, X.Nonconvex, X.Convex)),
+ rq.Set('coord_mode', 1, (X.CoordModeOrigin, X.CoordModePrevious)),
+ rq.Pad(2),
+ rq.List('points', structs.Point),
+ )
+
+class PolyFillRectangle(rq.Request):
+ _request = rq.Struct(
+ rq.Opcode(70),
+ rq.Pad(1),
+ rq.RequestLength(),
+ rq.Drawable('drawable'),
+ rq.GC('gc'),
+ rq.List('rectangles', structs.Rectangle),
+ )
+
+class PolyFillArc(rq.Request):
+ _request = rq.Struct(
+ rq.Opcode(71),
+ rq.Pad(1),
+ rq.RequestLength(),
+ rq.Drawable('drawable'),
+ rq.GC('gc'),
+ rq.List('arcs', structs.Arc),
+ )
+
+class PutImage(rq.Request):
+ _request = rq.Struct(
+ rq.Opcode(72),
+ rq.Set('format', 1, (X.XYBitmap, X.XYPixmap, X.ZPixmap)),
+ rq.RequestLength(),
+ rq.Drawable('drawable'),
+ rq.GC('gc'),
+ rq.Card16('width'),
+ rq.Card16('height'),
+ rq.Int16('dst_x'),
+ rq.Int16('dst_y'),
+ rq.Card8('left_pad'),
+ rq.Card8('depth'),
+ rq.Pad(2),
+ rq.String8('data'),
+ )
+
+class GetImage(rq.ReplyRequest):
+ _request = rq.Struct(
+ rq.Opcode(73),
+ rq.Set('format', 1, (X.XYPixmap, X.ZPixmap)),
+ rq.RequestLength(),
+ rq.Drawable('drawable'),
+ rq.Int16('x'),
+ rq.Int16('y'),
+ rq.Card16('width'),
+ rq.Card16('height'),
+ rq.Card32('plane_mask'),
+ )
+
+ _reply = rq.Struct(
+ rq.ReplyCode(),
+ rq.Card8('depth'),
+ rq.Card16('sequence_number'),
+ rq.ReplyLength(),
+ rq.Card32('visual'),
+ rq.Pad(20),
+ rq.String8('data'),
+ )
+
+class PolyText8(rq.Request):
+ _request = rq.Struct(
+ rq.Opcode(74),
+ rq.Pad(1),
+ rq.RequestLength(),
+ rq.Drawable('drawable'),
+ rq.GC('gc'),
+ rq.Int16('x'),
+ rq.Int16('y'),
+ rq.TextElements8('items'),
+ )
+
+class PolyText16(rq.Request):
+ _request = rq.Struct(
+ rq.Opcode(75),
+ rq.Pad(1),
+ rq.RequestLength(),
+ rq.Drawable('drawable'),
+ rq.GC('gc'),
+ rq.Int16('x'),
+ rq.Int16('y'),
+ rq.TextElements16('items'),
+ )
+
+class ImageText8(rq.Request):
+ _request = rq.Struct(
+ rq.Opcode(76),
+ rq.LengthOf('string', 1),
+ rq.RequestLength(),
+ rq.Drawable('drawable'),
+ rq.GC('gc'),
+ rq.Int16('x'),
+ rq.Int16('y'),
+ rq.String8('string'),
+ )
+
+class ImageText16(rq.Request):
+ _request = rq.Struct(
+ rq.Opcode(77),
+ rq.LengthOf('string', 1),
+ rq.RequestLength(),
+ rq.Drawable('drawable'),
+ rq.GC('gc'),
+ rq.Int16('x'),
+ rq.Int16('y'),
+ rq.String16('string'),
+ )
+
+class CreateColormap(rq.Request):
+ _request = rq.Struct(
+ rq.Opcode(78),
+ rq.Set('alloc', 1, (X.AllocNone, X.AllocAll)),
+ rq.RequestLength(),
+ rq.Colormap('mid'),
+ rq.Window('window'),
+ rq.Card32('visual'),
+ )
+
+class FreeColormap(rq.Request):
+ _request = rq.Struct(
+ rq.Opcode(79),
+ rq.Pad(1),
+ rq.RequestLength(),
+ rq.Colormap('cmap')
+ )
+
+class CopyColormapAndFree(rq.Request):
+ _request = rq.Struct(
+ rq.Opcode(80),
+ rq.Pad(1),
+ rq.RequestLength(),
+ rq.Colormap('mid'),
+ rq.Colormap('src_cmap'),
+ )
+
+class InstallColormap(rq.Request):
+ _request = rq.Struct(
+ rq.Opcode(81),
+ rq.Pad(1),
+ rq.RequestLength(),
+ rq.Colormap('cmap')
+ )
+
+class UninstallColormap(rq.Request):
+ _request = rq.Struct(
+ rq.Opcode(82),
+ rq.Pad(1),
+ rq.RequestLength(),
+ rq.Colormap('cmap')
+ )
+
+class ListInstalledColormaps(rq.ReplyRequest):
+ _request = rq.Struct(
+ rq.Opcode(83),
+ rq.Pad(1),
+ rq.RequestLength(),
+ rq.Window('window')
+ )
+
+ _reply = rq.Struct(
+ rq.ReplyCode(),
+ rq.Pad(1),
+ rq.Card16('sequence_number'),
+ rq.ReplyLength(),
+ rq.LengthOf('cmaps', 2),
+ rq.Pad(22),
+ rq.List('cmaps', rq.ColormapObj),
+ )
+
+class AllocColor(rq.ReplyRequest):
+ _request = rq.Struct(
+ rq.Opcode(84),
+ rq.Pad(1),
+ rq.RequestLength(),
+ rq.Colormap('cmap'),
+ rq.Card16('red'),
+ rq.Card16('green'),
+ rq.Card16('blue'),
+ rq.Pad(2),
+ )
+
+ _reply = rq.Struct(
+ rq.ReplyCode(),
+ rq.Pad(1),
+ rq.Card16('sequence_number'),
+ rq.ReplyLength(),
+ rq.Card16('red'),
+ rq.Card16('green'),
+ rq.Card16('blue'),
+ rq.Pad(2),
+ rq.Card32('pixel'),
+ rq.Pad(12),
+ )
+
+class AllocNamedColor(rq.ReplyRequest):
+ _request = rq.Struct(
+ rq.Opcode(85),
+ rq.Pad(1),
+ rq.RequestLength(),
+ rq.Colormap('cmap'),
+ rq.LengthOf('name', 2),
+ rq.Pad(2),
+ rq.String8('name'),
+ )
+
+ _reply = rq.Struct(
+ rq.ReplyCode(),
+ rq.Pad(1),
+ rq.Card16('sequence_number'),
+ rq.ReplyLength(),
+ rq.Card32('pixel'),
+ rq.Card16('exact_red'),
+ rq.Card16('exact_green'),
+ rq.Card16('exact_blue'),
+ rq.Card16('screen_red'),
+ rq.Card16('screen_green'),
+ rq.Card16('screen_blue'),
+ rq.Pad(8),
+ )
+
+class AllocColorCells(rq.ReplyRequest):
+ _request = rq.Struct(
+ rq.Opcode(86),
+ rq.Bool('contiguous'),
+ rq.RequestLength(),
+ rq.Colormap('cmap'),
+ rq.Card16('colors'),
+ rq.Card16('planes'),
+ )
+
+ _reply = rq.Struct(
+ rq.ReplyCode(),
+ rq.Pad(1),
+ rq.Card16('sequence_number'),
+ rq.ReplyLength(),
+ rq.LengthOf('pixels', 2),
+ rq.LengthOf('masks', 2),
+ rq.Pad(20),
+ rq.List('pixels', rq.Card32Obj),
+ rq.List('masks', rq.Card32Obj),
+ )
+
+class AllocColorPlanes(rq.ReplyRequest):
+ _request = rq.Struct(
+ rq.Opcode(87),
+ rq.Bool('contiguous'),
+ rq.RequestLength(),
+ rq.Colormap('cmap'),
+ rq.Card16('colors'),
+ rq.Card16('red'),
+ rq.Card16('green'),
+ rq.Card16('blue'),
+ )
+
+ _reply = rq.Struct(
+ rq.ReplyCode(),
+ rq.Pad(1),
+ rq.Card16('sequence_number'),
+ rq.ReplyLength(),
+ rq.LengthOf('pixels', 2),
+ rq.Pad(2),
+ rq.Card32('red_mask'),
+ rq.Card32('green_mask'),
+ rq.Card32('blue_mask'),
+ rq.Pad(8),
+ rq.List('pixels', rq.Card32Obj),
+ )
+
+class FreeColors(rq.Request):
+ _request = rq.Struct(
+ rq.Opcode(88),
+ rq.Pad(1),
+ rq.RequestLength(),
+ rq.Colormap('cmap'),
+ rq.Card32('plane_mask'),
+ rq.List('pixels', rq.Card32Obj),
+ )
+
+class StoreColors(rq.Request):
+ _request = rq.Struct(
+ rq.Opcode(89),
+ rq.Pad(1),
+ rq.RequestLength(),
+ rq.Colormap('cmap'),
+ rq.List('items', structs.ColorItem),
+ )
+
+class StoreNamedColor(rq.Request):
+ _request = rq.Struct(
+ rq.Opcode(90),
+ rq.Card8('flags'),
+ rq.RequestLength(),
+ rq.Colormap('cmap'),
+ rq.Card32('pixel'),
+ rq.LengthOf('name', 2),
+ rq.Pad(2),
+ rq.String8('name'),
+ )
+
+class QueryColors(rq.ReplyRequest):
+ _request = rq.Struct(
+ rq.Opcode(91),
+ rq.Pad(1),
+ rq.RequestLength(),
+ rq.Colormap('cmap'),
+ rq.List('pixels', rq.Card32Obj),
+ )
+
+ _reply = rq.Struct(
+ rq.ReplyCode(),
+ rq.Pad(1),
+ rq.Card16('sequence_number'),
+ rq.ReplyLength(),
+ rq.LengthOf('colors', 2),
+ rq.Pad(22),
+ rq.List('colors', structs.RGB),
+ )
+
+class LookupColor(rq.ReplyRequest):
+ _request = rq.Struct(
+ rq.Opcode(92),
+ rq.Pad(1),
+ rq.RequestLength(),
+ rq.Colormap('cmap'),
+ rq.LengthOf('name', 2),
+ rq.Pad(2),
+ rq.String8('name'),
+ )
+
+ _reply = rq.Struct(
+ rq.ReplyCode(),
+ rq.Pad(1),
+ rq.Card16('sequence_number'),
+ rq.ReplyLength(),
+ rq.Card16('exact_red'),
+ rq.Card16('exact_green'),
+ rq.Card16('exact_blue'),
+ rq.Card16('screen_red'),
+ rq.Card16('screen_green'),
+ rq.Card16('screen_blue'),
+ rq.Pad(12),
+ )
+
+
+class CreateCursor(rq.Request):
+ _request = rq.Struct(
+ rq.Opcode(93),
+ rq.Pad(1),
+ rq.RequestLength(),
+ rq.Cursor('cid'),
+ rq.Pixmap('source'),
+ rq.Pixmap('mask'),
+ rq.Card16('fore_red'),
+ rq.Card16('fore_green'),
+ rq.Card16('fore_blue'),
+ rq.Card16('back_red'),
+ rq.Card16('back_green'),
+ rq.Card16('back_blue'),
+ rq.Card16('x'),
+ rq.Card16('y'),
+ )
+
+class CreateGlyphCursor(rq.Request):
+ _request = rq.Struct(
+ rq.Opcode(94),
+ rq.Pad(1),
+ rq.RequestLength(),
+ rq.Cursor('cid'),
+ rq.Font('source'),
+ rq.Font('mask'),
+ rq.Card16('source_char'),
+ rq.Card16('mask_char'),
+ rq.Card16('fore_red'),
+ rq.Card16('fore_green'),
+ rq.Card16('fore_blue'),
+ rq.Card16('back_red'),
+ rq.Card16('back_green'),
+ rq.Card16('back_blue'),
+ )
+
+class FreeCursor(rq.Request):
+ _request = rq.Struct(
+ rq.Opcode(95),
+ rq.Pad(1),
+ rq.RequestLength(),
+ rq.Cursor('cursor')
+ )
+
+class RecolorCursor(rq.Request):
+ _request = rq.Struct(
+ rq.Opcode(96),
+ rq.Pad(1),
+ rq.RequestLength(),
+ rq.Cursor('cursor'),
+ rq.Card16('fore_red'),
+ rq.Card16('fore_green'),
+ rq.Card16('fore_blue'),
+ rq.Card16('back_red'),
+ rq.Card16('back_green'),
+ rq.Card16('back_blue'),
+ )
+
+class QueryBestSize(rq.ReplyRequest):
+ _request = rq.Struct(
+ rq.Opcode(97),
+ rq.Set('item_class', 1, (X.CursorShape, X.TileShape, X.StippleShape)),
+ rq.RequestLength(),
+ rq.Drawable('drawable'),
+ rq.Card16('width'),
+ rq.Card16('height'),
+ )
+
+ _reply = rq.Struct(
+ rq.ReplyCode(),
+ rq.Pad(1),
+ rq.Card16('sequence_number'),
+ rq.ReplyLength(),
+ rq.Card16('width'),
+ rq.Card16('height'),
+ rq.Pad(20),
+ )
+
+class QueryExtension(rq.ReplyRequest):
+ _request = rq.Struct(
+ rq.Opcode(98),
+ rq.Pad(1),
+ rq.RequestLength(),
+ rq.LengthOf('name', 2),
+ rq.Pad(2),
+ rq.String8('name'),
+ )
+
+ _reply = rq.Struct(
+ rq.ReplyCode(),
+ rq.Pad(1),
+ rq.Card16('sequence_number'),
+ rq.ReplyLength(),
+ rq.Card8('present'),
+ rq.Card8('major_opcode'),
+ rq.Card8('first_event'),
+ rq.Card8('first_error'),
+ rq.Pad(20),
+ )
+
+class ListExtensions(rq.ReplyRequest):
+ _request = rq.Struct(
+ rq.Opcode(99),
+ rq.Pad(1),
+ rq.RequestLength(),
+ )
+
+ _reply = rq.Struct(
+ rq.ReplyCode(),
+ rq.LengthOf('names', 1),
+ rq.Card16('sequence_number'),
+ rq.ReplyLength(),
+ rq.Pad(24),
+ rq.List('names', rq.Str),
+ )
+
+class ChangeKeyboardMapping(rq.Request):
+ _request = rq.Struct(
+ rq.Opcode(100),
+ rq.LengthOf('keysyms', 1),
+ rq.RequestLength(),
+ rq.Card8('first_keycode'),
+ rq.Format('keysyms', 1),
+ rq.Pad(2),
+ rq.KeyboardMapping('keysyms'),
+ )
+
+class GetKeyboardMapping(rq.ReplyRequest):
+ _request = rq.Struct(
+ rq.Opcode(101),
+ rq.Pad(1),
+ rq.RequestLength(),
+ rq.Card8('first_keycode'),
+ rq.Card8('count'),
+ rq.Pad(2),
+ )
+
+ _reply = rq.Struct(
+ rq.ReplyCode(),
+ rq.Format('keysyms', 1),
+ rq.Card16('sequence_number'),
+ rq.ReplyLength(),
+ rq.Pad(24),
+ rq.KeyboardMapping('keysyms'),
+ )
+
+
+class ChangeKeyboardControl(rq.Request):
+ _request = rq.Struct(
+ rq.Opcode(102),
+ rq.Pad(1),
+ rq.RequestLength(),
+ rq.ValueList( 'attrs', 4, 0,
+ rq.Int8('key_click_percent'),
+ rq.Int8('bell_percent'),
+ rq.Int16('bell_pitch'),
+ rq.Int16('bell_duration'),
+ rq.Card8('led'),
+ rq.Set('led_mode', 1, (X.LedModeOff, X.LedModeOn)),
+ rq.Card8('key'),
+ rq.Set('auto_repeat_mode', 1, (X.AutoRepeatModeOff,
+ X.AutoRepeatModeOn,
+ X.AutoRepeatModeDefault))
+ )
+ )
+
+class GetKeyboardControl(rq.ReplyRequest):
+ _request = rq.Struct(
+ rq.Opcode(103),
+ rq.Pad(1),
+ rq.RequestLength(),
+ )
+
+ _reply = rq.Struct(
+ rq.ReplyCode(),
+ rq.Card8('global_auto_repeat'),
+ rq.Card16('sequence_number'),
+ rq.ReplyLength(),
+ rq.Card32('led_mask'),
+ rq.Card8('key_click_percent'),
+ rq.Card8('bell_percent'),
+ rq.Card16('bell_pitch'),
+ rq.Card16('bell_duration'),
+ rq.Pad(2),
+ rq.FixedList('auto_repeats', 32, rq.Card8Obj),
+ )
+
+class Bell(rq.Request):
+ _request = rq.Struct(
+ rq.Opcode(104),
+ rq.Int8('percent'),
+ rq.RequestLength(),
+ )
+
+class ChangePointerControl(rq.Request):
+ _request = rq.Struct(
+ rq.Opcode(105),
+ rq.Pad(1),
+ rq.RequestLength(),
+ rq.Int16('accel_num'),
+ rq.Int16('accel_denum'),
+ rq.Int16('threshold'),
+ rq.Bool('do_accel'),
+ rq.Bool('do_thresh'),
+ )
+
+class GetPointerControl(rq.ReplyRequest):
+ _request = rq.Struct(
+ rq.Opcode(106),
+ rq.Pad(1),
+ rq.RequestLength(),
+ )
+
+ _reply = rq.Struct(
+ rq.ReplyCode(),
+ rq.Pad(1),
+ rq.Card16('sequence_number'),
+ rq.ReplyLength(),
+ rq.Card16('accel_num'),
+ rq.Card16('accel_denom'),
+ rq.Card16('threshold'),
+ rq.Pad(18),
+ )
+
+class SetScreenSaver(rq.Request):
+ _request = rq.Struct(
+ rq.Opcode(107),
+ rq.Pad(1),
+ rq.RequestLength(),
+ rq.Int16('timeout'),
+ rq.Int16('interval'),
+ rq.Set('prefer_blank', 1, (X.DontPreferBlanking,
+ X.PreferBlanking,
+ X.DefaultBlanking)),
+ rq.Set('allow_exposures', 1, (X.DontAllowExposures,
+ X.AllowExposures,
+ X.DefaultExposures)),
+ rq.Pad(2),
+ )
+
+class GetScreenSaver(rq.ReplyRequest):
+ _request = rq.Struct(
+ rq.Opcode(108),
+ rq.Pad(1),
+ rq.RequestLength(),
+ )
+
+ _reply = rq.Struct(
+ rq.ReplyCode(),
+ rq.Pad(1),
+ rq.Card16('sequence_number'),
+ rq.ReplyLength(),
+ rq.Card16('timeout'),
+ rq.Card16('interval'),
+ rq.Card8('prefer_blanking'),
+ rq.Card8('allow_exposures'),
+ rq.Pad(18),
+ )
+
+class ChangeHosts(rq.Request):
+ _request = rq.Struct(
+ rq.Opcode(109),
+ rq.Set('mode', 1, (X.HostInsert, X.HostDelete)),
+ rq.RequestLength(),
+ rq.Set('host_family', 1, (X.FamilyInternet, X.FamilyDECnet, X.FamilyChaos)),
+ rq.Pad(1),
+ rq.LengthOf('host', 2),
+ rq.List('host', rq.Card8Obj)
+ )
+
+class ListHosts(rq.ReplyRequest):
+ _request = rq.Struct(
+ rq.Opcode(110),
+ rq.Pad(1),
+ rq.RequestLength(),
+ )
+
+ _reply = rq.Struct(
+ rq.ReplyCode(),
+ rq.Card8('mode'),
+ rq.Card16('sequence_number'),
+ rq.ReplyLength(),
+ rq.LengthOf('hosts', 2),
+ rq.Pad(22),
+ rq.List('hosts', structs.Host),
+ )
+
+class SetAccessControl(rq.Request):
+ _request = rq.Struct(
+ rq.Opcode(111),
+ rq.Set('mode', 1, (X.DisableAccess, X.EnableAccess)),
+ rq.RequestLength(),
+ )
+
+class SetCloseDownMode(rq.Request):
+ _request = rq.Struct(
+ rq.Opcode(112),
+ rq.Set('mode', 1, (X.DestroyAll, X.RetainPermanent, X.RetainTemporary)),
+ rq.RequestLength(),
+ )
+
+class KillClient(rq.Request):
+ _request = rq.Struct(
+ rq.Opcode(113),
+ rq.Pad(1),
+ rq.RequestLength(),
+ rq.Resource('resource')
+ )
+
+class RotateProperties(rq.Request):
+ _request = rq.Struct(
+ rq.Opcode(114),
+ rq.Pad(1),
+ rq.RequestLength(),
+ rq.Window('window'),
+ rq.LengthOf('properties', 2),
+ rq.Int16('delta'),
+ rq.List('properties', rq.Card32Obj),
+ )
+
+class ForceScreenSaver(rq.Request):
+ _request = rq.Struct(
+ rq.Opcode(115),
+ rq.Set('mode', 1, (X.ScreenSaverReset, X.ScreenSaverActive)),
+ rq.RequestLength(),
+ )
+
+class SetPointerMapping(rq.ReplyRequest):
+ _request = rq.Struct(
+ rq.Opcode(116),
+ rq.LengthOf('map', 1),
+ rq.RequestLength(),
+ rq.List('map', rq.Card8Obj),
+ )
+
+ _reply = rq.Struct(
+ rq.ReplyCode(),
+ rq.Card8('status'),
+ rq.Card16('sequence_number'),
+ rq.ReplyLength(),
+ rq.Pad(24),
+ )
+
+class GetPointerMapping(rq.ReplyRequest):
+ _request = rq.Struct(
+ rq.Opcode(117),
+ rq.Pad(1),
+ rq.RequestLength(),
+ )
+
+ _reply = rq.Struct(
+ rq.ReplyCode(),
+ rq.LengthOf('map', 1),
+ rq.Card16('sequence_number'),
+ rq.ReplyLength(),
+ rq.Pad(24),
+ rq.List('map', rq.Card8Obj),
+ )
+
+class SetModifierMapping(rq.ReplyRequest):
+ _request = rq.Struct(
+ rq.Opcode(118),
+ rq.Format('keycodes', 1),
+ rq.RequestLength(),
+ rq.ModifierMapping('keycodes')
+ )
+
+ _reply = rq.Struct(
+ rq.ReplyCode(),
+ rq.Card8('status'),
+ rq.Card16('sequence_number'),
+ rq.ReplyLength(),
+ rq.Pad(24),
+ )
+
+class GetModifierMapping(rq.ReplyRequest):
+ _request = rq.Struct(
+ rq.Opcode(119),
+ rq.Pad(1),
+ rq.RequestLength(),
+ )
+
+ _reply = rq.Struct(
+ rq.ReplyCode(),
+ rq.Format('keycodes', 1),
+ rq.Card16('sequence_number'),
+ rq.ReplyLength(),
+ rq.Pad(24),
+ rq.ModifierMapping('keycodes')
+ )
+
+class NoOperation(rq.Request):
+ _request = rq.Struct(
+ rq.Opcode(127),
+ rq.Pad(1),
+ rq.RequestLength(),
+ )
+
+
+major_codes = {
+ 1: CreateWindow,
+ 2: ChangeWindowAttributes,
+ 3: GetWindowAttributes,
+ 4: DestroyWindow,
+ 5: DestroySubWindows,
+ 6: ChangeSaveSet,
+ 7: ReparentWindow,
+ 8: MapWindow,
+ 9: MapSubwindows,
+ 10: UnmapWindow,
+ 11: UnmapSubwindows,
+ 12: ConfigureWindow,
+ 13: CirculateWindow,
+ 14: GetGeometry,
+ 15: QueryTree,
+ 16: InternAtom,
+ 17: GetAtomName,
+ 18: ChangeProperty,
+ 19: DeleteProperty,
+ 20: GetProperty,
+ 21: ListProperties,
+ 22: SetSelectionOwner,
+ 23: GetSelectionOwner,
+ 24: ConvertSelection,
+ 25: SendEvent,
+ 26: GrabPointer,
+ 27: UngrabPointer,
+ 28: GrabButton,
+ 29: UngrabButton,
+ 30: ChangeActivePointerGrab,
+ 31: GrabKeyboard,
+ 32: UngrabKeyboard,
+ 33: GrabKey,
+ 34: UngrabKey,
+ 35: AllowEvents,
+ 36: GrabServer,
+ 37: UngrabServer,
+ 38: QueryPointer,
+ 39: GetMotionEvents,
+ 40: TranslateCoords,
+ 41: WarpPointer,
+ 42: SetInputFocus,
+ 43: GetInputFocus,
+ 44: QueryKeymap,
+ 45: OpenFont,
+ 46: CloseFont,
+ 47: QueryFont,
+ 48: QueryTextExtents,
+ 49: ListFonts,
+ 50: ListFontsWithInfo,
+ 51: SetFontPath,
+ 52: GetFontPath,
+ 53: CreatePixmap,
+ 54: FreePixmap,
+ 55: CreateGC,
+ 56: ChangeGC,
+ 57: CopyGC,
+ 58: SetDashes,
+ 59: SetClipRectangles,
+ 60: FreeGC,
+ 61: ClearArea,
+ 62: CopyArea,
+ 63: CopyPlane,
+ 64: PolyPoint,
+ 65: PolyLine,
+ 66: PolySegment,
+ 67: PolyRectangle,
+ 68: PolyArc,
+ 69: FillPoly,
+ 70: PolyFillRectangle,
+ 71: PolyFillArc,
+ 72: PutImage,
+ 73: GetImage,
+ 74: PolyText8,
+ 75: PolyText16,
+ 76: ImageText8,
+ 77: ImageText16,
+ 78: CreateColormap,
+ 79: FreeColormap,
+ 80: CopyColormapAndFree,
+ 81: InstallColormap,
+ 82: UninstallColormap,
+ 83: ListInstalledColormaps,
+ 84: AllocColor,
+ 85: AllocNamedColor,
+ 86: AllocColorCells,
+ 87: AllocColorPlanes,
+ 88: FreeColors,
+ 89: StoreColors,
+ 90: StoreNamedColor,
+ 91: QueryColors,
+ 92: LookupColor,
+ 93: CreateCursor,
+ 94: CreateGlyphCursor,
+ 95: FreeCursor,
+ 96: RecolorCursor,
+ 97: QueryBestSize,
+ 98: QueryExtension,
+ 99: ListExtensions,
+ 100: ChangeKeyboardMapping,
+ 101: GetKeyboardMapping,
+ 102: ChangeKeyboardControl,
+ 103: GetKeyboardControl,
+ 104: Bell,
+ 105: ChangePointerControl,
+ 106: GetPointerControl,
+ 107: SetScreenSaver,
+ 108: GetScreenSaver,
+ 109: ChangeHosts,
+ 110: ListHosts,
+ 111: SetAccessControl,
+ 112: SetCloseDownMode,
+ 113: KillClient,
+ 114: RotateProperties,
+ 115: ForceScreenSaver,
+ 116: SetPointerMapping,
+ 117: GetPointerMapping,
+ 118: SetModifierMapping,
+ 119: GetModifierMapping,
+ 127: NoOperation,
+ }
diff --git a/Xlib/protocol/rq.py b/Xlib/protocol/rq.py
new file mode 100644
index 0000000..b35bccc
--- /dev/null
+++ b/Xlib/protocol/rq.py
@@ -0,0 +1,1513 @@
+# $Id: rq.py,v 1.16 2007/06/10 14:11:58 mggrant Exp $
+#
+# Xlib.protocol.rq -- structure primitives for request, events and errors
+#
+# Copyright (C) 2000-2002 Peter Liljenberg <petli@ctrl-c.liu.se>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+# Standard modules
+import sys
+import traceback
+import struct
+import string
+from array import array
+import types
+import new
+
+# Xlib modules
+from Xlib import X
+from Xlib.support import lock
+
+
+class BadDataError(Exception): pass
+
+# These are struct codes, we know their byte sizes
+
+signed_codes = { 1: 'b', 2: 'h', 4: 'l' }
+unsigned_codes = { 1: 'B', 2: 'H', 4: 'L' }
+
+
+# Unfortunately, we don't know the array sizes of B, H and L, since
+# these use the underlying architecture's size for a char, short and
+# long. Therefore we probe for their sizes, and additionally create
+# a mapping that translates from struct codes to array codes.
+#
+# Bleah.
+
+array_unsigned_codes = { }
+struct_to_array_codes = { }
+
+for c in 'bhil':
+ size = array(c).itemsize
+
+ array_unsigned_codes[size] = string.upper(c)
+ try:
+ struct_to_array_codes[signed_codes[size]] = c
+ struct_to_array_codes[unsigned_codes[size]] = string.upper(c)
+ except KeyError:
+ pass
+
+# print array_unsigned_codes, struct_to_array_codes
+
+
+class Field:
+ """Field objects represent the data fields of a Struct.
+
+ Field objects must have the following attributes:
+
+ name -- the field name, or None
+ structcode -- the struct codes representing this field
+ structvalues -- the number of values encodes by structcode
+
+ Additionally, these attributes should either be None or real methods:
+
+ check_value -- check a value before it is converted to binary
+ parse_value -- parse a value after it has been converted from binary
+
+ If one of these attributes are None, no check or additional
+ parsings will be done one values when converting to or from binary
+ form. Otherwise, the methods should have the following behaviour:
+
+ newval = check_value(val)
+ Check that VAL is legal when converting to binary form. The
+ value can also be converted to another Python value. In any
+ case, return the possibly new value. NEWVAL should be a
+ single Python value if structvalues is 1, a tuple of
+ structvalues elements otherwise.
+
+ newval = parse_value(val, display)
+ VAL is an unpacked Python value, which now can be further
+ refined. DISPLAY is the current Display object. Return the
+ new value. VAL will be a single value if structvalues is 1,
+ a tuple of structvalues elements otherwise.
+
+ If `structcode' is None the Field must have the method
+ f.parse_binary_value() instead. See its documentation string for
+ details.
+
+ """
+
+ name = None
+ default = None
+
+ structcode = None
+ structvalues = 0
+
+ check_value = None
+ parse_value = None
+
+ keyword_args = 0
+
+ def __init__(self):
+ pass
+
+ def parse_binary_value(self, data, display, length, format):
+ """value, remaindata = f.parse_binary_value(data, display, length, format)
+
+ Decode a value for this field from the binary string DATA.
+ If there are a LengthField and/or a FormatField connected to this
+ field, their values will be LENGTH and FORMAT, respectively. If
+ there are no such fields the parameters will be None.
+
+ DISPLAY is the display involved, which is really only used by
+ the Resource fields.
+
+ The decoded value is returned as VALUE, and the remaining part
+ of DATA shold be returned as REMAINDATA.
+ """
+
+ raise RuntimeError('Neither structcode or parse_binary_value provided for %s'
+ % self)
+
+
+class Pad(Field):
+ def __init__(self, size):
+ self.size = size
+ self.value = '\0' * size
+ self.structcode = '%dx' % size
+ self.structvalues = 0
+
+
+class ConstantField(Field):
+ def __init__(self, value):
+ self.value = value
+
+
+class Opcode(ConstantField):
+ structcode = 'B'
+ structvalues = 1
+
+class ReplyCode(ConstantField):
+ structcode = 'B'
+ structvalues = 1
+
+ def __init__(self):
+ self.value = 1
+
+class LengthField(Field):
+ """A LengthField stores the length of some other Field whose size
+ may vary, e.g. List and String8.
+
+ Its name should be the same as the name of the field whose size
+ it stores.
+
+ The lf.get_binary_value() method of LengthFields is not used, instead
+ a lf.get_binary_length() should be provided.
+
+ Unless LengthField.get_binary_length() is overridden in child classes,
+ there should also be a lf.calc_length().
+ """
+
+ structcode = 'L'
+ structvalues = 1
+
+ def calc_length(self, length):
+ """newlen = lf.calc_length(length)
+
+ Return a new length NEWLEN based on the provided LENGTH.
+ """
+
+ return length
+
+
+class TotalLengthField(LengthField):
+ pass
+
+class RequestLength(TotalLengthField):
+ structcode = 'H'
+ structvalues = 1
+
+ def calc_length(self, length):
+ return length / 4
+
+class ReplyLength(TotalLengthField):
+ structcode = 'L'
+ structvalues = 1
+
+ def calc_length(self, length):
+ return (length - 32) / 4
+
+
+class LengthOf(LengthField):
+ def __init__(self, name, size):
+ self.name = name
+ self.structcode = unsigned_codes[size]
+
+
+class OddLength(LengthField):
+ structcode = 'B'
+ structvalues = 1
+
+ def __init__(self, name):
+ self.name = name
+
+ def calc_length(self, length):
+ return length % 2
+
+ def parse_value(self, value, display):
+ if value == 0:
+ return 'even'
+ else:
+ return 'odd'
+
+
+class FormatField(Field):
+ """A FormatField encodes the format of some other field, in a manner
+ similar to LengthFields.
+
+ The ff.get_binary_value() method is not used, replaced by
+ ff.get_binary_format().
+ """
+
+ structvalues = 1
+
+ def __init__(self, name, size):
+ self.name = name
+ self.structcode = unsigned_codes[size]
+
+Format = FormatField
+
+
+class ValueField(Field):
+ def __init__(self, name, default = None):
+ self.name = name
+ self.default = default
+
+
+class Int8(ValueField):
+ structcode = 'b'
+ structvalues = 1
+
+class Int16(ValueField):
+ structcode = 'h'
+ structvalues = 1
+
+class Int32(ValueField):
+ structcode = 'l'
+ structvalues = 1
+
+class Card8(ValueField):
+ structcode = 'B'
+ structvalues = 1
+
+class Card16(ValueField):
+ structcode = 'H'
+ structvalues = 1
+
+class Card32(ValueField):
+ structcode = 'L'
+ structvalues = 1
+
+
+class Resource(Card32):
+ cast_function = '__resource__'
+ class_name = 'resource'
+
+ def __init__(self, name, codes = (), default = None):
+ Card32.__init__(self, name, default)
+ self.codes = codes
+
+ def check_value(self, value):
+ if type(value) is types.InstanceType:
+ return getattr(value, self.cast_function)()
+ else:
+ return value
+
+ def parse_value(self, value, display):
+ # if not display:
+ # return value
+ if value in self.codes:
+ return value
+
+ c = display.get_resource_class(self.class_name)
+ if c:
+ return c(display, value)
+ else:
+ return value
+
+class Window(Resource):
+ cast_function = '__window__'
+ class_name = 'window'
+
+class Pixmap(Resource):
+ cast_function = '__pixmap__'
+ class_name = 'pixmap'
+
+class Drawable(Resource):
+ cast_function = '__drawable__'
+ class_name = 'drawable'
+
+class Fontable(Resource):
+ cast_function = '__fontable__'
+ class_name = 'fontable'
+
+class Font(Resource):
+ cast_function = '__font__'
+ class_name = 'font'
+
+class GC(Resource):
+ cast_function = '__gc__'
+ class_name = 'gc'
+
+class Colormap(Resource):
+ cast_function = '__colormap__'
+ class_name = 'colormap'
+
+class Cursor(Resource):
+ cast_function = '__cursor__'
+ class_name = 'cursor'
+
+
+class Bool(ValueField):
+ structvalues = 1
+ structcode = 'B'
+
+ def check_value(self, value):
+ return not not value
+
+class Set(ValueField):
+ structvalues = 1
+
+ def __init__(self, name, size, values, default = None):
+ ValueField.__init__(self, name, default)
+ self.structcode = unsigned_codes[size]
+ self.values = values
+
+ def check_value(self, val):
+ if val not in self.values:
+ raise ValueError('field %s: argument %s not in %s'
+ % (self.name, val, self.values))
+
+ return val
+
+class Gravity(Set):
+ def __init__(self, name):
+ Set.__init__(self, name, 1, (X.ForgetGravity, X.StaticGravity,
+ X.NorthWestGravity, X.NorthGravity,
+ X.NorthEastGravity, X.WestGravity,
+ X.CenterGravity, X.EastGravity,
+ X.SouthWestGravity, X.SouthGravity,
+ X.SouthEastGravity))
+
+
+class FixedString(ValueField):
+ structvalues = 1
+
+ def __init__(self, name, size):
+ ValueField.__init__(self, name)
+ self.structcode = '%ds' % size
+
+
+class String8(ValueField):
+ structcode = None
+
+ def __init__(self, name, pad = 1):
+ ValueField.__init__(self, name)
+ self.pad = pad
+
+ def pack_value(self, val):
+ slen = len(val)
+
+ if self.pad:
+ return val + '\0' * ((4 - slen % 4) % 4), slen, None
+ else:
+ return val, slen, None
+
+ def parse_binary_value(self, data, display, length, format):
+ if length is None:
+ return str(data), ''
+
+ if self.pad:
+ slen = length + ((4 - length % 4) % 4)
+ else:
+ slen = length
+
+ return str(data[:length]), buffer(data, slen)
+
+
+class String16(ValueField):
+ structcode = None
+
+ def __init__(self, name, pad = 1):
+ ValueField.__init__(self, name)
+ self.pad = pad
+
+ def pack_value(self, val):
+ # Convert 8-byte string into 16-byte list
+ if type(val) is types.StringType:
+ val = map(lambda c: ord(c), val)
+
+ slen = len(val)
+
+ if self.pad:
+ pad = '\0\0' * (slen % 2)
+ else:
+ pad = ''
+
+ return apply(struct.pack, ('>' + 'H' * slen, ) + tuple(val)) + pad, slen, None
+
+ def parse_binary_value(self, data, display, length, format):
+ if length == 'odd':
+ length = len(data) / 2 - 1
+ elif length == 'even':
+ length = len(data) / 2
+
+ if self.pad:
+ slen = length + (length % 2)
+ else:
+ slen = length
+
+ return struct.unpack('>' + 'H' * length, data[:length * 2]), buffer(data, slen * 2)
+
+
+
+class List(ValueField):
+ """The List, FixedList and Object fields store compound data objects.
+ The type of data objects must be provided as an object with the
+ following attributes and methods:
+
+ ...
+
+ """
+
+ structcode = None
+
+ def __init__(self, name, type, pad = 1):
+ ValueField.__init__(self, name)
+ self.type = type
+ self.pad = pad
+
+ def parse_binary_value(self, data, display, length, format):
+ if length is None:
+ ret = []
+ if self.type.structcode is None:
+ while data:
+ val, data = self.type.parse_binary(data, display)
+ ret.append(val)
+ else:
+ scode = '=' + self.type.structcode
+ slen = struct.calcsize(scode)
+ pos = 0
+ while pos + slen <= len(data):
+ v = struct.unpack(scode, data[pos: pos + slen])
+
+ if self.type.structvalues == 1:
+ v = v[0]
+
+ if self.type.parse_value is None:
+ ret.append(v)
+ else:
+ ret.append(self.type.parse_value(v, display))
+
+ pos = pos + slen
+
+ data = buffer(data, pos)
+
+ else:
+ ret = [None] * int(length)
+
+ if self.type.structcode is None:
+ for i in range(0, length):
+ ret[i], data = self.type.parse_binary(data, display)
+ else:
+ scode = '=' + self.type.structcode
+ slen = struct.calcsize(scode)
+ pos = 0
+ for i in range(0, length):
+ v = struct.unpack(scode, data[pos: pos + slen])
+
+ if self.type.structvalues == 1:
+ v = v[0]
+
+ if self.type.parse_value is None:
+ ret[i] = v
+ else:
+ ret[i] = self.type.parse_value(v, display)
+
+ pos = pos + slen
+
+ data = buffer(data, pos)
+
+ if self.pad:
+ data = buffer(data, len(data) % 4)
+
+ return ret, data
+
+ def pack_value(self, val):
+ # Single-char values, we'll assume that means integer lists.
+ if self.type.structcode and len(self.type.structcode) == 1:
+ data = array(struct_to_array_codes[self.type.structcode],
+ val).tostring()
+ else:
+ data = []
+ for v in val:
+ data.append(self.type.pack_value(v))
+
+ data = string.join(data, '')
+
+ if self.pad:
+ dlen = len(data)
+ data = data + '\0' * ((4 - dlen % 4) % 4)
+
+ return data, len(val), None
+
+
+class FixedList(List):
+ def __init__(self, name, size, type, pad = 1):
+ List.__init__(self, name, type, pad)
+ self.size = size
+
+ def parse_binary_value(self, data, display, length, format):
+ return List.parse_binary_value(self, data, display, self.size, format)
+
+ def pack_value(self, val):
+ if len(val) != self.size:
+ raise BadDataError('length mismatch for FixedList %s' % self.name)
+ return List.pack_value(self, val)
+
+
+class Object(ValueField):
+ structcode = None
+
+ def __init__(self, name, type, default = None):
+ ValueField.__init__(self, name, default)
+ self.type = type
+ self.structcode = self.type.structcode
+ self.structvalues = self.type.structvalues
+
+ def parse_binary_value(self, data, display, length, format):
+ if self.type.structcode is None:
+ return self.type.parse_binary(data, display)
+
+ else:
+ scode = '=' + self.type.structcode
+ slen = struct.calcsize(scode)
+
+ v = struct.unpack(scode, data[:slen])
+ if self.type.structvalues == 1:
+ v = v[0]
+
+ if self.type.parse_value is not None:
+ v = self.type.parse_value(v, display)
+
+ return v, buffer(data, slen)
+
+ def parse_value(self, val, display):
+ if self.type.parse_value is None:
+ return val
+ else:
+ return self.type.parse_value(val, display)
+
+ def pack_value(self, val):
+ # Single-char values, we'll assume that mean an integer
+ if self.type.structcode and len(self.type.structcode) == 1:
+ return struct.pack('=' + self.type.structcode, val), None, None
+ else:
+ return self.type.pack_value(val)
+
+ def check_value(self, val):
+ if self.type.structcode is None:
+ return val
+
+ if type(val) is types.TupleType:
+ return val
+
+ if type(val) is types.DictType:
+ data = val
+ elif isinstance(val, DictWrapper):
+ data = val._data
+ else:
+ raise TypeError('Object value must be tuple, dictionary or DictWrapper: %s' % val)
+
+ vals = []
+ for f in self.type.fields:
+ if f.name:
+ vals.append(data[f.name])
+
+ return vals
+
+
+class PropertyData(ValueField):
+ structcode = None
+
+ def parse_binary_value(self, data, display, length, format):
+ if length is None:
+ length = len(data) / (format / 8)
+ else:
+ length = int(length)
+
+ if format == 0:
+ ret = None
+
+ elif format == 8:
+ ret = (8, str(data[:length]))
+ data = buffer(data, length + ((4 - length % 4) % 4))
+
+ elif format == 16:
+ ret = (16, array(array_unsigned_codes[2], str(data[:2 * length])))
+ data = buffer(data, 2 * (length + length % 2))
+
+ elif format == 32:
+ ret = (32, array(array_unsigned_codes[4], str(data[:4 * length])))
+ data = buffer(data, 4 * length)
+
+ return ret, data
+
+ def pack_value(self, value):
+ fmt, val = value
+
+ if fmt not in (8, 16, 32):
+ raise BadDataError('Invalid property data format %d' % format)
+
+ if type(val) is types.StringType:
+ size = fmt / 8
+ vlen = len(val)
+ if vlen % size:
+ vlen = vlen - vlen % size
+ data = val[:vlen]
+ else:
+ data = val
+
+ dlen = vlen / size
+
+ else:
+ if type(val) is types.TupleType:
+ val = list(val)
+
+ size = fmt / 8
+ data = array(array_unsigned_codes[size], val).tostring()
+ dlen = len(val)
+
+ dl = len(data)
+ data = data + '\0' * ((4 - dl % 4) % 4)
+
+ return data, dlen, fmt
+
+
+class FixedPropertyData(PropertyData):
+ def __init__(self, name, size):
+ PropertyData.__init__(self, name)
+ self.size = size
+
+ def parse_binary_value(self, data, display, length, format):
+ return PropertyData.parse_binary_value(self, data, display,
+ self.size / (format / 8), format)
+
+ def pack_value(self, value):
+ data, dlen, fmt = PropertyData.pack_value(self, value)
+
+ if len(data) != self.size:
+ raise BadDataError('Wrong data length for FixedPropertyData: %s'
+ % (value, ))
+
+ return data, dlen, fmt
+
+
+class ValueList(Field):
+ structcode = None
+ keyword_args = 1
+ default = 'usekeywords'
+
+ def __init__(self, name, mask, pad, *fields):
+ self.name = name
+ self.maskcode = '=%s%dx' % (unsigned_codes[mask], pad)
+ self.maskcodelen = struct.calcsize(self.maskcode)
+ self.fields = []
+
+ flag = 1
+ for f in fields:
+ if f.name:
+ self.fields.append((f, flag))
+ flag = flag << 1
+
+ def pack_value(self, arg, keys):
+ mask = 0
+ data = ''
+
+ if arg == self.default:
+ arg = keys
+
+ for field, flag in self.fields:
+ if arg.has_key(field.name):
+ mask = mask | flag
+
+ val = arg[field.name]
+ if field.check_value is not None:
+ val = field.check_value(val)
+
+ d = struct.pack('=' + field.structcode, val)
+ data = data + d + '\0' * (4 - len(d))
+
+ return struct.pack(self.maskcode, mask) + data, None, None
+
+ def parse_binary_value(self, data, display, length, format):
+ r = {}
+
+ mask = int(struct.unpack(self.maskcode, data[:self.maskcodelen])[0])
+ data = buffer(data, self.maskcodelen)
+
+ for field, flag in self.fields:
+ if mask & flag:
+ if field.structcode:
+ vals = struct.unpack('=' + field.structcode,
+ data[:struct.calcsize('=' + field.structcode)])
+ if field.structvalues == 1:
+ vals = vals[0]
+
+ if field.parse_value is not None:
+ vals = field.parse_value(vals, display)
+
+ else:
+ vals, d = field.parse_binary_value(data[:4], display, None, None)
+
+ r[field.name] = vals
+ data = buffer(data, 4)
+
+ return DictWrapper(r), data
+
+
+class KeyboardMapping(ValueField):
+ structcode = None
+
+ def parse_binary_value(self, data, display, length, format):
+ if length is None:
+ dlen = len(data)
+ else:
+ dlen = 4 * length * format
+
+ a = array(array_unsigned_codes[4], str(data[:dlen]))
+
+ ret = []
+ for i in range(0, len(a), format):
+ ret.append(a[i : i + format])
+
+ return ret, buffer(data, dlen)
+
+ def pack_value(self, value):
+ keycodes = 0
+ for v in value:
+ keycodes = max(keycodes, len(v))
+
+ a = array(array_unsigned_codes[4])
+
+ for v in value:
+ for k in v:
+ a.append(k)
+ for i in range(len(v), keycodes):
+ a.append(X.NoSymbol)
+
+ return a.tostring(), len(value), keycodes
+
+
+class ModifierMapping(ValueField):
+ structcode = None
+
+ def parse_binary_value(self, data, display, length, format):
+ a = array(array_unsigned_codes[1], str(data[:8 * format]))
+
+ ret = []
+ for i in range(0, 8):
+ ret.append(a[i * format : (i + 1) * format])
+
+ return ret, buffer(data, 8 * format)
+
+ def pack_value(self, value):
+ if len(value) != 8:
+ raise BadDataError('ModifierMapping list should have eight elements')
+
+ keycodes = 0
+ for v in value:
+ keycodes = max(keycodes, len(v))
+
+ a = array(array_unsigned_codes[1])
+
+ for v in value:
+ for k in v:
+ a.append(k)
+ for i in range(len(v), keycodes):
+ a.append(0)
+
+ return a.tostring(), len(value), keycodes
+
+class EventField(ValueField):
+ structcode = None
+
+ def pack_value(self, value):
+ if not isinstance(value, Event):
+ raise BadDataError('%s is not an Event for field %s' % (value, self.name))
+
+ return value._binary, None, None
+
+ def parse_binary_value(self, data, display, length, format):
+ import event
+
+ estruct = display.event_classes.get(ord(data[0]) & 0x7f, event.AnyEvent)
+
+ return estruct(display = display, binarydata = data[:32]), buffer(data, 32)
+
+
+#
+# Objects usable for List and FixedList fields.
+# Struct is also usable.
+#
+
+class ScalarObj:
+ def __init__(self, code):
+ self.structcode = code
+ self.structvalues = 1
+ self.parse_value = None
+
+Card8Obj = ScalarObj('B')
+Card16Obj = ScalarObj('H')
+Card32Obj = ScalarObj('L')
+
+class ResourceObj:
+ structcode = 'L'
+ structvalues = 1
+
+ def __init__(self, class_name):
+ self.class_name = class_name
+
+ def parse_value(self, value, display):
+ # if not display:
+ # return value
+ c = display.get_resource_class(self.class_name)
+ if c:
+ return c(display, value)
+ else:
+ return value
+
+WindowObj = ResourceObj('window')
+ColormapObj = ResourceObj('colormap')
+
+class StrClass:
+ structcode = None
+
+ def pack_value(self, val):
+ return chr(len(val)) + val
+
+ def parse_binary(self, data, display):
+ slen = ord(data[0]) + 1
+ return data[1:slen], buffer(data, slen)
+
+Str = StrClass()
+
+
+class Struct:
+
+ """Struct objects represents a binary data structure. It can
+ contain both fields with static and dynamic sizes. However, all
+ static fields must appear before all dynamic fields.
+
+ Fields are represented by various subclasses of the abstract base
+ class Field. The fields of a structure are given as arguments
+ when instantiating a Struct object.
+
+ Struct objects have two public methods:
+
+ to_binary() -- build a binary representation of the structure
+ with the values given as arguments
+ parse_binary() -- convert a binary (string) representation into
+ a Python dictionary or object.
+
+ These functions will be generated dynamically for each Struct
+ object to make conversion as fast as possible. They are
+ generated the first time the methods are called.
+
+ """
+
+ def __init__(self, *fields):
+ self.fields = fields
+
+ # Structures for to_binary, parse_value and parse_binary
+ self.static_codes = '='
+ self.static_values = 0
+ self.static_fields = []
+ self.static_size = None
+ self.var_fields = []
+
+ for f in self.fields:
+ # Append structcode if there is one and we haven't
+ # got any varsize fields yet.
+ if f.structcode is not None:
+ assert not self.var_fields
+
+ self.static_codes = self.static_codes + f.structcode
+
+ # Only store fields with values
+ if f.structvalues > 0:
+ self.static_fields.append(f)
+ self.static_values = self.static_values + f.structvalues
+
+ # If we have got one varsize field, all the rest must
+ # also be varsize fields.
+ else:
+ self.var_fields.append(f)
+
+ self.static_size = struct.calcsize(self.static_codes)
+ if self.var_fields:
+ self.structcode = None
+ self.structvalues = 0
+ else:
+ self.structcode = self.static_codes[1:]
+ self.structvalues = self.static_values
+
+
+ # These functions get called only once, as they will override
+ # themselves with dynamically created functions in the Struct
+ # object
+
+ def to_binary(self, *varargs, **keys):
+
+ """data = s.to_binary(...)
+
+ Convert Python values into the binary representation. The
+ arguments will be all value fields with names, in the order
+ given when the Struct object was instantiated. With one
+ exception: fields with default arguments will be last.
+
+ Returns the binary representation as the string DATA.
+
+ """
+
+ code = ''
+ total_length = str(self.static_size)
+ joins = []
+ args = []
+ defargs = []
+ kwarg = 0
+
+ # First pack all varfields so their lengths and formats are
+ # available when we pack their static LengthFields and
+ # FormatFields
+
+ i = 0
+ for f in self.var_fields:
+ if f.keyword_args:
+ kwarg = 1
+ kw = ', _keyword_args'
+ else:
+ kw = ''
+
+ # Call pack_value method for each field, storing
+ # the return values for later use
+ code = code + (' _%(name)s, _%(name)s_length, _%(name)s_format'
+ ' = self.var_fields[%(fno)d].pack_value(%(name)s%(kw)s)\n'
+ % { 'name': f.name,
+ 'fno': i,
+ 'kw': kw })
+
+ total_length = total_length + ' + len(_%s)' % f.name
+ joins.append('_%s' % f.name)
+
+ i = i + 1
+
+
+ # Construct argument list for struct.pack call, packing all
+ # static fields. First argument is the structcode, the
+ # remaining are values.
+
+ pack_args = ['"%s"' % self.static_codes]
+
+ i = 0
+ for f in self.static_fields:
+ if isinstance(f, LengthField):
+
+ # If this is a total length field, insert
+ # the calculated field value here
+ if isinstance(f, TotalLengthField):
+ if self.var_fields:
+ pack_args.append('self.static_fields[%d].calc_length(%s)'
+ % (i, total_length))
+ else:
+ pack_args.append(str(f.calc_length(self.static_size)))
+ else:
+ pack_args.append('self.static_fields[%d].calc_length(_%s_length)'
+ % (i, f.name))
+
+ # Format field, just insert the value we got previously
+ elif isinstance(f, FormatField):
+ pack_args.append('_%s_format' % f.name)
+
+ # A constant field, insert its value directly
+ elif isinstance(f, ConstantField):
+ pack_args.append(str(f.value))
+
+ # Value fields
+ else:
+ if f.structvalues == 1:
+
+ # If there's a value check/convert function, call it
+ if f.check_value is not None:
+ pack_args.append('self.static_fields[%d].check_value(%s)'
+ % (i, f.name))
+
+ # Else just use the argument as provided
+ else:
+ pack_args.append(f.name)
+
+ # Multivalue field. Handled like single valuefield,
+ # but the value are tuple unpacked into seperate arguments
+ # which are appended to pack_args
+ else:
+ a = []
+ for j in range(f.structvalues):
+ a.append('_%s_%d' % (f.name, j))
+
+ if f.check_value is not None:
+ code = code + (' %s = self.static_fields[%d].check_value(%s)\n'
+ % (string.join(a, ', '), i, f.name))
+ else:
+ code = code + ' %s = %s\n' % (string.join(a, ', '), f.name)
+
+ pack_args = pack_args + a
+
+ # Add field to argument list
+ if f.name:
+ if f.default is None:
+ args.append(f.name)
+ else:
+ defargs.append('%s = %s' % (f.name, repr(f.default)))
+
+ i = i + 1
+
+
+ # Construct call to struct.pack
+ pack = 'struct.pack(%s)' % string.join(pack_args, ', ')
+
+ # If there are any varfields, we append the packed strings to build
+ # the resulting binary value
+ if self.var_fields:
+ code = code + ' return %s + %s\n' % (pack, string.join(joins, ' + '))
+
+ # If there's only static fields, return the packed value
+ else:
+ code = code + ' return %s\n' % pack
+
+ # Add all varsize fields to argument list. We do it here
+ # to ensure that they appear after the static fields.
+ for f in self.var_fields:
+ if f.name:
+ if f.default is None:
+ args.append(f.name)
+ else:
+ defargs.append('%s = %s' % (f.name, repr(f.default)))
+
+ args = args + defargs
+ if kwarg:
+ args.append('**_keyword_args')
+
+ # Add function header
+ code = 'def to_binary(self, %s):\n' % string.join(args, ', ') + code
+
+ # self._pack_code = code
+
+ # print
+ # print code
+ # print
+
+ # Finally, compile function by evaluating it. This will store
+ # the function in the local variable to_binary, thanks to the
+ # def: line. Convert it into a instance metod bound to self,
+ # and store it in self.
+
+ # Unfortunately, this creates a circular reference. However,
+ # Structs are not really created dynamically so the potential
+ # memory leak isn't that serious. Besides, Python 2.0 has
+ # real garbage collect.
+
+ exec code
+ self.to_binary = new.instancemethod(to_binary, self, self.__class__)
+
+ # Finally call it manually
+ return apply(self.to_binary, varargs, keys)
+
+
+ def pack_value(self, value):
+
+ """ This function allows Struct objects to be used in List and
+ Object fields. Each item represents the arguments to pass to
+ to_binary, either a tuple, a dictionary or a DictWrapper.
+
+ """
+
+ if type(value) is types.TupleType:
+ return apply(self.to_binary, value, {})
+ elif type(value) is types.DictionaryType:
+ return apply(self.to_binary, (), value)
+ elif isinstance(value, DictWrapper):
+ return apply(self.to_binary, (), value._data)
+ else:
+ raise BadDataError('%s is not a tuple or a list' % (value))
+
+
+ def parse_value(self, val, display, rawdict = 0):
+
+ """This function is used by List and Object fields to convert
+ Struct objects with no var_fields into Python values.
+
+ """
+
+ code = ('def parse_value(self, val, display, rawdict = 0):\n'
+ ' ret = {}\n')
+
+ vno = 0
+ fno = 0
+ for f in self.static_fields:
+ # Fields without names should be ignored, and there should
+ # not be any length or format fields if this function
+ # ever gets called. (If there were such fields, there should
+ # be a matching field in var_fields and then parse_binary
+ # would have been called instead.
+
+ if not f.name:
+ pass
+
+ elif isinstance(f, LengthField):
+ pass
+
+ elif isinstance(f, FormatField):
+ pass
+
+ # Value fields
+ else:
+
+ # Get the index or range in val representing this field.
+
+ if f.structvalues == 1:
+ vrange = str(vno)
+ else:
+ vrange = '%d:%d' % (vno, vno + f.structvalues)
+
+ # If this field has a parse_value method, call it, otherwise
+ # use the unpacked value as is.
+
+ if f.parse_value is None:
+ code = code + ' ret["%s"] = val[%s]\n' % (f.name, vrange)
+ else:
+ code = code + (' ret["%s"] = self.static_fields[%d].'
+ 'parse_value(val[%s], display)\n'
+ % (f.name, fno, vrange))
+
+ fno = fno + 1
+ vno = vno + f.structvalues
+
+ code = code + ' if not rawdict: return DictWrapper(ret)\n'
+ code = code + ' return ret\n'
+
+ # print
+ # print code
+ # print
+
+ # Finally, compile function as for to_binary.
+
+ exec code
+ self.parse_value = new.instancemethod(parse_value, self, self.__class__)
+
+ # Call it manually
+ return self.parse_value(val, display, rawdict)
+
+
+ def parse_binary(self, data, display, rawdict = 0):
+
+ """values, remdata = s.parse_binary(data, display, rawdict = 0)
+
+ Convert a binary representation of the structure into Python values.
+
+ DATA is a string or a buffer containing the binary data.
+ DISPLAY should be a Xlib.protocol.display.Display object if
+ there are any Resource fields or Lists with ResourceObjs.
+
+ The Python values are returned as VALUES. If RAWDICT is true,
+ a Python dictionary is returned, where the keys are field
+ names and the values are the corresponding Python value. If
+ RAWDICT is false, a DictWrapper will be returned where all
+ fields are available as attributes.
+
+ REMDATA are the remaining binary data, unused by the Struct object.
+
+ """
+
+ code = ('def parse_binary(self, data, display, rawdict = 0):\n'
+ ' ret = {}\n'
+ ' val = struct.unpack("%s", data[:%d])\n'
+ % (self.static_codes, self.static_size))
+
+ lengths = {}
+ formats = {}
+
+ vno = 0
+ fno = 0
+ for f in self.static_fields:
+
+ # Fields without name should be ignored. This is typically
+ # pad and constant fields
+
+ if not f.name:
+ pass
+
+ # Store index in val for Length and Format fields, to be used
+ # when treating varfields.
+
+ elif isinstance(f, LengthField):
+ if f.parse_value is None:
+ lengths[f.name] = 'val[%d]' % vno
+ else:
+ lengths[f.name] = ('self.static_fields[%d].'
+ 'parse_value(val[%d], display)'
+ % (fno, vno))
+
+ elif isinstance(f, FormatField):
+ formats[f.name] = 'val[%d]' % vno
+
+ # Treat value fields the same was as in parse_value.
+ else:
+ if f.structvalues == 1:
+ vrange = str(vno)
+ else:
+ vrange = '%d:%d' % (vno, vno + f.structvalues)
+
+ if f.parse_value is None:
+ code = code + ' ret["%s"] = val[%s]\n' % (f.name, vrange)
+ else:
+ code = code + (' ret["%s"] = self.static_fields[%d].'
+ 'parse_value(val[%s], display)\n'
+ % (f.name, fno, vrange))
+
+ fno = fno + 1
+ vno = vno + f.structvalues
+
+ code = code + ' data = buffer(data, %d)\n' % self.static_size
+
+ # Call parse_binary_value for each var_field, passing the
+ # length and format values from the unpacked val.
+
+ fno = 0
+ for f in self.var_fields:
+ code = code + (' ret["%s"], data = '
+ 'self.var_fields[%d].parse_binary_value'
+ '(data, display, %s, %s)\n'
+ % (f.name, fno,
+ lengths.get(f.name, 'None'),
+ formats.get(f.name, 'None')))
+ fno = fno + 1
+
+ code = code + ' if not rawdict: ret = DictWrapper(ret)\n'
+ code = code + ' return ret, data\n'
+
+ # print
+ # print code
+ # print
+
+ # Finally, compile function as for to_binary.
+
+ exec code
+ self.parse_binary = new.instancemethod(parse_binary, self, self.__class__)
+
+ # Call it manually
+ return self.parse_binary(data, display, rawdict)
+
+
+class TextElements8(ValueField):
+ string_textitem = Struct( LengthOf('string', 1),
+ Int8('delta'),
+ String8('string', pad = 0) )
+
+ def pack_value(self, value):
+ data = ''
+ args = {}
+
+ for v in value:
+ # Let values be simple strings, meaning a delta of 0
+ if type(v) is types.StringType:
+ v = (0, v)
+
+ # A tuple, it should be (delta, string)
+ # Encode it as one or more textitems
+
+ if type(v) in (types.TupleType, types.DictType) or \
+ isinstance(v, DictWrapper):
+
+ if type(v) is types.TupleType:
+ delta, str = v
+ else:
+ delta = v['delta']
+ str = v['string']
+
+ while delta or str:
+ args['delta'] = delta
+ args['string'] = str[:254]
+
+ data = data + apply(self.string_textitem.to_binary, (), args)
+
+ delta = 0
+ str = str[254:]
+
+ # Else an integer, i.e. a font change
+ else:
+ # Use fontable cast function if instance
+ if type(v) is types.InstanceType:
+ v = v.__fontable__()
+
+ data = data + struct.pack('>BL', 255, v)
+
+ # Pad out to four byte length
+ dlen = len(data)
+ return data + '\0' * ((4 - dlen % 4) % 4), None, None
+
+ def parse_binary_value(self, data, display, length, format):
+ values = []
+ while 1:
+ if len(data) < 2:
+ break
+
+ # font change
+ if ord(data[0]) == 255:
+ values.append(struct.unpack('>L', str(data[1:5]))[0])
+ data = buffer(data, 5)
+
+ # skip null strings
+ elif ord(data[0]) == 0 and ord(data[1]) == 0:
+ data = buffer(data, 2)
+
+ # string with delta
+ else:
+ v, data = self.string_textitem.parse_binary(data, display)
+ values.append(v)
+
+ return values, ''
+
+
+
+class TextElements16(TextElements8):
+ string_textitem = Struct( LengthOf('string', 1),
+ Int8('delta'),
+ String16('string', pad = 0) )
+
+
+
+class GetAttrData:
+ def __getattr__(self, attr):
+ try:
+ if self._data:
+ return self._data[attr]
+ else:
+ raise AttributeError(attr)
+ except KeyError:
+ raise AttributeError(attr)
+
+class DictWrapper(GetAttrData):
+ def __init__(self, dict):
+ self.__dict__['_data'] = dict
+
+ def __getitem__(self, key):
+ return self._data[key]
+
+ def __setitem__(self, key, value):
+ self._data[key] = value
+
+ def __delitem__(self, key):
+ del self._data[key]
+
+ def __setattr__(self, key, value):
+ self._data[key] = value
+
+ def __delattr__(self, key):
+ del self._data[key]
+
+ def __str__(self):
+ return str(self._data)
+
+ def __repr__(self):
+ return '%s(%s)' % (self.__class__, repr(self._data))
+
+ def __cmp__(self, other):
+ if isinstance(other, DictWrapper):
+ return cmp(self._data, other._data)
+ else:
+ return cmp(self._data, other)
+
+
+class Request:
+ def __init__(self, display, onerror = None, *args, **keys):
+ self._errorhandler = onerror
+ self._binary = apply(self._request.to_binary, args, keys)
+ self._serial = None
+ display.send_request(self, onerror is not None)
+
+ def _set_error(self, error):
+ if self._errorhandler is not None:
+ return call_error_handler(self._errorhandler, error, self)
+ else:
+ return 0
+
+class ReplyRequest(GetAttrData):
+ def __init__(self, display, defer = 0, *args, **keys):
+ self._display = display
+ self._binary = apply(self._request.to_binary, args, keys)
+ self._serial = None
+ self._data = None
+ self._error = None
+
+ self._response_lock = lock.allocate_lock()
+
+ self._display.send_request(self, 1)
+ if not defer:
+ self.reply()
+
+ def reply(self):
+ # Send request and wait for reply if we hasn't
+ # already got one. This means that reply() can safely
+ # be called more than one time.
+
+ self._response_lock.acquire()
+ while self._data is None and self._error is None:
+ self._display.send_recv_lock.acquire()
+ self._response_lock.release()
+
+ self._display.send_and_recv(request = self._serial)
+ self._response_lock.acquire()
+
+ self._response_lock.release()
+ self._display = None
+
+ # If error has been set, raise it
+ if self._error:
+ raise self._error
+
+ def _parse_response(self, data):
+ self._response_lock.acquire()
+ self._data, d = self._reply.parse_binary(data, self._display, rawdict = 1)
+ self._response_lock.release()
+
+ def _set_error(self, error):
+ self._response_lock.acquire()
+ self._error = error
+ self._response_lock.release()
+ return 1
+
+ def __repr__(self):
+ return '<%s serial = %s, data = %s, error = %s>' % (self.__class__, self._serial, self._data, self._error)
+
+
+class Event(GetAttrData):
+ def __init__(self, binarydata = None, display = None,
+ **keys):
+ if binarydata:
+ self._binary = binarydata
+ self._data, data = self._fields.parse_binary(binarydata, display,
+ rawdict = 1)
+ # split event type into type and send_event bit
+ self._data['send_event'] = not not self._data['type'] & 0x80
+ self._data['type'] = self._data['type'] & 0x7f
+ else:
+ if self._code:
+ keys['type'] = self._code
+
+ keys['sequence_number'] = 0
+
+ self._binary = apply(self._fields.to_binary, (), keys)
+
+ keys['send_event'] = 0
+ self._data = keys
+
+ def __repr__(self):
+ kwlist = []
+ for kw, val in self._data.items():
+ if kw == 'send_event':
+ continue
+ if kw == 'type' and self._data['send_event']:
+ val = val | 0x80
+ kwlist.append('%s = %s' % (kw, repr(val)))
+
+ kws = string.join(kwlist, ', ')
+ return '%s(%s)' % (self.__class__, kws)
+
+ def __cmp__(self, other):
+ if isinstance(other, Event):
+ return cmp(self._data, other._data)
+ else:
+ return cmp(self._data, other)
+
+
+def call_error_handler(handler, error, request):
+ try:
+ return handler(error, request)
+ except:
+ sys.stderr.write('Exception raised by error handler.\n')
+ traceback.print_exc()
+ return 0
diff --git a/Xlib/protocol/structs.py b/Xlib/protocol/structs.py
new file mode 100644
index 0000000..b47e024
--- /dev/null
+++ b/Xlib/protocol/structs.py
@@ -0,0 +1,160 @@
+# $Id: structs.py,v 1.4 2007/06/10 14:11:58 mggrant Exp $
+#
+# Xlib.protocol.structs -- some common request structures
+#
+# Copyright (C) 2000 Peter Liljenberg <petli@ctrl-c.liu.se>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+# Xlib modules
+from Xlib import X
+
+# Xlib.protocol modules
+import rq
+
+def WindowValues(arg):
+ return rq.ValueList( arg, 4, 0,
+ rq.Pixmap('background_pixmap'),
+ rq.Card32('background_pixel'),
+ rq.Pixmap('border_pixmap'),
+ rq.Card32('border_pixel'),
+ rq.Gravity('bit_gravity'),
+ rq.Gravity('win_gravity'),
+ rq.Set('backing_store', 1,
+ (X.NotUseful, X.WhenMapped, X.Always)),
+ rq.Card32('backing_planes'),
+ rq.Card32('backing_pixel'),
+ rq.Bool('override_redirect'),
+ rq.Bool('save_under'),
+ rq.Card32('event_mask'),
+ rq.Card32('do_not_propagate_mask'),
+ rq.Colormap('colormap'),
+ rq.Cursor('cursor'),
+ )
+
+def GCValues(arg):
+ return rq.ValueList( arg, 4, 0,
+ rq.Set('function', 1,
+ (X.GXclear, X.GXand, X.GXandReverse,
+ X.GXcopy, X.GXandInverted, X.GXnoop,
+ X.GXxor, X.GXor, X.GXnor, X.GXequiv,
+ X.GXinvert, X.GXorReverse, X.GXcopyInverted,
+ X.GXorInverted, X.GXnand, X.GXset)),
+ rq.Card32('plane_mask'),
+ rq.Card32('foreground'),
+ rq.Card32('background'),
+ rq.Card16('line_width'),
+ rq.Set('line_style', 1,
+ (X.LineSolid, X.LineOnOffDash, X.LineDoubleDash)),
+ rq.Set('cap_style', 1,
+ (X.CapNotLast, X.CapButt,
+ X.CapRound, X.CapProjecting)),
+ rq.Set('join_style', 1,
+ (X.JoinMiter, X.JoinRound, X.JoinBevel)),
+ rq.Set('fill_style', 1,
+ (X.FillSolid, X.FillTiled,
+ X.FillStippled, X.FillOpaqueStippled)),
+ rq.Set('fill_rule', 1,
+ (X.EvenOddRule, X.WindingRule)),
+ rq.Pixmap('tile'),
+ rq.Pixmap('stipple'),
+ rq.Int16('tile_stipple_x_origin'),
+ rq.Int16('tile_stipple_y_origin'),
+ rq.Font('font'),
+ rq.Set('subwindow_mode', 1,
+ (X.ClipByChildren, X.IncludeInferiors)),
+ rq.Bool('graphics_exposures'),
+ rq.Int16('clip_x_origin'),
+ rq.Int16('clip_y_origin'),
+ rq.Pixmap('clip_mask'),
+ rq.Card16('dash_offset'),
+ rq.Card8('dashes'),
+ rq.Set('arc_mode', 1, (X.ArcChord, X.ArcPieSlice))
+ )
+
+
+
+TimeCoord = rq.Struct(
+ rq.Card32('time'),
+ rq.Int16('x'),
+ rq.Int16('y'),
+ )
+
+Host = rq.Struct(
+ rq.Set('family', 1, (X.FamilyInternet, X.FamilyDECnet, X.FamilyChaos)),
+ rq.Pad(1),
+ rq.LengthOf('name', 2),
+ rq.List('name', rq.Card8Obj)
+ )
+
+CharInfo = rq.Struct(
+ rq.Int16('left_side_bearing'),
+ rq.Int16('right_side_bearing'),
+ rq.Int16('character_width'),
+ rq.Int16('ascent'),
+ rq.Int16('descent'),
+ rq.Card16('attributes'),
+ )
+
+FontProp = rq.Struct(
+ rq.Card32('name'),
+ rq.Card32('value'),
+ )
+
+ColorItem = rq.Struct(
+ rq.Card32('pixel'),
+ rq.Card16('red'),
+ rq.Card16('green'),
+ rq.Card16('blue'),
+ rq.Card8('flags'),
+ rq.Pad(1),
+ )
+
+
+RGB = rq.Struct(
+ rq.Card16('red'),
+ rq.Card16('green'),
+ rq.Card16('blue'),
+ rq.Pad(2),
+ )
+
+
+Point = rq.Struct(
+ rq.Int16('x'),
+ rq.Int16('y'),
+ )
+
+Segment = rq.Struct(
+ rq.Int16('x1'),
+ rq.Int16('y1'),
+ rq.Int16('x2'),
+ rq.Int16('y2'),
+ )
+
+Rectangle = rq.Struct(
+ rq.Int16('x'),
+ rq.Int16('y'),
+ rq.Card16('width'),
+ rq.Card16('height'),
+ )
+
+Arc = rq.Struct(
+ rq.Int16('x'),
+ rq.Int16('y'),
+ rq.Card16('width'),
+ rq.Card16('height'),
+ rq.Int16('angle1'),
+ rq.Int16('angle2'),
+ )
diff --git a/Xlib/rdb.py b/Xlib/rdb.py
new file mode 100644
index 0000000..57063dc
--- /dev/null
+++ b/Xlib/rdb.py
@@ -0,0 +1,706 @@
+# $Id: rdb.py,v 1.5 2007/06/10 14:11:58 mggrant Exp $
+#
+# Xlib.rdb -- X resource database implementation
+#
+# Copyright (C) 2000 Peter Liljenberg <petli@ctrl-c.liu.se>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+# See end of file for an explanation of the algorithm and
+# data structures used.
+
+
+# Standard modules
+import string
+import types
+import re
+import sys
+
+# Xlib modules
+from support import lock
+
+# Set up a few regexpes for parsing string representation of resources
+
+comment_re = re.compile(r'^\s*!')
+resource_spec_re = re.compile(r'^\s*([-_a-zA-Z0-9?.*]+)\s*:\s*(.*)$')
+value_escape_re = re.compile('\\\\([ \tn\\\\]|[0-7]{3,3})')
+resource_parts_re = re.compile(r'([.*]+)')
+
+# Constants used for determining which match is best
+
+NAME_MATCH = 0
+CLASS_MATCH = 2
+WILD_MATCH = 4
+MATCH_SKIP = 6
+
+# Option error class
+class OptionError(Exception):
+ pass
+
+
+class ResourceDB:
+ def __init__(self, file = None, string = None, resources = None):
+ self.db = {}
+ self.lock = lock.allocate_lock()
+
+ if file is not None:
+ self.insert_file(file)
+ if string is not None:
+ self.insert_string(string)
+ if resources is not None:
+ self.insert_resources(resources)
+
+ def insert_file(self, file):
+ """insert_file(file)
+
+ Load resources entries from FILE, and insert them into the
+ database. FILE can be a filename (a string)or a file object.
+
+ """
+
+ if type(file) is types.StringType:
+ file = open(file, 'r')
+
+ self.insert_string(file.read())
+
+
+ def insert_string(self, data):
+ """insert_string(data)
+
+ Insert the resources entries in the string DATA into the
+ database.
+
+ """
+
+ # First split string into lines
+ lines = string.split(data, '\n')
+
+ while lines:
+ line = lines[0]
+ del lines[0]
+
+ # Skip empty line
+ if not line:
+ continue
+
+ # Skip comments
+ if comment_re.match(line):
+ continue
+
+ # Handle continued lines
+ while line[-1] == '\\':
+ if lines:
+ line = line[:-1] + lines[0]
+ del lines[0]
+ else:
+ line = line[:-1]
+ break
+
+ # Split line into resource and value
+ m = resource_spec_re.match(line)
+
+ # Bad line, just ignore it silently
+ if not m:
+ continue
+
+ res, value = m.group(1, 2)
+
+ # Convert all escape sequences in value
+ splits = value_escape_re.split(value)
+
+ for i in range(1, len(splits), 2):
+ s = splits[i]
+ if len(s) == 3:
+ splits[i] = chr(string.atoi(s, 8))
+ elif s == 'n':
+ splits[i] = '\n'
+
+ # strip the last value part to get rid of any
+ # unescaped blanks
+ splits[-1] = string.rstrip(splits[-1])
+
+ value = string.join(splits, '')
+
+ self.insert(res, value)
+
+
+ def insert_resources(self, resources):
+ """insert_resources(resources)
+
+ Insert all resources entries in the list RESOURCES into the
+ database. Each element in RESOURCES should be a tuple:
+
+ (resource, value)
+
+ Where RESOURCE is a string and VALUE can be any Python value.
+
+ """
+
+ for res, value in resources:
+ self.insert(res, value)
+
+ def insert(self, resource, value):
+ """insert(resource, value)
+
+ Insert a resource entry into the database. RESOURCE is a
+ string and VALUE can be any Python value.
+
+ """
+
+ # Split res into components and bindings
+ parts = resource_parts_re.split(resource)
+
+ # If the last part is empty, this is an invalid resource
+ # which we simply ignore
+ if parts[-1] == '':
+ return
+
+ self.lock.acquire()
+
+ db = self.db
+ for i in range(1, len(parts), 2):
+
+ # Create a new mapping/value group
+ if not db.has_key(parts[i - 1]):
+ db[parts[i - 1]] = ({}, {})
+
+ # Use second mapping if a loose binding, first otherwise
+ if '*' in parts[i]:
+ db = db[parts[i - 1]][1]
+ else:
+ db = db[parts[i - 1]][0]
+
+ # Insert value into the derived db
+ if db.has_key(parts[-1]):
+ db[parts[-1]] = db[parts[-1]][:2] + (value, )
+ else:
+ db[parts[-1]] = ({}, {}, value)
+
+ self.lock.release()
+
+ def __getitem__(self, (name, cls)):
+ """db[name, class]
+
+ Return the value matching the resource identified by NAME and
+ CLASS. If no match is found, KeyError is raised.
+ """
+
+ # Split name and class into their parts
+
+ namep = string.split(name, '.')
+ clsp = string.split(cls, '.')
+
+ # It is an error for name and class to have different number
+ # of parts
+
+ if len(namep) != len(clsp):
+ raise ValueError('Different number of parts in resource name/class: %s/%s' % (name, cls))
+
+ complen = len(namep)
+ matches = []
+
+ # Lock database and wrap the lookup code in a try-finally
+ # block to make sure that it is unlocked.
+
+ self.lock.acquire()
+ try:
+
+ # Precedence order: name -> class -> ?
+
+ if self.db.has_key(namep[0]):
+ bin_insert(matches, _Match((NAME_MATCH, ), self.db[namep[0]]))
+
+ if self.db.has_key(clsp[0]):
+ bin_insert(matches, _Match((CLASS_MATCH, ), self.db[clsp[0]]))
+
+ if self.db.has_key('?'):
+ bin_insert(matches, _Match((WILD_MATCH, ), self.db['?']))
+
+
+ # Special case for the unlikely event that the resource
+ # only has one component
+ if complen == 1 and matches:
+ x = matches[0]
+ if x.final(complen):
+ return x.value()
+ else:
+ raise KeyError((name, cls))
+
+
+ # Special case for resources which begins with a loose
+ # binding, e.g. '*foo.bar'
+ if self.db.has_key(''):
+ bin_insert(matches, _Match((), self.db[''][1]))
+
+
+ # Now iterate over all components until we find the best match.
+
+ # For each component, we choose the best partial match among
+ # the mappings by applying these rules in order:
+
+ # Rule 1: If the current group contains a match for the
+ # name, class or '?', we drop all previously found loose
+ # binding mappings.
+
+ # Rule 2: A matching name has precedence over a matching
+ # class, which in turn has precedence over '?'.
+
+ # Rule 3: Tight bindings have precedence over loose
+ # bindings.
+
+ while matches:
+
+ # Work on the first element == the best current match
+
+ x = matches[0]
+ del matches[0]
+
+ # print 'path: ', x.path
+ # if x.skip:
+ # print 'skip: ', x.db
+ # else:
+ # print 'group: ', x.group
+ # print
+
+ i = x.match_length()
+
+ for part, score in ((namep[i], NAME_MATCH),
+ (clsp[i], CLASS_MATCH),
+ ('?', WILD_MATCH)):
+
+ # Attempt to find a match in x
+ match = x.match(part, score)
+ if match:
+ # Hey, we actually found a value!
+ if match.final(complen):
+ return match.value()
+
+ # Else just insert the new match
+ else:
+ bin_insert(matches, match)
+
+ # Generate a new loose match
+ match = x.skip_match(complen)
+ if match:
+ bin_insert(matches, match)
+
+ # Oh well, nothing matched
+ raise KeyError((name, cls))
+
+ finally:
+ self.lock.release()
+
+ def get(self, res, cls, default = None):
+ """get(name, class [, default])
+
+ Return the value matching the resource identified by NAME and
+ CLASS. If no match is found, DEFAULT is returned, or None if
+ DEFAULT isn't specified.
+
+ """
+
+ try:
+ return self[(res, cls)]
+ except KeyError:
+ return default
+
+ def update(self, db):
+ """update(db)
+
+ Update this database with all resources entries in the resource
+ database DB.
+
+ """
+
+ self.lock.acquire()
+ update_db(self.db, db.db)
+ self.lock.release()
+
+ def output(self):
+ """output()
+
+ Return the resource database in text representation.
+ """
+
+ self.lock.acquire()
+ text = output_db('', self.db)
+ self.lock.release()
+ return text
+
+ def getopt(self, name, argv, opts):
+ """getopt(name, argv, opts)
+
+ Parse X command line options, inserting the recognised options
+ into the resource database.
+
+ NAME is the application name, and will be prepended to all
+ specifiers. ARGV is the list of command line arguments,
+ typically sys.argv[1:].
+
+ OPTS is a mapping of options to resource specifiers. The key is
+ the option flag (with leading -), and the value is an instance of
+ some Option subclass:
+
+ NoArg(specifier, value): set resource to value.
+ IsArg(specifier): set resource to option itself
+ SepArg(specifier): value is next argument
+ ResArg: resource and value in next argument
+ SkipArg: ignore this option and next argument
+ SkipLine: ignore rest of arguments
+ SkipNArgs(count): ignore this option and count arguments
+
+ The remaining, non-option, oparguments is returned.
+
+ rdb.OptionError is raised if there is an error in the argument list.
+ """
+
+ while argv and argv[0] and argv[0][0] == '-':
+ try:
+ argv = opts[argv[0]].parse(name, self, argv)
+ except KeyError:
+ raise OptionError('unknown option: %s' % argv[0])
+ except IndexError:
+ raise OptionError('missing argument to option: %s' % argv[0])
+
+ return argv
+
+
+class _Match:
+ def __init__(self, path, dbs):
+ self.path = path
+
+ if type(dbs) is types.TupleType:
+ self.skip = 0
+ self.group = dbs
+
+ else:
+ self.skip = 1
+ self.db = dbs
+
+ def __cmp__(self, other):
+ return cmp(self.path, other.path)
+
+ def match_length(self):
+ return len(self.path)
+
+ def match(self, part, score):
+ if self.skip:
+ if self.db.has_key(part):
+ return _Match(self.path + (score, ), self.db[part])
+ else:
+ return None
+ else:
+ if self.group[0].has_key(part):
+ return _Match(self.path + (score, ), self.group[0][part])
+ elif self.group[1].has_key(part):
+ return _Match(self.path + (score + 1, ), self.group[1][part])
+ else:
+ return None
+
+ def skip_match(self, complen):
+ # Can't make another skip if we have run out of components
+ if len(self.path) + 1 >= complen:
+ return None
+
+ # If this already is a skip match, clone a new one
+ if self.skip:
+ if self.db:
+ return _Match(self.path + (MATCH_SKIP, ), self.db)
+ else:
+ return None
+
+ # Only generate a skip match if the loose binding mapping
+ # is non-empty
+ elif self.group[1]:
+ return _Match(self.path + (MATCH_SKIP, ), self.group[1])
+
+ # This is a dead end match
+ else:
+ return None
+
+ def final(self, complen):
+ if not self.skip and len(self.path) == complen and len(self.group) > 2:
+ return 1
+ else:
+ return 0
+
+ def value(self):
+ return self.group[2]
+
+
+#
+# Helper function for ResourceDB.__getitem__()
+#
+
+def bin_insert(list, element):
+ """bin_insert(list, element)
+
+ Insert ELEMENT into LIST. LIST must be sorted, and ELEMENT will
+ be inserted to that LIST remains sorted. If LIST already contains
+ ELEMENT, it will not be duplicated.
+
+ """
+
+ if not list:
+ list.append(element)
+ return
+
+ lower = 0
+ upper = len(list) - 1
+
+ while lower <= upper:
+ center = (lower + upper) / 2
+ if element < list[center]:
+ upper = center - 1
+ elif element > list[center]:
+ lower = center + 1
+ elif element == list[center]:
+ return
+
+ if element < list[upper]:
+ list.insert(upper, element)
+ elif element > list[upper]:
+ list.insert(upper + 1, element)
+
+
+#
+# Helper functions for ResourceDB.update()
+#
+
+def update_db(dest, src):
+ for comp, group in src.items():
+
+ # DEST already contains this component, update it
+ if dest.has_key(comp):
+
+ # Update tight and loose binding databases
+ update_db(dest[comp][0], group[0])
+ update_db(dest[comp][1], group[1])
+
+ # If a value has been set in SRC, update
+ # value in DEST
+
+ if len(group) > 2:
+ dest[comp] = dest[comp][:2] + group[2:]
+
+ # COMP not in src, make a deep copy
+ else:
+ dest[comp] = copy_group(group)
+
+def copy_group(group):
+ return (copy_db(group[0]), copy_db(group[1])) + group[2:]
+
+def copy_db(db):
+ newdb = {}
+ for comp, group in db.items():
+ newdb[comp] = copy_group(group)
+
+ return newdb
+
+
+#
+# Helper functions for output
+#
+
+def output_db(prefix, db):
+ res = ''
+ for comp, group in db.items():
+
+ # There's a value for this component
+ if len(group) > 2:
+ res = res + '%s%s: %s\n' % (prefix, comp, output_escape(group[2]))
+
+ # Output tight and loose bindings
+ res = res + output_db(prefix + comp + '.', group[0])
+ res = res + output_db(prefix + comp + '*', group[1])
+
+ return res
+
+def output_escape(value):
+ value = str(value)
+ if not value:
+ return value
+
+ for char, esc in (('\\', '\\\\'),
+ ('\000', '\\000'),
+ ('\n', '\\n')):
+
+ value = string.replace(value, char, esc)
+
+ # If first or last character is space or tab, escape them.
+ if value[0] in ' \t':
+ value = '\\' + value
+ if value[-1] in ' \t' and value[-2:-1] != '\\':
+ value = value[:-1] + '\\' + value[-1]
+
+ return value
+
+
+#
+# Option type definitions
+#
+
+class Option:
+ def __init__(self):
+ pass
+
+ def parse(self, name, db, args):
+ pass
+
+class NoArg(Option):
+ """Value is provided to constructor."""
+ def __init__(self, specifier, value):
+ self.specifier = specifier
+ self.value = value
+
+ def parse(self, name, db, args):
+ db.insert(name + self.specifier, self.value)
+ return args[1:]
+
+class IsArg(Option):
+ """Value is the option string itself."""
+ def __init__(self, specifier):
+ self.specifier = specifier
+
+ def parse(self, name, db, args):
+ db.insert(name + self.specifier, args[0])
+ return args[1:]
+
+class SepArg(Option):
+ """Value is the next argument."""
+ def __init__(self, specifier):
+ self.specifier = specifier
+
+ def parse(self, name, db, args):
+ db.insert(name + self.specifier, args[1])
+ return args[2:]
+
+class ResArgClass(Option):
+ """Resource and value in the next argument."""
+ def parse(self, name, db, args):
+ db.insert_string(args[1])
+ return args[2:]
+
+ResArg = ResArgClass()
+
+class SkipArgClass(Option):
+ """Ignore this option and next argument."""
+ def parse(self, name, db, args):
+ return args[2:]
+
+SkipArg = SkipArgClass()
+
+class SkipLineClass(Option):
+ """Ignore rest of the arguments."""
+ def parse(self, name, db, args):
+ return []
+
+SkipLine = SkipLineClass()
+
+class SkipNArgs(Option):
+ """Ignore this option and the next COUNT arguments."""
+ def __init__(self, count):
+ self.count = count
+
+ def parse(self, name, db, args):
+ return args[1 + self.count:]
+
+
+
+def get_display_opts(options, argv = sys.argv):
+ """display, name, db, args = get_display_opts(options, [argv])
+
+ Parse X OPTIONS from ARGV (or sys.argv if not provided).
+
+ Connect to the display specified by a *.display resource if one is
+ set, or to the default X display otherwise. Extract the
+ RESOURCE_MANAGER property and insert all resources from ARGV.
+
+ The four return values are:
+ DISPLAY -- the display object
+ NAME -- the application name (the filname of ARGV[0])
+ DB -- the created resource database
+ ARGS -- any remaining arguments
+ """
+
+ from Xlib import display, Xatom
+ import os
+
+ name = os.path.splitext(os.path.basename(argv[0]))[0]
+
+ optdb = ResourceDB()
+ leftargv = optdb.getopt(name, argv[1:], options)
+
+ dname = optdb.get(name + '.display', name + '.Display', None)
+ d = display.Display(dname)
+
+ rdbstring = d.screen(0).root.get_full_property(Xatom.RESOURCE_MANAGER,
+ Xatom.STRING)
+ if rdbstring:
+ data = rdbstring.value
+ else:
+ data = None
+
+ db = ResourceDB(string = data)
+ db.update(optdb)
+
+ return d, name, db, leftargv
+
+
+# Common X options
+stdopts = {'-bg': SepArg('*background'),
+ '-background': SepArg('*background'),
+ '-fg': SepArg('*foreground'),
+ '-foreground': SepArg('*foreground'),
+ '-fn': SepArg('*font'),
+ '-font': SepArg('*font'),
+ '-name': SepArg('.name'),
+ '-title': SepArg('.title'),
+ '-synchronous': NoArg('*synchronous', 'on'),
+ '-xrm': ResArg,
+ '-display': SepArg('.display'),
+ '-d': SepArg('.display'),
+ }
+
+
+# Notes on the implementation:
+
+# Resource names are split into their components, and each component
+# is stored in a mapping. The value for a component is a tuple of two
+# or three elements:
+
+# (tightmapping, loosemapping [, value])
+
+# tightmapping contains the next components which are connected with a
+# tight binding (.). loosemapping contains the ones connected with
+# loose binding (*). If value is present, then this component is the
+# last component for some resource which that value.
+
+# The top level components are stored in the mapping r.db, where r is
+# the resource object.
+
+# Example: Inserting "foo.bar*gazonk: yep" into an otherwise empty
+# resource database would give the folliwing structure:
+
+# { 'foo': ( { 'bar': ( { },
+# { 'gazonk': ( { },
+# { },
+# 'yep')
+# }
+# )
+# },
+# {})
+# }
diff --git a/Xlib/support/__init__.py b/Xlib/support/__init__.py
new file mode 100644
index 0000000..39c32f7
--- /dev/null
+++ b/Xlib/support/__init__.py
@@ -0,0 +1,25 @@
+# $Id: __init__.py,v 1.3 2001/01/12 11:05:03 petli Exp $
+#
+# Xlib.support.__init__ -- support code package
+#
+# Copyright (C) 2000 Peter Liljenberg <petli@ctrl-c.liu.se>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+__all__ = [
+ 'lock',
+ 'connect'
+ # The platform specific modules should not be listed here
+ ]
diff --git a/Xlib/support/connect.py b/Xlib/support/connect.py
new file mode 100644
index 0000000..27ab8a6
--- /dev/null
+++ b/Xlib/support/connect.py
@@ -0,0 +1,96 @@
+# $Id: connect.py,v 1.3 2007/06/10 14:11:58 mggrant Exp $
+#
+# Xlib.support.connect -- OS-independent display connection functions
+#
+# Copyright (C) 2000 Peter Liljenberg <petli@ctrl-c.liu.se>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+import sys
+import string
+
+# List the modules which contain the corresponding functions
+
+_display_mods = {
+ 'OpenVMS': 'vms_connect',
+ }
+
+_default_display_mod = 'unix_connect'
+
+_socket_mods = {
+ 'OpenVMS': 'vms_connect'
+ }
+
+_default_socket_mod = 'unix_connect'
+
+_auth_mods = {
+ 'OpenVMS': 'vms_connect'
+ }
+
+_default_auth_mod = 'unix_connect'
+
+
+# Figure out which OS we're using.
+# sys.platform is either "OS-ARCH" or just "OS".
+
+_parts = string.split(sys.platform, '-')
+platform = _parts[0]
+del _parts
+
+
+def get_display(display):
+ """dname, host, dno, screen = get_display(display)
+
+ Parse DISPLAY into its components. If DISPLAY is None, use
+ the default display. The return values are:
+
+ DNAME -- the full display name (string)
+ HOST -- the host name (string, possibly empty)
+ DNO -- display number (integer)
+ SCREEN -- default screen number (integer)
+ """
+
+ modname = _display_mods.get(platform, _default_display_mod)
+ mod = __import__(modname, globals())
+ return mod.get_display(display)
+
+
+def get_socket(dname, host, dno):
+ """socket = get_socket(dname, host, dno)
+
+ Connect to the display specified by DNAME, HOST and DNO, which
+ are the corresponding values from a previous call to get_display().
+
+ Return SOCKET, a new socket object connected to the X server.
+ """
+
+ modname = _socket_mods.get(platform, _default_socket_mod)
+ mod = __import__(modname, globals())
+ return mod.get_socket(dname, host, dno)
+
+
+def get_auth(sock, dname, host, dno):
+ """auth_name, auth_data = get_auth(sock, dname, host, dno)
+
+ Return authentication data for the display on the other side of
+ SOCK, which was opened with DNAME, HOST and DNO.
+
+ Return AUTH_NAME and AUTH_DATA, two strings to be used in the
+ connection setup request.
+ """
+
+ modname = _auth_mods.get(platform, _default_auth_mod)
+ mod = __import__(modname, globals())
+ return mod.get_auth(sock, dname, host, dno)
diff --git a/Xlib/support/lock.py b/Xlib/support/lock.py
new file mode 100644
index 0000000..b49c177
--- /dev/null
+++ b/Xlib/support/lock.py
@@ -0,0 +1,43 @@
+# $Id: lock.py,v 1.2 2007/06/10 14:11:58 mggrant Exp $
+#
+# Xlib.support.lock -- allocate a lock
+#
+# Copyright (C) 2000 Peter Liljenberg <petli@ctrl-c.liu.se>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+class _DummyLock:
+ def __init__(self):
+
+ # This might be nerdy, but by assigning methods like this
+ # instead of defining them all, we create a single bound
+ # method object once instead of one each time one of the
+ # methods is called.
+
+ # This gives some speed improvements which should reduce the
+ # impact of the threading infrastructure in the regular code,
+ # when not using threading.
+
+ self.acquire = self.release = self.locked = self.__noop
+
+ def __noop(self, *args):
+ return
+
+
+# More optimisations: we use a single lock for all lock instances
+_dummy_lock = _DummyLock()
+
+def allocate_lock():
+ return _dummy_lock
diff --git a/Xlib/support/unix_connect.py b/Xlib/support/unix_connect.py
new file mode 100644
index 0000000..3753124
--- /dev/null
+++ b/Xlib/support/unix_connect.py
@@ -0,0 +1,149 @@
+# $Id: unix_connect.py,v 1.5 2007/06/10 14:11:58 mggrant Exp $
+#
+# Xlib.support.unix_connect -- Unix-type display connection functions
+#
+# Copyright (C) 2000,2002 Peter Liljenberg <petli@ctrl-c.liu.se>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+import re
+import string
+import os
+import socket
+
+# FCNTL is deprecated from Python 2.2, so only import it if we doesn't
+# get the names we need. Furthermore, FD_CLOEXEC seems to be missing
+# in Python 2.2.
+
+import fcntl
+
+if hasattr(fcntl, 'F_SETFD'):
+ F_SETFD = fcntl.F_SETFD
+ if hasattr(fcntl, 'FD_CLOEXEC'):
+ FD_CLOEXEC = fcntl.FD_CLOEXEC
+ else:
+ FD_CLOEXEC = 1
+else:
+ from FCNTL import F_SETFD, FD_CLOEXEC
+
+
+from Xlib import error, xauth
+
+display_re = re.compile(r'^([-a-zA-Z0-9._]*):([0-9]+)(\.([0-9]+))?$')
+
+def get_display(display):
+ # Use $DISPLAY if display isn't provided
+ if display is None:
+ display = os.environ.get('DISPLAY', '')
+
+ m = display_re.match(display)
+ if not m:
+ raise error.DisplayNameError(display)
+
+ name = display
+ host = m.group(1)
+ dno = int(m.group(2))
+ screen = m.group(4)
+ if screen:
+ screen = int(screen)
+ else:
+ screen = 0
+
+ return name, host, dno, screen
+
+
+def get_socket(dname, host, dno):
+ try:
+ # If hostname (or IP) is provided, use TCP socket
+ if host:
+ s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ s.connect((host, 6000 + dno))
+
+ # Else use Unix socket
+ else:
+ s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
+ s.connect('/tmp/.X11-unix/X%d' % dno)
+ except socket.error, val:
+ raise error.DisplayConnectionError(dname, str(val))
+
+ # Make sure that the connection isn't inherited in child processes
+ fcntl.fcntl(s.fileno(), F_SETFD, FD_CLOEXEC)
+
+ return s
+
+
+def new_get_auth(sock, dname, host, dno):
+ # Translate socket address into the xauth domain
+ if host:
+ family = xauth.FamilyInternet
+
+ # Convert the prettyprinted IP number into 4-octet string.
+ # Sometimes these modules are too damn smart...
+ octets = string.split(sock.getpeername()[0], '.')
+ addr = string.join(map(lambda x: chr(int(x)), octets), '')
+ else:
+ family = xauth.FamilyLocal
+ addr = socket.gethostname()
+
+ au = xauth.Xauthority()
+ while 1:
+ try:
+ return au.get_best_auth(family, addr, dno)
+ except error.XNoAuthError:
+ pass
+
+ # We need to do this to handle ssh's X forwarding. It sets
+ # $DISPLAY to localhost:10, but stores the xauth cookie as if
+ # DISPLAY was :10. Hence, if localhost and not found, try
+ # again as a Unix socket.
+ if family == xauth.FamilyInternet and addr == '\x7f\x00\x00\x01':
+ family = xauth.FamilyLocal
+ addr = socket.gethostname()
+ else:
+ return '', ''
+
+
+def old_get_auth(sock, dname, host, dno):
+ # Find authorization cookie
+ auth_name = auth_data = ''
+
+ try:
+ # We could parse .Xauthority, but xauth is simpler
+ # although more inefficient
+ data = os.popen('xauth list %s 2>/dev/null' % dname).read()
+
+ # If there's a cookie, it is of the format
+ # DISPLAY SCHEME COOKIE
+ # We're interested in the two last parts for the
+ # connection establishment
+ lines = string.split(data, '\n')
+ if len(lines) >= 1:
+ parts = string.split(lines[0], None, 2)
+ if len(parts) == 3:
+ auth_name = parts[1]
+ hexauth = parts[2]
+ auth = ''
+
+ # Translate hexcode into binary
+ for i in range(0, len(hexauth), 2):
+ auth = auth + chr(string.atoi(hexauth[i:i+2], 16))
+
+ auth_data = auth
+ except os.error:
+ pass
+
+ return auth_name, auth_data
+
+get_auth = new_get_auth
diff --git a/Xlib/support/vms_connect.py b/Xlib/support/vms_connect.py
new file mode 100644
index 0000000..f9eecbb
--- /dev/null
+++ b/Xlib/support/vms_connect.py
@@ -0,0 +1,73 @@
+# $Id: vms_connect.py,v 1.3 2007/06/10 14:11:58 mggrant Exp $
+#
+# Xlib.support.vms_connect -- VMS-type display connection functions
+#
+# Copyright (C) 2000 Peter Liljenberg <petli@ctrl-c.liu.se>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+import re
+import socket
+
+from Xlib import error
+
+display_re = re.compile(r'^([-a-zA-Z0-9._]*):([0-9]+)(\.([0-9]+))?$')
+
+def get_display(display):
+
+ # Use dummy display if none is set. We really should
+ # check DECW$DISPLAY instead, but that has to wait
+
+ if display is None:
+ return ':0.0', 'localhost', 0, 0
+
+ m = display_re.match(display)
+ if not m:
+ raise error.DisplayNameError(display)
+
+ name = display
+
+ # Always return a host, since we don't have AF_UNIX sockets
+ host = m.group(1)
+ if not host:
+ host = 'localhost'
+
+ dno = int(m.group(2))
+ screen = m.group(4)
+ if screen:
+ screen = int(screen)
+ else:
+ screen = 0
+
+ return name, host, dno, screen
+
+
+def get_socket(dname, host, dno):
+ try:
+ # Always use TCP/IP sockets. Later it would be nice to
+ # be able to use DECNET och LOCAL connections.
+
+ s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ s.connect((host, 6000 + dno))
+
+ except socket.error, val:
+ raise error.DisplayConnectionError(dname, str(val))
+
+ return s
+
+
+def get_auth(sock, dname, host, dno):
+ # VMS doesn't have xauth
+ return '', ''
diff --git a/Xlib/threaded.py b/Xlib/threaded.py
new file mode 100644
index 0000000..b9079f4
--- /dev/null
+++ b/Xlib/threaded.py
@@ -0,0 +1,27 @@
+# $Id: threaded.py,v 1.2 2007/06/10 14:11:58 mggrant Exp $
+#
+# Xlib.threaded -- Import this module to enable threading
+#
+# Copyright (C) 2000 Peter Liljenberg <petli@ctrl-c.liu.se>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+import thread
+
+# We change the allocate_lock function in Xlib.support.lock to
+# return a basic Python lock, instead of the default dummy lock
+
+from Xlib.support import lock
+lock.allocate_lock = thread.allocate_lock
diff --git a/Xlib/xauth.py b/Xlib/xauth.py
new file mode 100644
index 0000000..4755b35
--- /dev/null
+++ b/Xlib/xauth.py
@@ -0,0 +1,129 @@
+# $Id: xauth.py,v 1.5 2007/06/10 14:11:58 mggrant Exp $
+#
+# Xlib.xauth -- ~/.Xauthority access
+#
+# Copyright (C) 2000 Peter Liljenberg <petli@ctrl-c.liu.se>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+import os
+import struct
+
+from Xlib import X, error
+
+FamilyInternet = X.FamilyInternet
+FamilyDECnet = X.FamilyDECnet
+FamilyChaos = X.FamilyChaos
+FamilyLocal = 256
+
+class Xauthority:
+ def __init__(self, filename = None):
+ if filename is None:
+ filename = os.environ.get('XAUTHORITY')
+
+ if filename is None:
+ try:
+ filename = os.path.join(os.environ['HOME'], '.Xauthority')
+ except KeyError:
+ raise error.XauthError(
+ '$HOME not set, cannot find ~/.Xauthority')
+
+ try:
+ raw = open(filename, 'rb').read()
+ except IOError, err:
+ raise error.XauthError('~/.Xauthority: %s' % err)
+
+ self.entries = []
+
+ # entry format (all shorts in big-endian)
+ # short family;
+ # short addrlen;
+ # char addr[addrlen];
+ # short numlen;
+ # char num[numlen];
+ # short namelen;
+ # char name[namelen];
+ # short datalen;
+ # char data[datalen];
+
+ n = 0
+ try:
+ while n < len(raw):
+ family, = struct.unpack('>H', raw[n:n+2])
+ n = n + 2
+
+ length, = struct.unpack('>H', raw[n:n+2])
+ n = n + length + 2
+ addr = raw[n - length : n]
+
+ length, = struct.unpack('>H', raw[n:n+2])
+ n = n + length + 2
+ num = raw[n - length : n]
+
+ length, = struct.unpack('>H', raw[n:n+2])
+ n = n + length + 2
+ name = raw[n - length : n]
+
+ length, = struct.unpack('>H', raw[n:n+2])
+ n = n + length + 2
+ data = raw[n - length : n]
+
+ if len(data) != length:
+ break
+
+ self.entries.append((family, addr, num, name, data))
+ except struct.error, e:
+ print "Xlib.xauth: warning, failed to parse part of xauthority file (%s), aborting all further parsing" % filename
+ #pass
+
+ if len(self.entries) == 0:
+ print "Xlib.xauth: warning, no xauthority details available"
+ # raise an error? this should get partially caught by the XNoAuthError in get_best_auth..
+
+ def __len__(self):
+ return len(self.entries)
+
+ def __getitem__(self, i):
+ return self.entries[i]
+
+ def get_best_auth(self, family, address, dispno,
+ types = ( "MIT-MAGIC-COOKIE-1", )):
+
+ """Find an authentication entry matching FAMILY, ADDRESS and
+ DISPNO.
+
+ The name of the auth scheme must match one of the names in
+ TYPES. If several entries match, the first scheme in TYPES
+ will be choosen.
+
+ If an entry is found, the tuple (name, data) is returned,
+ otherwise XNoAuthError is raised.
+ """
+
+ num = str(dispno)
+
+ matches = {}
+
+ for efam, eaddr, enum, ename, edata in self.entries:
+ if efam == family and eaddr == address and num == enum:
+ matches[ename] = edata
+
+ for t in types:
+ try:
+ return (t, matches[t])
+ except KeyError:
+ pass
+
+ raise error.XNoAuthError((family, address, dispno))
diff --git a/Xlib/xobject/__init__.py b/Xlib/xobject/__init__.py
new file mode 100644
index 0000000..1e284da
--- /dev/null
+++ b/Xlib/xobject/__init__.py
@@ -0,0 +1,28 @@
+# $Id: __init__.py,v 1.3 2000/10/04 08:15:57 petli Exp $
+#
+# Xlib.xobject.__init__ -- glue for Xlib.xobject package
+#
+# Copyright (C) 2000 Peter Liljenberg <petli@ctrl-c.liu.se>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+__all__ = [
+ 'colormap',
+ 'cursor',
+ 'drawable',
+ 'fontable',
+ 'icccm',
+ 'resource',
+ ]
diff --git a/Xlib/xobject/colormap.py b/Xlib/xobject/colormap.py
new file mode 100644
index 0000000..b1764fe
--- /dev/null
+++ b/Xlib/xobject/colormap.py
@@ -0,0 +1,141 @@
+# $Id: colormap.py,v 1.6 2007/06/10 14:11:59 mggrant Exp $
+#
+# Xlib.xobject.colormap -- colormap object
+#
+# Copyright (C) 2000 Peter Liljenberg <petli@ctrl-c.liu.se>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+from Xlib import error
+from Xlib.protocol import request
+
+import resource
+
+import re
+import string
+
+rgb_res = [
+ re.compile(r'\Argb:([0-9a-fA-F]{1,4})/([0-9a-fA-F]{1,4})/([0-9a-fA-F]{1,4})\Z'),
+ re.compile(r'\A#([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])\Z'),
+ re.compile(r'\A#([0-9a-fA-F][0-9a-fA-F])([0-9a-fA-F][0-9a-fA-F])([0-9a-fA-F][0-9a-fA-F])\Z'),
+ re.compile(r'\A#([0-9a-fA-F][0-9a-fA-F][0-9a-fA-F])([0-9a-fA-F][0-9a-fA-F][0-9a-fA-F])([0-9a-fA-F][0-9a-fA-F][0-9a-fA-F])\Z'),
+ re.compile(r'\A#([0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F])([0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F])([0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F])\Z'),
+ ]
+
+class Colormap(resource.Resource):
+ __colormap__ = resource.Resource.__resource__
+
+ def free(self, onerror = None):
+ request.FreeColormap(display = self.display,
+ onerror = onerror,
+ cmap = self.id)
+
+ self.display.free_resource_id(self.id)
+
+ def copy_colormap_and_free(self, scr_cmap):
+ mid = self.display.allocate_resource_id()
+ request.CopyColormapAndFree(display = self.display,
+ mid = mid,
+ src_cmap = src_cmap)
+
+ cls = self.display.get_resource_class('colormap', Colormap)
+ return cls(self.display, mid, owner = 1)
+
+ def install_colormap(self, onerror = None):
+ request.InstallColormap(display = self.display,
+ onerror = onerror,
+ cmap = self.id)
+
+ def uninstall_colormap(self, onerror = None):
+ request.UninstallColormap(display = self.display,
+ onerror = onerror,
+ cmap = self.id)
+
+ def alloc_color(self, red, green, blue):
+ return request.AllocColor(display = self.display,
+ cmap = self.id,
+ red = red,
+ green = green,
+ blue = blue)
+
+ def alloc_named_color(self, name):
+ for r in rgb_res:
+ m = r.match(name)
+ if m:
+ rs = m.group(1)
+ r = string.atoi(rs + '0' * (4 - len(rs)), 16)
+
+ gs = m.group(2)
+ g = string.atoi(gs + '0' * (4 - len(gs)), 16)
+
+ bs = m.group(3)
+ b = string.atoi(bs + '0' * (4 - len(bs)), 16)
+
+ return self.alloc_color(r, g, b)
+
+ try:
+ return request.AllocNamedColor(display = self.display,
+ cmap = self.id,
+ name = name)
+ except error.BadName:
+ return None
+
+ def alloc_color_cells(self, contiguous, colors, planes):
+ return request.AllocColorCells(display = self.display,
+ contiguous = contiguous,
+ cmap = self.id,
+ colors = colors,
+ planes = planes)
+
+ def alloc_color_planes(self, contiguous, colors, red, green, blue):
+ return request.AllocColorPlanes(display = self.display,
+ contiguous = contiguous,
+ cmap = self.id,
+ colors = colors,
+ red = red,
+ green = green,
+ blue = blue)
+
+ def free_colors(self, pixels, plane_mask, onerror = None):
+ request.FreeColors(display = self.display,
+ onerror = onerror,
+ cmap = self.id,
+ plane_mask = plane_mask,
+ pixels = pixels)
+
+ def store_colors(self, items, onerror = None):
+ request.StoreColors(display = self.display,
+ onerror = onerror,
+ cmap = self.id,
+ items = items)
+
+ def store_named_color(self, name, pixel, flags, onerror = None):
+ request.StoreNamedColor(display = self.display,
+ onerror = onerror,
+ flags = flags,
+ cmap = self.id,
+ pixel = pixel,
+ name = name)
+
+ def query_colors(self, pixels):
+ r = request.QueryColors(display = self.display,
+ cmap = self.id,
+ pixels = pixels)
+ return r.colors
+
+ def lookup_color(self, name):
+ return request.LookupColor(display = self.display,
+ cmap = self.id,
+ name = name)
diff --git a/Xlib/xobject/cursor.py b/Xlib/xobject/cursor.py
new file mode 100644
index 0000000..5a99cfd
--- /dev/null
+++ b/Xlib/xobject/cursor.py
@@ -0,0 +1,45 @@
+# $Id: cursor.py,v 1.4 2007/06/10 14:11:59 mggrant Exp $
+#
+# Xlib.xobject.cursor -- cursor object
+#
+# Copyright (C) 2000 Peter Liljenberg <petli@ctrl-c.liu.se>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+from Xlib.protocol import request
+
+import resource
+
+class Cursor(resource.Resource):
+ __cursor__ = resource.Resource.__resource__
+
+ def free(self, onerror = None):
+ request.FreeCursor(display = self.display,
+ onerror = onerror,
+ cursor = self.id)
+ self.display.free_resource_id(self.id)
+
+ def recolor(self, (fore_red, fore_green, fore_blue),
+ (back_red, back_green, back_blue), onerror = None):
+
+ request.RecolorCursor(display = self.display,
+ onerror = onerror,
+ cursor = self.id,
+ fore_red = fore_red,
+ fore_green = fore_green,
+ fore_blue = fore_blue,
+ back_red = back_red,
+ back_green = back_green,
+ back_blue = back_blue)
diff --git a/Xlib/xobject/drawable.py b/Xlib/xobject/drawable.py
new file mode 100644
index 0000000..334bc92
--- /dev/null
+++ b/Xlib/xobject/drawable.py
@@ -0,0 +1,824 @@
+# $Id: drawable.py,v 1.15 2007/06/10 14:11:59 mggrant Exp $
+#
+# Xlib.xobject.drawable -- drawable objects (window and pixmap)
+#
+# Copyright (C) 2000 Peter Liljenberg <petli@ctrl-c.liu.se>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+import string
+
+from Xlib import X, Xatom, Xutil
+from Xlib.protocol import request, rq
+
+# Other X resource objects
+import resource
+import colormap
+import cursor
+import fontable
+
+# Inter-client communication conventions
+import icccm
+
+class Drawable(resource.Resource):
+ __drawable__ = resource.Resource.__resource__
+
+ def get_geometry(self):
+ return request.GetGeometry(display = self.display,
+ drawable = self)
+
+ def create_pixmap(self, width, height, depth):
+ pid = self.display.allocate_resource_id()
+ request.CreatePixmap(display = self.display,
+ depth = depth,
+ pid = pid,
+ drawable = self.id,
+ width = width,
+ height = height)
+
+ cls = self.display.get_resource_class('pixmap', Pixmap)
+ return cls(self.display, pid, owner = 1)
+
+ def create_gc(self, **keys):
+ cid = self.display.allocate_resource_id()
+ request.CreateGC(display = self.display,
+ cid = cid,
+ drawable = self.id,
+ attrs = keys)
+
+ cls = self.display.get_resource_class('gc', fontable.GC)
+ return cls(self.display, cid, owner = 1)
+
+ def copy_area(self, gc, src_drawable, src_x, src_y, width, height, dst_x, dst_y, onerror = None):
+ request.CopyArea(display = self.display,
+ onerror = onerror,
+ src_drawable = src_drawable,
+ dst_drawable = self.id,
+ gc = gc,
+ src_x = src_x,
+ src_y = src_y,
+ dst_x = dst_x,
+ dst_y = dst_y,
+ width = width,
+ height = height)
+
+ def copy_plane(self, gc, src_drawable, src_x, src_y, width, height,
+ dst_x, dst_y, bit_plane, onerror = None):
+ request.CopyPlane(display = self.display,
+ onerror = onerror,
+ src_drawable = src_drawable,
+ dst_drawable = self.id,
+ gc = gc,
+ src_x = src_x,
+ src_y = src_y,
+ dst_x = dst_x,
+ dst_y = dst_y,
+ width = width,
+ height = height,
+ bit_plane = bit_plane)
+
+ def poly_point(self, gc, coord_mode, points, onerror = None):
+ request.PolyPoint(display = self.display,
+ onerror = onerror,
+ coord_mode = coord_mode,
+ drawable = self.id,
+ gc = gc,
+ points = points)
+
+ def point(self, gc, x, y, onerror = None):
+ request.PolyPoint(display = self.display,
+ onerror = onerror,
+ coord_mode = X.CoordModeOrigin,
+ drawable = self.id,
+ gc = gc,
+ points = [(x, y)])
+
+ def poly_line(self, gc, coord_mode, points, onerror = None):
+ request.PolyLine(display = self.display,
+ onerror = onerror,
+ coord_mode = coord_mode,
+ drawable = self.id,
+ gc = gc,
+ points = points)
+
+ def line(self, gc, x1, y1, x2, y2, onerror = None):
+ request.PolySegment(display = self.display,
+ onerror = onerror,
+ drawable = self.id,
+ gc = gc,
+ segments = [(x1, y1, x2, y2)])
+
+ def poly_segment(self, gc, segments, onerror = None):
+ request.PolySegment(display = self.display,
+ onerror = onerror,
+ drawable = self.id,
+ gc = gc,
+ segments = segments)
+
+ def poly_rectangle(self, gc, rectangles, onerror = None):
+ request.PolyRectangle(display = self.display,
+ onerror = onerror,
+ drawable = self.id,
+ gc = gc,
+ rectangles = rectangles)
+
+ def rectangle(self, gc, x, y, width, height, onerror = None):
+ request.PolyRectangle(display = self.display,
+ onerror = onerror,
+ drawable = self.id,
+ gc = gc,
+ rectangles = [(x, y, width, height)])
+
+
+ def poly_arc(self, gc, arcs, onerror = None):
+ request.PolyArc(display = self.display,
+ onerror = onerror,
+ drawable = self.id,
+ gc = gc,
+ arcs = arcs)
+
+ def arc(self, gc, x, y, width, height, angle1, angle2, onerror = None):
+ request.PolyArc(display = self.display,
+ onerror = onerror,
+ drawable = self.id,
+ gc = gc,
+ arcs = [(x, y, width, height, angle1, angle2)])
+
+ def fill_poly(self, gc, shape, coord_mode, points, onerror = None):
+ request.FillPoly(display = self.display,
+ onerror = onerror,
+ shape = shape,
+ coord_mode = coord_mode,
+ drawable = self.id,
+ gc = gc,
+ points = points)
+
+ def poly_fill_rectangle(self, gc, rectangles, onerror = None):
+ request.PolyFillRectangle(display = self.display,
+ onerror = onerror,
+ drawable = self.id,
+ gc = gc,
+ rectangles = rectangles)
+
+ def fill_rectangle(self, gc, x, y, width, height, onerror = None):
+ request.PolyFillRectangle(display = self.display,
+ onerror = onerror,
+ drawable = self.id,
+ gc = gc,
+ rectangles = [(x, y, width, height)])
+
+ def poly_fill_arc(self, gc, arcs, onerror = None):
+ request.PolyFillArc(display = self.display,
+ onerror = onerror,
+ drawable = self.id,
+ gc = gc,
+ arcs = arcs)
+
+ def fill_arc(self, gc, x, y, width, height, angle1, angle2, onerror = None):
+ request.PolyFillArc(display = self.display,
+ onerror = onerror,
+ drawable = self.id,
+ gc = gc,
+ arcs = [(x, y, width, height, angle1, angle2)])
+
+
+ def put_image(self, gc, x, y, width, height, format,
+ depth, left_pad, data, onerror = None):
+ request.PutImage(display = self.display,
+ onerror = onerror,
+ format = format,
+ drawable = self.id,
+ gc = gc,
+ width = width,
+ height = height,
+ dst_x = x,
+ dst_y = y,
+ left_pad = left_pad,
+ depth = depth,
+ data = data)
+
+ # Trivial little method for putting PIL images. Will break on anything
+ # but depth 1 or 24...
+ def put_pil_image(self, gc, x, y, image, onerror = None):
+ width, height = image.size
+ if image.mode == '1':
+ format = X.XYBitmap
+ depth = 1
+ if self.display.info.bitmap_format_bit_order == 0:
+ rawmode = '1;R'
+ else:
+ rawmode = '1'
+ pad = self.display.info.bitmap_format_scanline_pad
+ stride = roundup(width, pad) >> 3
+ elif image.mode == 'RGB':
+ format = X.ZPixmap
+ depth = 24
+ if self.display.info.image_byte_order == 0:
+ rawmode = 'BGRX'
+ else:
+ rawmode = 'RGBX'
+ pad = self.display.info.bitmap_format_scanline_pad
+ unit = self.display.info.bitmap_format_scanline_unit
+ stride = roundup(width * unit, pad) >> 3
+ else:
+ raise ValueError, 'Unknown data format'
+
+ maxlen = (self.display.info.max_request_length << 2) \
+ - request.PutImage._request.static_size
+ split = maxlen / stride
+
+ x1 = 0
+ x2 = width
+ y1 = 0
+
+ while y1 < height:
+ h = min(height, split)
+ if h < height:
+ subimage = image.crop((x1, y1, x2, y1 + h))
+ else:
+ subimage = image
+ w, h = subimage.size
+ data = subimage.tostring("raw", rawmode, stride, 0)
+ self.put_image(gc, x, y, w, h, format, depth, 0, data)
+ y1 = y1 + h
+ y = y + h
+
+
+ def get_image(self, x, y, width, height, format, plane_mask):
+ return request.GetImage(display = self.display,
+ format = format,
+ drawable = self.id,
+ x = x,
+ y = y,
+ width = width,
+ height = height,
+ plane_mask = plane_mask)
+
+ def draw_text(self, gc, x, y, text, onerror = None):
+ request.PolyText8(display = self.display,
+ onerror = onerror,
+ drawable = self.id,
+ gc = gc,
+ x = x,
+ y = y,
+ items = [text])
+
+ def poly_text(self, gc, x, y, items, onerror = None):
+ request.PolyText8(display = self.display,
+ onerror = onerror,
+ drawable = self.id,
+ gc = gc,
+ x = x,
+ y = y,
+ items = items)
+
+ def poly_text_16(self, gc, x, y, items, onerror = None):
+ request.PolyText16(display = self.display,
+ onerror = onerror,
+ drawable = self.id,
+ gc = gc,
+ x = x,
+ y = y,
+ items = items)
+
+ def image_text(self, gc, x, y, string, onerror = None):
+ request.ImageText8(display = self.display,
+ onerror = onerror,
+ drawable = self.id,
+ gc = gc,
+ x = x,
+ y = y,
+ string = string)
+
+ def image_text_16(self, gc, x, y, string, onerror = None):
+ request.ImageText16(display = self.display,
+ onerror = onerror,
+ drawable = self.id,
+ gc = gc,
+ x = x,
+ y = y,
+ string = string)
+
+ def query_best_size(self, item_class, width, height):
+ return request.QueryBestSize(display = self.display,
+ item_class = item_class,
+ drawable = self.id,
+ width = width,
+ height = height)
+
+class Window(Drawable):
+ __window__ = resource.Resource.__resource__
+
+ def create_window(self, x, y, width, height, border_width, depth,
+ window_class = X.CopyFromParent,
+ visual = X.CopyFromParent,
+ **keys):
+
+ wid = self.display.allocate_resource_id()
+ request.CreateWindow(display = self.display,
+ depth = depth,
+ wid = wid,
+ parent = self.id,
+ x = x,
+ y = y,
+ width = width,
+ height = height,
+ border_width = border_width,
+ window_class = window_class,
+ visual = visual,
+ attrs = keys)
+
+ cls = self.display.get_resource_class('window', Window)
+ return cls(self.display, wid, owner = 1)
+
+ def change_attributes(self, onerror = None, **keys):
+ request.ChangeWindowAttributes(display = self.display,
+ onerror = onerror,
+ window = self.id,
+ attrs = keys)
+
+ def get_attributes(self):
+ return request.GetWindowAttributes(display = self.display,
+ window = self.id)
+
+ def destroy(self, onerror = None):
+ request.DestroyWindow(display = self.display,
+ onerror = onerror,
+ window = self.id)
+
+ self.display.free_resource_id(self.id)
+
+ def destroy_sub_windows(self, onerror = None):
+ request.DestroySubWindows(display = self.display,
+ onerror = onerror,
+ window = self.id)
+
+
+ def change_save_set(self, mode, onerror = None):
+ request.ChangeSaveSet(display = self.display,
+ onerror = onerror,
+ mode = mode,
+ window = self.id)
+
+ def reparent(self, parent, x, y, onerror = None):
+ request.ReparentWindow(display = self.display,
+ onerror = onerror,
+ window = self.id,
+ parent = parent,
+ x = x,
+ y = y)
+
+ def map(self, onerror = None):
+ request.MapWindow(display = self.display,
+ onerror = onerror,
+ window = self.id)
+
+ def map_sub_windows(self, onerror = None):
+ request.MapSubwindows(display = self.display,
+ onerror = onerror,
+ window = self.id)
+
+ def unmap(self, onerror = None):
+ request.UnmapWindow(display = self.display,
+ onerror = onerror,
+ window = self.id)
+
+ def unmap_sub_windows(self, onerror = None):
+ request.UnmapSubwindows(display = self.display,
+ onerror = onerror,
+ window = self.id)
+
+ def configure(self, onerror = None, **keys):
+ request.ConfigureWindow(display = self.display,
+ onerror = onerror,
+ window = self.id,
+ attrs = keys)
+
+ def circulate(self, direction, onerror = None):
+ request.CirculateWindow(display = self.display,
+ onerror = onerror,
+ direction = direction,
+ window = self.id)
+
+ def raise_window(self, onerror = None):
+ """alias for raising the window to the top - as in XRaiseWindow"""
+ self.configure(onerror, stack_mode = X.Above)
+
+ def query_tree(self):
+ return request.QueryTree(display = self.display,
+ window = self.id)
+
+
+ def change_property(self, property, type, format, data,
+ mode = X.PropModeReplace, onerror = None):
+
+ request.ChangeProperty(display = self.display,
+ onerror = onerror,
+ mode = mode,
+ window = self.id,
+ property = property,
+ type = type,
+ data = (format, data))
+
+ def delete_property(self, property, onerror = None):
+ request.DeleteProperty(display = self.display,
+ onerror = onerror,
+ window = self.id,
+ property = property)
+
+ def get_property(self, property, type, offset, length, delete = 0):
+ r = request.GetProperty(display = self.display,
+ delete = delete,
+ window = self.id,
+ property = property,
+ type = type,
+ long_offset = offset,
+ long_length = length)
+
+ if r.property_type:
+ fmt, value = r.value
+ r.format = fmt
+ r.value = value
+ return r
+ else:
+ return None
+
+ def get_full_property(self, property, type, sizehint = 10):
+ prop = self.get_property(property, type, 0, sizehint)
+ if prop:
+ val = prop.value
+ if prop.bytes_after:
+ prop = self.get_property(property, type, sizehint,
+ prop.bytes_after / 4 + 1)
+ val = val + prop.value
+
+ prop.value = val
+ return prop
+ else:
+ return None
+
+ def list_properties(self):
+ r = request.ListProperties(display = self.display,
+ window = self.id)
+ return r.atoms
+
+ def set_selection_owner(self, selection, time, onerror = None):
+ request.SetSelectionOwner(display = self.display,
+ onerror = onerror,
+ window = self.id,
+ selection = selection,
+ time = time)
+
+ def convert_selection(self, selection, target, property, time, onerror = None):
+ request.ConvertSelection(display = self.display,
+ onerror = onerror,
+ requestor = self.id,
+ selection = selection,
+ target = target,
+ property = property,
+ time = time)
+
+ def send_event(self, event, event_mask = 0, propagate = 0, onerror = None):
+ request.SendEvent(display = self.display,
+ onerror = onerror,
+ propagate = propagate,
+ destination = self.id,
+ event_mask = event_mask,
+ event = event)
+
+ def grab_pointer(self, owner_events, event_mask,
+ pointer_mode, keyboard_mode,
+ confine_to, cursor, time):
+
+ r = request.GrabPointer(display = self.display,
+ owner_events = owner_events,
+ grab_window = self.id,
+ event_mask = event_mask,
+ pointer_mode = pointer_mode,
+ keyboard_mode = keyboard_mode,
+ confine_to = confine_to,
+ cursor = cursor,
+ time = time)
+ return r.status
+
+ def grab_button(self, button, modifiers, owner_events, event_mask,
+ pointer_mode, keyboard_mode,
+ confine_to, cursor, onerror = None):
+
+ request.GrabButton(display = self.display,
+ onerror = onerror,
+ owner_events = owner_events,
+ grab_window = self.id,
+ event_mask = event_mask,
+ pointer_mode = pointer_mode,
+ keyboard_mode = keyboard_mode,
+ confine_to = confine_to,
+ cursor = cursor,
+ button = button,
+ modifiers = modifiers)
+
+ def ungrab_button(self, button, modifiers, onerror = None):
+ request.UngrabButton(display = self.display,
+ onerror = onerror,
+ button = button,
+ grab_window = self.id,
+ modifiers = modifiers)
+
+
+ def grab_keyboard(self, owner_events, pointer_mode, keyboard_mode, time):
+ r = request.GrabKeyboard(display = self.display,
+ owner_events = owner_events,
+ grab_window = self.id,
+ time = time,
+ pointer_mode = pointer_mode,
+ keyboard_mode = keyboard_mode)
+
+ return r.status
+
+ def grab_key(self, key, modifiers, owner_events, pointer_mode, keyboard_mode, onerror = None):
+ request.GrabKey(display = self.display,
+ onerror = onerror,
+ owner_events = owner_events,
+ grab_window = self.id,
+ modifiers = modifiers,
+ key = key,
+ pointer_mode = pointer_mode,
+ keyboard_mode = keyboard_mode)
+
+ def ungrab_key(self, key, modifiers, onerror = None):
+ request.UngrabKey(display = self.display,
+ onerror = onerror,
+ key = key,
+ grab_window = self.id,
+ modifiers = modifiers)
+
+ def query_pointer(self):
+ return request.QueryPointer(display = self.display,
+ window = self.id)
+
+ def get_motion_events(self, start, stop):
+ r = request.GetMotionEvents(display = self.display,
+ window = self.id,
+ start = start,
+ stop = stop)
+ return r.events
+
+ def translate_coords(self, src_window, src_x, src_y):
+ return request.TranslateCoords(display = self.display,
+ src_wid = src_window,
+ dst_wid = self.id,
+ src_x = src_x,
+ src_y = src_y)
+
+ def warp_pointer(self, x, y, src_window = 0, src_x = 0, src_y = 0,
+ src_width = 0, src_height = 0, onerror = None):
+
+ request.WarpPointer(display = self.display,
+ onerror = onerror,
+ src_window = src_window,
+ dst_window = self.id,
+ src_x = src_x,
+ src_y = src_y,
+ src_width = src_width,
+ src_height = src_height,
+ dst_x = x,
+ dst_y = y)
+
+ def set_input_focus(self, revert_to, time, onerror = None):
+ request.SetInputFocus(display = self.display,
+ onerror = onerror,
+ revert_to = revert_to,
+ focus = self.id,
+ time = time)
+
+ def clear_area(self, x = 0, y = 0, width = 0, height = 0, exposures = 0, onerror = None):
+ request.ClearArea(display = self.display,
+ onerror = onerror,
+ exposures = exposures,
+ window = self.id,
+ x = x,
+ y = y,
+ width = width,
+ height = height)
+
+ def create_colormap(self, visual, alloc):
+ mid = self.display.allocate_resource_id()
+ request.CreateColormap(display = self.display,
+ alloc = alloc,
+ mid = mid,
+ window = self.id,
+ visual = visual)
+ cls = self.display.get_resource_class('colormap', colormap.Colormap)
+ return cls(self.display, mid, owner = 1)
+
+ def list_installed_colormaps(self):
+ r = request.ListInstalledColormaps(display = self.display,
+ window = self.id)
+ return r.cmaps
+
+ def rotate_properties(self, properties, delta, onerror = None):
+ request.RotateProperties(display = self.display,
+ onerror = onerror,
+ window = self.id,
+ delta = delta,
+ properties = properties)
+
+ def set_wm_name(self, name, onerror = None):
+ self.change_property(Xatom.WM_NAME, Xatom.STRING, 8, name,
+ onerror = onerror)
+
+ def get_wm_name(self):
+ d = self.get_full_property(Xatom.WM_NAME, Xatom.STRING)
+ if d is None or d.format != 8:
+ return None
+ else:
+ return d.value
+
+ def set_wm_icon_name(self, name, onerror = None):
+ self.change_property(Xatom.WM_ICON_NAME, Xatom.STRING, 8, name,
+ onerror = onerror)
+
+ def get_wm_icon_name(self):
+ d = self.get_full_property(Xatom.WM_ICON_NAME, Xatom.STRING)
+ if d is None or d.format != 8:
+ return None
+ else:
+ return d.value
+
+
+ def set_wm_class(self, inst, cls, onerror = None):
+ self.change_property(Xatom.WM_CLASS, Xatom.STRING, 8,
+ '%s\0%s\0' % (inst, cls),
+ onerror = onerror)
+
+ def get_wm_class(self):
+ d = self.get_full_property(Xatom.WM_CLASS, Xatom.STRING)
+ if d is None or d.format != 8:
+ return None
+ else:
+ parts = string.split(d.value, '\0')
+ if len(parts) < 2:
+ return None
+ else:
+ return parts[0], parts[1]
+
+ def set_wm_transient_for(self, window, onerror = None):
+ self.change_property(Xatom.WM_TRANSIENT_FOR, Xatom.WINDOW,
+ 32, window.id,
+ onerror = onerror)
+
+ def get_wm_transient_for(self):
+ d = self.get_property(Xatom.WM_TRANSIENT_FOR, Xatom.WINDOW, 0, 1)
+ if d is None or d.format != 32 or len(d.value) < 1:
+ return None
+ else:
+ cls = self.display.get_resource_class('window', Window)
+ return cls(self.display, d.value[0])
+
+
+ def set_wm_protocols(self, protocols, onerror = None):
+ self.change_property(self.display.get_atom('WM_PROTOCOLS'),
+ Xatom.ATOM, 32, protocols,
+ onerror = onerror)
+
+ def get_wm_protocols(self):
+ d = self.get_full_property(self.display.get_atom('WM_PROTOCOLS'), Xatom.ATOM)
+ if d is None or d.format != 32:
+ return []
+ else:
+ return d.value
+
+ def set_wm_colormap_windows(self, windows, onerror = None):
+ self.change_property(self.display.get_atom('WM_COLORMAP_WINDOWS'),
+ Xatom.WINDOW, 32,
+ map(lambda w: w.id, windows),
+ onerror = onerror)
+
+ def get_wm_colormap_windows(self):
+ d = self.get_full_property(self.display.get_atom('WM_COLORMAP_WINDOWS'),
+ Xatom.WINDOW)
+ if d is None or d.format != 32:
+ return []
+ else:
+ cls = self.display.get_resource_class('window', Window)
+ return map(lambda i, d = self.display, c = cls: c(d, i),
+ d.value)
+
+
+ def set_wm_client_machine(self, name, onerror = None):
+ self.change_property(Xatom.WM_CLIENT_MACHINE, Xatom.STRING, 8, name,
+ onerror = onerror)
+
+ def get_wm_client_machine(self):
+ d = self.get_full_property(Xatom.WM_CLIENT_MACHINE, Xatom.STRING)
+ if d is None or d.format != 8:
+ return None
+ else:
+ return d.value
+
+ def set_wm_normal_hints(self, hints = {}, onerror = None, **keys):
+ self._set_struct_prop(Xatom.WM_NORMAL_HINTS, Xatom.WM_SIZE_HINTS,
+ icccm.WMNormalHints, hints, keys, onerror)
+
+ def get_wm_normal_hints(self):
+ return self._get_struct_prop(Xatom.WM_NORMAL_HINTS, Xatom.WM_SIZE_HINTS,
+ icccm.WMNormalHints)
+
+ def set_wm_hints(self, hints = {}, onerror = None, **keys):
+ self._set_struct_prop(Xatom.WM_HINTS, Xatom.WM_HINTS,
+ icccm.WMHints, hints, keys, onerror)
+
+ def get_wm_hints(self):
+ return self._get_struct_prop(Xatom.WM_HINTS, Xatom.WM_HINTS,
+ icccm.WMHints)
+
+ def set_wm_state(self, hints = {}, onerror = None, **keys):
+ atom = self.display.get_atom('WM_STATE')
+ self._set_struct_prop(atom, atom, icccm.WMState, hints, keys, onerror)
+
+ def get_wm_state(self):
+ atom = self.display.get_atom('WM_STATE')
+ return self._get_struct_prop(atom, atom, icccm.WMState)
+
+ def set_wm_icon_size(self, hints = {}, onerror = None, **keys):
+ self._set_struct_prop(Xatom.WM_ICON_SIZE, Xatom.WM_ICON_SIZE,
+ icccm.WMIconSize, hints, keys, onerror)
+
+ def get_wm_icon_size(self):
+ return self._get_struct_prop(Xatom.WM_ICON_SIZE, Xatom.WM_ICON_SIZE,
+ icccm.WMIconSize)
+
+ # Helper function for getting structured properties.
+ # pname and ptype are atoms, and pstruct is a Struct object.
+ # Returns a DictWrapper, or None
+
+ def _get_struct_prop(self, pname, ptype, pstruct):
+ r = self.get_property(pname, ptype, 0, pstruct.static_size / 4)
+ if r and r.format == 32:
+ value = r.value.tostring()
+ if len(value) == pstruct.static_size:
+ return pstruct.parse_binary(value, self.display)[0]
+
+ return None
+
+ # Helper function for setting structured properties.
+ # pname and ptype are atoms, and pstruct is a Struct object.
+ # hints is a mapping or a DictWrapper, keys is a mapping. keys
+ # will be modified. onerror is the error handler.
+
+ def _set_struct_prop(self, pname, ptype, pstruct, hints, keys, onerror):
+ if isinstance(hints, rq.DictWrapper):
+ keys.update(hints._data)
+ else:
+ keys.update(hints)
+
+ value = apply(pstruct.to_binary, (), keys)
+
+ self.change_property(pname, ptype, 32, value, onerror = onerror)
+
+
+class Pixmap(Drawable):
+ __pixmap__ = resource.Resource.__resource__
+
+ def free(self, onerror = None):
+ request.FreePixmap(display = self.display,
+ onerror = onerror,
+ pixmap = self.id)
+
+ self.display.free_resource_id(self.id)
+
+ def create_cursor(self, mask,
+ (fore_red, fore_green, fore_blue),
+ (back_red, back_green, back_blue),
+ x, y):
+ cid = self.display.allocate_resource_id()
+ request.CreateCursor(display = self.display,
+ cid = cid,
+ source = self.id,
+ mask = mask,
+ fore_red = fore_red,
+ fore_green = fore_green,
+ fore_blue = fore_blue,
+ back_red = back_red,
+ back_green = back_green,
+ back_blue = back_blue,
+ x = x,
+ y = y)
+ cls = self.display.get_resource_class('cursor', cursor.Cursor)
+ return cls(self.display, cid, owner = 1)
+
+
+def roundup(value, unit):
+ return (value + (unit - 1)) & ~(unit - 1)
diff --git a/Xlib/xobject/fontable.py b/Xlib/xobject/fontable.py
new file mode 100644
index 0000000..d48c5fc
--- /dev/null
+++ b/Xlib/xobject/fontable.py
@@ -0,0 +1,108 @@
+# $Id: fontable.py,v 1.4 2007/06/10 14:11:59 mggrant Exp $
+#
+# Xlib.xobject.fontable -- fontable objects (GC, font)
+#
+# Copyright (C) 2000 Peter Liljenberg <petli@ctrl-c.liu.se>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+from Xlib.protocol import request
+
+import resource
+import cursor
+
+class Fontable(resource.Resource):
+ __fontable__ = resource.Resource.__resource__
+
+ def query(self):
+ return request.QueryFont(display = self.display,
+ font = self.id)
+
+ def query_text_extents(self, string):
+ return request.QueryTextExtents(display = self.display,
+ font = self.id,
+ string = string)
+
+
+class GC(Fontable):
+ __gc__ = resource.Resource.__resource__
+
+ def change(self, onerror = None, **keys):
+ request.ChangeGC(display = self.display,
+ onerror = onerror,
+ gc = self.id,
+ attrs = keys)
+
+
+ def copy(self, src_gc, mask, onerror = None):
+ request.CopyGC(display = self.display,
+ onerror = onerror,
+ src_gc = src_gc,
+ dst_gc = self.id,
+ mask = mask)
+
+ def set_dashes(self, offset, dashes, onerror = None):
+ request.SetDashes(display = self.display,
+ onerror = onerror,
+ gc = self.id,
+ dash_offset = offset,
+ dashes = dashes)
+
+ def set_clip_rectangles(self, x_origin, y_origin, rectangles, ordering, onerror = None):
+ request.SetClipRectangles(display = self.display,
+ onerror = onerror,
+ ordering = ordering,
+ gc = self.id,
+ x_origin = x_origin,
+ y_origin = y_origin,
+ rectangles = rectangles)
+ def free(self, onerror = None):
+ request.FreeGC(display = self.display,
+ onerror = onerror,
+ gc = self.id)
+
+ self.display.free_resource_id(self.id)
+
+
+
+class Font(Fontable):
+ __font__ = resource.Resource.__resource__
+
+ def close(self, onerror = None):
+ request.CloseFont(display = self.display,
+ onerror = onerror,
+ font = self.id)
+ self.display.free_resource_id(self.id)
+
+ def create_glyph_cursor(self, mask, source_char, mask_char,
+ (fore_red, fore_green, fore_blue),
+ (back_red, back_green, back_blue)):
+
+ cid = self.display.allocate_resource_id()
+ request.CreateGlyphCursor(display = self.display,
+ cid = cid,
+ source = self.id,
+ mask = mask,
+ source_char = source_char,
+ mask_char = mask_char,
+ fore_red = fore_red,
+ fore_green = fore_green,
+ fore_blue = fore_blue,
+ back_red = back_red,
+ back_green = back_green,
+ back_blue = back_blue)
+
+ cls = self.display.get_resource_class('cursor', cursor.Cursor)
+ return cls(self.display, cid, owner = 1)
diff --git a/Xlib/xobject/icccm.py b/Xlib/xobject/icccm.py
new file mode 100644
index 0000000..cf656c7
--- /dev/null
+++ b/Xlib/xobject/icccm.py
@@ -0,0 +1,74 @@
+# $Id: icccm.py,v 1.5 2007/06/10 14:11:59 mggrant Exp $
+#
+# Xlib.xobject.icccm -- ICCCM structures
+#
+# Copyright (C) 2000 Peter Liljenberg <petli@ctrl-c.liu.se>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+from Xlib import X, Xutil
+from Xlib.protocol import rq
+
+Aspect = rq.Struct( rq.Int32('num'), rq.Int32('denum') )
+
+WMNormalHints = rq.Struct( rq.Card32('flags'),
+ rq.Pad(16),
+ rq.Int32('min_width', default = 0),
+ rq.Int32('min_height', default = 0),
+ rq.Int32('max_width', default = 0),
+ rq.Int32('max_height', default = 0),
+ rq.Int32('width_inc', default = 0),
+ rq.Int32('height_inc', default = 0),
+ rq.Object('min_aspect', Aspect, default = (0, 0)),
+ rq.Object('max_aspect', Aspect, default = (0, 0)),
+ rq.Int32('base_width', default = 0),
+ rq.Int32('base_height', default = 0),
+ rq.Int32('win_gravity', default = 0),
+ )
+
+WMHints = rq.Struct( rq.Card32('flags'),
+ rq.Card32('input', default = 0),
+ rq.Set('initial_state', 4,
+ # withdrawn is totally bogus according to
+ # ICCCM, but some window managers seem to
+ # use this value to identify dockapps.
+ # Oh well.
+ ( Xutil.WithdrawnState,
+ Xutil.NormalState,
+ Xutil.IconicState ),
+ default = Xutil.NormalState),
+ rq.Pixmap('icon_pixmap', default = 0),
+ rq.Window('icon_window', default = 0),
+ rq.Int32('icon_x', default = 0),
+ rq.Int32('icon_y', default = 0),
+ rq.Pixmap('icon_mask', default = 0),
+ rq.Window('window_group', default = 0),
+ )
+
+WMState = rq.Struct( rq.Set('state', 4,
+ ( Xutil.WithdrawnState,
+ Xutil.NormalState,
+ Xutil.IconicState )),
+ rq.Window('icon', ( X.NONE, )),
+ )
+
+
+WMIconSize = rq.Struct( rq.Card32('min_width'),
+ rq.Card32('min_height'),
+ rq.Card32('max_width'),
+ rq.Card32('max_height'),
+ rq.Card32('width_inc'),
+ rq.Card32('height_inc'),
+ )
diff --git a/Xlib/xobject/resource.py b/Xlib/xobject/resource.py
new file mode 100644
index 0000000..10d58c9
--- /dev/null
+++ b/Xlib/xobject/resource.py
@@ -0,0 +1,53 @@
+# $Id: resource.py,v 1.5 2007/06/10 14:11:59 mggrant Exp $
+#
+# Xlib.xobject.resource -- any X resource object
+#
+# Copyright (C) 2000 Peter Liljenberg <petli@ctrl-c.liu.se>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+from Xlib.protocol import request
+
+class Resource:
+ def __init__(self, display, rid, owner = 0):
+ self.display = display
+ self.id = rid
+ self.owner = owner
+
+ def __resource__(self):
+ return self.id
+
+ def __cmp__(self, obj):
+ if isinstance(obj, Resource):
+ if self.display == obj.display:
+ return cmp(self.id, obj.id)
+ else:
+ return cmp(self.display, obj.display)
+ else:
+ return cmp(id(self), id(obj))
+
+ def __hash__(self):
+ return int(self.id)
+
+ def __str__(self):
+ return '%s(0x%08x)' % (self.__class__, self.id)
+
+ def __repr__(self):
+ return '<%s 0x%08x>' % (self.__class__, self.id)
+
+ def kill_client(self, onerror = None):
+ request.KillClient(display = self.display,
+ onerror = onerror,
+ resource = self.id)
diff --git a/clMonty.py b/clMonty.py
index 850fef2..e6c57e4 100644
--- a/clMonty.py
+++ b/clMonty.py
@@ -57,7 +57,8 @@ class Monty(QtCore.QObject):
"""Connect to MPD@$host:$port. Returns true at success, false otherwise."""
if self._client:
return
- self._client = jmpc.jmpc()
+ #self._client = jmpc.jmpc()
+ self._client = mpd.MPDClient()
#try:
self._client.connect(host, port)
#except:
diff --git a/montypc.py b/montypc.py
index 1e181c5..724401b 100644
--- a/montypc.py
+++ b/montypc.py
@@ -8,20 +8,11 @@ from winMain import winMain
from winSettings import winSettings
from clMonty import monty
from traceback import print_exc
-from clMonty import Monty
-
-# start a server
-import jmpd
-server=jmpd.server()
-server.start()
try:
- m=Monty()
- m.connect("localhost", 6600)
- #wMain = winMain()
- #wMain.show()
- #app.exec_()
+ wMain = winMain()
+ wMain.show()
+ app.exec_()
except Exception, e:
print_exc()
-#profile.run('app.exec_()')