OSDN Git Service

3338e9ae562dc617891eaf6d65e536406c6238f7
[mutilities/MUtilities.git] / src / GUI_Win32.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // MuldeR's Utilities for Qt
3 // Copyright (C) 2004-2021 LoRd_MuldeR <MuldeR2@GMX.de>
4 //
5 // This library is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU Lesser General Public
7 // License as published by the Free Software Foundation; either
8 // version 2.1 of the License, or (at your option) any later version.
9 //
10 // This library is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 // Lesser General Public License for more details.
14 //
15 // You should have received a copy of the GNU Lesser General Public
16 // License along with this library; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
18 //
19 // http://www.gnu.org/licenses/lgpl-2.1.txt
20 //////////////////////////////////////////////////////////////////////////////////
21
22 //Win32 API
23 #define WIN32_LEAN_AND_MEAN 1
24 #include <Windows.h>
25
26 //MUtils
27 #include <MUtils/GUI.h>
28 #include <MUtils/OSSupport.h>
29
30 //Internal
31 #include "Utils_Win32.h"
32
33 //Qt
34 #include <QIcon>
35 #include <QApplication>
36 #include <QWidget>
37 #include <QReadWriteLock>
38 #include <Dwmapi.h>
39
40 ///////////////////////////////////////////////////////////////////////////////
41 // THEME SUPPORT
42 ///////////////////////////////////////////////////////////////////////////////
43
44 static QReadWriteLock g_themes_lock;
45 static int g_themes_initialized = 0;
46
47 typedef int (WINAPI *IsAppThemedFunction)(void);
48
49 bool MUtils::GUI::themes_enabled(void)
50 {
51         QReadLocker readLock(&g_themes_lock);
52
53         if(g_themes_initialized != 0)
54         {
55                 return (g_themes_initialized > 0);
56         }
57
58         readLock.unlock();
59         QWriteLocker writeLock(&g_themes_lock);
60
61         if(g_themes_initialized != 0)
62         {
63                 return (g_themes_initialized > 0);
64         }
65
66         const MUtils::OS::Version::os_version_t &osVersion = MUtils::OS::os_version();
67         if(osVersion >= MUtils::OS::Version::WINDOWS_WINXP)
68         {
69                 const IsAppThemedFunction isAppThemedPtr = MUtils::Win32Utils::resolve<IsAppThemedFunction>(QLatin1String("UxTheme"), QLatin1String("IsAppThemed"));
70                 if(isAppThemedPtr)
71                 {
72                         g_themes_initialized = isAppThemedPtr() ? 1 : (-1);
73                         if(g_themes_initialized < 0)
74                         {
75                                 qWarning("Theme support is disabled for this process!");
76                         }
77                 }
78         }
79
80         return (g_themes_initialized > 0);
81 }
82
83 ///////////////////////////////////////////////////////////////////////////////
84 // SYSTEM MENU
85 ///////////////////////////////////////////////////////////////////////////////
86
87 bool MUtils::GUI::sysmenu_append(const QWidget *win, const unsigned int identifier, const QString &text)
88 {
89         bool ok = false;
90         
91         if(HMENU hMenu = GetSystemMenu(reinterpret_cast<HWND>(win->winId()), FALSE))
92         {
93                 ok = (AppendMenuW(hMenu, MF_SEPARATOR, 0, 0) == TRUE);
94                 ok = (AppendMenuW(hMenu, MF_STRING, identifier, MUTILS_WCHR(text)) == TRUE);
95         }
96
97         return ok;
98 }
99
100 bool MUtils::GUI::sysmenu_update(const QWidget *win, const unsigned int identifier, const QString &text)
101 {
102         bool ok = false;
103         
104         if(HMENU hMenu = ::GetSystemMenu(reinterpret_cast<HWND>(win->winId()), FALSE))
105         {
106                 ok = (ModifyMenu(hMenu, identifier, MF_STRING | MF_BYCOMMAND, identifier, MUTILS_WCHR(text)) == TRUE);
107         }
108         return ok;
109 }
110
111 bool MUtils::GUI::sysmenu_check_msg(void *const message, const unsigned int &identifier)
112 {
113         return (((MSG*)message)->message == WM_SYSCOMMAND) && ((((MSG*)message)->wParam & 0xFFF0) == identifier);
114 }
115
116 ///////////////////////////////////////////////////////////////////////////////
117 // CLOSE BUTTON
118 ///////////////////////////////////////////////////////////////////////////////
119
120 bool MUtils::GUI::enable_close_button(const QWidget *win, const bool &bEnable)
121 {
122         bool ok = false;
123
124         if(HMENU hMenu = GetSystemMenu(reinterpret_cast<HWND>(win->winId()), FALSE))
125         {
126                 ok = (EnableMenuItem(hMenu, SC_CLOSE, MF_BYCOMMAND | (bEnable ? MF_ENABLED : MF_GRAYED)) == TRUE);
127         }
128
129         return ok;
130 }
131
132 ///////////////////////////////////////////////////////////////////////////////
133 // BRING WINDOW TO FRONT
134 ///////////////////////////////////////////////////////////////////////////////
135
136 static BOOL CALLBACK bring_process_to_front_helper(HWND hwnd, LPARAM lParam)
137 {
138         DWORD processId = *reinterpret_cast<WORD*>(lParam);
139         DWORD windowProcessId = NULL;
140         GetWindowThreadProcessId(hwnd, &windowProcessId);
141         if(windowProcessId == processId)
142         {
143                 SwitchToThisWindow(hwnd, TRUE);
144                 SetForegroundWindow(hwnd);
145                 return FALSE;
146         }
147
148         return TRUE;
149 }
150
151 bool MUtils::GUI::bring_to_front(const QWidget *window)
152 {
153         bool ret = false;
154         
155         if(window)
156         {
157                 for(int i = 0; (i < 5) && (!ret); i++)
158                 {
159                         ret = (SetForegroundWindow(reinterpret_cast<HWND>(window->winId())) != FALSE);
160                         SwitchToThisWindow(reinterpret_cast<HWND>(window->winId()), TRUE);
161                 }
162                 LockSetForegroundWindow(LSFW_LOCK);
163         }
164
165         return ret;
166 }
167
168 bool MUtils::GUI::bring_to_front(const unsigned long pid)
169 {
170         return EnumWindows(bring_process_to_front_helper, reinterpret_cast<LPARAM>(&pid)) == TRUE;
171 }
172
173 ///////////////////////////////////////////////////////////////////////////////
174 // SHEET OF GLASS EFFECT
175 ///////////////////////////////////////////////////////////////////////////////
176
177 typedef HRESULT (__stdcall *DwmIsCompositionEnabledFun)      (BOOL *bEnabled);
178 typedef HRESULT (__stdcall *DwmExtendFrameIntoClientAreaFun) (HWND hWnd, const MARGINS* pMarInset);
179 typedef HRESULT (__stdcall *DwmEnableBlurBehindWindowFun)    (HWND hWnd, const DWM_BLURBEHIND* pBlurBehind);
180
181 bool MUtils::GUI::sheet_of_glass(QWidget *const window)
182 {
183         const DwmIsCompositionEnabledFun      dwmIsCompositionEnabledFun      = MUtils::Win32Utils::resolve<DwmIsCompositionEnabledFun>     (QLatin1String("dwmapi"), QLatin1String("DwmIsCompositionEnabled")     );
184         const DwmExtendFrameIntoClientAreaFun dwmExtendFrameIntoClientAreaFun = MUtils::Win32Utils::resolve<DwmExtendFrameIntoClientAreaFun>(QLatin1String("dwmapi"), QLatin1String("DwmExtendFrameIntoClientArea"));
185         const DwmEnableBlurBehindWindowFun    dwmEnableBlurBehindWindowFun    = MUtils::Win32Utils::resolve<DwmEnableBlurBehindWindowFun>   (QLatin1String("dwmapi"), QLatin1String("DwmEnableBlurBehindWindow")   );
186
187         //Required functions available?
188         BOOL bCompositionEnabled = FALSE;
189         if(dwmIsCompositionEnabledFun && dwmExtendFrameIntoClientAreaFun && dwmEnableBlurBehindWindowFun)
190         {
191                 //Check if composition is currently enabled
192                 if(HRESULT hr = dwmIsCompositionEnabledFun(&bCompositionEnabled))
193                 {
194                         qWarning("DwmIsCompositionEnabled function has failed! (error %d)", hr);
195                         return false;
196                 }
197         }
198         
199         //All functions available *and* composition enabled?
200         if(!bCompositionEnabled)
201         {
202                 return false;
203         }
204
205         //Enable the "sheet of glass" effect on this window
206         MARGINS margins = {-1, -1, -1, -1};
207         if(HRESULT hr = dwmExtendFrameIntoClientAreaFun(reinterpret_cast<HWND>(window->winId()), &margins))
208         {
209                 qWarning("DwmExtendFrameIntoClientArea function has failed! (error %d)", hr);
210                 return false;
211         }
212
213         //Create and populate the Blur Behind structure
214         if (MUtils::OS::os_version() < MUtils::OS::Version::WINDOWS_WIN11)
215         {
216                 DWM_BLURBEHIND bb;
217                 memset(&bb, 0, sizeof(DWM_BLURBEHIND));
218                 bb.fEnable = TRUE;
219                 bb.dwFlags = DWM_BB_ENABLE;
220                 if (HRESULT hr = dwmEnableBlurBehindWindowFun(reinterpret_cast<HWND>(window->winId()), &bb))
221                 {
222                         qWarning("DwmEnableBlurBehindWindow function has failed! (error %d)", hr);
223                         return false;
224                 }
225         }
226
227         //Required for Qt
228         window->setAutoFillBackground(false);
229         window->setAttribute(Qt::WA_TranslucentBackground);
230         window->setAttribute(Qt::WA_NoSystemBackground);
231
232         return true;
233 }
234
235 bool MUtils::GUI::sheet_of_glass_update(QWidget *const window)
236 {
237         const DwmIsCompositionEnabledFun      dwmIsCompositionEnabledFun      = MUtils::Win32Utils::resolve<DwmIsCompositionEnabledFun>     (QLatin1String("dwmapi"), QLatin1String("DwmIsCompositionEnabled")     );
238         const DwmExtendFrameIntoClientAreaFun dwmExtendFrameIntoClientAreaFun = MUtils::Win32Utils::resolve<DwmExtendFrameIntoClientAreaFun>(QLatin1String("dwmapi"), QLatin1String("DwmExtendFrameIntoClientArea"));
239         const DwmEnableBlurBehindWindowFun    dwmEnableBlurBehindWindowFun    = MUtils::Win32Utils::resolve<DwmEnableBlurBehindWindowFun>   (QLatin1String("dwmapi"), QLatin1String("DwmEnableBlurBehindWindow")   );
240         
241         //Required functions available?
242         BOOL bCompositionEnabled = FALSE;
243         if(dwmIsCompositionEnabledFun && dwmExtendFrameIntoClientAreaFun && dwmEnableBlurBehindWindowFun)
244         {
245                 //Check if composition is currently enabled
246                 if(HRESULT hr = dwmIsCompositionEnabledFun(&bCompositionEnabled))
247                 {
248                         qWarning("DwmIsCompositionEnabled function has failed! (error %d)", hr);
249                         return false;
250                 }
251         }
252         
253         //All functions available *and* composition enabled?
254         if(!bCompositionEnabled)
255         {
256                 return false;
257         }
258
259         //Create and populate the Blur Behind structure
260         DWM_BLURBEHIND bb;
261         memset(&bb, 0, sizeof(DWM_BLURBEHIND));
262         bb.fEnable = TRUE;
263         bb.dwFlags = DWM_BB_ENABLE;
264         if(HRESULT hr = dwmEnableBlurBehindWindowFun(reinterpret_cast<HWND>(window->winId()), &bb))
265         {
266                 qWarning("DwmEnableBlurBehindWindow function has failed! (error %d)", hr);
267                 return false;
268         }
269
270         return true;
271 }
272
273 ///////////////////////////////////////////////////////////////////////////////
274 // SYSTEM COLORS
275 ///////////////////////////////////////////////////////////////////////////////
276
277 QColor MUtils::GUI::system_color(const int &color_id)
278 {
279         int nIndex = -1;
280
281         switch(color_id)
282         {
283         case SYSCOLOR_TEXT:
284                 nIndex = COLOR_WINDOWTEXT;              /*Text in windows*/
285                 break;
286         case SYSCOLOR_BACKGROUND:
287                 nIndex = COLOR_WINDOW;                  /*Window background*/
288                 break;
289         case SYSCOLOR_CAPTION:
290                 nIndex = COLOR_CAPTIONTEXT;             /*Text in caption, size box, and scroll bar arrow box*/
291                 break;
292         default:
293                 qWarning("Unknown system color id (%d) specified!", color_id);
294                 nIndex = COLOR_WINDOWTEXT;
295         }
296         
297         const DWORD rgb = GetSysColor(nIndex);
298         QColor color(GetRValue(rgb), GetGValue(rgb), GetBValue(rgb));
299         return color;
300 }