Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Rearrange configuration objects a bit

There are several motivations for doing this:

* manager.py was huge, so anything that makes it smaller is a Good Thing.
* There are at least two hacks around circular dependencies which are removed
  by this commit. (There are still more which could probably be resolved, and
  hopefully those can be addressed without config breakage now.)
* With the dgroups refactoring, the config objects were sort of spread out
  everywhere; it's useful to have them in one place.

Full documentation is available in CHANGELOG or the docs, but a:

    sed -i -e 's/libqtile.manager/libqtile.config' config.py

should work for most people.
  • Loading branch information...
commit d6b7d1863bf6047c7dc3f449ba0307e8832252e1 1 parent 81308ea
@tych0 tych0 authored
View
14 CHANGELOG
@@ -3,11 +3,19 @@ qtile $NEXT, released $DATE:
This release breaks your config file in several ways:
- The Textbox widget no longer takes a ``name'' positional parameter,
since it was redundant; you can use the ``name'' kwarg to define it.
- - manager.Group is not used to configure groups any more;
- dgroups.Group replaces it. For simple configurations (i.e.
+ - manager.Group (now _Group) is not used to configure groups any more;
+ config.Group replaces it. For simple configurations (i.e.
Group("a") type configs), this should be a drop in replacement.
- dgroups.Group also provides many more options for showing and hiding
+ config.Group also provides many more options for showing and hiding
groups, assigning windows to groups by default, etc.
+ - The Key, Screen, Drag, and Click objects have moved from the manager
+ module to the config module.
+ - The Match object has moved from the dgroups module to the config
+ module.
+ For most people, you should be able to just:
+ sed -i -e 's/libqtile.manager/libqtile.config' config.py
+ ...dgroups users will need to go to a bit more work, but hopefully
+ configuration will be much simpler now for new users.
* features
- New widgets: task list,
- Added ability to drag and drop groups on GroupBox
View
10 docs/manual/config/groups.rst
@@ -12,10 +12,10 @@ be configured to show and hide themselves when they're not empty, spawn
applications for them when they start, automatically acquire certain groups,
and various other options.
-.. autoclass:: libqtile.dgroups.Match
+.. autoclass:: libqtile.config.Match
:members: __init__
-.. autoclass:: libqtile.dgroups.Group
+.. autoclass:: libqtile.config.Group
:members: __init__
.. autofunction:: libqtile.dgroups.simple_key_binder
@@ -25,13 +25,15 @@ Example
::
- from libqtile.dgroups import Group, simple_key_binder
+ from libqtile.config import Group, Match
groups = [
Group("a"),
Group("b"),
Group("c", match=Match(wm_title=["Firefox"])),
]
- # allow mod3+1 through mod3+0 to bind to groups
+ # allow mod3+1 through mod3+0 to bind to groups; if you bind your groups
+ # by hand in your config, you don't need to do this.
+ from libqtile.dgroups simple_key_binder
dgroups_key_binder = simple_key_binder("mod3")
View
11 docs/manual/config/index.rst
@@ -9,10 +9,13 @@ Configuration variables
-----------------------
:doc:`groups </manual/config/groups>`
- A list of ``libqtile.manager.Group`` objects which defines the group names. A group is a container for a bunch of windows, analogous to workspaces in other window managers. Each client window managed by the window manager belongs to exactly one group.
+ A list of ``libqtile.config.Group`` objects which defines the group names.
+ A group is a container for a bunch of windows, analogous to workspaces in
+ other window managers. Each client window managed by the window manager
+ belongs to exactly one group.
:doc:`keys </manual/config/keys>`
- A list of ``libqtile.manager.Key`` objects which defines the keybindings.
+ A list of ``libqtile.config.Key`` objects which defines the keybindings.
At a minimum, this will probably include bindings to switch between
windows, groups and layouts.
@@ -20,11 +23,11 @@ Configuration variables
A list of layout objects, configuring the layouts you want to use.
:doc:`mouse </manual/config/mouse>`
- A list of ``libqtile.manager.Drag`` and ``libqtile.manager.Click`` objects
+ A list of ``libqtile.config.Drag`` and ``libqtile.config.Click`` objects
defining mouse operations.
:doc:`screens </manual/config/screens>`
- A list of ``libqtile.manager.Screen`` objects, which defines the physical
+ A list of ``libqtile.config.Screen`` objects, which defines the physical
screens you want to use, and the bars and widgets associated with them.
Most of the visible "look and feel" configuration will happen in this
section.
View
2  docs/manual/config/keys.rst
@@ -17,7 +17,7 @@ Example
::
- from libqtile.manager import Key
+ from libqtile.config import Key
from libqtile.command import lazy
keys = [
Key(
View
2  docs/manual/config/mouse.rst
@@ -11,7 +11,7 @@ Example
::
- from libqtile.manager import Click, Drag
+ from libqtile.config import Click, Drag
mouse = [
Drag([mod], "Button1", lazy.window.set_position_floating(),
start=lazy.window.get_position()),
View
2  docs/manual/config/screens.rst
@@ -17,7 +17,7 @@ Tying together screens, bars and widgets, we get something like this:
::
- from libqtile.manager import Screen
+ from libqtile.config import Screen
from libqtile import bar, widget
screens = [
View
349 libqtile/config.py
@@ -0,0 +1,349 @@
+import command, hook, utils, xcbq
+
+class Key:
+ """
+ Defines a keybinding.
+ """
+ def __init__(self, modifiers, key, *commands):
+ """
+ - modifiers: A list of modifier specifications. Modifier
+ specifications are one of: "shift", "lock", "control", "mod1",
+ "mod2", "mod3", "mod4", "mod5".
+
+ - key: A key specification, e.g. "a", "Tab", "Return", "space".
+
+ - *commands: A list of lazy command objects generated with the
+ command.lazy helper. If multiple Call objects are specified, they
+ are run in sequence.
+ """
+ self.modifiers, self.key, self.commands = modifiers, key, commands
+ if key not in xcbq.keysyms:
+ raise utils.QtileError("Unknown key: %s" % key)
+ self.keysym = xcbq.keysyms[key]
+ try:
+ self.modmask = utils.translateMasks(self.modifiers)
+ except KeyError, v:
+ raise utils.QtileError(v)
+
+ def __repr__(self):
+ return "Key(%s, %s)" % (self.modifiers, self.key)
+
+class Drag(object):
+ """
+ Defines binding of a mouse to some dragging action
+
+ On each motion event command is executed
+ with two extra parameters added
+ x and y offset from previous move
+ """
+ def __init__(self, modifiers, button, *commands, **kw):
+ self.start = kw.pop('start', None)
+ if kw:
+ raise TypeError("Unexpected arguments: %s" % ', '.join(kw))
+ self.modifiers = modifiers
+ self.button = button
+ self.commands = commands
+ try:
+ self.button_code = int(self.button.replace('Button', ''))
+ self.modmask = utils.translateMasks(self.modifiers)
+ except KeyError, v:
+ raise utils.QtileError(v)
+
+ def __repr__(self):
+ return "Drag(%s, %s)" % (self.modifiers, self.button)
+
+
+class Click(object):
+ """
+ Defines binding of a mouse click
+ """
+ def __init__(self, modifiers, button, *commands):
+ self.modifiers = modifiers
+ self.button = button
+ self.commands = commands
+ try:
+ self.button_code = int(self.button.replace('Button', ''))
+ self.modmask = utils.translateMasks(self.modifiers)
+ except KeyError, v:
+ raise utils.QtileError(v)
+
+ def __repr__(self):
+ return "Click(%s, %s)" % (self.modifiers, self.button)
+
+
+class ScreenRect(object):
+
+ def __init__(self, x, y, width, height):
+ self.x = x
+ self.y = y
+ self.width = width
+ self.height = height
+
+ def __repr__(self):
+ return '<%s %d,%d %d,%d>' % (self.__class__.__name__,
+ self.x, self.y, self.width, self.height)
+
+ def hsplit(self, columnwidth):
+ assert columnwidth > 0
+ assert columnwidth < self.width
+ return (self.__class__(self.x, self.y, columnwidth, self.height),
+ self.__class__(self.x + columnwidth, self.y,
+ self.width - columnwidth, self.height))
+
+ def vsplit(self, rowheight):
+ assert rowheight > 0
+ assert rowheight < self.height
+ return (self.__class__(self.x, self.y, self.width, rowheight),
+ self.__class__(self.x, self.y + rowheight,
+ self.width, self.height - rowheight))
+
+
+class Screen(command.CommandObject):
+ """
+ A physical screen, and its associated paraphernalia.
+ """
+ group = None
+
+ def __init__(self, top=None, bottom=None, left=None, right=None,
+ x=None, y=None, width=None, height=None):
+ """
+ - top, bottom, left, right: Instances of bar objects, or None.
+
+ Note that bar.Bar objects can only be placed at the top or the
+ bottom of the screen (bar.Gap objects can be placed anywhere).
+
+ x,y,width and height aren't specified usually unless you are
+ using 'fake screens'.
+ """
+ self.top, self.bottom = top, bottom
+ self.left, self.right = left, right
+ self.qtile = None
+ self.index = None
+ self.x = x # x position of upper left corner can be > 0
+ # if one screen is "right" of the other
+ self.y = y
+ self.width = width
+ self.height = height
+
+ def _configure(self, qtile, index, x, y, width, height, group):
+ self.qtile = qtile
+ self.index, self.x, self.y = index, x, y,
+ self.width, self.height = width, height
+ self.setGroup(group)
+ for i in self.gaps:
+ i._configure(qtile, self)
+
+ @property
+ def gaps(self):
+ lst = []
+ for i in [self.top, self.bottom, self.left, self.right]:
+ if i:
+ lst.append(i)
+ return lst
+
+ @property
+ def dx(self):
+ return self.x + self.left.size if self.left else self.x
+
+ @property
+ def dy(self):
+ return self.y + self.top.size if self.top else self.y
+
+ @property
+ def dwidth(self):
+ val = self.width
+ if self.left:
+ val -= self.left.size
+ if self.right:
+ val -= self.right.size
+ return val
+
+ @property
+ def dheight(self):
+ val = self.height
+ if self.top:
+ val -= self.top.size
+ if self.bottom:
+ val -= self.bottom.size
+ return val
+
+ def get_rect(self):
+ return ScreenRect(self.dx, self.dy, self.dwidth, self.dheight)
+
+ def setGroup(self, new_group):
+ """
+ Put group on this screen
+ """
+ if new_group.screen == self:
+ return
+ elif new_group.screen:
+ # g1 <-> s1 (self)
+ # g2 (new_group)<-> s2 to
+ # g1 <-> s2
+ # g2 <-> s1
+ g1 = self.group
+ s1 = self
+ g2 = new_group
+ s2 = new_group.screen
+
+ s2.group = g1
+ g1._setScreen(s2)
+ s1.group = g2
+ g2._setScreen(s1)
+ else:
+ old_group = self.group
+ self.group = new_group
+
+ # display clients of the new group and then hide from old group
+ # to remove the screen flickering
+ new_group._setScreen(self)
+
+ if old_group is not None:
+ old_group._setScreen(None)
+
+ hook.fire("setgroup")
+ hook.fire("focus_change")
+ hook.fire("layout_change",
+ self.group.layouts[self.group.currentLayout],
+ self.group)
+
+ def _items(self, name):
+ if name == "layout":
+ return True, range(len(self.group.layouts))
+ elif name == "window":
+ return True, [i.window.wid for i in self.group.windows]
+ elif name == "bar":
+ return False, [x.position for x in self.gaps]
+
+ def _select(self, name, sel):
+ if name == "layout":
+ if sel is None:
+ return self.group.layout
+ else:
+ return utils.lget(self.group.layouts, sel)
+ elif name == "window":
+ if sel is None:
+ return self.group.currentWindow
+ else:
+ for i in self.group.windows:
+ if i.window.wid == sel:
+ return i
+ elif name == "bar":
+ return getattr(self, sel)
+
+ def resize(self, x=None, y=None, w=None, h=None):
+ x = x or self.x
+ y = y or self.y
+ w = w or self.width
+ h = h or self.height
+ self._configure(self.qtile, self.index, x, y, w, h, self.group)
+ for bar in [self.top, self.bottom, self.left, self.right]:
+ if bar:
+ bar.draw()
+ self.group.layoutAll()
+
+ def cmd_info(self):
+ """
+ Returns a dictionary of info for this screen.
+ """
+ return dict(
+ index=self.index,
+ width=self.width,
+ height=self.height,
+ x=self.x,
+ y=self.y
+ )
+
+ def cmd_resize(self, x=None, y=None, w=None, h=None):
+ """
+ Resize the screen.
+ """
+ self.resize(x, y, w, h)
+
+class Group(object):
+ """
+ Represents a "dynamic" group. These groups can spawn apps, only allow
+ certain Matched windows to be on them, hide when they're not in use, etc.
+ """
+ def __init__(self, name, matches=None, rules=None, exclusive=False,
+ spawn=None, layout=None, persist=True, init=True,):
+ """
+ :param name: the name of this group
+ :type name: string
+ :param matches: list of ``Match`` objects whose windows will be assigned to this group
+ :type matches: default ``None``
+ :param rules: list of ``Rule`` objectes wich are applied to this group
+ :type rules: default ``None``
+ :param exclusive: when other apps are started in this group, should we allow them here or not?
+ :type exclusive: boolean
+ :param spawn: this will be ``exec()`` d when the group is created
+ :type spawn: string
+ :param layout: the default layout for this group (e.g. 'max' or 'stack')
+ :type layout: string
+ :param persist: should this group stay alive with no member windows?
+ :type persist: boolean
+ :param init: is this group alive when qtile starts?
+ :type init: boolean
+
+ """
+ self.name = name
+ self.exclusive = exclusive
+ self.spawn = spawn
+ self.layout = layout
+ self.persist = persist
+ self.init = init
+ self.rules = rules
+ if self.rules is None:
+ self.rules = []
+ for rule in self.rules:
+ rule.group = self.name
+ if matches is None:
+ matches = []
+ self.matches = matches
+
+ # undocumented, any idea what these do?
+ self.master = None
+ self.ratio = None
+
+class Match(object):
+ ''' Match for dynamic groups
+ it can match by title, class or role '''
+ def __init__(self, title=[], wm_class=[], role=[], wm_type=[]):
+ """
+
+ ``Match`` supports both regular expression objects (i.e. the result of
+ ``re.compile()``) or strings (match as a "include" match). If a window
+ matches any of the things in any of the lists, it is considered a
+ match.
+
+ :param title: things to match against the title
+ :param wm_classes: things to match against the WM_CLASS atom
+ :param role: things to match against the WM_ROLE atom
+ :param wm_type: things to match against the WM_TYPE atom
+ """
+ self._rules = [('title', t) for t in title]
+ self._rules += [('wm_class', w) for w in wm_class]
+ self._rules += [('role', r) for r in role]
+ self._rules += [('wm_type', r) for r in wm_type]
+
+ def compare(self, client):
+ for _type, rule in self._rules:
+ match_func = getattr(rule, 'match', None) or\
+ getattr(rule, 'count')
+
+ if _type == 'title':
+ value = client.name
+ elif _type == 'wm_class':
+ value = client.window.get_wm_class()
+ if value and len(value)>1:
+ value = value[1]
+ elif value:
+ value = value[0]
+ elif _type == 'wm_type':
+ value = client.window.get_wm_type()
+ else:
+ value = client.window.get_wm_window_role()
+
+ if value and match_func(value):
+ return True
+ return False
View
99 libqtile/dgroups.py
@@ -2,53 +2,9 @@
import gobject
import libqtile.hook
-from libqtile.manager import Key
+from libqtile.config import Key
from libqtile.command import lazy
-class Match(object):
- ''' Match for dynamic groups
- it can match by title, class or role '''
- def __init__(self, title=[], wm_class=[], role=[], wm_type=[]):
- """
-
- ``Match`` supports both regular expression objects (i.e. the result of
- ``re.compile()``) or strings (match as a "include" match). If a window
- matches any of the things in any of the lists, it is considered a
- match.
-
- :param title: things to match against the title
- :param wm_classes: things to match against the WM_CLASS atom
- :param role: things to match against the WM_ROLE atom
- :param wm_type: things to match against the WM_TYPE atom
- """
- self._rules = [('title', t) for t in title]
- self._rules += [('wm_class', w) for w in wm_class]
- self._rules += [('role', r) for r in role]
- self._rules += [('wm_type', r) for r in wm_type]
-
- def compare(self, client):
- for _type, rule in self._rules:
- match_func = getattr(rule, 'match', None) or\
- getattr(rule, 'count')
-
- if _type == 'title':
- value = client.name
- elif _type == 'wm_class':
- value = client.window.get_wm_class()
- if value and len(value)>1:
- value = value[1]
- elif value:
- value = value[0]
- elif _type == 'wm_type':
- value = client.window.get_wm_type()
- else:
- value = client.window.get_wm_window_role()
-
- if value and match_func(value):
- return True
- return False
-
-
def simple_key_binder(mod, keynames=None):
"""
Bind keys to mod+group position or to the keys specified as
@@ -99,52 +55,6 @@ def __init__(self, match, group=None, float=False, intrusive=False):
def matches(self, w):
return self.match.compare(w)
-class Group(object):
- """
- Represents a "dynamic" group. These groups can spawn apps, only allow
- certain Matched windows to be on them, hide when they're not in use, etc.
- """
- def __init__(self, name, matches=None, rules=None, exclusive=False,
- spawn=None, layout=None, persist=True, init=True,):
- """
- :param name: the name of this group
- :type name: string
- :param matches: list of ``Match`` objects whose windows will be assigned to this group
- :type matches: default ``None``
- :param rules: list of ``Rule`` objectes wich are applied to this group
- :type rules: default ``None``
- :param exclusive: when other apps are started in this group, should we allow them here or not?
- :type exclusive: boolean
- :param spawn: this will be ``exec()`` d when the group is created
- :type spawn: string
- :param layout: the default layout for this group (e.g. 'max' or 'stack')
- :type layout: string
- :param persist: should this group stay alive with no member windows?
- :type persist: boolean
- :param init: is this group alive when qtile starts?
- :type init: boolean
-
- """
- self.name = name
- self.exclusive = exclusive
- self.spawn = spawn
- self.layout = layout
- self.persist = persist
- self.init = init
- self.rules = rules
- if self.rules is None:
- self.rules = []
- for rule in self.rules:
- rule.group = self.name
- if matches is None:
- matches = []
- self.rules.extend([Rule(match, group=self.name) for match in matches])
-
- # undocumented, any idea what these do?
- self.master = None
- self.ratio = None
-
-
class DGroups(object):
''' Dynamic Groups '''
def __init__(self, qtile, dgroups, key_binder=None, delay=1):
@@ -155,7 +65,12 @@ def __init__(self, qtile, dgroups, key_binder=None, delay=1):
for group in self.groups:
self.groupMap[group.name] = group
- self.rules = itertools.chain.from_iterable([g.rules for g in dgroups])
+ self.rules = list(itertools.chain.from_iterable([g.rules for g in dgroups]))
+
+ for group in dgroups:
+ rules = [Rule(m, group=group.name) for m in group.matches]
+ self.rules.extend(rules)
+
self.keys = []
self.key_binder = key_binder
View
379 libqtile/group.py
@@ -0,0 +1,379 @@
+import command, hook, window, utils
+import contextlib
+import xcb
+import xcb.xproto
+
+class _Group(command.CommandObject):
+ """
+ A group is a container for a bunch of windows, analogous to workspaces
+ in other window managers. Each client window managed by the window
+ manager belongs to exactly one group.
+ """
+ def __init__(self, name, layout=None):
+ self.name = name
+ self.customLayout = layout # will be set on _configure
+ self.windows = set()
+ self.qtile = None
+ self.layouts = []
+ self.floating_layout = None
+ self.currentWindow = None
+ self.screen = None
+ self.currentLayout = None
+
+ def _configure(self, layouts, floating_layout, qtile):
+ self.screen = None
+ self.currentLayout = 0
+ self.currentWindow = None
+ self.windows = set()
+ self.qtile = qtile
+ self.layouts = [i.clone(self) for i in layouts]
+ self.floating_layout = floating_layout.clone(self)
+ if self.customLayout is not None:
+ self.layout = self.customLayout
+ self.customLayout = None
+
+ @property
+ def layout(self):
+ return self.layouts[self.currentLayout]
+
+ @layout.setter
+ def layout(self, layout):
+ """
+ "layout" is a string with matching the name of a Layout object.
+ """
+ for index, obj in enumerate(self.layouts):
+ if obj.name == layout:
+ self.currentLayout = index
+ hook.fire("layout_change",
+ self.layouts[self.currentLayout], self)
+ self.layoutAll()
+ return
+ raise ValueError("No such layout: %s" % layout)
+
+ def nextLayout(self):
+ self.layout.hide()
+ self.currentLayout = (self.currentLayout + 1) % (len(self.layouts))
+ hook.fire("layout_change", self.layouts[self.currentLayout], self)
+ self.layoutAll()
+ screen = self.screen.get_rect()
+ self.layout.show(screen)
+
+ def prevLayout(self):
+ self.layout.hide()
+ self.currentLayout = (self.currentLayout - 1) % (len(self.layouts))
+ hook.fire("layout_change", self.layouts[self.currentLayout], self)
+ self.layoutAll()
+ screen = self.screen.get_rect()
+ self.layout.show(screen)
+
+ def layoutAll(self, warp=False):
+ """
+ Layout the floating layer, then the current layout.
+
+ If we have have a currentWindow give it focus, optionally
+ moving warp to it.
+ """
+ if self.screen and len(self.windows):
+ with self.disableMask(xcb.xproto.EventMask.EnterWindow):
+ normal = [x for x in self.windows if not x.floating]
+ floating = [x for x in self.windows
+ if x.floating and not x.minimized]
+ screen = self.screen.get_rect()
+ if normal:
+ self.layout.layout(normal, screen)
+ if floating:
+ self.floating_layout.layout(floating, screen)
+ if (self.currentWindow and
+ self.screen == self.qtile.currentScreen):
+ self.currentWindow.focus(warp)
+
+ def _setScreen(self, screen):
+ """
+ Set this group's screen to new_screen
+ """
+ if screen == self.screen:
+ return
+ self.screen = screen
+ if self.screen:
+ # move all floating guys offset to new screen
+ self.floating_layout.to_screen(self.screen)
+ self.layoutAll()
+ rect = self.screen.get_rect()
+ self.floating_layout.show(rect)
+ self.layout.show(rect)
+ else:
+ self.hide()
+
+ def hide(self):
+ self.screen = None
+ with self.disableMask(xcb.xproto.EventMask.EnterWindow |
+ xcb.xproto.EventMask.FocusChange |
+ xcb.xproto.EventMask.LeaveWindow):
+ for i in self.windows:
+ i.hide()
+ self.layout.hide()
+
+ @contextlib.contextmanager
+ def disableMask(self, mask):
+ for i in self.windows:
+ i._disableMask(mask)
+ yield
+ for i in self.windows:
+ i._resetMask()
+
+ def focus(self, win, warp):
+ """
+ if win is in the group, blur any windows and call
+ ``focus`` on the layout (in case it wants to track
+ anything), fire focus_change hook and invoke layoutAll.
+
+ warp - warp pointer to win
+ """
+ if self.qtile._drag:
+ # don't change focus while dragging windows
+ return
+ if win and not win in self.windows:
+ return
+ if win:
+ self.currentWindow = win
+ if win.floating:
+ for l in self.layouts:
+ l.blur()
+ self.floating_layout.focus(win)
+ else:
+ self.floating_layout.blur()
+ for l in self.layouts:
+ l.focus(win)
+ else:
+ self.currentWindow = None
+ hook.fire("focus_change")
+ # !!! note that warp isn't hooked up now
+ self.layoutAll(warp)
+
+ def info(self):
+ return dict(
+ name=self.name,
+ focus=self.currentWindow.name if self.currentWindow else None,
+ windows=[i.name for i in self.windows],
+ layout=self.layout.name,
+ floating_info=self.floating_layout.info(),
+ screen=self.screen.index if self.screen else None
+ )
+
+ def add(self, win):
+ hook.fire("group_window_add")
+ self.windows.add(win)
+ win.group = self
+ try:
+ if (win.window.get_net_wm_state() == 'fullscreen' and
+ self.qtile.config.auto_fullscreen):
+ win._float_state = window.FULLSCREEN
+ elif self.floating_layout.match(win):
+ # !!! tell it to float, can't set floating
+ # because it's too early
+ # so just set the flag underneath
+ win._float_state = window.FLOATING
+ except (xcb.xproto.BadWindow, xcb.xproto.BadAccess):
+ pass # doesn't matter
+ if win.floating:
+ self.floating_layout.add(win)
+ else:
+ for i in self.layouts:
+ i.add(win)
+ self.focus(win, True)
+
+ def remove(self, win):
+ self.windows.remove(win)
+ win.group = None
+ nextfocus = None
+ if win.floating:
+ nextfocus = self.floating_layout.remove(win)
+ if nextfocus is None:
+ nextfocus = self.layout.focus_first()
+ if nextfocus is None:
+ nextfocus = self.floating_layout.focus_first()
+ else:
+ for i in self.layouts:
+ if i is self.layout:
+ nextfocus = i.remove(win)
+ else:
+ i.remove(win)
+ if nextfocus is None:
+ nextfocus = self.floating_layout.focus_first()
+ if nextfocus is None:
+ nextfocus = self.layout.focus_first()
+ self.focus(nextfocus, True)
+ #else: TODO: change focus
+
+ def mark_floating(self, win, floating):
+ if floating and win in self.floating_layout.clients:
+ # already floating
+ pass
+ elif floating:
+ for i in self.layouts:
+ i.remove(win)
+ if win is self.currentWindow:
+ i.blur()
+ self.floating_layout.add(win)
+ if win is self.currentWindow:
+ self.floating_layout.focus(win)
+ else:
+ self.floating_layout.remove(win)
+ self.floating_layout.blur()
+ for i in self.layouts:
+ i.add(win)
+ if win is self.currentWindow:
+ i.focus(win)
+ self.layoutAll()
+
+ def _items(self, name):
+ if name == "layout":
+ return True, range(len(self.layouts))
+ elif name == "window":
+ return True, [i.window.wid for i in self.windows]
+ elif name == "screen":
+ return True, None
+
+ def _select(self, name, sel):
+ if name == "layout":
+ if sel is None:
+ return self.layout
+ else:
+ return utils.lget(self.layouts, sel)
+ elif name == "window":
+ if sel is None:
+ return self.currentWindow
+ else:
+ for i in self.windows:
+ if i.window.wid == sel:
+ return i
+ elif name == "screen":
+ return self.screen
+
+ def cmd_setlayout(self, layout):
+ self.layout = layout
+
+ def cmd_info(self):
+ """
+ Returns a dictionary of info for this group.
+ """
+ return self.info()
+
+ def cmd_toscreen(self, screen=None):
+ """
+ Pull a group to a specified screen.
+
+ - screen: Screen offset. If not specified,
+ we assume the current screen.
+
+ Pull group to the current screen:
+ toscreen()
+
+ Pull group to screen 0:
+ toscreen(0)
+ """
+ if screen is None:
+ screen = self.qtile.currentScreen
+ else:
+ screen = self.qtile.screens[screen]
+ screen.setGroup(self)
+
+ def _dirGroup(self, direction):
+ currentgroup = self.qtile.groups.index(self)
+ nextgroup = (currentgroup + direction) % len(self.qtile.groups)
+ return self.qtile.groups[nextgroup]
+
+ def _dirSkipEmptyGroup(self, direction):
+ """
+ Find a non-empty group walking the groups list in the specified
+ direction.
+ """
+ index = currentgroup = self.qtile.groups.index(self)
+ while True:
+ index = (index + direction) % len(self.qtile.groups)
+ group = self.qtile.groups[index]
+ if index == currentgroup or group.windows:
+ return group
+
+ def prevGroup(self):
+ return self._dirGroup(-1)
+
+ def nextGroup(self):
+ return self._dirGroup(1)
+
+ def prevEmptyGroup(self):
+ return self._dirSkipEmptyGroup(-1)
+
+ def nextEmptyGroup(self):
+ return self._dirSkipEmptyGroup(1)
+
+ # FIXME cmd_nextgroup and cmd_prevgroup should be on the Screen object.
+ def cmd_nextgroup(self, skip_empty=False):
+ """
+ Switch to the next group.
+ """
+ if skip_empty:
+ n = self.nextEmptyGroup()
+ else:
+ n = self.nextGroup()
+ self.qtile.currentScreen.setGroup(n)
+ return n.name
+
+ def cmd_prevgroup(self, skip_empty=False):
+ """
+ Switch to the previous group.
+ """
+ if skip_empty:
+ n = self.prevEmptyGroup()
+ else:
+ n = self.prevGroup()
+ self.qtile.currentScreen.setGroup(n)
+ return n.name
+
+ def cmd_unminimise_all(self):
+ """
+ Unminimise all windows in this group.
+ """
+ for w in self.windows:
+ w.minimised = False
+ self.layoutAll()
+
+ def cmd_next_window(self):
+ if not self.windows:
+ return
+ if self.currentWindow.floating:
+ nxt = self.floating_layout.focus_next(self.currentWindow)
+ if not nxt:
+ nxt = self.layout.focus_first()
+ if not nxt:
+ nxt = self.floating_layout.focus_first()
+ else:
+ nxt = self.layout.focus_next(self.currentWindow)
+ if not nxt:
+ nxt = self.floating_layout.focus_first()
+ if not nxt:
+ nxt = self.layout.focus_first()
+ self.focus(nxt, True)
+
+ def cmd_prev_window(self):
+ if not self.windows:
+ return
+ if self.currentWindow.floating:
+ nxt = self.floating_layout.focus_prev(self.currentWindow)
+ if not nxt:
+ nxt = self.layout.focus_last()
+ if not nxt:
+ nxt = self.floating_layout.focus_last()
+ else:
+ nxt = self.layout.focus_prev(self.currentWindow)
+ if not nxt:
+ nxt = self.floating_layout.focus_last()
+ if not nxt:
+ nxt = self.layout.focus_last()
+ self.focus(nxt, True)
+
+ def cmd_switch_groups(self, name):
+ """
+ Switch position of current group with name
+ """
+ self.qtile.cmd_switch_groups(self.name, name)
View
6 libqtile/hook.py
@@ -1,4 +1,4 @@
-import manager
+import utils
subscriptions = {}
SKIPLOG = set()
@@ -190,7 +190,7 @@ def _subscribe(self, event, func):
try:
lst.remove(func)
except ValueError:
- raise manager.QtileError("Tried to unsubscribe a hook that was not"
+ raise utils.QtileError("Tried to unsubscribe a hook that was not"
" currently subscribed")
unsubscribe = Unsubscribe()
@@ -198,7 +198,7 @@ def _subscribe(self, event, func):
def fire(event, *args, **kwargs):
if event not in subscribe.hooks:
- raise manager.QtileError("Unknown event: %s" % event)
+ raise utils.QtileError("Unknown event: %s" % event)
if not event in SKIPLOG:
qtile.log.info("Internal event: %s(%s, %s)" %
(event, args, kwargs))
View
653 libqtile/manager.py
@@ -18,13 +18,16 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
+from config import Drag, Click, Screen
+from utils import QtileError
from libqtile.log_utils import init_log
+from libqtile.dgroups import DGroups
from state import QtileState
+from group import _Group
from StringIO import StringIO
from xcb.xproto import EventMask
import atexit
import command
-import contextlib
import gobject
import hook
import logging
@@ -40,11 +43,6 @@
import xcb.xproto
import xcbq
-
-class QtileError(Exception):
- pass
-
-
class Defaults:
def __init__(self, *defaults):
"""
@@ -60,645 +58,6 @@ def load(self, target, config):
val = config.get(i[0], i[1])
setattr(target, i[0], val)
-
-class Key:
- """
- Defines a keybinding.
- """
- def __init__(self, modifiers, key, *commands):
- """
- - modifiers: A list of modifier specifications. Modifier
- specifications are one of: "shift", "lock", "control", "mod1",
- "mod2", "mod3", "mod4", "mod5".
-
- - key: A key specification, e.g. "a", "Tab", "Return", "space".
-
- - *commands: A list of lazy command objects generated with the
- command.lazy helper. If multiple Call objects are specified, they
- are run in sequence.
- """
- self.modifiers, self.key, self.commands = modifiers, key, commands
- if key not in xcbq.keysyms:
- raise QtileError("Unknown key: %s" % key)
- self.keysym = xcbq.keysyms[key]
- try:
- self.modmask = utils.translateMasks(self.modifiers)
- except KeyError, v:
- raise QtileError(v)
-
- def __repr__(self):
- return "Key(%s, %s)" % (self.modifiers, self.key)
-
-
-class Drag(object):
- """
- Defines binding of a mouse to some dragging action
-
- On each motion event command is executed
- with two extra parameters added
- x and y offset from previous move
- """
- def __init__(self, modifiers, button, *commands, **kw):
- self.start = kw.pop('start', None)
- if kw:
- raise TypeError("Unexpected arguments: %s" % ', '.join(kw))
- self.modifiers = modifiers
- self.button = button
- self.commands = commands
- try:
- self.button_code = int(self.button.replace('Button', ''))
- self.modmask = utils.translateMasks(self.modifiers)
- except KeyError, v:
- raise QtileError(v)
-
- def __repr__(self):
- return "Drag(%s, %s)" % (self.modifiers, self.button)
-
-
-class Click(object):
- """
- Defines binding of a mouse click
- """
- def __init__(self, modifiers, button, *commands):
- self.modifiers = modifiers
- self.button = button
- self.commands = commands
- try:
- self.button_code = int(self.button.replace('Button', ''))
- self.modmask = utils.translateMasks(self.modifiers)
- except KeyError, v:
- raise QtileError(v)
-
- def __repr__(self):
- return "Click(%s, %s)" % (self.modifiers, self.button)
-
-
-class ScreenRect(object):
-
- def __init__(self, x, y, width, height):
- self.x = x
- self.y = y
- self.width = width
- self.height = height
-
- def __repr__(self):
- return '<%s %d,%d %d,%d>' % (self.__class__.__name__,
- self.x, self.y, self.width, self.height)
-
- def hsplit(self, columnwidth):
- assert columnwidth > 0
- assert columnwidth < self.width
- return (self.__class__(self.x, self.y, columnwidth, self.height),
- self.__class__(self.x + columnwidth, self.y,
- self.width - columnwidth, self.height))
-
- def vsplit(self, rowheight):
- assert rowheight > 0
- assert rowheight < self.height
- return (self.__class__(self.x, self.y, self.width, rowheight),
- self.__class__(self.x, self.y + rowheight,
- self.width, self.height - rowheight))
-
-
-class Screen(command.CommandObject):
- """
- A physical screen, and its associated paraphernalia.
- """
- group = None
-
- def __init__(self, top=None, bottom=None, left=None, right=None,
- x=None, y=None, width=None, height=None):
- """
- - top, bottom, left, right: Instances of bar objects, or None.
-
- Note that bar.Bar objects can only be placed at the top or the
- bottom of the screen (bar.Gap objects can be placed anywhere).
-
- x,y,width and height aren't specified usually unless you are
- using 'fake screens'.
- """
- self.top, self.bottom = top, bottom
- self.left, self.right = left, right
- self.qtile = None
- self.index = None
- self.x = x # x position of upper left corner can be > 0
- # if one screen is "right" of the other
- self.y = y
- self.width = width
- self.height = height
-
- def _configure(self, qtile, index, x, y, width, height, group):
- self.qtile = qtile
- self.index, self.x, self.y = index, x, y,
- self.width, self.height = width, height
- self.setGroup(group)
- for i in self.gaps:
- i._configure(qtile, self)
-
- @property
- def gaps(self):
- lst = []
- for i in [self.top, self.bottom, self.left, self.right]:
- if i:
- lst.append(i)
- return lst
-
- @property
- def dx(self):
- return self.x + self.left.size if self.left else self.x
-
- @property
- def dy(self):
- return self.y + self.top.size if self.top else self.y
-
- @property
- def dwidth(self):
- val = self.width
- if self.left:
- val -= self.left.size
- if self.right:
- val -= self.right.size
- return val
-
- @property
- def dheight(self):
- val = self.height
- if self.top:
- val -= self.top.size
- if self.bottom:
- val -= self.bottom.size
- return val
-
- def get_rect(self):
- return ScreenRect(self.dx, self.dy, self.dwidth, self.dheight)
-
- def setGroup(self, new_group):
- """
- Put group on this screen
- """
- if new_group.screen == self:
- return
- elif new_group.screen:
- # g1 <-> s1 (self)
- # g2 (new_group)<-> s2 to
- # g1 <-> s2
- # g2 <-> s1
- g1 = self.group
- s1 = self
- g2 = new_group
- s2 = new_group.screen
-
- s2.group = g1
- g1._setScreen(s2)
- s1.group = g2
- g2._setScreen(s1)
- else:
- old_group = self.group
- self.group = new_group
-
- # display clients of the new group and then hide from old group
- # to remove the screen flickering
- new_group._setScreen(self)
-
- if old_group is not None:
- old_group._setScreen(None)
-
- hook.fire("setgroup")
- hook.fire("focus_change")
- hook.fire("layout_change",
- self.group.layouts[self.group.currentLayout],
- self.group)
-
- def _items(self, name):
- if name == "layout":
- return True, range(len(self.group.layouts))
- elif name == "window":
- return True, [i.window.wid for i in self.group.windows]
- elif name == "bar":
- return False, [x.position for x in self.gaps]
-
- def _select(self, name, sel):
- if name == "layout":
- if sel is None:
- return self.group.layout
- else:
- return utils.lget(self.group.layouts, sel)
- elif name == "window":
- if sel is None:
- return self.group.currentWindow
- else:
- for i in self.group.windows:
- if i.window.wid == sel:
- return i
- elif name == "bar":
- return getattr(self, sel)
-
- def resize(self, x=None, y=None, w=None, h=None):
- x = x or self.x
- y = y or self.y
- w = w or self.width
- h = h or self.height
- self._configure(self.qtile, self.index, x, y, w, h, self.group)
- for bar in [self.top, self.bottom, self.left, self.right]:
- if bar:
- bar.draw()
- self.group.layoutAll()
-
- def cmd_info(self):
- """
- Returns a dictionary of info for this screen.
- """
- return dict(
- index=self.index,
- width=self.width,
- height=self.height,
- x=self.x,
- y=self.y
- )
-
- def cmd_resize(self, x=None, y=None, w=None, h=None):
- """
- Resize the screen.
- """
- self.resize(x, y, w, h)
-
-
-class _Group(command.CommandObject):
- """
- A group is a container for a bunch of windows, analogous to workspaces
- in other window managers. Each client window managed by the window
- manager belongs to exactly one group.
- """
- def __init__(self, name, layout=None):
- self.name = name
- self.customLayout = layout # will be set on _configure
- self.windows = set()
- self.qtile = None
- self.layouts = []
- self.floating_layout = None
- self.currentWindow = None
- self.screen = None
- self.currentLayout = None
-
- def _configure(self, layouts, floating_layout, qtile):
- self.screen = None
- self.currentLayout = 0
- self.currentWindow = None
- self.windows = set()
- self.qtile = qtile
- self.layouts = [i.clone(self) for i in layouts]
- self.floating_layout = floating_layout.clone(self)
- if self.customLayout is not None:
- self.layout = self.customLayout
- self.customLayout = None
-
- @property
- def layout(self):
- return self.layouts[self.currentLayout]
-
- @layout.setter
- def layout(self, layout):
- """
- "layout" is a string with matching the name of a Layout object.
- """
- for index, obj in enumerate(self.layouts):
- if obj.name == layout:
- self.currentLayout = index
- hook.fire("layout_change",
- self.layouts[self.currentLayout], self)
- self.layoutAll()
- return
- raise ValueError("No such layout: %s" % layout)
-
- def nextLayout(self):
- self.layout.hide()
- self.currentLayout = (self.currentLayout + 1) % (len(self.layouts))
- hook.fire("layout_change", self.layouts[self.currentLayout], self)
- self.layoutAll()
- screen = self.screen.get_rect()
- self.layout.show(screen)
-
- def prevLayout(self):
- self.layout.hide()
- self.currentLayout = (self.currentLayout - 1) % (len(self.layouts))
- hook.fire("layout_change", self.layouts[self.currentLayout], self)
- self.layoutAll()
- screen = self.screen.get_rect()
- self.layout.show(screen)
-
- def layoutAll(self, warp=False):
- """
- Layout the floating layer, then the current layout.
-
- If we have have a currentWindow give it focus, optionally
- moving warp to it.
- """
- if self.screen and len(self.windows):
- with self.disableMask(xcb.xproto.EventMask.EnterWindow):
- normal = [x for x in self.windows if not x.floating]
- floating = [x for x in self.windows
- if x.floating and not x.minimized]
- screen = self.screen.get_rect()
- if normal:
- self.layout.layout(normal, screen)
- if floating:
- self.floating_layout.layout(floating, screen)
- if (self.currentWindow and
- self.screen == self.qtile.currentScreen):
- self.currentWindow.focus(warp)
-
- def _setScreen(self, screen):
- """
- Set this group's screen to new_screen
- """
- if screen == self.screen:
- return
- self.screen = screen
- if self.screen:
- # move all floating guys offset to new screen
- self.floating_layout.to_screen(self.screen)
- self.layoutAll()
- rect = self.screen.get_rect()
- self.floating_layout.show(rect)
- self.layout.show(rect)
- else:
- self.hide()
-
- def hide(self):
- self.screen = None
- with self.disableMask(xcb.xproto.EventMask.EnterWindow |
- xcb.xproto.EventMask.FocusChange |
- xcb.xproto.EventMask.LeaveWindow):
- for i in self.windows:
- i.hide()
- self.layout.hide()
-
- @contextlib.contextmanager
- def disableMask(self, mask):
- for i in self.windows:
- i._disableMask(mask)
- yield
- for i in self.windows:
- i._resetMask()
-
- def focus(self, win, warp):
- """
- if win is in the group, blur any windows and call
- ``focus`` on the layout (in case it wants to track
- anything), fire focus_change hook and invoke layoutAll.
-
- warp - warp pointer to win
- """
- if self.qtile._drag:
- # don't change focus while dragging windows
- return
- if win and not win in self.windows:
- return
- if win:
- self.currentWindow = win
- if win.floating:
- for l in self.layouts:
- l.blur()
- self.floating_layout.focus(win)
- else:
- self.floating_layout.blur()
- for l in self.layouts:
- l.focus(win)
- else:
- self.currentWindow = None
- hook.fire("focus_change")
- # !!! note that warp isn't hooked up now
- self.layoutAll(warp)
-
- def info(self):
- return dict(
- name=self.name,
- focus=self.currentWindow.name if self.currentWindow else None,
- windows=[i.name for i in self.windows],
- layout=self.layout.name,
- floating_info=self.floating_layout.info(),
- screen=self.screen.index if self.screen else None
- )
-
- def add(self, win):
- hook.fire("group_window_add")
- self.windows.add(win)
- win.group = self
- try:
- if (win.window.get_net_wm_state() == 'fullscreen' and
- self.qtile.config.auto_fullscreen):
- win._float_state = window.FULLSCREEN
- elif self.floating_layout.match(win):
- # !!! tell it to float, can't set floating
- # because it's too early
- # so just set the flag underneath
- win._float_state = window.FLOATING
- except (xcb.xproto.BadWindow, xcb.xproto.BadAccess):
- pass # doesn't matter
- if win.floating:
- self.floating_layout.add(win)
- else:
- for i in self.layouts:
- i.add(win)
- self.focus(win, True)
-
- def remove(self, win):
- self.windows.remove(win)
- win.group = None
- nextfocus = None
- if win.floating:
- nextfocus = self.floating_layout.remove(win)
- if nextfocus is None:
- nextfocus = self.layout.focus_first()
- if nextfocus is None:
- nextfocus = self.floating_layout.focus_first()
- else:
- for i in self.layouts:
- if i is self.layout:
- nextfocus = i.remove(win)
- else:
- i.remove(win)
- if nextfocus is None:
- nextfocus = self.floating_layout.focus_first()
- if nextfocus is None:
- nextfocus = self.layout.focus_first()
- self.focus(nextfocus, True)
- #else: TODO: change focus
-
- def mark_floating(self, win, floating):
- if floating and win in self.floating_layout.clients:
- # already floating
- pass
- elif floating:
- for i in self.layouts:
- i.remove(win)
- if win is self.currentWindow:
- i.blur()
- self.floating_layout.add(win)
- if win is self.currentWindow:
- self.floating_layout.focus(win)
- else:
- self.floating_layout.remove(win)
- self.floating_layout.blur()
- for i in self.layouts:
- i.add(win)
- if win is self.currentWindow:
- i.focus(win)
- self.layoutAll()
-
- def _items(self, name):
- if name == "layout":
- return True, range(len(self.layouts))
- elif name == "window":
- return True, [i.window.wid for i in self.windows]
- elif name == "screen":
- return True, None
-
- def _select(self, name, sel):
- if name == "layout":
- if sel is None:
- return self.layout
- else:
- return utils.lget(self.layouts, sel)
- elif name == "window":
- if sel is None:
- return self.currentWindow
- else:
- for i in self.windows:
- if i.window.wid == sel:
- return i
- elif name == "screen":
- return self.screen
-
- def cmd_setlayout(self, layout):
- self.layout = layout
-
- def cmd_info(self):
- """
- Returns a dictionary of info for this group.
- """
- return self.info()
-
- def cmd_toscreen(self, screen=None):
- """
- Pull a group to a specified screen.
-
- - screen: Screen offset. If not specified,
- we assume the current screen.
-
- Pull group to the current screen:
- toscreen()
-
- Pull group to screen 0:
- toscreen(0)
- """
- if screen is None:
- screen = self.qtile.currentScreen
- else:
- screen = self.qtile.screens[screen]
- screen.setGroup(self)
-
- def _dirGroup(self, direction):
- currentgroup = self.qtile.groups.index(self)
- nextgroup = (currentgroup + direction) % len(self.qtile.groups)
- return self.qtile.groups[nextgroup]
-
- def _dirSkipEmptyGroup(self, direction):
- """
- Find a non-empty group walking the groups list in the specified
- direction.
- """
- index = currentgroup = self.qtile.groups.index(self)
- while True:
- index = (index + direction) % len(self.qtile.groups)
- group = self.qtile.groups[index]
- if index == currentgroup or group.windows:
- return group
-
- def prevGroup(self):
- return self._dirGroup(-1)
-
- def nextGroup(self):
- return self._dirGroup(1)
-
- def prevEmptyGroup(self):
- return self._dirSkipEmptyGroup(-1)
-
- def nextEmptyGroup(self):
- return self._dirSkipEmptyGroup(1)
-
- # FIXME cmd_nextgroup and cmd_prevgroup should be on the Screen object.
- def cmd_nextgroup(self, skip_empty=False):
- """
- Switch to the next group.
- """
- if skip_empty:
- n = self.nextEmptyGroup()
- else:
- n = self.nextGroup()
- self.qtile.currentScreen.setGroup(n)
- return n.name
-
- def cmd_prevgroup(self, skip_empty=False):
- """
- Switch to the previous group.
- """
- if skip_empty:
- n = self.prevEmptyGroup()
- else:
- n = self.prevGroup()
- self.qtile.currentScreen.setGroup(n)
- return n.name
-
- def cmd_unminimise_all(self):
- """
- Unminimise all windows in this group.
- """
- for w in self.windows:
- w.minimised = False
- self.layoutAll()
-
- def cmd_next_window(self):
- if not self.windows:
- return
- if self.currentWindow.floating:
- nxt = self.floating_layout.focus_next(self.currentWindow)
- if not nxt:
- nxt = self.layout.focus_first()
- if not nxt:
- nxt = self.floating_layout.focus_first()
- else:
- nxt = self.layout.focus_next(self.currentWindow)
- if not nxt:
- nxt = self.floating_layout.focus_first()
- if not nxt:
- nxt = self.layout.focus_first()
- self.focus(nxt, True)
-
- def cmd_prev_window(self):
- if not self.windows:
- return
- if self.currentWindow.floating:
- nxt = self.floating_layout.focus_prev(self.currentWindow)
- if not nxt:
- nxt = self.layout.focus_last()
- if not nxt:
- nxt = self.floating_layout.focus_last()
- else:
- nxt = self.layout.focus_prev(self.currentWindow)
- if not nxt:
- nxt = self.floating_layout.focus_last()
- if not nxt:
- nxt = self.layout.focus_last()
- self.focus(nxt, True)
-
- def cmd_switch_groups(self, name):
- """
- Switch position of current group with name
- """
- self.qtile.cmd_switch_groups(self.name, name)
-
-
class Qtile(command.CommandObject):
"""
This object is the __root__ of the command graph.
@@ -759,8 +118,6 @@ def __init__(self, config,
config.main(self)
if self.config.groups:
- # TODO: break some dependencies out of this file (i.e. break more configs)
- from libqtile.dgroups import DGroups
key_binder = None
if hasattr(self.config, 'dgroups_key_binder'):
key_binder = self.config.dgroups_key_binder
@@ -1850,7 +1207,7 @@ def f(cmd):
if cmd:
c = command.CommandRoot(self)
try:
- cmd_arg = str(cmd).split(' ')
+ cmd_arg = str(cmd).split(' ')
except AttributeError:
return
cmd_len = len(cmd_arg)
View
3  libqtile/resources/default_config.py
@@ -1,5 +1,4 @@
-from libqtile.manager import Key, Screen
-from libqtile.dgroups import Group
+from libqtile.config import Key, Screen, Group
from libqtile.command import lazy
from libqtile import layout, bar, widget
View
2  libqtile/utils.py
@@ -25,6 +25,8 @@
import os
import xcbq
+class QtileError(Exception):
+ pass
def lget(o, v):
try:
View
4 test/configs/basic.py
@@ -1,7 +1,7 @@
-from libqtile import manager
+from libqtile import config
keys = [
- manager.Key(["control"], "k", "focusnext")
+ config.Key(["control"], "k", "focusnext")
]
screens = []
View
38 test/test_bar.py
@@ -3,7 +3,7 @@
import libqtile.bar
import libqtile.widget
import libqtile.manager
-import libqtile.dgroups
+import libqtile.config
import libqtile.confreader
from utils import Xephyr
@@ -12,16 +12,16 @@ class GBConfig:
keys = []
mouse = []
groups = [
- libqtile.dgroups.Group("a"),
- libqtile.dgroups.Group("bb"),
- libqtile.dgroups.Group("ccc"),
- libqtile.dgroups.Group("dddd"),
- libqtile.dgroups.Group("Pppy")
+ libqtile.config.Group("a"),
+ libqtile.config.Group("bb"),
+ libqtile.config.Group("ccc"),
+ libqtile.config.Group("dddd"),
+ libqtile.config.Group("Pppy")
]
layouts = [libqtile.layout.stack.Stack(stacks=1)]
floating_layout = libqtile.layout.floating.Floating()
screens = [
- libqtile.manager.Screen(
+ libqtile.config.Screen(
top=libqtile.bar.Bar(
[
libqtile.widget.CPUGraph(
@@ -141,15 +141,15 @@ class GeomConf:
keys = []
mouse = []
groups = [
- libqtile.dgroups.Group("a"),
- libqtile.dgroups.Group("b"),
- libqtile.dgroups.Group("c"),
- libqtile.dgroups.Group("d")
+ libqtile.config.Group("a"),
+ libqtile.config.Group("b"),
+ libqtile.config.Group("c"),
+ libqtile.config.Group("d")
]
layouts = [libqtile.layout.stack.Stack(stacks=1)]
floating_layout = libqtile.layout.floating.Floating()
screens = [
- libqtile.manager.Screen(
+ libqtile.config.Screen(
left=libqtile.bar.Gap(10),
right=libqtile.bar.Gap(10),
top=libqtile.bar.Bar([], 10),
@@ -240,12 +240,12 @@ def off(l):
class TopBottomConf(GeomConf):
screens = [
- libqtile.manager.Screen(left=libqtile.bar.Bar([], 10))
+ libqtile.config.Screen(left=libqtile.bar.Bar([], 10))
]
class MultiStretchConf(GeomConf):
screens = [
- libqtile.manager.Screen(top=libqtile.bar.Bar([
+ libqtile.config.Screen(top=libqtile.bar.Bar([
libqtile.widget.TextBox(txt, width=libqtile.bar.STRETCH)
for txt in ["text1", "text2"]
], 10))
@@ -255,11 +255,11 @@ class ErrConf:
main = None
keys = []
mouse = []
- groups = [libqtile.dgroups.Group("a")]
+ groups = [libqtile.config.Group("a")]
layouts = [libqtile.layout.stack.Stack(stacks=1)]
floating_layout = libqtile.layout.floating.Floating()
screens = [
- libqtile.manager.Screen(
+ libqtile.config.Screen(
left=libqtile.bar.Bar([], 10),
)
]
@@ -284,7 +284,7 @@ def draw(self):
@Xephyr(True, GeomConf(), False)
def test_basic(self):
self.config.screens = [
- libqtile.manager.Screen(
+ libqtile.config.Screen(
bottom=libqtile.bar.Bar(
[
TestWidget(),
@@ -308,7 +308,7 @@ def test_basic(self):
@Xephyr(True, GeomConf(), False)
def test_singlespacer(self):
self.config.screens = [
- libqtile.manager.Screen(
+ libqtile.config.Screen(
bottom=libqtile.bar.Bar(
[
libqtile.widget.Spacer(libqtile.bar.STRETCH),
@@ -328,7 +328,7 @@ def test_singlespacer(self):
@Xephyr(True, GeomConf(), False)
def test_nospacer(self):
self.config.screens = [
- libqtile.manager.Screen(
+ libqtile.config.Screen(
bottom=libqtile.bar.Bar(
[
TestWidget(),
View
22 test/test_command.py
@@ -1,7 +1,7 @@
import libqtile
import libqtile.confreader
import libqtile.manager
-import libqtile.dgroups
+import libqtile.config
import libqtile.layout
import libqtile.bar
import libqtile.widget
@@ -11,19 +11,19 @@
class CallConfig(object):
keys = [
- libqtile.manager.Key(
+ libqtile.config.Key(
["control"], "j",
libqtile.command._Call([("layout", None)], "down")
),
- libqtile.manager.Key(
+ libqtile.config.Key(
["control"], "k",
libqtile.command._Call([("layout", None)], "up"),
),
]
mouse = []
groups = [
- libqtile.dgroups.Group("a"),
- libqtile.dgroups.Group("b"),
+ libqtile.config.Group("a"),
+ libqtile.config.Group("b"),
]
layouts = [
libqtile.layout.Stack(stacks=1),
@@ -31,7 +31,7 @@ class CallConfig(object):
]
floating_layout = libqtile.layout.floating.Floating()
screens = [
- libqtile.manager.Screen(
+ libqtile.config.Screen(
bottom=libqtile.bar.Bar(
[
libqtile.widget.GroupBox(),
@@ -124,9 +124,9 @@ class ServerConfig(object):
keys = []
mouse = []
groups = [
- libqtile.dgroups.Group("a"),
- libqtile.dgroups.Group("b"),
- libqtile.dgroups.Group("c"),
+ libqtile.config.Group("a"),
+ libqtile.config.Group("b"),
+ libqtile.config.Group("c"),
]
layouts = [
libqtile.layout.Stack(stacks=1),
@@ -135,7 +135,7 @@ class ServerConfig(object):
]
floating_layout = libqtile.layout.floating.Floating()
screens = [
- libqtile.manager.Screen(
+ libqtile.config.Screen(
bottom=libqtile.bar.Bar(
[
libqtile.widget.TextBox("one"),
@@ -143,7 +143,7 @@ class ServerConfig(object):
20
),
),
- libqtile.manager.Screen(
+ libqtile.config.Screen(
bottom=libqtile.bar.Bar(
[
libqtile.widget.TextBox("two"),
View
12 test/test_fakescreen.py
@@ -1,7 +1,7 @@
import libqtile.manager
-import libqtile.dgroups
+import libqtile.config
from libqtile import layout, bar, widget
-from libqtile.manager import Screen
+from libqtile.config import Screen
from utils import Xephyr
LEFT_ALT = 'mod1'
@@ -35,10 +35,10 @@
class FakeScreenConfig:
main = None
groups = [
- libqtile.dgroups.Group("a"),
- libqtile.dgroups.Group("b"),
- libqtile.dgroups.Group("c"),
- libqtile.dgroups.Group("d")
+ libqtile.config.Group("a"),
+ libqtile.config.Group("b"),
+ libqtile.config.Group("c"),
+ libqtile.config.Group("d")
]
layouts = [
layout.Max(),
View
3  test/test_hook.py
@@ -1,5 +1,6 @@
import cStringIO
import libqtile.manager
+import libqtile.utils
import libqtile.hook
import logging
from nose.tools import with_setup, raises
@@ -27,7 +28,7 @@ def teardown():
libqtile.hook.clear()
-@raises(libqtile.manager.QtileError)
+@raises(libqtile.utils.QtileError)
def test_cannot_fire_unknown_event():
libqtile.hook.fire("unknown")
View
38 test/test_layout.py
@@ -1,6 +1,6 @@
from libqtile import layout
import libqtile.manager
-import libqtile.dgroups
+import libqtile.config
from time import sleep
from utils import Xephyr
@@ -43,10 +43,10 @@ def assertFocusPath(self, *names):
class MaxConfig:
main = None
groups = [
- libqtile.dgroups.Group("a"),
- libqtile.dgroups.Group("b"),
- libqtile.dgroups.Group("c"),
- libqtile.dgroups.Group("d")
+ libqtile.config.Group("a"),
+ libqtile.config.Group("b"),
+ libqtile.config.Group("c"),
+ libqtile.config.Group("d")
]
layouts = [
layout.Max()
@@ -89,10 +89,10 @@ def test_max_remove(self):
class StackConfig:
main = None
groups = [
- libqtile.dgroups.Group("a"),
- libqtile.dgroups.Group("b"),
- libqtile.dgroups.Group("c"),
- libqtile.dgroups.Group("d")
+ libqtile.config.Group("a"),
+ libqtile.config.Group("b"),
+ libqtile.config.Group("c"),
+ libqtile.config.Group("d")
]
layouts = [
layout.Stack(stacks=2),
@@ -283,10 +283,10 @@ def test_stack_info(self):
class RatioTileConfig:
main = None
groups = [
- libqtile.dgroups.Group("a"),
- libqtile.dgroups.Group("b"),
- libqtile.dgroups.Group("c"),
- libqtile.dgroups.Group("d")
+ libqtile.config.Group("a"),
+ libqtile.config.Group("b"),
+ libqtile.config.Group("c"),
+ libqtile.config.Group("d")
]
layouts = [
layout.RatioTile(ratio=.5),
@@ -438,10 +438,10 @@ def test_ratiotile_basic(self):
class TileConfig:
main = None
groups = [
- libqtile.dgroups.Group("a"),
- libqtile.dgroups.Group("b"),
- libqtile.dgroups.Group("c"),
- libqtile.dgroups.Group("d")
+ libqtile.config.Group("a"),
+ libqtile.config.Group("b"),
+ libqtile.config.Group("c"),
+ libqtile.config.Group("d")
]
layouts = [
layout.Tile(),
@@ -520,7 +520,7 @@ def test_tile_remove(self):
class SliceConfig:
main = None
groups = [
- libqtile.dgroups.Group("a"),
+ libqtile.config.Group("a"),
]
layouts = [
layout.Slice(side='left', width=200, wname='slice',
@@ -606,7 +606,7 @@ def test_all_slices(self):
class ZoomyConfig:
main = None
groups = [
- libqtile.dgroups.Group("a"),
+ libqtile.config.Group("a"),
]
layouts = [
layout.Zoomy(columnwidth=200),
View
50 test/test_manager.py
@@ -9,7 +9,7 @@
import libqtile.command
import libqtile.widget
import libqtile.manager
-import libqtile.dgroups
+import libqtile.config
import libqtile.hook
import utils
from utils import Xephyr
@@ -19,10 +19,10 @@
class TestConfig:
groups = [
- libqtile.dgroups.Group("a"),
- libqtile.dgroups.Group("b"),
- libqtile.dgroups.Group("c"),
- libqtile.dgroups.Group("d")
+ libqtile.config.Group("a"),
+ libqtile.config.Group("b"),
+ libqtile.config.Group("c"),
+ libqtile.config.Group("d")
]
layouts = [
libqtile.layout.stack.Stack(stacks=1),
@@ -32,19 +32,19 @@ class TestConfig:
floating_layout = libqtile.layout.floating.Floating(
float_rules=[dict(wmclass="xclock")])
keys = [
- libqtile.manager.Key(
+ libqtile.config.Key(
["control"],
"k",
libqtile.command._Call([("layout", None)], "up")
),
- libqtile.manager.Key(
+ libqtile.config.Key(
["control"],
"j",
libqtile.command._Call([("layout", None)], "down")
),
]
mouse = []
- screens = [libqtile.manager.Screen(
+ screens = [libqtile.config.Screen(
bottom=libqtile.bar.Bar(
[
libqtile.widget.GroupBox(),
@@ -58,10 +58,10 @@ class TestConfig:
class BareConfig:
groups = [
- libqtile.dgroups.Group("a"),
- libqtile.dgroups.Group("b"),
- libqtile.dgroups.Group("c"),
- libqtile.dgroups.Group("d")
+ libqtile.config.Group("a"),
+ libqtile.config.Group("b"),
+ libqtile.config.Group("c"),
+ libqtile.config.Group("d")
]
layouts = [
libqtile.layout.stack.Stack(stacks=1),
@@ -69,19 +69,19 @@ class BareConfig:
]
floating_layout = libqtile.layout.floating.Floating()
keys = [
- libqtile.manager.Key(
+ libqtile.config.Key(
["control"],
"k",
libqtile.command._Call([("layout", None)], "up")
),
- libqtile.manager.Key(
+ libqtile.config.Key(
["control"],
"j",
libqtile.command._Call([("layout", None)], "down")
),
]
mouse = []
- screens = [libqtile.manager.Screen()]
+ screens = [libqtile.config.Screen()]
main = None
follow_mouse_focus = False
@@ -730,17 +730,17 @@ def test_unmap_noscreen(self):
def test_init():
assert_raises(
libqtile.manager.QtileError,
- libqtile.manager.Key,
+ libqtile.config.Key,
[], "unknown", libqtile.command._Call("base", None, "foo")
)
assert_raises(
libqtile.manager.QtileError,
- libqtile.manager.Key,
+ libqtile.config.Key,
["unknown"], "x", libqtile.command._Call("base", None, "foo")
)
-class TScreen(libqtile.manager.Screen):
+class TScreen(libqtile.config.Screen):
def setGroup(self, x):
pass
@@ -775,10 +775,10 @@ def test_dheight():
class _Config:
groups = [
- libqtile.dgroups.Group("a"),
- libqtile.dgroups.Group("b"),
- libqtile.dgroups.Group("c"),
- libqtile.dgroups.Group("d")
+ libqtile.config.Group("a"),
+ libqtile.config.Group("b"),
+ libqtile.config.Group("c"),
+ libqtile.config.Group("d")
]
layouts = [
libqtile.layout.stack.Stack(stacks=1),
@@ -786,19 +786,19 @@ class _Config:
]
floating_layout = libqtile.layout.floating.Floating()
keys = [
- libqtile.manager.Key(
+ libqtile.config.Key(
["control"],
"k",
libqtile.command._Call([("layout", None)], "up")
),
- libqtile.manager.Key(
+ libqtile.config.Key(
["control"],
"j",
libqtile.command._Call([("layout", None)], "down")
),
]
mouse = []
- screens = [libqtile.manager.Screen(
+ screens = [libqtile.config.Screen(
bottom=libqtile.bar.Bar(
[
libqtile.widget.GroupBox(),
View
8 test/test_sh.py
@@ -3,7 +3,7 @@
import libqtile.confreader
import libqtile.layout
import libqtile.manager
-import libqtile.dgroups