--
-- ion/ioncore/ioncore_menudb.lua -- Routines for defining menus.
--
--- Copyright (c) Tuomo Valkonen 2004-2006.
+-- Copyright (c) Tuomo Valkonen 2004-2008.
--
--- 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
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
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
-- \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
-- 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
+
-- }}}
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)
end
-local function get_ctxmenu(reg, sub, is_par)
+local function get_ctxmenu(reg, sub)
local m={}
local function cp(m2)
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
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
-- }}}