X-Git-Url: https://git.decadent.org.uk/gitweb/?a=blobdiff_plain;ds=sidebyside;f=ioncore%2Fioncore_menudb.lua;h=1d8100b7c3b9635f92fc522295f75eb2e752f15a;hb=HEAD;hp=6032b9415df05e79a9b503724a6e9917966c2b0a;hpb=8366314611bf30a0f31d25bf5f5023186fa87692;p=ion3.git diff --git a/ioncore/ioncore_menudb.lua b/ioncore/ioncore_menudb.lua index 6032b94..1d8100b 100644 --- a/ioncore/ioncore_menudb.lua +++ b/ioncore/ioncore_menudb.lua @@ -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 -- }}}