Added support for Visual Studio 2017.9 (v15.9.21).
[MUtilities.git] / src / GUI_Win32.cpp
blobfc80e8e3a3b714fc5fe2fc31dfccc6dcee00635f
1 ///////////////////////////////////////////////////////////////////////////////
2 // MuldeR's Utilities for Qt
3 // Copyright (C) 2004-2019 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.
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
19 // http://www.gnu.org/licenses/lgpl-2.1.txt
20 //////////////////////////////////////////////////////////////////////////////////
22 //Win32 API
23 #define WIN32_LEAN_AND_MEAN 1
24 #include <Windows.h>
26 //MUtils
27 #include <MUtils/GUI.h>
28 #include <MUtils/OSSupport.h>
30 //Internal
31 #include "Utils_Win32.h"
33 //Qt
34 #include <QIcon>
35 #include <QApplication>
36 #include <QWidget>
37 #include <QReadWriteLock>
38 #include <Dwmapi.h>
40 ///////////////////////////////////////////////////////////////////////////////
41 // THEME SUPPORT
42 ///////////////////////////////////////////////////////////////////////////////
44 static QReadWriteLock g_themes_lock;
45 static int g_themes_initialized = 0;
47 typedef int (WINAPI *IsAppThemedFunction)(void);
49 bool MUtils::GUI::themes_enabled(void)
51 QReadLocker readLock(&g_themes_lock);
53 if(g_themes_initialized != 0)
55 return (g_themes_initialized > 0);
58 readLock.unlock();
59 QWriteLocker writeLock(&g_themes_lock);
61 if(g_themes_initialized != 0)
63 return (g_themes_initialized > 0);
66 const MUtils::OS::Version::os_version_t &osVersion = MUtils::OS::os_version();
67 if(osVersion >= MUtils::OS::Version::WINDOWS_WINXP)
69 const IsAppThemedFunction isAppThemedPtr = MUtils::Win32Utils::resolve<IsAppThemedFunction>(QLatin1String("UxTheme"), QLatin1String("IsAppThemed"));
70 if(isAppThemedPtr)
72 g_themes_initialized = isAppThemedPtr() ? 1 : (-1);
73 if(g_themes_initialized < 0)
75 qWarning("Theme support is disabled for this process!");
80 return (g_themes_initialized > 0);
83 ///////////////////////////////////////////////////////////////////////////////
84 // SYSTEM MENU
85 ///////////////////////////////////////////////////////////////////////////////
87 bool MUtils::GUI::sysmenu_append(const QWidget *win, const unsigned int identifier, const QString &text)
89 bool ok = false;
91 if(HMENU hMenu = GetSystemMenu(reinterpret_cast<HWND>(win->winId()), FALSE))
93 ok = (AppendMenuW(hMenu, MF_SEPARATOR, 0, 0) == TRUE);
94 ok = (AppendMenuW(hMenu, MF_STRING, identifier, MUTILS_WCHR(text)) == TRUE);
97 return ok;
100 bool MUtils::GUI::sysmenu_update(const QWidget *win, const unsigned int identifier, const QString &text)
102 bool ok = false;
104 if(HMENU hMenu = ::GetSystemMenu(reinterpret_cast<HWND>(win->winId()), FALSE))
106 ok = (ModifyMenu(hMenu, identifier, MF_STRING | MF_BYCOMMAND, identifier, MUTILS_WCHR(text)) == TRUE);
108 return ok;
111 bool MUtils::GUI::sysmenu_check_msg(void *const message, const unsigned int &identifier)
113 return (((MSG*)message)->message == WM_SYSCOMMAND) && ((((MSG*)message)->wParam & 0xFFF0) == identifier);
116 ///////////////////////////////////////////////////////////////////////////////
117 // CLOSE BUTTON
118 ///////////////////////////////////////////////////////////////////////////////
120 bool MUtils::GUI::enable_close_button(const QWidget *win, const bool &bEnable)
122 bool ok = false;
124 if(HMENU hMenu = GetSystemMenu(reinterpret_cast<HWND>(win->winId()), FALSE))
126 ok = (EnableMenuItem(hMenu, SC_CLOSE, MF_BYCOMMAND | (bEnable ? MF_ENABLED : MF_GRAYED)) == TRUE);
129 return ok;
132 ///////////////////////////////////////////////////////////////////////////////
133 // BRING WINDOW TO FRONT
134 ///////////////////////////////////////////////////////////////////////////////
136 static BOOL CALLBACK bring_process_to_front_helper(HWND hwnd, LPARAM lParam)
138 DWORD processId = *reinterpret_cast<WORD*>(lParam);
139 DWORD windowProcessId = NULL;
140 GetWindowThreadProcessId(hwnd, &windowProcessId);
141 if(windowProcessId == processId)
143 SwitchToThisWindow(hwnd, TRUE);
144 SetForegroundWindow(hwnd);
145 return FALSE;
148 return TRUE;
151 bool MUtils::GUI::bring_to_front(const QWidget *window)
153 bool ret = false;
155 if(window)
157 for(int i = 0; (i < 5) && (!ret); i++)
159 ret = (SetForegroundWindow(reinterpret_cast<HWND>(window->winId())) != FALSE);
160 SwitchToThisWindow(reinterpret_cast<HWND>(window->winId()), TRUE);
162 LockSetForegroundWindow(LSFW_LOCK);
165 return ret;
168 bool MUtils::GUI::bring_to_front(const unsigned long pid)
170 return EnumWindows(bring_process_to_front_helper, reinterpret_cast<LPARAM>(&pid)) == TRUE;
173 ///////////////////////////////////////////////////////////////////////////////
174 // SHEET OF GLASS EFFECT
175 ///////////////////////////////////////////////////////////////////////////////
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);
181 bool MUtils::GUI::sheet_of_glass(QWidget *const window)
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") );
187 //Required functions available?
188 BOOL bCompositionEnabled = FALSE;
189 if(dwmIsCompositionEnabledFun && dwmExtendFrameIntoClientAreaFun && dwmEnableBlurBehindWindowFun)
191 //Check if composition is currently enabled
192 if(HRESULT hr = dwmIsCompositionEnabledFun(&bCompositionEnabled))
194 qWarning("DwmIsCompositionEnabled function has failed! (error %d)", hr);
195 return false;
199 //All functions available *and* composition enabled?
200 if(!bCompositionEnabled)
202 return false;
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))
209 qWarning("DwmExtendFrameIntoClientArea function has failed! (error %d)", hr);
210 return false;
213 //Create and populate the Blur Behind structure
214 DWM_BLURBEHIND bb;
215 memset(&bb, 0, sizeof(DWM_BLURBEHIND));
216 bb.fEnable = TRUE;
217 bb.dwFlags = DWM_BB_ENABLE;
218 if(HRESULT hr = dwmEnableBlurBehindWindowFun(reinterpret_cast<HWND>(window->winId()), &bb))
220 qWarning("DwmEnableBlurBehindWindow function has failed! (error %d)", hr);
221 return false;
224 //Required for Qt
225 window->setAutoFillBackground(false);
226 window->setAttribute(Qt::WA_TranslucentBackground);
227 window->setAttribute(Qt::WA_NoSystemBackground);
229 return true;
232 bool MUtils::GUI::sheet_of_glass_update(QWidget *const window)
234 const DwmIsCompositionEnabledFun dwmIsCompositionEnabledFun = MUtils::Win32Utils::resolve<DwmIsCompositionEnabledFun> (QLatin1String("dwmapi"), QLatin1String("DwmIsCompositionEnabled") );
235 const DwmExtendFrameIntoClientAreaFun dwmExtendFrameIntoClientAreaFun = MUtils::Win32Utils::resolve<DwmExtendFrameIntoClientAreaFun>(QLatin1String("dwmapi"), QLatin1String("DwmExtendFrameIntoClientArea"));
236 const DwmEnableBlurBehindWindowFun dwmEnableBlurBehindWindowFun = MUtils::Win32Utils::resolve<DwmEnableBlurBehindWindowFun> (QLatin1String("dwmapi"), QLatin1String("DwmEnableBlurBehindWindow") );
238 //Required functions available?
239 BOOL bCompositionEnabled = FALSE;
240 if(dwmIsCompositionEnabledFun && dwmExtendFrameIntoClientAreaFun && dwmEnableBlurBehindWindowFun)
242 //Check if composition is currently enabled
243 if(HRESULT hr = dwmIsCompositionEnabledFun(&bCompositionEnabled))
245 qWarning("DwmIsCompositionEnabled function has failed! (error %d)", hr);
246 return false;
250 //All functions available *and* composition enabled?
251 if(!bCompositionEnabled)
253 return false;
256 //Create and populate the Blur Behind structure
257 DWM_BLURBEHIND bb;
258 memset(&bb, 0, sizeof(DWM_BLURBEHIND));
259 bb.fEnable = TRUE;
260 bb.dwFlags = DWM_BB_ENABLE;
261 if(HRESULT hr = dwmEnableBlurBehindWindowFun(reinterpret_cast<HWND>(window->winId()), &bb))
263 qWarning("DwmEnableBlurBehindWindow function has failed! (error %d)", hr);
264 return false;
267 return true;
270 ///////////////////////////////////////////////////////////////////////////////
271 // SYSTEM COLORS
272 ///////////////////////////////////////////////////////////////////////////////
274 QColor MUtils::GUI::system_color(const int &color_id)
276 int nIndex = -1;
278 switch(color_id)
280 case SYSCOLOR_TEXT:
281 nIndex = COLOR_WINDOWTEXT; /*Text in windows*/
282 break;
283 case SYSCOLOR_BACKGROUND:
284 nIndex = COLOR_WINDOW; /*Window background*/
285 break;
286 case SYSCOLOR_CAPTION:
287 nIndex = COLOR_CAPTIONTEXT; /*Text in caption, size box, and scroll bar arrow box*/
288 break;
289 default:
290 qWarning("Unknown system color id (%d) specified!", color_id);
291 nIndex = COLOR_WINDOWTEXT;
294 const DWORD rgb = GetSysColor(nIndex);
295 QColor color(GetRValue(rgb), GetGValue(rgb), GetBValue(rgb));
296 return color;