1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
|
// 26 april 2015
#include "uipriv_windows.hpp"
// This contains code used by all uiControls that contain other controls.
// It also contains the code to draw the background of a container.c container, as that is a variant of the WM_CTLCOLORxxx handler code.
static HBRUSH parentBrush = NULL;
static HWND parentWithBackground(HWND hwnd)
{
HWND parent;
int cls;
parent = hwnd;
for (;;) {
parent = parentOf(parent);
// skip groupboxes; they're (supposed to be) transparent
// skip uiContainers; they don't draw anything
cls = windowClassOf(parent, L"button", containerClass, NULL);
if (cls != 0 && cls != 1)
break;
}
return parent;
}
struct parentDraw {
HDC cdc;
HBITMAP bitmap;
HBITMAP prevbitmap;
};
static HRESULT parentDraw(HDC dc, HWND parent, struct parentDraw *pd)
{
RECT r;
uiWindowsEnsureGetClientRect(parent, &r);
pd->cdc = CreateCompatibleDC(dc);
if (pd->cdc == NULL)
return logLastError(L"error creating compatible DC");
pd->bitmap = CreateCompatibleBitmap(dc, r.right - r.left, r.bottom - r.top);
if (pd->bitmap == NULL)
return logLastError(L"error creating compatible bitmap");
pd->prevbitmap = (HBITMAP) SelectObject(pd->cdc, pd->bitmap);
if (pd->prevbitmap == NULL)
return logLastError(L"error selecting bitmap into compatible DC");
SendMessageW(parent, WM_PRINTCLIENT, (WPARAM) (pd->cdc), PRF_CLIENT);
return S_OK;
}
static void endParentDraw(struct parentDraw *pd)
{
// continue in case of any error
if (pd->prevbitmap != NULL)
if (((HBITMAP) SelectObject(pd->cdc, pd->prevbitmap)) != pd->bitmap)
logLastError(L"error selecting previous bitmap back into compatible DC");
if (pd->bitmap != NULL)
if (DeleteObject(pd->bitmap) == 0)
logLastError(L"error deleting compatible bitmap");
if (pd->cdc != NULL)
if (DeleteDC(pd->cdc) == 0)
logLastError(L"error deleting compatible DC");
}
// see http://www.codeproject.com/Articles/5978/Correctly-drawn-themed-dialogs-in-WinXP
static HBRUSH getControlBackgroundBrush(HWND hwnd, HDC dc)
{
HWND parent;
RECT hwndScreenRect;
struct parentDraw pd;
HBRUSH brush;
HRESULT hr;
parent = parentWithBackground(hwnd);
hr = parentDraw(dc, parent, &pd);
if (hr != S_OK)
return NULL;
brush = CreatePatternBrush(pd.bitmap);
if (brush == NULL) {
logLastError(L"error creating pattern brush");
endParentDraw(&pd);
return NULL;
}
endParentDraw(&pd);
// now figure out where the control is relative to the parent so we can align the brush properly
// if anything fails, give up and return the brush as-is
uiWindowsEnsureGetWindowRect(hwnd, &hwndScreenRect);
// this will be in screen coordinates; convert to parent coordinates
mapWindowRect(NULL, parent, &hwndScreenRect);
if (SetBrushOrgEx(dc, -hwndScreenRect.left, -hwndScreenRect.top, NULL) == 0)
logLastError(L"error setting brush origin");
return brush;
}
void paintContainerBackground(HWND hwnd, HDC dc, RECT *paintRect)
{
HWND parent;
RECT paintRectParent;
struct parentDraw pd;
HRESULT hr;
parent = parentWithBackground(hwnd);
hr = parentDraw(dc, parent, &pd);
if (hr != S_OK) // we couldn't get it; draw nothing
return;
paintRectParent = *paintRect;
mapWindowRect(hwnd, parent, &paintRectParent);
if (BitBlt(dc, paintRect->left, paintRect->top, paintRect->right - paintRect->left, paintRect->bottom - paintRect->top,
pd.cdc, paintRectParent.left, paintRectParent.top,
SRCCOPY) == 0)
logLastError(L"error drawing parent background over uiContainer");
endParentDraw(&pd);
}
// TODO make this public if we want custom containers
// why have this to begin with? http://blogs.msdn.com/b/oldnewthing/archive/2010/03/16/9979112.aspx
BOOL handleParentMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *lResult)
{
switch (uMsg) {
case WM_COMMAND:
return runWM_COMMAND(wParam, lParam, lResult);
case WM_NOTIFY:
return runWM_NOTIFY(wParam, lParam, lResult);
case WM_HSCROLL:
return runWM_HSCROLL(wParam, lParam, lResult);
case WM_CTLCOLORSTATIC:
case WM_CTLCOLORBTN:
if (parentBrush != NULL)
if (DeleteObject(parentBrush) == 0)
logLastError(L"error deleting old background brush()"); // but continue anyway; we will leak a brush but whatever
if (SetBkMode((HDC) wParam, TRANSPARENT) == 0)
logLastError(L"error setting transparent background mode to controls"); // but continue anyway; text will be wrong
parentBrush = getControlBackgroundBrush((HWND) lParam, (HDC) wParam);
if (parentBrush == NULL) // failed; just do default behavior
return FALSE;
*lResult = (LRESULT) parentBrush;
return TRUE;
}
return FALSE;
}
|