xref: /aosp_15_r20/external/lzma/CPP/Windows/Control/Dialog.cpp (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
1 // Windows/Control/Dialog.cpp
2 
3 #include "StdAfx.h"
4 
5 // #include "../../Windows/DLL.h"
6 
7 #ifndef _UNICODE
8 #include "../../Common/StringConvert.h"
9 #endif
10 
11 #include "Dialog.h"
12 
13 extern HINSTANCE g_hInstance;
14 #ifndef _UNICODE
15 extern bool g_IsNT;
16 #endif
17 
18 namespace NWindows {
19 namespace NControl {
20 
21 static
22 #ifdef Z7_OLD_WIN_SDK
23   BOOL
24 #else
25   INT_PTR
26 #endif
27 APIENTRY
DialogProcedure(HWND dialogHWND,UINT message,WPARAM wParam,LPARAM lParam)28 DialogProcedure(HWND dialogHWND, UINT message, WPARAM wParam, LPARAM lParam)
29 {
30   CWindow tempDialog(dialogHWND);
31   if (message == WM_INITDIALOG)
32     tempDialog.SetUserDataLongPtr(lParam);
33   CDialog *dialog = (CDialog *)(tempDialog.GetUserDataLongPtr());
34   if (dialog == NULL)
35     return FALSE;
36   if (message == WM_INITDIALOG)
37     dialog->Attach(dialogHWND);
38 
39   /* MSDN: The dialog box procedure should return
40        TRUE  - if it processed the message
41        FALSE - if it did not process the message
42      If the dialog box procedure returns FALSE,
43      the dialog manager performs the default dialog operation in response to the message.
44   */
45 
46   try { return BoolToBOOL(dialog->OnMessage(message, wParam, lParam)); }
47   catch(...) { return TRUE; }
48 }
49 
OnMessage(UINT message,WPARAM wParam,LPARAM lParam)50 bool CDialog::OnMessage(UINT message, WPARAM wParam, LPARAM lParam)
51 {
52   switch (message)
53   {
54     case WM_INITDIALOG: return OnInit();
55     case WM_COMMAND: return OnCommand(HIWORD(wParam), LOWORD(wParam), lParam);
56     case WM_NOTIFY: return OnNotify((UINT)wParam, (LPNMHDR) lParam);
57     case WM_TIMER: return OnTimer(wParam, lParam);
58     case WM_SIZE: return OnSize(wParam, LOWORD(lParam), HIWORD(lParam));
59     case WM_DESTROY: return OnDestroy();
60     case WM_HELP: OnHelp(); return true;
61     /*
62         OnHelp(
63           #ifdef UNDER_CE
64           (void *)
65           #else
66           (LPHELPINFO)
67           #endif
68           lParam);
69         return true;
70     */
71     default: return false;
72   }
73 }
74 
75 /*
76 bool CDialog::OnCommand2(WPARAM wParam, LPARAM lParam)
77 {
78   return OnCommand(HIWORD(wParam), LOWORD(wParam), lParam);
79 }
80 */
81 
OnCommand(unsigned code,unsigned itemID,LPARAM lParam)82 bool CDialog::OnCommand(unsigned code, unsigned itemID, LPARAM lParam)
83 {
84   if (code == BN_CLICKED)
85     return OnButtonClicked(itemID, (HWND)lParam);
86   return false;
87 }
88 
OnButtonClicked(unsigned buttonID,HWND)89 bool CDialog::OnButtonClicked(unsigned buttonID, HWND /* buttonHWND */)
90 {
91   switch (buttonID)
92   {
93     case IDOK: OnOK(); break;
94     case IDCANCEL: OnCancel(); break;
95     case IDCLOSE: OnClose(); break;
96     case IDCONTINUE: OnContinue(); break;
97     case IDHELP: OnHelp(); break;
98     default: return false;
99   }
100   return true;
101 }
102 
103 #ifndef UNDER_CE
104 /* in win2000/win98 : monitor functions are supported.
105    We need dynamic linking, if we want nt4/win95 support in program.
106    Even if we compile the code with low (WINVER) value, we still
107    want to use monitor functions. So we declare missing functions here */
108 // #if (WINVER < 0x0500)
109 #ifndef MONITOR_DEFAULTTOPRIMARY
110 extern "C" {
111 DECLARE_HANDLE(HMONITOR);
112 #define MONITOR_DEFAULTTOPRIMARY    0x00000001
113 typedef struct tagMONITORINFO
114 {
115     DWORD   cbSize;
116     RECT    rcMonitor;
117     RECT    rcWork;
118     DWORD   dwFlags;
119 } MONITORINFO, *LPMONITORINFO;
120 WINUSERAPI HMONITOR WINAPI MonitorFromWindow(HWND hwnd, DWORD dwFlags);
121 WINUSERAPI BOOL WINAPI GetMonitorInfoA(HMONITOR hMonitor, LPMONITORINFO lpmi);
122 }
123 #endif
124 #endif
125 
GetWorkAreaRect(RECT * rect,HWND hwnd)126 static bool GetWorkAreaRect(RECT *rect, HWND hwnd)
127 {
128   if (hwnd)
129   {
130     #ifndef UNDER_CE
131     /* MonitorFromWindow() is supported in Win2000+
132        MonitorFromWindow() : retrieves a handle to the display monitor that has the
133          largest area of intersection with the bounding rectangle of a specified window.
134        dwFlags: Determines the function's return value if the window does not intersect any display monitor.
135          MONITOR_DEFAULTTONEAREST : Returns display that is nearest to the window.
136          MONITOR_DEFAULTTONULL    : Returns NULL.
137          MONITOR_DEFAULTTOPRIMARY : Returns the primary display monitor.
138     */
139     const HMONITOR hmon = MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY);
140     if (hmon)
141     {
142       MONITORINFO mi;
143       memset(&mi, 0, sizeof(mi));
144       mi.cbSize = sizeof(mi);
145       if (GetMonitorInfoA(hmon, &mi))
146       {
147         *rect = mi.rcWork;
148         return true;
149       }
150     }
151     #endif
152   }
153 
154   /* Retrieves the size of the work area on the primary display monitor.
155      The work area is the portion of the screen not obscured
156      by the system taskbar or by application desktop toolbars.
157      Any DPI virtualization mode of the caller has no effect on this output. */
158 
159   return BOOLToBool(::SystemParametersInfo(SPI_GETWORKAREA, 0, rect, 0));
160 }
161 
162 
IsDialogSizeOK(int xSize,int ySize,HWND hwnd)163 bool IsDialogSizeOK(int xSize, int ySize, HWND hwnd)
164 {
165   // it returns for system font. Real font uses another values
166   const LONG v = GetDialogBaseUnits();
167   const int x = LOWORD(v);
168   const int y = HIWORD(v);
169 
170   RECT rect;
171   GetWorkAreaRect(&rect, hwnd);
172   const int wx = RECT_SIZE_X(rect);
173   const int wy = RECT_SIZE_Y(rect);
174   return
175     xSize / 4 * x <= wx &&
176     ySize / 8 * y <= wy;
177 }
178 
GetMargins(int margin,int & x,int & y)179 bool CDialog::GetMargins(int margin, int &x, int &y)
180 {
181   x = margin;
182   y = margin;
183   RECT rect;
184   rect.left = 0;
185   rect.top = 0;
186   rect.right = margin;
187   rect.bottom = margin;
188   if (!MapRect(&rect))
189     return false;
190   x = rect.right - rect.left;
191   y = rect.bottom - rect.top;
192   return true;
193 }
194 
Units_To_Pixels_X(int units)195 int CDialog::Units_To_Pixels_X(int units)
196 {
197   RECT rect;
198   rect.left = 0;
199   rect.top = 0;
200   rect.right = units;
201   rect.bottom = units;
202   if (!MapRect(&rect))
203     return units * 3 / 2;
204   return rect.right - rect.left;
205 }
206 
GetItemSizes(unsigned id,int & x,int & y)207 bool CDialog::GetItemSizes(unsigned id, int &x, int &y)
208 {
209   RECT rect;
210   if (!::GetWindowRect(GetItem(id), &rect))
211     return false;
212   x = RECT_SIZE_X(rect);
213   y = RECT_SIZE_Y(rect);
214   return true;
215 }
216 
GetClientRectOfItem(unsigned id,RECT & rect)217 void CDialog::GetClientRectOfItem(unsigned id, RECT &rect)
218 {
219   ::GetWindowRect(GetItem(id), &rect);
220   ScreenToClient(&rect);
221 }
222 
MoveItem(unsigned id,int x,int y,int width,int height,bool repaint)223 bool CDialog::MoveItem(unsigned id, int x, int y, int width, int height, bool repaint)
224 {
225   return BOOLToBool(::MoveWindow(GetItem(id), x, y, width, height, BoolToBOOL(repaint)));
226 }
227 
228 
229 /*
230 typedef BOOL (WINAPI * Func_DwmGetWindowAttribute)(
231     HWND hwnd, DWORD dwAttribute, PVOID pvAttribute, DWORD cbAttribute);
232 
233 static bool GetWindowsRect_DWM(HWND hwnd, RECT *rect)
234 {
235   // dll load and free is too slow : 300 calls in second.
236   NDLL::CLibrary dll;
237   if (!dll.Load(FTEXT("dwmapi.dll")))
238     return false;
239   Func_DwmGetWindowAttribute f = (Func_DwmGetWindowAttribute)dll.GetProc("DwmGetWindowAttribute" );
240   if (f)
241   {
242     #define MY__DWMWA_EXTENDED_FRAME_BOUNDS 9
243     // 30000 per second
244     RECT r;
245     if (f(hwnd, MY__DWMWA_EXTENDED_FRAME_BOUNDS, &r, sizeof(RECT)) == S_OK)
246     {
247       *rect = r;
248       return true;
249     }
250   }
251   return false;
252 }
253 */
254 
255 
IsRect_Small_Inside_Big(const RECT & sm,const RECT & big)256 static bool IsRect_Small_Inside_Big(const RECT &sm, const RECT &big)
257 {
258   return sm.left   >= big.left
259       && sm.right  <= big.right
260       && sm.top    >= big.top
261       && sm.bottom <= big.bottom;
262 }
263 
264 
AreRectsOverlapped(const RECT & r1,const RECT & r2)265 static bool AreRectsOverlapped(const RECT &r1, const RECT &r2)
266 {
267   return r1.left   < r2.right
268       && r1.right  > r2.left
269       && r1.top    < r2.bottom
270       && r1.bottom > r2.top;
271 }
272 
273 
AreRectsEqual(const RECT & r1,const RECT & r2)274 static bool AreRectsEqual(const RECT &r1, const RECT &r2)
275 {
276   return r1.left   == r2.left
277       && r1.right  == r2.right
278       && r1.top    == r2.top
279       && r1.bottom == r2.bottom;
280 }
281 
282 
NormalizeSize(bool fullNormalize)283 void CDialog::NormalizeSize(bool fullNormalize)
284 {
285   RECT workRect;
286   if (!GetWorkAreaRect(&workRect, *this))
287     return;
288   RECT rect;
289   if (!GetWindowRect(&rect))
290     return;
291   int xs = RECT_SIZE_X(rect);
292   int ys = RECT_SIZE_Y(rect);
293 
294   // we don't want to change size using workRect, if window is outside of WorkArea
295   if (!AreRectsOverlapped(rect, workRect))
296     return;
297 
298   /* here rect and workRect are overlapped, but it can be false
299      overlapping of small shadow when window in another display. */
300 
301   const int xsW = RECT_SIZE_X(workRect);
302   const int ysW = RECT_SIZE_Y(workRect);
303   if (xs <= xsW && ys <= ysW)
304     return; // size of window is OK
305   if (fullNormalize)
306   {
307     Show(SW_SHOWMAXIMIZED);
308     return;
309   }
310   int x = workRect.left;
311   int y = workRect.top;
312   if (xs < xsW)  x += (xsW - xs) / 2;  else xs = xsW;
313   if (ys < ysW)  y += (ysW - ys) / 2;  else ys = ysW;
314   Move(x, y, xs, ys, true);
315 }
316 
317 
NormalizePosition()318 void CDialog::NormalizePosition()
319 {
320   RECT workRect;
321   if (!GetWorkAreaRect(&workRect, *this))
322     return;
323 
324   RECT rect2 = workRect;
325   bool useWorkArea = true;
326   const HWND parentHWND = GetParent();
327 
328   if (parentHWND)
329   {
330     RECT workRectParent;
331     if (!GetWorkAreaRect(&workRectParent, parentHWND))
332       return;
333 
334     // if windows are in different monitors, we use only workArea of current window
335 
336     if (AreRectsEqual(workRectParent, workRect))
337     {
338       // RECT rect3; if (GetWindowsRect_DWM(parentHWND, &rect3)) {}
339       CWindow wnd(parentHWND);
340       if (wnd.GetWindowRect(&rect2))
341       {
342         // it's same monitor. So we try to use parentHWND rect.
343         /* we don't want to change position, if parent window is not inside work area.
344            In Win10 : parent window rect is 8 pixels larger for each corner than window size for shadow.
345            In maximize mode : window is outside of workRect.
346            if parent window is inside workRect, we will use parent window instead of workRect */
347         if (IsRect_Small_Inside_Big(rect2, workRect))
348           useWorkArea = false;
349       }
350     }
351   }
352 
353   RECT rect;
354   if (!GetWindowRect(&rect))
355     return;
356 
357   if (useWorkArea)
358   {
359     // we don't want to move window, if it's already inside.
360     if (IsRect_Small_Inside_Big(rect, workRect))
361       return;
362     // we don't want to move window, if it's outside of workArea
363     if (!AreRectsOverlapped(rect, workRect))
364       return;
365     rect2 = workRect;
366   }
367 
368   {
369     const int xs = RECT_SIZE_X(rect);
370     const int ys = RECT_SIZE_Y(rect);
371     const int xs2 = RECT_SIZE_X(rect2);
372     const int ys2 = RECT_SIZE_Y(rect2);
373     // we don't want to change position if parent is smaller.
374     if (xs <= xs2 && ys <= ys2)
375     {
376       const int x = rect2.left + (xs2 - xs) / 2;
377       const int y = rect2.top  + (ys2 - ys) / 2;
378 
379       if (x != rect.left || y != rect.top)
380         Move(x, y, xs, ys, true);
381       // SetWindowPos(*this, HWND_TOP, x, y, 0, 0, SWP_NOSIZE);
382       return;
383     }
384   }
385 }
386 
387 
388 
Create(LPCTSTR templateName,HWND parentWindow)389 bool CModelessDialog::Create(LPCTSTR templateName, HWND parentWindow)
390 {
391   const HWND aHWND = CreateDialogParam(g_hInstance, templateName, parentWindow, DialogProcedure, (LPARAM)this);
392   if (!aHWND)
393     return false;
394   Attach(aHWND);
395   return true;
396 }
397 
Create(LPCTSTR templateName,HWND parentWindow)398 INT_PTR CModalDialog::Create(LPCTSTR templateName, HWND parentWindow)
399 {
400   return DialogBoxParam(g_hInstance, templateName, parentWindow, DialogProcedure, (LPARAM)this);
401 }
402 
403 #ifndef _UNICODE
404 
Create(LPCWSTR templateName,HWND parentWindow)405 bool CModelessDialog::Create(LPCWSTR templateName, HWND parentWindow)
406 {
407   HWND aHWND;
408   if (g_IsNT)
409     aHWND = CreateDialogParamW(g_hInstance, templateName, parentWindow, DialogProcedure, (LPARAM)this);
410   else
411   {
412     AString name;
413     LPCSTR templateNameA;
414     if (IS_INTRESOURCE(templateName))
415       templateNameA = (LPCSTR)templateName;
416     else
417     {
418       name = GetSystemString(templateName);
419       templateNameA = name;
420     }
421     aHWND = CreateDialogParamA(g_hInstance, templateNameA, parentWindow, DialogProcedure, (LPARAM)this);
422   }
423   if (aHWND == 0)
424     return false;
425   Attach(aHWND);
426   return true;
427 }
428 
Create(LPCWSTR templateName,HWND parentWindow)429 INT_PTR CModalDialog::Create(LPCWSTR templateName, HWND parentWindow)
430 {
431   if (g_IsNT)
432     return DialogBoxParamW(g_hInstance, templateName, parentWindow, DialogProcedure, (LPARAM)this);
433   AString name;
434   LPCSTR templateNameA;
435   if (IS_INTRESOURCE(templateName))
436     templateNameA = (LPCSTR)templateName;
437   else
438   {
439     name = GetSystemString(templateName);
440     templateNameA = name;
441   }
442   return DialogBoxParamA(g_hInstance, templateNameA, parentWindow, DialogProcedure, (LPARAM)this);
443 }
444 #endif
445 
446 }}
447