PageRenderTime 36ms CodeModel.GetById 28ms RepoModel.GetById 1ms app.codeStats 0ms

/pyglet/canvas/xlib.py

https://bitbucket.org/kolauren/morbify_hackathon
Python | 260 lines | 190 code | 45 blank | 25 comment | 28 complexity | 80f59a3c0e5289e90206ba4caa2988e2 MD5 | raw file
  1. #!/usr/bin/env python
  2. '''
  3. '''
  4. __docformat__ = 'restructuredtext'
  5. __version__ = '$Id: $'
  6. from ctypes import *
  7. import ctypes
  8. from pyglet import app
  9. from pyglet.app.xlib import XlibSelectDevice
  10. from .base import Display, Screen, ScreenMode, Canvas
  11. from . import xlib_vidmoderestore
  12. # XXX
  13. #from pyglet.window import NoSuchDisplayException
  14. class NoSuchDisplayException(Exception):
  15. pass
  16. from pyglet.libs.x11 import xlib
  17. try:
  18. from pyglet.libs.x11 import xinerama
  19. _have_xinerama = True
  20. except:
  21. _have_xinerama = False
  22. try:
  23. from pyglet.libs.x11 import xsync
  24. _have_xsync = True
  25. except:
  26. _have_xsync = False
  27. try:
  28. from pyglet.libs.x11 import xf86vmode
  29. _have_xf86vmode = True
  30. except:
  31. _have_xf86vmode = False
  32. # Set up error handler
  33. def _error_handler(display, event):
  34. # By default, all errors are silently ignored: this has a better chance
  35. # of working than the default behaviour of quitting ;-)
  36. #
  37. # We've actually never seen an error that was our fault; they're always
  38. # driver bugs (and so the reports are useless). Nevertheless, set
  39. # environment variable PYGLET_DEBUG_X11 to 1 to get dumps of the error
  40. # and a traceback (execution will continue).
  41. import pyglet
  42. if pyglet.options['debug_x11']:
  43. event = event.contents
  44. buf = c_buffer(1024)
  45. xlib.XGetErrorText(display, event.error_code, buf, len(buf))
  46. print('X11 error:', buf.value)
  47. print(' serial:', event.serial)
  48. print(' request:', event.request_code)
  49. print(' minor:', event.minor_code)
  50. print(' resource:', event.resourceid)
  51. import traceback
  52. print('Python stack trace (innermost last):')
  53. traceback.print_stack()
  54. return 0
  55. _error_handler_ptr = xlib.XErrorHandler(_error_handler)
  56. xlib.XSetErrorHandler(_error_handler_ptr)
  57. class XlibDisplay(XlibSelectDevice, Display):
  58. _display = None # POINTER(xlib.Display)
  59. _x_im = None # X input method
  60. # TODO close _x_im when display connection closed.
  61. _enable_xsync = False
  62. _screens = None # Cache of get_screens()
  63. def __init__(self, name=None, x_screen=None):
  64. if x_screen is None:
  65. x_screen = 0
  66. self._display = xlib.XOpenDisplay(name)
  67. if not self._display:
  68. raise NoSuchDisplayException('Cannot connect to "%s"' % name)
  69. screen_count = xlib.XScreenCount(self._display)
  70. if x_screen >= screen_count:
  71. raise NoSuchDisplayException(
  72. 'Display "%s" has no screen %d' % (name, x_screen))
  73. super(XlibDisplay, self).__init__()
  74. self.name = name
  75. self.x_screen = x_screen
  76. self._fileno = xlib.XConnectionNumber(self._display)
  77. self._window_map = {}
  78. # Initialise XSync
  79. if _have_xsync:
  80. event_base = c_int()
  81. error_base = c_int()
  82. if xsync.XSyncQueryExtension(self._display,
  83. byref(event_base),
  84. byref(error_base)):
  85. major_version = c_int()
  86. minor_version = c_int()
  87. if xsync.XSyncInitialize(self._display,
  88. byref(major_version),
  89. byref(minor_version)):
  90. self._enable_xsync = True
  91. # Add to event loop select list. Assume we never go away.
  92. app.platform_event_loop._select_devices.add(self)
  93. def get_screens(self):
  94. if self._screens:
  95. return self._screens
  96. if _have_xinerama and xinerama.XineramaIsActive(self._display):
  97. number = c_int()
  98. infos = xinerama.XineramaQueryScreens(self._display,
  99. byref(number))
  100. infos = cast(infos,
  101. POINTER(xinerama.XineramaScreenInfo * number.value)).contents
  102. self._screens = []
  103. using_xinerama = number.value > 1
  104. for info in infos:
  105. self._screens.append(XlibScreen(self,
  106. info.x_org,
  107. info.y_org,
  108. info.width,
  109. info.height,
  110. using_xinerama))
  111. xlib.XFree(infos)
  112. else:
  113. # No xinerama
  114. screen_info = xlib.XScreenOfDisplay(self._display, self.x_screen)
  115. screen = XlibScreen(self,
  116. 0, 0,
  117. screen_info.contents.width,
  118. screen_info.contents.height,
  119. False)
  120. self._screens = [screen]
  121. return self._screens
  122. # XlibSelectDevice interface
  123. def fileno(self):
  124. return self._fileno
  125. def select(self):
  126. e = xlib.XEvent()
  127. while xlib.XPending(self._display):
  128. xlib.XNextEvent(self._display, e)
  129. # Key events are filtered by the xlib window event
  130. # handler so they get a shot at the prefiltered event.
  131. if e.xany.type not in (xlib.KeyPress, xlib.KeyRelease):
  132. if xlib.XFilterEvent(e, e.xany.window):
  133. continue
  134. try:
  135. dispatch = self._window_map[e.xany.window]
  136. except KeyError:
  137. continue
  138. dispatch(e)
  139. def poll(self):
  140. return xlib.XPending(self._display)
  141. class XlibScreen(Screen):
  142. _initial_mode = None
  143. def __init__(self, display, x, y, width, height, xinerama):
  144. super(XlibScreen, self).__init__(display, x, y, width, height)
  145. self._xinerama = xinerama
  146. def get_matching_configs(self, template):
  147. canvas = XlibCanvas(self.display, None)
  148. configs = template.match(canvas)
  149. # XXX deprecate
  150. for config in configs:
  151. config.screen = self
  152. return configs
  153. def get_modes(self):
  154. if not _have_xf86vmode:
  155. return []
  156. if self._xinerama:
  157. # If Xinerama/TwinView is enabled, xf86vidmode's modelines
  158. # correspond to metamodes, which don't distinguish one screen from
  159. # another. XRandR (broken) or NV (complicated) extensions needed.
  160. return []
  161. count = ctypes.c_int()
  162. info_array = \
  163. ctypes.POINTER(ctypes.POINTER(xf86vmode.XF86VidModeModeInfo))()
  164. xf86vmode.XF86VidModeGetAllModeLines(
  165. self.display._display, self.display.x_screen, count, info_array)
  166. # Copy modes out of list and free list
  167. modes = []
  168. for i in range(count.value):
  169. info = xf86vmode.XF86VidModeModeInfo()
  170. ctypes.memmove(ctypes.byref(info),
  171. ctypes.byref(info_array.contents[i]),
  172. ctypes.sizeof(info))
  173. modes.append(XlibScreenMode(self, info))
  174. if info.privsize:
  175. xlib.XFree(info.private)
  176. xlib.XFree(info_array)
  177. return modes
  178. def get_mode(self):
  179. modes = self.get_modes()
  180. if modes:
  181. return modes[0]
  182. return None
  183. def set_mode(self, mode):
  184. assert mode.screen is self
  185. if not self._initial_mode:
  186. self._initial_mode = self.get_mode()
  187. xlib_vidmoderestore.set_initial_mode(self._initial_mode)
  188. xf86vmode.XF86VidModeSwitchToMode(self.display._display,
  189. self.display.x_screen, mode.info)
  190. xlib.XFlush(self.display._display)
  191. xf86vmode.XF86VidModeSetViewPort(self.display._display,
  192. self.display.x_screen, 0, 0)
  193. xlib.XFlush(self.display._display)
  194. self.width = mode.width
  195. self.height = mode.height
  196. def restore_mode(self):
  197. if self._initial_mode:
  198. self.set_mode(self._initial_mode)
  199. def __repr__(self):
  200. return 'XlibScreen(display=%r, x=%d, y=%d, ' \
  201. 'width=%d, height=%d, xinerama=%d)' % \
  202. (self.display, self.x, self.y, self.width, self.height,
  203. self._xinerama)
  204. class XlibScreenMode(ScreenMode):
  205. def __init__(self, screen, info):
  206. super(XlibScreenMode, self).__init__(screen)
  207. self.info = info
  208. self.width = info.hdisplay
  209. self.height = info.vdisplay
  210. self.rate = info.dotclock
  211. self.depth = None
  212. class XlibCanvas(Canvas):
  213. def __init__(self, display, x_window):
  214. super(XlibCanvas, self).__init__(display)
  215. self.x_window = x_window