2008-10-17 22:38:01 +02:00
|
|
|
----------------------------------------------------------------------------
|
|
|
|
-- @author koniu <gkusnierz@gmail.com>
|
|
|
|
-- @copyright 2008 koniu
|
|
|
|
-- @release @AWESOME_VERSION@
|
|
|
|
----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
-- Package environment
|
|
|
|
local pairs = pairs
|
|
|
|
local table = table
|
2008-12-17 17:47:23 +01:00
|
|
|
local type = type
|
2008-10-17 22:38:01 +02:00
|
|
|
local string = string
|
2013-03-10 10:57:49 +01:00
|
|
|
local tostring = tostring
|
2010-07-16 19:35:51 +02:00
|
|
|
local pcall = pcall
|
2009-05-08 09:01:14 +02:00
|
|
|
local capi = { screen = screen,
|
2012-05-27 19:20:34 +02:00
|
|
|
awesome = awesome }
|
2014-12-06 16:44:04 +01:00
|
|
|
local timer = require("gears.timer")
|
2009-04-17 18:08:52 +02:00
|
|
|
local button = require("awful.button")
|
|
|
|
local util = require("awful.util")
|
2008-11-13 11:53:41 +01:00
|
|
|
local bt = require("beautiful")
|
2010-10-06 14:19:20 +02:00
|
|
|
local wibox = require("wibox")
|
2012-05-27 19:20:34 +02:00
|
|
|
local surface = require("gears.surface")
|
|
|
|
local cairo = require("lgi").cairo
|
2008-10-17 22:38:01 +02:00
|
|
|
|
|
|
|
--- Notification library
|
2012-06-12 03:48:41 +02:00
|
|
|
local naughty = {}
|
2008-10-17 22:38:01 +02:00
|
|
|
|
2009-05-06 18:39:56 +02:00
|
|
|
--- Naughty configuration - a table containing common popup settings.
|
2012-11-19 14:09:10 +01:00
|
|
|
naughty.config = {}
|
|
|
|
--- Space between popups and edge of the workarea. Default: 4
|
|
|
|
naughty.config.padding = 4
|
|
|
|
--- Spacing between popups. Default: 1
|
|
|
|
naughty.config.spacing = 1
|
|
|
|
--- List of directories that will be checked by getIcon()
|
2008-11-22 18:24:33 +01:00
|
|
|
-- Default: { "/usr/share/pixmaps/", }
|
2012-11-19 14:09:10 +01:00
|
|
|
naughty.config.icon_dirs = { "/usr/share/pixmaps/", }
|
|
|
|
--- List of formats that will be checked by getIcon()
|
2008-11-22 18:24:33 +01:00
|
|
|
-- Default: { "png", "gif" }
|
2012-11-19 14:09:10 +01:00
|
|
|
naughty.config.icon_formats = { "png", "gif" }
|
|
|
|
--- Callback used to modify or reject notifications.
|
2011-01-28 01:37:47 +01:00
|
|
|
-- Default: nil
|
|
|
|
-- Example:
|
|
|
|
-- naughty.config.notify_callback = function(args)
|
|
|
|
-- args.text = 'prefix: ' .. args.text
|
|
|
|
-- return args
|
|
|
|
-- end
|
2012-06-12 03:48:41 +02:00
|
|
|
naughty.config.notify_callback = nil
|
2008-11-27 10:07:07 +01:00
|
|
|
|
|
|
|
|
|
|
|
--- Notification Presets - a table containing presets for different purposes
|
2012-05-28 19:16:10 +02:00
|
|
|
-- Preset is a table of any parameters available to notify(), overriding default
|
|
|
|
-- values (@see defaults)
|
2008-11-27 10:07:07 +01:00
|
|
|
-- You have to pass a reference of a preset in your notify() call to use the preset
|
|
|
|
-- The presets "low", "normal" and "critical" are used for notifications over DBUS
|
|
|
|
-- @field low The preset for notifications with low urgency level
|
|
|
|
-- @field normal The default preset for every notification without a preset that will also be used for normal urgency level
|
|
|
|
-- @field critical The preset for notifications with a critical urgency level
|
2014-04-13 18:06:49 +02:00
|
|
|
-- @table naughty.config.presets
|
2012-06-12 03:48:41 +02:00
|
|
|
naughty.config.presets = {
|
2008-11-27 10:07:07 +01:00
|
|
|
low = {
|
|
|
|
timeout = 5
|
|
|
|
},
|
2014-04-13 18:06:49 +02:00
|
|
|
normal = {},
|
2008-11-27 10:07:07 +01:00
|
|
|
critical = {
|
|
|
|
bg = "#ff0000",
|
|
|
|
fg = "#ffffff",
|
|
|
|
timeout = 0,
|
|
|
|
}
|
|
|
|
}
|
2008-10-17 22:38:01 +02:00
|
|
|
|
2012-06-05 16:20:30 +02:00
|
|
|
--- Default values for the params to notify().
|
|
|
|
-- These can optionally be overridden by specifying a preset
|
2012-11-19 14:09:10 +01:00
|
|
|
-- @see naughty.config.presets
|
|
|
|
-- @see naughty.notify
|
2012-06-12 03:48:41 +02:00
|
|
|
naughty.config.defaults = {
|
2012-05-28 19:16:10 +02:00
|
|
|
timeout = 5,
|
|
|
|
text = "",
|
|
|
|
screen = 1,
|
|
|
|
ontop = true,
|
|
|
|
margin = "5",
|
|
|
|
border_width = "1",
|
|
|
|
position = "top_right"
|
|
|
|
}
|
2009-05-06 18:39:56 +02:00
|
|
|
|
2015-01-10 17:32:27 +01:00
|
|
|
naughty.notificationClosedReason = {
|
|
|
|
silent = -1,
|
2014-12-31 14:28:46 +01:00
|
|
|
expired = 1,
|
|
|
|
dismissedByUser = 2,
|
|
|
|
dismissedByCommand = 3,
|
|
|
|
undefined = 4
|
|
|
|
}
|
|
|
|
|
2008-12-11 13:53:24 +01:00
|
|
|
-- Counter for the notifications
|
|
|
|
-- Required for later access via DBUS
|
|
|
|
local counter = 1
|
|
|
|
|
2010-02-16 17:54:45 +01:00
|
|
|
-- True if notifying is suspended
|
|
|
|
local suspended = false
|
|
|
|
|
2012-12-16 11:40:06 +01:00
|
|
|
--- Index of notifications per screen and position. See config table for valid
|
|
|
|
-- 'position' values. Each element is a table consisting of:
|
2008-10-17 22:38:01 +02:00
|
|
|
-- @field box Wibox object containing the popup
|
2008-11-15 17:55:38 +01:00
|
|
|
-- @field height Popup height
|
2008-11-19 03:16:44 +01:00
|
|
|
-- @field width Popup width
|
2008-11-15 17:55:38 +01:00
|
|
|
-- @field die Function to be executed on timeout
|
2008-11-22 15:46:51 +01:00
|
|
|
-- @field id Unique notification id based on a counter
|
2014-04-13 18:06:49 +02:00
|
|
|
-- @table naughty.notifications
|
2012-12-15 20:58:18 +01:00
|
|
|
naughty.notifications = { suspended = { } }
|
2009-05-08 09:01:14 +02:00
|
|
|
for s = 1, capi.screen.count() do
|
2012-12-15 20:58:18 +01:00
|
|
|
naughty.notifications[s] = {
|
2008-11-20 17:13:23 +01:00
|
|
|
top_left = {},
|
|
|
|
top_right = {},
|
|
|
|
bottom_left = {},
|
|
|
|
bottom_right = {},
|
|
|
|
}
|
|
|
|
end
|
2008-10-17 22:38:01 +02:00
|
|
|
|
2010-02-16 17:54:45 +01:00
|
|
|
--- Suspend notifications
|
2012-06-12 03:48:41 +02:00
|
|
|
function naughty.suspend()
|
2010-02-16 17:54:45 +01:00
|
|
|
suspended = true
|
|
|
|
end
|
|
|
|
|
|
|
|
--- Resume notifications
|
2012-06-12 03:48:41 +02:00
|
|
|
function naughty.resume()
|
2010-02-16 17:54:45 +01:00
|
|
|
suspended = false
|
2012-12-15 20:58:18 +01:00
|
|
|
for i, v in pairs(naughty.notifications.suspended) do
|
2010-02-16 17:54:45 +01:00
|
|
|
v.box.visible = true
|
|
|
|
if v.timer then v.timer:start() end
|
|
|
|
end
|
2012-12-15 20:58:18 +01:00
|
|
|
naughty.notifications.suspended = { }
|
2010-02-16 17:54:45 +01:00
|
|
|
end
|
|
|
|
|
2011-07-23 09:17:34 +02:00
|
|
|
--- Toggle notification state
|
2012-06-12 03:48:41 +02:00
|
|
|
function naughty.toggle()
|
2011-07-23 09:17:34 +02:00
|
|
|
if suspended then
|
2012-06-12 03:48:41 +02:00
|
|
|
naughty.resume()
|
2011-07-23 09:17:34 +02:00
|
|
|
else
|
2012-06-12 03:48:41 +02:00
|
|
|
naughty.suspend()
|
2011-07-23 09:17:34 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2009-01-08 12:26:00 +01:00
|
|
|
-- Evaluate desired position of the notification by index - internal
|
2008-10-17 22:38:01 +02:00
|
|
|
-- @param idx Index of the notification
|
|
|
|
-- @param position top_right | top_left | bottom_right | bottom_left
|
2008-11-15 17:55:38 +01:00
|
|
|
-- @param height Popup height
|
2008-11-19 03:16:44 +01:00
|
|
|
-- @param width Popup width (optional)
|
2009-05-08 13:08:09 +02:00
|
|
|
-- @return Absolute position and index in { x = X, y = Y, idx = I } table
|
2008-11-20 17:13:23 +01:00
|
|
|
local function get_offset(screen, position, idx, width, height)
|
2009-08-18 15:45:17 +02:00
|
|
|
local ws = capi.screen[screen].workarea
|
2008-10-17 22:38:01 +02:00
|
|
|
local v = {}
|
2012-12-15 20:58:18 +01:00
|
|
|
local idx = idx or #naughty.notifications[screen][position] + 1
|
|
|
|
local width = width or naughty.notifications[screen][position][idx].width
|
2008-10-17 22:38:01 +02:00
|
|
|
|
|
|
|
-- calculate x
|
|
|
|
if position:match("left") then
|
2012-06-12 03:48:41 +02:00
|
|
|
v.x = ws.x + naughty.config.padding
|
2008-10-17 22:38:01 +02:00
|
|
|
else
|
2012-06-12 03:48:41 +02:00
|
|
|
v.x = ws.x + ws.width - (width + naughty.config.padding)
|
2008-10-17 22:38:01 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
-- calculate existing popups' height
|
|
|
|
local existing = 0
|
|
|
|
for i = 1, idx-1, 1 do
|
2012-12-15 20:58:18 +01:00
|
|
|
existing = existing + naughty.notifications[screen][position][i].height + naughty.config.spacing
|
2008-10-17 22:38:01 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
-- calculate y
|
|
|
|
if position:match("top") then
|
2012-06-12 03:48:41 +02:00
|
|
|
v.y = ws.y + naughty.config.padding + existing
|
2008-10-17 22:38:01 +02:00
|
|
|
else
|
2012-06-12 03:48:41 +02:00
|
|
|
v.y = ws.y + ws.height - (naughty.config.padding + height + existing)
|
2008-10-17 22:38:01 +02:00
|
|
|
end
|
|
|
|
|
2008-10-23 18:47:43 +02:00
|
|
|
-- if positioned outside workarea, destroy oldest popup and recalculate
|
2008-11-15 17:55:38 +01:00
|
|
|
if v.y + height > ws.y + ws.height or v.y < ws.y then
|
2008-10-23 18:47:43 +02:00
|
|
|
idx = idx - 1
|
2012-12-15 20:58:18 +01:00
|
|
|
naughty.destroy(naughty.notifications[screen][position][1])
|
2008-11-20 17:13:23 +01:00
|
|
|
v = get_offset(screen, position, idx, width, height)
|
2008-10-23 18:47:43 +02:00
|
|
|
end
|
2009-05-08 13:08:09 +02:00
|
|
|
if not v.idx then v.idx = idx end
|
2008-10-23 18:47:43 +02:00
|
|
|
|
2008-10-17 22:38:01 +02:00
|
|
|
return v
|
|
|
|
end
|
|
|
|
|
2009-01-08 12:26:00 +01:00
|
|
|
-- Re-arrange notifications according to their position and index - internal
|
2008-10-17 22:38:01 +02:00
|
|
|
-- @return None
|
2008-11-20 17:13:23 +01:00
|
|
|
local function arrange(screen)
|
2012-12-15 20:58:18 +01:00
|
|
|
for p,pos in pairs(naughty.notifications[screen]) do
|
|
|
|
for i,notification in pairs(naughty.notifications[screen][p]) do
|
2008-11-20 17:13:23 +01:00
|
|
|
local offset = get_offset(screen, p, i, notification.width, notification.height)
|
2009-08-07 23:13:49 +02:00
|
|
|
notification.box:geometry({ x = offset.x, y = offset.y })
|
2009-05-08 13:08:09 +02:00
|
|
|
notification.idx = offset.idx
|
2008-10-17 22:38:01 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2010-02-16 20:16:17 +01:00
|
|
|
--- Destroy notification by notification object
|
2008-11-25 09:45:28 +01:00
|
|
|
-- @param notification Notification object to be destroyed
|
2015-01-10 17:32:27 +01:00
|
|
|
-- @param reason One of the reasons from notificationClosedReason
|
2008-10-17 22:38:01 +02:00
|
|
|
-- @return True if the popup was successfully destroyed, nil otherwise
|
2015-01-10 17:32:27 +01:00
|
|
|
function naughty.destroy(notification, reason)
|
2011-03-27 16:36:01 +02:00
|
|
|
if notification and notification.box.visible then
|
2010-02-16 17:54:45 +01:00
|
|
|
if suspended then
|
2012-12-15 20:58:18 +01:00
|
|
|
for k, v in pairs(naughty.notifications.suspended) do
|
2010-02-16 17:54:45 +01:00
|
|
|
if v.box == notification.box then
|
2012-12-15 20:58:18 +01:00
|
|
|
table.remove(naughty.notifications.suspended, k)
|
2010-02-16 17:54:45 +01:00
|
|
|
break
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2011-03-27 16:36:01 +02:00
|
|
|
local scr = notification.screen
|
2012-12-15 20:58:18 +01:00
|
|
|
table.remove(naughty.notifications[scr][notification.position], notification.idx)
|
2009-08-20 18:07:30 +02:00
|
|
|
if notification.timer then
|
|
|
|
notification.timer:stop()
|
|
|
|
end
|
2011-03-27 16:36:01 +02:00
|
|
|
notification.box.visible = false
|
2008-11-20 17:13:23 +01:00
|
|
|
arrange(scr)
|
2015-01-10 17:32:27 +01:00
|
|
|
if notification.destroy_cb and reason ~= naughty.notificationClosedReason.silent then
|
|
|
|
notification.destroy_cb(reason or naughty.notificationClosedReason.undefined)
|
|
|
|
end
|
2008-10-17 22:38:01 +02:00
|
|
|
return true
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2009-01-08 12:26:00 +01:00
|
|
|
-- Get notification by ID
|
2008-11-20 17:51:29 +01:00
|
|
|
-- @param id ID of the notification
|
|
|
|
-- @return notification object if it was found, nil otherwise
|
2015-01-10 21:06:30 +01:00
|
|
|
function naughty.getById(id)
|
2008-11-20 17:51:29 +01:00
|
|
|
-- iterate the notifications to get the notfications with the correct ID
|
2009-05-08 09:01:14 +02:00
|
|
|
for s = 1, capi.screen.count() do
|
2012-12-15 20:58:18 +01:00
|
|
|
for p,pos in pairs(naughty.notifications[s]) do
|
|
|
|
for i,notification in pairs(naughty.notifications[s][p]) do
|
2008-11-20 17:51:29 +01:00
|
|
|
if notification.id == id then
|
|
|
|
return notification
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2009-05-06 18:39:56 +02:00
|
|
|
--- Create notification. args is a dictionary of (optional) arguments.
|
|
|
|
-- @param text Text of the notification. Default: ''
|
|
|
|
-- @param title Title of the notification. Default: nil
|
|
|
|
-- @param timeout Time in seconds after which popup expires.
|
|
|
|
-- Set 0 for no timeout. Default: 5
|
|
|
|
-- @param hover_timeout Delay in seconds after which hovered popup disappears.
|
|
|
|
-- Default: nil
|
|
|
|
-- @param screen Target screen for the notification. Default: 1
|
|
|
|
-- @param position Corner of the workarea displaying the popups.
|
|
|
|
-- Values: "top_right" (default), "top_left", "bottom_left", "bottom_right".
|
|
|
|
-- @param ontop Boolean forcing popups to display on top. Default: true
|
|
|
|
-- @param height Popup height. Default: nil (auto)
|
|
|
|
-- @param width Popup width. Default: nil (auto)
|
|
|
|
-- @param font Notification font. Default: beautiful.font or awesome.font
|
|
|
|
-- @param icon Path to icon. Default: nil
|
|
|
|
-- @param icon_size Desired icon size in px. Default: nil
|
|
|
|
-- @param fg Foreground color. Default: beautiful.fg_focus or '#ffffff'
|
|
|
|
-- @param bg Background color. Default: beautiful.bg_focus or '#535d6c'
|
|
|
|
-- @param border_width Border width. Default: 1
|
|
|
|
-- @param border_color Border color.
|
|
|
|
-- Default: beautiful.border_focus or '#535d6c'
|
|
|
|
-- @param run Function to run on left click. Default: nil
|
2015-01-10 17:32:27 +01:00
|
|
|
-- @param destroy Function to run when notification is destroyed. Default: nil
|
2009-05-06 18:39:56 +02:00
|
|
|
-- @param preset Table with any of the above parameters. Note: Any parameters
|
|
|
|
-- specified directly in args will override ones defined in the preset.
|
2008-11-20 17:51:29 +01:00
|
|
|
-- @param replaces_id Replace the notification with the given ID
|
2009-05-06 18:39:56 +02:00
|
|
|
-- @param callback function that will be called with all arguments
|
|
|
|
-- the notification will only be displayed if the function returns true
|
|
|
|
-- note: this function is only relevant to notifications sent via dbus
|
2015-01-10 17:48:32 +01:00
|
|
|
-- @param actions mapping that maps a string to a callback when this action is
|
|
|
|
-- selected
|
2009-05-06 18:39:56 +02:00
|
|
|
-- @usage naughty.notify({ title = "Achtung!", text = "You're idling", timeout = 0 })
|
2008-11-25 09:45:28 +01:00
|
|
|
-- @return The notification object
|
2012-06-12 03:48:41 +02:00
|
|
|
function naughty.notify(args)
|
|
|
|
if naughty.config.notify_callback then
|
|
|
|
args = naughty.config.notify_callback(args)
|
2011-01-28 01:37:47 +01:00
|
|
|
if not args then return end
|
|
|
|
end
|
|
|
|
|
2008-11-15 17:55:38 +01:00
|
|
|
-- gather variables together
|
2012-06-12 03:48:41 +02:00
|
|
|
local preset = util.table.join(naughty.config.defaults or {},
|
|
|
|
args.preset or naughty.config.presets.normal or {})
|
2012-05-28 19:16:10 +02:00
|
|
|
local timeout = args.timeout or preset.timeout
|
2009-05-06 18:39:56 +02:00
|
|
|
local icon = args.icon or preset.icon
|
|
|
|
local icon_size = args.icon_size or preset.icon_size
|
2012-05-28 19:16:10 +02:00
|
|
|
local text = args.text or preset.text
|
2009-05-06 18:39:56 +02:00
|
|
|
local title = args.title or preset.title
|
2012-05-28 19:16:10 +02:00
|
|
|
local screen = args.screen or preset.screen
|
|
|
|
local ontop = args.ontop or preset.ontop
|
2009-05-06 18:39:56 +02:00
|
|
|
local width = args.width or preset.width
|
|
|
|
local height = args.height or preset.height
|
|
|
|
local hover_timeout = args.hover_timeout or preset.hover_timeout
|
|
|
|
local opacity = args.opacity or preset.opacity
|
2012-05-28 19:16:10 +02:00
|
|
|
local margin = args.margin or preset.margin
|
|
|
|
local border_width = args.border_width or preset.border_width
|
|
|
|
local position = args.position or preset.position
|
2014-12-31 14:28:46 +01:00
|
|
|
local actions = args.actions
|
2015-01-10 17:32:27 +01:00
|
|
|
local destroy_cb = args.destroy
|
2013-03-26 09:16:58 +01:00
|
|
|
local escape_pattern = "[<>&]"
|
|
|
|
local escape_subs = { ['<'] = "<", ['>'] = ">", ['&'] = "&" }
|
2008-10-17 22:38:01 +02:00
|
|
|
|
2008-11-21 01:43:18 +01:00
|
|
|
-- beautiful
|
|
|
|
local beautiful = bt.get()
|
2009-06-06 12:28:25 +02:00
|
|
|
local font = args.font or preset.font or beautiful.font or capi.awesome.font
|
2009-05-06 18:39:56 +02:00
|
|
|
local fg = args.fg or preset.fg or beautiful.fg_normal or '#ffffff'
|
|
|
|
local bg = args.bg or preset.bg or beautiful.bg_normal or '#535d6c'
|
|
|
|
local border_color = args.border_color or preset.border_color or beautiful.bg_focus or '#535d6c'
|
2015-01-10 17:32:27 +01:00
|
|
|
local notification = { screen = screen, destroy_cb = destroy_cb }
|
2008-11-20 17:51:29 +01:00
|
|
|
|
|
|
|
-- replace notification if needed
|
|
|
|
if args.replaces_id then
|
2015-01-10 21:06:30 +01:00
|
|
|
local obj = naughty.getById(args.replaces_id)
|
2008-11-20 17:51:29 +01:00
|
|
|
if obj then
|
|
|
|
-- destroy this and ...
|
2015-01-10 17:32:27 +01:00
|
|
|
naughty.destroy(obj, naughty.notificationClosedReason.silent)
|
2008-11-20 17:51:29 +01:00
|
|
|
end
|
|
|
|
-- ... may use its ID
|
2011-09-07 21:41:47 +02:00
|
|
|
if args.replaces_id <= counter then
|
2008-11-20 17:51:29 +01:00
|
|
|
notification.id = args.replaces_id
|
|
|
|
else
|
|
|
|
counter = counter + 1
|
|
|
|
notification.id = counter
|
|
|
|
end
|
|
|
|
else
|
|
|
|
-- get a brand new ID
|
|
|
|
counter = counter + 1
|
|
|
|
notification.id = counter
|
|
|
|
end
|
|
|
|
|
2009-05-06 18:39:56 +02:00
|
|
|
notification.position = position
|
2008-10-17 22:38:01 +02:00
|
|
|
|
2009-05-06 18:39:56 +02:00
|
|
|
if title then title = title .. "\n" else title = "" end
|
2008-10-19 20:58:50 +02:00
|
|
|
|
2008-11-15 17:55:38 +01:00
|
|
|
-- hook destroy
|
2014-12-31 14:28:46 +01:00
|
|
|
local die = function (reason)
|
2015-01-10 17:32:27 +01:00
|
|
|
naughty.destroy(notification, reason)
|
2014-12-31 14:28:46 +01:00
|
|
|
end
|
2009-08-20 18:07:30 +02:00
|
|
|
if timeout > 0 then
|
2014-12-06 16:44:04 +01:00
|
|
|
local timer_die = timer { timeout = timeout }
|
2015-01-10 17:32:27 +01:00
|
|
|
timer_die:connect_signal("timeout", function() die(naughty.notificationClosedReason.expired) end)
|
2010-02-16 17:54:45 +01:00
|
|
|
if not suspended then
|
|
|
|
timer_die:start()
|
|
|
|
end
|
2009-08-20 18:07:30 +02:00
|
|
|
notification.timer = timer_die
|
|
|
|
end
|
2008-11-05 03:18:01 +01:00
|
|
|
notification.die = die
|
2008-11-04 20:35:18 +01:00
|
|
|
|
2008-11-25 06:45:40 +01:00
|
|
|
local run = function ()
|
2008-12-03 23:52:59 +01:00
|
|
|
if args.run then
|
|
|
|
args.run(notification)
|
|
|
|
else
|
2015-01-10 17:32:27 +01:00
|
|
|
die(naughty.notificationClosedReason.dismissedByUser)
|
2008-12-03 23:52:59 +01:00
|
|
|
end
|
2008-11-25 06:45:40 +01:00
|
|
|
end
|
2008-11-05 03:03:28 +01:00
|
|
|
|
2008-11-04 20:35:18 +01:00
|
|
|
local hover_destroy = function ()
|
2009-08-20 18:07:30 +02:00
|
|
|
if hover_timeout == 0 then
|
2015-01-10 17:32:27 +01:00
|
|
|
die(naughty.notificationClosedReason.expired)
|
2009-08-25 01:19:46 +02:00
|
|
|
else
|
|
|
|
if notification.timer then notification.timer:stop() end
|
2014-12-06 16:44:04 +01:00
|
|
|
notification.timer = timer { timeout = hover_timeout }
|
2015-01-10 17:32:27 +01:00
|
|
|
notification.timer:connect_signal("timeout", function() die(naughty.notificationClosedReason.expired) end)
|
2009-08-25 01:19:46 +02:00
|
|
|
notification.timer:start()
|
2009-08-20 18:07:30 +02:00
|
|
|
end
|
2008-11-04 20:35:18 +01:00
|
|
|
end
|
|
|
|
|
2008-11-15 17:55:38 +01:00
|
|
|
-- create textbox
|
2010-10-06 14:19:20 +02:00
|
|
|
local textbox = wibox.widget.textbox()
|
|
|
|
local marginbox = wibox.layout.margin()
|
|
|
|
marginbox:set_margins(margin)
|
|
|
|
marginbox:set_widget(textbox)
|
2011-04-14 07:04:48 +02:00
|
|
|
textbox:set_valign("middle")
|
|
|
|
textbox:set_font(font)
|
2008-10-17 22:38:01 +02:00
|
|
|
|
2011-01-14 16:16:04 +01:00
|
|
|
local function setMarkup(pattern, replacements)
|
2013-03-26 09:16:58 +01:00
|
|
|
textbox:set_markup(string.format('<b>%s</b>%s', title, text:gsub(pattern, replacements)))
|
2010-07-16 19:35:51 +02:00
|
|
|
end
|
2011-01-14 16:16:04 +01:00
|
|
|
local function setText()
|
2011-01-14 19:06:54 +01:00
|
|
|
textbox:set_text(string.format('%s %s', title, text))
|
2011-01-14 16:16:04 +01:00
|
|
|
end
|
2010-07-16 19:35:51 +02:00
|
|
|
|
2013-03-26 09:16:58 +01:00
|
|
|
-- Since the title cannot contain markup, it must be escaped first so that
|
|
|
|
-- it is not interpreted by Pango later.
|
|
|
|
title = title:gsub(escape_pattern, escape_subs)
|
|
|
|
-- Try to set the text while only interpreting <br>.
|
2010-07-16 19:35:51 +02:00
|
|
|
-- (Setting a textbox' .text to an invalid pattern throws a lua error)
|
2011-01-14 16:16:04 +01:00
|
|
|
if not pcall(setMarkup, "<br.->", "\n") then
|
2010-07-16 19:35:51 +02:00
|
|
|
-- That failed, escape everything which might cause an error from pango
|
2013-03-26 09:16:58 +01:00
|
|
|
if not pcall(setMarkup, escape_pattern, escape_subs) then
|
2011-01-14 16:16:04 +01:00
|
|
|
-- Ok, just ignore all pango markup. If this fails, we got some invalid utf8
|
|
|
|
if not pcall(setText) then
|
|
|
|
textbox:set_markup("<i><Invalid markup or UTF8, cannot display message></i>")
|
|
|
|
end
|
2010-07-30 14:15:42 +02:00
|
|
|
end
|
2010-07-16 19:35:51 +02:00
|
|
|
end
|
|
|
|
|
2014-12-31 14:28:46 +01:00
|
|
|
local actionslayout = wibox.layout.fixed.vertical()
|
|
|
|
local actions_max_width = 0
|
|
|
|
local actions_total_height = 0
|
|
|
|
if actions then
|
2015-01-10 17:48:32 +01:00
|
|
|
for action, callback in pairs(actions) do
|
|
|
|
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 and width
|
|
|
|
local w, h = actiontextbox:fit(-1, -1)
|
|
|
|
local height = h + 2 * margin
|
|
|
|
local width = w + 2 * margin
|
|
|
|
|
|
|
|
actionmarginbox:buttons(util.table.join(
|
|
|
|
button({ }, 1, callback),
|
|
|
|
button({ }, 3, callback)
|
|
|
|
))
|
|
|
|
actionslayout:add(actionmarginbox)
|
|
|
|
|
|
|
|
actions_total_height = actions_total_height + height
|
|
|
|
if actions_max_width < width then
|
|
|
|
actions_max_width = width
|
2014-12-31 14:28:46 +01:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2008-11-15 17:55:38 +01:00
|
|
|
-- create iconbox
|
2008-10-17 22:38:01 +02:00
|
|
|
local iconbox = nil
|
2010-10-06 14:19:20 +02:00
|
|
|
local iconmargin = nil
|
|
|
|
local icon_w, icon_h = 0, 0
|
2008-10-17 22:38:01 +02:00
|
|
|
if icon then
|
2014-04-13 12:22:24 +02:00
|
|
|
-- Is this really an URI instead of a path?
|
|
|
|
if type(icon) == "string" and string.sub(icon, 1, 7) == "file://" then
|
|
|
|
icon = string.sub(icon, 8)
|
|
|
|
end
|
2008-11-22 18:24:33 +01:00
|
|
|
-- try to guess icon if the provided one is non-existent/readable
|
2009-05-08 09:01:14 +02:00
|
|
|
if type(icon) == "string" and not util.file_readable(icon) then
|
2013-03-10 10:57:49 +01:00
|
|
|
icon = util.geticonpath(icon, naughty.config.icon_formats, naughty.config.icon_dirs, icon_size) or icon
|
|
|
|
end
|
|
|
|
|
|
|
|
-- is the icon file readable?
|
2014-04-09 21:49:27 +02:00
|
|
|
local success, res = pcall(function() return surface.load_uncached(icon) end)
|
2013-03-10 10:57:49 +01:00
|
|
|
if success then
|
|
|
|
icon = res
|
|
|
|
else
|
|
|
|
io.stderr:write(string.format("naughty: Couldn't load image '%s': %s\n", tostring(icon), res))
|
|
|
|
icon = nil
|
2009-03-11 17:11:06 +01:00
|
|
|
end
|
2008-11-22 18:24:33 +01:00
|
|
|
|
|
|
|
-- if we have an icon, use it
|
|
|
|
if icon then
|
2010-10-06 14:19:20 +02:00
|
|
|
iconbox = wibox.widget.imagebox()
|
2010-10-08 17:22:00 +02:00
|
|
|
iconmargin = wibox.layout.margin(iconbox, margin, margin, margin, margin)
|
2008-11-22 18:24:33 +01:00
|
|
|
if icon_size then
|
2012-05-27 19:20:34 +02:00
|
|
|
local scaled = cairo.ImageSurface(cairo.Format.ARGB32, icon_size, icon_size)
|
|
|
|
local cr = cairo.Context(scaled)
|
2013-03-10 10:57:49 +01:00
|
|
|
cr:scale(icon_size / icon:get_height(), icon_size / icon:get_width())
|
|
|
|
cr:set_source_surface(icon, 0, 0)
|
2010-10-06 14:19:20 +02:00
|
|
|
cr:paint()
|
2013-03-10 10:57:49 +01:00
|
|
|
icon = scaled
|
2008-11-22 18:24:33 +01:00
|
|
|
end
|
2010-10-06 14:19:20 +02:00
|
|
|
iconbox:set_resize(false)
|
2013-03-10 10:57:49 +01:00
|
|
|
iconbox:set_image(icon)
|
|
|
|
icon_w = icon:get_width()
|
|
|
|
icon_h = icon:get_height()
|
2008-11-04 21:09:28 +01:00
|
|
|
end
|
2008-10-17 22:38:01 +02:00
|
|
|
end
|
|
|
|
|
2008-11-15 17:55:38 +01:00
|
|
|
-- create container wibox
|
2010-10-06 14:19:20 +02:00
|
|
|
notification.box = wibox({ fg = fg,
|
|
|
|
bg = bg,
|
|
|
|
border_color = border_color,
|
|
|
|
border_width = border_width,
|
|
|
|
type = "notification" })
|
2008-11-15 17:55:38 +01:00
|
|
|
|
2009-10-09 20:39:55 +02:00
|
|
|
if hover_timeout then notification.box:connect_signal("mouse::enter", hover_destroy) end
|
2009-08-17 15:43:32 +02:00
|
|
|
|
2009-05-06 20:43:28 +02:00
|
|
|
-- calculate the height
|
|
|
|
if not height then
|
2010-10-06 14:19:20 +02:00
|
|
|
local w, h = textbox:fit(-1, -1)
|
|
|
|
if iconbox and icon_h + 2 * margin > h + 2 * margin then
|
|
|
|
height = icon_h + 2 * margin
|
2009-05-05 20:38:15 +02:00
|
|
|
else
|
2010-10-06 14:19:20 +02:00
|
|
|
height = h + 2 * margin
|
2009-05-05 20:38:15 +02:00
|
|
|
end
|
|
|
|
end
|
2009-05-06 20:43:28 +02:00
|
|
|
|
2014-12-31 14:28:46 +01:00
|
|
|
height = height + actions_total_height
|
|
|
|
|
2009-05-06 20:43:28 +02:00
|
|
|
-- calculate the width
|
|
|
|
if not width then
|
2010-10-06 14:19:20 +02:00
|
|
|
local w, h = textbox:fit(-1, -1)
|
|
|
|
width = w + (iconbox and icon_w + 2 * margin or 0) + 2 * margin
|
2009-05-05 20:38:15 +02:00
|
|
|
end
|
2009-05-06 20:43:28 +02:00
|
|
|
|
2014-12-31 14:28:46 +01:00
|
|
|
if width < actions_max_width then
|
|
|
|
width = actions_max_width
|
|
|
|
end
|
|
|
|
|
2009-05-06 20:43:28 +02:00
|
|
|
-- crop to workarea size if too big
|
2009-08-18 15:45:17 +02:00
|
|
|
local workarea = capi.screen[screen].workarea
|
2012-06-12 03:48:41 +02:00
|
|
|
if width > workarea.width - 2 * (border_width or 0) - 2 * (naughty.config.padding or 0) then
|
|
|
|
width = workarea.width - 2 * (border_width or 0) - 2 * (naughty.config.padding or 0)
|
2009-05-05 20:38:15 +02:00
|
|
|
end
|
2012-06-12 03:48:41 +02:00
|
|
|
if height > workarea.height - 2 * (border_width or 0) - 2 * (naughty.config.padding or 0) then
|
|
|
|
height = workarea.height - 2 * (border_width or 0) - 2 * (naughty.config.padding or 0)
|
2009-05-05 20:38:15 +02:00
|
|
|
end
|
|
|
|
|
2009-05-06 20:43:28 +02:00
|
|
|
-- set size in notification object
|
|
|
|
notification.height = height + 2 * (border_width or 0)
|
|
|
|
notification.width = width + 2 * (border_width or 0)
|
|
|
|
|
|
|
|
-- position the wibox
|
2009-07-29 14:43:00 +02:00
|
|
|
local offset = get_offset(screen, notification.position, nil, notification.width, notification.height)
|
2009-03-10 20:25:56 +01:00
|
|
|
notification.box.ontop = ontop
|
2009-07-29 14:43:00 +02:00
|
|
|
notification.box:geometry({ width = width,
|
|
|
|
height = height,
|
2008-11-15 17:55:38 +01:00
|
|
|
x = offset.x,
|
|
|
|
y = offset.y })
|
2009-04-10 23:18:51 +02:00
|
|
|
notification.box.opacity = opacity
|
2011-03-27 16:36:01 +02:00
|
|
|
notification.box.visible = true
|
2009-05-08 13:08:09 +02:00
|
|
|
notification.idx = offset.idx
|
2008-11-15 17:55:38 +01:00
|
|
|
|
|
|
|
-- populate widgets
|
2010-10-06 14:19:20 +02:00
|
|
|
local layout = wibox.layout.fixed.horizontal()
|
|
|
|
if iconmargin then
|
|
|
|
layout:add(iconmargin)
|
2009-10-26 23:31:20 +01:00
|
|
|
end
|
2010-10-06 14:19:20 +02:00
|
|
|
layout:add(marginbox)
|
2014-12-31 14:28:46 +01:00
|
|
|
|
|
|
|
local completelayout = wibox.layout.fixed.vertical()
|
|
|
|
completelayout:add(layout)
|
|
|
|
completelayout:add(actionslayout)
|
|
|
|
notification.box:set_widget(completelayout)
|
2010-10-06 14:19:20 +02:00
|
|
|
|
|
|
|
-- Setup the mouse events
|
2014-12-31 14:28:46 +01:00
|
|
|
layout:buttons(util.table.join(button({ }, 1, run),
|
|
|
|
button({ }, 3, function()
|
2015-01-10 17:32:27 +01:00
|
|
|
die(naughty.notificationClosedReason.dismissedByUser)
|
2014-12-31 14:28:46 +01:00
|
|
|
end)))
|
2008-10-17 22:38:01 +02:00
|
|
|
|
|
|
|
-- insert the notification to the table
|
2012-12-15 20:58:18 +01:00
|
|
|
table.insert(naughty.notifications[screen][notification.position], notification)
|
2008-10-17 22:38:01 +02:00
|
|
|
|
2010-02-16 17:54:45 +01:00
|
|
|
if suspended then
|
|
|
|
notification.box.visible = false
|
2012-12-15 20:58:18 +01:00
|
|
|
table.insert(naughty.notifications.suspended, notification)
|
2010-02-16 17:54:45 +01:00
|
|
|
end
|
|
|
|
|
2008-11-25 09:45:28 +01:00
|
|
|
-- return the notification
|
|
|
|
return notification
|
|
|
|
end
|
2008-11-20 17:51:29 +01:00
|
|
|
|
2012-06-12 03:48:41 +02:00
|
|
|
return naughty
|
|
|
|
|
2011-09-11 16:50:01 +02:00
|
|
|
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|