diff options
| author | Hunter Kvalevog <hunter@kvog.sh> | 2026-05-21 13:43:03 -0500 |
|---|---|---|
| committer | Hunter Kvalevog <hunter@kvog.sh> | 2026-05-21 15:11:09 -0500 |
| commit | df2c43b689d9a181fee8737ec7d7a31d07631126 (patch) | |
| tree | 91793bf845e6eef5fed63fca1f56bb0ee6c6b38f | |
| parent | 7609a834a1fbadfa8577d066f40b593fde2f0047 (diff) | |
| -rw-r--r-- | win-resize-mt/build.sh | 3 | ||||
| -rw-r--r-- | win-resize-mt/win-resize-mt.c | 277 | ||||
| -rw-r--r-- | win-resize-st/build.bat | 3 | ||||
| -rw-r--r-- | win-resize-st/build.sh | 3 | ||||
| -rw-r--r-- | win-resize-st/win-resize-st.c (renamed from win-resize/win-resize.c) | 457 | ||||
| -rw-r--r-- | win-resize/build.bat | 3 | ||||
| -rwxr-xr-x | win-resize/build.sh | 3 |
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 |