Skip to content

Instantly share code, notes, and snippets.

@mridgers
Created April 30, 2023 09:33
Show Gist options
  • Save mridgers/8e88a7fb4b428d460e4efef57dd2839d to your computer and use it in GitHub Desktop.
Save mridgers/8e88a7fb4b428d460e4efef57dd2839d to your computer and use it in GitHub Desktop.
Three column window placement using hot keys
/*
* building;
* cl.exe thirds.cpp /std:c++17 /EHsc /Zi /Ox /link /subsystem:windows
*
* using;
* Win-Ctrl-A : [-1/3-:-1/3-:-1/3-]
* Win-Ctrl-Z : [-1/3-:----2/3----] + fat middle
* Win-Ctrl-W : toggles between top/bottom halves of column from 'A'
*/
#include <dwmapi.h>
#include <shellscalingapi.h>
#include <vector>
#include <Windows.h>
#pragma comment(lib, "user32")
#pragma comment(lib, "shcore")
#pragma comment(lib, "dwmapi")
//------------------------------------------------------------------------------
struct Point
{
Point operator - (const Point& r) const { return { x - r.x, y - r.y }; }
int length_sq() const { return (x * x) + (y * y); }
int x, y;
};
//------------------------------------------------------------------------------
struct Box
{
operator bool () const { return get_dims().x == 0; }
operator RECT* () { return (RECT*)this; }
Point get_origin() const { return { left, top }; }
Point get_dims() const { return { right - left, bottom - top }; }
Point get_centre() const { return { (left + right) / 2, (top + bottom) / 2 }; }
void expand(int d) { left -= d; top -= d; right += d; bottom += d; }
int left, top, right, bottom;
};
static_assert(sizeof(Box) == sizeof(RECT));
//------------------------------------------------------------------------------
static void three_columns(std::vector<Box>& boxes, const Box& monitor)
{
auto [x, y] = monitor.get_origin();
auto [w, h] = monitor.get_dims();
int third_w = w / 3;
int xs[4] = {
x,
x + third_w,
x + (third_w * 2),
x + w,
};
boxes.push_back({ xs[0], y, xs[1], y + h });
boxes.push_back({ xs[1], y, xs[2], y + h });
boxes.push_back({ xs[2], y, xs[3], y + h });
for (auto& box : boxes)
box.expand(1);
}
//------------------------------------------------------------------------------
static void two_thirds(std::vector<Box>& boxes, const Box& monitor)
{
auto [x, y] = monitor.get_origin();
auto [w, h] = monitor.get_dims();
int third_w = w / 3;
int d;
if ((w * 10) / h < 16)
d = (third_w * 4) / 9;
else
d = (third_w * 2) / 10;
boxes.push_back({ x, y, x + third_w, y + h });
boxes.push_back({ x + third_w - d, y, x + (third_w * 2) + d, y + h });
boxes.push_back({ x + third_w, y, x + w, y + h });
for (auto& box : boxes)
box.expand(1);
}
//------------------------------------------------------------------------------
static int get_closest(const std::vector<Box>& boxes, const Box& box, int threshold=INT_MAX)
{
Point point = box.get_centre();
const Box* best = nullptr;
int dist = INT_MAX;
for (int i = 0, n = boxes.size(); i < n; ++i)
{
const Box& box = boxes[i];
int candidate = (box.get_centre() - point).length_sq();
if (candidate < threshold && candidate < dist)
{
best = &box;
dist = candidate;
}
}
if (best == nullptr)
return -1;
return int(uintptr_t(best - &(boxes[0])));
}
//------------------------------------------------------------------------------
static Box get_monitor_box(HWND handle)
{
HMONITOR monitor = MonitorFromWindow(handle, MONITOR_DEFAULTTONEAREST);
if (monitor == nullptr)
return {};
MONITORINFO info = { sizeof(info) };
GetMonitorInfoW(monitor, &info);
const RECT& rect = info.rcWork;
return { rect.left, rect.top, rect.right, rect.bottom };
}
//------------------------------------------------------------------------------
static void on_hotkey(HWND handle, int key)
{
Box monitor_box = get_monitor_box(handle);
if (!monitor_box)
return;
if (IsZoomed(handle))
ShowWindow(handle, SW_RESTORE);
std::vector<Box> boxes;
switch (key)
{
case 'A':
case 'W': three_columns(boxes, monitor_box); break;
case 'Z': two_thirds(boxes, monitor_box); break;
default: return;
}
Box window_box;
GetWindowRect(handle, window_box);
int box_index = -1;
if (key != 'W')
{
box_index = get_closest(boxes, window_box, 100);
if (box_index != -1)
box_index = (box_index + 1) % boxes.size();
}
if (box_index == -1)
box_index = get_closest(boxes, window_box);
if (unsigned(box_index) >= unsigned(boxes.size()))
{
ShowWindowAsync(handle, SW_SHOWMAXIMIZED);
return;
}
Box box = boxes[box_index];
if (key == 'W')
{
int half_height = box.get_dims().y / 2;
if (window_box.top < half_height - 100)
{
if (window_box.bottom < half_height + 100)
box.top += half_height;
else
box.bottom -= half_height;
}
}
Point tl = box.get_origin();
Point wh = box.get_dims();
// to get perfect alignment we need to adjust for whatever DWM is up to
Box dwm_box;
if (SUCCEEDED(DwmGetWindowAttribute(handle, DWMWA_EXTENDED_FRAME_BOUNDS, dwm_box, sizeof(dwm_box))))
{
int left_offset = dwm_box.left - window_box.left;
tl.x -= left_offset;
wh.x += left_offset - (dwm_box.right - window_box.right);
wh.y += window_box.bottom - dwm_box.bottom;
}
SetWindowPos(handle, nullptr, tl.x, tl.y, wh.x, wh.y, SWP_ASYNCWINDOWPOS);
}
//------------------------------------------------------------------------------
static int go()
{
SetCurrentDirectoryW(L"c:/");
enum { ID = 0x04930000 };
int modifiers = MOD_WIN|MOD_CONTROL|MOD_NOREPEAT;
for (int key : { 'A', 'W', 'Z' })
if (!RegisterHotKey(nullptr, ID|key, modifiers, key))
return 1;
SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE);
MSG message;
while (GetMessage(&message, nullptr, 0, 0) > 0)
{
if (message.message != WM_HOTKEY)
continue;
int hotkey_id = (message.wParam & 0x7fff0000);
if (hotkey_id != ID)
continue;
if (HWND handle = GetForegroundWindow())
{
int hotkey_key = (message.wParam & 0xffff);
on_hotkey(handle, hotkey_key);
}
}
return 0;
}
//------------------------------------------------------------------------------
int main(int, char**) { return go(); }
int CALLBACK WinMain(HINSTANCE, HINSTANCE, LPSTR, int) { return go(); }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment