Grabby/Overlay.c
snow flurry be95698d10 OverlayWndProc: Fix flickering issue
The flickering was caused by DefWindowProc trying to erase the background, then GDI painting back in the bitmap. By not letting DefWindowProc draw the background, flickering is effectively removed.

git-svn-id: svn://vcs.sdm.2ki.xyz/Grabby/trunk@15 27729192-006e-004d-b9b5-06fbd0ef7001
2024-02-20 02:37:01 +00:00

234 lines
4.9 KiB
C

#include "stdafx.h"
#include "Bitmap.h"
LRESULT CALLBACK OverlayWndProc(HWND, UINT, WPARAM, LPARAM);
#define OVERLAY_CLASS _T("GrabbyOverlay")
#define OVERLAY_TITLE _T("Grabby Overlay")
// Static function to store and retrieve the overlay-chosen rect.
static void
SetGetRect(BOOL set, RECT *r)
{
static RECT rcMain = {0};
if (r) {
if (set) {
CopyMemory(&rcMain, r, sizeof(RECT));
} else {
CopyMemory(r, &rcMain, sizeof(RECT));
}
}
return;
}
void
GetChosenRect(RECT *rcOut)
{
SetGetRect(FALSE, rcOut);
return;
}
int
CreateOverlay(HINSTANCE hInstance,
Screen *scrn)
{
HWND hWnd = NULL;
RECT rcScreen = {0};
MSG msg = {0};
BOOL bRet;
WNDCLASSEX wcClass = {
sizeof(WNDCLASSEX),
CS_HREDRAW | CS_VREDRAW,
OverlayWndProc,
0,
0,
hInstance,
LoadIcon(NULL, IDI_APPLICATION),
LoadCursor(NULL, IDC_CROSS),
(HBRUSH)( COLOR_WINDOW + 1 ),
OVERLAY_TITLE,
OVERLAY_CLASS,
NULL
};
if (!RegisterClassEx(&wcClass)) {
return -1;
}
if (!GetRgnBox(scrn->hScreenRgn, &rcScreen)) {
UnregisterClass(OVERLAY_CLASS, hInstance);
return -1;
}
hWnd = CreateWindowEx(
WS_EX_TOPMOST,
OVERLAY_CLASS,
OVERLAY_TITLE,
WS_VISIBLE | WS_POPUP,
rcScreen.left,
rcScreen.top,
rcScreen.right - rcScreen.left,
rcScreen.bottom - rcScreen.top,
NULL,
NULL,
hInstance,
scrn);
if (!hWnd) {
UnregisterClass(OVERLAY_CLASS, hInstance);
return -1;
}
ShowWindow(hWnd, SW_SHOWNORMAL);
while ((bRet = GetMessage(&msg, hWnd, 0, 0)) != 0) {
if (bRet == -1) {
// TODO: error handling
break;
} else {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
if (hWnd) DestroyWindow(hWnd);
UnregisterClass(OVERLAY_CLASS, hInstance);
return (int)msg.wParam;
}
// Left, Top, Right, Bottom
#define POINT2RECT(a,b) { \
min(a.x, b.x), \
min(a.y, b.y), \
max(a.x, b.x), \
max(a.y, b.y) \
}
LRESULT CALLBACK
OverlayWndProc(HWND hWnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam)
{
HDC hDC = NULL;
PAINTSTRUCT ps = {0};
static POINTS ptStart = {0}, // Starting drag point
ptCur = {0}; // Current/end drag point
static BOOL isDrag = FALSE; // Are we mid-drag?
static Screen *scrn = NULL; // Screen data
static RECT rcScreen = {0};
static HGDIOBJ hOldObj = NULL;
switch (uMsg) {
case WM_CREATE:
{
HDC dcWnd = GetDC(hWnd);
// Get the Screen object passed in from CreateWindowEx
HBITMAP hOldBmp = NULL;
LPCREATESTRUCT csCreate = (LPCREATESTRUCT)lParam;
if (csCreate && csCreate->lpCreateParams) {
scrn = (Screen *)csCreate->lpCreateParams;
if (!scrn) {
// uhhhhhhhhh
MessageBox(hWnd,
_T("Couldn't get screen info for mysterious reasons !?"),
_T("Fatal Error"),
MB_OK | MB_ICONERROR);
PostQuitMessage(1);
return 1;
}
GetRgnBox(scrn->hScreenRgn, &rcScreen);
if (!SnapScreen(scrn)) {
MessageBox(hWnd,
_T("Couldn't store screen data !!"),
_T("Fatal Error"),
MB_OK | MB_ICONERROR);
PostQuitMessage(1);
return 1;
}
}
}
/* PASSTHRU */
case WM_PAINT:
hDC = BeginPaint(hWnd, &ps);
if (scrn->hBitmap) {
// Draw the "background"
if (!BitBlt(hDC,
ps.rcPaint.left,
ps.rcPaint.top,
ps.rcPaint.right - ps.rcPaint.left,
ps.rcPaint.bottom - ps.rcPaint.top,
scrn->hdcBitmap,
rcScreen.left + ps.rcPaint.left,
rcScreen.top + ps.rcPaint.top,
SRCCOPY))
{
// walk it off, I guess...
OutputDebugString(_T("Failed to blit background to DC..."));
}
}
if (isDrag && hDC) {
RECT rcOuter = POINT2RECT(ptStart, ptCur);
DrawFocusRect(hDC, &rcOuter);
}
EndPaint(hWnd, &ps);
break;
case WM_ERASEBKGND:
// Do nothing
return 1;
case WM_MOUSEMOVE:
if (isDrag && (wParam & MK_LBUTTON)) {
POINTS ptPrev = ptCur;
ptCur = MAKEPOINTS(lParam);
if ((ptCur.x != ptStart.x) &&
(ptCur.y != ptStart.y))
{
RECT rcPrevDmg = POINT2RECT(ptStart, ptPrev);
// Expand out a little bit to contain the focus rect
rcPrevDmg.left--;
rcPrevDmg.right++;
rcPrevDmg.top--;
rcPrevDmg.bottom++;
InvalidateRect(hWnd, &rcPrevDmg, TRUE);
}
}
break;
case WM_LBUTTONDOWN:
if (!isDrag) {
// Start the drag operation and set the origin
ptStart = ptCur = MAKEPOINTS(lParam);
isDrag = TRUE;
}
break;
case WM_LBUTTONUP:
if (isDrag) {
// Done dragging, store the rect and get out of here
RECT rcFinal = POINT2RECT(ptStart, ptCur);
SetGetRect(TRUE, &rcFinal);
isDrag = FALSE;
PostQuitMessage(0);
}
break;
case WM_KEYUP:
if (wParam != VK_ESCAPE) {
break;
}
/* PASSTHRU */
case WM_RBUTTONUP:
// We treat right click as Escape
PostQuitMessage(1);
break;
default:
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
return 0;
}