]> Dogcows Code - chaz/openbox/blobdiff - scripts/focus.py
historyplacement!!
[chaz/openbox] / scripts / focus.py
index 011fcc5b09731ed6b957dc88a1f966a342f5f1c7..f1097aa51426c69f952c080123d7b02bcf09c1e0 100644 (file)
 ###          Functions for helping out with your window focus.          ###
 ###########################################################################
 
-# raise the window also when it is focused
-ob_focus_raise = 1
-# send focus somewhere when nothing is left with the focus if possible
-ob_focus_fallback = 0
+###########################################################################
+###         Options that affect the behavior of the focus module.       ###
+###                                                                     ###
+# cycle_raise - raise the window also when it is focused                ###
+cycle_raise = 1                                                         ###
+# avoid_skip_taskbar - 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.                           ###
+avoid_skip_taskbar = 1                                                  ###
+# stacked_cycle_raise - raise as you cycle in stacked mode              ###
+stacked_cycle_raise = 0                                                 ###
+# stacked_cycle_popup_list - show a pop-up list of windows while        ###
+###                          cycling                                    ###
+stacked_cycle_popup_list = 1                                            ###
+# send focus somewhere when nothing is left with the focus, if possible ###
+fallback = 0                                                            ###
+###                                                                     ###
+###                                                                     ###
+# Provides:                                                             ###
+# def focus_next_stacked(data, forward=1):                              ###
+#   """Focus the next (or previous, with forward=0) window in a stacked ###
+#      order."""                                                        ###
+# def focus_prev_stacked(data):                                         ###
+#   """Focus the previous window in a stacked order."""                 ###
+# def focus_next(data, num=1, forward=1):                               ###
+#   """Focus the next (or previous, with forward=0) window in a linear  ###
+#      order."""                                                        ###
+# def focus_prev(data, num=1):                                          ###
+#   """Focus the previous window in a linear order."""                  ###
+###                                                                     ###
+# All of these functions call be used as callbacks for bindings         ###
+# directly.                                                             ###
+###                                                                     ###
+###########################################################################
+
+import otk
+import ob
 
 # maintain a list of clients, stacked in focus order
-ob_clients = []
+_clients = []
 # maintaint he current focused window
-ob_doing_stacked = 0
+_doing_stacked = 0
+
+def _focusable(client, desktop):
+    if not (avoid_skip_taskbar and client.skipTaskbar()) and \
+       (client.desktop() == desktop or client.desktop() == 0xffffffff) and \
+       client.normal() and (client.canFocus() or client.focusNotify()):
+        return 1
+    return 0
 
-def ob_new_win(data):
-    global ob_clients
-    global ob_doing_stacked
-    global ob_cyc_w;
+def _new_win(data):
+    global _clients
+    global _doing_stacked
+    global _cyc_w;
 
-    if ob_doing_stacked:
-        ob_clients.insert(ob_clients.index(ob_cyc_w), data.client.window())
+    if _doing_stacked:
+        _clients.insert(_clients.index(_cyc_w), data.client.window())
+        _create_popup_list(data)
+        _hilite_popup_list(data)
     else:
-        if not len(ob_clients):
-            ob_clients.append(data.client.window())
+        if not len(_clients):
+            _clients.append(data.client.window())
         else:
-            ob_clients.insert(1, data.client.window()) # insert in 2nd slot
+            _clients.insert(1, data.client.window()) # insert in 2nd slot
 
-def ob_close_win(data):
-    global ob_clients
-    global ob_cyc_w;
-    global ob_doing_stacked
+def _close_win(data):
+    global _clients
+    global _cyc_w;
+    global _doing_stacked
 
-    if not ob_doing_stacked:
+    if not _doing_stacked:
         # not in the middle of stacked cycling, so who cares
-        ob_clients.remove(data.client.window())
+        _clients.remove(data.client.window())
     else:
         # have to fix the cycling if we remove anything
         win = data.client.window()
-        if ob_cyc_w == win:
-            do_stacked_cycle(data) # cycle off the window first
-        ob_clients.remove(win)
-
-def ob_focused(data):
-    global ob_clients
-    global ob_doing_stacked
-    global ob_cyc_w
+        if _cyc_w == win:
+            _do_stacked_cycle(data, 1) # cycle off the window first, forward
+        _clients.remove(win)
+        _create_popup_list(data)
+
+def _focused(data):
+    global _clients
+    global _doing_stacked
+    global _cyc_w
     
     if data.client:
-        if not ob_doing_stacked: # only move the window when we're not cycling
+        if not _doing_stacked: # only move the window when we're not cycling
             win = data.client.window()
             # move it to the top
-            ob_clients.remove(win)
-            ob_clients.insert(0, win)
+            _clients.remove(win)
+            _clients.insert(0, win)
         else: # if we are cycling, then update our pointer
-            ob_cyc_w = data.client.window()
-    elif ob_focus_fallback: 
+            _cyc_w = data.client.window()
+            _hilite_popup_list(data)
+    elif fallback: 
         # pass around focus
-        desktop = openbox.screen(ob_cyc_screen).desktop()
-        for w in ob_clients:
-            client = openbox.findClient(w)
-            if client and (client.desktop() == desktop and \
-                           client.normal() and client.focus()):
+        desktop = ob.openbox.screen(_cyc_screen).desktop()
+        for w in _clients:
+            client = ob.openbox.findClient(w)
+            if client and _focusable(client, desktop) and client.focus():
                 break
+        if _doing_stacked:
+            _cyc_w = 0
+            _hilite_popup_list(data)
+
+_cyc_mask = 0
+_cyc_key = 0
+_cyc_w = 0 # last window cycled to
+_cyc_screen = 0
 
-ebind(EventNewWindow, ob_new_win)
-ebind(EventCloseWindow, ob_close_win)
-ebind(EventFocus, ob_focused)
+def _do_stacked_cycle(data, forward):
+    global _cyc_w
+    global stacked_cycle_raise
+    global _clients
 
-ob_cyc_mask = 0
-ob_cyc_key = 0
-ob_cyc_w = 0 # last window cycled to
-ob_cyc_screen = 0
+    clients = _clients[:] # make a copy
 
-def do_stacked_cycle(data):
-    global ob_cyc_w
+    if not forward:
+        clients.reverse()
 
     try:
-        i = ob_clients.index(ob_cyc_w) + 1
+        i = clients.index(_cyc_w) + 1
     except ValueError:
-        i = 0
+        i = 1
+    clients = clients[i:] + clients[:i]
         
-    clients = ob_clients[i:] + ob_clients[:i]
+    desktop = ob.openbox.screen(data.screen).desktop()
     for w in clients:
-        client = openbox.findClient(w)
-        if client and (client.desktop() == desktop and \
-                       client.normal() and client.focus()):
+        client = ob.openbox.findClient(w)
+                   
+        if client and _focusable(client, desktop) and client.focus():
+            if stacked_cycle_raise:
+                ob.openbox.screen(data.screen).raiseWindow(client)
             return
 
-def focus_next_stacked_grab(data):
-    global ob_cyc_mask;
-    global ob_cyc_key;
-    global ob_cyc_w;
-    global ob_doing_stacked;
+def _focus_stacked_ungrab(data):
+    global _cyc_mask;
+    global _cyc_key;
+    global _doing_stacked;
 
-    if data.action == EventKeyRelease:
+    if data.action == ob.KeyAction.Release:
         # have all the modifiers this started with been released?
-        if not ob_cyc_mask & data.state:
-            kungrab() # ungrab ourself
-            ob_doing_stacked = 0;
-            print "UNGRABBED!"
+        if not _cyc_mask & data.state:
+            _destroy_popup_list()
+            ob.kungrab()
+            ob.mungrab()
+            _doing_stacked = 0;
+            if cycle_raise:
+                client = ob.openbox.findClient(_cyc_w)
+                if client:
+                    ob.openbox.screen(data.screen).raiseWindow(client)
+
+_list_widget = 0
+_list_labels = []
+_list_windows = []
+
+def _hilite_popup_list(data):
+    global _cyc_w, _doing_stacked
+    global _list_widget, _list_labels, _list_windows
+    found = 0
+
+    if not _list_widget and _doing_stacked:
+        _create_popup_list(data)
+    
+    if _list_widget:
+        i = 0
+        for w in _list_windows:
+            if w == _cyc_w:
+                _list_labels[i].focus()
+                found = 1
+            else:
+                _list_labels[i].unfocus()
+            i += 1
+    if not found:
+        _create_popup_list(data)
+
+def _destroy_popup_list():
+    global _list_widget, _list_labels, _list_windows
+    if _list_widget:
+        _list_windows = []
+        _list_labels = []
+        _list_widget = 0
+    
+def _create_popup_list(data):
+    global avoid_skip_taskbar
+    global _list_widget, _list_labels, _list_windows, _clients
+
+    if _list_widget:
+        _destroy_popup_list()
+    
+    style = ob.openbox.screen(data.screen).style()
+    _list_widget = otk.Widget(ob.openbox, style,
+                              otk.Widget.Vertical, 0,
+                              style.bevelWidth(), 1)
+    t = style.titlebarFocusBackground()
+    _list_widget.setTexture(t)
+
+    titles = []
+    font = style.labelFont()
+    height = font.height()
+    longest = 0
+    desktop = ob.openbox.screen(data.screen).desktop()
+    for c in _clients:
+        client = ob.openbox.findClient(c)
+        if client and _focusable(client, desktop):
+            t = client.title()
+            if len(t) > 50: # limit the length of titles
+                t = t[:24] + "..." + t[-24:]
+            titles.append(t)
+            _list_windows.append(c)
+            l = font.measureString(t)
+            if l > longest: longest = l
+    if len(titles) > 1:
+        for t in titles:
+            w = otk.FocusLabel(_list_widget)
+            w.fitSize(longest, height)
+            w.setText(t)
+            w.unfocus()
+            _list_labels.append(w)
+        _list_widget.update()
+        area = otk.display.screenInfo(data.screen).rect()
+        _list_widget.move(area.x() + (area.width() -
+                                      _list_widget.width()) / 2,
+                          area.y() + (area.height() -
+                                      _list_widget.height()) / 2)
+        _list_widget.show(1)
     else:
-        if ob_cyc_key == data.key:
-            # the next window to try focusing in ob_clients[ob_cyc_i]
-            print "CYCLING!!"
-            do_stacked_cycle(data)
+        _destroy_popup_list() # nothing (or only 1) to list
 
 def focus_next_stacked(data, forward=1):
-    global ob_cyc_mask
-    global ob_cyc_key
-    global ob_cyc_w
-    global ob_cyc_screen
-    global ob_doing_stacked
-    ob_cyc_mask = data.state
-    ob_cyc_key = data.key
-    ob_cyc_w = 0
-    ob_cyc_screen = data.screen
-    ob_doing_stacked = 1
-
-    kgrab(data.screen, focus_next_stacked_grab)
-    print "GRABBED!"
-    focus_next_stacked_grab(data) # start with the first press
+    """Focus the next (or previous, with forward=0) window in a stacked
+       order."""
+    global _cyc_mask
+    global _cyc_key
+    global _cyc_w
+    global _cyc_screen
+    global _doing_stacked
+
+    if _doing_stacked:
+        if _cyc_key == data.key:
+            _do_stacked_cycle(data,forward)
+    else:
+        _cyc_mask = data.state
+        _cyc_key = data.key
+        _cyc_w = 0
+        _cyc_screen = data.screen
+        _doing_stacked = 1
+
+        global stacked_cycle_popup_list
+        if stacked_cycle_popup_list:
+            _create_popup_list(data)
+
+        ob.kgrab(data.screen, _focus_stacked_ungrab)
+        # 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
+        ob.mgrab(data.screen)
+        focus_next_stacked(data, forward) # start with the first press
 
 def focus_prev_stacked(data):
-    return
+    """Focus the previous window in a stacked order."""
+    focus_next_stacked(data, forward=0)
 
 def focus_next(data, num=1, forward=1):
     """Focus the next (or previous, with forward=0) window in a linear
        order."""
-    screen = openbox.screen(data.screen)
+    global avoid_skip_taskbar
+
+    screen = ob.openbox.screen(data.screen)
     count = screen.clientCount()
 
     if not count: return # no clients
@@ -150,13 +297,11 @@ def focus_next(data, num=1, forward=1):
             else: target = count - 1
 
     t = target
-    curdesk = screen.desktop()
+    desktop = screen.desktop()
     while 1:
         client = screen.client(t)
-        if client.normal() and \
-               (client.desktop() == curdesk or client.desktop() == 0xffffffff)\
-               and client.focus():
-            if ob_focus_raise:
+        if client and _focusable(client, desktop) and client.focus():
+            if cycle_raise:
                 screen.raiseWindow(client)
             return
         if forward:
@@ -172,4 +317,8 @@ def focus_prev(data, num=1):
     focus_next(data, num, forward=0)
 
 
+ob.ebind(ob.EventAction.NewWindow, _new_win)
+ob.ebind(ob.EventAction.CloseWindow, _close_win)
+ob.ebind(ob.EventAction.Focus, _focused)
+
 print "Loaded focus.py"
This page took 0.02811 seconds and 4 git commands to generate.