-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathWindowPlacer.lua
More file actions
152 lines (122 loc) · 4.78 KB
/
WindowPlacer.lua
File metadata and controls
152 lines (122 loc) · 4.78 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
---
--- Generated by Luanalysis
--- Created by muescha.
--- DateTime: 26.01.23 02:12
---
--- done with ChatGPT :)
--- can you write me an hammerspoon lua script where i can place a window on
--- main screen on macbook and the other one on halfscreen (top and bottom)
--- of my portrait mode external monitor.
---
--- can it done more generic for the external monitor, so that it find out by
--- self if a monitor external, and if it is in portrait mode it should place
--- on top or bottom and if it is in landscape mode it should be placed on left and right
fileInfo()
local units = require("hs.geometry").rect
debugTable(hs.screen.allScreens())
for k, v in pairs(hs.screen.allScreens()) do
print(v:currentMode().desc .. ": " .. v:name())
end
local function to_unit(values, rotate)
if rotate then
return units(values[1], 0, values[2], 1 )
else
return units(0, values[1], 1, values[2] )
end
end
-- TODO make this as setup
local layout_setup = {
--key start, size
["1"] = { 0, 1/3, "+==1==+-----+-----+"},
["2"] = {1/3, 1/3, "+-----+==2==+-----+"},
["3"] = {2/3, 1/3, "+-----+-----+==3==+"},
["4"] = { 0, 1, "+========4========+"}, -- max
["5"] = { 0, 2/3, "+=====5=====+-----+"},
["6"] = {2/6, 3/6, "+-----+=====6==+--+"},
["7"] = {1/3, 2/3, "+-----+=====7=====+"}, -- udemy
["8"] = {1/2, 1/2, "+--------+==8=====+"}, -- bottom
["a"] = { 0, 1/2, "+=====a==+--------+"}, -- top
["b"] = {1/2, 2/6, "+--------+==b==+--+"},
["c"] = {5/6, 1/6, "+-----+-----+--=c=+"},
["d"] = { 0, 5/6, "+=======d======+--+"},
}
local layout_keys = {
maximize = "4",
top = "a",
bottom = "8",
udemy = "7"
}
-- TODO make this as config
local screens = {
internal = "Built%-in",
monitor_1 = 'Thunderbolt',
monitor_2 = '5120x1440'
}
local layout = { ["portrait"] = {}, ["landscape"] = {}}
local layout_info = "Layout: "
local sortedLayoutSetupIterator = helper.table.sortByKeyIterator(layout_setup)
for i, v in sortedLayoutSetupIterator do
layout["portrait"][i] = to_unit(v, false)
layout["landscape"][i] = to_unit(v, true)
layout_info = layout_info .. "\n key "..i..": " .. v[3]:gsub("-"," "):gsub("+"," ")
end
local function framesEqual(f1, f2, tolerance)
tolerance = tolerance or 1
return math.abs(f1.x - f2.x) < tolerance and
math.abs(f1.y - f2.y) < tolerance and
math.abs(f1.w - f2.w) < tolerance and
math.abs(f1.h - f2.h) < tolerance
end
local function windowMoveToUnit(window, screen, newUnit)
if window:screen() ~= screen then return end
local expectedFrame = screen:fromUnitRect(newUnit)
local actualFrame = window:frame()
if framesEqual(actualFrame, expectedFrame) then
debugInfo('No Adjustment needed...')
return false
else
debugInfo('Adjustment needed...')
window:moveToUnit(newUnit)
return true
end
end
local function windowMoveToKey(screenId, key)
local screen = hs.screen.find(screenId)
if screen == nil then hs.alert.show('No screen available for keyword: ' .. screenId) return end
local window = hs.window.focusedWindow()
local direction = (screen:rotate()==0) and "landscape" or "portrait"
local newUnit = layout[direction][key]
window:moveToScreen(screen)
--retryWhile(function() return windowMoveToUnit(window, screen, newUnit) end)
retryWhileOnComplete(function() return windowMoveToUnit(window, screen, newUnit) end, function(success) print(success and "Success: placed the window on right place!" or "Failed to place windows!") end)
end
debugInfo(layout_info)
local function startFn()
local window = hs.window.frontmostWindow()
hs.alert.show(layout_info, { textFont = "Menlo"}, window, 'do-not-close')
end
local function exitFn ()
hs.alert.closeAll()
end
local hkbm = hotkeybindmodal(hyper, "w", keyInfo("place on Big Monitor "), startFn, exitFn)
for key, _ in pairs(layout_setup) do
local move = function()
windowMoveToKey(screens.monitor_2, key)
hkbm:exit()
end
hkbm:bind({}, key, move)
hkbm:bind(hyper, key, move)
end
local opts_keys = { SCREEN = 1, LAYOUT = 2, DESC = 3, }
local layout_non_modal = {
["1"] = { screens.monitor_1, layout_keys.top, "place on one half of monitor" },
["2"] = { screens.monitor_1, layout_keys.bottom, "place on other half of monitor" },
["3"] = { screens.internal, layout_keys.maximize, "place on main screen" },
["4"] = { screens.monitor_1, layout_keys.maximize, "place fullscreen on monitor" },
["8"] = { screens.monitor_1, layout_keys.udemy, "place 2/3 on monitor (Udemy Mode)" },
}
for key, opts in pairs(layout_non_modal) do
hs.hotkey.bind(hyper, key, keyInfo(opts[opts_keys.DESC]), function()
windowMoveToKey(opts[opts_keys.SCREEN], opts[opts_keys.LAYOUT])
end)
end