summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--win-resize-mt/build.sh3
-rw-r--r--win-resize-mt/win-resize-mt.c277
-rw-r--r--win-resize-st/build.bat3
-rw-r--r--win-resize-st/build.sh3
-rw-r--r--win-resize-st/win-resize-st.c (renamed from win-resize/win-resize.c)457
-rw-r--r--win-resize/build.bat3
-rwxr-xr-xwin-resize/build.sh3
7 files changed, 514 insertions, 235 deletions
diff --git a/win-resize-mt/build.sh b/win-resize-mt/build.sh
new file mode 100644
index 0000000..c7c4423
--- /dev/null
+++ b/win-resize-mt/build.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+mkdir -p bin
+cc -o bin/win-resize-mt -Wall -Wextra -Wpedantic -O0 -g ./win-resize-mt.c -ldwmapi -lgdi32
diff --git a/win-resize-mt/win-resize-mt.c b/win-resize-mt/win-resize-mt.c
new file mode 100644
index 0000000..2f9dd4e
--- /dev/null
+++ b/win-resize-mt/win-resize-mt.c
@@ -0,0 +1,277 @@
+// ================================================================================================
+// Example of how to draw while resizing / moving a window on Windows in C.
+//
+// This demo uses a dedicated render thread with basic synchronization with the event loop. There
+// is a single-threaded version called win-resize/ if that's more your style.
+//
+// Build (MSVC):
+// > cl /W4 /Od /Zi win-resize-mt.c /Fe:win-resize-mt.exe
+// Build (GCC/clang):
+// $ cc -o win-resize-mt.exe -Wall -Wextra -Wpedantic -O0 -g win-resize-mt.c -ldwmapi -lgdi32
+//
+// Changelog:
+// XX/XX/XXXX: Initial release
+//
+// License:
+// Copyright (c) 2026 Hunter Kvalevog
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+// WITH REGARD TO THIS SOFTWARE.
+// ================================================================================================
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <dwmapi.h>
+
+#include <assert.h>
+#include <math.h>
+#include <stdio.h>
+
+#ifdef _MSC_VER
+# pragma comment(lib, "dwmapi.lib")
+# pragma comment(lib, "gdi32.lib")
+# pragma comment(lib, "user32.lib")
+#endif
+
+#define UNUSED(Var) ((void)(Var))
+
+static void GfxInit(HWND wnd);
+static void GfxResize(UINT vpw, UINT vph);
+static void GfxDraw(void);
+
+#define THREAD_BIT_QUIT (1 << 0)
+#define THREAD_BIT_SIZE (1 << 1)
+#define THREAD_BIT_SYNC (1 << 2)
+
+typedef struct ThreadData ThreadData;
+struct ThreadData
+{
+ HWND wnd;
+ HANDLE init_sig;
+ HANDLE sync_sig;
+ volatile LONG bits;
+ volatile LONG size_w;
+ volatile LONG size_h;
+};
+
+//
+static DWORD WINAPI RenderThread(LPVOID opaque)
+{
+ ThreadData *td = opaque;
+ GfxInit(td->wnd);
+ GfxDraw();
+
+ SetEvent(td->init_sig);
+
+ while (TRUE) {
+ const LONG bits = InterlockedOr(&td->bits, 0);
+
+ if (bits & THREAD_BIT_QUIT) {
+ break;
+ }
+
+ if (bits & THREAD_BIT_SIZE) {
+ const LONG size_w = InterlockedOr(&td->size_w, 0);
+ const LONG size_h = InterlockedOr(&td->size_h, 0);
+ GfxResize(size_w, size_h);
+ InterlockedAnd(&td->bits, ~THREAD_BIT_SIZE);
+ }
+
+ GfxDraw();
+
+ if (bits & THREAD_BIT_SYNC) {
+ SetEvent(td->sync_sig);
+ InterlockedAnd(&td->bits, ~THREAD_BIT_SYNC);
+ }
+ }
+
+ return 0;
+}
+
+//
+static LRESULT CALLBACK WndProc(HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam)
+{
+ ThreadData *td = (ThreadData *)GetWindowLongPtrW(wnd, GWLP_USERDATA);
+ switch (msg)
+ {
+ case WM_DESTROY:
+ PostQuitMessage(0);
+ return 0;
+ case WM_SIZE:
+ // Resize
+ InterlockedExchange(&td->size_w, LOWORD(lparam));
+ InterlockedExchange(&td->size_h, HIWORD(lparam));
+ InterlockedOr(&td->bits, THREAD_BIT_SIZE);
+
+ // Sync
+ InterlockedOr(&td->bits, THREAD_BIT_SYNC);
+ WaitForSingleObject(td->sync_sig, INFINITE);
+ ResetEvent(td->sync_sig);
+ break;
+ }
+ return DefWindowProcW(wnd, msg, wparam, lparam);
+}
+
+//
+int WinMain(HINSTANCE instance, HINSTANCE previnstance, LPSTR cmdline, int cmdshow)
+{
+ UNUSED(previnstance); UNUSED(cmdline);
+
+ // Register window class
+ WNDCLASSEXW wc = { 0 };
+ wc.cbSize = sizeof(wc);
+ wc.hCursor = LoadCursor(0, IDC_ARROW);
+ wc.hInstance = instance;
+ wc.lpfnWndProc = WndProc;
+ wc.lpszClassName = L"win-resize-mt";
+
+ ATOM atom = RegisterClassExW(&wc);
+ assert(atom && "Failed to register window class");
+
+ // Create window
+ HWND wnd = CreateWindowExW(WS_EX_APPWINDOW, wc.lpszClassName, wc.lpszClassName,
+ WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
+ CW_USEDEFAULT, 0, 0, wc.hInstance, 0);
+ assert(wnd && "Failed to create window");
+
+ //
+ ThreadData td = { 0 };
+ td.wnd = wnd;
+ td.init_sig = CreateEvent(0, TRUE, FALSE, 0);
+ td.sync_sig = CreateEvent(0, TRUE, FALSE, 0);
+
+ //
+ HANDLE th = CreateThread(0, 0, RenderThread, &td, 0, 0);
+ assert(th && "Failed to create render thread");
+
+ //
+ SetWindowLongPtrW(wnd, GWLP_USERDATA, (LONG_PTR)&td);
+ WaitForSingleObject(td.init_sig, INFINITE);
+
+ //
+ ShowWindow(wnd, cmdshow);
+
+ //
+ MSG msg;
+ while (GetMessageW(&msg, 0, 0, 0) > 0) {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+
+ //
+ InterlockedOr(&td.bits, THREAD_BIT_QUIT);
+ WaitForSingleObject(th, INFINITE);
+
+ return 0;
+}
+
+// ================================================================================================
+
+static UINT g_vpw = 0;
+static UINT g_vph = 0;
+static HDC g_hdc = 0;
+static HDC g_hdc_back = 0;
+static HBITMAP g_bmp = 0;
+static HBRUSH g_bgbr = 0;
+static HBRUSH g_fgbr = 0;
+static HPEN g_pen = 0;
+
+static void GfxInit(HWND wnd)
+{
+ g_hdc = GetDC(wnd);
+ g_hdc_back = CreateCompatibleDC(g_hdc);
+ g_bgbr = CreateSolidBrush(RGB(0x00, 0x20, 0x20));
+ g_fgbr = CreateSolidBrush(RGB(0xE0, 0xE0, 0xE0));
+ g_pen = CreatePen(PS_SOLID, 2, RGB(0xFF, 0x10, 0x10));
+
+ RECT rc;
+ GetClientRect(wnd, &rc);
+
+ GfxResize(rc.right, rc.bottom);
+}
+
+static void GfxResize(UINT vpw, UINT vph)
+{
+ if (g_bmp)
+ {
+ DeleteObject(g_bmp);
+ g_bmp = 0;
+ }
+
+ if (vpw > 0 && vph > 0)
+ {
+ g_bmp = CreateCompatibleBitmap(g_hdc, vpw, vph);
+ SelectObject(g_hdc_back, g_bmp);
+ }
+
+ g_vpw = vpw;
+ g_vph = vph;
+}
+
+static void GfxDraw(void)
+{
+ static UINT frame = 0;
+ ++frame;
+
+ if (g_bmp && g_vpw > 0 && g_vph > 0)
+ {
+ HDC hdc = g_hdc_back;
+
+ // Clear
+ {
+ RECT rc = { 0, 0, g_vpw, g_vph };
+ FillRect(hdc, &rc, g_bgbr);
+ }
+
+ // Draw X
+ {
+ SelectObject(hdc, g_pen);
+ MoveToEx(hdc, 0, 0, 0);
+ LineTo(hdc, g_vpw, g_vph);
+ MoveToEx(hdc, 0, g_vph, 0);
+ LineTo(hdc, g_vpw, 0);
+ }
+
+ // Draw rotating triangle
+ {
+ int cx = g_vpw / 2;
+ int cy = g_vph / 2;
+ int r = (g_vpw < g_vph ? g_vpw : g_vph) / 3;
+
+ POINT verts[3];
+ for (int i = 0; i < 3; ++i)
+ {
+ float ang = ((float)frame / 100.0f) + (float)i * (2.0f * 3.14159265f / 3.0f);
+ verts[i].x = cx + (int)(cosf(ang) * r);
+ verts[i].y = cy + (int)(sinf(ang) * r);
+ }
+
+ SelectObject(hdc, g_pen);
+ SelectObject(hdc, g_fgbr);
+ Polygon(hdc, verts, ARRAYSIZE(verts));
+ }
+
+ // Draw text
+ {
+ WCHAR txtbuf[256];
+ _snwprintf_s(txtbuf, ARRAYSIZE(txtbuf), _TRUNCATE, L"win-resize-mt (frame %u)", frame);
+
+ SIZE sz;
+ GetTextExtentPoint32W(hdc, txtbuf, (int)wcslen(txtbuf), &sz);
+
+ SetBkMode(hdc, TRANSPARENT);
+ SetTextColor(hdc, RGB(0xE0, 0xE0, 0xE0));
+ TextOutW(hdc, (g_vpw - sz.cx) / 2, 19, txtbuf, (int)wcslen(txtbuf));
+ }
+
+ // Present
+ BitBlt(g_hdc, 0, 0, g_vpw, g_vph, g_hdc_back, 0, 0, SRCCOPY);
+
+ // Wait for dwm to display a frame
+ DwmFlush();
+ }
+}
+
diff --git a/win-resize-st/build.bat b/win-resize-st/build.bat
new file mode 100644
index 0000000..8568ca2
--- /dev/null
+++ b/win-resize-st/build.bat
@@ -0,0 +1,3 @@
+@echo off
+if not exist bin mkdir bin
+cl /W4 /Od /Zi /Fe:bin\win-resize-st.exe win-resize-st.c /Fd:bin\ /Fo:bin\
diff --git a/win-resize-st/build.sh b/win-resize-st/build.sh
new file mode 100644
index 0000000..d644837
--- /dev/null
+++ b/win-resize-st/build.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+mkdir -p bin
+cc -o bin/win-resize-st -Wall -Wextra -Wpedantic -O0 -g ./win-resize-st.c -ldwmapi -lgdi32
diff --git a/win-resize/win-resize.c b/win-resize-st/win-resize-st.c
index 275760e..5aace81 100644
--- a/win-resize/win-resize.c
+++ b/win-resize-st/win-resize-st.c
@@ -1,229 +1,228 @@
-// ================================================================================================
-// Example of how to draw while resizing / moving a window on Windows in C.
-//
-// Window contents are rendered via GDI, but the behavior is the same no matter what graphics API
-// you use. The original version of this demo (on old-20260427 branch) used D3D11.
-//
-// Pretty much all modern Direct3D Windows apps use a render thread and therefore don't have to
-// deal with this problem. That strategy doesn't work with APIs that have weird thread affinity
-// issues (OpenGL), so this is one way of doing it without multithreading.
-//
-// Build (MSVC):
-// > cl /W4 /Od /Zi win-resize.c /Fe:win-resize.exe
-// Build (GCC/clang):
-// $ cc -o win-resize.exe -Wall -Wextra -Wpedantic -O0 -g win-resize.c -ldwmapi -lgdi32
-//
-// Changelog:
-// 5/15/2026: Initial release
-//
-// License:
-// SPDX-License-Identifier: 0BSD
-// Copyright (c) 2026 Hunter Kvalevog
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-// WITH REGARD TO THIS SOFTWARE.
-// ================================================================================================
-
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-#include <dwmapi.h>
-
-#include <assert.h>
-#include <math.h>
-#include <stdio.h>
-
-#ifdef _MSC_VER
-# pragma comment(lib, "dwmapi.lib")
-# pragma comment(lib, "gdi32.lib")
-# pragma comment(lib, "user32.lib")
-#endif
-
-#define UNUSED(Var) ((void)(Var))
-
-static void GfxInit(HWND wnd);
-static void GfxResize(UINT vpw, UINT vph);
-static void GfxDraw(void);
-
-//
-static LRESULT CALLBACK WndProc(HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam)
-{
- switch (msg)
- {
- case WM_DESTROY:
- PostQuitMessage(0);
- return 0;
- case WM_SIZE:
- GfxResize(LOWORD(lparam), HIWORD(lparam));
- GfxDraw();
- break;
- case WM_ENTERSIZEMOVE:
- SetTimer(wnd, 1, USER_TIMER_MINIMUM, 0);
- break;
- case WM_EXITSIZEMOVE:
- KillTimer(wnd, 1);
- break;
- case WM_TIMER:
- GfxDraw();
- break;
- }
- return DefWindowProcW(wnd, msg, wparam, lparam);
-}
-
-//
-int WinMain(HINSTANCE instance, HINSTANCE previnstance, LPSTR cmdline, int cmdshow)
-{
- UNUSED(previnstance); UNUSED(cmdline);
-
- // Register window class
- WNDCLASSEXW wc = { };
- wc.cbSize = sizeof(wc);
- wc.hCursor = LoadCursor(0, IDC_ARROW);
- wc.hInstance = instance;
- wc.lpfnWndProc = WndProc;
- wc.lpszClassName = L"win-resize";
-
- ATOM atom = RegisterClassExW(&wc);
- assert(atom && "Failed to register window class");
-
- // Create window
- HWND wnd = CreateWindowExW(WS_EX_APPWINDOW, wc.lpszClassName, wc.lpszClassName,
- WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
- CW_USEDEFAULT, 0, 0, wc.hInstance, 0);
- assert(wnd && "Failed to create window");
-
- //
- GfxInit(wnd);
-
- //
- ShowWindow(wnd, cmdshow);
-
- // Run a typical D3D-style window loop
- BOOL quit = FALSE;
- while (!quit)
- {
- // Pump the message loop
- MSG msg;
- while (PeekMessageW(&msg, 0, 0, 0, PM_REMOVE))
- {
- quit |= (msg.message == WM_QUIT);
- TranslateMessage(&msg);
- DispatchMessageW(&msg);
- }
-
- // Update the screen
- GfxDraw();
- }
-
- return 0;
-}
-
-// ================================================================================================
-
-static UINT g_vpw = 0;
-static UINT g_vph = 0;
-static HDC g_hdc = 0;
-static HDC g_hdc_back = 0;
-static HBITMAP g_bmp = 0;
-static HBRUSH g_bgbr = 0;
-static HBRUSH g_fgbr = 0;
-static HPEN g_pen = 0;
-
-static void GfxInit(HWND wnd)
-{
- g_hdc = GetDC(wnd);
- g_hdc_back = CreateCompatibleDC(g_hdc);
- g_bgbr = CreateSolidBrush(RGB(0x00, 0x20, 0x20));
- g_fgbr = CreateSolidBrush(RGB(0xE0, 0xE0, 0xE0));
- g_pen = CreatePen(PS_SOLID, 2, RGB(0xFF, 0x10, 0x10));
-
- RECT rc;
- GetClientRect(wnd, &rc);
-
- GfxResize(rc.right, rc.bottom);
-}
-
-static void GfxResize(UINT vpw, UINT vph)
-{
- if (g_bmp)
- {
- DeleteObject(g_bmp);
- g_bmp = 0;
- }
-
- if (vpw > 0 && vph > 0)
- {
- g_bmp = CreateCompatibleBitmap(g_hdc, vpw, vph);
- SelectObject(g_hdc_back, g_bmp);
- }
-
- g_vpw = vpw;
- g_vph = vph;
-}
-
-static void GfxDraw(void)
-{
- static UINT frame = 0;
- ++frame;
-
- if (g_bmp && g_vpw > 0 && g_vph > 0)
- {
- HDC hdc = g_hdc_back;
-
- // Clear
- {
- RECT rc = { 0, 0, g_vpw, g_vph };
- FillRect(hdc, &rc, g_bgbr);
- }
-
- // Draw X
- {
- SelectObject(hdc, g_pen);
- MoveToEx(hdc, 0, 0, 0);
- LineTo(hdc, g_vpw, g_vph);
- MoveToEx(hdc, 0, g_vph, 0);
- LineTo(hdc, g_vpw, 0);
- }
-
- // Draw rotating triangle
- {
- int cx = g_vpw / 2;
- int cy = g_vph / 2;
- int r = (g_vpw < g_vph ? g_vpw : g_vph) / 3;
-
- POINT verts[3];
- for (int i = 0; i < 3; ++i)
- {
- float ang = ((float)frame / 100.0f) + (float)i * (2.0f * 3.14159265f / 3.0f);
- verts[i].x = cx + (int)(cosf(ang) * r);
- verts[i].y = cy + (int)(sinf(ang) * r);
- }
-
- SelectObject(hdc, g_pen);
- SelectObject(hdc, g_fgbr);
- Polygon(hdc, verts, ARRAYSIZE(verts));
- }
-
- // Draw text
- {
- WCHAR txtbuf[256];
- _snwprintf_s(txtbuf, ARRAYSIZE(txtbuf), _TRUNCATE, L"win-resize (frame %u)", frame);
-
- SIZE sz;
- GetTextExtentPoint32W(hdc, txtbuf, (int)wcslen(txtbuf), &sz);
-
- SetBkMode(hdc, TRANSPARENT);
- SetTextColor(hdc, RGB(0xE0, 0xE0, 0xE0));
- TextOutW(hdc, (g_vpw - sz.cx) / 2, 19, txtbuf, (int)wcslen(txtbuf));
- }
-
- // Present
- BitBlt(g_hdc, 0, 0, g_vpw, g_vph, g_hdc_back, 0, 0, SRCCOPY);
-
- // Wait for dwm to display a frame
- DwmFlush();
- }
-}
-
+// ================================================================================================
+// Example of how to draw while resizing / moving a window on Windows in C.
+//
+// Window contents are rendered via GDI, but the behavior is the same no matter what graphics API
+// you use. The original version of this demo (on old-20260427 branch) used D3D11.
+//
+// Pretty much all modern Direct3D Windows apps use a render thread and therefore don't have to
+// deal with this problem. That strategy doesn't work with APIs that have weird thread affinity
+// issues (OpenGL), so this is one way of doing it without multithreading.
+//
+// Build (MSVC):
+// > cl /W4 /Od /Zi win-resize-st.c /Fe:win-resize-st.exe
+// Build (GCC/clang):
+// $ cc -o win-resize-st.exe -Wall -Wextra -Wpedantic -O0 -g win-resize-st.c -ldwmapi -lgdi32
+//
+// Changelog:
+// 5/15/2026: Initial release
+//
+// License:
+// Copyright (c) 2026 Hunter Kvalevog
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+// WITH REGARD TO THIS SOFTWARE.
+// ================================================================================================
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <dwmapi.h>
+
+#include <assert.h>
+#include <math.h>
+#include <stdio.h>
+
+#ifdef _MSC_VER
+# pragma comment(lib, "dwmapi.lib")
+# pragma comment(lib, "gdi32.lib")
+# pragma comment(lib, "user32.lib")
+#endif
+
+#define UNUSED(Var) ((void)(Var))
+
+static void GfxInit(HWND wnd);
+static void GfxResize(UINT vpw, UINT vph);
+static void GfxDraw(void);
+
+//
+static LRESULT CALLBACK WndProc(HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam)
+{
+ switch (msg)
+ {
+ case WM_DESTROY:
+ PostQuitMessage(0);
+ return 0;
+ case WM_SIZE:
+ GfxResize(LOWORD(lparam), HIWORD(lparam));
+ GfxDraw();
+ break;
+ case WM_ENTERSIZEMOVE:
+ SetTimer(wnd, 1, USER_TIMER_MINIMUM, 0);
+ break;
+ case WM_EXITSIZEMOVE:
+ KillTimer(wnd, 1);
+ break;
+ case WM_TIMER:
+ GfxDraw();
+ break;
+ }
+ return DefWindowProcW(wnd, msg, wparam, lparam);
+}
+
+//
+int WinMain(HINSTANCE instance, HINSTANCE previnstance, LPSTR cmdline, int cmdshow)
+{
+ UNUSED(previnstance); UNUSED(cmdline);
+
+ // Register window class
+ WNDCLASSEXW wc = { 0 };
+ wc.cbSize = sizeof(wc);
+ wc.hCursor = LoadCursor(0, IDC_ARROW);
+ wc.hInstance = instance;
+ wc.lpfnWndProc = WndProc;
+ wc.lpszClassName = L"win-resize-st";
+
+ ATOM atom = RegisterClassExW(&wc);
+ assert(atom && "Failed to register window class");
+
+ // Create window
+ HWND wnd = CreateWindowExW(WS_EX_APPWINDOW, wc.lpszClassName, wc.lpszClassName,
+ WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
+ CW_USEDEFAULT, 0, 0, wc.hInstance, 0);
+ assert(wnd && "Failed to create window");
+
+ //
+ GfxInit(wnd);
+
+ //
+ ShowWindow(wnd, cmdshow);
+
+ // Run a typical D3D-style window loop
+ BOOL quit = FALSE;
+ while (!quit)
+ {
+ // Pump the message loop
+ MSG msg;
+ while (PeekMessageW(&msg, 0, 0, 0, PM_REMOVE))
+ {
+ quit |= (msg.message == WM_QUIT);
+ TranslateMessage(&msg);
+ DispatchMessageW(&msg);
+ }
+
+ // Update the screen
+ GfxDraw();
+ }
+
+ return 0;
+}
+
+// ================================================================================================
+
+static UINT g_vpw = 0;
+static UINT g_vph = 0;
+static HDC g_hdc = 0;
+static HDC g_hdc_back = 0;
+static HBITMAP g_bmp = 0;
+static HBRUSH g_bgbr = 0;
+static HBRUSH g_fgbr = 0;
+static HPEN g_pen = 0;
+
+static void GfxInit(HWND wnd)
+{
+ g_hdc = GetDC(wnd);
+ g_hdc_back = CreateCompatibleDC(g_hdc);
+ g_bgbr = CreateSolidBrush(RGB(0x00, 0x20, 0x20));
+ g_fgbr = CreateSolidBrush(RGB(0xE0, 0xE0, 0xE0));
+ g_pen = CreatePen(PS_SOLID, 2, RGB(0xFF, 0x10, 0x10));
+
+ RECT rc;
+ GetClientRect(wnd, &rc);
+
+ GfxResize(rc.right, rc.bottom);
+}
+
+static void GfxResize(UINT vpw, UINT vph)
+{
+ if (g_bmp)
+ {
+ DeleteObject(g_bmp);
+ g_bmp = 0;
+ }
+
+ if (vpw > 0 && vph > 0)
+ {
+ g_bmp = CreateCompatibleBitmap(g_hdc, vpw, vph);
+ SelectObject(g_hdc_back, g_bmp);
+ }
+
+ g_vpw = vpw;
+ g_vph = vph;
+}
+
+static void GfxDraw(void)
+{
+ static UINT frame = 0;
+ ++frame;
+
+ if (g_bmp && g_vpw > 0 && g_vph > 0)
+ {
+ HDC hdc = g_hdc_back;
+
+ // Clear
+ {
+ RECT rc = { 0, 0, g_vpw, g_vph };
+ FillRect(hdc, &rc, g_bgbr);
+ }
+
+ // Draw X
+ {
+ SelectObject(hdc, g_pen);
+ MoveToEx(hdc, 0, 0, 0);
+ LineTo(hdc, g_vpw, g_vph);
+ MoveToEx(hdc, 0, g_vph, 0);
+ LineTo(hdc, g_vpw, 0);
+ }
+
+ // Draw rotating triangle
+ {
+ int cx = g_vpw / 2;
+ int cy = g_vph / 2;
+ int r = (g_vpw < g_vph ? g_vpw : g_vph) / 3;
+
+ POINT verts[3];
+ for (int i = 0; i < 3; ++i)
+ {
+ float ang = ((float)frame / 100.0f) + (float)i * (2.0f * 3.14159265f / 3.0f);
+ verts[i].x = cx + (int)(cosf(ang) * r);
+ verts[i].y = cy + (int)(sinf(ang) * r);
+ }
+
+ SelectObject(hdc, g_pen);
+ SelectObject(hdc, g_fgbr);
+ Polygon(hdc, verts, ARRAYSIZE(verts));
+ }
+
+ // Draw text
+ {
+ WCHAR txtbuf[256];
+ _snwprintf_s(txtbuf, ARRAYSIZE(txtbuf), _TRUNCATE, L"win-resize-st (frame %u)", frame);
+
+ SIZE sz;
+ GetTextExtentPoint32W(hdc, txtbuf, (int)wcslen(txtbuf), &sz);
+
+ SetBkMode(hdc, TRANSPARENT);
+ SetTextColor(hdc, RGB(0xE0, 0xE0, 0xE0));
+ TextOutW(hdc, (g_vpw - sz.cx) / 2, 19, txtbuf, (int)wcslen(txtbuf));
+ }
+
+ // Present
+ BitBlt(g_hdc, 0, 0, g_vpw, g_vph, g_hdc_back, 0, 0, SRCCOPY);
+
+ // Wait for dwm to display a frame
+ DwmFlush();
+ }
+}
+
diff --git a/win-resize/build.bat b/win-resize/build.bat
deleted file mode 100644
index 14ca49c..0000000
--- a/win-resize/build.bat
+++ /dev/null
@@ -1,3 +0,0 @@
-@echo off
-if not exist bin mkdir bin
-cl /W4 /Od /Zi /Fe:bin\win-resize.exe win-resize.c /Fd:bin\ /Fo:bin\
diff --git a/win-resize/build.sh b/win-resize/build.sh
deleted file mode 100755
index 4d3a4ab..0000000
--- a/win-resize/build.sh
+++ /dev/null
@@ -1,3 +0,0 @@
-#!/bin/bash
-mkdir -p bin
-cc -o bin/win-resize -Wall -Wextra -Wpedantic -O0 -g ./win-resize.c -ldwmapi -lgdi32