def actor_on_configure_notify(self, evt): """ if the actor is configured, configure the window, too """ if not self._obsolete: geom = Rect(width=evt.width, height=evt.height) compute_window_geom(geom) self._window_configures += 1 self.client.window.configure(**geom.to_dict()) # TODO: is that efficient? self.client.conn.flush()
def on_window_configure_notify(self, event): rect = Rect.from_object(event) if rect.width != self.style['width'] or rect.height != self.style['height']: self.style['width'] = rect.width self.style['height'] = rect.height self.recreate_surface() self.layout()
def window_on_configure_notify(self, evt): """ if the window is configured, configure the actor, too """ log.debug('%s got window configure notify event, configure counter=%d' % (self, self._window_configures)) if self._window_configures == 0: geom = Rect.from_object(evt) compute_actor_geom(geom) self.client.actor.configure(**geom.to_dict()) self.client.conn.flush() else: self._window_configures -= 1
def __init__(self, screen, window, wa): self.screen = screen self.window = window self.geom = Rect(wa.x, wa.y, wa.width, wa.height) self.floating_geom = self.geom.copy() self.maxed_geom = self.geom.copy() self.old_border = wa.border_width self.desktop = None self.border_width = 1 self.title = None self.maximised = False self.minimised = False self.shaded = False self.sticky = False self.skip_taskbar = False #self.decorated = True self.resizing = False self.config = samuraix.config['client'] self.configure_window() self.update_title() self.update_size_hints() self.update_wm_hints() self.check_ewmh() log.info("new client with %s %s" % (self.window, self.geom)) self.all_clients.append(self) self.window_2_client_map[self.window] = self self.frame_context = None frame_geom = self.geom.copy() frame_geom.height += 15 frame_geom.width += 2 self.frame = SimpleWindow(self.screen, self.geom, 1) xlib.XReparentWindow(samuraix.display, self.window, self.frame.window, 1, 15) xlib.XMapWindow(samuraix.display, self.frame.window) self.draw_frame() self.all_frames.append(self.frame) self.window_2_frame_map[self.frame.window] = self xlib.XSelectInput(samuraix.display, self.frame.window, xlib.StructureNotifyMask | xlib.PropertyChangeMask | xlib.EnterWindowMask) self.decorations = [] #[TitleBar(self)] self.update_decorations()
def window_on_configure_notify(self, event): if self._window_configures != 0: self._window_configures -=1 else: self._window_configures += 1 geom = Rect.from_object(event) if geom.width != self.clientwin.style['width'] or geom.height != self.clientwin.style['height']: self.clientwin.style['width'] = geom.width self.clientwin.style['height'] = geom.height self.ui.fit() # put the width and height back because we want these to be # automatic self.clientwin.style['width'] = None self.clientwin.style['height'] = None
class Client(pyglet.event.EventDispatcher): all_clients = [] window_2_client_map = weakref.WeakValueDictionary() all_frames = [] window_2_frame_map = weakref.WeakValueDictionary() @classmethod def get_by_window(cls, window): return cls.window_2_client_map.get(window) @classmethod def get_by_frame(cls, window): return cls.window_2_frame_map.get(window) def __init__(self, screen, window, wa): self.screen = screen self.window = window self.geom = Rect(wa.x, wa.y, wa.width, wa.height) self.floating_geom = self.geom.copy() self.maxed_geom = self.geom.copy() self.old_border = wa.border_width self.desktop = None self.border_width = 1 self.title = None self.maximised = False self.minimised = False self.shaded = False self.sticky = False self.skip_taskbar = False #self.decorated = True self.resizing = False self.config = samuraix.config['client'] self.configure_window() self.update_title() self.update_size_hints() self.update_wm_hints() self.check_ewmh() log.info("new client with %s %s" % (self.window, self.geom)) self.all_clients.append(self) self.window_2_client_map[self.window] = self self.frame_context = None frame_geom = self.geom.copy() frame_geom.height += 15 frame_geom.width += 2 self.frame = SimpleWindow(self.screen, self.geom, 1) xlib.XReparentWindow(samuraix.display, self.window, self.frame.window, 1, 15) xlib.XMapWindow(samuraix.display, self.frame.window) self.draw_frame() self.all_frames.append(self.frame) self.window_2_frame_map[self.frame.window] = self xlib.XSelectInput(samuraix.display, self.frame.window, xlib.StructureNotifyMask | xlib.PropertyChangeMask | xlib.EnterWindowMask) self.decorations = [] #[TitleBar(self)] self.update_decorations() def __str__(self): return "<Client window=%s geom=%s title='%s'>" % (self.window, self.geom, self.title) def configure_window(self): ce = xlib.XConfigureEvent() ce.type = xlib.ConfigureNotify ce.display = samuraix.display ce.event = self.window ce.window = self.window ce.x = self.geom.x ce.y = self.geom.y ce.width = self.geom.width ce.height = self.geom.height ce.border_width = self.border_width ce.above = xlib.None_ ce.override_redirect = False return xlib.XSendEvent(samuraix.display, self.window, False, xlib.StructureNotifyMask, cast(byref(ce), POINTER(xlib.XEvent))) def check_ewmh(self): format = c_int() real = xlib.Atom() data = c_uchar_p() n = c_ulong() extra = c_ulong() #if (xlib.XGetWindowProperty(samuraix.display, self.window, samuraix.atoms['_NET_WM_STATE'], # 0, LONG_NAN, False, xatom.XA_ATOM, byref(real), byref(format), byref(n), # byref(extra), byref(data)) == xlib.Success): # state = cast(data, xlib.Atom_p) def process_property_notify(self, ev): log.debug('prop change for client %s' % client) if ev.atom == xatom.XA_WM_TRANSIENT_FOR: trans = xlib.Window() xlib.XGetTransientForHint(samuraix.display, self.window, byref(trans)) # needs rearrange elif ev.atom == xatom.XA_WM_NORMAL_HINTS: self.update_size_hints() elif ev.atom == xatom.XA_WM_HINTS: self.update_wm_hints() elif ev.atom == xatom.XA_WM_NAME or ev.atom == samuraix.atoms['_NET_WM_NAME']: self.update_title() def update_title(self): title = xhelpers.get_text_property(self.window, samuraix.atoms['_NET_WM_NAME']) if not title: title = xhelpers.get_text_property(self.window, samuraix.atoms['WM_NAME']) if title != self.title: self.title = title self.dispatch_event('on_title_changed') log.debug("title of %s is now %s" % (self, self.title)) def update_size_hints(self): msize = c_long() size = xlib.XSizeHints() if not xlib.XGetWMNormalHints(samuraix.display, self.window, byref(size), byref(msize)): return 0 if size.flags & xlib.PBaseSize: self.base_width = size.base_width self.base_height = size.base_height elif size.flags & xlib.PMinSize: self.base_width = size.min_width self.base_height = size.min_height else: self.base_width = 0 self.base_height = 0 if size.flags & xlib.PResizeInc: self.inc_width = size.width_inc self.inc_height = size.height_inc else: self.inc_width = 0 self.inc_height = 0 if size.flags & xlib.PMaxSize: self.max_width = size.max_width self.max_height = size.max_height else: self.max_width = 0 self.max_height = 0 if size.flags & xlib.PMinSize: self.min_width = size.min_width self.min_height = size.min_height elif size.flags & xlib.PBaseSize: self.min_width = size.base_width self.min_height = size.base_height else: self.min_width = 0 self.min_height = 0 if size.flags & xlib.PAspect: self.min_aspect_x = size.min_aspect.x self.min_aspect_y = size.min_aspect.y self.max_aspect_x = size.max_aspect.x self.max_aspect_y = size.max_aspect.y else: self.min_aspect_x = 0 self.min_aspect_y = 0 self.max_aspect_x = 0 self.max_aspect_y = 0 return size.flags def update_wm_hints(self): wmhp = xlib.XGetWMHints(samuraix.display, self.window) if wmhp: wmh = wmhp[0] self.urgent = wmh.flags & xlib.XUrgencyHint if self.urgent: # and its not the focused window... pass # meant to invalidate that cache and draw titlebar if wmh.flags & xlib.StateHint and wmh.initial_state == xlib.WithdrawnState: self.border_width = 0 self.skip = True xlib.XFree(wmhp) def process_ewmh_state_atom(self, client, state, set): def handle_prop(prop, cb=None): if set == NET_WM_STATE_ADD: r = True elif set == NET_WM_STATE_REMOVE: r = False elif set == NET_WM_STATE_TOGGLE: r = not getattr(self, prop) if cb is not None: if r != getattr(self, prop): cb() else: setattr(self, prop, r) if state == samuraix.atoms['_NET_WM_STATE_STICKY']: sticky = handle_prop('sticky', self.toggle_sticky) elif state == samuraix.atoms['_NET_WM_STATE_SKIP_TASKBAR']: skip_taskbar = handle_prop('skip_taskbar') elif state == samuraix.atoms['_NET_WM_STATE_FULLSCREEN']: fullscreen = handle_prop('fullscreen', self.toggle_fullscreen) def update_decorations(self): for decoration in self.decorations: decoration.update_geometry() def resize(self, geometry, hints=False): if geometry.width <= 0 or geometry.height <= 0: log.debug('not resizing - too small') return False if (geometry.x != self.geom.x or geometry.y != self.geom.y or geometry.width != self.geom.width or geometry.height != self.geom.height): wc = xlib.XWindowChanges() self.geom.x = wc.x = geometry.x self.geom.y = wc.y = geometry.y self.geom.width = wc.width = geometry.width self.geom.height = wc.height = geometry.height wc.border_width = self.border_width xlib.XConfigureWindow(samuraix.display, self.frame.window, xlib.CWX | xlib.CWY | xlib.CWWidth | xlib.CWHeight | xlib.CWBorderWidth, byref(wc)) self.frame_context = None self.draw_frame() wc.x = 1 wc.y = 15 wc.width = self.geom.width - 2 wc.height = self.geom.height - 15 wc.border_width = 0 xlib.XConfigureWindow(samuraix.display, self.window, xlib.CWX | xlib.CWY | xlib.CWWidth | xlib.CWHeight | xlib.CWBorderWidth, byref(wc)) self.configure_window() if not self.resizing: self.update_decorations() def draw_frame(self): if self.frame_context is None: self.frame_context = DrawContext(self.screen, self.geom.width, self.geom.height, self.frame.drawable) self.frame_context.fill((0.0, 0.0, 1.0)) self.frame.refresh_drawable() def focus(self): log.debug('focusing %s' % self) xlib.XSetInputFocus(samuraix.display, self.window, xlib.RevertToPointerRoot, xlib.CurrentTime) self.bring_to_front() self.grab_buttons() if self.screen.focused_client is not None: self.screen.focused_client.dispatch_event('on_blur') self.screen.focused_client = self self.dispatch_event('on_focus') def bring_to_front(self): log.debug('stacking %s' % self) xlib.XRaiseWindow(samuraix.display, self.window) for decoration in self.decorations: decoration.bring_to_front() def maximise(self): self.maximised = True self.resize(self.screen.workspace_geom) def unmaximise(self): self.maximised = False self.resize(self.floating_geom) def toggle_maximise(self): if self.maximised: self.unmaximise() else: self.maximise() def toggle_sticky(self): pass def toggle_fullscreen(self): pass def remove(self): log.debug('removing %s' % self) try: self.all_clients.remove(self) del self.window_2_client_map[self.window] except (ValueError, KeyError): log.warn('remove bug') wc = xlib.XWindowChanges() wc.border_width = self.old_border xlib.XGrabServer(samuraix.display) xlib.XConfigureWindow(samuraix.display, self.window, xlib.CWBorderWidth, byref(wc)) xlib.XUngrabButton(samuraix.display, xlib.AnyButton, xlib.AnyModifier, self.window) xhelpers.set_window_state(self.window, xlib.WithdrawnState) xlib.XSync(samuraix.display, False) xlib.XUngrabServer(samuraix.display) self.dispatch_event('on_removed') for decoration in self.decorations: decoration.remove() def on_button_press(self, ev): modifiers = CLEANMASK(ev.state) log.debug("client %s button_press %s %s" % (self, ev.button, modifiers)) try: func = self.config['buttons'][(ev.button, modifiers)] except KeyError: log.debug("no callback found for event") else: func(self) def grab_buttons(self): log.debug("grab_buttons %s %s" % (self, self.window)) xlib.XGrabButton(samuraix.display, xlib.Button1, xlib.NoSymbol, self.window, False, BUTTONMASK, xlib.GrabModeSync, xlib.GrabModeAsync, xlib.None_, xlib.None_) xlib.XGrabButton(samuraix.display, xlib.Button1, xlib.NoSymbol | xlib.LockMask, self.window, False, BUTTONMASK, xlib.GrabModeSync, xlib.GrabModeAsync, xlib.None_, xlib.None_) xlib.XGrabButton(samuraix.display, xlib.Button1, xlib.NoSymbol | xlib.NumLockMask, self.window, False, BUTTONMASK, xlib.GrabModeSync, xlib.GrabModeAsync, xlib.None_, xlib.None_) xlib.XGrabButton(samuraix.display, xlib.Button1, xlib.NoSymbol | xlib.NumLockMask | xlib.LockMask, self.window, False, BUTTONMASK, xlib.GrabModeSync, xlib.GrabModeAsync, xlib.None_, xlib.None_) for button, modifiers in self.config['buttons'].iterkeys(): xlib.XGrabButton(samuraix.display, button, modifiers, self.window, False, BUTTONMASK, xlib.GrabModeAsync, xlib.GrabModeSync, xlib.None_, xlib.None_) xlib.XGrabButton(samuraix.display, button, modifiers | xlib.LockMask, self.window, False, BUTTONMASK, xlib.GrabModeAsync, xlib.GrabModeSync, xlib.None_, xlib.None_) xlib.XGrabButton(samuraix.display, button, modifiers | xlib.NumLockMask, self.window, False, BUTTONMASK, xlib.GrabModeAsync, xlib.GrabModeSync, xlib.None_, xlib.None_) xlib.XGrabButton(samuraix.display, button, modifiers | xlib.NumLockMask | xlib.LockMask, self.window, False, BUTTONMASK, xlib.GrabModeAsync, xlib.GrabModeSync, xlib.None_, xlib.None_) self.screen.ungrab_buttons() def mousemove(self): if self.maximised: self.unmaximise() self.resize(self.floating_geom) root = self.screen.root_window if (xlib.XGrabPointer(samuraix.display, root, False, MOUSEMASK, xlib.GrabModeAsync, xlib.GrabModeAsync, root, samuraix.cursors['move'], xlib.CurrentTime) != xlib.GrabSuccess): return dummy = xlib.Window() x = c_int() y = c_int() di = c_int() dui = c_uint() xlib.XQueryPointer(samuraix.display, root, byref(dummy), byref(dummy), byref(x), byref(y), byref(di), byref(di), byref(dui)) x = x.value y = y.value ev = xlib.XEvent() ox = self.geom.x oy = self.geom.y geom = self.geom.copy() while True: xlib.XMaskEvent(samuraix.display, MOUSEMASK | xlib.ExposureMask | xlib.SubstructureRedirectMask, byref(ev)) if ev.type == xlib.ButtonRelease: xlib.XUngrabPointer(samuraix.display, xlib.CurrentTime) break elif ev.type == xlib.MotionNotify: geom.x = ox + (ev.xmotion.x - x) geom.y = oy + (ev.xmotion.y - y) self.resize(geom) else: samuraix.app.handle_event(ev) self.floating_geom = self.geom.copy() def mouseresize(self): if self.maximised: self.maximised = False self.resizing = True ocx = self.geom.x ocy = self.geom.y root = xlib.XRootWindow(samuraix.display, self.screen.num) dummy = xlib.Window() x = c_int() y = c_int() di = c_int() dui = c_uint() xlib.XQueryPointer(samuraix.display, root, byref(dummy), byref(dummy), byref(x), byref(y), byref(di), byref(di), byref(dui)) omx = x.value omy = y.value if (xlib.XGrabPointer(samuraix.display, root, False, MOUSEMASK, xlib.GrabModeAsync, xlib.GrabModeAsync, root, samuraix.cursors['resize'], xlib.CurrentTime) != xlib.GrabSuccess): return #xlib.XGrabServer(samuraix.display) gc = xlib.XCreateGC(samuraix.display, self.window, 0, None) xlib.XSetForeground(samuraix.display, gc, self.screen.white_pixel) xlib.XSetFunction(samuraix.display, gc, xlib.GXxor) xlib.XSetSubwindowMode(samuraix.display, gc, xlib.IncludeInferiors) xlib.XSetBackground(samuraix.display, gc, self.screen.white_pixel) xlib.XWarpPointer(samuraix.display, xlib.None_, self.window, 0, 0, 0, 0, self.geom.width + self.border_width - 1, self.geom.height + self.border_width - 1) ev = xlib.XEvent() geom = self.geom.copy() xlib.XDrawRectangle(samuraix.display, root, gc, geom.x, geom.y, geom.width, geom.height) xlib.XFlush(samuraix.display) xlib.XSync(samuraix.display, 0) ev = xlib.XEvent() while True: #xlib.XNextEvent(samuraix.display, byref(ev)) xlib.XMaskEvent(samuraix.display, MOUSEMASK | xlib.ExposureMask | xlib.SubstructureRedirectMask, byref(ev)) if ev.type == xlib.ButtonRelease: xlib.XUngrabPointer(samuraix.display, xlib.CurrentTime) break elif ev.type == xlib.MotionNotify: # erase the old box xlib.XDrawRectangle(samuraix.display, root, gc, geom.x, geom.y, geom.width, geom.height) geom.width = max(0, ev.xmotion.x - ocx - 2 * self.border_width + 1) geom.height = max(0, ev.xmotion.y - ocy - 2 * self.border_width + 1) xlib.XDrawRectangle(samuraix.display, root, gc, geom.x, geom.y, geom.width, geom.height) xlib.XFlush(samuraix.display) xlib.XSync(samuraix.display, 0) else: samuraix.app.handle_event(ev) # erase the box xlib.XDrawRectangle(samuraix.display, root, gc, geom.x, geom.y, geom.width, geom.height) xlib.XWarpPointer(samuraix.display, xlib.None_, root, 0, 0, 0, 0, omx, omy) xlib.XFlush(samuraix.display) xlib.XSync(samuraix.display, 0) #xlib.XUngrabServer(samuraix.display) xlib.XFreeGC(samuraix.display, gc) self.resize(geom) self.floating_geom = self.geom.copy() self.resizing = False self.update_decorations() def on_enter(self): log.debug("enter %s" % self) self.grab_buttons() #if samuraix.config['focus'] == 'sloppy': # self.desktop.focus_client(self) def ban(self): log.debug('banning %s' % self) xlib.XUnmapWindow(samuraix.display, self.window) xhelpers.set_window_state(self.window, xlib.IconicState) for decoration in self.decorations: decoration.ban() def unban(self): log.debug('unbanning %s' % self) xlib.XMapWindow(samuraix.display, self.window) xhelpers.set_window_state(self.window, xlib.NormalState) for decoration in self.decorations: decoration.unban() def move_to_desktop(self, desktop): log.debug('move to desktop %s %s' % (self, desktop)) self.desktop.remove_client(self) desktop.add_client(self)