text: #!/usr/bin/python3
  """
  Bindings for the Yutani graphics libraries, including the core Yutani protocol,
  general graphics routines, and the system decoration library.
  """
  
  from ctypes import *
  import importlib
  
  yutani_lib = None
  yutani_gfx_lib = None
  yutani_ctx = None
  yutani_windows = {}
  
  _cairo_lib = None
  _cairo_module = None
  _cairo_module_lib = None
  
  _libc = CDLL('libc.so')
  
  def usleep(microseconds):
      _libc.usleep(microseconds)
  
  class Message(object):
      """A generic event message from the Yutani server."""
      class _yutani_msg_t(Structure):
          _fields_ = [
              ('magic', c_uint32),
              ('type', c_uint32),
              ('size', c_uint32),
              ('data', c_char*0),
          ]
  
      MSG_HELLO               = 0x00000001
      MSG_WINDOW_NEW          = 0x00000002
      MSG_FLIP                = 0x00000003
      MSG_KEY_EVENT           = 0x00000004
      MSG_MOUSE_EVENT         = 0x00000005
      MSG_WINDOW_MOVE         = 0x00000006
      MSG_WINDOW_CLOSE        = 0x00000007
      MSG_WINDOW_SHOW         = 0x00000008
      MSG_WINDOW_HIDE         = 0x00000009
      MSG_WINDOW_STACK        = 0x0000000A
      MSG_WINDOW_FOCUS_CHANGE = 0x0000000B
      MSG_WINDOW_MOUSE_EVENT  = 0x0000000C
      MSG_FLIP_REGION         = 0x0000000D
      MSG_WINDOW_NEW_FLAGS    = 0x0000000E
      MSG_RESIZE_REQUEST      = 0x00000010
      MSG_RESIZE_OFFER        = 0x00000011
      MSG_RESIZE_ACCEPT       = 0x00000012
      MSG_RESIZE_BUFID        = 0x00000013
      MSG_RESIZE_DONE         = 0x00000014
      MSG_WINDOW_ADVERTISE    = 0x00000020
      MSG_SUBSCRIBE           = 0x00000021
      MSG_UNSUBSCRIBE         = 0x00000022
      MSG_NOTIFY              = 0x00000023
      MSG_QUERY_WINDOWS       = 0x00000024
      MSG_WINDOW_FOCUS        = 0x00000025
      MSG_WINDOW_DRAG_START   = 0x00000026
      MSG_WINDOW_WARP_MOUSE   = 0x00000027
      MSG_WINDOW_SHOW_MOUSE   = 0x00000028
      MSG_WINDOW_RESIZE_START = 0x00000029
      MSG_SESSION_END         = 0x00000030
      MSG_KEY_BIND            = 0x00000040
      MSG_WINDOW_UPDATE_SHAPE = 0x00000050
      MSG_GOODBYE             = 0x000000F0
      MSG_TIMER_REQUEST       = 0x00000100 # XXX deprecated
      MSG_TIMER_TICK          = 0x00000101 # xxx deprecated
      MSG_WELCOME             = 0x00010001
      MSG_WINDOW_INIT         = 0x00010002
  
      def __init__(self, msg):
          self._ptr = msg
  
      def free(self):
          if self._ptr:
              _libc.free(self._ptr)
              self._ptr = None
  
      @property
      def type(self):
          return self._ptr.contents.type
  
  _message_types = {}
  
  class MessageBuilder(type):
  
      def __new__(cls, name, bases, dct):
          global _message_types
          new_cls = super(MessageBuilder, cls).__new__(cls, name, bases, dct)
          if 'type_val' in dct:
              _message_types[dct['type_val']] = new_cls
          return new_cls
  
  class MessageEx(Message, metaclass=MessageBuilder):
      """An event message with extra data available."""
      type_val = None
      data_struct = None
  
      def __init__(self, msg):
          Message.__init__(self, msg)
          self._data_ptr = cast(byref(self._ptr.contents,Message._yutani_msg_t.data.offset), POINTER(self.data_struct))
  
      def __getattr__(self, name):
          if name in dir(self._data_ptr.contents):
              return getattr(self._data_ptr.contents, name)
          raise AttributeError(name)
  
  class MessageWelcome(MessageEx):
      """Message sent by the server on display size changes."""
      type_val = Message.MSG_WELCOME
      class data_struct(Structure):
          _fields_ = [
              ('display_width', c_uint32),
              ('display_height', c_uint32),
          ]
  
  class Keycode(object):
      """Keycodes."""
      NONE        = 0
      BACKSPACE   = 8
      CTRL_A      = 1
      CTRL_B      = 2
      CTRL_C      = 3
      CTRL_D      = 4
      CTRL_E      = 5
      CTRL_F      = 6
      CTRL_G      = 7
      CTRL_H      = 8
      CTRL_I      = 9
      CTRL_J      = 10
      CTRL_K      = 11
      CTRL_L      = 12
      CTRL_M      = 13
      CTRL_N      = 14
      CTRL_O      = 15
      CTRL_P      = 16
      CTRL_Q      = 17
      CTRL_R      = 18
      CTRL_S      = 19
      CTRL_T      = 20
      CTRL_U      = 21
      CTRL_V      = 22
      CTRL_W      = 23
      CTRL_X      = 24
      CTRL_Y      = 25
      CTRL_Z      = 26
      ESCAPE      = 27
      NORMAL_MAX  = 256
      ARROW_UP    = 257
      ARROW_DOWN  = 258
      ARROW_RIGHT = 259
      ARROW_LEFT  = 260
      BAD_STATE   = -1
  
      CTRL_ARROW_UP    = 261
      CTRL_ARROW_DOWN  = 262
      CTRL_ARROW_RIGHT = 263
      CTRL_ARROW_LEFT  = 264
  
      SHIFT_ARROW_UP    = 265
      SHIFT_ARROW_DOWN  = 266
      SHIFT_ARROW_RIGHT = 267
      SHIFT_ARROW_LEFT  = 268
  
      LEFT_CTRL   = 1001
      LEFT_SHIFT  = 1002
      LEFT_ALT    = 1003
      LEFT_SUPER  = 1004
  
      RIGHT_CTRL  = 1011
      RIGHT_SHIFT = 1012
      RIGHT_ALT   = 1013
      RIGHT_SUPER = 1014
  
      F1          = 2001
      F2          = 2002
      F3          = 2003
      F4          = 2004
      F5          = 2005
      F6          = 2006
      F7          = 2007
      F8          = 2008
      F9          = 2009
      F10         = 2010
      F11         = 2011
      F12         = 2012
  
      PAGE_DOWN   = 2013
      PAGE_UP     = 2014
  
      HOME        = 2015
      END         = 2016
      DEL         = 2017
      INSERT      = 2018
  
  class Modifier(object):
      """Modifier key flags."""
      MOD_LEFT_CTRL   = 0x01
      MOD_LEFT_SHIFT  = 0x02
      MOD_LEFT_ALT    = 0x04
      MOD_LEFT_SUPER  = 0x08
      MOD_RIGHT_CTRL  = 0x10
      MOD_RIGHT_SHIFT = 0x20
      MOD_RIGHT_ALT   = 0x40
      MOD_RIGHT_SUPER = 0x80
  
  class KeyAction(object):
      """Keyboard action (up or down)"""
      ACTION_DOWN = 1
      ACTION_UP = 2
  
  class MessageKeyEvent(MessageEx):
      """Message containing key event information."""
      type_val = Message.MSG_KEY_EVENT
      class data_struct(Structure):
          class key_event_t(Structure):
              _fields_ = [
                  ('keycode', c_uint),
                  ('modifiers', c_uint),
                  ('action', c_ubyte),
                  ('key', c_char),
              ]
          class key_event_state_t(Structure):
              _fields = [
                  ("kbd_state", c_int),
                  ("kbd_s_state", c_int),
  
                  ("k_ctrl", c_int),
                  ("k_shift", c_int),
                  ("k_alt", c_int),
                  ("k_super", c_int),
  
                  ("kl_ctrl", c_int),
                  ("kl_shift", c_int),
                  ("kl_alt", c_int),
                  ("kl_super", c_int),
  
                  ("kr_ctrl", c_int),
                  ("kr_shift", c_int),
                  ("kr_alt", c_int),
                  ("kr_super", c_int),
  
                  ("kbd_esc_buf", c_int),
              ]
          _fields_ = [
              ('wid', c_uint32),
              ('event', key_event_t),
              ('state', key_event_state_t),
          ]
  
  class MessageWindowMouseEvent(MessageEx):
      """Message containing window-relative mouse event information."""
      type_val = Message.MSG_WINDOW_MOUSE_EVENT
      class data_struct(Structure):
          _fields_ = [
              ('wid', c_uint32),
              ('new_x', c_int32),
              ('new_y', c_int32),
              ('old_x', c_int32),
              ('old_y', c_int32),
              ('buttons', c_ubyte),
              ('command', c_ubyte),
          ]
  
  class MessageWindowFocusChange(MessageEx):
      """Message indicating the focus state of a window has changed."""
      type_val = Message.MSG_WINDOW_FOCUS_CHANGE
      class data_struct(Structure):
          _fields_ = [
              ('wid', c_uint32),
              ('focused', c_int),
          ]
  
  class MessageWindowResize(MessageEx):
      """Message indicating the server wishes to resize this window."""
      type_val = Message.MSG_RESIZE_OFFER
      class data_struct(Structure):
          _fields_ = [
              ('wid', c_uint32),
              ('width', c_uint32),
              ('height', c_uint32),
              ('bufid', c_uint32),
          ]
  
  class MessageWindowAdvertisement(MessageEx):
      """Message containing information about a foreign window."""
      type_val = Message.MSG_WINDOW_ADVERTISE
      class data_struct(Structure):
          _fields_ = [
              ('wid', c_uint32),
              ('flags', c_uint32),
              ('offsets', c_uint16 * 5),
              ('size', c_uint32),
              ('strings', c_byte * 0),
          ]
  
      @property
      def name(self):
          return string_at(addressof(self.strings) + self.offsets[0]).decode('utf-8')
  
      @property
      def icon(self):
          return string_at(addressof(self.strings) + self.offsets[1]).decode('utf-8')
  
  class MessageWindowMove(MessageEx):
      """Message received when a window has moved containing its new coordinates."""
      type_val = Message.MSG_WINDOW_MOVE
      class data_struct(Structure):
          _fields_ = [
              ('wid', c_uint32),
              ('x', c_int32),
              ('y', c_int32),
          ]
  
  class Yutani(object):
      """Base Yutani communication class. Must be initialized to start a connection."""
      class _yutani_t(Structure):
          _fields_ = [
              ("sock", c_void_p), # File pointer
              ("display_width", c_size_t),
              ("display_height", c_size_t),
              ("windows", c_void_p), # hashmap
              ("queued", c_void_p), # list
              ("server_ident", c_char_p),
          ]
  
      def __init__(self):
          global yutani_lib
          global yutani_ctx
          global yutani_gfx_lib
          yutani_lib = CDLL("libtoaru-yutani.so")
          yutani_gfx_lib = CDLL("libtoaru-graphics.so")
          self._ptr = cast(yutani_lib.yutani_init(), POINTER(self._yutani_t))
          yutani_ctx = self
          self._fileno = _libc.fileno(self._ptr.contents.sock)
  
      def poll(self, sync=True):
          """Poll for an event message."""
          if sync:
              result = yutani_lib.yutani_poll(self._ptr)
          else:
              result = yutani_lib.yutani_poll_async(self._ptr)
          if not result:
              return None
          msg_ptr = cast(result, POINTER(Message._yutani_msg_t))
          msg_class = _message_types.get(msg_ptr.contents.type, Message)
          return msg_class(msg_ptr)
  
      def wait_for(self, message):
          """Wait for a particular kind of message to be delivered."""
          result = yutani_lib.yutani_wait_for(self._ptr, message)
          msg_ptr = cast(result, POINTER(Message._yutani_msg_t))
          msg_class = _message_types.get(msg_ptr.contents.type, Message)
          return msg_class(msg_ptr)
  
      def subscribe(self):
          """Subscribe to window information changes."""
          yutani_lib.yutani_subscribe_windows(self._ptr)
  
      def unsubscribe(self):
          """Unsubscribe from window information changes."""
          yutani_lib.yutani_unsubscribe_windows(self._ptr)
  
      def query_windows(self):
          """Request a window subsription list."""
          yutani_lib.yutani_query_windows(self._ptr)
  
      def focus_window(self, wid):
          """Request that the server change the focused window to the window with the specified wid."""
          yutani_lib.yutani_focus_window(self._ptr, wid)
  
      def session_end(self):
          """Request the end of the user session."""
          yutani_lib.yutani_session_end(self._ptr)
  
      def key_bind(self, keycode, modifiers, flags):
          """Set global key binding."""
          yutani_lib.yutani_key_bind(self._ptr, keycode, modifiers, flags)
  
      def fileno(self):
          """Act file-like and return our file descriptor number."""
          return self._fileno
  
      def query(self):
          """Asynchronously check if data is available."""
          return yutani_lib.yutani_query(self._ptr)
  
  class KeybindFlag(object):
      """Flags for global key bindings."""
      BIND_PASSTHROUGH = 0 # The key bind should be received by other clients.
      BIND_STEAL       = 1 # The key bind should stop after being processed here.
  
  class WindowShape(object):
      """Window shaping modes for Window.update_shape."""
      # These are actually values representing the minimum required
      # alpha value for a pixel to be registered as part of the given window.
      # 256 is more than the maximum alpha value, so all clicks will pass through.
      # 0 will catch every pixel, even if it is entirely transparent.
      THRESHOLD_NONE        = 0
      THRESHOLD_CLEAR       = 1
      THRESHOLD_HALF        = 127
      THRESHOLD_ANY         = 255
      THRESHOLD_PASSTHROUGH = 256
  
  class WindowStackOrder(object):
      """Window stack order options."""
      ZORDER_MAX    = 0xFFFF
      ZORDER_TOP    = 0xFFFF
      ZORDER_BOTTOM = 0x0000
  
  class WindowFlag(object):
      """Flags for window creation."""
      FLAG_NO_STEAL_FOCUS  = (1 << 0) # Don't steal focus on window creation.
      FLAG_DISALLOW_DRAG   = (1 << 1) # Don't allow this window to be dragged.
      FLAG_DISALLOW_RESIZE = (1 << 2) # Don't allow this window to be resized.
      FLAG_ALT_ANIMATION   = (1 << 3) # Use the alternate animation when mapping and unmapping.
  
  class MouseButton(object):
      """Mouse button flags."""
      BUTTON_LEFT   = 0x01
      BUTTON_RIGHT  = 0x02
      BUTTON_MIDDLE = 0x04
      SCROLL_UP     = 0x10
      SCROLL_DOWN   = 0x20
  
  class MouseEvent(object):
      """Mouse event types."""
      CLICK = 0
      DRAG  = 1
      RAISE = 2
      DOWN  = 3
      MOVE  = 4
      LEAVE = 5
      ENTER = 6
  
  class CursorType(object):
      """Cursor types for show_mouse."""
      RESET             = -1
      HIDE              = 0
      NORMAL            = 1
      DRAG              = 2
      RESIZE_VERTICAL   = 3
      RESIZE_HORIZONTAL = 4
      RESIZE_UP_DOWN    = 5
      RESIZE_DOWN_UP    = 6
  
  class GraphicsBuffer(object):
      """Generic buffer for rendering."""
  
      def __init__(self, width, height):
          self.width = width
          self.height = height
  
          self._sprite = yutani_gfx_lib.create_sprite(width,height,2)
          self._gfx = cast(yutani_gfx_lib.init_graphics_sprite(self._sprite),POINTER(Window._gfx_context_t))
  
      def get_cairo_surface(self):
          return Window.get_cairo_surface(self)
  
      def get_value(self,x,y):
          return cast(self._gfx.contents.backbuffer,POINTER(c_uint32))[self.width * y + x]
  
      def destroy(self):
          yutani_gfx_lib.sprite_free(self._sprite)
          _libc.free(self._gfx)
  
  
  class Window(object):
      """Yutani Window object."""
      class _yutani_window_t(Structure):
          _fields_ = [
              ("wid", c_uint),
              ("width", c_uint32),
              ("height", c_uint32),
              ("buffer", POINTER(c_uint8)),
              ("bufid", c_uint32),
              ("focused", c_uint8),
              ("oldbufid", c_uint32),
          ]
  
      class _gfx_context_t(Structure):
          _fields_ = [
              ('width', c_uint16),
              ('height', c_uint16),
              ('depth', c_uint16),
              ('size', c_uint32),
              ('buffer', POINTER(c_char)),
              ('backbuffer', POINTER(c_char)),
          ]
  
      def __init__(self, width, height, flags=0, title=None, icon=None, doublebuffer=False):
          if not yutani_ctx:
              raise ValueError("Not connected.")
  
          self._ptr = cast(yutani_lib.yutani_window_create_flags(yutani_ctx._ptr, width, height, flags), POINTER(self._yutani_window_t))
  
          yutani_windows[self.wid] = self
  
          self.doublebuffer = doublebuffer
  
          if doublebuffer:
              self._gfx = cast(yutani_lib.init_graphics_yutani_double_buffer(self._ptr), POINTER(self._gfx_context_t))
          else:
              self._gfx = cast(yutani_lib.init_graphics_yutani(self._ptr), POINTER(self._gfx_context_t))
  
          if title:
              self.set_title(title, icon)
  
          self.closed = False
  
      def get_cairo_surface(self):
          """Obtain a pycairo.ImageSurface representing the window backbuffer."""
          global _cairo_lib
          global _cairo_module
          global _cairo_module_lib
          if not _cairo_lib:
              _cairo_lib = CDLL('libcairo.so')
              _cairo_module = importlib.import_module('_cairo')
              _cairo_module_lib = CDLL(_cairo_module.__file__)
          buffer = self._gfx.contents.backbuffer
          width = self.width
          height = self.height
          format = _cairo_module.FORMAT_ARGB32
          # int cairo_format_stride_for_width(cairo_format_t format, int width)
          cfsfw = _cairo_lib.cairo_format_stride_for_width
          cfsfw.argtypes = [c_int, c_int]
          cfsfw.restype = c_int
          # stride = cairo_format_stride_for_width(format, width)
          stride = cfsfw(format, width)
          # cairo_surface_t * cairo_image_surface_create_for_data(unsigned char * data, cairo_format_t format, int ...)
          ciscfd = _cairo_lib.cairo_image_surface_create_for_data
          ciscfd.argtypes = [POINTER(c_char), c_int, c_int, c_int, c_int]
          ciscfd.restype = c_void_p
          # surface = cairo_image_surface_create_for_data(buffer,format,width,height,stride)
          surface = ciscfd(buffer,format,width,height,stride)
          # PyObject * PycairoSurface_FromSurface(cairo_surface_t * surface, PyObject * base)
          pcsfs = _cairo_module_lib.PycairoSurface_FromSurface
          pcsfs.argtypes = [c_void_p, c_int]
          pcsfs.restype = py_object
          # return PycairoSurface_FromSurface(surface, NULL)
          return pcsfs(surface, 0)
  
  
      def set_title(self, title, icon=None):
          """Advertise this window with the given title and optional icon string."""
          self.title = title
          self.icon = icon
          title_string = title.encode('utf-8') if title else None
          icon_string = icon.encode('utf-8') if icon else None
  
          if not icon:
              yutani_lib.yutani_window_advertise(yutani_ctx._ptr, self._ptr, title_string)
          else:
              yutani_lib.yutani_window_advertise_icon(yutani_ctx._ptr, self._ptr, title_string, icon_string)
  
      def buffer(self):
          """Obtain a reference to the graphics backbuffer representing this window's canvas."""
          return cast(self._gfx.contents.backbuffer, POINTER(c_uint32))
  
      def flip(self, region=None):
          """Flip the window buffer when double buffered and inform the server of updates."""
          if self.doublebuffer:
              yutani_gfx_lib.flip(self._gfx)
          yutani_lib.yutani_flip(yutani_ctx._ptr, self._ptr)
  
      def close(self):
          """Close the window."""
          if self.wid in yutani_windows:
              del yutani_windows[self.wid]
          self.closed = True
          yutani_lib.yutani_close(yutani_ctx._ptr, self._ptr)
          yutani_lib.release_graphics_yutani(self._gfx)
  
      def move(self, x, y):
          """Move the window to the requested location."""
          yutani_lib.yutani_window_move(yutani_ctx._ptr, self._ptr, x, y)
  
      def resize_accept(self, w, h):
          """Inform the server that we have accepted the offered resize."""
          yutani_lib.yutani_window_resize_accept(yutani_ctx._ptr, self._ptr, w, h)
  
      def resize_done(self):
          """Inform the server that we are done resizing and the new window may be displayed."""
          yutani_lib.yutani_window_resize_done(yutani_ctx._ptr, self._ptr)
  
      def resize_offer(self, width, height):
          """Offer alternative dimensions in response to a server offer."""
          yutani_lib.yutani_window_resize_offer(yutani_ctx._ptr, self._ptr, width, height)
  
      def resize(self, width, height):
          """Request that a window be resized to the given dimensions."""
          yutani_lib.yutani_window_resize(yutani_ctx._ptr, self._ptr, width, height)
  
      def reinit(self):
          """Reinitialize the internal graphics context for the window. Should be done after a resize_accept."""
          yutani_lib.reinit_graphics_yutani(self._gfx, self._ptr)
  
      def fill(self, color):
          """Fill the entire window with a given color."""
          yutani_gfx_lib.draw_fill(self._gfx, color)
  
      def update_shape(self, mode):
          """Set the mouse passthrough / window shaping mode. Does not affect appearance of window."""
          yutani_lib.yutani_window_update_shape(yutani_ctx._ptr, self._ptr, mode)
  
      def set_stack(self, stack):
          """Set the stack layer for the window."""
          yutani_lib.yutani_set_stack(yutani_ctx._ptr, self._ptr, stack)
  
      def drag_start(self):
          """Begin window drag."""
          yutani_lib.yutani_window_drag_start(yutani_ctx._ptr, self._ptr)
  
      @property
      def width(self):
          return self._ptr.contents.width
  
      @property
      def height(self):
          return self._ptr.contents.height
  
      # TODO: setters for width/height call resize?
  
      @property
      def wid(self):
          """The identifier of the window."""
          return self._ptr.contents.wid
  
      @property
      def focused(self):
          """Whether the window is current focused."""
          return self._ptr.contents.focused
  
      @focused.setter
      def focused(self, value):
          self._ptr.contents.focused = value
  
  class Decor(object):
      """Class for rendering decorations with the system decorator library."""
  
      EVENT_OTHER = 1
      EVENT_CLOSE = 2
      EVENT_RESIZE = 3
  
      def __init__(self):
          self.lib = CDLL("libtoaru-decorations.so")
          self.lib.init_decorations()
  
      def width(self):
          """The complete width of the left and right window borders."""
          return int(self.lib.decor_width())
  
      def height(self):
          """The complete height of the top and bottom window borders."""
          return int(self.lib.decor_height())
  
      def top_height(self):
          """The height of the top edge of the decorations."""
          return c_uint32.in_dll(self.lib, "decor_top_height").value
  
      def bottom_height(self):
          """The height of the bottom edge of the decorations."""
          return c_uint32.in_dll(self.lib, "decor_bottom_height").value
  
      def left_width(self):
          """The width of the left edge of the decorations."""
          return c_uint32.in_dll(self.lib, "decor_left_width").value
  
      def right_width(self):
          """The width of the right edge of the decorations."""
          return c_uint32.in_dll(self.lib, "decor_right_width").value
  
      def render(self, window, title=None):
          """Render decorations on this window. If a title is not provided, it will be retreived from the window object."""
          if not title:
              title = window.title
          title_string = title.encode('utf-8') if title else None
          self.lib.render_decorations(window._ptr, window._gfx, title_string)
  
      def handle_event(self, msg):
          """Let the decorator library handle an event. Usually passed mouse events."""
          return self.lib.decor_handle_event(yutani_ctx._ptr, msg._ptr)
  
  # Demo follows.
  if __name__ == '__main__':
      # Connect to the server.
      Yutani()
  
      # Initialize the decoration library.
      d = Decor()
  
      # Create a new window.
      w = Window(200+d.width(),200+d.height(),title="Python Demo")
  
      # Since this is Python, we can attach data to our window, such
      # as its internal width (excluding the decorations).
      w.int_width = 200
      w.int_height = 200
  
      # We can set window shaping...
      w.update_shape(WindowShape.THRESHOLD_HALF)
  
      # Move the window...
      w.move(100, 100)
  
      def draw_decors():
          """Render decorations for the window."""
          d.render(w)
  
      def draw_window():
          """Draw the window."""
          w.fill(0xFFFF00FF)
          draw_decors()
  
      def finish_resize(msg):
          """Accept a resize."""
  
          # Tell the server we accept.
          w.resize_accept(msg.width, msg.height)
  
          # Reinitialize internal graphics context.
          w.reinit()
  
          # Calculate new internal dimensions.
          w.int_width = msg.width - d.width()
          w.int_height = msg.height - d.height()
  
          # Redraw the window buffer.
          draw_window()
  
          # Inform the server we are done.
          w.resize_done()
  
          # And flip.
          w.flip()
  
      # Do an initial draw.
      draw_window()
  
      # Don't forget to flip. Our single-buffered window only needs
      # the Yutani flip call, but the API will perform both if needed.
      w.flip()
  
      while 1:
          # Poll for events.
          msg = yutani_ctx.poll()
          if msg.type == Message.MSG_SESSION_END:
              # All applications should attempt to exit on SESSION_END.
              w.close()
              break
          elif msg.type == Message.MSG_KEY_EVENT:
              # Print key events for debugging.
              print(f'W({msg.wid}) key {msg.event.key} {msg.event.action}')
              if msg.event.key == b'q':
                  # Convention says to close windows when 'q' is pressed,
                  # unless we're using keyboard input "normally".
                  w.close()
                  break
          elif msg.type == Message.MSG_WINDOW_FOCUS_CHANGE:
              # If the focus of our window changes, redraw the borders.
              if msg.wid == w.wid:
                  # This attribute is stored in the underlying struct
                  # and used by the decoration library to pick which
                  # version of the decorations to draw for the window.
                  w.focused = msg.focused
                  draw_decors()
                  w.flip()
          elif msg.type == Message.MSG_RESIZE_OFFER:
              # Resize the window.
              finish_resize(msg)
          elif msg.type == Message.MSG_WINDOW_MOUSE_EVENT:
              # Handle mouse events, first by passing them
              # to the decorator library for processing.
              if d.handle_event(msg) == Decor.EVENT_CLOSE:
                  # Close the window when the 'X' button is clicked.
                  w.close()
                  break
              else:
                  # For events that didn't get handled by the decorations,
                  # print a debug message with details.
                  print(f'W({msg.wid}) mouse {msg.new_x},{msg.new_y}')
  