Moved all the Sound-specific functions into MUtilities library.
[LameXP.git] / src / Global_Win32.cpp
blob91a69ed23fcb0ce66158e07744365618da2b44f4
1 ///////////////////////////////////////////////////////////////////////////////
2 // LameXP - Audio Encoder Front-End
3 // Copyright (C) 2004-2014 LoRd_MuldeR <MuldeR2@GMX.de>
4 //
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 2 of the License, or
8 // (at your option) any later version, but always including the *additional*
9 // restrictions defined in the "License.txt" file.
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // You should have received a copy of the GNU General Public License along
17 // with this program; if not, write to the Free Software Foundation, Inc.,
18 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 // http://www.gnu.org/licenses/gpl-2.0.txt
21 ///////////////////////////////////////////////////////////////////////////////
23 #include "Global.h"
25 //Target version
26 #include "Targetver.h"
28 //Visual Leaks Detector
29 #include <vld.h>
31 //Windows includes
32 #define NOMINMAX
33 #define WIN32_LEAN_AND_MEAN
34 #include <Windows.h>
35 #include <MMSystem.h>
36 #include <ShellAPI.h>
37 #include <SensAPI.h>
38 #include <Objbase.h>
39 #include <PowrProf.h>
40 #include <Psapi.h>
41 #include <dwmapi.h>
43 //Qt includes
44 #include <QApplication>
45 #include <QDate>
46 #include <QDir>
47 #include <QEvent>
48 #include <QIcon>
49 #include <QImageReader>
50 #include <QLibrary>
51 #include <QLibraryInfo>
52 #include <QMap>
53 #include <QMessageBox>
54 #include <QPlastiqueStyle>
55 #include <QProcess>
56 #include <QReadWriteLock>
57 #include <QRegExp>
58 #include <QSysInfo>
59 #include <QTextCodec>
60 #include <QTimer>
61 #include <QTranslator>
62 #include <QUuid>
63 #include <QResource>
65 //LameXP includes
66 #define LAMEXP_INC_CONFIG
67 #include "Resource.h"
68 #include "Config.h"
70 //MUtils
71 #include <MUtils/Global.h>
72 #include <MUtils/OSSupport.h>
73 #include <MUtils/Terminal.h>
75 //CRT includes
76 #include <cstdio>
77 #include <iostream>
78 #include <fstream>
79 #include <io.h>
80 #include <fcntl.h>
81 #include <intrin.h>
82 #include <cmath>
83 #include <ctime>
84 #include <process.h>
85 #include <csignal>
87 //Initialize static Qt plugins
88 #ifdef QT_NODLL
89 #if QT_VERSION < QT_VERSION_CHECK(5,0,0)
90 Q_IMPORT_PLUGIN(qico)
91 Q_IMPORT_PLUGIN(qsvg)
92 #else
93 Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin)
94 Q_IMPORT_PLUGIN(QICOPlugin)
95 #endif
96 #endif
98 ///////////////////////////////////////////////////////////////////////////////
99 // HELPER MACROS
100 ///////////////////////////////////////////////////////////////////////////////
102 #define _LAMEXP_MAKE_STR(STR) #STR
103 #define LAMEXP_MAKE_STR(STR) _LAMEXP_MAKE_STR(STR)
105 ///////////////////////////////////////////////////////////////////////////////
106 // GLOBAL VARS
107 ///////////////////////////////////////////////////////////////////////////////
109 //Wine detection
110 static struct
112 bool bInitialized;
113 bool bIsWine;
114 QReadWriteLock lock;
116 g_lamexp_wine;
118 //Win32 Theme support
119 static struct
121 bool bInitialized;
122 bool bThemesEnabled;
123 QReadWriteLock lock;
125 g_lamexp_themes_enabled;
127 //Win32 DWM API functions
128 static struct
130 bool bInitialized;
131 HRESULT (__stdcall *dwmIsCompositionEnabled)(BOOL *bEnabled);
132 HRESULT (__stdcall *dwmExtendFrameIntoClientArea)(HWND hWnd, const MARGINS* pMarInset);
133 HRESULT (__stdcall *dwmEnableBlurBehindWindow)(HWND hWnd, const DWM_BLURBEHIND* pBlurBehind);
134 QLibrary *dwmapi_dll;
135 QReadWriteLock lock;
137 g_lamexp_dwmapi;
139 //Sound file cache
140 static struct
142 QHash<const QString, const unsigned char*> *sound_db;
143 QReadWriteLock lock;
145 g_lamexp_sounds;
147 //Main thread ID
148 static const DWORD g_main_thread_id = GetCurrentThreadId();
150 //Localization
151 const char* LAMEXP_DEFAULT_LANGID = "en";
152 const char* LAMEXP_DEFAULT_TRANSLATION = "LameXP_EN.qm";
154 ///////////////////////////////////////////////////////////////////////////////
155 // GLOBAL FUNCTIONS
156 ///////////////////////////////////////////////////////////////////////////////
159 * Check if visual themes are enabled (WinXP and later)
161 bool lamexp_themes_enabled(void)
163 typedef int (WINAPI *IsAppThemedFun)(void);
165 QReadLocker readLock(&g_lamexp_themes_enabled.lock);
166 if(g_lamexp_themes_enabled.bInitialized)
168 return g_lamexp_themes_enabled.bThemesEnabled;
171 readLock.unlock();
172 QWriteLocker writeLock(&g_lamexp_themes_enabled.lock);
174 if(!g_lamexp_themes_enabled.bInitialized)
176 g_lamexp_themes_enabled.bThemesEnabled = false;
177 const MUtils::OS::Version::os_version_t &osVersion = MUtils::OS::os_version();
178 if(osVersion >= MUtils::OS::Version::WINDOWS_WINXP)
180 IsAppThemedFun IsAppThemedPtr = NULL;
181 QLibrary uxTheme(QString("%1/UxTheme.dll").arg(MUtils::OS::known_folder(MUtils::OS::FOLDER_SYSTEMFOLDER)));
182 if(uxTheme.load())
184 IsAppThemedPtr = (IsAppThemedFun) uxTheme.resolve("IsAppThemed");
186 if(IsAppThemedPtr)
188 g_lamexp_themes_enabled.bThemesEnabled = IsAppThemedPtr();
189 if(!g_lamexp_themes_enabled.bThemesEnabled)
191 qWarning("Theme support is disabled for this process!");
195 g_lamexp_themes_enabled.bInitialized = true;
198 return g_lamexp_themes_enabled.bThemesEnabled;
202 * Insert entry to the window's system menu
204 bool lamexp_append_sysmenu(const QWidget *win, const unsigned int identifier, const QString &text)
206 bool ok = false;
208 if(HMENU hMenu = GetSystemMenu(win->winId(), FALSE))
210 ok = (AppendMenuW(hMenu, MF_SEPARATOR, 0, 0) == TRUE);
211 ok = (AppendMenuW(hMenu, MF_STRING, identifier, MUTILS_WCHR(text)) == TRUE);
214 return ok;
218 * Insert entry to the window's system menu
220 bool lamexp_check_sysmenu_msg(void *message, const unsigned int identifier)
222 return (((MSG*)message)->message == WM_SYSCOMMAND) && ((((MSG*)message)->wParam & 0xFFF0) == identifier);
226 * Update system menu entry
228 bool lamexp_update_sysmenu(const QWidget *win, const unsigned int identifier, const QString &text)
230 bool ok = false;
232 if(HMENU hMenu = ::GetSystemMenu(win->winId(), FALSE))
234 ok = (ModifyMenu(hMenu, identifier, MF_STRING | MF_BYCOMMAND, identifier, MUTILS_WCHR(text)) == TRUE);
236 return ok;
240 * Display the window's close button
242 bool lamexp_enable_close_button(const QWidget *win, const bool bEnable)
244 bool ok = false;
246 if(HMENU hMenu = GetSystemMenu(win->winId(), FALSE))
248 ok = (EnableMenuItem(hMenu, SC_CLOSE, MF_BYCOMMAND | (bEnable ? MF_ENABLED : MF_GRAYED)) == TRUE);
251 return ok;
255 * Check whether ESC key has been pressed since the previous call to this function
257 bool lamexp_check_escape_state(void)
259 return (GetAsyncKeyState(VK_ESCAPE) & 0x0001) != 0;
263 * Bring the specifed window to the front
265 bool lamexp_bring_to_front(const QWidget *window)
267 bool ret = false;
269 if(window)
271 for(int i = 0; (i < 5) && (!ret); i++)
273 ret = (SetForegroundWindow(window->winId()) != FALSE);
274 SwitchToThisWindow(window->winId(), TRUE);
276 LockSetForegroundWindow(LSFW_LOCK);
279 return ret;
283 * Bring window of the specifed process to the front (callback)
285 static BOOL CALLBACK lamexp_bring_process_to_front_helper(HWND hwnd, LPARAM lParam)
287 DWORD processId = *reinterpret_cast<WORD*>(lParam);
288 DWORD windowProcessId = NULL;
289 GetWindowThreadProcessId(hwnd, &windowProcessId);
290 if(windowProcessId == processId)
292 SwitchToThisWindow(hwnd, TRUE);
293 SetForegroundWindow(hwnd);
294 return FALSE;
297 return TRUE;
301 * Bring window of the specifed process to the front
303 bool lamexp_bring_process_to_front(const unsigned long pid)
305 return EnumWindows(lamexp_bring_process_to_front_helper, reinterpret_cast<LPARAM>(&pid)) == TRUE;
308 static void lamexp_init_dwmapi(void)
310 QReadLocker writeLock(&g_lamexp_dwmapi.lock);
312 //Not initialized yet?
313 if(g_lamexp_dwmapi.bInitialized)
315 return;
318 //Reset function pointers
319 g_lamexp_dwmapi.dwmIsCompositionEnabled = NULL;
320 g_lamexp_dwmapi.dwmExtendFrameIntoClientArea = NULL;
321 g_lamexp_dwmapi.dwmEnableBlurBehindWindow = NULL;
323 //Does OS support DWM?
324 const MUtils::OS::Version::os_version_t &osVersion = MUtils::OS::os_version();
325 if(osVersion >= MUtils::OS::Version::WINDOWS_VISTA)
327 //Load DWMAPI.DLL
328 g_lamexp_dwmapi.dwmapi_dll = new QLibrary("dwmapi.dll");
329 if(g_lamexp_dwmapi.dwmapi_dll->load())
331 //Initialize function pointers
332 g_lamexp_dwmapi.dwmIsCompositionEnabled = (HRESULT (__stdcall*)(BOOL*)) g_lamexp_dwmapi.dwmapi_dll->resolve("DwmIsCompositionEnabled");
333 g_lamexp_dwmapi.dwmExtendFrameIntoClientArea = (HRESULT (__stdcall*)(HWND, const MARGINS*)) g_lamexp_dwmapi.dwmapi_dll->resolve("DwmExtendFrameIntoClientArea");
334 g_lamexp_dwmapi.dwmEnableBlurBehindWindow = (HRESULT (__stdcall*)(HWND, const DWM_BLURBEHIND*)) g_lamexp_dwmapi.dwmapi_dll->resolve("DwmEnableBlurBehindWindow");
336 else
338 MUTILS_DELETE(g_lamexp_dwmapi.dwmapi_dll);
339 qWarning("Failed to load DWMAPI.DLL on a DWM-enabled system!");
343 g_lamexp_dwmapi.bInitialized = true;
347 * Enable "sheet of glass" effect on the given Window
349 bool lamexp_sheet_of_glass(QWidget *window)
351 QReadLocker readLock(&g_lamexp_dwmapi.lock);
353 //Initialize the DWM API
354 while(!g_lamexp_dwmapi.bInitialized)
356 readLock.unlock();
357 lamexp_init_dwmapi();
358 readLock.relock();
361 BOOL bCompositionEnabled = FALSE;
363 //Required functions available?
364 if((g_lamexp_dwmapi.dwmIsCompositionEnabled != NULL) && (g_lamexp_dwmapi.dwmExtendFrameIntoClientArea != NULL) && (g_lamexp_dwmapi.dwmEnableBlurBehindWindow != NULL))
366 //Check if composition is currently enabled
367 if(HRESULT hr = g_lamexp_dwmapi.dwmIsCompositionEnabled(&bCompositionEnabled))
369 qWarning("DwmIsCompositionEnabled function has failed! (error %d)", hr);
370 return false;
374 //All functions available *and* composition enabled?
375 if(!bCompositionEnabled)
377 return false;
380 //Enable the "sheet of glass" effect on this window
381 MARGINS margins = {-1, -1, -1, -1};
382 if(HRESULT hr = g_lamexp_dwmapi.dwmExtendFrameIntoClientArea(window->winId(), &margins))
384 qWarning("DwmExtendFrameIntoClientArea function has failed! (error %d)", hr);
385 return false;
388 //Create and populate the Blur Behind structure
389 DWM_BLURBEHIND bb;
390 memset(&bb, 0, sizeof(DWM_BLURBEHIND));
391 bb.fEnable = TRUE;
392 bb.dwFlags = DWM_BB_ENABLE;
393 if(HRESULT hr = g_lamexp_dwmapi.dwmEnableBlurBehindWindow(window->winId(), &bb))
395 qWarning("DwmEnableBlurBehindWindow function has failed! (error %d)", hr);
396 return false;
399 //Required for Qt
400 window->setAutoFillBackground(false);
401 window->setAttribute(Qt::WA_TranslucentBackground);
402 window->setAttribute(Qt::WA_NoSystemBackground);
404 return true;
408 * Update "sheet of glass" effect on the given Window
410 bool lamexp_sheet_of_glass_update(QWidget *window)
412 QReadLocker readLock(&g_lamexp_dwmapi.lock);
414 //Initialize the DWM API
415 while(!g_lamexp_dwmapi.bInitialized)
417 readLock.unlock();
418 lamexp_init_dwmapi();
419 readLock.relock();
422 BOOL bCompositionEnabled = FALSE;
424 //Required functions available?
425 if((g_lamexp_dwmapi.dwmIsCompositionEnabled != NULL) && (g_lamexp_dwmapi.dwmEnableBlurBehindWindow != NULL))
427 //Check if composition is currently enabled
428 if(HRESULT hr = g_lamexp_dwmapi.dwmIsCompositionEnabled(&bCompositionEnabled))
430 qWarning("DwmIsCompositionEnabled function has failed! (error %d)", hr);
431 return false;
435 //All functions available *and* composition enabled?
436 if(!bCompositionEnabled)
438 return false;
441 //Create and populate the Blur Behind structure
442 DWM_BLURBEHIND bb;
443 memset(&bb, 0, sizeof(DWM_BLURBEHIND));
444 bb.fEnable = TRUE;
445 bb.dwFlags = DWM_BB_ENABLE;
446 if(HRESULT hr = g_lamexp_dwmapi.dwmEnableBlurBehindWindow(window->winId(), &bb))
448 qWarning("DwmEnableBlurBehindWindow function has failed! (error %d)", hr);
449 return false;
452 return true;
456 * Get system color info
458 QColor lamexp_system_color(const int color_id)
460 int nIndex = -1;
462 switch(color_id)
464 case lamexp_syscolor_text:
465 nIndex = COLOR_WINDOWTEXT; /*Text in windows*/
466 break;
467 case lamexp_syscolor_background:
468 nIndex = COLOR_WINDOW; /*Window background*/
469 break;
470 case lamexp_syscolor_caption:
471 nIndex = COLOR_CAPTIONTEXT; /*Text in caption, size box, and scroll bar arrow box*/
472 break;
473 default:
474 qWarning("Unknown system color id (%d) specified!", color_id);
475 nIndex = COLOR_WINDOWTEXT;
478 const DWORD rgb = GetSysColor(nIndex);
479 QColor color(GetRValue(rgb), GetGValue(rgb), GetBValue(rgb));
480 return color;
483 ///////////////////////////////////////////////////////////////////////////////
484 // INITIALIZATION
485 ///////////////////////////////////////////////////////////////////////////////
487 extern "C" void _lamexp_global_init_win32(void)
489 //Zero *before* constructors are called
490 MUTILS_ZERO_MEMORY(g_lamexp_wine);
491 MUTILS_ZERO_MEMORY(g_lamexp_themes_enabled);
492 MUTILS_ZERO_MEMORY(g_lamexp_dwmapi);
493 MUTILS_ZERO_MEMORY(g_lamexp_sounds);
496 ///////////////////////////////////////////////////////////////////////////////
497 // FINALIZATION
498 ///////////////////////////////////////////////////////////////////////////////
500 extern "C" void _lamexp_global_free_win32(void)
502 //Release DWM API
503 g_lamexp_dwmapi.dwmIsCompositionEnabled = NULL;
504 g_lamexp_dwmapi.dwmExtendFrameIntoClientArea = NULL;
505 g_lamexp_dwmapi.dwmEnableBlurBehindWindow = NULL;
506 MUTILS_DELETE(g_lamexp_dwmapi.dwmapi_dll);
508 //Clear sound cache
509 MUTILS_DELETE(g_lamexp_sounds.sound_db);