aboutsummaryrefslogtreecommitdiff
path: root/.config/awesome/signals/naughty.lua
diff options
context:
space:
mode:
Diffstat (limited to '.config/awesome/signals/naughty.lua')
-rw-r--r--.config/awesome/signals/naughty.lua292
1 files changed, 246 insertions, 46 deletions
diff --git a/.config/awesome/signals/naughty.lua b/.config/awesome/signals/naughty.lua
index 90594c1..cc096e7 100644
--- a/.config/awesome/signals/naughty.lua
+++ b/.config/awesome/signals/naughty.lua
@@ -1,54 +1,254 @@
-local awful = require "awful"
-local beautiful = require "beautiful"
+local gdebug = require "gears.debug"
local naughty = require "naughty"
-local qvars = require "quarrel.vars"
-local wibox = require "wibox"
-
-naughty.connect_signal("request::display", function(n)
- naughty.layout.box {
- notification = n,
- placement = function(d)
- return awful.placement.right(d, {
- margins = beautiful.useless_gap * 2
- })
- end,
- widget_template = {
- widget = wibox.container.margin,
- margins = qvars.big_padding,
- {
- {
- widget = naughty.widget.icon,
- notification = n
- },
- {
- widget = wibox.container.place,
- valign = "center",
- halign = "center",
- {
- {
- widget = naughty.widget.title,
- notification = n
- },
- {
- widget = naughty.widget.message,
- notification = n
- },
- -- spacing = 4,
- layout = wibox.layout.fixed.vertical,
- }
- },
- fill_space = true,
- spacing = n.icon and qvars.big_padding or 0,
- layout = wibox.layout.fixed.horizontal
- }
- }
+local ndbus = require "naughty.dbus"
+local qdelegate = require "quarrel.delegate"
+local wicked = require "ui.wicked"
+
+---@diagnostic disable-next-line:redundant-parameter
+ndbus._notif_methods.Notify = qdelegate(function(env, sender, object_path, interface, method, parameters, invocation)
+ local appname, replaces_id, app_icon, title, text, actions, hints, expire = env.unpack(parameters.value)
+
+ local args = {}
+ if text ~= "" then
+ args.message = text
+ if title ~= "" then
+ args.title = title
+ end
+ else
+ if title ~= "" then
+ args.message = title
+ else
+ -- FIXME: We have to reply *something* to the DBus invocation.
+ -- Right now this leads to a memory leak, I think.
+ return
+ end
+ end
+
+ if appname ~= "" then
+ args.appname = appname --TODO v6 Remove this.
+ args.app_name = appname
+ end
+
+ local preset = args.preset or env.cst.config.defaults
+ local notification
+ if actions then
+ args.actions = {}
+
+ for i = 1, #actions, 2 do
+ local action_id = actions[i]
+ local action_text = actions[i + 1]
+
+ if action_id == "default" then
+ args.run = function()
+ env.sendActionInvoked(notification.id, "default")
+ notification:destroy(env.cst.notification_closed_reason.dismissed_by_user)
+ end
+ elseif action_id ~= nil and action_text ~= nil then
+ local a = env.naction {
+ name = action_text,
+ id = action_id,
+ position = (i - 1) / 2 + 1,
+ }
+
+ -- Right now `gears` doesn't have a great icon implementation
+ -- and `naughty` doesn't depend on `menubar`, so delegate the
+ -- icon "somewhere" using a request.
+ if hints["action-icons"] and action_id ~= "" then
+ naughty.emit_signal("request::action_icon", a, "dbus", { id = action_id })
+ end
+
+ a:connect_signal("invoked", function()
+ env.sendActionInvoked(notification.id, action_id)
+
+ if not notification.resident then
+ notification:destroy(env.cst.notification_closed_reason.dismissed_by_user)
+ end
+ end)
+
+ table.insert(args.actions, a)
+ end
+ end
+ end
+ args.destroy = function(reason)
+ env.sendNotificationClosed(notification.id, reason)
+ end
+ local legacy_data = { -- This data used to be generated by AwesomeWM's C code
+ type = "method_call",
+ interface = interface,
+ path = object_path,
+ member = method,
+ sender = sender,
+ bus = "session",
}
-end)
+ if
+ not preset.callback
+ or (
+ type(preset.callback) == "function"
+ and preset.callback(legacy_data, appname, replaces_id, app_icon, title, text, actions, hints, expire)
+ )
+ then
+ if app_icon ~= "" then
+ args.app_icon = app_icon
+ end
+
+ if hints.icon_data or hints.image_data or hints["image-data"] then
+ -- Icon data is a bit complex and hence needs special care:
+ -- .value breaks with the array of bytes (ay) that we get here.
+ -- So, bypass it and look up the needed value differently
+ local icon_condidates = {}
+ for k, v in parameters:get_child_value(7 - 1):pairs() do
+ if k == "image-data" then
+ icon_condidates[1] = v -- not deprecated
+ break
+ elseif k == "image_data" then -- deprecated
+ icon_condidates[2] = v
+ elseif k == "icon_data" then -- deprecated
+ icon_condidates[3] = v
+ end
+ end
+
+ -- The order is mandated by the spec.
+ local icon_data = icon_condidates[1] or icon_condidates[2] or icon_condidates[3]
+
+ -- icon_data is an array:
+ -- 1 -> width
+ -- 2 -> height
+ -- 3 -> rowstride
+ -- 4 -> has alpha
+ -- 5 -> bits per sample
+ -- 6 -> channels
+ -- 7 -> data
+
+ -- Get the value as a GVariant and then use LGI's special
+ -- GVariant.data to get that as an LGI byte buffer. That one can
+ -- then by converted to a string via its __tostring metamethod.
+ local data = tostring(icon_data:get_child_value(7 - 1).data)
+ args.image = env.convert_icon(icon_data[1], icon_data[2], icon_data[3], icon_data[6], data)
+
+ -- Convert all animation frames.
+ if naughty.image_animations_enabled then
+ args.images = { args.image }
+
+ if #icon_data > 7 then
+ for frame = 8, #icon_data do
+ data = tostring(icon_data:get_child_value(frame - 1).data)
+
+ table.insert(
+ args.images,
+ env.convert_icon(icon_data[1], icon_data[2], icon_data[3], icon_data[6], data)
+ )
+ end
+ end
+ end
+ end
+
+ -- Alternate ways to set the icon. The specs recommends to allow both
+ -- the icon and image to co-exist since they serve different purpose.
+ -- However in case the icon isn't specified, use the image.
+ args.image = args.image
+ or hints["image-path"] -- not deprecated
+ or hints["image_path"] -- deprecated
+
+ if naughty.image_animations_enabled then
+ args.images = args.images or {}
+ end
+
+ if replaces_id and replaces_id ~= "" and replaces_id ~= 0 then
+ args.replaces_id = replaces_id
+ end
+ if expire and expire > -1 then
+ args.timeout = expire / 1000
+ end
+
+ args.freedesktop_hints = hints
+
+ -- Not very pretty, but given the current format is documented in the
+ -- public API... well, whatever...
+ if hints and hints.urgency then
+ for name, key in pairs(env.urgency) do
+ local b = string.char(hints.urgency)
+ if key == b then
+ args.urgency = name
+ end
+ end
+ end
+
+ args.urgency = args.urgency or "normal"
+
+ -- Try to update existing objects when possible
+ notification = naughty.get_by_id(replaces_id)
+
+ if notification then
+ if not notification._private._unique_sender then
+ -- If this happens, the notification is either trying to
+ -- highjack content created within AwesomeWM or it is garbage
+ -- to begin with.
+ gdebug.print_warning(
+ "A notification has been received, but tried to update "
+ .. "the content of a notification it does not own."
+ )
+ elseif notification._private._unique_sender ~= sender then
+ -- Nothing says you cannot and some scripts may do it
+ -- accidentally, but this is rather unexpected.
+ gdebug.print_warning(
+ "Notification "
+ .. notification.title
+ .. " is being updated"
+ .. "by a different DBus connection ("
+ .. sender
+ .. "), this is "
+ .. "suspicious. The original connection was "
+ .. notification._private._unique_sender
+ )
+ end
+
+ for k, v in pairs(args) do
+ if k == "destroy" then
+ k = "destroy_cb"
+ end
+ notification[k] = v
+ end
+
+ -- Update the icon if necessary.
+ if app_icon ~= notification._private.app_icon then
+ notification._private.app_icon = app_icon
+
+ naughty._emit_signal_if("request::icon", function()
+ if notification._private.icon then
+ return true
+ end
+ end, notification, "dbus_clear", {})
+ end
+
+ -- Even if no property changed, restart the timeout.
+ notification:reset_timeout()
+ else
+ -- Only set the sender for new notifications.
+ args._unique_sender = sender
+ args._foreign = true
+
+ notification = env.nnotif(args)
+
+ notification:connect_signal("destroyed", function(_, r)
+ args.destroy(r)
+ end)
+ end
+
+ invocation:return_value(env.GLib.Variant("(u)", { notification.id }))
+ return
+ end
+
+ invocation:return_value(env.GLib.Variant("(u)", { env.nnotif._gen_next_id() }))
+end, ndbus._notif_methods.Notify)
+
+naughty.connect_signal("request::display", wicked)
naughty.connect_signal("request::display_error", function(message, startup)
naughty.notification {
urgency = "critical",
- title = "Oops, an error happened"..(startup and " during startup!" or "!"),
- message = message
+ title = "Oops, an error happened" .. (startup and " during startup!" or "!"),
+ message = message,
}
+
+ gdebug.print_error("[Error" .. (startup and "during startup" or "") .. "]: " .. message)
end)