216 lines
6.3 KiB
Python
216 lines
6.3 KiB
Python
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)
|