OSDN Git Service

Some more code refactoring.
[mutilities/MUtilities.git] / src / GUI_Win32.cpp
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.
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(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(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(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(window->winId()) != FALSE);
160                         SwitchToThisWindow(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(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         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(window->winId(), &bb))
219         {
220                 qWarning("DwmEnableBlurBehindWindow function has failed! (error %d)", hr);
221                 return false;
222         }
223
224         //Required for Qt
225         window->setAutoFillBackground(false);
226         window->setAttribute(Qt::WA_TranslucentBackground);
227         window->setAttribute(Qt::WA_NoSystemBackground);
228
229         return true;
230 }
231
232 bool MUtils::GUI::sheet_of_glass_update(QWidget *const window)
233 {
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")   );
237         
238         //Required functions available?
239         BOOL bCompositionEnabled = FALSE;
240         if(dwmIsCompositionEnabledFun && dwmExtendFrameIntoClientAreaFun && dwmEnableBlurBehindWindowFun)
241         {
242                 //Check if composition is currently enabled
243                 if(HRESULT hr = dwmIsCompositionEnabledFun(&bCompositionEnabled))
244                 {
245                         qWarning("DwmIsCompositionEnabled function has failed! (error %d)", hr);
246                         return false;
247                 }
248         }
249         
250         //All functions available *and* composition enabled?
251         if(!bCompositionEnabled)
252         {
253                 return false;
254         }
255
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(window->winId(), &bb))
262         {
263                 qWarning("DwmEnableBlurBehindWindow function has failed! (error %d)", hr);
264                 return false;
265         }
266
267         return true;
268 }
269
270 ///////////////////////////////////////////////////////////////////////////////
271 // SYSTEM COLORS
272 ///////////////////////////////////////////////////////////////////////////////
273
274 QColor MUtils::GUI::system_color(const int &color_id)
275 {
276         int nIndex = -1;
277
278         switch(color_id)
279         {
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;
292         }
293         
294         const DWORD rgb = GetSysColor(nIndex);
295         QColor color(GetRValue(rgb), GetGValue(rgb), GetBValue(rgb));
296         return color;
297 }