naughty: Bump the SPEC version compliance to v1.2.
* action icons * persistence * residence * categories * animated icons * more ways to get icons In addition, the commit also tries its best to attach notifications to objects using various dubious semi compliant hints or the DBus PID. It works often enough to be useful.
This commit is contained in:
parent
620241e056
commit
e076bc664e
|
@ -134,10 +134,36 @@ gtable.crush(naughty, require("naughty.constants"))
|
|||
-- @property auto_reset_timeout
|
||||
-- @tparam[opt=true] boolean auto_reset_timeout
|
||||
|
||||
--- Enable or disable naughty ability to claim to support animations.
|
||||
--
|
||||
-- When this is true, applications which query `naughty` feature support
|
||||
-- will see that animations are supported. Note that there is *very little*
|
||||
-- support for this and enabled it will cause bugs.
|
||||
--
|
||||
-- @property image_animations_enabled
|
||||
-- @param[opt=false] boolean
|
||||
|
||||
--- Enable or disable the persistent notifications.
|
||||
--
|
||||
-- This is very annoying when using `naughty.layout.box` popups, but tolerable
|
||||
-- when using `naughty.list.notifications`.
|
||||
--
|
||||
-- Note that enabling this **does nothing** in `naughty` itself. The timeouts
|
||||
-- are still honored and notifications still destroyed. It is the user
|
||||
-- responsibility to disable the dismiss timer. However, this tells the
|
||||
-- applications that notification persistence is supported so they might
|
||||
-- stop using systray icons for the sake of displaying or other changes like
|
||||
-- that.
|
||||
--
|
||||
-- @property persistence_enabled
|
||||
-- @param[opt=false] boolean
|
||||
|
||||
local properties = {
|
||||
suspended = false,
|
||||
expiration_paused = false,
|
||||
auto_reset_timeout = true,
|
||||
image_animations_enabled = false,
|
||||
persistence_enabled = false,
|
||||
}
|
||||
|
||||
--TODO v5 Deprecate the public `naughty.notifications` (to make it private)
|
||||
|
@ -514,6 +540,18 @@ end
|
|||
-- including, but not limited to, all `naughty.notification` properties.
|
||||
-- @signal request::preset
|
||||
|
||||
--- Emitted when an action requires an icon it doesn't know.
|
||||
--
|
||||
-- The implementation should look in the icon theme for an action icon or
|
||||
-- provide something natively.
|
||||
--
|
||||
-- If an icon is found, the handler must set the `icon` property on the `action`
|
||||
-- object to a path or a `gears.surface`.
|
||||
--
|
||||
-- @signal request::icon
|
||||
-- @tparam naughty.action action The action.
|
||||
-- @tparam string icon_name The icon name.
|
||||
|
||||
-- Register a new notification object.
|
||||
local function register(notification, args)
|
||||
-- Add the some more properties
|
||||
|
@ -564,6 +602,8 @@ local function set_index_miss(_, key, value)
|
|||
if not value then
|
||||
resume()
|
||||
end
|
||||
|
||||
naughty.emit_signal("property::"..key)
|
||||
else
|
||||
rawset(naughty, key, value)
|
||||
end
|
||||
|
|
|
@ -14,6 +14,7 @@ local string = string
|
|||
local capi = { awesome = awesome }
|
||||
local gtable = require("gears.table")
|
||||
local gsurface = require("gears.surface")
|
||||
local gdebug = require("gears.debug")
|
||||
local protected_call = require("gears.protected_call")
|
||||
local lgi = require("lgi")
|
||||
local cairo, Gio, GLib, GObject = lgi.cairo, lgi.Gio, lgi.GLib, lgi.GObject
|
||||
|
@ -28,6 +29,10 @@ local cst = require("naughty.constants")
|
|||
local nnotif = require("naughty.notification")
|
||||
local naction = require("naughty.action")
|
||||
|
||||
local capabilities = {
|
||||
"body", "body-markup", "icon-static", "actions", "action-icons"
|
||||
}
|
||||
|
||||
--- Notification library, dbus bindings
|
||||
local dbus = { config = {} }
|
||||
|
||||
|
@ -123,7 +128,7 @@ end
|
|||
local notif_methods = {}
|
||||
|
||||
function notif_methods.Notify(sender, object_path, interface, method, parameters, invocation)
|
||||
local appname, replaces_id, icon, title, text, actions, hints, expire =
|
||||
local appname, replaces_id, app_icon, title, text, actions, hints, expire =
|
||||
unpack(parameters.value)
|
||||
|
||||
local args = {}
|
||||
|
@ -167,14 +172,26 @@ function notif_methods.Notify(sender, object_path, interface, method, parameters
|
|||
notification:destroy(cst.notification_closed_reason.dismissed_by_user)
|
||||
end
|
||||
elseif action_id ~= nil and action_text ~= nil then
|
||||
|
||||
local a = naction {
|
||||
name = action_text,
|
||||
position = action_id,
|
||||
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::icon", a, action_id)
|
||||
end
|
||||
|
||||
a:connect_signal("invoked", function()
|
||||
sendActionInvoked(notification.id, action_id)
|
||||
|
||||
if not notification.resident then
|
||||
notification:destroy(cst.notification_closed_reason.dismissed_by_user)
|
||||
end
|
||||
end)
|
||||
|
||||
table.insert(args.actions, a)
|
||||
|
@ -189,22 +206,34 @@ function notif_methods.Notify(sender, object_path, interface, method, parameters
|
|||
member = method, sender = sender, bus = "session"
|
||||
}
|
||||
if not preset.callback or (type(preset.callback) == "function" and
|
||||
preset.callback(legacy_data, appname, replaces_id, icon, title, text, actions, hints, expire)) then
|
||||
if icon ~= "" then
|
||||
args.icon = icon
|
||||
elseif hints.icon_data or hints.image_data then
|
||||
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_data
|
||||
local icon_condidates = {}
|
||||
for k, v in parameters:get_child_value(7 - 1):pairs() do
|
||||
if k == "icon_data" then
|
||||
icon_data = v
|
||||
elseif k == "image_data" and icon_data == nil then
|
||||
icon_data = v
|
||||
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
|
||||
|
@ -218,20 +247,87 @@ function notif_methods.Notify(sender, object_path, interface, method, parameters
|
|||
-- 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.icon = convert_icon(icon_data[1], icon_data[2], icon_data[3], icon_data[6], data)
|
||||
args.image = 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,
|
||||
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(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
|
||||
|
@ -240,6 +336,9 @@ function notif_methods.Notify(sender, object_path, interface, method, parameters
|
|||
-- Even if no property changed, restart the timeout.
|
||||
notification:reset_timeout()
|
||||
else
|
||||
-- Only set the sender for new notifications.
|
||||
args._unique_sender = sender
|
||||
|
||||
notification = nnotif(args)
|
||||
end
|
||||
|
||||
|
@ -261,16 +360,14 @@ end
|
|||
function notif_methods.GetServerInformation(_, _, _, _, _, invocation)
|
||||
-- name of notification app, name of vender, version, specification version
|
||||
invocation:return_value(GLib.Variant("(ssss)", {
|
||||
"naughty", "awesome", capi.awesome.version, "1.0"
|
||||
"naughty", "awesome", capi.awesome.version, "1.2"
|
||||
}))
|
||||
end
|
||||
|
||||
function notif_methods.GetCapabilities(_, _, _, _, _, invocation)
|
||||
-- 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.
|
||||
invocation:return_value(GLib.Variant("(as)", {
|
||||
{ "body", "body-markup", "icon-static", "actions" }
|
||||
}))
|
||||
invocation:return_value(GLib.Variant("(as)", {capabilities}))
|
||||
end
|
||||
|
||||
local function method_call(_, sender, object_path, interface, method, parameters, invocation)
|
||||
|
@ -330,6 +427,101 @@ local function on_bus_acquire(conn, _)
|
|||
GObject.Closure(method_call))
|
||||
end
|
||||
|
||||
local bus_proxy, pid_for_unique_name = nil, {}
|
||||
|
||||
Gio.DBusProxy.new_for_bus(
|
||||
Gio.BusType.SESSION,
|
||||
Gio.DBusProxyFlags.DO_NOT_LOAD_PROPERTIES,
|
||||
nil,
|
||||
"org.freedesktop.DBus",
|
||||
"/org/freedesktop/DBus",
|
||||
"org.freedesktop.DBus",
|
||||
nil,
|
||||
function(proxy)
|
||||
bus_proxy = proxy
|
||||
end,
|
||||
nil
|
||||
)
|
||||
|
||||
--- Get the clients associated with a notification.
|
||||
--
|
||||
-- Note that is based on the process PID. PIDs roll over, so don't use this
|
||||
-- with very old notifications.
|
||||
--
|
||||
-- Also note that some multi-process application can use a different process
|
||||
-- for the clients and the service used to send the notifications.
|
||||
--
|
||||
-- Since this is based on PIDs, it is impossible to know which client sent the
|
||||
-- notification if the process has multiple clients (windows). Using the
|
||||
-- `client.type` can be used to further filter this list into more probable
|
||||
-- candidates (tooltips, menus and dialogs are unlikely to send notifications).
|
||||
--
|
||||
-- @tparam naughty.notification notif A notification object.
|
||||
-- @treturn table A table with all associated clients.
|
||||
function dbus.get_clients(notif)
|
||||
-- First, the trivial case, but I never found an app that implements it.
|
||||
-- It isn't standardized, but mentioned as possible.
|
||||
local win_id = notif.freedesktop_hints and (notif.freedesktop_hints.window_ID
|
||||
or notif.freedesktop_hints["window-id"]
|
||||
or notif.freedesktop_hints.windowID
|
||||
or notif.freedesktop_hints.windowid)
|
||||
|
||||
if win_id then
|
||||
for _, c in ipairs(client.get()) do
|
||||
if c.window_id == win_id then
|
||||
return {win_id}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Less trivial, but mentioned in the spec. Note that this isn't
|
||||
-- recommended by the spec, let alone mandatory. It is mentioned it can
|
||||
-- exist. This wont work with Flatpak or Snaps.
|
||||
local pid = notif.freedesktop_hints and (
|
||||
notif.freedesktop_hints.PID or notif.freedesktop_hints.pid
|
||||
)
|
||||
|
||||
if ((not bus_proxy) or not notif._private._unique_sender) and not pid then
|
||||
return {}
|
||||
end
|
||||
|
||||
if (not pid) and (not pid_for_unique_name[notif._private._unique_sender]) then
|
||||
local owner = GLib.Variant("(s)", {notif._private._unique_sender})
|
||||
|
||||
-- It is sync, but this isn't done very often and since it is DBus
|
||||
-- daemon itself, it is very responsive. Doing this using the async
|
||||
-- variant would cause the clients to be unavailable in the notification
|
||||
-- rules.
|
||||
pid = bus_proxy:call_sync("GetConnectionUnixProcessID",
|
||||
owner,
|
||||
Gio.DBusCallFlags.NONE,
|
||||
-1
|
||||
)
|
||||
|
||||
if (not pid) or (not pid.value) then return {} end
|
||||
|
||||
pid = pid.value and pid.value[1]
|
||||
|
||||
if not pid then return {} end
|
||||
|
||||
pid_for_unique_name[notif._private._unique_sender] = pid
|
||||
end
|
||||
|
||||
pid = pid or pid_for_unique_name[notif._private._unique_sender]
|
||||
|
||||
if not pid then return {} end
|
||||
|
||||
local ret = {}
|
||||
|
||||
for _, c in ipairs(client.get()) do
|
||||
if c.pid == pid then
|
||||
table.insert(ret, c)
|
||||
end
|
||||
end
|
||||
|
||||
return ret
|
||||
end
|
||||
|
||||
local function on_name_acquired(conn, _)
|
||||
bus_connection = conn
|
||||
end
|
||||
|
@ -345,6 +537,35 @@ Gio.bus_own_name(Gio.BusType.SESSION, "org.freedesktop.Notifications",
|
|||
-- For testing
|
||||
dbus._notif_methods = notif_methods
|
||||
|
||||
local function remove_capability(cap)
|
||||
for k, v in ipairs(capabilities) do
|
||||
if v == cap then
|
||||
table.remove(capabilities, k)
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Update the capabilities.
|
||||
naughty.connect_signal("property::persistence_enabled", function()
|
||||
remove_capability("persistence")
|
||||
|
||||
if naughty.persistence_enabled then
|
||||
table.insert(capabilities, "persistence")
|
||||
end
|
||||
end)
|
||||
naughty.connect_signal("property::image_animations_enabled", function()
|
||||
remove_capability("icon-multi")
|
||||
remove_capability("icon-static")
|
||||
|
||||
table.insert(capabilities, naughty.persistence_enabled
|
||||
and "icon-multi" or "icon-static"
|
||||
)
|
||||
end)
|
||||
|
||||
-- For the tests.
|
||||
dbus._capabilities = capabilities
|
||||
|
||||
return dbus
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
---------------------------------------------------------------------------
|
||||
local gobject = require("gears.object")
|
||||
local gtable = require("gears.table")
|
||||
local gsurface = require("gears.surface")
|
||||
local timer = require("gears.timer")
|
||||
local cst = require("naughty.constants")
|
||||
local naughty = require("naughty.core")
|
||||
|
@ -95,6 +96,72 @@ local notification = {}
|
|||
-- @property timeout
|
||||
-- @param number
|
||||
|
||||
--- The notification urgency level.
|
||||
--
|
||||
-- The default urgency levels are:
|
||||
--
|
||||
-- * low
|
||||
-- * normal
|
||||
-- * critical
|
||||
--
|
||||
-- @property urgency
|
||||
-- @param string
|
||||
|
||||
--- The notification category.
|
||||
--
|
||||
-- The category should be named using the `x-vendor.class.name` naming scheme or
|
||||
-- use one of the default categories:
|
||||
--
|
||||
-- <table class='widget_list' border=1>
|
||||
-- <tr style='font-weight: bold;'>
|
||||
-- <th align='center'>Name</th>
|
||||
-- <th align='center'>Description</th>
|
||||
-- </tr>
|
||||
-- <tr><td><b>device</b></td><td>A generic device-related notification that
|
||||
-- doesn't fit into any other category.</td></tr>
|
||||
-- <tr><td><b>device.added</b></td><td>A device, such as a USB device, was added to the system.</td></tr>
|
||||
-- <tr><td><b>device.error</b></td><td>A device had some kind of error.</td></tr>
|
||||
-- <tr><td><b>device.removed</b></td><td>A device, such as a USB device, was removed from the system.</td></tr>
|
||||
-- <tr><td><b>email</b></td><td>A generic e-mail-related notification that doesn't fit into
|
||||
-- any other category.</td></tr>
|
||||
-- <tr><td><b>email.arrived</b></td><td>A new e-mail notification.</td></tr>
|
||||
-- <tr><td><b>email.bounced</b></td><td>A notification stating that an e-mail has bounced.</td></tr>
|
||||
-- <tr><td><b>im</b></td><td>A generic instant message-related notification that doesn't fit into
|
||||
-- any other category.</td></tr>
|
||||
-- <tr><td><b>im.error</b></td><td>An instant message error notification.</td></tr>
|
||||
-- <tr><td><b>im.received</b></td><td>A received instant message notification.</td></tr>
|
||||
-- <tr><td><b>network</b></td><td>A generic network notification that doesn't fit into any other
|
||||
-- category.</td></tr>
|
||||
-- <tr><td><b>network.connected</b></td><td>A network connection notification, such as successful
|
||||
-- sign-on to a network service. <br />
|
||||
-- This should not be confused with device.added for new network devices.</td></tr>
|
||||
-- <tr><td><b>network.disconnected</b></td><td>A network disconnected notification. This should not
|
||||
-- be confused with <br />
|
||||
-- device.removed for disconnected network devices.</td></tr>
|
||||
-- <tr><td><b>network.error</b></td><td>A network-related or connection-related error.</td></tr>
|
||||
-- <tr><td><b>presence</b></td><td>A generic presence change notification that doesn't fit into any
|
||||
-- other category, <br />
|
||||
-- such as going away or idle.</td></tr>
|
||||
-- <tr><td><b>presence.offline</b></td><td>An offline presence change notification.</td></tr>
|
||||
-- <tr><td><b>presence.online</b></td><td>An online presence change notification.</td></tr>
|
||||
-- <tr><td><b>transfer</b></td><td>A generic file transfer or download notification that doesn't
|
||||
-- fit into any other category.</td></tr>
|
||||
-- <tr><td><b>transfer.complete</b></td><td>A file transfer or download complete notification.</td></tr>
|
||||
-- <tr><td><b>transfer.error</b></td><td>A file transfer or download error.</td></tr>
|
||||
-- </table>
|
||||
--
|
||||
-- @property category
|
||||
-- @tparam string|nil category
|
||||
|
||||
--- True if the notification should be kept when an action is pressed.
|
||||
--
|
||||
-- By default, invoking an action will destroy the notification. Some actions,
|
||||
-- like the "Snooze" action of alarm clock, will cause the notification to
|
||||
-- be updated with a date further in the future.
|
||||
--
|
||||
-- @property resident
|
||||
-- @param[opt=false] boolean
|
||||
|
||||
--- Delay in seconds after which hovered popup disappears.
|
||||
-- @property hover_timeout
|
||||
-- @param number
|
||||
|
@ -143,14 +210,59 @@ local notification = {}
|
|||
-- @property font
|
||||
-- @param string
|
||||
|
||||
--- Path to icon.
|
||||
--- "All in one" way to access the default image or icon.
|
||||
--
|
||||
-- A notification can provide a combination of an icon, a static image, or if
|
||||
-- enabled, a looping animation. Add to that the ability to import the icon
|
||||
-- information from the client or from a `.desktop` file, there is multiple
|
||||
-- conflicting sources of "icons".
|
||||
--
|
||||
-- On the other hand, the vast majority of notifications don't multiple or
|
||||
-- ambiguous sources of icons. This property will pick the first of the
|
||||
-- following.
|
||||
--
|
||||
-- * The `image`.
|
||||
-- * The `app_icon`.
|
||||
-- * The `icon` from a client with `normal` type.
|
||||
-- * The `icon` of a client with `dialog` type.
|
||||
--
|
||||
-- @property icon
|
||||
-- @tparam string|surface icon
|
||||
-- @see app_icon
|
||||
-- @see image
|
||||
|
||||
--- Desired icon size in px.
|
||||
-- @property icon_size
|
||||
-- @param number
|
||||
|
||||
--- The icon provided in the `app_icon` field of the DBus notification.
|
||||
--
|
||||
-- This should always be either the URI (path) to an icon or a valid XDG
|
||||
-- icon name to be fetched from the theme.
|
||||
--
|
||||
-- @property app_icon
|
||||
-- @param string
|
||||
|
||||
--- The notification image.
|
||||
--
|
||||
-- This is usually provided as a `gears.surface` object. The image is used
|
||||
-- instead of the `app_icon` by notification assets which are auto-generated
|
||||
-- or stored elsewhere than the filesystem (databases, web, Android phones, etc).
|
||||
--
|
||||
-- @property image
|
||||
-- @tparam string|surface image
|
||||
|
||||
--- The notification (animated) images.
|
||||
--
|
||||
-- Note that calling this without first setting
|
||||
-- `naughty.image_animations_enabled` to true will throw an exception.
|
||||
--
|
||||
-- Also note that there is *zero* support for this anywhere else in `naughty`
|
||||
-- and very, very few applications support this.
|
||||
--
|
||||
-- @property images
|
||||
-- @tparam nil|table images
|
||||
|
||||
--- Foreground color.
|
||||
--
|
||||
--@DOC_awful_notification_fg_EXAMPLE@
|
||||
|
@ -284,11 +396,20 @@ local notification = {}
|
|||
-- @property ignore_suspend If set to true this notification
|
||||
-- will be shown even if notifications are suspended via `naughty.suspend`.
|
||||
|
||||
--- A list of clients associated with this notification.
|
||||
--
|
||||
-- When used with DBus notifications, this returns all clients sharing the PID
|
||||
-- of the notification sender. Note that this is highly unreliable.
|
||||
-- Applications that use a different process to send the notification or
|
||||
-- applications (and scripts) calling the `notify-send` command wont have any
|
||||
-- client.
|
||||
--
|
||||
-- @property clients
|
||||
-- @param table
|
||||
|
||||
--FIXME remove the screen attribute, let the handlers decide
|
||||
-- document all handler extra properties
|
||||
|
||||
--FIXME add methods such as persist
|
||||
|
||||
--- Destroy notification by notification object.
|
||||
--
|
||||
-- @method destroy
|
||||
|
@ -398,7 +519,8 @@ local properties = {
|
|||
"fg" , "bg" , "height" , "border_color" ,
|
||||
"shape" , "opacity" , "margin" , "ignore_suspend",
|
||||
"destroy" , "preset" , "callback", "actions" ,
|
||||
"run" , "id" , "ignore" , "auto_reset_timeout"
|
||||
"run" , "id" , "ignore" , "auto_reset_timeout",
|
||||
"urgency" , "image" , "images" ,
|
||||
}
|
||||
|
||||
for _, prop in ipairs(properties) do
|
||||
|
@ -425,12 +547,68 @@ for _, prop in ipairs(properties) do
|
|||
if reset then
|
||||
self:reset_timeout()
|
||||
end
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
local hints_default = {
|
||||
urgency = "normal",
|
||||
resident = false,
|
||||
}
|
||||
|
||||
for _, prop in ipairs { "category", "resident" } do
|
||||
notification["get_"..prop] = notification["get_"..prop] or function(self)
|
||||
return self._private[prop] or (
|
||||
self._private.freedesktop_hints and self._private.freedesktop_hints[prop]
|
||||
) or hints_default[prop]
|
||||
end
|
||||
|
||||
notification["set_"..prop] = notification["set_"..prop] or function(self, value)
|
||||
self._private[prop] = value
|
||||
self:emit_signal("property::"..prop, value)
|
||||
end
|
||||
end
|
||||
|
||||
function notification.get_icon(self)
|
||||
if self._private.icon then
|
||||
return self._private.icon == "" and nil or self._private.icon
|
||||
elseif self.image and self.image ~= "" then
|
||||
return self.image
|
||||
elseif self._private.app_icon and self._private.app_icon ~= "" then
|
||||
return self._private.app_icon
|
||||
end
|
||||
|
||||
local clients = notification.get_clients(self)
|
||||
|
||||
for _, c in ipairs(clients) do
|
||||
if c.type == "normal" then
|
||||
self._private.icon = gsurface(c.icon)
|
||||
return self._private.icon
|
||||
end
|
||||
end
|
||||
|
||||
for _, c in ipairs(clients) do
|
||||
if c.type == "dialog" then
|
||||
self._private.icon = gsurface(c.icon)
|
||||
return self._private.icon
|
||||
end
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
function notification.get_clients(self)
|
||||
-- Clients from the future don't send notification, it's useless to reload
|
||||
-- the list over and over.
|
||||
if self._private.clients then return self._private.clients end
|
||||
|
||||
if not self._private._unique_sender then return {} end
|
||||
|
||||
self._private.clients = require("naughty.dbus").get_clients(self)
|
||||
|
||||
return self._private.clients
|
||||
end
|
||||
|
||||
--TODO v6: remove this
|
||||
local function convert_actions(actions)
|
||||
gdebug.deprecate(
|
||||
|
|
|
@ -250,7 +250,7 @@ for f in $tests; do
|
|||
error="$(echo "$error" | grep -vE ".{19} W: awesome: (Can't read color .* from GTK)" || true)"
|
||||
if [[ $fail_on_warning ]]; then
|
||||
# Filter out ignored warnings.
|
||||
error="$(echo "$error" | grep -vE ".{19} W: awesome: (a_glib_poll|Cannot reliably detect EOF|beautiful: can't get colorscheme from xrdb|Can't read color .* from GTK+3 theme)" || true)"
|
||||
error="$(echo "$error" | grep -vE ".{19} W: awesome: (a_glib_poll|Cannot reliably detect EOF|beautiful: can't get colorscheme from xrdb|Can't read color .* from GTK+3 theme|A notification|Notification)" || true)"
|
||||
fi
|
||||
if [[ -n "$error" ]]; then
|
||||
color_red
|
||||
|
|
Loading…
Reference in New Issue