]> git.decadent.org.uk Git - ion3.git/blobdiff - ioncore/ioncore_menudb.lua
Imported Upstream version 20090110
[ion3.git] / ioncore / ioncore_menudb.lua
index 6032b9415df05e79a9b503724a6e9917966c2b0a..1d8100b7c3b9635f92fc522295f75eb2e752f15a 100644 (file)
@@ -1,12 +1,9 @@
 --
 -- ion/ioncore/ioncore_menudb.lua -- Routines for defining menus.
 -- 
--- Copyright (c) Tuomo Valkonen 2004-2006.
+-- Copyright (c) Tuomo Valkonen 2004-2009.
 --
--- Ion is free software; you can redistribute it and/or modify it under
--- the terms of the GNU Lesser General Public License as published by
--- the Free Software Foundation; either version 2.1 of the License, or
--- (at your option) any later version.
+-- See the included file LICENSE for details.
 --
 
 local ioncore=_G.ioncore
@@ -28,7 +25,9 @@ function ioncore.defmenu(name, tab)
             ioncore.warn(TR("Unable to append to non-table menu"))
             return
         else
-            table.append(menus[name], tab)
+            for k, v in ipairs(tab) do
+                table.insert(menus[name], v)
+            end
         end
     else
         menus[name]=tab
@@ -46,11 +45,12 @@ end
 -- of menu entries.
 function ioncore.defctxmenu(ctx, ...)
     local tab, add
-    if #arg>1 and type(arg[1])=="string" then
-        tab=arg[2]
-        tab.label=ioncore.gettext(arg[1])
+    local a1, a2 = ...
+    if a2 and type(a1)=="string" then
+        tab=a2
+        tab.label=ioncore.gettext(a1)
     else
-        tab=arg[1]
+        tab=a1
     end
     ioncore.defmenu("ctxmenu-"..ctx, tab)
 end
@@ -61,34 +61,47 @@ function ioncore.getctxmenu(name)
     return menus["ctxmenu-"..name]
 end
 
-
-function ioncore.evalmenu(menu, args)
+function ioncore.evalmenu(menu, ...)
     if type(menu)=="string" then
-        return ioncore.evalmenu(menus[menu], args)
+        return ioncore.evalmenu(menus[menu], ...)
     elseif type(menu)=="function" then
-        if args then
-            return menu(unpack(args))
-        else
-            return menu()
-        end
+        return menu(...)
     elseif type(menu)=="table" then
         return menu
     end
 end
 
-
 --DOC
 -- Use this function to define normal menu entries. The string \var{name} 
--- is the string shown in the visual representation of menu, and the
--- parameter \var{cmd} and \var{guard} are similar to those of
--- \fnref{ioncore.defbindings}.
-function ioncore.menuentry(name, cmd, guard)
+-- is the string shown in the visual representation of menu. The
+-- parameter \var{cmd} and \var{guard_or_opts} (when string) are similar
+-- to those of \fnref{ioncore.defbindings}.  If \var{guard_or_opts} is
+-- a table, it may contains the \var{guard} field, and the \var{priority}
+-- field, for controlling positioning of entries in context menus.
+-- (The default priority is 1 for most entries, and -1 for auto-generated
+-- submenus.)
+function ioncore.menuentry(name, cmd, guard_or_opts)
+    local guard
+    local opts
+    
+    if type(guard_or_opts)=="string" then
+        guard=guard_or_opts
+    elseif type(guard_or_opts)=="table" then
+        opts=guard_or_opts
+        guard=opts.guard
+    end
+    
     local fn, gfn=ioncore.compile_cmd(cmd, guard)
     if fn then
-        return {name=ioncore.gettext(name), func=fn, guard_func=gfn}
+        return table.append({
+                   name=ioncore.gettext(name), 
+                   func=fn, 
+                   guard_func=gfn, 
+               }, opts or {})
     end
 end
 
+
 --DOC
 -- Use this function to define menu entries for submenus. The parameter
 -- \fnref{sub_or_name} is either a table of menu entries or the name
@@ -98,17 +111,12 @@ end
 -- \var{options.noautoexpand} that will cause \fnref{mod_query.query_menu}
 -- to not automatically expand this submenu.
 function ioncore.submenu(name, sub_or_name, options)
-    if not options then
-        options={}
-    end
-    return {
-        name=ioncore.gettext(name),
-        submenu_fn=function()
-                       return ioncore.evalmenu(sub_or_name)
-                   end,
-        initial=options.initial,
-        noautoexpand=options.noautoexpand,
-    }
+    return table.append({
+               name=ioncore.gettext(name),
+               submenu_fn=function()
+                              return ioncore.evalmenu  (sub_or_name)
+                          end,
+           }, options or {})
 end
 
 
@@ -117,23 +125,78 @@ end
 
 -- Workspace and window lists {{{
 
-local function makelist(list)
-    local function mkentry(tgt)
-        return menuentry(tgt:name(), function() tgt:goto() end)
+local function addto(list)
+    return function(tgt, attr)
+        local e=menuentry(tgt:name(), function() tgt:goto() end)
+        e.attr=attr;
+        table.insert(list, e)
+        return true
     end
-    local entries=table.map(mkentry, list)
+end
+    
+local function sort(entries)
     table.sort(entries, function(a, b) return a.name < b.name end)
     return entries
 end
 
 function menus.windowlist()
-    return makelist(ioncore.clientwin_list())
+    local entries={}
+    ioncore.clientwin_i(addto(entries))
+    return sort(entries)
 end
 
 function menus.workspacelist()
-    return makelist(ioncore.region_list("WGenWS"))
+    local entries={}
+    local iter_=addto(entries)
+    
+    local function iter(obj) 
+        return (not obj_is(obj, "WGroupWS") 
+                or iter_(obj))
+    end
+    
+    ioncore.region_i(iter)
+    
+    return sort(entries)
+end
+
+local function focuslist(do_act)
+    local entries={}
+    local seen={}
+    local iter_=addto(entries)
+    
+    local function iter(obj, attr) 
+        if obj_is(obj, "WClientWin") then
+            iter_(obj, attr)
+            seen[obj]=true
+        end
+        return true
+    end
+    
+    local function iter_act(obj)
+        return iter(obj, "activity")
+    end
+    
+    local function iter_foc(obj)
+        return (seen[obj] or iter(obj))
+    end
+    
+    if do_act then
+        -- Windows with activity first
+        ioncore.activity_i(iter_act)
+    end
+    
+    -- The ones that have been focused in their lifetime
+    ioncore.focushistory_i(iter_foc)
+    
+    -- And then the rest
+    ioncore.clientwin_i(iter_foc)
+    
+    return entries
 end
 
+menus.focuslist=function() return focuslist(true) end
+menus.focuslist_=function() return focuslist(false) end
+
 -- }}}
 
 
@@ -198,7 +261,7 @@ local function receive_styles(str)
     local styles={}
     local stylemenu={}
     
-    for look in string.gfind(data, "(look[-_][^\n]*)%.lua\n") do
+    for look in string.gmatch(data, "(look[-_][^\n]*)%.lua\n") do
         if not found[look] then
             found[look]=true
             table.insert(styles, look)
@@ -277,7 +340,7 @@ local function modeparts(mode)
 end
 
 
-local function get_ctxmenu(reg, sub, is_par)
+local function get_ctxmenu(reg, sub)
     local m={}
     
     local function cp(m2)
@@ -303,11 +366,7 @@ local function get_ctxmenu(reg, sub, is_par)
     
     local function add_ctxmenu(m2, use_label)
         if m2 then
-            if is_par then
-                m2=cp(m2)
-            end
-
-            m=table.icat(m, m2)
+            m=table.icat(m, cp(m2))
             m.label=(use_label and m2.label) or m.label
         end
     end
@@ -329,23 +388,53 @@ local function get_ctxmenu(reg, sub, is_par)
     return m
 end
 
+
+local function sortmenu(m)
+    local v=1/2
+    
+    for _, e in ipairs(m) do
+        e.priority=(e.priority or 1)+v
+        v=v/2
+    end
+    
+    table.sort(m, function(e1, e2) return e1.priority > e2.priority end)
+    
+    return m
+end
+
+
 function menus.ctxmenu(reg, sub)
-    local m=get_ctxmenu(reg, sub, false);
+    local m, r, s
+    
+    if obj_is(sub, "WGroup") then
+        sub=(sub:bottom() or sub)
+    end
     
-    sub=reg
-    reg=reg:manager()
+    -- First, stuff between reg (inclusive) and sub_or_chld (inclusive)
+    -- at the top level in the menu.
+    r=(sub or reg)
+    while r and s~=reg do
+        local mm=get_ctxmenu(r, s)
+        m=((m and table.icat(mm, m)) or mm)
+        s=r
+        r=r:manager()
+    end
+    
+    m=(m or {})
     
-    while reg do
-        local mm = get_ctxmenu(reg, sub, true)
+    -- Then stuff below reg (exclusive) as submenus
+    while r do
+        local mm = get_ctxmenu(r, s)
         if #mm>0 then
             local nm=mm.label or obj_typename(reg)
-            table.insert(m, ioncore.submenu(nm, mm))
+            local tmp=ioncore.submenu(nm, sortmenu(mm), {priority=-1})
+            table.insert(m, tmp)
         end
-        sub=reg
-        reg=reg:manager()
+        s=r
+        r=r:manager()
     end
     
-    return m
+    return sortmenu(m)
 end
 
 -- }}}