2011-03-30 23:11:41 +02:00
--------------------------------------------------------------------------------
2014-05-20 13:02:39 +02:00
--- A menu for awful
--
2008-10-22 14:22:48 +02:00
-- @author Damien Leone <damien.leone@gmail.com>
2008-11-07 15:27:35 +01:00
-- @author Julien Danjou <julien@danjou.info>
2011-03-30 23:11:41 +02:00
-- @author dodo
-- @copyright 2008, 2011 Damien Leone, Julien Danjou, dodo
2008-10-22 14:22:48 +02:00
-- @release @AWESOME_VERSION@
2014-05-20 13:02:39 +02:00
-- @module awful.menu
2011-03-30 23:11:41 +02:00
--------------------------------------------------------------------------------
2008-10-22 14:22:48 +02:00
2011-03-30 23:11:41 +02:00
local wibox = require ( " wibox " )
local button = require ( " awful.button " )
local util = require ( " awful.util " )
2015-09-30 00:05:56 +02:00
local spawn = require ( " awful.spawn " )
2011-03-30 23:11:41 +02:00
local tags = require ( " awful.tag " )
2012-04-30 17:45:48 +02:00
local keygrabber = require ( " awful.keygrabber " )
2015-11-04 12:00:41 +01:00
local client_iterate = require ( " awful.client " ) . iterate
2011-03-30 23:11:41 +02:00
local beautiful = require ( " beautiful " )
2015-07-15 18:38:57 +02:00
local dpi = require ( " beautiful " ) . xresources.apply_dpi
2011-03-30 23:11:41 +02:00
local object = require ( " gears.object " )
2012-05-27 19:20:34 +02:00
local surface = require ( " gears.surface " )
local cairo = require ( " lgi " ) . cairo
2011-03-30 23:11:41 +02:00
local setmetatable = setmetatable
local tonumber = tonumber
local string = string
local ipairs = ipairs
2008-10-23 11:19:46 +02:00
local pairs = pairs
2011-03-30 23:11:41 +02:00
local pcall = pcall
local print = print
2008-10-22 14:22:48 +02:00
local table = table
local type = type
2011-03-30 23:11:41 +02:00
local math = math
local capi = {
2009-03-04 19:42:25 +01:00
screen = screen ,
mouse = mouse ,
2012-05-27 19:20:34 +02:00
client = client }
2015-01-31 16:40:46 +01:00
local screen = require ( " awful.screen " )
2011-03-30 23:11:41 +02:00
2008-10-22 14:22:48 +02:00
2012-06-12 20:13:09 +02:00
local menu = { mt = { } }
2008-10-22 14:22:48 +02:00
2011-03-30 23:11:41 +02:00
local table_update = function ( t , set )
for k , v in pairs ( set ) do
t [ k ] = v
end
return t
end
2009-08-21 16:34:41 +02:00
--- Key bindings for menu navigation.
2011-05-02 05:30:59 +02:00
-- Keys are: up, down, exec, enter, back, close. Value are table with a list of valid
2009-08-21 16:34:41 +02:00
-- keys for the action, i.e. menu_keys.up = { "j", "k" } will bind 'j' and 'k'
-- key to up action. This is common to all created menu.
-- @class table
-- @name menu_keys
2014-12-01 00:27:28 +01:00
menu.menu_keys = { up = { " Up " , " k " } ,
down = { " Down " , " j " } ,
back = { " Left " , " h " } ,
2011-05-02 05:30:59 +02:00
exec = { " Return " } ,
2014-12-01 00:27:28 +01:00
enter = { " Right " , " l " } ,
2009-08-21 16:34:41 +02:00
close = { " Escape " } }
2009-03-09 14:14:01 +01:00
2008-10-24 22:31:14 +02:00
2011-03-30 23:11:41 +02:00
local function load_theme ( a , b )
a = a or { }
b = b or { }
local ret = { }
local fallback = beautiful.get ( )
if a.reset then b = fallback end
if a == " reset " then a = fallback end
ret.border = a.border_color or b.menu_border_color or b.border_normal or
fallback.menu_border_color or fallback.border_normal
ret.border_width = a.border_width or b.menu_border_width or b.border_width or
2012-11-25 19:17:27 +01:00
fallback.menu_border_width or fallback.border_width or 0
2011-03-30 23:11:41 +02:00
ret.fg_focus = a.fg_focus or b.menu_fg_focus or b.fg_focus or
fallback.menu_fg_focus or fallback.fg_focus
ret.bg_focus = a.bg_focus or b.menu_bg_focus or b.bg_focus or
fallback.menu_bg_focus or fallback.bg_focus
ret.fg_normal = a.fg_normal or b.menu_fg_normal or b.fg_normal or
fallback.menu_fg_normal or fallback.fg_normal
ret.bg_normal = a.bg_normal or b.menu_bg_normal or b.bg_normal or
fallback.menu_bg_normal or fallback.bg_normal
ret.submenu_icon = a.submenu_icon or b.menu_submenu_icon or b.submenu_icon or
fallback.menu_submenu_icon or fallback.submenu_icon
2011-05-17 22:29:00 +02:00
ret.submenu = a.submenu or b.menu_submenu or b.submenu or
fallback.menu_submenu or fallback.submenu or " ▶ "
2011-03-30 23:11:41 +02:00
ret.height = a.height or b.menu_height or b.height or
fallback.menu_height or 16
ret.width = a.width or b.menu_width or b.width or
fallback.menu_width or 100
2011-04-14 07:04:48 +02:00
ret.font = a.font or b.font or fallback.font
2011-03-31 11:56:11 +02:00
for _ , prop in ipairs ( { " width " , " height " , " menu_width " } ) do
if type ( ret [ prop ] ) ~= " number " then ret [ prop ] = tonumber ( ret [ prop ] ) end
end
2011-03-30 23:11:41 +02:00
return ret
end
2008-10-22 14:22:48 +02:00
2008-10-24 22:31:14 +02:00
2012-06-12 20:13:09 +02:00
local function item_position ( _menu , child )
2011-03-30 23:11:41 +02:00
local in_dir , other , a , b = 0 , 0 , " height " , " width "
2015-04-18 08:53:57 +02:00
local dir = _menu.layout . dir or " y "
2011-03-30 23:11:41 +02:00
if dir == " x " then a , b = b , a end
2008-10-22 14:22:48 +02:00
2012-06-12 20:13:09 +02:00
local in_dir , other = 0 , _menu [ b ]
local num = util.table . hasitem ( _menu.child , child )
2011-03-30 23:11:41 +02:00
if num then
for i = 0 , num - 1 do
2012-06-12 20:13:09 +02:00
local item = _menu.items [ i ]
2011-03-30 23:11:41 +02:00
if item then
other = math.max ( other , item [ b ] )
in_dir = in_dir + item [ a ]
end
end
end
local w , h = other , in_dir
if dir == " x " then w , h = h , w end
return w , h
end
2008-10-22 14:22:48 +02:00
2012-06-12 20:13:09 +02:00
local function set_coords ( _menu , screen_idx , m_coords )
2011-03-30 23:11:41 +02:00
local s_geometry = capi.screen [ screen_idx ] . workarea
local screen_w = s_geometry.x + s_geometry.width
local screen_h = s_geometry.y + s_geometry.height
2012-06-12 20:13:09 +02:00
_menu.width = _menu.wibox . width
_menu.height = _menu.wibox . height
2011-03-30 23:11:41 +02:00
2012-06-12 20:13:09 +02:00
_menu.x = _menu.wibox . x
_menu.y = _menu.wibox . y
2011-03-30 23:11:41 +02:00
2012-06-12 20:13:09 +02:00
if _menu.parent then
local w , h = item_position ( _menu.parent , _menu )
w = w + _menu.parent . theme.border_width
2011-03-30 23:11:41 +02:00
2012-06-12 20:13:09 +02:00
_menu.y = _menu.parent . y + h + _menu.height > screen_h and
screen_h - _menu.height or _menu.parent . y + h
_menu.x = _menu.parent . x + w + _menu.width > screen_w and
_menu.parent . x - _menu.width or _menu.parent . x + w
2011-03-30 23:11:41 +02:00
else
if m_coords == nil then
m_coords = capi.mouse . coords ( )
m_coords.x = m_coords.x + 1
m_coords.y = m_coords.y + 1
end
2012-06-12 20:13:09 +02:00
_menu.y = m_coords.y < s_geometry.y and s_geometry.y or m_coords.y
_menu.x = m_coords.x < s_geometry.x and s_geometry.x or m_coords.x
2008-10-22 14:22:48 +02:00
2012-06-12 20:13:09 +02:00
_menu.y = _menu.y + _menu.height > screen_h and
screen_h - _menu.height or _menu.y
_menu.x = _menu.x + _menu.width > screen_w and
screen_w - _menu.width or _menu.x
2009-03-04 19:42:25 +01:00
end
2011-03-30 23:11:41 +02:00
2012-06-12 20:13:09 +02:00
_menu.wibox . x = _menu.x
_menu.wibox . y = _menu.y
2009-03-04 19:42:25 +01:00
end
2009-03-09 14:14:01 +01:00
2012-06-12 20:13:09 +02:00
local function set_size ( _menu )
2011-03-30 23:11:41 +02:00
local in_dir , other , a , b = 0 , 0 , " height " , " width "
2015-04-18 08:53:57 +02:00
local dir = _menu.layout . dir or " y "
2011-03-30 23:11:41 +02:00
if dir == " x " then a , b = b , a end
2012-06-12 20:13:09 +02:00
for _ , item in ipairs ( _menu.items ) do
2011-03-30 23:11:41 +02:00
other = math.max ( other , item [ b ] )
in_dir = in_dir + item [ a ]
2009-03-09 14:14:01 +01:00
end
2012-06-12 20:13:09 +02:00
_menu [ a ] , _menu [ b ] = in_dir , other
2011-03-30 23:11:41 +02:00
if in_dir > 0 and other > 0 then
2012-06-12 20:13:09 +02:00
_menu.wibox [ a ] = in_dir
_menu.wibox [ b ] = other
2011-03-30 23:11:41 +02:00
return true
2009-03-09 14:14:01 +01:00
end
2011-03-30 23:11:41 +02:00
return false
2008-10-22 14:22:48 +02:00
end
2011-03-30 23:11:41 +02:00
2012-06-12 20:13:09 +02:00
local function check_access_key ( _menu , key )
for i , item in ipairs ( _menu.items ) do
2011-03-30 23:11:41 +02:00
if item.akey == key then
2012-06-12 20:13:09 +02:00
_menu : item_enter ( i )
_menu : exec ( i , { exec = true } )
2011-03-30 23:11:41 +02:00
return
end
end
2012-06-12 20:13:09 +02:00
if _menu.parent then
check_access_key ( _menu.parent , key )
2011-03-30 23:11:41 +02:00
end
end
2012-06-12 20:13:09 +02:00
local function grabber ( _menu , mod , key , event )
2012-03-01 21:43:29 +01:00
if event ~= " press " then return end
2011-03-30 23:11:41 +02:00
2012-06-12 20:13:09 +02:00
local sel = _menu.sel or 0
2012-11-30 22:46:55 +01:00
if util.table . hasitem ( menu.menu_keys . up , key ) then
2012-06-12 20:13:09 +02:00
local sel_new = sel - 1 < 1 and # _menu.items or sel - 1
_menu : item_enter ( sel_new )
2012-11-30 22:46:55 +01:00
elseif util.table . hasitem ( menu.menu_keys . down , key ) then
2012-06-12 20:13:09 +02:00
local sel_new = sel + 1 > # _menu.items and 1 or sel + 1
_menu : item_enter ( sel_new )
2012-11-30 22:46:55 +01:00
elseif sel > 0 and util.table . hasitem ( menu.menu_keys . enter , key ) then
2012-06-12 20:13:09 +02:00
_menu : exec ( sel )
2012-11-30 22:46:55 +01:00
elseif sel > 0 and util.table . hasitem ( menu.menu_keys . exec , key ) then
2012-06-12 20:13:09 +02:00
_menu : exec ( sel , { exec = true } )
2012-11-30 22:46:55 +01:00
elseif util.table . hasitem ( menu.menu_keys . back , key ) then
2012-06-12 20:13:09 +02:00
_menu : hide ( )
2012-11-30 22:46:55 +01:00
elseif util.table . hasitem ( menu.menu_keys . close , key ) then
2012-06-12 20:13:09 +02:00
menu.get_root ( _menu ) : hide ( )
2011-03-30 23:11:41 +02:00
else
2012-06-12 20:13:09 +02:00
check_access_key ( _menu , key )
2011-03-30 23:11:41 +02:00
end
2008-10-22 14:22:48 +02:00
end
2011-03-30 23:11:41 +02:00
2012-11-19 14:09:10 +01:00
function menu : exec ( num , opts )
2011-05-02 05:30:59 +02:00
opts = opts or { }
2012-11-19 14:09:10 +01:00
local item = self.items [ num ]
2011-03-30 23:11:41 +02:00
if not item then return end
local cmd = item.cmd
2009-02-23 12:04:27 +01:00
if type ( cmd ) == " table " then
2011-05-02 05:30:59 +02:00
local action = cmd.cmd
2009-03-30 23:45:29 +02:00
if # cmd == 0 then
2011-05-02 05:30:59 +02:00
if opts.exec and action and type ( action ) == " function " then
action ( )
end
2009-03-30 23:45:29 +02:00
return
end
2012-11-19 14:09:10 +01:00
if not self.child [ num ] then
self.child [ num ] = menu.new ( cmd , self )
2008-11-10 19:09:20 +01:00
end
2011-05-02 05:30:59 +02:00
local can_invoke_action = opts.exec and
action and type ( action ) == " function " and
2012-11-19 14:09:10 +01:00
( not opts.mouse or ( opts.mouse and ( self.auto_expand or
( self.active_child == self.child [ num ] and
self.active_child . wibox.visible ) ) ) )
2011-05-02 05:30:59 +02:00
if can_invoke_action then
2012-11-19 14:09:10 +01:00
local visible = action ( self.child [ num ] , item )
2011-05-02 05:30:59 +02:00
if not visible then
2012-11-19 14:09:10 +01:00
menu.get_root ( self ) : hide ( )
2011-05-02 05:30:59 +02:00
return
else
2012-11-19 14:09:10 +01:00
self.child [ num ] : update ( )
2011-05-02 05:30:59 +02:00
end
end
2012-11-19 14:09:10 +01:00
if self.active_child and self.active_child ~= self.child [ num ] then
self.active_child : hide ( )
2008-10-30 12:46:49 +01:00
end
2012-11-19 14:09:10 +01:00
self.active_child = self.child [ num ]
if not self.active_child . visible then
self.active_child : show ( )
2011-05-02 05:30:59 +02:00
end
2009-02-23 12:04:27 +01:00
elseif type ( cmd ) == " string " then
2012-11-19 14:09:10 +01:00
menu.get_root ( self ) : hide ( )
2015-09-30 00:05:56 +02:00
spawn ( cmd )
2009-02-23 12:04:27 +01:00
elseif type ( cmd ) == " function " then
2012-11-19 14:09:10 +01:00
local visible , action = cmd ( item , self )
2011-03-30 23:11:41 +02:00
if not visible then
2012-11-19 14:09:10 +01:00
menu.get_root ( self ) : hide ( )
2011-03-30 23:11:41 +02:00
else
2012-11-19 14:09:10 +01:00
self : update ( )
if self.items [ num ] then
self : item_enter ( num , opts )
2011-03-30 23:11:41 +02:00
end
end
if action and type ( action ) == " function " then
action ( )
end
2008-10-22 14:22:48 +02:00
end
end
2012-11-19 14:09:10 +01:00
function menu : item_enter ( num , opts )
2011-05-02 05:30:59 +02:00
opts = opts or { }
2012-11-19 14:09:10 +01:00
local item = self.items [ num ]
if num == nil or self.sel == num or not item then
2009-03-04 19:42:25 +01:00
return
2012-11-19 14:09:10 +01:00
elseif self.sel then
self : item_leave ( self.sel )
2009-03-04 19:42:25 +01:00
end
2011-03-30 23:11:41 +02:00
--print("sel", num, menu.sel, item.theme.bg_focus)
item._background : set_fg ( item.theme . fg_focus )
item._background : set_bg ( item.theme . bg_focus )
2012-11-19 14:09:10 +01:00
self.sel = num
2009-03-04 19:42:25 +01:00
2012-11-19 14:09:10 +01:00
if self.auto_expand and opts.hover then
if self.active_child then
self.active_child : hide ( )
self.active_child = nil
2009-02-22 16:01:39 +01:00
end
2011-03-30 23:11:41 +02:00
if type ( item.cmd ) == " table " then
2012-11-19 14:09:10 +01:00
self : exec ( num , opts )
2009-02-22 16:01:39 +01:00
end
end
2009-02-23 12:04:27 +01:00
end
2011-03-30 23:11:41 +02:00
2012-11-19 14:09:10 +01:00
function menu : item_leave ( num )
2011-03-30 23:11:41 +02:00
--print("leave", num)
2012-11-19 14:09:10 +01:00
local item = self.items [ num ]
2011-03-30 23:11:41 +02:00
if item then
item._background : set_fg ( item.theme . fg_normal )
item._background : set_bg ( item.theme . bg_normal )
end
2009-11-26 12:47:39 +01:00
end
2011-03-30 23:11:41 +02:00
--- Show a menu.
2014-05-19 13:28:57 +02:00
-- @param args The arguments
2011-03-30 23:11:41 +02:00
-- @param args.coords Menu position defaulting to mouse.coords()
2012-11-19 14:09:10 +01:00
function menu : show ( args )
2011-03-30 23:11:41 +02:00
args = args or { }
local coords = args.coords or nil
2015-01-31 16:40:46 +01:00
local screen_index = screen.focused ( )
2011-03-30 23:11:41 +02:00
2012-11-19 14:09:10 +01:00
if not set_size ( self ) then return end
set_coords ( self , screen_index , coords )
2011-03-30 23:11:41 +02:00
2012-11-19 14:09:10 +01:00
keygrabber.run ( self._keygrabber )
self.wibox . visible = true
2011-03-30 23:11:41 +02:00
end
--- Hide a menu popup.
2012-11-19 14:09:10 +01:00
function menu : hide ( )
2011-03-30 23:11:41 +02:00
-- Remove items from screen
2012-11-19 14:09:10 +01:00
for i = 1 , # self.items do
self : item_leave ( i )
2011-03-30 23:11:41 +02:00
end
2012-11-19 14:09:10 +01:00
if self.active_child then
self.active_child : hide ( )
self.active_child = nil
2011-03-30 23:11:41 +02:00
end
2012-11-19 14:09:10 +01:00
self.sel = nil
2011-03-30 23:11:41 +02:00
2012-11-19 14:09:10 +01:00
keygrabber.stop ( self._keygrabber )
self.wibox . visible = false
2011-03-30 23:11:41 +02:00
end
--- Toggle menu visibility.
2014-05-19 13:28:57 +02:00
-- @param args The arguments
2011-03-30 23:11:41 +02:00
-- @param args.coords Menu position {x,y}
2012-11-19 14:09:10 +01:00
function menu : toggle ( args )
if self.wibox . visible then
self : hide ( )
2009-11-26 12:47:39 +01:00
else
2012-11-19 14:09:10 +01:00
self : show ( args )
2011-03-30 23:11:41 +02:00
end
end
--- Update menu content
2012-11-19 14:09:10 +01:00
function menu : update ( )
if self.wibox . visible then
self : show ( { coords = { x = self.x , y = self.y } } )
2009-03-09 14:14:01 +01:00
end
end
2011-03-30 23:11:41 +02:00
--- Get the elder parent so for example when you kill
-- it, it will destroy the whole family.
2012-11-19 14:09:10 +01:00
function menu : get_root ( )
return self.parent and menu.get_root ( self.parent ) or self
2011-03-30 23:11:41 +02:00
end
2012-11-19 14:09:10 +01:00
--- Add a new menu entry.
-- args.* params needed for the menu entry constructor.
2011-03-30 23:11:41 +02:00
-- @param args The item params
2015-02-26 22:06:34 +01:00
-- @param args.new (Default: awful.menu.entry) The menu entry constructor.
-- @param[opt] args.theme The menu entry theme.
-- @param[opt] index The index where the new entry will inserted.
2012-11-19 14:09:10 +01:00
function menu : add ( args , index )
2011-03-30 23:11:41 +02:00
if not args then return end
2012-11-19 14:09:10 +01:00
local theme = load_theme ( args.theme or { } , self.theme )
2011-03-30 23:11:41 +02:00
args.theme = theme
2012-06-12 20:13:09 +02:00
args.new = args.new or menu.entry
2012-11-19 14:09:10 +01:00
local success , item = pcall ( args.new , self , args )
2011-03-30 23:11:41 +02:00
if not success then
print ( " Error while creating menu entry: " .. item )
return
end
if not item.widget then
print ( " Error while checking menu entry: no property widget found. " )
return
end
2012-11-19 14:09:10 +01:00
item.parent = self
2011-03-30 23:11:41 +02:00
item.theme = item.theme or theme
item.width = item.width or theme.width
item.height = item.height or theme.height
wibox.widget . base.check_widget ( item.widget )
item._background = wibox.widget . background ( )
item._background : set_widget ( item.widget )
item._background : set_fg ( item.theme . fg_normal )
item._background : set_bg ( item.theme . bg_normal )
2008-10-22 14:22:48 +02:00
-- Create bindings
2011-03-30 23:11:41 +02:00
item._background : buttons ( util.table . join (
2012-11-19 14:09:10 +01:00
button ( { } , 3 , function ( ) self : hide ( ) end ) ,
2011-03-30 23:11:41 +02:00
button ( { } , 1 , function ( )
2012-11-19 14:09:10 +01:00
local num = util.table . hasitem ( self.items , item )
self : item_enter ( num , { mouse = true } )
self : exec ( num , { exec = true , mouse = true } )
2011-03-30 23:11:41 +02:00
end ) ) )
item._mouse = function ( )
2012-11-19 14:09:10 +01:00
local num = util.table . hasitem ( self.items , item )
self : item_enter ( num , { hover = true , moue = true } )
2011-03-30 23:11:41 +02:00
end
item.widget : connect_signal ( " mouse::enter " , item._mouse )
2008-10-22 14:22:48 +02:00
2011-03-30 23:11:41 +02:00
if index then
2012-11-19 14:09:10 +01:00
self.layout : reset ( )
table.insert ( self.items , index , item )
for _ , i in ipairs ( self.items ) do
self.layout : add ( i._background )
2011-03-30 23:11:41 +02:00
end
else
2012-11-19 14:09:10 +01:00
table.insert ( self.items , item )
self.layout : add ( item._background )
2011-03-30 23:11:41 +02:00
end
2015-04-18 08:57:15 +02:00
if self.wibox then
set_size ( self )
end
2011-03-30 23:11:41 +02:00
return item
end
2015-02-20 15:45:53 +01:00
--- Delete menu entry at given position
2011-03-30 23:11:41 +02:00
-- @param num The position in the table of the menu entry to be deleted; can be also the menu entry itself
2012-11-19 14:09:10 +01:00
function menu : delete ( num )
2011-03-30 23:11:41 +02:00
if type ( num ) == " table " then
2012-11-19 14:09:10 +01:00
num = util.table . hasitem ( self.items , num )
2011-03-30 23:11:41 +02:00
end
2012-11-19 14:09:10 +01:00
local item = self.items [ num ]
2011-03-30 23:11:41 +02:00
if not item then return end
item.widget : disconnect_signal ( " mouse::enter " , item._mouse )
2011-03-31 12:36:32 +02:00
item.widget . visible = false
2012-11-19 14:09:10 +01:00
table.remove ( self.items , num )
if self.sel == num then
self : item_leave ( self.sel )
self.sel = nil
2012-06-12 20:13:09 +02:00
end
2012-11-19 14:09:10 +01:00
self.layout : reset ( )
for _ , i in ipairs ( self.items ) do
self.layout : add ( i._background )
2012-06-12 20:13:09 +02:00
end
2012-11-19 14:09:10 +01:00
if self.child [ num ] then
self.child [ num ] : hide ( )
if self.active_child == self.child [ num ] then
self.active_child = nil
2011-03-30 23:11:41 +02:00
end
2012-11-19 14:09:10 +01:00
table.remove ( self.child , num )
2011-03-30 23:11:41 +02:00
end
2015-04-18 08:57:15 +02:00
if self.wibox then
set_size ( self )
end
2011-03-30 23:11:41 +02:00
end
--------------------------------------------------------------------------------
2015-12-12 20:10:27 +01:00
--- Build a popup menu with running clients and show it.
-- @tparam[opt] table args Menu table, see `new()` for more information.
-- @tparam[opt] table item_args Table that will be merged into each item, see
-- `new()` for more information.
-- @tparam[opt] func filter A function taking a client as an argument and
-- returning `true` or `false` to indicate whether the client should be
-- included in the menu.
2011-03-30 23:11:41 +02:00
-- @return The menu.
2015-11-04 12:00:41 +01:00
function menu . clients ( args , item_args , filter )
2011-03-30 23:11:41 +02:00
local cls_t = { }
2015-11-04 12:00:41 +01:00
for c in client_iterate ( filter or function ( ) return true end ) do
2011-03-30 23:11:41 +02:00
cls_t [ # cls_t + 1 ] = {
2013-12-26 15:50:10 +01:00
c.name or " " ,
2011-03-30 23:11:41 +02:00
function ( )
if not c : isvisible ( ) then
tags.viewmore ( c : tags ( ) , c.screen )
end
2015-06-19 22:24:12 +02:00
c : emit_signal ( " request::activate " , " menu.clients " , { raise = true } )
2011-03-30 23:11:41 +02:00
end ,
c.icon }
2014-01-11 21:23:23 +01:00
if item_args then
if type ( item_args ) == " function " then
2015-09-20 16:42:24 +02:00
util.table . merge ( cls_t [ # cls_t ] , item_args ( c ) )
2014-01-11 21:23:23 +01:00
else
2015-09-20 16:42:24 +02:00
util.table . merge ( cls_t [ # cls_t ] , item_args )
2014-01-11 21:23:23 +01:00
end
end
2011-03-30 23:11:41 +02:00
end
args = args or { }
args.items = args.items or { }
2015-09-20 16:42:24 +02:00
util.table . merge ( args.items , cls_t )
2011-03-30 23:11:41 +02:00
2012-06-24 03:04:47 +02:00
local m = menu.new ( args )
2011-03-30 23:11:41 +02:00
m : show ( args )
return m
end
--------------------------------------------------------------------------------
--- Default awful.menu.entry constructor
-- @param parent The parent menu
-- @param args the item params
-- @return table with 'widget', 'cmd', 'akey' and all the properties the user wants to change
2012-06-12 20:13:09 +02:00
function menu . entry ( parent , args )
2011-03-30 23:11:41 +02:00
args = args or { }
args.text = args [ 1 ] or args.text or " "
args.cmd = args [ 2 ] or args.cmd
args.icon = args [ 3 ] or args.icon
local ret = { }
2008-12-18 18:02:54 +01:00
-- Create the item label widget
2010-10-06 14:21:19 +02:00
local label = wibox.widget . textbox ( )
2009-11-26 12:47:39 +01:00
local key = ' '
2011-04-14 07:04:48 +02:00
label : set_font ( args.theme . font )
2011-03-30 23:11:41 +02:00
label : set_markup ( string.gsub (
util.escape ( args.text ) , " &(%w) " ,
function ( l )
key = string.lower ( l )
return " <u> " .. l .. " </u> "
end , 1 ) )
2008-12-18 18:02:54 +01:00
-- Set icon if needed
2011-03-30 23:11:41 +02:00
local icon , iconbox
2010-10-06 14:21:19 +02:00
local margin = wibox.layout . margin ( )
margin : set_widget ( label )
2011-03-30 23:11:41 +02:00
if args.icon then
2012-11-25 21:18:23 +01:00
icon = surface.load ( args.icon )
2011-03-30 23:11:41 +02:00
end
if icon then
local iw = icon : get_width ( )
local ih = icon : get_height ( )
if iw > args.theme . width or ih > args.theme . height then
2010-09-29 16:06:44 +02:00
local w , h
2011-03-30 23:11:41 +02:00
if ( ( args.theme . height / ih ) * iw ) > args.theme . width then
w , h = args.theme . height , ( args.theme . height / iw ) * ih
2008-12-18 18:02:54 +01:00
else
2011-03-30 23:11:41 +02:00
w , h = ( args.theme . height / ih ) * iw , args.theme . height
2008-12-18 18:02:54 +01:00
end
2010-09-29 16:06:44 +02:00
-- We need to scale the image to size w x h
2012-05-27 19:20:34 +02:00
local img = cairo.ImageSurface ( cairo.Format . ARGB32 , w , h )
local cr = cairo.Context ( img )
2011-03-30 23:11:41 +02:00
cr : scale ( w / iw , h / ih )
2012-05-27 19:20:34 +02:00
cr : set_source_surface ( icon , 0 , 0 )
2010-09-29 16:06:44 +02:00
cr : paint ( )
icon = img
2008-10-23 11:19:46 +02:00
end
2010-10-06 14:21:19 +02:00
iconbox = wibox.widget . imagebox ( )
2011-03-30 23:11:41 +02:00
if iconbox : set_image ( icon ) then
2015-07-15 18:38:57 +02:00
margin : set_left ( dpi ( 2 ) )
2011-03-30 23:11:41 +02:00
else
2011-03-04 22:07:36 +01:00
iconbox = nil
end
end
if not iconbox then
2015-07-15 18:38:57 +02:00
margin : set_left ( args.theme . height + dpi ( 2 ) )
2008-10-22 14:22:48 +02:00
end
-- Create the submenu icon widget
2011-05-17 22:29:00 +02:00
local submenu
2011-03-30 23:11:41 +02:00
if type ( args.cmd ) == " table " then
if args.theme . submenu_icon then
2011-05-17 22:29:00 +02:00
submenu = wibox.widget . imagebox ( )
2012-05-27 19:20:34 +02:00
submenu : set_image ( surface.load ( args.theme . submenu_icon ) )
2011-05-17 22:29:00 +02:00
else
submenu = wibox.widget . textbox ( )
submenu : set_font ( args.theme . font )
submenu : set_text ( args.theme . submenu )
2010-10-06 14:21:19 +02:00
end
2008-10-22 14:22:48 +02:00
end
-- Add widgets to the wibox
2010-10-06 14:21:19 +02:00
local left = wibox.layout . fixed.horizontal ( )
2009-08-25 18:13:19 +02:00
if iconbox then
2010-10-06 14:21:19 +02:00
left : add ( iconbox )
end
-- This contains the label
left : add ( margin )
local layout = wibox.layout . align.horizontal ( )
2013-01-05 16:12:50 +01:00
layout : set_left ( left )
2011-05-17 22:29:00 +02:00
if submenu then
layout : set_right ( submenu )
2008-10-24 22:31:14 +02:00
end
2011-03-30 23:11:41 +02:00
return table_update ( ret , {
label = label ,
2011-05-17 22:29:00 +02:00
sep = submenu ,
2011-03-30 23:11:41 +02:00
icon = iconbox ,
widget = layout ,
cmd = args.cmd ,
akey = key ,
} )
2008-11-07 15:27:35 +01:00
end
2008-10-24 09:10:42 +02:00
2011-03-30 23:11:41 +02:00
--------------------------------------------------------------------------------
2008-10-24 09:10:42 +02:00
2011-03-30 23:11:41 +02:00
--- Create a menu popup.
2015-02-20 15:41:19 +01:00
-- @param args Table containing the menu informations.
--
-- * Key items: Table containing the displayed items. Each element is a table by default (when element 'new' is awful.menu.entry) containing: item name, triggered action, submenu table or function, item icon (optional).
-- * Keys theme.[fg|bg]_[focus|normal], theme.border_color, theme.border_width, theme.submenu_icon, theme.height and theme.width override the default display for your menu and/or of your menu entry, each of them are optional.
-- * Key auto_expand controls the submenu auto expand behaviour by setting it to true (default) or false.
--
2008-10-23 11:19:46 +02:00
-- @param parent Specify the parent menu if we want to open a submenu, this value should never be set by the user.
2014-08-28 19:45:46 +02:00
-- @usage -- The following function builds and shows a menu of clients that match
-- -- a particular rule.
-- -- Bound to a key, it can be used to select from dozens of terminals open on
-- -- several tags.
2015-02-20 15:41:19 +01:00
-- -- When using @{rules.match_any} instead of @{rules.match},
2014-08-28 19:45:46 +02:00
-- -- a menu of clients with different classes could be build.
2011-01-26 21:42:58 +01:00
--
2014-08-28 19:45:46 +02:00
-- function terminal_menu ()
-- terms = {}
-- for i, c in pairs(client.get()) do
-- if awful.rules.match(c, {class = "URxvt"}) then
-- terms[i] =
-- {c.name,
-- function()
2015-07-14 00:27:26 +02:00
-- awful.tag.viewonly(c.first_tag)
2014-08-28 19:45:46 +02:00
-- client.focus = c
-- end,
-- c.icon
-- }
-- end
-- end
-- awful.menu(terms):show()
-- end
2012-06-12 20:13:09 +02:00
function menu . new ( args , parent )
2011-03-30 23:11:41 +02:00
args = args or { }
args.layout = args.layout or wibox.layout . flex.vertical
2012-06-12 20:13:09 +02:00
local _menu = table_update ( object ( ) , {
item_enter = menu.item_enter ,
item_leave = menu.item_leave ,
get_root = menu.get_root ,
delete = menu.delete ,
update = menu.update ,
toggle = menu.toggle ,
hide = menu.hide ,
show = menu.show ,
exec = menu.exec ,
add = menu.add ,
2011-03-30 23:11:41 +02:00
child = { } ,
items = { } ,
parent = parent ,
layout = args.layout ( ) ,
theme = load_theme ( args.theme or { } , parent and parent.theme ) } )
2009-02-23 14:19:49 +01:00
if parent then
2012-06-12 20:13:09 +02:00
_menu.auto_expand = parent.auto_expand
2011-03-30 23:11:41 +02:00
elseif args.auto_expand ~= nil then
2012-06-12 20:13:09 +02:00
_menu.auto_expand = args.auto_expand
2009-02-23 14:12:28 +01:00
else
2012-06-12 20:13:09 +02:00
_menu.auto_expand = true
2009-02-23 14:12:28 +01:00
end
2008-10-22 14:22:48 +02:00
-- Create items
2012-06-12 20:13:09 +02:00
for i , v in ipairs ( args ) do _menu : add ( v ) end
2011-03-30 23:11:41 +02:00
if args.items then
2012-06-12 20:13:09 +02:00
for i , v in pairs ( args.items ) do _menu : add ( v ) end
2008-10-22 14:22:48 +02:00
end
2012-06-12 20:13:09 +02:00
_menu._keygrabber = function ( ... )
grabber ( _menu , ... )
2012-04-30 17:45:48 +02:00
end
2012-06-12 20:13:09 +02:00
_menu.wibox = wibox ( {
2011-03-30 23:11:41 +02:00
ontop = true ,
2012-06-12 20:13:09 +02:00
fg = _menu.theme . fg_normal ,
bg = _menu.theme . bg_normal ,
border_color = _menu.theme . border ,
border_width = _menu.theme . border_width ,
2011-03-30 23:11:41 +02:00
type = " popup_menu " } )
2012-06-12 20:13:09 +02:00
_menu.wibox . visible = false
_menu.wibox : set_widget ( _menu.layout )
set_size ( _menu )
2011-03-30 23:11:41 +02:00
2012-06-12 20:13:09 +02:00
_menu.x = _menu.wibox . x
_menu.y = _menu.wibox . y
return _menu
2009-04-17 18:08:52 +02:00
end
2009-07-15 15:57:31 +02:00
2012-06-12 20:13:09 +02:00
function menu . mt : __call ( ... )
return menu.new ( ... )
end
return setmetatable ( menu , menu.mt )
2009-07-15 15:57:31 +02:00
2011-09-11 16:50:01 +02:00
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80