Skip to content

Instantly share code, notes, and snippets.

@EncodeTheCode
Last active May 20, 2026 14:04
Show Gist options
  • Select an option

  • Save EncodeTheCode/368d79820b93c8700f66dca288d15700 to your computer and use it in GitHub Desktop.

Select an option

Save EncodeTheCode/368d79820b93c8700f66dca288d15700 to your computer and use it in GitHub Desktop.
#define UNICODE
#define NOMINMAX
#include <windows.h>
#include <windowsx.h>
#include <dwmapi.h>
#include <chrono>
#include <thread>
#include <algorithm>
#include <string>
#pragma comment(lib, "dwmapi.lib")
class BorderlessWindow {
public:
bool create(HINSTANCE hInstance, const wchar_t* title, int width, int height, int targetFps = 120) {
hInstance_ = hInstance;
title_ = title ? title : L"Window";
width_ = width;
height_ = height;
setTargetFPS(targetFps);
WNDCLASSEXW wc{};
wc.cbSize = sizeof(wc);
wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
wc.lpfnWndProc = &BorderlessWindow::WndProc;
wc.hInstance = hInstance_;
wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
wc.hbrBackground = nullptr;
wc.lpszClassName = kClassName;
if (!RegisterClassExW(&wc) && GetLastError() != ERROR_CLASS_ALREADY_EXISTS) {
return false;
}
hwnd_ = CreateWindowExW(
WS_EX_APPWINDOW,
kClassName,
title_.c_str(),
WS_POPUP | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
CW_USEDEFAULT, CW_USEDEFAULT, width_, height_,
nullptr, nullptr, hInstance_, this);
return hwnd_ != nullptr;
}
void show(int cmdShow = SW_SHOWDEFAULT) {
ShowWindow(hwnd_, cmdShow);
UpdateWindow(hwnd_);
}
int run() {
MSG msg{};
int exitCode = 0;
auto lastFrame = clock::now();
nextFrame_ = lastFrame;
while (running_) {
while (PeekMessageW(&msg, nullptr, 0, 0, PM_REMOVE)) {
if (msg.message == WM_QUIT) {
running_ = false;
exitCode = static_cast<int>(msg.wParam);
break;
}
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
if (!running_) break;
const auto now = clock::now();
const float dt = std::chrono::duration<float>(now - lastFrame).count();
lastFrame = now;
onUpdate(dt);
RedrawWindow(hwnd_, nullptr, nullptr, RDW_INVALIDATE | RDW_UPDATENOW);
throttleFPS();
}
return exitCode;
}
void setTargetFPS(int fps) {
targetFps_ = std::clamp(fps, 1, 1000);
frameStep_ = std::chrono::duration<double>(1.0 / static_cast<double>(targetFps_));
}
void minimize() { ShowWindow(hwnd_, SW_MINIMIZE); }
void maximize() { ShowWindow(hwnd_, SW_MAXIMIZE); }
void restore() { ShowWindow(hwnd_, SW_RESTORE); }
void toggleMaximize() { ShowWindow(hwnd_, IsZoomed(hwnd_) ? SW_RESTORE : SW_MAXIMIZE); }
void close() { PostMessageW(hwnd_, WM_CLOSE, 0, 0); }
protected:
virtual void onUpdate(float dt) {
(void)dt;
}
virtual void onRender(HDC hdc) {
RECT rc{};
GetClientRect(hwnd_, &rc);
// Background
HBRUSH bg = (HBRUSH)GetStockObject(DC_BRUSH);
SetDCBrushColor(hdc, RGB(18, 18, 20));
FillRect(hdc, &rc, bg);
// Title bar
RECT titleBar = { 0, 0, rc.right, kTitleBarHeight };
SetDCBrushColor(hdc, RGB(28, 28, 32));
FillRect(hdc, &titleBar, bg);
// Title text
SetBkMode(hdc, TRANSPARENT);
SetTextColor(hdc, RGB(240, 240, 240));
RECT textRc = { 12, 0, rc.right - 160, kTitleBarHeight };
DrawTextW(hdc, title_.c_str(), -1, &textRc, DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS);
// Buttons
drawButton(hdc, buttonRectClose(), L"×", RGB(180, 50, 50), RGB(255, 255, 255));
drawButton(hdc, buttonRectMax(), IsZoomed(hwnd_) ? L"❐" : L"□", RGB(48, 48, 54), RGB(255, 255, 255));
drawButton(hdc, buttonRectMin(), L"—", RGB(48, 48, 54), RGB(255, 255, 255));
}
private:
using clock = std::chrono::steady_clock;
static constexpr const wchar_t* kClassName = L"BorderlessGameWindowClass";
static constexpr int kTitleBarHeight = 32;
static constexpr int kButtonWidth = 46;
static constexpr int kResizeBorder = 8;
HINSTANCE hInstance_ = nullptr;
HWND hwnd_ = nullptr;
std::wstring title_;
int width_ = 0;
int height_ = 0;
bool running_ = true;
int targetFps_ = 120;
std::chrono::duration<double> frameStep_{ 1.0 / 120.0 };
clock::time_point nextFrame_{};
static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
BorderlessWindow* self = nullptr;
if (msg == WM_NCCREATE) {
auto* cs = reinterpret_cast<CREATESTRUCTW*>(lParam);
self = static_cast<BorderlessWindow*>(cs->lpCreateParams);
SetWindowLongPtrW(hwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(self));
self->hwnd_ = hwnd;
} else {
self = reinterpret_cast<BorderlessWindow*>(GetWindowLongPtrW(hwnd, GWLP_USERDATA));
}
if (self) {
return self->handleMessage(msg, wParam, lParam);
}
return DefWindowProcW(hwnd, msg, wParam, lParam);
}
LRESULT handleMessage(UINT msg, WPARAM wParam, LPARAM lParam) {
switch (msg) {
case WM_CREATE:
return 0;
case WM_NCCALCSIZE:
if (wParam) return 0; // Remove standard non-client area
break;
case WM_NCHITTEST:
return hitTest(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
case WM_GETMINMAXINFO:
keepMaximizeInsideMonitor(reinterpret_cast<MINMAXINFO*>(lParam));
return 0;
case WM_SIZE:
if (wParam == SIZE_MAXIMIZED) {
maximized_ = true;
} else if (wParam == SIZE_RESTORED) {
maximized_ = false;
}
return 0;
case WM_ERASEBKGND:
return 1; // reduce flicker
case WM_LBUTTONUP:
handleClick(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
return 0;
case WM_LBUTTONDBLCLK: {
POINT pt{ GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
if (pointInRect(pt, buttonRectClose()) || pointInRect(pt, buttonRectMin()) || pointInRect(pt, buttonRectMax())) {
return 0;
}
toggleMaximize();
return 0;
}
case WM_SYSCOMMAND:
if ((wParam & 0xFFF0) == SC_KEYMENU) return 0; // blocks alt menu flash
break;
case WM_CLOSE:
DestroyWindow(hwnd_);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
running_ = false;
return 0;
case WM_PAINT: {
PAINTSTRUCT ps{};
HDC hdc = BeginPaint(hwnd_, &ps);
onRender(hdc);
EndPaint(hwnd_, &ps);
return 0;
}
}
return DefWindowProcW(hwnd_, msg, wParam, lParam);
}
void throttleFPS() {
if (targetFps_ <= 0) return;
const auto now = clock::now();
if (nextFrame_ == clock::time_point{}) {
nextFrame_ = now;
}
nextFrame_ += std::chrono::duration_cast<clock::duration>(frameStep_);
if (now < nextFrame_) {
const auto coarseSleepUntil = nextFrame_ - std::chrono::milliseconds(1);
if (now < coarseSleepUntil) {
std::this_thread::sleep_until(coarseSleepUntil);
}
while (clock::now() < nextFrame_) {
std::this_thread::yield();
}
} else {
// If we fell behind, resync so we do not accumulate lag forever.
nextFrame_ = now;
}
}
void keepMaximizeInsideMonitor(MINMAXINFO* mmi) {
if (!mmi || !hwnd_) return;
MONITORINFO mi{};
mi.cbSize = sizeof(mi);
if (GetMonitorInfoW(MonitorFromWindow(hwnd_, MONITOR_DEFAULTTONEAREST), &mi)) {
mmi->ptMaxPosition.x = mi.rcWork.left - mi.rcMonitor.left;
mmi->ptMaxPosition.y = mi.rcWork.top - mi.rcMonitor.top;
mmi->ptMaxSize.x = mi.rcWork.right - mi.rcWork.left;
mmi->ptMaxSize.y = mi.rcWork.bottom - mi.rcWork.top;
}
}
LRESULT hitTest(int screenX, int screenY) {
POINT pt{ screenX, screenY };
ScreenToClient(hwnd_, &pt);
RECT rc{};
GetClientRect(hwnd_, &rc);
const bool onTop = pt.y >= 0 && pt.y < kTitleBarHeight;
const bool onLeft = !IsZoomed(hwnd_) && pt.x >= 0 && pt.x < kResizeBorder;
const bool onRight = !IsZoomed(hwnd_) && pt.x >= rc.right - kResizeBorder && pt.x < rc.right;
const bool onBottom = !IsZoomed(hwnd_) && pt.y >= rc.bottom - kResizeBorder && pt.y < rc.bottom;
if (!IsZoomed(hwnd_)) {
if (onTop && onLeft) return HTTOPLEFT;
if (onTop && onRight) return HTTOPRIGHT;
if (onBottom && onLeft) return HTBOTTOMLEFT;
if (onBottom && onRight) return HTBOTTOMRIGHT;
if (onLeft) return HTLEFT;
if (onRight) return HTRIGHT;
if (pt.y < kResizeBorder) return HTTOP;
if (onBottom) return HTBOTTOM;
}
if (onTop &&
!pointInRect(pt, buttonRectClose()) &&
!pointInRect(pt, buttonRectMin()) &&
!pointInRect(pt, buttonRectMax())) {
return HTCAPTION;
}
return HTCLIENT;
}
void handleClick(int x, int y) {
POINT pt{ x, y };
if (pointInRect(pt, buttonRectClose())) {
close();
} else if (pointInRect(pt, buttonRectMin())) {
minimize();
} else if (pointInRect(pt, buttonRectMax())) {
toggleMaximize();
}
}
RECT buttonRectClose() const {
RECT rc{};
GetClientRect(hwnd_, &rc);
return RECT{
rc.right - kButtonWidth,
0,
rc.right,
kTitleBarHeight
};
}
RECT buttonRectMax() const {
RECT rc{};
GetClientRect(hwnd_, &rc);
return RECT{
rc.right - (kButtonWidth * 2),
0,
rc.right - kButtonWidth,
kTitleBarHeight
};
}
RECT buttonRectMin() const {
RECT rc{};
GetClientRect(hwnd_, &rc);
return RECT{
rc.right - (kButtonWidth * 3),
0,
rc.right - (kButtonWidth * 2),
kTitleBarHeight
};
}
static bool pointInRect(const POINT& pt, const RECT& rc) {
return pt.x >= rc.left && pt.x < rc.right && pt.y >= rc.top && pt.y < rc.bottom;
}
void drawButton(HDC hdc, const RECT& rc, const wchar_t* label, COLORREF bg, COLORREF fg) {
HBRUSH brush = (HBRUSH)GetStockObject(DC_BRUSH);
SetDCBrushColor(hdc, bg);
FillRect(hdc, &rc, brush);
SetBkMode(hdc, TRANSPARENT);
SetTextColor(hdc, fg);
RECT textRc = rc;
DrawTextW(hdc, label, -1, &textRc, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
}
bool maximized_ = false;
};
class MyGameWindow : public BorderlessWindow {
protected:
void onUpdate(float dt) override {
(void)dt;
// Put your game update logic here.
}
void onRender(HDC hdc) override {
BorderlessWindow::onRender(hdc);
// Draw your game UI / test content here.
}
};
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR, int cmdShow) {
MyGameWindow app;
if (!app.create(hInstance, L"Custom Borderless Game Window", 1280, 720, 120)) {
MessageBoxW(nullptr, L"Window creation failed.", L"Error", MB_ICONERROR);
return 1;
}
app.show(cmdShow);
return app.run();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment