transient.lua 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  1. -- @author cedlemo
  2. -- Modifications based on original work from Uli Schlachter
  3. -- @copyright 2010 Uli Schlachter
  4. local capi = {
  5. drawin = drawin,
  6. root = root,
  7. awesome = awesome,
  8. screen = screen,
  9. mouse = mouse
  10. }
  11. local setmetatable = setmetatable
  12. local pairs = pairs
  13. local type = type
  14. local table = table
  15. local string_format = string.format
  16. local color = require("gears.color")
  17. local object = require("gears.object")
  18. local sort = require("gears.sort")
  19. local beautiful = require("beautiful")
  20. local surface = require("gears.surface")
  21. local cairo = require("lgi").cairo
  22. ---Wibox with timeout
  23. --@module blingbling.transient
  24. --- This provides widget box windows. Every transient can also be used as if it were
  25. -- a drawin. All drawin functions and properties are also available on transientes!
  26. -- transient
  27. local transient = { mt = {} }
  28. transient.layout = require("wibox.layout")
  29. transient.widget = require("wibox.widget")
  30. transient.drawable = require("wibox.drawable")
  31. --- Set the widget that the transient displays
  32. function transient:set_widget(widget)
  33. self._drawable:set_widget(widget)
  34. end
  35. --- Set the background of the transient
  36. -- @param c The background to use. This must either be a cairo pattern object,
  37. -- nil or a string that gears.color() understands.
  38. function transient:set_bg(c)
  39. self._drawable:set_bg(c)
  40. end
  41. --- Set the foreground of the transient
  42. -- @param c The foreground to use. This must either be a cairo pattern object,
  43. -- nil or a string that gears.color() understands.
  44. function transient:set_fg(c)
  45. self._drawable:set_fg(c)
  46. end
  47. for _, k in pairs{ "buttons", "struts", "geometry", "get_xproperty", "set_xproperty" } do
  48. transient[k] = function(self, ...)
  49. return self.drawin[k](self.drawin, ...)
  50. end
  51. end
  52. local function setup_signals(_transient)
  53. local w = _transient.drawin
  54. local function clone_signal(name)
  55. _transient:add_signal(name)
  56. -- When "name" is emitted on transient.drawin, also emit it on transient
  57. w:connect_signal(name, function(_, ...)
  58. _transient:emit_signal(name, ...)
  59. end)
  60. end
  61. clone_signal("property::border_color")
  62. clone_signal("property::border_width")
  63. clone_signal("property::height")
  64. clone_signal("property::ontop")
  65. clone_signal("property::opacity")
  66. clone_signal("property::struts")
  67. clone_signal("property::visible")
  68. clone_signal("property::width")
  69. clone_signal("property::x")
  70. clone_signal("property::y")
  71. local d = _transient._drawable
  72. local function clone_signal(name)
  73. _transient:add_signal(name)
  74. -- When "name" is emitted on transient.drawin, also emit it on transient
  75. d:connect_signal(name, function(_, ...)
  76. _transient:emit_signal(name, ...)
  77. end)
  78. end
  79. clone_signal("property::surface")
  80. end
  81. --- Show the transient window according to the timeout set when creating the
  82. -- transient window
  83. function transient:show()
  84. -- self:top_left()
  85. if not self.visible then
  86. self.visible = true
  87. local mytimer = timer({ timeout = self.timeout })
  88. mytimer:connect_signal("timeout", function ()
  89. if self.visible == true then
  90. self.visible=false
  91. mytimer:stop()
  92. end
  93. end)
  94. mytimer:start()
  95. end
  96. end
  97. function transient:top_left()
  98. local current_screen = mouse.screen
  99. local geometry
  100. if self.parent then
  101. geometry = self.parent:geometry()
  102. else
  103. geometry = screen[current_screen].workarea
  104. end
  105. self:geometry({x=geometry.x, y=geometry.y})
  106. end
  107. function transient:top_center()
  108. local current_screen = mouse.screen
  109. local geometry
  110. if self.parent then
  111. geometry = self.parent:geometry()
  112. else
  113. geometry = screen[current_screen].workarea
  114. end
  115. local w = self.width
  116. local h = self.height
  117. local x = geometry.x + geometry.width/2 - w/2
  118. self:geometry({x=x, y=geometry.y})
  119. end
  120. function transient:top_right()
  121. local current_screen = mouse.screen
  122. local geometry
  123. if self.parent then
  124. geometry = self.parent:geometry()
  125. else
  126. geometry = screen[current_screen].workarea
  127. end
  128. local w = self.width
  129. local h = self.height
  130. local x = geometry.x + geometry.width - w
  131. self:geometry({x=x, y=geometry.y})
  132. end
  133. function transient:center()
  134. local current_screen = mouse.screen
  135. local geometry
  136. if self.parent then
  137. geometry = self.parent:geometry()
  138. else
  139. geometry = screen[current_screen].workarea
  140. end
  141. local w = self.width
  142. local h = self.height
  143. local x,y = 0
  144. x = ((geometry.width /2) + geometry.x) - w/2
  145. y = ((geometry.height /2) + geometry.y) - h/2
  146. self:geometry({x=x, y=y})
  147. end
  148. function transient:bottom_left()
  149. local current_screen = mouse.screen
  150. local geometry
  151. if self.parent then
  152. geometry = self.parent:geometry()
  153. else
  154. geometry = screen[current_screen].workarea
  155. end
  156. local w = self.width
  157. local h = self.height
  158. local x = geometry.x
  159. local y = geometry.y + geometry.height - h
  160. self:geometry({x=x, y=y})
  161. end
  162. function transient:bottom_center()
  163. local current_screen = mouse.screen
  164. local geometry
  165. if self.parent then
  166. geometry = self.parent:geometry()
  167. else
  168. geometry = screen[current_screen].workarea
  169. end
  170. local w = self.width
  171. local h = self.height
  172. local x = geometry.x + geometry.width/2 - w/2
  173. local y = geometry.y + geometry.height - h
  174. self:geometry({x=x, y=y})
  175. end
  176. function transient:bottom_right()
  177. local current_screen = mouse.screen
  178. local geometry
  179. if self.parent then
  180. geometry = self.parent:geometry()
  181. else
  182. geometry = screen[current_screen].workarea
  183. end
  184. local w = self.width
  185. local h = self.height
  186. local x = geometry.x + geometry.width - w
  187. local y = geometry.y + geometry.height - h
  188. self:geometry({x=x, y=y})
  189. end
  190. function transient:center_right()
  191. local current_screen = mouse.screen
  192. local geometry
  193. if self.parent then
  194. geometry = self.parent:geometry()
  195. else
  196. geometry = screen[current_screen].workarea
  197. end
  198. local w = self.width
  199. local h = self.height
  200. local x = geometry.x + geometry.width - w
  201. local y = geometry.y + geometry.height/2 - h/2
  202. self:geometry({x=x, y=y})
  203. end
  204. function transient:center_left()
  205. local current_screen = mouse.screen
  206. local geometry
  207. if self.parent then
  208. geometry = self.parent:geometry()
  209. else
  210. geometry = screen[current_screen].workarea
  211. end
  212. local w = self.width
  213. local h = self.height
  214. local x = geometry.x
  215. local y = geometry.y + geometry.height/2 - h/2
  216. self:geometry({x=x, y=y})
  217. end
  218. local function new(args)
  219. local ret = object()
  220. local w = capi.drawin(args)
  221. ret.drawin = w
  222. ret._drawable = transient.drawable(w.drawable, ret)
  223. if args.parent then
  224. ret.parent = args.parent
  225. end
  226. if args.timeout then
  227. ret.timeout = args.timeout
  228. else
  229. ret.timeout = 2
  230. end
  231. for k, v in pairs(transient) do
  232. if type(v) == "function" then
  233. ret[k] = v
  234. end
  235. end
  236. setup_signals(ret)
  237. ret.draw = ret._drawable.draw
  238. ret.widget_at = function(_, widget, x, y, width, height)
  239. return ret._drawable:widget_at(widget, x, y, width, height)
  240. end
  241. -- Set the default background
  242. ret:set_bg(args.bg or beautiful.bg_normal)
  243. ret:set_fg(args.fg or beautiful.fg_normal)
  244. -- Make sure the transient is drawn at least once
  245. ret.draw()
  246. -- Redirect all non-existing indexes to the "real" drawin
  247. setmetatable(ret, {
  248. __index = w,
  249. __newindex = w
  250. })
  251. ret.visible=false
  252. -- if args.position then
  253. -- if position == "center" then
  254. -- self:center()
  255. -- elseif position == "top-left" then
  256. -- self:top_left()
  257. -- elseif position == "top-center" then
  258. -- self:top_center()
  259. -- elseif position == "top-right" then
  260. -- self:top_right()
  261. -- elseif position == "bottom-left" then
  262. -- self:bottom_left()
  263. -- elseif position == "bottom-center" then
  264. -- self:bottom_center()
  265. -- elseif position == "bottom-right" then
  266. -- self:bottom_right()
  267. -- end
  268. -- end
  269. return ret
  270. end
  271. --- Redraw a transient. You should never have to call this explicitely because it is
  272. -- automatically called when needed.
  273. -- @param transient
  274. -- @name draw
  275. -- @class function
  276. --- Widget box object.
  277. -- Every transient "inherits" from a drawin and you can use all of drawin's
  278. -- functions directly on this as well. When creating a transient, you can specify a
  279. -- "fg" and a "bg" color as keys in the table that is passed to the constructor.
  280. -- All other arguments will be passed to drawin's constructor.
  281. -- @class table
  282. -- @name drawin
  283. function transient.mt:__call(...)
  284. return new(...)
  285. end
  286. return setmetatable(transient, transient.mt)
  287. -- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80