Merge branch 'notification_actions_master' of git://github.com/fbarthelery/awesome
This commit is contained in:
commit
33196d39ec
52
dbus.c
52
dbus.c
|
@ -791,6 +791,57 @@ luaA_dbus_disconnect_signal(lua_State *L)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Emit a signal on the D-Bus.
|
||||||
|
* \param L The Lua VM state.
|
||||||
|
* \return The number of elements pushed on stack.
|
||||||
|
* \luastack
|
||||||
|
* \lparam A string indicating if we are using system or session bus.
|
||||||
|
* \lparam A string with the dbus path.
|
||||||
|
* \lparam A string with the dbus interface.
|
||||||
|
* \lparam A string with the dbus method name.
|
||||||
|
* \lparam type of 1st arg
|
||||||
|
* \lparam 1st arg value
|
||||||
|
* \lparam type of 2nd arg
|
||||||
|
* \lparam 2nd arg value
|
||||||
|
* ... etc
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
luaA_dbus_emit_signal(lua_State *L)
|
||||||
|
{
|
||||||
|
const char *bus_name = luaL_checkstring(L, 1);
|
||||||
|
const char *path = luaL_checkstring(L, 2);
|
||||||
|
const char *itface = luaL_checkstring(L, 3);
|
||||||
|
const char *name = luaL_checkstring(L, 4);
|
||||||
|
DBusConnection *dbus_connection = a_dbus_bus_getbyname(bus_name);
|
||||||
|
DBusMessage* msg = dbus_message_new_signal(path, itface, name);
|
||||||
|
|
||||||
|
DBusMessageIter iter;
|
||||||
|
dbus_message_iter_init_append(msg, &iter);
|
||||||
|
int top = lua_gettop(L);
|
||||||
|
int nargs = top - 4;
|
||||||
|
|
||||||
|
if(nargs % 2 != 0)
|
||||||
|
{
|
||||||
|
luaA_warn(L, "your D-Bus signal emiting method has wrong number of arguments");
|
||||||
|
dbus_message_unref(msg);
|
||||||
|
lua_pushboolean(L, 0);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
for(int i = 5; i < top; i += 2) {
|
||||||
|
if(!a_dbus_convert_value(L, i, &iter))
|
||||||
|
{
|
||||||
|
luaA_warn(L, "your D-Bus signal emitting method has bad argument type");
|
||||||
|
dbus_message_unref(msg);
|
||||||
|
lua_pushboolean(L, 0);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dbus_connection_send(dbus_connection, msg, NULL);
|
||||||
|
dbus_message_unref(msg);
|
||||||
|
lua_pushboolean(L, 1);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
const struct luaL_Reg awesome_dbus_lib[] =
|
const struct luaL_Reg awesome_dbus_lib[] =
|
||||||
{
|
{
|
||||||
{ "request_name", luaA_dbus_request_name },
|
{ "request_name", luaA_dbus_request_name },
|
||||||
|
@ -799,6 +850,7 @@ const struct luaL_Reg awesome_dbus_lib[] =
|
||||||
{ "remove_match", luaA_dbus_remove_match },
|
{ "remove_match", luaA_dbus_remove_match },
|
||||||
{ "connect_signal", luaA_dbus_connect_signal },
|
{ "connect_signal", luaA_dbus_connect_signal },
|
||||||
{ "disconnect_signal", luaA_dbus_disconnect_signal },
|
{ "disconnect_signal", luaA_dbus_disconnect_signal },
|
||||||
|
{ "emit_signal", luaA_dbus_emit_signal },
|
||||||
{ "__index", luaA_default_index },
|
{ "__index", luaA_default_index },
|
||||||
{ "__newindex", luaA_default_newindex },
|
{ "__newindex", luaA_default_newindex },
|
||||||
{ NULL, NULL }
|
{ NULL, NULL }
|
||||||
|
|
|
@ -95,6 +95,13 @@ local urgency = {
|
||||||
critical = "\2"
|
critical = "\2"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
local notificationClosedReason = {
|
||||||
|
expired = 1,
|
||||||
|
dismissedByUser = 2,
|
||||||
|
dismissedByCommand = 3,
|
||||||
|
undefined = 4
|
||||||
|
}
|
||||||
|
|
||||||
--- DBUS notification to preset mapping
|
--- DBUS notification to preset mapping
|
||||||
-- The first element is an object containing the filter
|
-- The first element is an object containing the filter
|
||||||
-- If the rules in the filter matches the associated preset will be applied
|
-- If the rules in the filter matches the associated preset will be applied
|
||||||
|
@ -251,6 +258,20 @@ local function getById(id)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function sendActionInvoked(notificationId, action)
|
||||||
|
res = capi.dbus.emit_signal("session", "/org/freedesktop/Notifications",
|
||||||
|
"org.freedesktop.Notifications", "ActionInvoked",
|
||||||
|
"i", notificationId,
|
||||||
|
"s", action)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function sendNotificationClosed(notificationId, reason)
|
||||||
|
res = capi.dbus.emit_signal("session", "/org/freedesktop/Notifications",
|
||||||
|
"org.freedesktop.Notifications", "NotificationClosed",
|
||||||
|
"i", notificationId,
|
||||||
|
"i", reason)
|
||||||
|
end
|
||||||
|
|
||||||
--- Create notification. args is a dictionary of (optional) arguments.
|
--- Create notification. args is a dictionary of (optional) arguments.
|
||||||
-- @param text Text of the notification. Default: ''
|
-- @param text Text of the notification. Default: ''
|
||||||
-- @param title Title of the notification. Default: nil
|
-- @param title Title of the notification. Default: nil
|
||||||
|
@ -279,6 +300,7 @@ end
|
||||||
-- @param callback function that will be called with all arguments
|
-- @param callback function that will be called with all arguments
|
||||||
-- the notification will only be displayed if the function returns true
|
-- the notification will only be displayed if the function returns true
|
||||||
-- note: this function is only relevant to notifications sent via dbus
|
-- note: this function is only relevant to notifications sent via dbus
|
||||||
|
-- @param actions array of pair of String:String for each action (id:localized text)
|
||||||
-- @usage naughty.notify({ title = "Achtung!", text = "You're idling", timeout = 0 })
|
-- @usage naughty.notify({ title = "Achtung!", text = "You're idling", timeout = 0 })
|
||||||
-- @return The notification object
|
-- @return The notification object
|
||||||
function naughty.notify(args)
|
function naughty.notify(args)
|
||||||
|
@ -304,6 +326,7 @@ function naughty.notify(args)
|
||||||
local margin = args.margin or preset.margin
|
local margin = args.margin or preset.margin
|
||||||
local border_width = args.border_width or preset.border_width
|
local border_width = args.border_width or preset.border_width
|
||||||
local position = args.position or preset.position
|
local position = args.position or preset.position
|
||||||
|
local actions = args.actions
|
||||||
local escape_pattern = "[<>&]"
|
local escape_pattern = "[<>&]"
|
||||||
local escape_subs = { ['<'] = "<", ['>'] = ">", ['&'] = "&" }
|
local escape_subs = { ['<'] = "<", ['>'] = ">", ['&'] = "&" }
|
||||||
|
|
||||||
|
@ -340,10 +363,13 @@ function naughty.notify(args)
|
||||||
if title then title = title .. "\n" else title = "" end
|
if title then title = title .. "\n" else title = "" end
|
||||||
|
|
||||||
-- hook destroy
|
-- hook destroy
|
||||||
local die = function () naughty.destroy(notification) end
|
local die = function (reason)
|
||||||
|
naughty.destroy(notification)
|
||||||
|
sendNotificationClosed(notification.id, reason)
|
||||||
|
end
|
||||||
if timeout > 0 then
|
if timeout > 0 then
|
||||||
local timer_die = timer { timeout = timeout }
|
local timer_die = timer { timeout = timeout }
|
||||||
timer_die:connect_signal("timeout", die)
|
timer_die:connect_signal("timeout", function() die(notificationClosedReason.expired) end)
|
||||||
if not suspended then
|
if not suspended then
|
||||||
timer_die:start()
|
timer_die:start()
|
||||||
end
|
end
|
||||||
|
@ -351,21 +377,25 @@ function naughty.notify(args)
|
||||||
end
|
end
|
||||||
notification.die = die
|
notification.die = die
|
||||||
|
|
||||||
|
local has_default_action = false;
|
||||||
local run = function ()
|
local run = function ()
|
||||||
|
if has_default_action then
|
||||||
|
sendActionInvoked(notification.id, "default")
|
||||||
|
end
|
||||||
if args.run then
|
if args.run then
|
||||||
args.run(notification)
|
args.run(notification)
|
||||||
else
|
else
|
||||||
die()
|
die(notificationClosedReason.dismissedByUser)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local hover_destroy = function ()
|
local hover_destroy = function ()
|
||||||
if hover_timeout == 0 then
|
if hover_timeout == 0 then
|
||||||
die()
|
die(notificationClosedReason.expired)
|
||||||
else
|
else
|
||||||
if notification.timer then notification.timer:stop() end
|
if notification.timer then notification.timer:stop() end
|
||||||
notification.timer = timer { timeout = hover_timeout }
|
notification.timer = timer { timeout = hover_timeout }
|
||||||
notification.timer:connect_signal("timeout", die)
|
notification.timer:connect_signal("timeout", function() die(notificationClosedReason.expired) end)
|
||||||
notification.timer:start()
|
notification.timer:start()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -400,6 +430,56 @@ function naughty.notify(args)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local actionslayout = wibox.layout.fixed.vertical()
|
||||||
|
local actions_max_width = 0
|
||||||
|
local actions_total_height = 0
|
||||||
|
if actions then
|
||||||
|
local action
|
||||||
|
local actionid
|
||||||
|
-- create actions box
|
||||||
|
for i , v in ipairs(actions) do
|
||||||
|
if i % 2 == 1 then
|
||||||
|
actionid = v
|
||||||
|
if actionid == "default" then
|
||||||
|
has_default_action = true;
|
||||||
|
end
|
||||||
|
elseif actionid ~= nil and actionid ~= "default" then
|
||||||
|
action = v
|
||||||
|
local actiontextbox = wibox.widget.textbox()
|
||||||
|
local actionmarginbox = wibox.layout.margin()
|
||||||
|
actionmarginbox:set_margins(margin)
|
||||||
|
actionmarginbox:set_widget(actiontextbox)
|
||||||
|
actiontextbox:set_valign("middle")
|
||||||
|
actiontextbox:set_font(font)
|
||||||
|
actiontextbox:set_markup(string.format('<b>%s</b>', action))
|
||||||
|
-- calculate the height
|
||||||
|
local w, h = actiontextbox:fit(-1, -1)
|
||||||
|
local height = h + 2 * margin
|
||||||
|
|
||||||
|
-- calculate the width
|
||||||
|
w, h = actiontextbox:fit(-1, -1)
|
||||||
|
local width = w + 2 * margin
|
||||||
|
|
||||||
|
actionmarginbox:buttons(util.table.join(
|
||||||
|
button({ }, 1, function()
|
||||||
|
sendActionInvoked(notification.id, actionid)
|
||||||
|
die(notificationClosedReason.dismissedByUser)
|
||||||
|
end),
|
||||||
|
button({ }, 3, function()
|
||||||
|
sendActionInvoked(notification.id, actionid)
|
||||||
|
die(notificationClosedReason.dismissedByUser)
|
||||||
|
end))
|
||||||
|
)
|
||||||
|
actionslayout:add(actionmarginbox)
|
||||||
|
|
||||||
|
actions_total_height = actions_total_height + height
|
||||||
|
if actions_max_width < width then
|
||||||
|
actions_max_width = width
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
-- create iconbox
|
-- create iconbox
|
||||||
local iconbox = nil
|
local iconbox = nil
|
||||||
local iconmargin = nil
|
local iconmargin = nil
|
||||||
|
@ -461,12 +541,18 @@ function naughty.notify(args)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
height = height + actions_total_height
|
||||||
|
|
||||||
-- calculate the width
|
-- calculate the width
|
||||||
if not width then
|
if not width then
|
||||||
local w, h = textbox:fit(-1, -1)
|
local w, h = textbox:fit(-1, -1)
|
||||||
width = w + (iconbox and icon_w + 2 * margin or 0) + 2 * margin
|
width = w + (iconbox and icon_w + 2 * margin or 0) + 2 * margin
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if width < actions_max_width then
|
||||||
|
width = actions_max_width
|
||||||
|
end
|
||||||
|
|
||||||
-- crop to workarea size if too big
|
-- crop to workarea size if too big
|
||||||
local workarea = capi.screen[screen].workarea
|
local workarea = capi.screen[screen].workarea
|
||||||
if width > workarea.width - 2 * (border_width or 0) - 2 * (naughty.config.padding or 0) then
|
if width > workarea.width - 2 * (border_width or 0) - 2 * (naughty.config.padding or 0) then
|
||||||
|
@ -497,10 +583,17 @@ function naughty.notify(args)
|
||||||
layout:add(iconmargin)
|
layout:add(iconmargin)
|
||||||
end
|
end
|
||||||
layout:add(marginbox)
|
layout:add(marginbox)
|
||||||
notification.box:set_widget(layout)
|
|
||||||
|
local completelayout = wibox.layout.fixed.vertical()
|
||||||
|
completelayout:add(layout)
|
||||||
|
completelayout:add(actionslayout)
|
||||||
|
notification.box:set_widget(completelayout)
|
||||||
|
|
||||||
-- Setup the mouse events
|
-- Setup the mouse events
|
||||||
layout:buttons(util.table.join(button({ }, 1, run), button({ }, 3, die)))
|
layout:buttons(util.table.join(button({ }, 1, run),
|
||||||
|
button({ }, 3, function()
|
||||||
|
die(notificationClosedReason.dismissedByUser)
|
||||||
|
end)))
|
||||||
|
|
||||||
-- insert the notification to the table
|
-- insert the notification to the table
|
||||||
table.insert(naughty.notifications[screen][notification.position], notification)
|
table.insert(naughty.notifications[screen][notification.position], notification)
|
||||||
|
@ -544,6 +637,7 @@ if capi.dbus then
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
local preset = args.preset or naughty.config.defaults
|
local preset = args.preset or naughty.config.defaults
|
||||||
|
args.actions = actions
|
||||||
if not preset.callback or (type(preset.callback) == "function" and
|
if not preset.callback or (type(preset.callback) == "function" and
|
||||||
preset.callback(data, appname, replaces_id, icon, title, text, actions, hints, expire)) then
|
preset.callback(data, appname, replaces_id, icon, title, text, actions, hints, expire)) then
|
||||||
if icon ~= "" then
|
if icon ~= "" then
|
||||||
|
@ -610,6 +704,7 @@ if capi.dbus then
|
||||||
elseif data.member == "CloseNotification" then
|
elseif data.member == "CloseNotification" then
|
||||||
local obj = getById(appname)
|
local obj = getById(appname)
|
||||||
if obj then
|
if obj then
|
||||||
|
sendNotificationClosed(obj.id, notificationClosedReason.dismissedByCommand)
|
||||||
naughty.destroy(obj)
|
naughty.destroy(obj)
|
||||||
end
|
end
|
||||||
elseif data.member == "GetServerInfo" or data.member == "GetServerInformation" then
|
elseif data.member == "GetServerInfo" or data.member == "GetServerInformation" then
|
||||||
|
@ -618,7 +713,7 @@ if capi.dbus then
|
||||||
elseif data.member == "GetCapabilities" then
|
elseif data.member == "GetCapabilities" then
|
||||||
-- We actually do display the body of the message, we support <b>, <i>
|
-- We actually do display the body of the message, we support <b>, <i>
|
||||||
-- and <u> in the body and we handle static (non-animated) icons.
|
-- and <u> in the body and we handle static (non-animated) icons.
|
||||||
return "as", { "s", "body", "s", "body-markup", "s", "icon-static" }
|
return "as", { "s", "body", "s", "body-markup", "s", "icon-static", "s", "actions" }
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
@ -663,6 +758,14 @@ if capi.dbus then
|
||||||
<arg name="return_vendor" type="s" direction="out"/>
|
<arg name="return_vendor" type="s" direction="out"/>
|
||||||
<arg name="return_version" type="s" direction="out"/>
|
<arg name="return_version" type="s" direction="out"/>
|
||||||
</method>
|
</method>
|
||||||
|
<signal name="NotificationClosed">
|
||||||
|
<arg name="id" type="u" direction="out"/>
|
||||||
|
<arg name="reason" type="u" direction="out"/>
|
||||||
|
</signal>
|
||||||
|
<signal name="ActionInvoked">
|
||||||
|
<arg name="id" type="u" direction="out"/>
|
||||||
|
<arg name="action_key" type="s" direction="out"/>
|
||||||
|
</signal>
|
||||||
</interface>
|
</interface>
|
||||||
</node>]=]
|
</node>]=]
|
||||||
return "s", xml
|
return "s", xml
|
||||||
|
|
|
@ -41,3 +41,17 @@ module("dbus")
|
||||||
-- @param func The function to call.
|
-- @param func The function to call.
|
||||||
-- @name disconnect_signal
|
-- @name disconnect_signal
|
||||||
-- @class function
|
-- @class function
|
||||||
|
|
||||||
|
-- Emit a signal on the D-Bus.
|
||||||
|
-- @param bus A string indicating if we are using system or session bus.
|
||||||
|
-- @param path A string with the dbus path.
|
||||||
|
-- @param interface A string with the dbus interface.
|
||||||
|
-- @param method A string with the dbus method name.
|
||||||
|
-- @param type_1st_arg type of 1st argument
|
||||||
|
-- @param value_1st_arg value of 1st argument
|
||||||
|
-- @param type_2nd_arg type of 2nd argument
|
||||||
|
-- @param value_2nd_arg value of 2nd argument
|
||||||
|
-- ... etc
|
||||||
|
-- @name emit_signal
|
||||||
|
-- @class function
|
||||||
|
--
|
||||||
|
|
Loading…
Reference in New Issue