""" This plugin exports four functions - up, down, left and right - that when called will move window focus to the first window in that general direction. Focussing is based entirely on position and geometry, so is independent of screens, layouts and whether windows are floating or tiled. It can also move focus to and from empty screens. Example usage: import traverse keys.extend([ Key([mod], 'k', lazy.function(traverse.up)), Key([mod], 'j', lazy.function(traverse.down)), Key([mod], 'h', lazy.function(traverse.left)), Key([mod], 'l', lazy.function(traverse.right)), ]) Qtile versions known to work: 0.16 - 0.18 """ from libqtile.config import Screen def up(qtile): _focus_window(qtile, -1, 'y') def down(qtile): _focus_window(qtile, 1, 'y') def left(qtile): _focus_window(qtile, -1, 'x') def right(qtile): _focus_window(qtile, 1, 'x') def get_window_in_direction(qtile, dir, axis): win = None win_wide = None dist = 10000 dist_wide = 10000 cur = qtile.current_window if not cur: cur = qtile.current_screen if axis == 'x': dim = 'width' band_axis = 'y' band_dim = 'height' cur_pos = cur.x band_min = cur.y band_max = cur.y + cur.height else: dim = 'height' band_axis = 'x' band_dim = 'width' band_min = cur.x cur_pos = cur.y band_max = cur.x + cur.width cur_pos += getattr(cur, dim) / 2 windows = [w for g in qtile.groups if g.screen for w in g.windows] windows.extend([s for s in qtile.screens if not s.group.windows]) if cur in windows: windows.remove(cur) for w in windows: if isinstance(w, Screen) or not w.minimized: pos = getattr(w, axis) + getattr(w, dim) / 2 gap = dir * (pos - cur_pos) if gap > 5: band_pos = getattr(w, band_axis) + getattr(w, band_dim) / 2 if band_min < band_pos < band_max: if gap < dist: dist = gap win = w else: if gap < dist_wide: dist_wide = gap win_wide = w if not win: win = win_wide return win def _focus_window(qtile, dir, axis): win = get_window_in_direction(qtile, dir, axis) if win: qtile.focus_screen(win.group.screen.index) win.group.focus(win, True) if not isinstance(win, Screen): win.focus(False)