summaryrefslogtreecommitdiff
path: root/scripts/focus.py
blob: 172c165829ea963bae7545e116a25b99bc64e493 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
###########################################################################
###          Functions for helping out with your window focus.          ###
###########################################################################

###########################################################################
###         Options that affect the behavior of the focus module.       ###
###########################################################################
avoid_skip_taskbar = 1
"""Don't focus windows which have requested to not be displayed in taskbars.
   You will still be able to focus the windows, but not through cycling, and
   they won't be focused as a fallback if 'fallback' is enabled."""
raise_window = 1
"""When cycling focus, raise the window chosen as well as focusing it. This
   does not affect fallback focusing behavior."""
fallback = 0
"""Send focus somewhere when nothing is left with the focus, if possible."""
###########################################################################

def next(data, num=1):
    """Focus the next window."""
    _cycle(data, num, 1)

def previous(data, num=1):
    """Focus the previous window."""
    _cycle(data, num, 0)

###########################################################################
###########################################################################

###########################################################################
###      Internal stuff, should not be accessed outside the module.     ###
###########################################################################

import otk
import ob

# maintain a list of clients, stacked in focus order
_clients = []
_disable = 0

def _focusable(client, desktop):
    if not client.normal(): return 0
    if not (client.canFocus() or client.focusNotify()): return 0
    if avoid_skip_taskbar and client.skipTaskbar(): return 0

    desk = client.desktop()
    if not (desk == 0xffffffff or desk == desktop): return 0

    return 1

def _focused(data):
    global _clients

    if _disable: return

    if data.client:
        win = data.client.window()
        # move it to the top
        _clients.remove(win)
        _clients.insert(0, win)
    elif fallback:
        # pass around focus
        desktop = ob.openbox.screen(data.screen).desktop()
        for w in _clients:
            client = ob.openbox.findClient(w)
            if client and _focusable(client, desktop) and client.focus():
                break

def _newwindow(data):
    _clients.append(data.client.window())
        
def _closewindow(data):
    try:
        focus._clients.remove(data.client.window())
    except ValueError: pass

ob.ebind(ob.EventAction.NewWindow, _newwindow)
ob.ebind(ob.EventAction.CloseWindow, _closewindow)
ob.ebind(ob.EventAction.Focus, _focused)

def _cycle(data, num, forward):
    global avoid_skip_taskbar
    
    screen = ob.openbox.screen(data.screen)
    count = screen.clientCount()

    if not count: return # no clients
    
    target = 0
    if data.client:
        client_win = data.client.window()
        found = 0
        r = range(count)
        if not forward:
            r.reverse()
        for i in r:
            if found:
                target = i
                found = 2
                break
            elif screen.client(i).window() == client_win:
                found = 1
        if found == 1: # wraparound
            if forward: target = 0
            else: target = count - 1

        t = target
        desktop = screen.desktop()
        while 1:
            client = screen.client(t)
            if client and _focusable(client, desktop) and client.focus():
                if cycle_raise:
                    screen.raiseWindow(client)
                return
            if forward:
                t += num
                if t >= count: t -= count
            else:
                t -= num
                if t < 0: t += count
            if t == target: return # nothing to focus
            
print "Loaded focus.py"