From f8a47de5ec444c452093371e3db16857eb39a490 Mon Sep 17 00:00:00 2001 From: Dana Jansens Date: Sun, 16 Mar 2003 21:11:39 +0000 Subject: merge the C branch into HEAD --- python/stackedcycle.py | 216 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 216 insertions(+) create mode 100644 python/stackedcycle.py (limited to 'python/stackedcycle.py') diff --git a/python/stackedcycle.py b/python/stackedcycle.py new file mode 100644 index 00000000..4f7f71da --- /dev/null +++ b/python/stackedcycle.py @@ -0,0 +1,216 @@ +import ob, config, hooks, focus +from input import Pointer, Keyboard + +config.add('stackedcycle', + 'activate_while_cycling', + 'Activate While Cycling', + "If this is True then windows will be activated as they are" + \ + "highlighted in the cycling list (except iconified windows).", + 'boolean', + True) + +config.add('stackedcycle', + 'raise_window', + 'Raise After Cycling', + "If this is True, the selected window will be raised as well as " +\ + "focused.", + 'boolean', + True) + +config.add('stackedcycle', + 'include_all_desktops', + 'Include Windows From All Desktops', + "If this is True then windows from all desktops will be included" +\ + " in the stacking list.", + 'boolean', + False) + +config.add('stackedcycle', + 'include_icons', + 'Include Icons', + "If this is True then windows which are iconified on the current" +\ + " desktop will be included in the stacking list.", + 'boolean', + False) + +config.add('stackedcycle', + 'include_icons_all_desktops', + 'Include Icons From All Desktops', + "If this is True then windows which are iconified from all " +\ + "desktops will be included in the stacking list (if Include Icons"+\ + " is also True).", + 'boolean', + True) + +config.add('stackedcycle', + 'include_omnipresent', + 'Include Omnipresent Windows', + "If this is True then windows which are on all-desktops at once " +\ + "will be included in the stacking list.", + 'boolean', + True) + +def next(keydata, client): _cycle(keydata, client, True) +def previous(keydata, client): _cycle(keydata, client, False) + +def _shouldAdd(client): + """Determines if a client should be added to the cycling list.""" + curdesk = ob.Openbox.desktop() + desk = client.desktop() + + if not (client.normal() and client.canFocus()): return False + if config.get('focus', 'avoid_skip_taskbar') and client.skipTaskbar(): + return False + + if client.iconic(): + if config.get('stackedcycle', 'include_icons'): + if config.get('stackedcycle', 'include_icons_all_desktops'): + return True + if desk == curdesk: return True + return False + if config.get('stackedcycle', 'include_omnipresent') and \ + desk == 0xffffffff: return True + if config.get('stackedcycle', 'include_all_desktops'): return True + if desk == curdesk: return True + + return False + +def _populateItems(): + global _items + # get the list of clients, keeping iconic windows at the bottom + _items = [] + iconic_clients = [] + for c in focus._clients: + if _shouldAdd(c): + if c.iconic(): iconic_clients.append(c) + else: _items.append(c) + _items.extend(iconic_clients) + +def _populate(): + global _pos, _items + try: + current = _items[_pos] + except IndexError: + current = None + oldpos = _pos + _pos = -1 + + _populateItems() + + i = 0 + for item in _items: + # current item might have shifted after a populateItems() + # call, so we need to do this test. + if current == item: + _pos = i + i += 1 + + # The item we were on might be gone entirely + if _pos < 0: + # try stay at the same spot in the menu + if oldpos >= len(_items): + _pos = len(_items) - 1 + else: + _pos = oldpos + + +def _activate(final): + """ + Activates (focuses and, if the user requested it, raises a window). + If final is True, then this is the very last window we're activating + and the user has finished cycling. + """ + print "_activate" + try: + client = _items[_pos] + except IndexError: return # empty list + print client + + # move the to client's desktop if required + if not (client.iconic() or client.desktop() == 0xffffffff or \ + client.desktop() == ob.Openbox.desktop()): + ob.Openbox.setDesktop(client.desktop()) + + if final or not client.iconic(): + if final: r = config.get('stackedcycle', 'raise_window') + else: r = False + client.focus(True) + if final and client.shaded(): client.setShaded(False) + print "final", final, "raising", r + if r: client.raiseWindow() + if not final: + focus._skip += 1 + +def _cycle(keydata, client, forward): + global _cycling, _state, _pos, _inititem, _items + + if not _cycling: + _items = [] # so it doesnt try start partway through the list + _populate() + + if not _items: return # don't bother doing anything + + Keyboard.grab(_grabfunc) + # the pointer grab causes pointer events during the keyboard grab + # to go away, which means we don't get enter notifies when the + # popup disappears, screwing up the focus + Pointer.grabPointer(True) + + _cycling = True + _state = keydata.state + _pos = 0 + _inititem = _items[_pos] + + if forward: + _pos += 1 + else: + _pos -= 1 + # wrap around + if _pos < 0: _pos = len(_items) - 1 + elif _pos >= len(_items): _pos = 0 + if config.get('stackedcycle', 'activate_while_cycling'): + _activate(False) # activate, but dont deiconify/unshade/raise + +def _grabfunc(keydata, client): + global _cycling + + done = False + notreverting = True + # have all the modifiers this started with been released? + if not _state & keydata.state: + done = True + elif keydata.press: + # has Escape been pressed? + if keydata.keychain == "Escape": + done = True + notreverting = False + # revert + try: + _pos = _items.index(_inititem) + except: + _pos = -1 + # has Enter been pressed? + elif keydata.keychain == "Return": + done = True + + if done: + # activate, and deiconify/unshade/raise + _activate(notreverting) + _cycling = False + Keyboard.ungrab() + Pointer.grabPointer(False) + + +_cycling = False +_pos = 0 +_inititem = None +_items = [] +_state = 0 + +def _newwin(data): + if _cycling: _populate() +def _closewin(data): + if _cycling: _populate() + +hooks.managed.append(_newwin) +hooks.closed.append(_closewin) -- cgit v1.2.3