Source code for powerline.segments.i3wm

# vim:fileencoding=utf-8:noet
from __future__ import (unicode_literals, division, absolute_import, print_function)

import re

from powerline.theme import requires_segment_info
from powerline.bindings.wm import get_i3_connection

WORKSPACE_REGEX = re.compile(r'^[0-9]+: ?')

def workspace_groups(w):
	group = []
	if w.focused:
		group.append('workspace:focused')
		group.append('w_focused')
	if w.urgent:
		group.append('workspace:urgent')
		group.append('w_urgent')
	if w.visible:
		group.append('workspace:visible')
		group.append('w_visible')
	group.append('workspace')
	return group


def format_name(name, strip=False):
	if strip:
		return WORKSPACE_REGEX.sub('', name, count=1)
	return name


def is_empty_workspace(workspace, containers):
	if workspace.focused or workspace.visible:
		return False
	wins = [win for win in containers[workspace.name].leaves()]
	return False if len(wins) > 0 else True

WS_ICONS = {"multiple": "M"}

def get_icon(workspace, separator, icons, show_multiple_icons, ws_containers):
	icons_tmp = WS_ICONS
	icons_tmp.update(icons)
	icons = icons_tmp

	wins = [win for win in ws_containers[workspace.name].leaves() \
		if win.parent.scratchpad_state == 'none']
	if len(wins) == 0:
		return ''

	result = ''
	cnt = 0
	for key in icons:
		if not icons[key] or len(icons[key]) < 1:
			continue
		if any(key in win.window_class for win in wins if win.window_class):
			result += (separator if cnt > 0 else '') + icons[key]
			cnt += 1
	if not show_multiple_icons and cnt > 1:
		if 'multiple' in icons:
			return icons['multiple']
		else:
			return ''
	return result

[docs]@requires_segment_info def workspaces(pl, segment_info, only_show=None, output=None, strip=0, format='{name}', icons=WS_ICONS, sort_workspaces=False, show_output=False, priority_workspaces=[], hide_empty_workspaces=False): '''Return list of used workspaces :param list only_show: Specifies which workspaces to show. Valid entries are ``"visible"``, ``"urgent"`` and ``"focused"``. If omitted or ``null`` all workspaces are shown. :param str output: May be set to the name of an X output. If specified, only workspaces on that output are shown. Overrides automatic output detection by the lemonbar renderer and bindings. Use "__all__" to show workspaces on all outputs. :param int strip: Specifies how many characters from the front of each workspace name should be stripped (e.g. to remove workspace numbers). Defaults to zero. :param str format: Specifies the format used to display workspaces; defaults to ``{name}``. Valid fields are: ``name`` (workspace name), ``number`` (workspace number if present), `stipped_name`` (workspace name stripped of leading number), ``icon`` (if available, icon for application running in the workspace, uses the ``multiple`` icon instead of multiple different icons), ``multi_icon`` (similar to ``icon``, but does not use ``multiple``, instead joins all icons with a single space) :param dict icons: A dictionary mapping a substring of window classes to strings to be used as an icon for that window class. Further, there is a ``multiple`` icon for workspaces containing more than one window. :param bool sort_workspaces: Sort the workspaces displayed by their name according to the natural ordering. :param bool show_output: Shows the name of the output if more than one output is connected. :param list priority_workspaces: A list of workspace names to be sorted before any other workspaces in the given order. :param bool hide_empty_workspaces: Hides all workspaces without any open window. Also hides non-focussed workspaces containing only an open scratchpad. Highlight groups used: ``workspace`` or ``w_visible``, ``workspace:visible``, ``workspace`` or ``w_focused``, ``workspace:focused``, ``workspace`` or ``w_urgent``, ``workspace:urgent``, ``workspace`` or ``output``. ''' conn = get_i3_connection() if not output == "__all__": output = output or segment_info.get('output') else: output = None if output: output = [output] else: output = [o.name for o in conn.get_outputs() if o.active] def sort_ws(ws): if sort_workspaces: def natural_key(ws): str = ws.name return [int(s) if s.isdigit() else s for s in re.split(r'(\d+)', str)] ws = sorted(ws, key=natural_key) result = [] for n in priority_workspaces: result += [w for w in ws if w.name == n] return result + [w for w in ws if not w.name in priority_workspaces] ws_containers = {w_con.name : w_con for w_con in conn.get_tree().workspaces()} if len(output) <= 1: res = [] if show_output: res += [{ 'contents': output[0], 'highlight_groups': ['output'] }] res += [{ 'contents': format.format(name = w.name[min(len(w.name), strip):], stripped_name = format_name(w.name, strip=True), number = w.num, icon = get_icon(w, '', icons, False, ws_containers), multi_icon = get_icon(w, ' ', icons, True, ws_containers)), 'highlight_groups': workspace_groups(w) } for w in sort_ws(conn.get_workspaces()) \ if (not only_show or any(getattr(w, tp) for tp in only_show)) \ if w.output == output[0] \ if not (hide_empty_workspaces and is_empty_workspace(w, ws_containers))] return res else: res = [] for n in output: if show_output: res += [{ 'contents': n, 'highlight_groups': ['output'] }] res += [{ 'contents': format.format(name = w.name[min(len(w.name), strip):], stripped_name = format_name(w.name, strip=True), number = w.num, icon = get_icon(w, '', icons, False, ws_containers), multi_icon = get_icon(w, ' ', icons, True, ws_containers)), 'highlight_groups': workspace_groups(w) } for w in sort_ws(conn.get_workspaces()) \ if (not only_show or any(getattr(w, tp) for tp in only_show)) \ if w.output == n \ if not (hide_empty_workspaces and is_empty_workspace(w, ws_containers))] return res
[docs]@requires_segment_info def workspace(pl, segment_info, workspace=None, strip=False, format=None, icons=WS_ICONS): '''Return the specified workspace name :param str workspace: Specifies which workspace to show. If unspecified, may be set by the ``list_workspaces`` lister if used, otherwise falls back to currently focused workspace. :param bool strip: Specifies whether workspace numbers (in the ``1: name`` format) should be stripped from workspace names before being displayed. Defaults to false. Deprecated: Use {name} or {stripped_name} of format instead. :param str format: Specifies the format used to display workspaces; defaults to ``{name}``. Valid fields are: ``name`` (workspace name), ``number`` (workspace number if present), `stipped_name`` (workspace name stripped of leading number), ``icon`` (if available, icon for application running in the workspace, uses the ``multiple`` icon instead of multiple different icons), ``multi_icon`` (similar to ``icon``, but does not use ``multiple``, instead joins all icons with a single space) :param dict icons: A dictionary mapping a substring of window classes to strings to be used as an icon for that window class. Further, there is a ``multiple`` icon for workspaces containing more than one window. Highlight groups used: ``workspace`` or ``w_visible``, ``workspace:visible``, ``workspace`` or ``w_focused``, ``workspace:focused``, ``workspace`` or ``w_urgent``, ``workspace:urgent``, ``workspace``. ''' if format == None: format = '{stripped_name}' if strip else '{name}' conn = get_i3_connection() ws_containers = {w_con.name : w_con for w_con in conn.get_tree().workspaces()} if workspace: try: w = next(( w for w in conn.get_workspaces() if w.name == workspace )) except StopIteration: return None elif segment_info.get('workspace'): w = segment_info['workspace'] else: try: w = next(( w for w in conn.get_workspaces() if w.focused )) except StopIteration: return None return [{ 'contents': format.format(name = w.name, stripped_name = format_name(w.name, strip=True), number = w.num, icon = get_icon(w, '', icons, False, ws_containers), multi_icon = get_icon(w, ' ', icons, True, ws_containers)), 'highlight_groups': workspace_groups(w) }]
[docs]@requires_segment_info def mode(pl, segment_info, names={'default': None}): '''Returns current i3 mode :param dict names: Specifies the string to show for various modes. Use ``null`` to hide a mode (``default`` is hidden by default). Highligh groups used: ``mode`` ''' mode = segment_info['mode'] if mode in names: return names[mode] return mode
def scratchpad_groups(w): group = [] if w.urgent: group.append('scratchpad:urgent') if w.nodes[0].focused: group.append('scratchpad:focused') if w.workspace().name != '__i3_scratch': group.append('scratchpad:visible') group.append('scratchpad') return group SCRATCHPAD_ICONS = { 'fresh': 'O', 'changed': 'X', }
[docs]def scratchpad(pl, icons=SCRATCHPAD_ICONS): '''Returns the windows currently on the scratchpad :param dict icons: Specifies the strings to show for the different scratchpad window states. Must contain the keys ``fresh`` and ``changed``. Highlight groups used: ``scratchpad`` or ``scratchpad:visible``, ``scratchpad`` or ``scratchpad:focused``, ``scratchpad`` or ``scratchpad:urgent``. ''' return [ { 'contents': icons.get(w.scratchpad_state, icons['changed']), 'highlight_groups': scratchpad_groups(w) } for w in get_i3_connection().get_tree().descendants() if w.scratchpad_state != 'none' ]
[docs]def active_window(pl, cutoff=100): '''Returns the title of the currently active window. :param int cutoff: Maximum title length. If the title is longer, the window_class is used instead. Highlight groups used: ``active_window_title``. ''' focused = get_i3_connection().get_tree().find_focused() cont = focused.name if len(cont) > cutoff: cont = focused.window_class return [{'contents': cont, 'highlight_groups': ['active_window_title']}] if focused.name != focused.workspace().name else []