#+TITLE: Demonstration on how to switch windows with python #+DATE: 2017-04-07 12:00:00 UTC #+DESCRIPTION: Shows how to get all window and change focus sequentially, could be used to implement your own window switcher. #+FILETAGS: xcb:python:xorg #+CATEGORY: python #+SLUG: xcb-window-switching-example #+THUMBNAIL: ../../../images/xcb/xcb-window-switcher.jpg #+BEGIN_COMMENT .. title: Demonstration on how to switch windows with python .. slug: xcb-window-switching-example .. date: 2017-04-07 12:00:00 UTC .. tags: xcb, python, xorg .. category: python .. description: Shows how to get all window and change focus sequentially, could be used to implement your own window switcher. .. type: text #+END_COMMENT #+CAPTION: Window list output [[../../../images/xcb/xcb-window-switcher.jpg]] I have been experimenting with writing my own launcher app similar to gnome do, one of the things i wanted was to switch windows by typing the name, so i wrote the below example to work out how to switch window. It works with you xserver to request a list of windows and then send the event to change focus, i have only tested this in gnome how ever it will likely work with other desktops. The main thing you need todo is to set input focus before raising the window, if you do not some window managers like gnome will just notify you instead of raising the window. #+BEGIN_SRC python #!/usr/bin/env python import time import struct import xcb from xcb import xproto # standard xcb to get an xserver connection and root window xserver = xcb.connect() xclient = xserver.core setup = xserver.get_setup() canvas = setup.roots[0] root_window = canvas.root unsigned_int_32_max_size = (1 << 32) - 1 def get_atom(name): return xclient.InternAtom( 0, len(name), name ).reply() # setup a load of atoms as constants for later use _NET_WM_STATE = get_atom('_NET_WM_STATE') _NET_WM_NAME = get_atom('_NET_WM_NAME') _NET_WM_WINDOW_TYPE = get_atom('_NET_WM_WINDOW_TYPE') _NET_WM_WINDOW_TYPE_APPLICATION = get_atom('_NET_WM_WINDOW_TYPE_NORMAL') _NET_CLIENT_LIST = get_atom('_NET_CLIENT_LIST') # query _NET_CLIENT_LIST which contains a list of windows clientlist_reply = xclient.GetProperty( False, root_window, _NET_CLIENT_LIST.atom, xcb.xproto.GetPropertyType.Any, 0, unsigned_int_32_max_size).reply() # unpack the reply into a list, xcb returns a list of ints # in this case window_list = list(struct.unpack( 'I' * clientlist_reply.value_len, clientlist_reply.value.buf())) for window in window_list: if window is 0: continue # get some of the useful properties # you can use xprop in a terminal to see whats available window_name = xclient.GetProperty( delete=False, window=window, property=xproto.Atom.WM_NAME, type=xproto.GetPropertyType.Any, long_offset=0, long_length=unsigned_int_32_max_size).reply() window_class = xclient.GetProperty( delete=False, window=window, property=xproto.Atom.WM_CLASS, type=xproto.GetPropertyType.Any, long_offset=0, long_length=unsigned_int_32_max_size).reply() window_type = xclient.GetProperty( delete=False, window=window, property=_NET_WM_WINDOW_TYPE.atom, type=xproto.GetPropertyType.Any, long_offset=0, long_length=1).reply() window_net_name = xclient.GetProperty( delete=False, window=window, property=_NET_WM_NAME.atom, type=xproto.Atom.Any, long_offset=0, long_length=unsigned_int_32_max_size).reply() # This does the focus, set the window to have input focus # then raise the window with configure window xclient.SetInputFocus( xcb.xproto.InputFocus.Parent, window, xcb.xproto.Time.CurrentTime) xclient.ConfigureWindow( window, xproto.ConfigWindow.StackMode, [xproto.StackMode.Above]) xserver.flush() time.sleep(0.25) window_class = ''.join([chr(c) for c in window_class.value]) window_name = ''.join([chr(c) for c in window_name.value]) window_net_name = ''.join([chr(c) for c in window_net_name.value]) print('-------') print('window id = %s' % window) print('window name = %s' % window_name) print('window net name = %s' % window_net_name) print('window class = %s' % window_class) #+END_SRC