Reno is the second iteration of the AWMTK-powered AwesomeWM config.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

273 lines
11 KiB

2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
  1. -- This file is part of Reno desktop.
  2. --
  3. -- Reno desktop is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
  4. --
  5. -- Reno desktop is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  6. --
  7. -- You should have received a copy of the GNU General Public License along with Reno desktop. If not, see <https://www.gnu.org/licenses/>.
  8. -- Dismal - not your average run prompt
  9. -- Reference implementation of a generic widget
  10. local awmtk2 = require("awmtk2")
  11. local wibox = require("wibox")
  12. local gears = require("gears")
  13. local awful = require("awful")
  14. local ask = require("asckey")
  15. local xdg_search = function(name,rlimit,sorting_method)
  16. local ranked_results = {}
  17. if sorting_method == "usage" then
  18. local filter = {}
  19. local keys = {}
  20. for k,v in pairs(xdg.apps) do
  21. if not v.count then
  22. v.count = 0
  23. end
  24. if v.name:lower():find(name,nil,true) then
  25. if not filter[v.count] then
  26. table.insert(keys, v.count)
  27. filter[v.count] = {}
  28. end
  29. table.insert(filter[v.count],{k,v})
  30. end
  31. end
  32. table.sort(keys,function(a,b) return a > b end)
  33. local count = 0
  34. local exit = false
  35. for k = 1,rlimit do
  36. local i = keys[k]
  37. if not filter[i] then
  38. break
  39. end
  40. for _,v in pairs(filter[i]) do
  41. table.insert(ranked_results, v)
  42. count = count + 1
  43. if count >= rlimit then
  44. exit = true
  45. break
  46. end
  47. end
  48. if exit == true then
  49. break
  50. end
  51. end
  52. elseif sorting_method == "recent" then
  53. local most_recent = 0
  54. for k,v in pairs(xdg.apps) do
  55. if v.name:lower():find(name,nil,true) and v.atime and v.atime >= most_recent then
  56. most_recent = v.atime
  57. table.insert(ranked_results,1,{k,v})
  58. end
  59. if #ranked_results > rlimit then
  60. table.remove(ranked_results,rlimit+1)
  61. end
  62. end
  63. end
  64. return ranked_results
  65. end
  66. return function(args)
  67. local style = awmtk2.create_style("dismal",
  68. awmtk2.generic.popup,args.style,args.vertical)
  69. local templates = awmtk2.create_template_lib("dismal",awmtk2.templates,args.templates)
  70. local t = awmtk2.build_templates(templates,style,args.vertical)
  71. local dismal = awful.popup(t.popup({
  72. id = "dismal_root",
  73. layout = wibox.layout.fixed.horizontal,
  74. spacing = style.container.spacing
  75. }))
  76. local available_positions = {
  77. top_left = awful.placement.top_left,
  78. top_right = awful.placement.top_right,
  79. bottom_left = awful.placement.bottom_left,
  80. bottom_right = awful.placement.bottom_right,
  81. left = awful.placement.left,
  82. right = awful.placement.right,
  83. top = awful.placement.top,
  84. bottom = awful.placement.bottom,
  85. centered = awful.placement.centered
  86. }
  87. local honor_workarea = true
  88. if (args.ignore_wibars) then
  89. honor_workarea = false
  90. end
  91. local popup_position = (args.pos and available_positions[args.pos])
  92. or available_positions["top_left"]
  93. local button_cache = gears.cache(function(name,exec,description,icon,key)
  94. -- beacause apparently cache doesn't allow nil values
  95. if icon == "" then icon = nil end
  96. -- contents of our button
  97. local widget = wibox.widget(t.button(t.article({
  98. icon = icon,
  99. resize = true,
  100. title = name,
  101. description = description,
  102. icon_size = (style.button.height and
  103. (style.button.height-style.button.margins)) or
  104. (34-style.button.margins)
  105. }),{
  106. forced_height = style.button.height or 30
  107. }))
  108. local exec = exec:gsub("%%%w","")
  109. -- theme-declared highlight function, because why not
  110. -- maybe you'd like to add duck noises to button presses idk.
  111. widget:connect_signal("button::press",style.button.onpress)
  112. widget:connect_signal("button::release",style.button.onrelease)
  113. widget:connect_signal("mouses::leave",style.button.onrelease)
  114. local bump = function()
  115. if not xdg.apps[key].count then
  116. xdg.apps[key].count = 0
  117. end
  118. xdg.apps[key].count = xdg.apps[key].count + 1
  119. xdg.apps[key].atime = os.time()
  120. end
  121. widget:buttons(
  122. gears.table.join(
  123. awful.button({},1,function()
  124. awful.spawn(exec)
  125. dismal.visible = false
  126. -- i know it's deprecated, you literally give me no option
  127. awful.keygrabber.stop()
  128. bump()
  129. end),
  130. awful.button({"Control"},1,function()
  131. awful.spawn({global.terminal,"-e",exec})
  132. dismal.visible = false
  133. awful.keygrabber.stop()
  134. bump()
  135. end),
  136. awful.button({},3,function()
  137. awful.spawn(exec)
  138. bump()
  139. end),
  140. awful.button({"Control"},3,function()
  141. awful.spawn({global.terminal,"-e",exec})
  142. bump()
  143. end)
  144. )
  145. )
  146. return widget
  147. end)
  148. local launchpad
  149. do -- Primary area
  150. launchpad = wibox.widget({
  151. t.container {
  152. t.textbox({
  153. text = "",
  154. id = "inputbox"
  155. }),
  156. layout = wibox.layout.fixed.vertical,
  157. },
  158. t.container({
  159. id = "resultbox",
  160. layout = wibox.layout.fixed.vertical,
  161. spacing = style.container.spacing
  162. },{
  163. bg = style.container.bg_highlight,
  164. bgimage = style.container.bgimage_highlight,
  165. forced_width = style.button.width or 180
  166. }),
  167. t.container({
  168. t.button(
  169. t.textbox({
  170. markup = "Most used"
  171. }),{
  172. id = "usage"
  173. }),
  174. t.button(
  175. t.textbox({
  176. markup = "Recent"
  177. }),{
  178. id = "recent"
  179. }),
  180. id = "buttonbox",
  181. spacing = style.container.spacing,
  182. layout = wibox.layout.flex.horizontal
  183. }),
  184. t.textbox({
  185. markup = "<b>Enter</b> - run\n<b>Ctrl+Enter</b> - run in terminal"
  186. }),
  187. spacing = style.container.spacing,
  188. layout = wibox.layout.fixed.vertical
  189. })
  190. local results_list = launchpad:get_children_by_id("resultbox")[1]
  191. local input_field = launchpad:get_children_by_id("inputbox")[1]
  192. local usage_sort = launchpad:get_children_by_id("usage")[1]
  193. local recent_sort = launchpad:get_children_by_id("recent")[1]
  194. local sorting_method = "usage"
  195. usage_sort:set_bg(style.bg_focus)
  196. if style.button.onpress then
  197. style.button.onpress(usage_sort)
  198. end
  199. usage_sort:connect_signal("button::press",function()
  200. recent_sort:set_bg(style.bg_normal)
  201. if style.button.onrelease then
  202. style.button.onrelease(recent_sort)
  203. end
  204. usage_sort:set_bg(style.bg_focus)
  205. if style.button.onpress then
  206. style.button.onpress(usage_sort)
  207. end
  208. sorting_method = "usage"
  209. end)
  210. recent_sort:connect_signal("button::press",function()
  211. usage_sort:set_bg(style.bg_normal)
  212. if style.button.onrelease then
  213. style.button.onrelease(usage_sort)
  214. end
  215. recent_sort:set_bg(style.bg_focus)
  216. if style.button.onpress then
  217. style.button.onpress(recent_sort)
  218. end
  219. sorting_method = "recent"
  220. end)
  221. root.keys(gears.table.join(
  222. root.keys(),
  223. ask.k(":dismal.run", function()
  224. results_list:reset()
  225. dismal.visible = true
  226. if dismal.visible then
  227. popup_position(dismal,{honor_workarea=honor_workarea})
  228. awful.prompt.run {
  229. prompt = "<b>Run: </b>",
  230. textbox = input_field,
  231. hooks = {
  232. { { "Control" }, "Return", function(cmd)
  233. awful.spawn({global.terminal, "-e", cmd})
  234. end},
  235. { { }, "Return", function(cmd)
  236. awful.spawn.with_shell(cmd)
  237. end},
  238. { {}, 'Escape', function()
  239. input_field.markup = ""
  240. end},
  241. },
  242. done_callback = function()
  243. dismal.visible = false
  244. end,
  245. changed_callback = function(command)
  246. local results = xdg_search(command,args.result_limit or 5,sorting_method)
  247. results_list:reset()
  248. for _,v in pairs(results) do
  249. results_list:add(button_cache:get(
  250. v[2].name,
  251. v[2].exec,
  252. v[2].description or "",
  253. v[2].icon or "",
  254. v[1]
  255. ))
  256. end
  257. end,
  258. completion_callback = function(before,after,ncomp)
  259. return awful.completion.shell(before,after,ncomp,global.shell)
  260. end,
  261. history_path = (gears.filesystem.get_xdg_cache_home() or "/tmp/")..".dismal_history",
  262. history_max = 50
  263. }
  264. end
  265. end,{description = "open run menu", group = "widgets"})
  266. ))
  267. end
  268. local dismal_root = dismal.widget:get_children_by_id("dismal_root")[1]
  269. dismal_root:add(launchpad)
  270. return dismal
  271. end