Added project/solution files for Visual Studio 2010.
[MUtilities.git] / src / GUI_Win32.cpp
blob28957ac066ac75baad7d3cce747fa0d779390359
1 ///////////////////////////////////////////////////////////////////////////////
2 // MuldeR's Utilities for Qt
3 // Copyright (C) 2004-2015 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 <QLibrary>
39 #include <Dwmapi.h>
41 ///////////////////////////////////////////////////////////////////////////////
42 // THEME SUPPORT
43 ///////////////////////////////////////////////////////////////////////////////
45 static QReadWriteLock g_themes_lock;
46 static bool g_themes_initialized = false;
47 static bool g_themes_enabled = false;
49 typedef int (WINAPI IsAppThemedFunction)(void);
51 bool MUtils::GUI::themes_enabled(void)
53 QReadLocker readLock(&g_themes_lock);
55 if(g_themes_initialized)
57 return g_themes_enabled;
60 readLock.unlock();
61 QWriteLocker writeLock(&g_themes_lock);
63 if(g_themes_initialized)
65 return g_themes_enabled;
68 const MUtils::OS::Version::os_version_t &osVersion = MUtils::OS::os_version();
69 if(osVersion >= MUtils::OS::Version::WINDOWS_WINXP)
71 QLibrary uxTheme("UxTheme.dll");
72 if(uxTheme.load())
74 if(IsAppThemedFunction *const IsAppThemedPtr = (IsAppThemedFunction*) uxTheme.resolve("IsAppThemed"))
76 g_themes_enabled = IsAppThemedPtr();
77 if(!g_themes_enabled)
79 qWarning("Theme support is disabled for this process!");
85 g_themes_initialized = true;
86 return g_themes_enabled;
89 ///////////////////////////////////////////////////////////////////////////////
90 // SYSTEM MENU
91 ///////////////////////////////////////////////////////////////////////////////
93 bool MUtils::GUI::sysmenu_append(const QWidget *win, const unsigned int identifier, const QString &text)
95 bool ok = false;
97 if(HMENU hMenu = GetSystemMenu(win->winId(), FALSE))
99 ok = (AppendMenuW(hMenu, MF_SEPARATOR, 0, 0) == TRUE);
100 ok = (AppendMenuW(hMenu, MF_STRING, identifier, MUTILS_WCHR(text)) == TRUE);
103 return ok;
106 bool MUtils::GUI::sysmenu_update(const QWidget *win, const unsigned int identifier, const QString &text)
108 bool ok = false;
110 if(HMENU hMenu = ::GetSystemMenu(win->winId(), FALSE))
112 ok = (ModifyMenu(hMenu, identifier, MF_STRING | MF_BYCOMMAND, identifier, MUTILS_WCHR(text)) == TRUE);
114 return ok;
117 bool MUtils::GUI::sysmenu_check_msg(void *const message, const unsigned int &identifier)
119 return (((MSG*)message)->message == WM_SYSCOMMAND) && ((((MSG*)message)->wParam & 0xFFF0) == identifier);
122 ///////////////////////////////////////////////////////////////////////////////
123 // CLOSE BUTTON
124 ///////////////////////////////////////////////////////////////////////////////
126 bool MUtils::GUI::enable_close_button(const QWidget *win, const bool &bEnable)
128 bool ok = false;
130 if(HMENU hMenu = GetSystemMenu(win->winId(), FALSE))
132 ok = (EnableMenuItem(hMenu, SC_CLOSE, MF_BYCOMMAND | (bEnable ? MF_ENABLED : MF_GRAYED)) == TRUE);
135 return ok;
138 ///////////////////////////////////////////////////////////////////////////////
139 // BRING WINDOW TO FRONT
140 ///////////////////////////////////////////////////////////////////////////////
142 static BOOL CALLBACK bring_process_to_front_helper(HWND hwnd, LPARAM lParam)
144 DWORD processId = *reinterpret_cast<WORD*>(lParam);
145 DWORD windowProcessId = NULL;
146 GetWindowThreadProcessId(hwnd, &windowProcessId);
147 if(windowProcessId == processId)
149 SwitchToThisWindow(hwnd, TRUE);
150 SetForegroundWindow(hwnd);
151 return FALSE;
154 return TRUE;
157 bool MUtils::GUI::bring_to_front(const QWidget *window)
159 bool ret = false;
161 if(window)
163 for(int i = 0; (i < 5) && (!ret); i++)
165 ret = (SetForegroundWindow(window->winId()) != FALSE);
166 SwitchToThisWindow(window->winId(), TRUE);
168 LockSetForegroundWindow(LSFW_LOCK);
171 return ret;
174 bool MUtils::GUI::bring_to_front(const unsigned long pid)
176 return EnumWindows(bring_process_to_front_helper, reinterpret_cast<LPARAM>(&pid)) == TRUE;
179 ///////////////////////////////////////////////////////////////////////////////
180 // SHEET OF GLASS EFFECT
181 ///////////////////////////////////////////////////////////////////////////////
183 static QReadWriteLock g_dwmapi_lock;
184 static QScopedPointer<QLibrary> g_dwmapi_library;
185 static bool g_dwmapi_initialized = false;
187 static struct
189 HRESULT (__stdcall *dwmIsCompositionEnabled)(BOOL *bEnabled);
190 HRESULT (__stdcall *dwmExtendFrameIntoClientArea)(HWND hWnd, const MARGINS* pMarInset);
191 HRESULT (__stdcall *dwmEnableBlurBehindWindow)(HWND hWnd, const DWM_BLURBEHIND* pBlurBehind);
193 g_dwmapi_pointers = { NULL, NULL, NULL };
195 static void initialize_dwmapi(void)
197 QReadLocker writeLock(&g_dwmapi_lock);
199 //Not initialized yet?
200 if(g_dwmapi_initialized)
202 return;
205 //Reset function pointers
206 g_dwmapi_pointers.dwmIsCompositionEnabled = NULL;
207 g_dwmapi_pointers.dwmExtendFrameIntoClientArea = NULL;
208 g_dwmapi_pointers.dwmEnableBlurBehindWindow = NULL;
210 //Does OS support DWM?
211 const MUtils::OS::Version::os_version_t &osVersion = MUtils::OS::os_version();
212 if(osVersion >= MUtils::OS::Version::WINDOWS_VISTA)
214 //Load DWMAPI.DLL
215 g_dwmapi_library.reset(new QLibrary("dwmapi.dll"));
216 if(g_dwmapi_library->load())
218 //Initialize function pointers
219 g_dwmapi_pointers.dwmIsCompositionEnabled = (HRESULT (__stdcall*)(BOOL*)) g_dwmapi_library->resolve("DwmIsCompositionEnabled");
220 g_dwmapi_pointers.dwmExtendFrameIntoClientArea = (HRESULT (__stdcall*)(HWND, const MARGINS*)) g_dwmapi_library->resolve("DwmExtendFrameIntoClientArea");
221 g_dwmapi_pointers.dwmEnableBlurBehindWindow = (HRESULT (__stdcall*)(HWND, const DWM_BLURBEHIND*)) g_dwmapi_library->resolve("DwmEnableBlurBehindWindow");
223 else
225 g_dwmapi_library.reset(NULL);
226 qWarning("Failed to load DWMAPI.DLL on a DWM-enabled system!");
230 g_dwmapi_initialized = true;
233 bool MUtils::GUI::sheet_of_glass(QWidget *const window)
235 QReadLocker readLock(&g_dwmapi_lock);
237 //Initialize the DWM API
238 if(!g_dwmapi_initialized)
240 readLock.unlock();
241 initialize_dwmapi();
242 readLock.relock();
245 //Required functions available?
246 BOOL bCompositionEnabled = FALSE;
247 if(g_dwmapi_pointers.dwmIsCompositionEnabled && g_dwmapi_pointers.dwmExtendFrameIntoClientArea && g_dwmapi_pointers.dwmEnableBlurBehindWindow)
249 //Check if composition is currently enabled
250 if(HRESULT hr = g_dwmapi_pointers.dwmIsCompositionEnabled(&bCompositionEnabled))
252 qWarning("DwmIsCompositionEnabled function has failed! (error %d)", hr);
253 return false;
257 //All functions available *and* composition enabled?
258 if(!bCompositionEnabled)
260 return false;
263 //Enable the "sheet of glass" effect on this window
264 MARGINS margins = {-1, -1, -1, -1};
265 if(HRESULT hr = g_dwmapi_pointers.dwmExtendFrameIntoClientArea(window->winId(), &margins))
267 qWarning("DwmExtendFrameIntoClientArea function has failed! (error %d)", hr);
268 return false;
271 //Create and populate the Blur Behind structure
272 DWM_BLURBEHIND bb;
273 memset(&bb, 0, sizeof(DWM_BLURBEHIND));
274 bb.fEnable = TRUE;
275 bb.dwFlags = DWM_BB_ENABLE;
276 if(HRESULT hr = g_dwmapi_pointers.dwmEnableBlurBehindWindow(window->winId(), &bb))
278 qWarning("DwmEnableBlurBehindWindow function has failed! (error %d)", hr);
279 return false;
282 //Required for Qt
283 window->setAutoFillBackground(false);
284 window->setAttribute(Qt::WA_TranslucentBackground);
285 window->setAttribute(Qt::WA_NoSystemBackground);
287 return true;
290 bool MUtils::GUI::sheet_of_glass_update(QWidget *const window)
292 QReadLocker readLock(&g_dwmapi_lock);
294 //Initialize the DWM API
295 if(!g_dwmapi_initialized)
297 readLock.unlock();
298 initialize_dwmapi();
299 readLock.relock();
302 //Required functions available?
303 BOOL bCompositionEnabled = FALSE;
304 if(g_dwmapi_pointers.dwmIsCompositionEnabled && g_dwmapi_pointers.dwmExtendFrameIntoClientArea && g_dwmapi_pointers.dwmEnableBlurBehindWindow)
306 //Check if composition is currently enabled
307 if(HRESULT hr = g_dwmapi_pointers.dwmIsCompositionEnabled(&bCompositionEnabled))
309 qWarning("DwmIsCompositionEnabled function has failed! (error %d)", hr);
310 return false;
314 //All functions available *and* composition enabled?
315 if(!bCompositionEnabled)
317 return false;
320 //Create and populate the Blur Behind structure
321 DWM_BLURBEHIND bb;
322 memset(&bb, 0, sizeof(DWM_BLURBEHIND));
323 bb.fEnable = TRUE;
324 bb.dwFlags = DWM_BB_ENABLE;
325 if(HRESULT hr = g_dwmapi_pointers.dwmEnableBlurBehindWindow(window->winId(), &bb))
327 qWarning("DwmEnableBlurBehindWindow function has failed! (error %d)", hr);
328 return false;
331 return true;
334 ///////////////////////////////////////////////////////////////////////////////
335 // SYSTEM COLORS
336 ///////////////////////////////////////////////////////////////////////////////
338 QColor MUtils::GUI::system_color(const int &color_id)
340 int nIndex = -1;
342 switch(color_id)
344 case SYSCOLOR_TEXT:
345 nIndex = COLOR_WINDOWTEXT; /*Text in windows*/
346 break;
347 case SYSCOLOR_BACKGROUND:
348 nIndex = COLOR_WINDOW; /*Window background*/
349 break;
350 case SYSCOLOR_CAPTION:
351 nIndex = COLOR_CAPTIONTEXT; /*Text in caption, size box, and scroll bar arrow box*/
352 break;
353 default:
354 qWarning("Unknown system color id (%d) specified!", color_id);
355 nIndex = COLOR_WINDOWTEXT;
358 const DWORD rgb = GetSysColor(nIndex);
359 QColor color(GetRValue(rgb), GetGValue(rgb), GetBValue(rgb));
360 return color;