LameXP/src/Global_Win32.cpp

511 lines
13 KiB
C++

///////////////////////////////////////////////////////////////////////////////
// LameXP - Audio Encoder Front-End
// Copyright (C) 2004-2014 LoRd_MuldeR <MuldeR2@GMX.de>
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version, but always including the *additional*
// restrictions defined in the "License.txt" file.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//
// http://www.gnu.org/licenses/gpl-2.0.txt
///////////////////////////////////////////////////////////////////////////////
#include "Global.h"
//Target version
#include "Targetver.h"
//Visual Leaks Detector
#include <vld.h>
//Windows includes
#define NOMINMAX
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <MMSystem.h>
#include <ShellAPI.h>
#include <SensAPI.h>
#include <Objbase.h>
#include <PowrProf.h>
#include <Psapi.h>
#include <dwmapi.h>
//Qt includes
#include <QApplication>
#include <QDate>
#include <QDir>
#include <QEvent>
#include <QIcon>
#include <QImageReader>
#include <QLibrary>
#include <QLibraryInfo>
#include <QMap>
#include <QMessageBox>
#include <QPlastiqueStyle>
#include <QProcess>
#include <QReadWriteLock>
#include <QRegExp>
#include <QSysInfo>
#include <QTextCodec>
#include <QTimer>
#include <QTranslator>
#include <QUuid>
#include <QResource>
//LameXP includes
#define LAMEXP_INC_CONFIG
#include "Resource.h"
#include "Config.h"
//MUtils
#include <MUtils/Global.h>
#include <MUtils/OSSupport.h>
#include <MUtils/Terminal.h>
//CRT includes
#include <cstdio>
#include <iostream>
#include <fstream>
#include <io.h>
#include <fcntl.h>
#include <intrin.h>
#include <cmath>
#include <ctime>
#include <process.h>
#include <csignal>
//Initialize static Qt plugins
#ifdef QT_NODLL
#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
Q_IMPORT_PLUGIN(qico)
Q_IMPORT_PLUGIN(qsvg)
#else
Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin)
Q_IMPORT_PLUGIN(QICOPlugin)
#endif
#endif
///////////////////////////////////////////////////////////////////////////////
// HELPER MACROS
///////////////////////////////////////////////////////////////////////////////
#define _LAMEXP_MAKE_STR(STR) #STR
#define LAMEXP_MAKE_STR(STR) _LAMEXP_MAKE_STR(STR)
///////////////////////////////////////////////////////////////////////////////
// GLOBAL VARS
///////////////////////////////////////////////////////////////////////////////
//Wine detection
static struct
{
bool bInitialized;
bool bIsWine;
QReadWriteLock lock;
}
g_lamexp_wine;
//Win32 Theme support
static struct
{
bool bInitialized;
bool bThemesEnabled;
QReadWriteLock lock;
}
g_lamexp_themes_enabled;
//Win32 DWM API functions
static struct
{
bool bInitialized;
HRESULT (__stdcall *dwmIsCompositionEnabled)(BOOL *bEnabled);
HRESULT (__stdcall *dwmExtendFrameIntoClientArea)(HWND hWnd, const MARGINS* pMarInset);
HRESULT (__stdcall *dwmEnableBlurBehindWindow)(HWND hWnd, const DWM_BLURBEHIND* pBlurBehind);
QLibrary *dwmapi_dll;
QReadWriteLock lock;
}
g_lamexp_dwmapi;
//Sound file cache
static struct
{
QHash<const QString, const unsigned char*> *sound_db;
QReadWriteLock lock;
}
g_lamexp_sounds;
//Main thread ID
static const DWORD g_main_thread_id = GetCurrentThreadId();
//Localization
const char* LAMEXP_DEFAULT_LANGID = "en";
const char* LAMEXP_DEFAULT_TRANSLATION = "LameXP_EN.qm";
///////////////////////////////////////////////////////////////////////////////
// GLOBAL FUNCTIONS
///////////////////////////////////////////////////////////////////////////////
/*
* Check if visual themes are enabled (WinXP and later)
*/
bool lamexp_themes_enabled(void)
{
typedef int (WINAPI *IsAppThemedFun)(void);
QReadLocker readLock(&g_lamexp_themes_enabled.lock);
if(g_lamexp_themes_enabled.bInitialized)
{
return g_lamexp_themes_enabled.bThemesEnabled;
}
readLock.unlock();
QWriteLocker writeLock(&g_lamexp_themes_enabled.lock);
if(!g_lamexp_themes_enabled.bInitialized)
{
g_lamexp_themes_enabled.bThemesEnabled = false;
const MUtils::OS::Version::os_version_t &osVersion = MUtils::OS::os_version();
if(osVersion >= MUtils::OS::Version::WINDOWS_WINXP)
{
IsAppThemedFun IsAppThemedPtr = NULL;
QLibrary uxTheme(QString("%1/UxTheme.dll").arg(MUtils::OS::known_folder(MUtils::OS::FOLDER_SYSTEMFOLDER)));
if(uxTheme.load())
{
IsAppThemedPtr = (IsAppThemedFun) uxTheme.resolve("IsAppThemed");
}
if(IsAppThemedPtr)
{
g_lamexp_themes_enabled.bThemesEnabled = IsAppThemedPtr();
if(!g_lamexp_themes_enabled.bThemesEnabled)
{
qWarning("Theme support is disabled for this process!");
}
}
}
g_lamexp_themes_enabled.bInitialized = true;
}
return g_lamexp_themes_enabled.bThemesEnabled;
}
/*
* Insert entry to the window's system menu
*/
bool lamexp_append_sysmenu(const QWidget *win, const unsigned int identifier, const QString &text)
{
bool ok = false;
if(HMENU hMenu = GetSystemMenu(win->winId(), FALSE))
{
ok = (AppendMenuW(hMenu, MF_SEPARATOR, 0, 0) == TRUE);
ok = (AppendMenuW(hMenu, MF_STRING, identifier, MUTILS_WCHR(text)) == TRUE);
}
return ok;
}
/*
* Insert entry to the window's system menu
*/
bool lamexp_check_sysmenu_msg(void *message, const unsigned int identifier)
{
return (((MSG*)message)->message == WM_SYSCOMMAND) && ((((MSG*)message)->wParam & 0xFFF0) == identifier);
}
/*
* Update system menu entry
*/
bool lamexp_update_sysmenu(const QWidget *win, const unsigned int identifier, const QString &text)
{
bool ok = false;
if(HMENU hMenu = ::GetSystemMenu(win->winId(), FALSE))
{
ok = (ModifyMenu(hMenu, identifier, MF_STRING | MF_BYCOMMAND, identifier, MUTILS_WCHR(text)) == TRUE);
}
return ok;
}
/*
* Display the window's close button
*/
bool lamexp_enable_close_button(const QWidget *win, const bool bEnable)
{
bool ok = false;
if(HMENU hMenu = GetSystemMenu(win->winId(), FALSE))
{
ok = (EnableMenuItem(hMenu, SC_CLOSE, MF_BYCOMMAND | (bEnable ? MF_ENABLED : MF_GRAYED)) == TRUE);
}
return ok;
}
/*
* Check whether ESC key has been pressed since the previous call to this function
*/
bool lamexp_check_escape_state(void)
{
return (GetAsyncKeyState(VK_ESCAPE) & 0x0001) != 0;
}
/*
* Bring the specifed window to the front
*/
bool lamexp_bring_to_front(const QWidget *window)
{
bool ret = false;
if(window)
{
for(int i = 0; (i < 5) && (!ret); i++)
{
ret = (SetForegroundWindow(window->winId()) != FALSE);
SwitchToThisWindow(window->winId(), TRUE);
}
LockSetForegroundWindow(LSFW_LOCK);
}
return ret;
}
/*
* Bring window of the specifed process to the front (callback)
*/
static BOOL CALLBACK lamexp_bring_process_to_front_helper(HWND hwnd, LPARAM lParam)
{
DWORD processId = *reinterpret_cast<WORD*>(lParam);
DWORD windowProcessId = NULL;
GetWindowThreadProcessId(hwnd, &windowProcessId);
if(windowProcessId == processId)
{
SwitchToThisWindow(hwnd, TRUE);
SetForegroundWindow(hwnd);
return FALSE;
}
return TRUE;
}
/*
* Bring window of the specifed process to the front
*/
bool lamexp_bring_process_to_front(const unsigned long pid)
{
return EnumWindows(lamexp_bring_process_to_front_helper, reinterpret_cast<LPARAM>(&pid)) == TRUE;
}
static void lamexp_init_dwmapi(void)
{
QReadLocker writeLock(&g_lamexp_dwmapi.lock);
//Not initialized yet?
if(g_lamexp_dwmapi.bInitialized)
{
return;
}
//Reset function pointers
g_lamexp_dwmapi.dwmIsCompositionEnabled = NULL;
g_lamexp_dwmapi.dwmExtendFrameIntoClientArea = NULL;
g_lamexp_dwmapi.dwmEnableBlurBehindWindow = NULL;
//Does OS support DWM?
const MUtils::OS::Version::os_version_t &osVersion = MUtils::OS::os_version();
if(osVersion >= MUtils::OS::Version::WINDOWS_VISTA)
{
//Load DWMAPI.DLL
g_lamexp_dwmapi.dwmapi_dll = new QLibrary("dwmapi.dll");
if(g_lamexp_dwmapi.dwmapi_dll->load())
{
//Initialize function pointers
g_lamexp_dwmapi.dwmIsCompositionEnabled = (HRESULT (__stdcall*)(BOOL*)) g_lamexp_dwmapi.dwmapi_dll->resolve("DwmIsCompositionEnabled");
g_lamexp_dwmapi.dwmExtendFrameIntoClientArea = (HRESULT (__stdcall*)(HWND, const MARGINS*)) g_lamexp_dwmapi.dwmapi_dll->resolve("DwmExtendFrameIntoClientArea");
g_lamexp_dwmapi.dwmEnableBlurBehindWindow = (HRESULT (__stdcall*)(HWND, const DWM_BLURBEHIND*)) g_lamexp_dwmapi.dwmapi_dll->resolve("DwmEnableBlurBehindWindow");
}
else
{
MUTILS_DELETE(g_lamexp_dwmapi.dwmapi_dll);
qWarning("Failed to load DWMAPI.DLL on a DWM-enabled system!");
}
}
g_lamexp_dwmapi.bInitialized = true;
}
/*
* Enable "sheet of glass" effect on the given Window
*/
bool lamexp_sheet_of_glass(QWidget *window)
{
QReadLocker readLock(&g_lamexp_dwmapi.lock);
//Initialize the DWM API
while(!g_lamexp_dwmapi.bInitialized)
{
readLock.unlock();
lamexp_init_dwmapi();
readLock.relock();
}
BOOL bCompositionEnabled = FALSE;
//Required functions available?
if((g_lamexp_dwmapi.dwmIsCompositionEnabled != NULL) && (g_lamexp_dwmapi.dwmExtendFrameIntoClientArea != NULL) && (g_lamexp_dwmapi.dwmEnableBlurBehindWindow != NULL))
{
//Check if composition is currently enabled
if(HRESULT hr = g_lamexp_dwmapi.dwmIsCompositionEnabled(&bCompositionEnabled))
{
qWarning("DwmIsCompositionEnabled function has failed! (error %d)", hr);
return false;
}
}
//All functions available *and* composition enabled?
if(!bCompositionEnabled)
{
return false;
}
//Enable the "sheet of glass" effect on this window
MARGINS margins = {-1, -1, -1, -1};
if(HRESULT hr = g_lamexp_dwmapi.dwmExtendFrameIntoClientArea(window->winId(), &margins))
{
qWarning("DwmExtendFrameIntoClientArea function has failed! (error %d)", hr);
return false;
}
//Create and populate the Blur Behind structure
DWM_BLURBEHIND bb;
memset(&bb, 0, sizeof(DWM_BLURBEHIND));
bb.fEnable = TRUE;
bb.dwFlags = DWM_BB_ENABLE;
if(HRESULT hr = g_lamexp_dwmapi.dwmEnableBlurBehindWindow(window->winId(), &bb))
{
qWarning("DwmEnableBlurBehindWindow function has failed! (error %d)", hr);
return false;
}
//Required for Qt
window->setAutoFillBackground(false);
window->setAttribute(Qt::WA_TranslucentBackground);
window->setAttribute(Qt::WA_NoSystemBackground);
return true;
}
/*
* Update "sheet of glass" effect on the given Window
*/
bool lamexp_sheet_of_glass_update(QWidget *window)
{
QReadLocker readLock(&g_lamexp_dwmapi.lock);
//Initialize the DWM API
while(!g_lamexp_dwmapi.bInitialized)
{
readLock.unlock();
lamexp_init_dwmapi();
readLock.relock();
}
BOOL bCompositionEnabled = FALSE;
//Required functions available?
if((g_lamexp_dwmapi.dwmIsCompositionEnabled != NULL) && (g_lamexp_dwmapi.dwmEnableBlurBehindWindow != NULL))
{
//Check if composition is currently enabled
if(HRESULT hr = g_lamexp_dwmapi.dwmIsCompositionEnabled(&bCompositionEnabled))
{
qWarning("DwmIsCompositionEnabled function has failed! (error %d)", hr);
return false;
}
}
//All functions available *and* composition enabled?
if(!bCompositionEnabled)
{
return false;
}
//Create and populate the Blur Behind structure
DWM_BLURBEHIND bb;
memset(&bb, 0, sizeof(DWM_BLURBEHIND));
bb.fEnable = TRUE;
bb.dwFlags = DWM_BB_ENABLE;
if(HRESULT hr = g_lamexp_dwmapi.dwmEnableBlurBehindWindow(window->winId(), &bb))
{
qWarning("DwmEnableBlurBehindWindow function has failed! (error %d)", hr);
return false;
}
return true;
}
/*
* Get system color info
*/
QColor lamexp_system_color(const int color_id)
{
int nIndex = -1;
switch(color_id)
{
case lamexp_syscolor_text:
nIndex = COLOR_WINDOWTEXT; /*Text in windows*/
break;
case lamexp_syscolor_background:
nIndex = COLOR_WINDOW; /*Window background*/
break;
case lamexp_syscolor_caption:
nIndex = COLOR_CAPTIONTEXT; /*Text in caption, size box, and scroll bar arrow box*/
break;
default:
qWarning("Unknown system color id (%d) specified!", color_id);
nIndex = COLOR_WINDOWTEXT;
}
const DWORD rgb = GetSysColor(nIndex);
QColor color(GetRValue(rgb), GetGValue(rgb), GetBValue(rgb));
return color;
}
///////////////////////////////////////////////////////////////////////////////
// INITIALIZATION
///////////////////////////////////////////////////////////////////////////////
extern "C" void _lamexp_global_init_win32(void)
{
//Zero *before* constructors are called
MUTILS_ZERO_MEMORY(g_lamexp_wine);
MUTILS_ZERO_MEMORY(g_lamexp_themes_enabled);
MUTILS_ZERO_MEMORY(g_lamexp_dwmapi);
MUTILS_ZERO_MEMORY(g_lamexp_sounds);
}
///////////////////////////////////////////////////////////////////////////////
// FINALIZATION
///////////////////////////////////////////////////////////////////////////////
extern "C" void _lamexp_global_free_win32(void)
{
//Release DWM API
g_lamexp_dwmapi.dwmIsCompositionEnabled = NULL;
g_lamexp_dwmapi.dwmExtendFrameIntoClientArea = NULL;
g_lamexp_dwmapi.dwmEnableBlurBehindWindow = NULL;
MUTILS_DELETE(g_lamexp_dwmapi.dwmapi_dll);
//Clear sound cache
MUTILS_DELETE(g_lamexp_sounds.sound_db);
}