centerwork.lua 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. --[[
  2. Licensed under GNU General Public License v2
  3. * (c) 2018, Eugene Pakhomov
  4. * (c) 2016, Henrik Antonsson
  5. * (c) 2015, Joerg Jaspert
  6. * (c) 2014, projektile
  7. * (c) 2013, Luca CPZ
  8. * (c) 2010-2012, Peter Hofmann
  9. --]]
  10. local floor, max, mouse, mousegrabber, screen = math.floor, math.max, mouse, mousegrabber, screen
  11. local centerwork = {
  12. name = "centerwork",
  13. horizontal = { name = "centerworkh" }
  14. }
  15. local function arrange(p, layout)
  16. local t = p.tag or screen[p.screen].selected_tag
  17. local wa = p.workarea
  18. local cls = p.clients
  19. if #cls == 0 then return end
  20. local g = {}
  21. -- Main column, fixed width and height
  22. local mwfact = t.master_width_factor
  23. local mainhei = floor(wa.height * mwfact)
  24. local mainwid = floor(wa.width * mwfact)
  25. local slavewid = wa.width - mainwid
  26. local slaveLwid = floor(slavewid / 2)
  27. local slaveRwid = slavewid - slaveLwid
  28. local slavehei = wa.height - mainhei
  29. local slaveThei = floor(slavehei / 2)
  30. local slaveBhei = slavehei - slaveThei
  31. local nbrFirstSlaves = floor(#cls / 2)
  32. local nbrSecondSlaves = floor((#cls - 1) / 2)
  33. local slaveFirstDim, slaveSecondDim = 0, 0
  34. if layout.name == "centerwork" then -- vertical
  35. if nbrFirstSlaves > 0 then slaveFirstDim = floor(wa.height / nbrFirstSlaves) end
  36. if nbrSecondSlaves > 0 then slaveSecondDim = floor(wa.height / nbrSecondSlaves) end
  37. g.height = wa.height
  38. g.width = mainwid
  39. g.x = wa.x + slaveLwid
  40. g.y = wa.y
  41. else -- horizontal
  42. if nbrFirstSlaves > 0 then slaveFirstDim = floor(wa.width / nbrFirstSlaves) end
  43. if nbrSecondSlaves > 0 then slaveSecondDim = floor(wa.width / nbrSecondSlaves) end
  44. g.height = mainhei
  45. g.width = wa.width
  46. g.x = wa.x
  47. g.y = wa.y + slaveThei
  48. end
  49. g.width = max(g.width, 1)
  50. g.height = max(g.height, 1)
  51. p.geometries[cls[1]] = g
  52. -- Auxiliary clients
  53. if #cls <= 1 then return end
  54. for i = 2, #cls do
  55. g = {}
  56. local idxChecker, dimToAssign
  57. local rowIndex = floor(i/2)
  58. if layout.name == "centerwork" then
  59. if i % 2 == 0 then -- left slave
  60. g.x = wa.x
  61. g.y = wa.y + (rowIndex - 1) * slaveFirstDim
  62. g.width = slaveLwid
  63. idxChecker, dimToAssign = nbrFirstSlaves, slaveFirstDim
  64. else -- right slave
  65. g.x = wa.x + slaveLwid + mainwid
  66. g.y = wa.y + (rowIndex - 1) * slaveSecondDim
  67. g.width = slaveRwid
  68. idxChecker, dimToAssign = nbrSecondSlaves, slaveSecondDim
  69. end
  70. -- if last slave in row, use remaining space for it
  71. if rowIndex == idxChecker then
  72. g.height = wa.y + wa.height - g.y
  73. else
  74. g.height = dimToAssign
  75. end
  76. else
  77. if i % 2 == 0 then -- top slave
  78. g.x = wa.x + (rowIndex - 1) * slaveFirstDim
  79. g.y = wa.y
  80. g.height = slaveThei
  81. idxChecker, dimToAssign = nbrFirstSlaves, slaveFirstDim
  82. else -- bottom slave
  83. g.x = wa.x + (rowIndex - 1) * slaveSecondDim
  84. g.y = wa.y + slaveThei + mainhei
  85. g.height = slaveBhei
  86. idxChecker, dimToAssign = nbrSecondSlaves, slaveSecondDim
  87. end
  88. -- if last slave in row, use remaining space for it
  89. if rowIndex == idxChecker then
  90. g.width = wa.x + wa.width - g.x
  91. else
  92. g.width = dimToAssign
  93. end
  94. end
  95. g.width = max(g.width, 1)
  96. g.height = max(g.height, 1)
  97. p.geometries[cls[i]] = g
  98. end
  99. end
  100. local function mouse_resize_handler(c, _, _, _, orientation)
  101. local wa = c.screen.workarea
  102. local mwfact = c.screen.selected_tag.master_width_factor
  103. local g = c:geometry()
  104. local offset = 0
  105. local cursor = "cross"
  106. local corner_coords
  107. if orientation == 'vertical' then
  108. if g.height + 15 >= wa.height then
  109. offset = g.height * .5
  110. cursor = "sb_h_double_arrow"
  111. elseif not (g.y + g.height + 15 > wa.y + wa.height) then
  112. offset = g.height
  113. end
  114. corner_coords = { x = wa.x + wa.width * (1 - mwfact) / 2, y = g.y + offset }
  115. else
  116. if g.width + 15 >= wa.width then
  117. offset = g.width * .5
  118. cursor = "sb_v_double_arrow"
  119. elseif not (g.x + g.width + 15 > wa.x + wa.width) then
  120. offset = g.width
  121. end
  122. corner_coords = { y = wa.y + wa.height * (1 - mwfact) / 2, x = g.x + offset }
  123. end
  124. mouse.coords(corner_coords)
  125. local prev_coords = {}
  126. mousegrabber.run(function(_mouse)
  127. if not c.valid then return false end
  128. for _, v in ipairs(_mouse.buttons) do
  129. if v then
  130. prev_coords = { x = _mouse.x, y = _mouse.y }
  131. local new_mwfact
  132. if orientation == 'vertical' then
  133. new_mwfact = 1 - (_mouse.x - wa.x) / wa.width * 2
  134. else
  135. new_mwfact = 1 - (_mouse.y - wa.y) / wa.height * 2
  136. end
  137. c.screen.selected_tag.master_width_factor = math.min(math.max(new_mwfact, 0.01), 0.99)
  138. return true
  139. end
  140. end
  141. return prev_coords.x == _mouse.x and prev_coords.y == _mouse.y
  142. end, cursor)
  143. end
  144. function centerwork.arrange(p)
  145. return arrange(p, centerwork)
  146. end
  147. function centerwork.horizontal.arrange(p)
  148. return arrange(p, centerwork.horizontal)
  149. end
  150. function centerwork.mouse_resize_handler(c, corner, x, y)
  151. return mouse_resize_handler(c, corner, x, y, 'vertical')
  152. end
  153. function centerwork.horizontal.mouse_resize_handler(c, corner, x, y)
  154. return mouse_resize_handler(c, corner, x, y, 'horizontal')
  155. end
  156. -------------------------------------------------------------------------------
  157. -- make focus.byidx and swap.byidx behave more consistently with other layouts
  158. local awful = require("awful")
  159. local gears = require("gears")
  160. local function compare_position(a, b)
  161. if a.x == b.x then
  162. return a.y < b.y
  163. else
  164. return a.x < b.x
  165. end
  166. end
  167. local function clients_by_position()
  168. local this = client.focus
  169. if this then
  170. local sorted = client.focus.first_tag:clients()
  171. table.sort(sorted, compare_position)
  172. local idx = 0
  173. for i, that in ipairs(sorted) do
  174. if this.window == that.window then
  175. idx = i
  176. end
  177. end
  178. if idx > 0 then
  179. return { sorted = sorted, idx = idx }
  180. end
  181. end
  182. return {}
  183. end
  184. local function in_centerwork()
  185. return client.focus and client.focus.first_tag.layout.name == "centerwork"
  186. end
  187. centerwork.focus = {}
  188. --[[
  189. Drop in replacements for awful.client.focus.byidx and awful.client.swap.byidx
  190. that behaves consistently with other layouts
  191. --]]
  192. function centerwork.focus.byidx(i)
  193. if in_centerwork() then
  194. local cls = clients_by_position()
  195. if cls.idx then
  196. local target = cls.sorted[gears.math.cycle(#cls.sorted, cls.idx + i)]
  197. awful.client.focus.byidx(0, target)
  198. end
  199. else
  200. awful.client.focus.byidx(i)
  201. end
  202. end
  203. centerwork.swap = {}
  204. function centerwork.swap.byidx(i)
  205. if in_centerwork() then
  206. local cls = clients_by_position()
  207. if cls.idx then
  208. local target = cls.sorted[gears.math.cycle(#cls.sorted, cls.idx + i)]
  209. client.focus:swap(target)
  210. end
  211. else
  212. awful.client.swap.byidx(i)
  213. end
  214. end
  215. return centerwork