diff options
58 files changed, 12023 insertions, 13 deletions
@@ -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) @@ -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: @@ -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_()') |