Compare commits
74 commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8f864f3394 | |||
| 3239e60471 | |||
| f1b734bea6 | |||
| 53f9506115 | |||
| 109330dbbd | |||
| 0a301fb9bf | |||
| a3d00be3fe | |||
| c60b6f71ed | |||
| f0d263d96e | |||
| 59a92fa34b | |||
| 667482cfea | |||
| cdde1ce9b8 | |||
| c87c8d0990 | |||
| 047808c89f | |||
| 94d2ebf1c2 | |||
| 801adbb17e | |||
| 5e5365274c | |||
| 2a1b30e166 | |||
| 9f7e7e30e2 | |||
| adca5111f6 | |||
| 1ae324b68a | |||
| 8e07b1efdd | |||
| 8e93120555 | |||
| 60890cecad | |||
| 13855c2e6f | |||
| 0bf8b321ae | |||
| d4db24ed7d | |||
| e42dbaa194 | |||
| 517f117575 | |||
| 42b30b1bf8 | |||
| 544da49e32 | |||
| 313a26c8e3 | |||
| f7de5ef803 | |||
| f8171f12f3 | |||
| 0e123f886d | |||
| b6b7e1c577 | |||
| 5d179bb91c | |||
| c1665b33e2 | |||
| 6ebe2604e7 | |||
| 33f3d8216f | |||
| cb320da8cd | |||
| 4f3f8b3e56 | |||
| 16604277fb | |||
| 6c588d068f | |||
| d75cf405f1 | |||
| 071505d3fe | |||
| c7d77c30ab | |||
| 75fdfaa095 | |||
| dc8951776f | |||
| 6bda4702df | |||
| 20a82b42d4 | |||
| cdadee58fc | |||
| 2115cdf508 | |||
| 46224d331c | |||
| 4756a00156 | |||
| 1b2ab191ca | |||
| 0880305b23 | |||
| 170d52067b | |||
| 4f637b4397 | |||
| 5b3b50a0d2 | |||
| 76d0afe672 | |||
| d801be1f61 | |||
| 78fabd3917 | |||
| bf01df610d | |||
| 621841e954 | |||
| 5229154c45 | |||
| e4732d086b | |||
| b3c663046f | |||
| 2e76621616 | |||
| 9d79757a49 | |||
| 90286b6853 | |||
| 8d1a0d190b | |||
| a373c706ac | |||
| 40bee90610 |
38 changed files with 6658 additions and 308 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -1,6 +1,8 @@
|
||||||
build
|
build
|
||||||
*.rdbg
|
*.rdbg
|
||||||
*.pdb
|
*.pdb
|
||||||
|
*.ps1
|
||||||
|
*.exe
|
||||||
Makefile
|
Makefile
|
||||||
Makefile.Debug
|
Makefile.Debug
|
||||||
Makefile.Release
|
Makefile.Release
|
||||||
15
README.md
Normal file
15
README.md
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
# Mixer
|
||||||
|
|
||||||
|
## Build
|
||||||
|
|
||||||
|
* Toolchain: [llvm-mingw UCRT 20220906](https://github.com/mstorsjo/llvm-mingw/releases/tag/20220906).
|
||||||
|
|
||||||
|
* Clone [this](https://code.qt.io/cgit/qt/qt5.git/tag/?h=v6.3.2) Qt branch
|
||||||
|
|
||||||
|
* Build Qt from sources following [this](https://wiki.qt.io/Building_Qt_6_from_Git) guide and executing `configure.bat` as such:
|
||||||
|
|
||||||
|
```
|
||||||
|
..\qt6\configure.bat -prefix ..\install -static -debug -opensource -confirm-license -qt-zlib -qt-libpng -qt-webp -qt-libjpeg -qt-freetype -skip qt3d -skip qtactiveqt -skip qtandroidextras -skip qtcharts -skip qtconnectivity -skip qtdatavis3d -skip qtdoc -skip qtgamepad -skip qtlocation -skip qtlottie -skip qtmacextras -skip qtmultimedia -skip qtnetworkauth -skip qtpurchasing -skip qtquick3d -skip qtquick3dphysics -skip qtquicktimeline -skip qtremoteobjects -skip qtscript -skip qtsensors -skip qtwayland -skip qtwebglplugin -skip qtwebview -skip webengine -nomake examples -nomake tests
|
||||||
|
```
|
||||||
|
|
||||||
|
* Clone this repo and execute `bueno.bat`.
|
||||||
10
assets.qrc
Normal file
10
assets.qrc
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
<!DOCTYPE RCC><RCC version="1.0">
|
||||||
|
<qresource prefix="/">
|
||||||
|
<file>assets/selawk.ttf</file>
|
||||||
|
<file>assets/notificationAreaIcon.png</file>
|
||||||
|
<file>assets/style.qss</file>
|
||||||
|
<file>assets/logo.ico</file>
|
||||||
|
<file>assets/mute.svg</file>
|
||||||
|
<file>assets/unmute.svg</file>
|
||||||
|
</qresource>
|
||||||
|
</RCC>
|
||||||
BIN
assets/installer.ico
Normal file
BIN
assets/installer.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 192 KiB |
BIN
assets/installer.xcf
Normal file
BIN
assets/installer.xcf
Normal file
Binary file not shown.
BIN
assets/logo.ico
Normal file
BIN
assets/logo.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 324 KiB |
BIN
assets/logo.png
Normal file
BIN
assets/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 38 KiB |
BIN
assets/logo.xcf
Normal file
BIN
assets/logo.xcf
Normal file
Binary file not shown.
BIN
assets/notificationAreaIcon.png
Normal file
BIN
assets/notificationAreaIcon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 156 KiB |
BIN
assets/selawk.ttf
Normal file
BIN
assets/selawk.ttf
Normal file
Binary file not shown.
6
assets/style.qss
Normal file
6
assets/style.qss
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
QMainWindow { background: rgba(100,100,100,100); }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
QCheckBox:hover, QCheckBox:checked { color: white }
|
||||||
BIN
assets/uninstaller.ico
Normal file
BIN
assets/uninstaller.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 192 KiB |
|
|
@ -1,2 +1,7 @@
|
||||||
qmake -o build\Makefile .\qtest.pro
|
taskkill /F /IM "MixerQ.exe"
|
||||||
mingw32-make.exe -C .\build -f Makefile.Release
|
taskkill /F /IM "MixerQd.exe"
|
||||||
|
qmake -o build\Makefile .\qtest.pro
|
||||||
|
REM mingw32-make.exe -C .\build -f Makefile.Release
|
||||||
|
mingw32-make.exe -C .\build -f Makefile.Debug
|
||||||
|
REM makensis /DBUILDTYPE=release install\installer.nsi
|
||||||
|
REM makensis /DBUILDTYPE=debug install\installer.nsi
|
||||||
|
|
|
||||||
265
install/installer.nsi
Normal file
265
install/installer.nsi
Normal file
|
|
@ -0,0 +1,265 @@
|
||||||
|
;Auto versioning-------------------------------
|
||||||
|
|
||||||
|
!makensis "/DBUILDTYPE=${BUILDTYPE} version.nsi"
|
||||||
|
!system "GetVersion.exe"
|
||||||
|
!include "Version.txt"
|
||||||
|
;optional cleanup
|
||||||
|
!delfile "GetVersion.exe"
|
||||||
|
!delfile "Version.txt"
|
||||||
|
|
||||||
|
;Includes--------------------------------
|
||||||
|
|
||||||
|
!include "MUI2.nsh"
|
||||||
|
!include "nsDialogs.nsh"
|
||||||
|
!include "LogicLib.nsh"
|
||||||
|
!include "${NSISDIR}\Contrib\Language files\English.nsh"
|
||||||
|
!include "${NSISDIR}\Contrib\Language files\Spanish.nsh"
|
||||||
|
;!include "${NSISDIR}\Contrib\Language files\English.nsh"
|
||||||
|
|
||||||
|
|
||||||
|
;Defines----------------------------------
|
||||||
|
!define MUI_LANGDLL_ALLLANGUAGES
|
||||||
|
!define MUI_UNICON "..\assets\uninstaller.ico"
|
||||||
|
!define MUI_ICON "..\assets\installer.ico"
|
||||||
|
|
||||||
|
|
||||||
|
;--------------------------------
|
||||||
|
;General
|
||||||
|
|
||||||
|
;Name and file
|
||||||
|
!if ${BUILDTYPE} == "release"
|
||||||
|
Name "MixerQ"
|
||||||
|
!else
|
||||||
|
Name "MixerQd"
|
||||||
|
!endif
|
||||||
|
OutFile "..\build\bin\MixerQ-installer-${version}.exe"
|
||||||
|
|
||||||
|
;Get installation folder from registry if available
|
||||||
|
;InstallDirRegKey HKCU "Software\Modern UI Test" ""
|
||||||
|
|
||||||
|
Unicode True
|
||||||
|
Var Is_Admin
|
||||||
|
Var Install_Type
|
||||||
|
|
||||||
|
;Request application privileges for UAC. If admin is not available, only user-level install will be available
|
||||||
|
RequestExecutionLevel highest
|
||||||
|
;--------------------------------
|
||||||
|
;Interface Settings
|
||||||
|
|
||||||
|
!define MUI_ABORTWARNING
|
||||||
|
|
||||||
|
;--------------------------------
|
||||||
|
;Pages
|
||||||
|
!insertmacro MUI_PAGE_WELCOME
|
||||||
|
!insertmacro MUI_PAGE_LICENSE "..\LICENSE.txt"
|
||||||
|
;!insertmacro MULTIUSER_PAGE_INSTALLMODE
|
||||||
|
Page Custom InstallTargetPage
|
||||||
|
;!insertmacro MUI_PAGE_COMPONENTS
|
||||||
|
!define MUI_PAGE_CUSTOMFUNCTION_PRE Skip_Directory_Func
|
||||||
|
!insertmacro MUI_PAGE_DIRECTORY
|
||||||
|
!insertmacro MUI_PAGE_INSTFILES
|
||||||
|
!insertmacro MUI_PAGE_FINISH
|
||||||
|
|
||||||
|
!insertmacro MUI_UNPAGE_WELCOME
|
||||||
|
!insertmacro MUI_UNPAGE_CONFIRM
|
||||||
|
!insertmacro MUI_UNPAGE_INSTFILES
|
||||||
|
!insertmacro MUI_UNPAGE_FINISH
|
||||||
|
|
||||||
|
;--------------------------------
|
||||||
|
;Languages
|
||||||
|
|
||||||
|
!insertmacro MUI_LANGUAGE "English"
|
||||||
|
!insertmacro MUI_LANGUAGE "Spanish"
|
||||||
|
!insertmacro MUI_LANGUAGE "SpanishInternational"
|
||||||
|
|
||||||
|
;English----------------------------
|
||||||
|
LangString Header_Title ${LANG_ENGLISH} "Configure Install"
|
||||||
|
LangString Header_Subtitle ${LANG_ENGLISH} "Customize install settings"
|
||||||
|
LangString Option_Scope ${LANG_ENGLISH} "Select for whom will $(^Name) be installed: "
|
||||||
|
LangString Scope_Machine ${LANG_ENGLISH} "All users"
|
||||||
|
LangString Scope_User ${LANG_ENGLISH} "Current user"
|
||||||
|
|
||||||
|
;Spanish/SpanishInternational----------------------------
|
||||||
|
LangString Header_Title ${LANG_SPANISH} "Configurar instalación"
|
||||||
|
LangString Header_Subtitle ${LANG_SPANISH} "Elija los ajustes de la instalación"
|
||||||
|
LangString Option_Scope ${LANG_SPANISH} "$(^Name) será instalado para: "
|
||||||
|
LangString Scope_Machine ${LANG_SPANISH} "Todos los usuarios"
|
||||||
|
LangString Scope_User ${LANG_SPANISH} "Usuario actual"
|
||||||
|
|
||||||
|
LangString Header_Title ${LANG_SPANISHINTERNATIONAL} "Configurar instalación"
|
||||||
|
LangString Header_Subtitle ${LANG_SPANISHINTERNATIONAL} "Elija los ajustes de la instalación"
|
||||||
|
LangString Option_Scope ${LANG_SPANISHINTERNATIONAL} "$(^Name) será instalado para: "
|
||||||
|
LangString Scope_Machine ${LANG_SPANISHINTERNATIONAL} "Todos los usuarios"
|
||||||
|
LangString Scope_User ${LANG_SPANISHINTERNATIONAL} "Usuario actual"
|
||||||
|
|
||||||
|
;Functions------------------------------
|
||||||
|
Function Skip_Directory_Func
|
||||||
|
;StrCmp $Install_Type "user" dontSkip
|
||||||
|
Abort # skip the page
|
||||||
|
;dontSkip:
|
||||||
|
FunctionEnd
|
||||||
|
|
||||||
|
!macro ONINIT un
|
||||||
|
Function ${un}.onInit
|
||||||
|
; The value of SetShellVarContext detetmines whether SHCTX is HKLM or HKCU
|
||||||
|
; and whether SMPROGRAMS refers to all users or just the current
|
||||||
|
!insertmacro MUI_LANGDLL_DISPLAY
|
||||||
|
UserInfo::GetAccountType
|
||||||
|
Pop $0
|
||||||
|
${If} $0 == "Admin"
|
||||||
|
; If we're an admin, default to installing to C:\Program Files
|
||||||
|
SetShellVarContext all
|
||||||
|
; StrCpy $INSTDIR "$PROGRAMFILES64\$(^Name)"
|
||||||
|
StrCpy $Is_Admin "true"
|
||||||
|
${Else}
|
||||||
|
; If we're just a user, default to installing to ~\AppData\Local
|
||||||
|
SetShellVarContext current
|
||||||
|
; StrCpy $INSTDIR "$LOCALAPPDATA\$(^Name)"
|
||||||
|
StrCpy $Is_Admin "false"
|
||||||
|
${EndIf}
|
||||||
|
|
||||||
|
; ${If} $INSTDIR == ""
|
||||||
|
; ; This only happens in the installer, because the uninstaller already knows INSTDIR
|
||||||
|
; ReadRegStr $0 SHCTX "Software\${PRODUCT_NAME}" ""
|
||||||
|
|
||||||
|
; ${If} $0 != ""
|
||||||
|
; ; If we're already installed, use the existing directory
|
||||||
|
; StrCpy $INSTDIR "$0"
|
||||||
|
; ${Else}
|
||||||
|
; StrCpy $INSTDIR "$INSTDIR_BASE\${PRODUCT_NAME}"
|
||||||
|
; ${Endif}
|
||||||
|
; ${Endif}
|
||||||
|
FunctionEnd
|
||||||
|
!macroend
|
||||||
|
|
||||||
|
!insertmacro ONINIT ""
|
||||||
|
!insertmacro ONINIT "un"
|
||||||
|
|
||||||
|
;NSDialog InstallTarget Page definition---------------------------------
|
||||||
|
|
||||||
|
Function InstallTargetPage
|
||||||
|
!insertmacro MUI_HEADER_TEXT $(Header_Title) $(Header_Subtitle)
|
||||||
|
;MessageBox MB_OK "Install type $Install_Type"
|
||||||
|
;MessageBox MB_OK "Build type ${BUILDTYPE}"
|
||||||
|
nsDialogs::Create 1018
|
||||||
|
Pop $0
|
||||||
|
|
||||||
|
FindWindow $0 "#32770"
|
||||||
|
GetDlgItem $1 $0 1 ;next/install button
|
||||||
|
SendMessage $1 ${WM_SETTEXT} 1 "STR:$(^InstallBtn)"
|
||||||
|
Pop $0
|
||||||
|
|
||||||
|
${NSD_CreateLabel} 0 0 100% 10% $(Option_Scope)
|
||||||
|
Pop $3
|
||||||
|
|
||||||
|
${NSD_CreateFirstRadioButton} 0 12% 40% 6% $(Scope_Machine)
|
||||||
|
Pop $1
|
||||||
|
${If} $Is_Admin == "false"
|
||||||
|
EnableWindow $1 0
|
||||||
|
StrCpy $INSTDIR "$LOCALAPPDATA\$(^Name)"
|
||||||
|
${Else}
|
||||||
|
SendMessage $1 ${BM_CLICK} "" "" ;Set default
|
||||||
|
StrCpy $INSTDIR "$PROGRAMFILES64\$(^Name)"
|
||||||
|
${EndIf}
|
||||||
|
${NSD_OnClick} $1 All_Users_Click
|
||||||
|
|
||||||
|
${NSD_CreateAdditionalRadioButton} 0 24% 40% 6% $(Scope_User)
|
||||||
|
Pop $2
|
||||||
|
${IfThen} $Is_Admin == "false" ${|} SendMessage $2 ${BM_CLICK} "" "" ${|}
|
||||||
|
${NSD_OnClick} $2 Current_User_Click
|
||||||
|
|
||||||
|
nsDialogs::Show
|
||||||
|
FunctionEnd
|
||||||
|
|
||||||
|
Function All_Users_Click
|
||||||
|
Pop $0
|
||||||
|
SetShellVarContext all
|
||||||
|
StrCpy $INSTDIR "$PROGRAMFILES64\$(^Name)"
|
||||||
|
StrCpy $Install_Type "machine"
|
||||||
|
;${NSD_SetText} $0 "machine"
|
||||||
|
;FindWindow $0 "#32770"
|
||||||
|
;GetDlgItem $1 $0 1 ;next/install button
|
||||||
|
;SendMessage $1 ${WM_SETTEXT} 1 "STR:$(^InstallBtn)"
|
||||||
|
FunctionEnd
|
||||||
|
|
||||||
|
Function Current_User_Click
|
||||||
|
Pop $0
|
||||||
|
SetShellVarContext current
|
||||||
|
StrCpy $INSTDIR "$LOCALAPPDATA\$(^Name)"
|
||||||
|
StrCpy $Install_Type "user"
|
||||||
|
;${NSD_SetText} $0 "user"
|
||||||
|
;FindWindow $0 "#32770"
|
||||||
|
;GetDlgItem $1 $0 1 ;next/install button
|
||||||
|
;SendMessage $1 ${WM_SETTEXT} 1 "STR:$(^NextBtn)"
|
||||||
|
FunctionEnd
|
||||||
|
|
||||||
|
;Default section----------------------
|
||||||
|
Section
|
||||||
|
SetRegView 64
|
||||||
|
SetOutPath $INSTDIR
|
||||||
|
|
||||||
|
!if ${BUILDTYPE} == "release"
|
||||||
|
File "..\build\bin\MixerQ.exe"
|
||||||
|
!else
|
||||||
|
File "..\build\bin\MixerQd.exe"
|
||||||
|
!endif
|
||||||
|
File "..\LICENSE.txt"
|
||||||
|
|
||||||
|
;Start menu shortcut
|
||||||
|
createDirectory "$SMPROGRAMS\$(^Name)"
|
||||||
|
createShortCut "$SMPROGRAMS\$(^Name)\$(^Name).lnk" "$INSTDIR\$(^Name).exe"
|
||||||
|
createShortCut "$SMPROGRAMS\$(^Name)\Uninstall$(^Name).lnk" "$INSTDIR\Uninstall$(^Name).exe"
|
||||||
|
|
||||||
|
;Store installation folder
|
||||||
|
WriteRegStr SHCTX "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" "DisplayName" "$(^Name)"
|
||||||
|
WriteRegStr SHCTX "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" "UninstallString" '"$INSTDIR\Uninstall$(^Name).exe"'
|
||||||
|
WriteRegDWORD SHCTX "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" "NoModify" 1
|
||||||
|
WriteRegDWORD SHCTX "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" "NoRepair" 1
|
||||||
|
WriteRegStr SHCTX "SOFTWARE\Microsoft\Windows\CurrentVersion\Run" "$(^Name)" "$INSTDIR\$(^Name)"
|
||||||
|
|
||||||
|
;Create uninstaller
|
||||||
|
WriteUninstaller "$INSTDIR\Uninstall$(^Name).exe"
|
||||||
|
|
||||||
|
SectionEnd
|
||||||
|
|
||||||
|
|
||||||
|
;--------------------------------
|
||||||
|
;Descriptions
|
||||||
|
|
||||||
|
; ;Language strings
|
||||||
|
; LangString DESC_SecDummy ${LANG_ENGLISH} "A test section."
|
||||||
|
|
||||||
|
; ;Assign language strings to sections
|
||||||
|
; !insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN
|
||||||
|
; !insertmacro MUI_DESCRIPTION_TEXT ${SecDummy} $(DESC_SecDummy)
|
||||||
|
; !insertmacro MUI_FUNCTION_DESCRIPTION_END
|
||||||
|
|
||||||
|
;--------------------------------
|
||||||
|
;Uninstaller Section
|
||||||
|
|
||||||
|
Section "Uninstall"
|
||||||
|
SetRegView 64
|
||||||
|
|
||||||
|
SetShellVarContext current
|
||||||
|
DeleteRegValue HKCU "SOFTWARE\Microsoft\Windows\CurrentVersion\Run" "$(^Name)"
|
||||||
|
DeleteRegKey HKCU "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)"
|
||||||
|
Delete "$SMPROGRAMS\$(^Name)\$(^Name).lnk"
|
||||||
|
Delete "$SMPROGRAMS\$(^Name)\Uninstall$(^Name).lnk"
|
||||||
|
RMDir "$SMPROGRAMS\$(^Name)"
|
||||||
|
|
||||||
|
${If} $Is_Admin == "true"
|
||||||
|
SetShellVarContext all
|
||||||
|
DeleteRegValue HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Run" "$(^Name)"
|
||||||
|
DeleteRegKey HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)"
|
||||||
|
Delete "$SMPROGRAMS\$(^Name)\$(^Name).lnk"
|
||||||
|
Delete "$SMPROGRAMS\$(^Name)\Uninstall$(^Name).lnk"
|
||||||
|
RMDir "$SMPROGRAMS\$(^Name)"
|
||||||
|
${EndIf}
|
||||||
|
|
||||||
|
Delete "$INSTDIR\$(^Name).exe"
|
||||||
|
Delete "$INSTDIR\LICENSE.txt"
|
||||||
|
Delete "$INSTDIR\Uninstall$(^Name).exe"
|
||||||
|
;!define PRODUCT_UNINST_ROOT_KEY "HKLM"
|
||||||
|
RMDir "$INSTDIR"
|
||||||
|
|
||||||
|
SectionEnd
|
||||||
26
install/version.nsi
Normal file
26
install/version.nsi
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
!if ${BUILDTYPE} == "release"
|
||||||
|
!define File "..\build\bin\MixerQ.exe"
|
||||||
|
!else
|
||||||
|
!define File "..\build\bin\MixerQd.exe"
|
||||||
|
!endif
|
||||||
|
|
||||||
|
OutFile "GetVersion.exe"
|
||||||
|
SilentInstall silent
|
||||||
|
RequestExecutionLevel user ; don't write $EXEDIR\Version.txt with admin permissions and prevent invoking UAC
|
||||||
|
|
||||||
|
Section
|
||||||
|
|
||||||
|
## Get file version
|
||||||
|
GetDllVersion "${File}" $R0 $R1
|
||||||
|
IntOp $R2 $R0 / 0x00010000
|
||||||
|
IntOp $R3 $R0 & 0x0000FFFF
|
||||||
|
IntOp $R4 $R1 / 0x00010000
|
||||||
|
IntOp $R5 $R1 & 0x0000FFFF
|
||||||
|
StrCpy $R1 "$R2.$R3.$R4.$R5"
|
||||||
|
|
||||||
|
## Write it to a !define for use in main script
|
||||||
|
FileOpen $R0 "$EXEDIR\Version.txt" w
|
||||||
|
FileWrite $R0 '!define version "$R1"'
|
||||||
|
FileClose $R0
|
||||||
|
|
||||||
|
SectionEnd
|
||||||
36
qtest.pro
36
qtest.pro
|
|
@ -1,8 +1,28 @@
|
||||||
CONFIG += debug console
|
TEMPLATE = app
|
||||||
QT += widgets
|
QMAKE_CXXFLAGS += --target=x86_64-w64-mingw32 -Werror=return-type
|
||||||
INCLUDEPATH += "$$PWD\src" "$$PWD\src\qt" "$$PWD\src\back" "$$PWD\src\cont"
|
QMAKE_LFLAGS += --target=x86_64-w64-mingw32 -v
|
||||||
DESTPATH += "$$PWD\src" "$$PWD\src\qt" "$$PWD\src\back" "$$PWD\src\cont"
|
CONFIG(release, debug|release) {
|
||||||
VPATH += "$$PWD\src" "$$PWD\src\qt" "$$PWD\src\back" "$$PWD\src\cont"
|
TARGET = MixerQ
|
||||||
SOURCES += qtestmain.cpp qtclasses.cpp backlasses.cpp contclasses.cpp
|
DESTDIR = bin
|
||||||
HEADERS += qtclasses.h backlasses.h contclasses.h global.h debug.h
|
VERSION = 0.9.0.0
|
||||||
#DESTDIR += "build"
|
#QMAKE_CXXFLAGS += -O2 < Default. Modifying requires removing.
|
||||||
|
} else {
|
||||||
|
TARGET = MixerQd
|
||||||
|
DESTDIR = bin
|
||||||
|
VERSION = 0.9.0.1
|
||||||
|
QMAKE_CXXFLAGS += -g -gcodeview -O0
|
||||||
|
QMAKE_LFLAGS += -g -Wl,-pdb=
|
||||||
|
}
|
||||||
|
|
||||||
|
LIBS += -lWinmm -lodbc32 -lodbccp32 -luuid -loleaut32 -lole32 -lshell32 -ladvapi32 -lcomdlg32 -lwinspool -lgdi32 -luser32 -lkernel32 -lpropsys -static -stdlib=libc++ -lunwind
|
||||||
|
DEFINES += QT_LOGGING_TO_CONSOLE=1 WIN32_LEAN_AND_MEAN _WIN32_WINNT=0x0602
|
||||||
|
DEFINES_DEBUG += DEBUG
|
||||||
|
|
||||||
|
QT += widgets network svg
|
||||||
|
INCLUDEPATH += "$$PWD\src" "$$PWD\src\qt" "$$PWD\src\back" "$$PWD\src\back\reimpl" "$$PWD\src\cont"
|
||||||
|
VPATH += "$$PWD\src" "$$PWD\src\qt" "$$PWD\src\back" "$$PWD\src\back\reimpl" "$$PWD\src\cont"
|
||||||
|
|
||||||
|
SOURCES += qtestmain.cpp qtclasses.cpp backlasses.cpp backsessionclasses.cpp contclasses.cpp contsessionclasses.cpp settings.cpp
|
||||||
|
HEADERS += qtclasses.h backlasses.h backsessionclasses.h contclasses.h contsessionclasses.h global.h debug.h backfuncs.h ipolicyconfig.h msinclude.h meterslider.h qtvisuals.h settings.h
|
||||||
|
RESOURCES = assets.qrc
|
||||||
|
RC_ICONS += assets/logo.ico
|
||||||
|
|
|
||||||
32
src/back/backfuncs.h
Normal file
32
src/back/backfuncs.h
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
GUID inline NGuidToGUID(NGuid guid) {
|
||||||
|
GUID msGuid = GUID();
|
||||||
|
msGuid.Data1 = guid.data1;
|
||||||
|
msGuid.Data2 = guid.data2;
|
||||||
|
msGuid.Data3 = guid.data3;
|
||||||
|
for (int i = 0; i < 8; i++){
|
||||||
|
msGuid.Data4[i] = guid.data4[i];
|
||||||
|
//log_debugcpp("MSGUID DATA4 BYTE " << i << ": ");
|
||||||
|
//log_debugcpp(print_as_binary(8, uint32_t, msGuid.Data4[i]));
|
||||||
|
}
|
||||||
|
//log_debugcpp("MSGUID DATA1: " << msGuid.Data1);
|
||||||
|
//log_debugcpp("MSGUID DATA2: " << msGuid.Data2);
|
||||||
|
//log_debugcpp("MSGUID DATA3: " << msGuid.Data3);
|
||||||
|
|
||||||
|
return msGuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
NGuid inline GUIDToNGuid(LPGUID msGuid){
|
||||||
|
NGuid guid = NGuid();
|
||||||
|
guid.data1 = msGuid->Data1;
|
||||||
|
guid.data2 = msGuid->Data2;
|
||||||
|
guid.data3 = msGuid->Data3;
|
||||||
|
for (int i = 0; i < 8; i++){
|
||||||
|
guid.data4[i] = msGuid->Data4[i];
|
||||||
|
//log_debugcpp("GUID DATA4 BYTE " << i << ": ");
|
||||||
|
//log_debugcpp(print_as_binary(8, uint32_t, guid.data4[i]));
|
||||||
|
}
|
||||||
|
//log_debugcpp("GUID DATA1: " << guid.data1);
|
||||||
|
//log_debugcpp("GUID DATA2: " << guid.data2);
|
||||||
|
//log_debugcpp("GUID DATA3: " << guid.data3);
|
||||||
|
return guid;
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,51 +1,173 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#define WIN32_LEAN_AND_MEAN
|
|
||||||
|
|
||||||
#include "debug.h"
|
#include "msinclude.h"
|
||||||
|
#include "backsessionclasses.h"
|
||||||
#include "global.h"
|
#include "global.h"
|
||||||
#include <vector>
|
#include "contclasses.h"
|
||||||
#include <iostream>
|
//#include "environment.h"
|
||||||
|
|
||||||
#include <Windows.h>
|
class EndpointVolumeCallback;
|
||||||
#include <mmdeviceapi.h>
|
class Session;
|
||||||
#include <combaseapi.h>
|
|
||||||
#include <initguid.h>
|
|
||||||
#include <functiondiscoverykeys_devpkey.h>
|
|
||||||
|
|
||||||
#include <endpointvolume.h>
|
// Convert a wide UTF16LE string to an UTF8 string
|
||||||
#include <audiopolicy.h>
|
static inline std::string utf16ToUtf8(const wchar_t* wstr) {
|
||||||
#include <audioclient.h>
|
if(!wstr || wstr[0] == '\0') return std::string();
|
||||||
//#include <comdef.h>
|
int size_needed = WideCharToMultiByte(CP_UTF8,
|
||||||
//#include <comip.h>
|
0,
|
||||||
#include <Winerror.h>
|
wstr,
|
||||||
|
-1,
|
||||||
|
NULL,
|
||||||
|
0,
|
||||||
|
NULL,
|
||||||
|
NULL);
|
||||||
|
std::string str(size_needed, 0);
|
||||||
|
WideCharToMultiByte(CP_UTF8,
|
||||||
|
0,
|
||||||
|
wstr,
|
||||||
|
-1,
|
||||||
|
&str[0],
|
||||||
|
size_needed,
|
||||||
|
NULL,
|
||||||
|
NULL);
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert an UTF8 string to a wide UTF16LE String
|
||||||
|
/*
|
||||||
|
* std::wstring utf8_decode(const std::string &str)
|
||||||
|
* {
|
||||||
|
* if( str.empty() ) return std::wstring();
|
||||||
|
* int size_needed = MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), NULL, 0);
|
||||||
|
* std::wstring wstrTo( size_needed, 0 );
|
||||||
|
* MultiByteToWideChar (CP_UTF8, 0, &str[0], (int)str.size(), &wstrTo[0], size_needed);
|
||||||
|
* return wstrTo;
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
|
||||||
class Endpoint {
|
class Endpoint {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Endpoint(IMMDevice* endpoint);
|
Endpoint(IMMDevice* endpoint, IPolicyConfig7* policyConfig, uint64_t idx = 0);
|
||||||
void setVolume(int channel, float volume);
|
//todo: how to forward declare delegate constructors?
|
||||||
/* float getLeftChannelVolume(); */
|
//Endpoint(IMMDevice* endpoint) : Endpoint(endpoint, 0) {};
|
||||||
/* float getRightChannelVolume(); */
|
void reloadEndpointChannels();
|
||||||
|
uint64_t getIndex();
|
||||||
|
void setIndex(uint64_t idx);
|
||||||
|
void setVolume(NGuid guid, int channel, float volume);
|
||||||
|
uint32_t getChannelCount();
|
||||||
float getVolume(int channel);
|
float getVolume(int channel);
|
||||||
void setMute();
|
void setMute(NGuid guid, bool muted);
|
||||||
bool getMute();
|
bool getMute();
|
||||||
LPWSTR getName();
|
void setState(EndpointState state);
|
||||||
|
EndpointState getState();
|
||||||
|
Roles getRoles();
|
||||||
|
void setRoles(Roles role);
|
||||||
|
void assignRoles(Roles role);
|
||||||
|
void removeRoles(Roles role);
|
||||||
|
void setFlow();
|
||||||
|
Flows getFlow();
|
||||||
|
float getPeakVolume();
|
||||||
|
std::wstring getId();
|
||||||
|
std::wstring getName();
|
||||||
|
void updateName();
|
||||||
|
|
||||||
|
void setVolumeCallback(EndpointVolumeCallback *epc);
|
||||||
|
void removeVolumeCallback(EndpointVolumeCallback *epc);
|
||||||
|
|
||||||
|
/* sessions */
|
||||||
|
std::vector<Session*> getSessions();
|
||||||
|
size_t getSessionCount();
|
||||||
|
void addSession(Session* session);
|
||||||
|
void registerNewSessionNotification(EndpointNewSessionCallback* ensc);
|
||||||
|
void unregisterNewSessionNotification(EndpointNewSessionCallback* ensc);
|
||||||
|
void deleteSessions();
|
||||||
|
void activateEndpointSessions();
|
||||||
|
//void deleteSessionManager();
|
||||||
|
std::mutex endpointSessionsMutex;
|
||||||
~Endpoint();
|
~Endpoint();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
IMMDevice* endpoint;
|
void inline activateEndpointVolume();
|
||||||
IAudioEndpointVolume *endpointVolume ;
|
|
||||||
|
std::vector<Session*> endpointSessions;
|
||||||
|
uint32_t channelCount = 0;
|
||||||
|
IMMDevice *endpoint;
|
||||||
|
IAudioEndpointVolume *endpointVolume = nullptr;
|
||||||
IPropertyStore *properties;
|
IPropertyStore *properties;
|
||||||
LPWSTR friendlyName;
|
IAudioMeterInformation *endpointPeakMeter = nullptr;
|
||||||
// LPWSTR endpointID = NULL;
|
//IAudioClient *audioClient;
|
||||||
|
int64_t defTime, minTime;
|
||||||
|
IAudioSessionManager2 *sessionManager = nullptr;
|
||||||
|
Flows flow;
|
||||||
|
std::wstring friendlyName;
|
||||||
|
std::wstring descriptionName;
|
||||||
|
std::wstring deviceName;
|
||||||
|
std::wstring endpointId;
|
||||||
|
EndpointState endpointState;
|
||||||
|
Roles endpointRoles = (Roles)0;
|
||||||
|
uint64_t idx;
|
||||||
|
//Not implemented in llvm-mingw. Sad! todo: mingw patch
|
||||||
|
IPolicyConfig7* policyConfig;
|
||||||
|
};
|
||||||
|
|
||||||
|
class EndpointVolumeCallback : public IAudioEndpointVolumeCallback {
|
||||||
|
|
||||||
|
public:
|
||||||
|
EndpointVolumeCallback(Endpoint* ep);
|
||||||
|
|
||||||
|
ULONG AddRef();
|
||||||
|
ULONG Release();
|
||||||
|
HRESULT QueryInterface(REFIID riid, VOID **ppvInterface);
|
||||||
|
HRESULT OnNotify(PAUDIO_VOLUME_NOTIFICATION_DATA update);
|
||||||
|
void updateVolumeInfo(AUDIO_VOLUME_NOTIFICATION_DATA newVolume, float* channelVolumes);
|
||||||
|
void reportFinished();
|
||||||
|
//~EndpointVolumeCallback();
|
||||||
|
|
||||||
|
private:
|
||||||
|
ULONG ref = 1;
|
||||||
|
Endpoint* ep;
|
||||||
|
std::atomic<bool> wait = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
class EndpointSituationCallback : public IMMNotificationClient {
|
||||||
|
public:
|
||||||
|
EndpointSituationCallback(Overseer* os);
|
||||||
|
ULONG AddRef();
|
||||||
|
ULONG Release();
|
||||||
|
HRESULT QueryInterface(REFIID riid, VOID **ppvInterface);
|
||||||
|
HRESULT OnDefaultDeviceChanged(EDataFlow flow, ERole role, LPCWSTR pwstrDeviceId);
|
||||||
|
HRESULT OnDeviceAdded(LPCWSTR pwstrDeviceId);
|
||||||
|
HRESULT OnDeviceRemoved(LPCWSTR pwstrDeviceId);
|
||||||
|
HRESULT OnDeviceStateChanged(LPCWSTR pwstrDeviceId, DWORD dwNewState);
|
||||||
|
HRESULT OnPropertyValueChanged(LPCWSTR pwstrDeviceId, const PROPERTYKEY key);
|
||||||
|
void reportFinishedStateChange();
|
||||||
|
private:
|
||||||
|
ULONG ref = 1;
|
||||||
|
Overseer* os;
|
||||||
|
std::atomic<bool> isEpStateChanging = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Overseer {
|
class Overseer {
|
||||||
//TODO singleton?
|
|
||||||
public:
|
public:
|
||||||
Overseer();
|
Overseer();
|
||||||
|
void registerEndpointSituationCallback();
|
||||||
|
NGuid getGuid();
|
||||||
|
|
||||||
std::vector<Endpoint*> getPlaybackEndpoints();
|
std::vector<Endpoint*> getPlaybackEndpoints();
|
||||||
void reloadEndpoints();
|
std::vector<Endpoint*> getCaptureEndpoints();
|
||||||
|
void updateEndpointInfo(std::wstring endpointId);
|
||||||
|
|
||||||
|
void createEndpoints(Flows flow);
|
||||||
|
Endpoint* addEndpoint(std::wstring endpointId, /* out */ Flows* flow);
|
||||||
|
|
||||||
|
void reportFinishedStateChange();
|
||||||
|
|
||||||
|
std::mutex playbackMutex;
|
||||||
|
std::mutex captureMutex;
|
||||||
|
//void setEndpointStatusCallback();
|
||||||
|
//void setEndpointStatusCallback();
|
||||||
|
|
||||||
//~Overseer();
|
//~Overseer();
|
||||||
//int getDefaultPlaybackEndpoint(Endpoint** defaultEndpoint);
|
//int getDefaultPlaybackEndpoint(Endpoint** defaultEndpoint);
|
||||||
//int getDefaultCaptureEndpoint(Endpoint** defaultEndpoint);
|
//int getDefaultCaptureEndpoint(Endpoint** defaultEndpoint);
|
||||||
|
|
@ -54,12 +176,65 @@ class Overseer {
|
||||||
~Overseer();
|
~Overseer();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
unsigned int numPlaybackEndpoints;
|
|
||||||
IMMDeviceEnumerator *deviceEnumerator;
|
|
||||||
std::vector<Endpoint*> playbackDevices;
|
|
||||||
void initCOMLibrary();
|
void initCOMLibrary();
|
||||||
|
|
||||||
|
NGuid guid;
|
||||||
|
|
||||||
|
IMMDeviceEnumerator *deviceEnumerator;
|
||||||
|
EndpointSituationCallback epsc;
|
||||||
|
|
||||||
|
std::vector<Endpoint*> playbackDevices;
|
||||||
|
std::vector<Endpoint*> captureDevices;
|
||||||
|
IPolicyConfig7* policyConfig;
|
||||||
|
friend class Endpoint;
|
||||||
//IMMDeviceCollection *deviceCollection;
|
//IMMDeviceCollection *deviceCollection;
|
||||||
//int numCaptureEndpoints;
|
//int numCaptureEndpoints;
|
||||||
//std::vector<Endpoint*> *captureDevices;
|
//std::vector<Endpoint*> *captureDevices;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class EndpointNewSessionCallback : public IAudioSessionNotification {
|
||||||
|
private:
|
||||||
|
struct SessionThreadParams;
|
||||||
|
|
||||||
|
public:
|
||||||
|
EndpointNewSessionCallback(EndpointHandler *eph);
|
||||||
|
ULONG AddRef();
|
||||||
|
ULONG Release();
|
||||||
|
HRESULT QueryInterface(REFIID riid, VOID **ppvInterface);
|
||||||
|
HRESULT OnSessionCreated(IAudioSessionControl *NewSession);
|
||||||
|
void createSessionThread(SessionThreadParams params);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::atomic<bool> wait = false;
|
||||||
|
ULONG ref = 1;
|
||||||
|
EndpointHandler *eph;
|
||||||
|
|
||||||
|
struct SessionThreadParams {
|
||||||
|
EndpointHandler *eph;
|
||||||
|
Session *session;
|
||||||
|
bool isDelete;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace Environment {
|
||||||
|
wchar_t* getExeAbsPath(uint32_t *exeAbsPathLength);
|
||||||
|
std::string createSettingsPath(SettingsTargetDirectory target);
|
||||||
|
void populateSystemValues();
|
||||||
|
void openControlPanel();
|
||||||
|
ProcessedNativeEvent processTopLevelWindowMessage(void* msg);
|
||||||
|
ProcessedNativeEvent updateColors();
|
||||||
|
bool checkStartup(HKEY rootKeyFlags);
|
||||||
|
void updateStartupConfig(bool onStartup);
|
||||||
|
void setStartupConfig(bool onStartup);
|
||||||
|
bool isLightMode();
|
||||||
|
bool isToRunAtStartup();
|
||||||
|
uint32_t getAccentColor();
|
||||||
|
|
||||||
|
//todo: binary path cache unused
|
||||||
|
static std::wstring exeAbsPath;
|
||||||
|
static uint32_t exeAbsPathLen;
|
||||||
|
static bool lightMode;
|
||||||
|
static bool startup = false;
|
||||||
|
static HKEY scope;
|
||||||
|
static uint32_t accentColor;
|
||||||
|
};
|
||||||
|
|
|
||||||
425
src/back/backsessionclasses.cpp
Normal file
425
src/back/backsessionclasses.cpp
Normal file
|
|
@ -0,0 +1,425 @@
|
||||||
|
#include "backsessionclasses.h"
|
||||||
|
#include "backfuncs.h"
|
||||||
|
|
||||||
|
SessionStateCallback::SessionStateCallback(SessionHandler *sh) {
|
||||||
|
this->sh = sh;
|
||||||
|
}
|
||||||
|
|
||||||
|
ULONG SessionStateCallback::AddRef() {
|
||||||
|
return InterlockedIncrement(&ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
ULONG SessionStateCallback::Release() {
|
||||||
|
ULONG tempRef = InterlockedDecrement(&ref);
|
||||||
|
if (tempRef == 0) {
|
||||||
|
delete this;
|
||||||
|
}
|
||||||
|
return tempRef;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT SessionStateCallback::QueryInterface(REFIID riid, VOID **ppvInterface) {
|
||||||
|
if (IID_IUnknown == riid)
|
||||||
|
{
|
||||||
|
AddRef();
|
||||||
|
*ppvInterface = (IUnknown*)this;
|
||||||
|
}
|
||||||
|
else if (__uuidof(IAudioSessionNotification) == riid)
|
||||||
|
{
|
||||||
|
AddRef();
|
||||||
|
*ppvInterface = (IMMNotificationClient*)this;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*ppvInterface = NULL;
|
||||||
|
return E_NOINTERFACE;
|
||||||
|
}
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT SessionStateCallback::OnDisplayNameChanged(LPCWSTR NewDisplayName, LPCGUID EventContext) {
|
||||||
|
//TODO: Preguntar
|
||||||
|
while(sh->getVolumeInfo()->isNameChanged == true);
|
||||||
|
|
||||||
|
sh->setName(std::wstring(NewDisplayName));
|
||||||
|
sh->getVolumeInfo()->isNameChanged = true;
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT SessionStateCallback::OnIconPathChanged(LPCWSTR NewIconPath, LPCGUID EventContex) {
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT SessionStateCallback::OnSimpleVolumeChanged(float NewVolume, BOOL NewMute, LPCGUID EventContext) {
|
||||||
|
sh->getVolumeInfo()->muted = NewMute;
|
||||||
|
sh->getVolumeInfo()->mainVolume = NewVolume;
|
||||||
|
sh->getVolumeInfo()->caller = GUIDToNGuid((LPGUID)EventContext);
|
||||||
|
/*
|
||||||
|
* if (NewMute)
|
||||||
|
* {
|
||||||
|
* printf("MUTE\n");
|
||||||
|
* }
|
||||||
|
* else
|
||||||
|
* {
|
||||||
|
* printf("Volume = %d percent\n",
|
||||||
|
* (UINT32)(100*NewVolume + 0.5));
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT SessionStateCallback::OnChannelVolumeChanged(DWORD ChannelCount, float NewChannelVolumeArray[], DWORD ChangedChannel, LPCGUID EventContext) {
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT SessionStateCallback::OnGroupingParamChanged(LPCGUID NewGroupingParam, LPCGUID EventContext) {
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT SessionStateCallback::OnStateChanged(AudioSessionState NewState) {
|
||||||
|
SessionState newState;// = sh->getState();
|
||||||
|
switch (NewState) {
|
||||||
|
case AudioSessionStateActive:
|
||||||
|
newState = SessionState::ACTIVE;
|
||||||
|
break;
|
||||||
|
case AudioSessionStateInactive:
|
||||||
|
newState = SessionState::INACTIVE;
|
||||||
|
break;
|
||||||
|
case AudioSessionStateExpired:
|
||||||
|
newState = SessionState::EXPIRED;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
sh->reviseSessionShowing(newState);
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT SessionStateCallback::OnSessionDisconnected(AudioSessionDisconnectReason DisconnectReason) {
|
||||||
|
if (DisconnectReason != DisconnectReasonDeviceRemoval) {
|
||||||
|
sh->setState(SessionState::DISCONNECTED);
|
||||||
|
sh->reviseSessionShowing(SessionState::DISCONNECTED);
|
||||||
|
}
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
Session::Session(Endpoint* ep, IAudioSessionControl2* sessionControl, size_t idx) {
|
||||||
|
this->ep = ep;
|
||||||
|
this->sessionControl = sessionControl;
|
||||||
|
this->idx = idx;
|
||||||
|
//https://matthewvaneerde.wordpress.com/2012/06/08/getting-audio-peak-meter-values-for-all-active-audio-sessions/
|
||||||
|
if (FAILED(sessionControl->QueryInterface(__uuidof(IAudioMeterInformation), (void**)&meterInformation))) { log_wdebugcpp(L"sPeakbros......"); };
|
||||||
|
//meterInformation = (IAudioMeterInformation*)sessionControl;
|
||||||
|
|
||||||
|
AudioSessionState msState;
|
||||||
|
sessionControl->GetState(&msState);
|
||||||
|
switch (msState) {
|
||||||
|
case AudioSessionState::AudioSessionStateActive:
|
||||||
|
this->sessionState = SessionState::ACTIVE;
|
||||||
|
break;
|
||||||
|
case AudioSessionState::AudioSessionStateInactive:
|
||||||
|
this->sessionState = SessionState::INACTIVE;
|
||||||
|
break;
|
||||||
|
case AudioSessionState::AudioSessionStateExpired:
|
||||||
|
this->sessionState = SessionState::EXPIRED;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
sessionControl->QueryInterface(__uuidof(ISimpleAudioVolume), (void**)&sessionVolume);
|
||||||
|
DWORD pid;
|
||||||
|
sessionControl->GetProcessId(&pid);
|
||||||
|
if (sessionControl->IsSystemSoundsSession() == S_OK)
|
||||||
|
this->sessionName = std::wstring(LSTRING_SYSTEM_SOUNDS);
|
||||||
|
else {
|
||||||
|
LPWSTR sessionDisplayName;
|
||||||
|
this->sessionControl->GetDisplayName(&sessionDisplayName);
|
||||||
|
if (!wcscmp(sessionDisplayName, L"")) {
|
||||||
|
std::wstring exePath;
|
||||||
|
if (getExePath(pid, &exePath)) {
|
||||||
|
this->sessionName = exePath;
|
||||||
|
if (fetchName(exePath, pid)) goto nameFound;
|
||||||
|
}
|
||||||
|
if (fetchNameViaWindowName(pid, &this->sessionName)) goto nameFound;
|
||||||
|
} else {
|
||||||
|
this->sessionName = std::wstring(sessionDisplayName);
|
||||||
|
goto nameFound;
|
||||||
|
}
|
||||||
|
|
||||||
|
nameFound:
|
||||||
|
CoTaskMemFree(sessionDisplayName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float Session::getVolume(int channel){
|
||||||
|
float volume;
|
||||||
|
if (channel == AudioChannel::CHANNEL_MAIN) {
|
||||||
|
if(FAILED(sessionVolume->GetMasterVolume(&volume))) { /* log_debugcpp("si") */;}
|
||||||
|
} else {
|
||||||
|
return 0.0;
|
||||||
|
//if(FAILED(endpointVolume->GetChannelVolumeLevelScalar(channel, &volume))) { /* log_debugcpp("si"); */}
|
||||||
|
}
|
||||||
|
return volume;
|
||||||
|
}
|
||||||
|
|
||||||
|
float Session::getPeakVolume() {
|
||||||
|
float peakVol;
|
||||||
|
if(meterInformation) meterInformation->GetPeakValue(&peakVol);
|
||||||
|
else return 0;
|
||||||
|
return peakVol;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* uint32_t Endpoint::getChannelCount(){
|
||||||
|
* return (uint32_t)channelCount;
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
|
||||||
|
std::wstring Session::getName() {
|
||||||
|
return sessionName;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Session::setName(std::wstring newName) {
|
||||||
|
this->sessionName = newName;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Session::getMute() {
|
||||||
|
BOOL mut;
|
||||||
|
if(FAILED(sessionVolume->GetMute(&mut))) { /* TIP: Below */ }
|
||||||
|
bool mute = (bool)mut;
|
||||||
|
return mute;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Session::setVolume(NGuid guid, int channel, float volume) {
|
||||||
|
//TIP: There used to be log messages here. Now, it's a ghost town.
|
||||||
|
GUID tempMsGuid = NGuidToGUID(guid);
|
||||||
|
if (channel == AudioChannel::CHANNEL_MAIN) {
|
||||||
|
if(FAILED(sessionVolume->SetMasterVolume(volume, &tempMsGuid))) {};
|
||||||
|
} else {
|
||||||
|
//if(FAILED(sessionVolume->SetChannelVolumeLevelScalar(channel, volume, &tempMsGuid))) {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Session::setIndex(size_t idx) {
|
||||||
|
this->idx = idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Session::setMute(NGuid guid, bool muted) {
|
||||||
|
GUID tempMsGuid = NGuidToGUID(guid);
|
||||||
|
if(FAILED(sessionVolume->SetMute(muted, &tempMsGuid))) { log_wdebugcpp(std::wstring(L"SessionVolume null?")); };
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Session::getExePath(DWORD pid, std::wstring *exePath) {
|
||||||
|
//std::wstring msixName;
|
||||||
|
HANDLE processHandle;
|
||||||
|
wchar_t fileName[UNICODE_STRING_MAX_CHARS];
|
||||||
|
processHandle = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);
|
||||||
|
if (processHandle != NULL) {
|
||||||
|
if (GetModuleFileNameEx(processHandle, NULL, fileName, UNICODE_STRING_MAX_CHARS) == 0) {
|
||||||
|
CloseHandle(processHandle);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log_wdebugcpp(L"aye no procname. -> " + std::to_wstring(GetLastError()));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
*exePath = std::wstring(fileName);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Session::fetchNameViaFD(std::wstring exePath, DWORD pid, std::wstring *sessionName) {
|
||||||
|
/* File description retrieval: size and available lang-codepages */
|
||||||
|
struct LANGANDCODEPAGE {
|
||||||
|
WORD wLanguage;
|
||||||
|
WORD wCodePage;
|
||||||
|
} *translationArray;
|
||||||
|
|
||||||
|
DWORD filler;
|
||||||
|
DWORD fileVersionInfoSize = GetFileVersionInfoSizeExW
|
||||||
|
(FILE_VER_GET_LOCALISED | FILE_VER_GET_NEUTRAL, exePath.c_str(), &filler);
|
||||||
|
if (!fileVersionInfoSize) return false;
|
||||||
|
|
||||||
|
void* fileVersionInfo = malloc(fileVersionInfoSize);
|
||||||
|
if(!GetFileVersionInfoExW(FILE_VER_GET_LOCALISED | FILE_VER_GET_NEUTRAL,
|
||||||
|
exePath.c_str(),0,fileVersionInfoSize, fileVersionInfo)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT translationArrayLen = 0;
|
||||||
|
if (!VerQueryValueW(fileVersionInfo, L"\\VarFileInfo\\Translation", (LPVOID*)&translationArray, &translationArrayLen)) {
|
||||||
|
free(fileVersionInfo);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//File descriptor parsing
|
||||||
|
//TODO: https://learn.microsoft.com/en-us/windows/win32/api/winnls/nf-winnls-getuserpreferreduilanguages
|
||||||
|
/* It is possible to retrieve user languages and try to use one of those before falling back to whatever
|
||||||
|
* is available. Also possible to hardcode en-US or any other lang-codepage combo. When an actual translation
|
||||||
|
* sysem is put in place, I'll come finish this up.
|
||||||
|
*/
|
||||||
|
uint64_t availableLangs = (translationArrayLen / sizeof(LANGANDCODEPAGE));
|
||||||
|
if (!availableLangs) { free(fileVersionInfo); return false; }
|
||||||
|
|
||||||
|
int8_t syslangIdx = -1;
|
||||||
|
wchar_t metadataStringKey[256];
|
||||||
|
wchar_t* metadataString = NULL;
|
||||||
|
for (UINT i = 0; i < availableLangs; i++) {
|
||||||
|
LANGID defaultUILanguage = GetUserDefaultUILanguage();
|
||||||
|
if (defaultUILanguage != translationArray[i].wLanguage)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
syslangIdx = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT metadataStringSize = 0;
|
||||||
|
swprintf(metadataStringKey, L"\\StringFileInfo\\%04x%04x\\FileDescription",
|
||||||
|
translationArray[(syslangIdx < 0 ? 0 : syslangIdx)].wLanguage,
|
||||||
|
translationArray[(syslangIdx < 0 ? 0 : syslangIdx)].wCodePage);
|
||||||
|
if (VerQueryValueW(fileVersionInfo, metadataStringKey, (LPVOID*)&metadataString, &metadataStringSize)
|
||||||
|
&& metadataString[0] != '\0') {
|
||||||
|
free(fileVersionInfo);
|
||||||
|
*sessionName = std::wstring(metadataString);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
swprintf(metadataStringKey, L"\\StringFileInfo\\%04x%04x\\ProductName",
|
||||||
|
translationArray[(syslangIdx < 0 ? 0 : syslangIdx)].wLanguage,
|
||||||
|
translationArray[(syslangIdx < 0 ? 0 : syslangIdx)].wCodePage);
|
||||||
|
if (VerQueryValueW(fileVersionInfo, metadataStringKey, (LPVOID*)&metadataString, &metadataStringSize)
|
||||||
|
&& metadataString[0] != '\0') {
|
||||||
|
free(fileVersionInfo);
|
||||||
|
*sessionName = std::wstring(metadataString);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(fileVersionInfo)
|
||||||
|
free(fileVersionInfo);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Session::fetchNameViaMSIX(std::wstring exePath, DWORD pid, std::wstring *sessionName) {
|
||||||
|
HANDLE process = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid);
|
||||||
|
if(!process) return false;
|
||||||
|
|
||||||
|
//constant missing in mingw64. TB removed when I upgrade to a mingw64 ver that has it
|
||||||
|
#define APPLICATION_USER_MODEL_ID_MAX_LENGTH 130
|
||||||
|
uint32_t length = APPLICATION_USER_MODEL_ID_MAX_LENGTH;
|
||||||
|
PWSTR userModelId = (PWSTR)malloc(length * sizeof(wchar_t));
|
||||||
|
if(GetApplicationUserModelId(process, &length, userModelId) != ERROR_SUCCESS) {
|
||||||
|
CloseHandle(process);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
CloseHandle(process);
|
||||||
|
|
||||||
|
static constexpr wchar_t* prefix = L"shell:appsfolder\\";
|
||||||
|
uint32_t prefixLen = wcslen(prefix);
|
||||||
|
uint32_t userModelIdLen = wcslen(userModelId);
|
||||||
|
wchar_t* fullName;
|
||||||
|
fullName = (prefixLen + userModelIdLen < length)
|
||||||
|
? (wchar_t*)malloc(length * sizeof(wchar_t))
|
||||||
|
: (wchar_t*)malloc((length * 2) * sizeof(wchar_t));
|
||||||
|
for (int32_t i = prefixLen - 1; i >= 0; i--) {
|
||||||
|
fullName[i] = prefix[i];
|
||||||
|
}
|
||||||
|
for (uint32_t i = 0; i < userModelIdLen + 1; i++) {
|
||||||
|
fullName[prefixLen + i] = userModelId[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
IShellItem* si;
|
||||||
|
HRESULT hr = SHCreateItemFromParsingName(fullName,
|
||||||
|
nullptr,
|
||||||
|
IID_IShellItem,
|
||||||
|
(void**)&si
|
||||||
|
);
|
||||||
|
free(fullName);
|
||||||
|
LPWSTR humanName = nullptr;
|
||||||
|
si->GetDisplayName(SIGDN_NORMALDISPLAY, &humanName);
|
||||||
|
if(humanName && humanName[0] != '\0') {
|
||||||
|
*sessionName = std::wstring(humanName);
|
||||||
|
CoTaskMemFree(humanName);
|
||||||
|
}
|
||||||
|
if(si) si->Release();
|
||||||
|
|
||||||
|
if (sessionName->length() > 0)
|
||||||
|
return true;
|
||||||
|
else return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Session::fetchNameViaWindowName(DWORD pid, std::wstring *sessionName) {
|
||||||
|
//lParam is documented as in, so... Beware of future explosions, ig?
|
||||||
|
std::pair<HWND, DWORD> params = { 0, pid };
|
||||||
|
|
||||||
|
BOOL result = EnumWindows([](HWND hwnd, LPARAM lParam) -> BOOL {
|
||||||
|
auto pParams = (std::pair<HWND, DWORD>*)(lParam);
|
||||||
|
|
||||||
|
DWORD processId;
|
||||||
|
//IsWindowVisible(hwnd) &&&& GetWindow(hwnd, GW_OWNER) == 0
|
||||||
|
if ( GetWindowThreadProcessId(hwnd, &processId) && processId == pParams->second) {
|
||||||
|
int length = GetWindowTextLength(hwnd);
|
||||||
|
if (!length) return TRUE;
|
||||||
|
|
||||||
|
// Stop enumerating
|
||||||
|
SetLastError(-1);
|
||||||
|
pParams->first = hwnd;
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Continue enumerating
|
||||||
|
return TRUE;
|
||||||
|
} , (LPARAM)¶ms);
|
||||||
|
|
||||||
|
if(!result && GetLastError() == -1 && params.first) {
|
||||||
|
//todo: double-dipping length... Not a fan
|
||||||
|
int length = GetWindowTextLength(params.first);
|
||||||
|
wchar_t* buffer = new wchar_t[length + 1];
|
||||||
|
GetWindowTextW(params.first, buffer, length + 1);
|
||||||
|
*sessionName = buffer;
|
||||||
|
delete[] buffer;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Session::fetchName(std::wstring exePath, DWORD pid) {
|
||||||
|
/*
|
||||||
|
* if(fetchNameViaWindowName(exePath, pid, &this->sessionName))
|
||||||
|
* return;
|
||||||
|
* else if(fetchNameViaMSIX(exePath, pid, &this->sessionName))
|
||||||
|
* return;
|
||||||
|
* else if(!fetchNameViaFD(exePath, pid, &this->sessionName))
|
||||||
|
* this->sessionName = exePath;
|
||||||
|
*/
|
||||||
|
|
||||||
|
if(fetchNameViaFD(exePath, pid, &this->sessionName))
|
||||||
|
return true;
|
||||||
|
return fetchNameViaMSIX(exePath, pid, &this->sessionName);
|
||||||
|
//else if(!fetchNameViaWindowName(exePath, pid, &this->sessionName))
|
||||||
|
/// this->sessionName = exePath;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//todo: conflicting names. change callback name
|
||||||
|
void Session::setState(SessionState state) {
|
||||||
|
sessionState = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
SessionState Session::getState() {
|
||||||
|
return sessionState;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Session::setStateCallback(SessionStateCallback *ssc){
|
||||||
|
sessionControl->RegisterAudioSessionNotification((IAudioSessionEvents*) ssc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Session::removeStateCallback(SessionStateCallback *ssc){
|
||||||
|
sessionControl->UnregisterAudioSessionNotification((IAudioSessionEvents*) ssc);
|
||||||
|
}
|
||||||
|
|
||||||
|
Session::~Session() {
|
||||||
|
meterInformation->Release();
|
||||||
|
sessionControl->Release();
|
||||||
|
sessionVolume->Release();
|
||||||
|
meterInformation = nullptr;
|
||||||
|
sessionControl = nullptr;
|
||||||
|
sessionVolume = nullptr;
|
||||||
|
}
|
||||||
64
src/back/backsessionclasses.h
Normal file
64
src/back/backsessionclasses.h
Normal file
|
|
@ -0,0 +1,64 @@
|
||||||
|
#pragma once
|
||||||
|
#include "msinclude.h"
|
||||||
|
|
||||||
|
#include "global.h"
|
||||||
|
#include "contclasses.h"
|
||||||
|
|
||||||
|
class Endpoint;
|
||||||
|
|
||||||
|
class SessionStateCallback : public IAudioSessionEvents {
|
||||||
|
public:
|
||||||
|
SessionStateCallback(SessionHandler *sh);
|
||||||
|
ULONG AddRef();
|
||||||
|
ULONG Release();
|
||||||
|
HRESULT QueryInterface(REFIID riid, VOID **ppvInterface);
|
||||||
|
HRESULT OnSessionCreated(IAudioSessionControl *NewSession);
|
||||||
|
HRESULT OnChannelVolumeChanged(DWORD ChannelCount, float NewChannelVolumeArray[], DWORD ChangedChannel, LPCGUID EventContext);
|
||||||
|
HRESULT OnDisplayNameChanged(LPCWSTR NewDisplayName, LPCGUID EventContext);
|
||||||
|
HRESULT OnGroupingParamChanged( LPCGUID NewGroupingParam, LPCGUID EventContext);
|
||||||
|
HRESULT OnIconPathChanged(LPCWSTR NewIconPath, LPCGUID EventContext);
|
||||||
|
HRESULT OnSessionDisconnected(AudioSessionDisconnectReason DisconnectReason);
|
||||||
|
HRESULT OnSimpleVolumeChanged(float NewVolume, BOOL NewMute, LPCGUID EventContext);
|
||||||
|
HRESULT OnStateChanged(AudioSessionState NewState);
|
||||||
|
|
||||||
|
private:
|
||||||
|
ULONG ref = 1;
|
||||||
|
SessionHandler *sh;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Session {
|
||||||
|
|
||||||
|
public:
|
||||||
|
Session(Endpoint* ep, IAudioSessionControl2* sessionControl, size_t idx);
|
||||||
|
Session(Endpoint* ep, IAudioSessionControl2* sessionControl) : Session(ep, sessionControl, SIZE_MAX) {};
|
||||||
|
void setVolume(NGuid guid, int channel, float volume);
|
||||||
|
float getVolume(int channel);
|
||||||
|
float getPeakVolume();
|
||||||
|
void setMute(NGuid guid, bool muted);
|
||||||
|
bool getMute();
|
||||||
|
SessionState getState();
|
||||||
|
void setState(SessionState state);
|
||||||
|
void setIndex(size_t idx);
|
||||||
|
std::wstring getName();
|
||||||
|
void setName(std::wstring newName);
|
||||||
|
void setStateCallback(SessionStateCallback *ssc);
|
||||||
|
void removeStateCallback(SessionStateCallback *ssc);
|
||||||
|
~Session();
|
||||||
|
//uint32_t getChannelCount();
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool getExePath(DWORD pid, /*out*/ std::wstring *exePath);
|
||||||
|
bool fetchName(std::wstring exePath, DWORD pid);
|
||||||
|
bool fetchNameViaFD(std::wstring exePath, DWORD pid, /*out*/ std::wstring *sessionName);
|
||||||
|
bool fetchNameViaMSIX(std::wstring exePath, DWORD pid, /*out*/ std::wstring *sessionName);
|
||||||
|
bool fetchNameViaWindowName(DWORD pid, /*out*/ std::wstring *sessionName);
|
||||||
|
/* std::wstring fetchProcessName(DWORD pid); */
|
||||||
|
std::wstring sessionName;
|
||||||
|
SessionState sessionState;
|
||||||
|
Endpoint* ep;
|
||||||
|
IAudioSessionControl2* sessionControl = nullptr;
|
||||||
|
IAudioMeterInformation* meterInformation = nullptr;
|
||||||
|
ISimpleAudioVolume* sessionVolume = nullptr;
|
||||||
|
size_t idx;
|
||||||
|
};
|
||||||
|
|
||||||
311
src/back/ipolicyconfig.h
Normal file
311
src/back/ipolicyconfig.h
Normal file
|
|
@ -0,0 +1,311 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef __IPolicyConfig7_FWD_DEFINED__
|
||||||
|
#define __IPolicyConfig7_FWD_DEFINED__
|
||||||
|
typedef interface IPolicyConfig7 IPolicyConfig7;
|
||||||
|
#ifdef __cplusplus
|
||||||
|
interface IPolicyConfig7;
|
||||||
|
#endif
|
||||||
|
#endif /* __IPolicyConfig7_FWD_DEFINED__ */
|
||||||
|
|
||||||
|
#ifndef __CPolicyConfigClient_FWD_DEFINED__
|
||||||
|
#define __CPolicyConfigClient_FWD_DEFINED__
|
||||||
|
typedef class CPolicyConfigClient CPolicyConfigClient;
|
||||||
|
#endif /* __CPolicyConfigClient_FWD_DEFINED__ */
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* CPolicyConfigClient coclass
|
||||||
|
*/
|
||||||
|
|
||||||
|
DEFINE_GUID(CLSID_CPolicyConfigClient, 0x870af99c, 0x171d, 0x4f9e, 0xaf,0x0d, 0xe6,0x3d,0xf4,0x0c,0x2b,0xc9);
|
||||||
|
#ifdef __cplusplus
|
||||||
|
class DECLSPEC_UUID("870af99c-171d-4f9e-af0d-e63df40c2bc9") CPolicyConfigClient;
|
||||||
|
#ifdef __CRT_UUID_DECL
|
||||||
|
__CRT_UUID_DECL(CPolicyConfigClient, 0x870af99c, 0x171d, 0x4f9e, 0xaf,0x0d, 0xe6,0x3d,0xf4,0x0c,0x2b,0xc9)
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* IPolicyConfig7 interface
|
||||||
|
*/
|
||||||
|
#ifndef __IPolicyConfig7_INTERFACE_DEFINED__
|
||||||
|
#define __IPolicyConfig7_INTERFACE_DEFINED__
|
||||||
|
DEFINE_GUID(IID_IPolicyConfig7, 0xf8679f50, 0x850a, 0x41cf, 0x9c,0x72, 0x43,0x0f,0x29,0x02,0x90,0xc8);
|
||||||
|
#if defined(__cplusplus) && !defined(CINTERFACE)
|
||||||
|
MIDL_INTERFACE("f8679f50-850a-41cf-9c72-430f290290c8")
|
||||||
|
IPolicyConfig7 : public IUnknown {
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual HRESULT GetMixFormat(
|
||||||
|
PCWSTR,
|
||||||
|
WAVEFORMATEX **
|
||||||
|
);
|
||||||
|
|
||||||
|
virtual HRESULT STDMETHODCALLTYPE GetDeviceFormat(
|
||||||
|
PCWSTR,
|
||||||
|
INT,
|
||||||
|
WAVEFORMATEX **
|
||||||
|
);
|
||||||
|
|
||||||
|
virtual HRESULT STDMETHODCALLTYPE ResetDeviceFormat(
|
||||||
|
PCWSTR
|
||||||
|
);
|
||||||
|
|
||||||
|
virtual HRESULT STDMETHODCALLTYPE SetDeviceFormat(
|
||||||
|
PCWSTR,
|
||||||
|
WAVEFORMATEX *,
|
||||||
|
WAVEFORMATEX *
|
||||||
|
);
|
||||||
|
|
||||||
|
virtual HRESULT STDMETHODCALLTYPE GetProcessingPeriod(
|
||||||
|
PCWSTR,
|
||||||
|
INT,
|
||||||
|
PINT64,
|
||||||
|
PINT64
|
||||||
|
);
|
||||||
|
|
||||||
|
virtual HRESULT STDMETHODCALLTYPE SetProcessingPeriod(
|
||||||
|
PCWSTR,
|
||||||
|
PINT64
|
||||||
|
);
|
||||||
|
|
||||||
|
virtual HRESULT STDMETHODCALLTYPE GetShareMode(
|
||||||
|
PCWSTR,
|
||||||
|
struct DeviceShareMode *
|
||||||
|
);
|
||||||
|
|
||||||
|
virtual HRESULT STDMETHODCALLTYPE SetShareMode(
|
||||||
|
PCWSTR,
|
||||||
|
struct DeviceShareMode *
|
||||||
|
);
|
||||||
|
|
||||||
|
virtual HRESULT STDMETHODCALLTYPE GetPropertyValue(
|
||||||
|
PCWSTR,
|
||||||
|
const PROPERTYKEY &,
|
||||||
|
PROPVARIANT *
|
||||||
|
);
|
||||||
|
|
||||||
|
virtual HRESULT STDMETHODCALLTYPE SetPropertyValue(
|
||||||
|
PCWSTR,
|
||||||
|
const PROPERTYKEY &,
|
||||||
|
PROPVARIANT *
|
||||||
|
);
|
||||||
|
|
||||||
|
virtual HRESULT STDMETHODCALLTYPE SetDefaultEndpoint(
|
||||||
|
PCWSTR wszDeviceId,
|
||||||
|
ERole eRole
|
||||||
|
);
|
||||||
|
|
||||||
|
virtual HRESULT STDMETHODCALLTYPE SetEndpointVisibility(
|
||||||
|
PCWSTR,
|
||||||
|
INT
|
||||||
|
);
|
||||||
|
};
|
||||||
|
#ifdef __CRT_UUID_DECL
|
||||||
|
__CRT_UUID_DECL(IPolicyConfig7, 0xf8679f50, 0x850a, 0x41cf, 0x9c,0x72, 0x43,0x0f,0x29,0x02,0x90,0xc8)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* __IPolicyConfig7_INTERFACE_DEFINED__ */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* __CRT_UUID_DECL(IPolicyConfig10, 0xca286fc3, 0x91fd, 0x42c3, 0x8e,0x9b, 0xca,0xaf,0xa6,0x62,0x42,0xe3) */
|
||||||
|
/* __CRT_UUID_DECL(CPolicyConfigClient, 0x870af99c, 0x171d, 0x4f9e, 0xaf,0x0d, 0xe6,0x3d,0xf4,0x0c,0x2b,0xc9) */
|
||||||
|
|
||||||
|
|
||||||
|
/* // ---------------------------------------------------------------------------- */
|
||||||
|
/* // PolicyConfig.h */
|
||||||
|
/* // Undocumented COM-interface IPolicyConfig. */
|
||||||
|
/* // Use for set default audio render endpoint */
|
||||||
|
/* // @author EreTIk */
|
||||||
|
/* // ---------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
/* #pragma once */
|
||||||
|
|
||||||
|
/* interface DECLSPEC_UUID("CA286FC3-91FD-42C3-8E9B-CAAFA66242E3") */
|
||||||
|
/* IPolicyConfig10; */
|
||||||
|
|
||||||
|
/* interface DECLSPEC_UUID("00000000-0000-0000-C000-000000000046") */
|
||||||
|
/* IPolicyConfig10_1; */
|
||||||
|
|
||||||
|
/* interface DECLSPEC_UUID("F8679F50-850A-41CF-9C72-430F290290C8") */
|
||||||
|
/* IPolicyConfig7; */
|
||||||
|
|
||||||
|
/* /\* interface DECLSPEC_UUID("568B9108-44BF-40B4-9006-86AFE5B5A620") *\/ */
|
||||||
|
/* /\* IPolicyConfigVista; *\/ */
|
||||||
|
|
||||||
|
/* interface DECLSPEC_UUID("f8679f50-850a-41cf-9c72-430f290290c8") */
|
||||||
|
/* IPolicyConfig; */
|
||||||
|
|
||||||
|
/* class DECLSPEC_UUID("870af99c-171d-4f9e-af0d-e63df40c2bc9") */
|
||||||
|
/* CPolicyConfigClient; */
|
||||||
|
/* // ---------------------------------------------------------------------------- */
|
||||||
|
/* // class CPolicyConfigClient */
|
||||||
|
/* // {870af99c-171d-4f9e-af0d-e63df40c2bc9} */
|
||||||
|
/* // */
|
||||||
|
/* // interface IPolicyConfig */
|
||||||
|
/* // {f8679f50-850a-41cf-9c72-430f290290c8} */
|
||||||
|
/* // */
|
||||||
|
/* // Query interface: */
|
||||||
|
/* // CComPtr<IPolicyConfig> PolicyConfig; */
|
||||||
|
/* // PolicyConfig.CoCreateInstance(__uuidof(CPolicyConfigClient)); */
|
||||||
|
/* // */
|
||||||
|
/* // @compatible: Windows 7 and Later */
|
||||||
|
/* // ---------------------------------------------------------------------------- */
|
||||||
|
/* interface IPolicyConfig : public IUnknown */
|
||||||
|
/* { */
|
||||||
|
/* public: */
|
||||||
|
|
||||||
|
/* virtual HRESULT GetMixFormat( */
|
||||||
|
/* PCWSTR, */
|
||||||
|
/* WAVEFORMATEX ** */
|
||||||
|
/* ); */
|
||||||
|
|
||||||
|
/* virtual HRESULT STDMETHODCALLTYPE GetDeviceFormat( */
|
||||||
|
/* PCWSTR, */
|
||||||
|
/* INT, */
|
||||||
|
/* WAVEFORMATEX ** */
|
||||||
|
/* ); */
|
||||||
|
|
||||||
|
/* virtual HRESULT STDMETHODCALLTYPE ResetDeviceFormat( */
|
||||||
|
/* PCWSTR */
|
||||||
|
/* ); */
|
||||||
|
|
||||||
|
/* virtual HRESULT STDMETHODCALLTYPE SetDeviceFormat( */
|
||||||
|
/* PCWSTR, */
|
||||||
|
/* WAVEFORMATEX *, */
|
||||||
|
/* WAVEFORMATEX * */
|
||||||
|
/* ); */
|
||||||
|
|
||||||
|
/* virtual HRESULT STDMETHODCALLTYPE GetProcessingPeriod( */
|
||||||
|
/* PCWSTR, */
|
||||||
|
/* INT, */
|
||||||
|
/* PINT64, */
|
||||||
|
/* PINT64 */
|
||||||
|
/* ); */
|
||||||
|
|
||||||
|
/* virtual HRESULT STDMETHODCALLTYPE SetProcessingPeriod( */
|
||||||
|
/* PCWSTR, */
|
||||||
|
/* PINT64 */
|
||||||
|
/* ); */
|
||||||
|
|
||||||
|
/* virtual HRESULT STDMETHODCALLTYPE GetShareMode( */
|
||||||
|
/* PCWSTR, */
|
||||||
|
/* struct DeviceShareMode * */
|
||||||
|
/* ); */
|
||||||
|
|
||||||
|
/* virtual HRESULT STDMETHODCALLTYPE SetShareMode( */
|
||||||
|
/* PCWSTR, */
|
||||||
|
/* struct DeviceShareMode * */
|
||||||
|
/* ); */
|
||||||
|
|
||||||
|
/* virtual HRESULT STDMETHODCALLTYPE GetPropertyValue( */
|
||||||
|
/* PCWSTR, */
|
||||||
|
/* const PROPERTYKEY &, */
|
||||||
|
/* PROPVARIANT * */
|
||||||
|
/* ); */
|
||||||
|
|
||||||
|
/* virtual HRESULT STDMETHODCALLTYPE SetPropertyValue( */
|
||||||
|
/* PCWSTR, */
|
||||||
|
/* const PROPERTYKEY &, */
|
||||||
|
/* PROPVARIANT * */
|
||||||
|
/* ); */
|
||||||
|
|
||||||
|
/* virtual HRESULT STDMETHODCALLTYPE SetDefaultEndpoint( */
|
||||||
|
/* PCWSTR wszDeviceId, */
|
||||||
|
/* ERole eRole */
|
||||||
|
/* ); */
|
||||||
|
|
||||||
|
/* virtual HRESULT STDMETHODCALLTYPE SetEndpointVisibility( */
|
||||||
|
/* PCWSTR, */
|
||||||
|
/* INT */
|
||||||
|
/* ); */
|
||||||
|
/* }; */
|
||||||
|
|
||||||
|
/* /\* interface DECLSPEC_UUID("568b9108-44bf-40b4-9006-86afe5b5a620") *\/ */
|
||||||
|
/* /\* IPolicyConfigVista; *\/ */
|
||||||
|
/* /\* class DECLSPEC_UUID("294935CE-F637-4E7C-A41B-AB255460B862") *\/ */
|
||||||
|
/* /\* CPolicyConfigVistaClient; *\/ */
|
||||||
|
/* /\* // ---------------------------------------------------------------------------- *\/ */
|
||||||
|
/* /\* // class CPolicyConfigVistaClient *\/ */
|
||||||
|
/* /\* // {294935CE-F637-4E7C-A41B-AB255460B862} *\/ */
|
||||||
|
/* /\* // *\/ */
|
||||||
|
/* /\* // interface IPolicyConfigVista *\/ */
|
||||||
|
/* /\* // {568b9108-44bf-40b4-9006-86afe5b5a620} *\/ */
|
||||||
|
/* /\* // *\/ */
|
||||||
|
/* /\* // Query interface: *\/ */
|
||||||
|
/* /\* // CComPtr<IPolicyConfigVista> PolicyConfig; *\/ */
|
||||||
|
/* /\* // PolicyConfig.CoCreateInstance(__uuidof(CPolicyConfigVistaClient)); *\/ */
|
||||||
|
/* /\* // *\/ */
|
||||||
|
/* /\* // @compatible: Windows Vista and Later *\/ */
|
||||||
|
/* /\* // ---------------------------------------------------------------------------- *\/ */
|
||||||
|
/* /\* interface IPolicyConfigVista : public IUnknown *\/ */
|
||||||
|
/* /\* { *\/ */
|
||||||
|
/* /\* public: *\/ */
|
||||||
|
|
||||||
|
/* /\* virtual HRESULT GetMixFormat( *\/ */
|
||||||
|
/* /\* PCWSTR, *\/ */
|
||||||
|
/* /\* WAVEFORMATEX ** *\/ */
|
||||||
|
/* /\* ); // not available on Windows 7, use method from IPolicyConfig *\/ */
|
||||||
|
|
||||||
|
/* /\* virtual HRESULT STDMETHODCALLTYPE GetDeviceFormat( *\/ */
|
||||||
|
/* /\* PCWSTR, *\/ */
|
||||||
|
/* /\* INT, *\/ */
|
||||||
|
/* /\* WAVEFORMATEX ** *\/ */
|
||||||
|
/* /\* ); *\/ */
|
||||||
|
|
||||||
|
/* /\* virtual HRESULT STDMETHODCALLTYPE SetDeviceFormat( *\/ */
|
||||||
|
/* /\* PCWSTR, *\/ */
|
||||||
|
/* /\* WAVEFORMATEX *, *\/ */
|
||||||
|
/* /\* WAVEFORMATEX * *\/ */
|
||||||
|
/* /\* ); *\/ */
|
||||||
|
|
||||||
|
/* /\* virtual HRESULT STDMETHODCALLTYPE GetProcessingPeriod( *\/ */
|
||||||
|
/* /\* PCWSTR, *\/ */
|
||||||
|
/* /\* INT, *\/ */
|
||||||
|
/* /\* PINT64, *\/ */
|
||||||
|
/* /\* PINT64 *\/ */
|
||||||
|
/* /\* ); // not available on Windows 7, use method from IPolicyConfig *\/ */
|
||||||
|
|
||||||
|
/* /\* virtual HRESULT STDMETHODCALLTYPE SetProcessingPeriod( *\/ */
|
||||||
|
/* /\* PCWSTR, *\/ */
|
||||||
|
/* /\* PINT64 *\/ */
|
||||||
|
/* /\* ); // not available on Windows 7, use method from IPolicyConfig *\/ */
|
||||||
|
|
||||||
|
/* /\* virtual HRESULT STDMETHODCALLTYPE GetShareMode( *\/ */
|
||||||
|
/* /\* PCWSTR, *\/ */
|
||||||
|
/* /\* struct DeviceShareMode * *\/ */
|
||||||
|
/* /\* ); // not available on Windows 7, use method from IPolicyConfig *\/ */
|
||||||
|
|
||||||
|
/* /\* virtual HRESULT STDMETHODCALLTYPE SetShareMode( *\/ */
|
||||||
|
/* /\* PCWSTR, *\/ */
|
||||||
|
/* /\* struct DeviceShareMode * *\/ */
|
||||||
|
/* /\* ); // not available on Windows 7, use method from IPolicyConfig *\/ */
|
||||||
|
|
||||||
|
/* /\* virtual HRESULT STDMETHODCALLTYPE GetPropertyValue( *\/ */
|
||||||
|
/* /\* PCWSTR, *\/ */
|
||||||
|
/* /\* const PROPERTYKEY &, *\/ */
|
||||||
|
/* /\* PROPVARIANT * *\/ */
|
||||||
|
/* /\* ); *\/ */
|
||||||
|
|
||||||
|
/* /\* virtual HRESULT STDMETHODCALLTYPE SetPropertyValue( *\/ */
|
||||||
|
/* /\* PCWSTR, *\/ */
|
||||||
|
/* /\* const PROPERTYKEY &, *\/ */
|
||||||
|
/* /\* PROPVARIANT * *\/ */
|
||||||
|
/* /\* ); *\/ */
|
||||||
|
|
||||||
|
/* /\* virtual HRESULT STDMETHODCALLTYPE SetDefaultEndpoint( *\/ */
|
||||||
|
/* /\* __in PCWSTR wszDeviceId, *\/ */
|
||||||
|
/* /\* __in ERole eRole *\/ */
|
||||||
|
/* /\* ); *\/ */
|
||||||
|
|
||||||
|
/* /\* virtual HRESULT STDMETHODCALLTYPE SetEndpointVisibility( *\/ */
|
||||||
|
/* /\* PCWSTR, *\/ */
|
||||||
|
/* /\* INT *\/ */
|
||||||
|
/* /\* ); // not available on Windows 7, use method from IPolicyConfig *\/ */
|
||||||
|
/* /\* }; *\/ */
|
||||||
64
src/back/msinclude.h
Normal file
64
src/back/msinclude.h
Normal file
|
|
@ -0,0 +1,64 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <sdkddkver.h>
|
||||||
|
|
||||||
|
//done by qt by def #define UNICODE
|
||||||
|
|
||||||
|
#include <Windows.h>
|
||||||
|
#include <shellapi.h>
|
||||||
|
#include <Shobjidl.h>
|
||||||
|
#include <Shlobj.h>
|
||||||
|
#include <fileapi.h>
|
||||||
|
#include <appmodel.h>
|
||||||
|
#include <processthreadsapi.h>
|
||||||
|
#include <mmdeviceapi.h>
|
||||||
|
#include <combaseapi.h>
|
||||||
|
#include <initguid.h>
|
||||||
|
#include <Propidl.h>
|
||||||
|
#include <propsys.h>
|
||||||
|
#include <functiondiscoverykeys_devpkey.h>
|
||||||
|
#include <psapi.h>
|
||||||
|
//#include <debugapi.h>
|
||||||
|
|
||||||
|
#include <endpointvolume.h>
|
||||||
|
#include <audiopolicy.h>
|
||||||
|
#include <audioclient.h>
|
||||||
|
//#include <comdef.h>
|
||||||
|
//#include <comip.h>
|
||||||
|
#include <Winerror.h>
|
||||||
|
#include <stringapiset.h>
|
||||||
|
#include <Mmreg.h>
|
||||||
|
#include <tlhelp32.h>
|
||||||
|
#include <Knownfolders.h>
|
||||||
|
|
||||||
|
#include "ipolicyconfig.h"
|
||||||
|
#include "audiometerinfo.h"
|
||||||
|
|
||||||
|
// IAudioMeterInformation
|
||||||
|
/* GUID manual; */
|
||||||
|
/* manual.Data1 = 0xc02216f6; */
|
||||||
|
/* manual.Data2 = 0x8c67; */
|
||||||
|
/* manual.Data3 = 0x4b5b; */
|
||||||
|
/* manual.Data4[0] = 0x9d; */
|
||||||
|
/* manual.Data4[1] = 0x00; */
|
||||||
|
/* manual.Data4[2] = 0xd0; */
|
||||||
|
/* manual.Data4[3] = 0x08; */
|
||||||
|
/* manual.Data4[4] = 0xe7; */
|
||||||
|
/* manual.Data4[5] = 0x3e; */
|
||||||
|
/* manual.Data4[6] = 0x00; */
|
||||||
|
/* manual.Data4[7] = 0x64; */
|
||||||
|
//if(FAILED(endpoint->Activate((const _GUID) manual,
|
||||||
|
|
||||||
|
//IMMEndpoint
|
||||||
|
/* GUID manual; */
|
||||||
|
/* manual.Data1 = 0x1be09788; */
|
||||||
|
/* manual.Data2 = 0x6894; */
|
||||||
|
/* manual.Data3 = 0x4089; */
|
||||||
|
/* manual.Data4[0] = 0x85; */
|
||||||
|
/* manual.Data4[1] = 0x86; */
|
||||||
|
/* manual.Data4[2] = 0x9a; */
|
||||||
|
/* manual.Data4[3] = 0x2a; */
|
||||||
|
/* manual.Data4[4] = 0x6c; */
|
||||||
|
/* manual.Data4[5] = 0x26; */
|
||||||
|
/* manual.Data4[6] = 0x5a; */
|
||||||
|
/* manual.Data4[7] = 0xc5; */
|
||||||
130
src/back/reimpl/audiometerinfo.h
Normal file
130
src/back/reimpl/audiometerinfo.h
Normal file
|
|
@ -0,0 +1,130 @@
|
||||||
|
#ifndef __IAudioMeterInformation_FWD_DEFINED__
|
||||||
|
#define __IAudioMeterInformation_FWD_DEFINED__
|
||||||
|
typedef interface IAudioMeterInformation IAudioMeterInformation;
|
||||||
|
|
||||||
|
#endif /* __IAudioMeterInformation_FWD_DEFINED__ */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"{
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* interface __MIDL_itf_endpointvolume_0000_0003 */
|
||||||
|
/* [local] */
|
||||||
|
|
||||||
|
#ifndef __IAudioMeterInformation_INTERFACE_DEFINED__
|
||||||
|
#define __IAudioMeterInformation_INTERFACE_DEFINED__
|
||||||
|
|
||||||
|
/* interface IAudioMeterInformation */
|
||||||
|
/* [unique][helpstring][nonextensible][uuid][local][object] */
|
||||||
|
|
||||||
|
DEFINE_GUID(IID_IAudioMeterInformation, 0xc02216f6, 0x8c67, 0x4b5b, 0x9d,0x00, 0xd0,0x08,0xe7,0x3e,0x00,0x64);
|
||||||
|
#if defined(__cplusplus) && !defined(CINTERFACE)
|
||||||
|
|
||||||
|
MIDL_INTERFACE("c02216f6-8c67-4b5b-9d00-d008e73e0064")
|
||||||
|
IAudioMeterInformation : public IUnknown
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual /* [helpstring] */ HRESULT STDMETHODCALLTYPE GetPeakValue(
|
||||||
|
/* [out] */ float *pfPeak) = 0;
|
||||||
|
|
||||||
|
virtual /* [helpstring] */ HRESULT STDMETHODCALLTYPE GetMeteringChannelCount(
|
||||||
|
/* [annotation][out] */
|
||||||
|
_Out_ UINT *pnChannelCount) = 0;
|
||||||
|
|
||||||
|
virtual /* [helpstring] */ HRESULT STDMETHODCALLTYPE GetChannelsPeakValues(
|
||||||
|
/* [in] */ UINT32 u32ChannelCount,
|
||||||
|
/* [size_is][out] */ float *afPeakValues) = 0;
|
||||||
|
|
||||||
|
virtual /* [helpstring] */ HRESULT STDMETHODCALLTYPE QueryHardwareSupport(
|
||||||
|
/* [annotation][out] */
|
||||||
|
_Out_ DWORD *pdwHardwareSupportMask) = 0;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef __CRT_UUID_DECL
|
||||||
|
__CRT_UUID_DECL(IAudioMeterInformation, 0xc02216f6, 0x8c67, 0x4b5b, 0x9d,0x00, 0xd0,0x08,0xe7,0x3e,0x00,0x64)
|
||||||
|
#endif
|
||||||
|
#else /* C style interface */
|
||||||
|
|
||||||
|
typedef struct IAudioMeterInformationVtbl
|
||||||
|
{
|
||||||
|
BEGIN_INTERFACE
|
||||||
|
|
||||||
|
HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
|
||||||
|
IAudioMeterInformation * This,
|
||||||
|
/* [in] */ REFIID riid,
|
||||||
|
/* [annotation][iid_is][out] */
|
||||||
|
_COM_Outptr_ void **ppvObject);
|
||||||
|
|
||||||
|
ULONG ( STDMETHODCALLTYPE *AddRef )(
|
||||||
|
IAudioMeterInformation * This);
|
||||||
|
|
||||||
|
ULONG ( STDMETHODCALLTYPE *Release )(
|
||||||
|
IAudioMeterInformation * This);
|
||||||
|
|
||||||
|
/* [helpstring] */ HRESULT ( STDMETHODCALLTYPE *GetPeakValue )(
|
||||||
|
IAudioMeterInformation * This,
|
||||||
|
/* [out] */ float *pfPeak);
|
||||||
|
|
||||||
|
/* [helpstring] */ HRESULT ( STDMETHODCALLTYPE *GetMeteringChannelCount )(
|
||||||
|
IAudioMeterInformation * This,
|
||||||
|
/* [annotation][out] */
|
||||||
|
_Out_ UINT *pnChannelCount);
|
||||||
|
|
||||||
|
/* [helpstring] */ HRESULT ( STDMETHODCALLTYPE *GetChannelsPeakValues )(
|
||||||
|
IAudioMeterInformation * This,
|
||||||
|
/* [in] */ UINT32 u32ChannelCount,
|
||||||
|
/* [size_is][out] */ float *afPeakValues);
|
||||||
|
|
||||||
|
/* [helpstring] */ HRESULT ( STDMETHODCALLTYPE *QueryHardwareSupport )(
|
||||||
|
IAudioMeterInformation * This,
|
||||||
|
/* [annotation][out] */
|
||||||
|
_Out_ DWORD *pdwHardwareSupportMask);
|
||||||
|
|
||||||
|
END_INTERFACE
|
||||||
|
} IAudioMeterInformationVtbl;
|
||||||
|
|
||||||
|
interface IAudioMeterInformation
|
||||||
|
{
|
||||||
|
CONST_VTBL struct IAudioMeterInformationVtbl *lpVtbl;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef COBJMACROS
|
||||||
|
|
||||||
|
|
||||||
|
#define IAudioMeterInformation_QueryInterface(This,riid,ppvObject) \
|
||||||
|
( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
|
||||||
|
|
||||||
|
#define IAudioMeterInformation_AddRef(This) \
|
||||||
|
( (This)->lpVtbl -> AddRef(This) )
|
||||||
|
|
||||||
|
#define IAudioMeterInformation_Release(This) \
|
||||||
|
( (This)->lpVtbl -> Release(This) )
|
||||||
|
|
||||||
|
|
||||||
|
#define IAudioMeterInformation_GetPeakValue(This,pfPeak) \
|
||||||
|
( (This)->lpVtbl -> GetPeakValue(This,pfPeak) )
|
||||||
|
|
||||||
|
#define IAudioMeterInformation_GetMeteringChannelCount(This,pnChannelCount) \
|
||||||
|
( (This)->lpVtbl -> GetMeteringChannelCount(This,pnChannelCount) )
|
||||||
|
|
||||||
|
#define IAudioMeterInformation_GetChannelsPeakValues(This,u32ChannelCount,afPeakValues) \
|
||||||
|
( (This)->lpVtbl -> GetChannelsPeakValues(This,u32ChannelCount,afPeakValues) )
|
||||||
|
|
||||||
|
#define IAudioMeterInformation_QueryHardwareSupport(This,pdwHardwareSupportMask) \
|
||||||
|
( (This)->lpVtbl -> QueryHardwareSupport(This,pdwHardwareSupportMask) )
|
||||||
|
|
||||||
|
#endif /* COBJMACROS */
|
||||||
|
|
||||||
|
#endif /* C style interface */
|
||||||
|
|
||||||
|
#endif /* __IAudioMeterInformation_INTERFACE_DEFINED__ */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,50 +1,464 @@
|
||||||
|
#include "backlasses.h"
|
||||||
#include "contclasses.h"
|
#include "contclasses.h"
|
||||||
|
|
||||||
Overseer OverseerHandler::os;
|
void setConfigDirToDefaults() {
|
||||||
|
#define tryFileDir(dir, create) do { \
|
||||||
EndpointHandler::EndpointHandler(Endpoint *ept, QObject *parent) : QObject(parent) {
|
OverseerHandler::settingsPath = Environment::createSettingsPath(dir); \
|
||||||
this->ept = ept;
|
set = ini::UserSettings::createSettings(OverseerHandler::settingsPath.c_str(), create); \
|
||||||
eptName = QString::fromStdWString(ept->getName());
|
if(set) { \
|
||||||
|
return; \
|
||||||
|
} else OverseerHandler::settingsPath.clear(); \
|
||||||
|
} while(0)
|
||||||
|
#define tryOpenFileDir(dir) tryFileDir(dir, false)
|
||||||
|
#define tryCreateFileDir(dir) tryFileDir(dir, true)
|
||||||
|
|
||||||
|
tryOpenFileDir(SettingsTargetDirectory::APP_PATH);
|
||||||
|
tryOpenFileDir(SettingsTargetDirectory::HOME_DIR);
|
||||||
|
tryCreateFileDir(SettingsTargetDirectory::HOME_DIR);
|
||||||
|
tryCreateFileDir(SettingsTargetDirectory::APP_PATH);
|
||||||
|
|
||||||
|
return;
|
||||||
|
#undef tryOpenFileDir
|
||||||
|
#undef tryCreateFileDir
|
||||||
|
#undef tryFileDir
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EndpointHandler::EndpointHandler(uint64_t idx, Flows flow) {
|
||||||
|
this->idx = idx;
|
||||||
|
this->flow = flow;
|
||||||
|
this->ep = (flow == Flows::FLOW_PLAYBACK ? osh->getPlaybackEndpoints().at(idx) : osh->getCaptureEndpoints().at(idx));
|
||||||
|
|
||||||
|
this->callbackInfo.caller = osh->getGuid();
|
||||||
|
//epName = ep->getName();
|
||||||
|
this->setBackEndpointVolumeCallbackInfoContent(this->getState());
|
||||||
|
osh->pushBackEndpointHandler(this, flow);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OverseerHandler::pushBackEndpointHandler(EndpointHandler* eph, Flows flow) {
|
||||||
|
if (eph == nullptr) return;
|
||||||
|
if (flow == Flows::FLOW_PLAYBACK)
|
||||||
|
this->playbackEndpointHandlers.push_back(eph);
|
||||||
|
else
|
||||||
|
this->captureEndpointHandlers.push_back(eph);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EndpointHandler::setFrontVisibilityInfo(EndpointState state, uint64_t frontIdx){
|
||||||
|
ephfv.visibility = state;
|
||||||
|
ephfv.frontIdx = frontIdx;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t EndpointHandler::getFrontVisibilityIndex(){
|
||||||
|
return ephfv.frontIdx;
|
||||||
|
}
|
||||||
|
|
||||||
|
EndpointState EndpointHandler::getFrontVisibilityState(){
|
||||||
|
return ephfv.visibility;
|
||||||
|
}
|
||||||
|
|
||||||
|
Flows EndpointHandler::getFlow(){
|
||||||
|
return ep->getFlow();
|
||||||
|
}
|
||||||
|
|
||||||
|
BackEndpointVolumeCallbackInfo* EndpointHandler::getCallbackInfo(){
|
||||||
|
return &this->callbackInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t EndpointHandler::getChannelCount(){
|
||||||
|
return ep->getChannelCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
void EndpointHandler::setIndex(uint64_t idx){
|
||||||
|
this->idx = idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t EndpointHandler::getIndex(){
|
||||||
|
return idx;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* -1 for master volume
|
* -1 for master volume
|
||||||
*/
|
*/
|
||||||
void EndpointHandler::setValue(int channel, int value){
|
void EndpointHandler::setVolume(NGuid guid, int channel, int value){
|
||||||
if (channel == ENDPOINT_MASTER_VOLUME)
|
if (channel == AudioChannel::CHANNEL_MAIN)
|
||||||
ept->setVolume(channel, (float)value / 100);
|
ep->setVolume(guid, channel, (float)value / 100);
|
||||||
else ept->setVolume(channel, (float)value / 100);
|
else ep->setVolume(guid, channel, (float)value / 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EndpointHandler::setMute(){
|
void EndpointHandler::setMute(NGuid guid, bool muted){
|
||||||
//Qt momento, de ahi el param?
|
ep->setMute(guid, muted);
|
||||||
log_debugcpp("kinda handling the muting tbh");
|
|
||||||
ept->setMute();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QString EndpointHandler::getName(){
|
std::wstring EndpointHandler::getName(){
|
||||||
return eptName;
|
return ep->getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::wstring EndpointHandler::getId(){
|
||||||
|
return ep->getId();
|
||||||
}
|
}
|
||||||
|
|
||||||
float EndpointHandler::getVolume(int channel){
|
float EndpointHandler::getVolume(int channel){
|
||||||
return ept->getVolume(channel);
|
return ep->getVolume(channel);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EndpointHandler::getMute(){
|
bool EndpointHandler::getMute(){
|
||||||
return ept->getMute();
|
return ep->getMute();
|
||||||
}
|
}
|
||||||
|
|
||||||
Overseer* OverseerHandler::getOverseer(){
|
size_t EndpointHandler::getState(){
|
||||||
return &os;
|
return ep->getState();
|
||||||
}
|
}
|
||||||
|
|
||||||
OverseerHandler::OverseerHandler(QObject *parent) : QObject(parent) {
|
void EndpointHandler::setBackEndpointVolumeCallbackInfoContent(uint8_t state) {
|
||||||
|
if(state == EndpointState::ENDPOINT_ACTIVE) {
|
||||||
|
callbackInfo.muted = this->getMute();
|
||||||
|
callbackInfo.mainVolume = this->getVolume(AudioChannel::CHANNEL_MAIN);
|
||||||
|
callbackInfo.channels = this->getChannelCount();
|
||||||
|
if (!epc) {
|
||||||
|
epc = new EndpointVolumeCallback(ep);
|
||||||
|
ep->setVolumeCallback(epc);
|
||||||
|
}
|
||||||
|
callbackInfo.channelVolumes.resize(this->callbackInfo.channels);
|
||||||
|
for(uint32_t i = 0; i < this->getChannelCount(); i++){
|
||||||
|
callbackInfo.channelVolumes.at(i) = this->getVolume(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EndpointHandler::setState(EndpointState state){
|
||||||
|
ep->setState(state);
|
||||||
|
this->setBackEndpointVolumeCallbackInfoContent(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EndpointHandler::setState(EndpointState state, uint64_t index){
|
||||||
|
ep->setState(state);
|
||||||
|
this->setFrontVisibilityInfo((EndpointState)state, index);
|
||||||
|
this->setBackEndpointVolumeCallbackInfoContent(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
float EndpointHandler::getPeakVolume() {
|
||||||
|
return ep->getPeakVolume();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t EndpointHandler::getRoles(){
|
||||||
|
return ep->getRoles();
|
||||||
|
}
|
||||||
|
|
||||||
|
void EndpointHandler::setRoles(Roles newRole){
|
||||||
|
ep->setRoles(newRole);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EndpointHandler::assignRoles(Roles newRole){
|
||||||
|
ep->assignRoles(newRole);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EndpointHandler::removeRoles(Roles newRole){
|
||||||
|
ep->removeRoles(newRole);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EndpointHandler::setAddSessionWidgetFunction(std::function<void(SessionHandler*)> addSessionWidget) {
|
||||||
|
this->addSessionWidget = addSessionWidget;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EndpointHandler::setRemoveSessionWidgetFunction(std::function<void(SessionHandler*)> removeSessionWidget) {
|
||||||
|
this->removeSessionWidget = removeSessionWidget;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* sessions */
|
||||||
|
size_t EndpointHandler::getSessionCount() {
|
||||||
|
return ep->getSessionCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Session*> EndpointHandler::getSessions(){
|
||||||
|
return ep->getSessions();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<SessionHandler*> EndpointHandler::getSessionHandlers(){
|
||||||
|
return this->sessionHandlers;
|
||||||
|
}
|
||||||
|
|
||||||
|
Endpoint* EndpointHandler::getEndpoint() {
|
||||||
|
return this->ep;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EndpointHandler::addSessionSendFront(Session* session) {
|
||||||
|
if(!ep->endpointSessionsMutex.try_lock()) return;
|
||||||
|
sessionHandlersMutex.lock();
|
||||||
|
|
||||||
|
this->ep->addSession(session);
|
||||||
|
SessionHandler* sessionHandler = new SessionHandler(this, session, (getSessionCount() - 1));
|
||||||
|
|
||||||
|
sessionHandlers.push_back(sessionHandler);
|
||||||
|
ep->endpointSessionsMutex.unlock();
|
||||||
|
sessionHandlersMutex.unlock();
|
||||||
|
this->addSessionWidget(sessionHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<EndpointHandler*>* OverseerHandler::getEndpointHandlers(){
|
void EndpointHandler::sendSessionToFront(SessionHandler* sh) {
|
||||||
return endpointHandlers;
|
this->addSessionWidget(sh);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OverseerHandler::setEndpointHandlers(std::vector<EndpointHandler*> *ephs){
|
void EndpointHandler::removeSessionFromFront(SessionHandler* sh) {
|
||||||
this->endpointHandlers = ephs;
|
this->removeSessionWidget(sh);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EndpointHandler::deleteSessions() {
|
||||||
|
ep->unregisterNewSessionNotification(ensc);
|
||||||
|
ensc->Release();
|
||||||
|
ensc = nullptr;
|
||||||
|
for (auto sh : sessionHandlers) {
|
||||||
|
delete sh;
|
||||||
|
}
|
||||||
|
sessionHandlers.resize(0);
|
||||||
|
ep->deleteSessions();
|
||||||
|
//ep->deleteSessionManager();
|
||||||
|
}
|
||||||
|
|
||||||
|
void EndpointHandler::createSessionHandlers() {
|
||||||
|
ep->activateEndpointSessions();
|
||||||
|
if (this->flow == Flows::FLOW_PLAYBACK) {
|
||||||
|
for (int i = 0; i < this->getSessionCount(); i++) {
|
||||||
|
SessionHandler* sessionHandler = new SessionHandler(this, this->getSessions().at(i),i);
|
||||||
|
sessionHandlers.push_back(sessionHandler);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EndpointHandler::createSessionHandlersCallback() {
|
||||||
|
ensc = new EndpointNewSessionCallback(this);
|
||||||
|
ep->registerNewSessionNotification(ensc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EndpointHandler::lockSessionCollections() {
|
||||||
|
this->sessionHandlersMutex.lock();
|
||||||
|
this->ep->endpointSessionsMutex.lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void EndpointHandler::unlockSessionCollections() {
|
||||||
|
this->sessionHandlersMutex.unlock();
|
||||||
|
this->ep->endpointSessionsMutex.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void EndpointHandler::removeVolumeCallback() {
|
||||||
|
ep->removeVolumeCallback(epc);
|
||||||
|
epc->Release();
|
||||||
|
epc = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
EndpointHandler::~EndpointHandler() {
|
||||||
|
ep->removeVolumeCallback(epc);
|
||||||
|
ep->unregisterNewSessionNotification(ensc);
|
||||||
|
epc->Release();
|
||||||
|
delete ep;
|
||||||
|
}
|
||||||
|
|
||||||
|
OverseerHandler::OverseerHandler() {
|
||||||
|
this->os = new Overseer();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OverseerHandler::setSettingsPath(std::string path) {
|
||||||
|
OverseerHandler::settingsPath = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string OverseerHandler::getSettingsPath(){
|
||||||
|
return OverseerHandler::settingsPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OverseerHandler::updateStartupConfig(bool onStartup) {
|
||||||
|
Environment::updateStartupConfig(onStartup);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OverseerHandler::setStartupConfig(bool onStartup) {
|
||||||
|
Environment::setStartupConfig(onStartup);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OverseerHandler::populateSystemValues() {
|
||||||
|
Environment::populateSystemValues();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OverseerHandler::openControlPanel() {
|
||||||
|
Environment::openControlPanel();
|
||||||
|
}
|
||||||
|
|
||||||
|
ProcessedNativeEvent OverseerHandler::processTopLevelWindowMessage(void* msg) {
|
||||||
|
return Environment::processTopLevelWindowMessage(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OverseerHandler::isLightMode() {
|
||||||
|
return Environment::isLightMode();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OverseerHandler::isToRunAtStartup() {
|
||||||
|
return Environment::isToRunAtStartup();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t OverseerHandler::getAccentColor() {
|
||||||
|
return Environment::getAccentColor();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Endpoint*> OverseerHandler::getPlaybackEndpoints() {
|
||||||
|
return this->os->getPlaybackEndpoints();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Endpoint*> OverseerHandler::getCaptureEndpoints() {
|
||||||
|
return this->os->getCaptureEndpoints();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<EndpointHandler*> OverseerHandler::getPlaybackEndpointHandlers(){
|
||||||
|
return playbackEndpointHandlers;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<EndpointHandler*> OverseerHandler::getCaptureEndpointHandlers(){
|
||||||
|
return captureEndpointHandlers;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t OverseerHandler::getPlaybackEndpointsCount(){
|
||||||
|
return this->os->getPlaybackEndpoints().size();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t OverseerHandler::getCaptureEndpointsCount(){
|
||||||
|
return this->os->getCaptureEndpoints().size();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OverseerHandler::createEndpointHandlers(){
|
||||||
|
//todo: add capture
|
||||||
|
|
||||||
|
//std::vector<EndpointHandler*>* ephs = new std::vector<EndpointHandler*>;
|
||||||
|
log_debugcpp("Playback VSize: " + std::to_string(this->getPlaybackEndpointsCount()));
|
||||||
|
|
||||||
|
for(uint64_t i = 0; i < this->getPlaybackEndpointsCount(); i++){
|
||||||
|
log_debugcpp("Creating Playback handler " + std::to_string(i));
|
||||||
|
new EndpointHandler(i, Flows::FLOW_PLAYBACK);
|
||||||
|
log_debugcpp("Created Playback handler " + std::to_string(i) + ", adding to vector. " + " VSize: " + std::to_string(this->playbackEndpointHandlers.size()));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
log_debugcpp("Capture VSize: " +
|
||||||
|
std::to_string(this->getCaptureEndpointsCount()));
|
||||||
|
|
||||||
|
for(uint64_t i = 0; i < this->getCaptureEndpointsCount(); i++) {
|
||||||
|
log_debugcpp("Creating Capture handler " + std::to_string(i));
|
||||||
|
new EndpointHandler(i, Flows::FLOW_CAPTURE);
|
||||||
|
log_debugcpp("Created Capture handler " + std::to_string(i) + ", adding to vector. " + " VSize: " + std::to_string(this->captureEndpointHandlers.size()));
|
||||||
|
/*
|
||||||
|
* if (i >= this->captureEndpointHandlers.size())
|
||||||
|
* captureEndpointHandlers.push_back(eph);
|
||||||
|
* else captureEndpointHandlers.at(i) = eph;
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
os->registerEndpointSituationCallback();
|
||||||
|
}
|
||||||
|
|
||||||
|
EndpointHandler* OverseerHandler::addEndpoint(std::wstring endpointId, /* out */ Flows *flow = nullptr) {
|
||||||
|
//This method is only called from the new endpoint callback and its subsequent thread
|
||||||
|
Flows localFlow;
|
||||||
|
Endpoint* newEp = this->os->addEndpoint(endpointId, &localFlow);
|
||||||
|
|
||||||
|
uint64_t ephIdx = (localFlow == Flows::FLOW_PLAYBACK ? this->getPlaybackEndpointsCount() : this->getCaptureEndpointsCount()) - 1;
|
||||||
|
|
||||||
|
EndpointHandler* newEph = new EndpointHandler(ephIdx, localFlow);
|
||||||
|
if (flow != nullptr) *flow = localFlow;
|
||||||
|
return newEph;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OverseerHandler::reportFinishedStateChange() {
|
||||||
|
os->reportFinishedStateChange();
|
||||||
|
}
|
||||||
|
|
||||||
|
NGuid OverseerHandler::getGuid() {
|
||||||
|
return this->os->getGuid();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* void OverseerHandler::setChangeFrontDefaultsFunction(std::function<void(Roles, std::wstring)> changeFrontDefaults){
|
||||||
|
* this->changeFrontDefaults = changeFrontDefaults;
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* void OverseerHandler::changeFrontDefaultsCallback(Roles role, std::wstring endpointId) {
|
||||||
|
* this->changeFrontDefaults(role, endpointId);
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
|
||||||
|
void OverseerHandler::roleBucketEntryCallback(Roles role, std::wstring endpointId){
|
||||||
|
this->roleBucketEntry(role, endpointId);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OverseerHandler::setRoleBucketEntryFunction(std::function<void(Roles, std::wstring)> roleBucketEntry) {
|
||||||
|
this->roleBucketEntry = roleBucketEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OverseerHandler::updateFrontEndpointName(Endpoint* ep) {
|
||||||
|
//todo: reintroduce capture devices
|
||||||
|
for (auto eph : playbackEndpointHandlers) {
|
||||||
|
if (eph->getEndpoint() == ep) eph->getCallbackInfo()->updateName = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OverseerHandler::reviseEndpointShowing(std::wstring endpointId, EndpointState state) {
|
||||||
|
//TODO: Race condition!!!!!
|
||||||
|
std::vector<EndpointHandler*> allHandlers;
|
||||||
|
handlersPlaybackMutex.lock();
|
||||||
|
handlersCaptureMutex.lock();
|
||||||
|
os->playbackMutex.lock();
|
||||||
|
os->captureMutex.lock();
|
||||||
|
allHandlers.insert(allHandlers.end(), this->captureEndpointHandlers.begin(), this->captureEndpointHandlers.end());
|
||||||
|
allHandlers.insert(allHandlers.end(), this->playbackEndpointHandlers.begin(), this->playbackEndpointHandlers.end());
|
||||||
|
EndpointHandler* eph = nullptr;
|
||||||
|
for (auto loopEph : allHandlers) {
|
||||||
|
if (loopEph->getId() == endpointId) {
|
||||||
|
eph = loopEph;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//debug
|
||||||
|
Flows flow;
|
||||||
|
if (!eph) {
|
||||||
|
if (state ^ EndpointState::ENDPOINT_ACTIVE) goto end;
|
||||||
|
//flow = Flows::FLOW_CAPTURE;
|
||||||
|
eph = osh->addEndpoint(endpointId, &flow);
|
||||||
|
} else
|
||||||
|
flow = eph->getFlow();
|
||||||
|
|
||||||
|
//todo: mic done but disabled. Tab-kun will come...
|
||||||
|
if (flow == Flows::FLOW_CAPTURE) goto end;
|
||||||
|
|
||||||
|
if (eph && EndpointState::ENDPOINT_ACTIVE & state) {
|
||||||
|
eph->setState(EndpointState::ENDPOINT_ACTIVE);
|
||||||
|
this->addEndpointWidget(eph);
|
||||||
|
} else if (eph && eph->getFrontVisibilityState() == EndpointState::ENDPOINT_ACTIVE) {
|
||||||
|
eph->removeVolumeCallback();
|
||||||
|
this->removeEndpointWidget(eph->getFrontVisibilityIndex());
|
||||||
|
}
|
||||||
|
|
||||||
|
end:
|
||||||
|
handlersPlaybackMutex.unlock();
|
||||||
|
handlersCaptureMutex.unlock();
|
||||||
|
os->playbackMutex.unlock();
|
||||||
|
os->captureMutex.unlock();
|
||||||
|
os->reportFinishedStateChange();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OverseerHandler::setAddEndpointWidgetFunction(std::function<void(EndpointHandler*)> addEndpointWidget){
|
||||||
|
this->addEndpointWidget = addEndpointWidget;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OverseerHandler::setRemoveEndpointWidgetFunction(std::function<void(uint64_t)> removeEndpointWidget){
|
||||||
|
this->removeEndpointWidget = removeEndpointWidget;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OverseerHandler::setEndpointHandlers(std::vector<EndpointHandler*> ephs){
|
||||||
|
this->playbackEndpointHandlers = ephs;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OverseerHandler::lockEndpoints() {
|
||||||
|
os->playbackMutex.lock();
|
||||||
|
os->captureMutex.lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OverseerHandler::unlockEndpoints() {
|
||||||
|
os->playbackMutex.unlock();
|
||||||
|
os->captureMutex.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,48 +1,168 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <QObject>
|
|
||||||
#include "backlasses.h"
|
|
||||||
|
|
||||||
|
#include "global.h"
|
||||||
|
#include "settings.h"
|
||||||
|
#include "contsessionclasses.h"
|
||||||
|
//#define invoke_mem_fn(object,ptrToMember) ((object).*(ptrToMember))
|
||||||
|
//#define pinvoke_mem_fn(object,ptrToMember) ((object)->*(ptrToMember))
|
||||||
|
|
||||||
class EndpointHandler : public QObject {
|
class EndpointWidget;
|
||||||
Q_OBJECT
|
class Endpoint;
|
||||||
|
class EndpointVolumeCallback;
|
||||||
|
class Overseer;
|
||||||
|
class SessionHandler;
|
||||||
|
class EndpointNewSessionCallback;
|
||||||
|
|
||||||
|
struct BackEndpointVolumeCallbackInfo {
|
||||||
|
NGuid caller;
|
||||||
|
bool muted;
|
||||||
|
float mainVolume;
|
||||||
|
size_t channels;
|
||||||
|
std::vector<float> channelVolumes;
|
||||||
|
bool updateName = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
void setConfigDirToDefaults();
|
||||||
|
|
||||||
|
class EndpointHandler {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
EndpointHandler(Endpoint *ept, QObject *parent = nullptr);
|
EndpointHandler(uint64_t idx, Flows flow);
|
||||||
QString getName();
|
void setBackEndpointVolumeCallbackInfoContent(uint8_t state);
|
||||||
|
|
||||||
|
//todo: replace all getEndpointHandler()
|
||||||
|
//todo: name refactor
|
||||||
|
BackEndpointVolumeCallbackInfo* getCallbackInfo();
|
||||||
|
uint32_t getChannelCount();
|
||||||
|
|
||||||
|
void setIndex(uint64_t idx);
|
||||||
|
uint64_t getIndex();
|
||||||
|
void setVolume(int channel, float volume);
|
||||||
|
|
||||||
|
std::wstring getName();
|
||||||
|
void setName(std::wstring newName);
|
||||||
|
std::wstring getId();
|
||||||
|
|
||||||
|
void setFrontVisibilityInfo(EndpointState state, uint64_t frontIdx);
|
||||||
|
uint64_t getFrontVisibilityIndex();
|
||||||
|
EndpointState getFrontVisibilityState();
|
||||||
|
|
||||||
|
Flows getFlow();
|
||||||
float getVolume(int channel);
|
float getVolume(int channel);
|
||||||
bool getMute();
|
bool getMute();
|
||||||
|
size_t getState();
|
||||||
|
uint8_t getRoles();
|
||||||
|
void setRoles(Roles newRole);
|
||||||
|
void assignRoles(Roles newRole);
|
||||||
|
void removeRoles(Roles newRole);
|
||||||
|
|
||||||
|
void setVolume(NGuid guid, int channel, int value);
|
||||||
|
void setMute(NGuid guid, bool muted);
|
||||||
|
void setState(EndpointState state);
|
||||||
|
void setState(EndpointState state, uint64_t idx);
|
||||||
|
|
||||||
|
float getPeakVolume();
|
||||||
|
/* sessions */
|
||||||
|
size_t getSessionCount();
|
||||||
|
std::vector<SessionHandler*> getSessionHandlers();
|
||||||
|
void createNewSession();
|
||||||
|
Endpoint* getEndpoint();
|
||||||
|
|
||||||
|
/*Session*/
|
||||||
|
void addSessionSendFront(Session* session);
|
||||||
|
void setAddSessionWidgetFunction(std::function<void(SessionHandler*)> addSessionWidget);
|
||||||
|
void setRemoveSessionWidgetFunction(std::function<void(SessionHandler*)> removeSessionWidget);
|
||||||
|
void sendSessionToFront(SessionHandler* sh);
|
||||||
|
void removeSessionFromFront(SessionHandler* sh);
|
||||||
|
void deleteSessions();
|
||||||
|
void createSessionHandlers();
|
||||||
|
void createSessionHandlersCallback();
|
||||||
|
std::mutex sessionHandlersMutex;
|
||||||
|
void lockSessionCollections();
|
||||||
|
void unlockSessionCollections();
|
||||||
|
void removeVolumeCallback();
|
||||||
|
|
||||||
|
~EndpointHandler();
|
||||||
private:
|
private:
|
||||||
Endpoint *ept;
|
std::vector<Session*> getSessions();
|
||||||
QString eptName;
|
|
||||||
//QSlider *slidy;
|
|
||||||
|
|
||||||
public slots:
|
|
||||||
void setValue(int channel, int value);
|
|
||||||
void setMute();
|
|
||||||
//signals:
|
|
||||||
|
|
||||||
|
|
||||||
|
uint64_t idx;
|
||||||
|
Endpoint *ep = nullptr;
|
||||||
|
EndpointVolumeCallback *epc = nullptr;
|
||||||
|
Flows flow;
|
||||||
|
BackEndpointVolumeCallbackInfo callbackInfo;
|
||||||
|
struct EndpointHandlerFrontVisibility {
|
||||||
|
EndpointState visibility = EndpointState::ENDPOINT_ALL;
|
||||||
|
uint64_t frontIdx = INT_MAX;
|
||||||
|
};
|
||||||
|
EndpointHandlerFrontVisibility ephfv;
|
||||||
|
EndpointNewSessionCallback* ensc;
|
||||||
|
std::vector<SessionHandler*> sessionHandlers;
|
||||||
|
std::function<void(SessionHandler*)> addSessionWidget;
|
||||||
|
std::function<void(SessionHandler*)> removeSessionWidget;
|
||||||
|
//QSlider *slidy;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class OverseerHandler {
|
||||||
class OverseerHandler : public QObject {
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
OverseerHandler(QObject *parent = nullptr);
|
OverseerHandler();
|
||||||
void setEndpointHandlers(std::vector<EndpointHandler*> *ephs);
|
static void setSettingsPath(std::string path);
|
||||||
std::vector<EndpointHandler*>* getEndpointHandlers();
|
static std::string getSettingsPath();
|
||||||
static Overseer* getOverseer();
|
static inline std::string settingsPath;
|
||||||
|
void updateStartupConfig(bool onStartup);
|
||||||
|
void setStartupConfig(bool onStartup);
|
||||||
|
void populateSystemValues();
|
||||||
|
void openControlPanel();
|
||||||
|
ProcessedNativeEvent processTopLevelWindowMessage(void* msg);
|
||||||
|
bool isLightMode();
|
||||||
|
bool isToRunAtStartup();
|
||||||
|
uint32_t getAccentColor();
|
||||||
|
|
||||||
|
//void setChangeFrontDefaultsFunction(std::function<void(Roles, std::wstring)> changeFrontDefaults);
|
||||||
|
//void changeFrontDefaultsCallback(Roles role, std::wstring endpointId);
|
||||||
|
|
||||||
|
void roleBucketEntryCallback(Roles role, std::wstring endpointId);
|
||||||
|
void setRoleBucketEntryFunction(std::function<void(Roles, std::wstring)> roleBucketEntry);
|
||||||
|
|
||||||
|
void updateFrontEndpointName(Endpoint* ep);
|
||||||
|
//void setReviseEndpointShowingFunction(std::function<void(std::wstring, EndpointState)> reviseEndpointShowing);
|
||||||
|
void reviseEndpointShowing(std::wstring endpointId, EndpointState state);
|
||||||
|
void setRemoveEndpointWidgetFunction(std::function<void(uint64_t)> removeEndpointWidget);
|
||||||
|
void setAddEndpointWidgetFunction(std::function<void(EndpointHandler*)> addEndpointWidget);
|
||||||
|
|
||||||
|
void setEndpointHandlers(std::vector<EndpointHandler*> ephs);
|
||||||
|
std::vector<EndpointHandler*> getPlaybackEndpointHandlers();
|
||||||
|
std::vector<EndpointHandler*> getCaptureEndpointHandlers();
|
||||||
|
std::vector<Endpoint*> getPlaybackEndpoints();
|
||||||
|
std::vector<Endpoint*> getCaptureEndpoints();
|
||||||
|
void pushBackEndpointHandler(EndpointHandler* eph, Flows flow);
|
||||||
|
uint64_t getPlaybackEndpointsCount();
|
||||||
|
uint64_t getCaptureEndpointsCount();
|
||||||
|
void createEndpointHandlers();
|
||||||
|
EndpointHandler* addEndpoint(std::wstring endpointId, Flows *flow);
|
||||||
|
void reportFinishedStateChange();
|
||||||
|
NGuid getGuid();
|
||||||
|
|
||||||
|
std::mutex handlersPlaybackMutex;
|
||||||
|
std::mutex handlersCaptureMutex;
|
||||||
|
void lockEndpoints();
|
||||||
|
void unlockEndpoints();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static Overseer os;
|
Overseer *os;
|
||||||
std::vector<EndpointHandler*> *endpointHandlers;
|
std::vector<EndpointHandler*> playbackEndpointHandlers;
|
||||||
//QSlider *slidy;
|
std::vector<EndpointHandler*> captureEndpointHandlers;
|
||||||
|
|
||||||
//public slots:
|
|
||||||
//void setValue(int value);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
std::function<void(Roles, std::wstring /* endpointid */)> changeFrontDefaults;
|
||||||
|
std::function<void(uint64_t /* epw id */)> removeEndpointWidget;
|
||||||
|
std::function<void(EndpointHandler*)> addEndpointWidget;
|
||||||
|
std::function<void(Roles, std::wstring /* endpointid */)> roleBucketEntry;
|
||||||
|
|
||||||
|
/* Session's */
|
||||||
|
std::function<void(float)> changeSessionVolume;
|
||||||
|
|
||||||
|
//std::function<void(uint64_t /* device */, uint32_t /* channel */, float /* value */)> updateFrontVolumeCallback;
|
||||||
|
//std::function<void(uint64_t /* device */, bool /* mute */)> updateFrontMuteCallback;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
||||||
91
src/cont/contsessionclasses.cpp
Normal file
91
src/cont/contsessionclasses.cpp
Normal file
|
|
@ -0,0 +1,91 @@
|
||||||
|
#include "contsessionclasses.h"
|
||||||
|
#include "backsessionclasses.h"
|
||||||
|
|
||||||
|
SessionHandler::SessionHandler(EndpointHandler* eph, Session* session, size_t idx) {
|
||||||
|
this->eph = eph;
|
||||||
|
this->idx = idx;
|
||||||
|
this->session = session;
|
||||||
|
|
||||||
|
this->svi.mainVolume = session->getVolume(AudioChannel::CHANNEL_MAIN);
|
||||||
|
this->svi.muted = session->getMute();
|
||||||
|
this->svi.caller = osh->getGuid();
|
||||||
|
|
||||||
|
ssc = new SessionStateCallback(this);
|
||||||
|
this->session->setStateCallback(ssc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SessionHandler::setVolume(NGuid guid, int channel, int value){
|
||||||
|
if (channel == AudioChannel::CHANNEL_MAIN)
|
||||||
|
session->setVolume(guid, channel, (float)value / 100);
|
||||||
|
else session->setVolume(guid, channel, (float)value / 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
float SessionHandler::getVolume(int channel){
|
||||||
|
return session->getVolume(channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SessionHandler::setMute(NGuid guid, bool muted){
|
||||||
|
session->setMute(guid, muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::wstring SessionHandler::getName(){
|
||||||
|
return session->getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SessionHandler::setName(std::wstring newName){
|
||||||
|
session->setName(newName);
|
||||||
|
}
|
||||||
|
|
||||||
|
float SessionHandler::getPeakVolume(){
|
||||||
|
return session->getPeakVolume();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SessionHandler::getMute(){
|
||||||
|
return session->getMute();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SessionHandler::setFrontIndex(uint64_t frontIdx) {
|
||||||
|
this->frontIdx = frontIdx;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t SessionHandler::getFrontIndex() {
|
||||||
|
return frontIdx;
|
||||||
|
}
|
||||||
|
|
||||||
|
SessionVolumeInfo* SessionHandler::getVolumeInfo() {
|
||||||
|
return &svi;
|
||||||
|
}
|
||||||
|
|
||||||
|
SessionState SessionHandler::getState() {
|
||||||
|
return session->getState();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SessionHandler::setState(SessionState state) {
|
||||||
|
session->setState(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SessionHandler::reviseSessionShowing(SessionState state) {
|
||||||
|
SessionState currentState = this->getState();
|
||||||
|
switch (currentState) {
|
||||||
|
case SessionState::ACTIVE:
|
||||||
|
case SessionState::INACTIVE:
|
||||||
|
if (state == SessionState::EXPIRED) {
|
||||||
|
eph->removeSessionFromFront(this);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SessionState::EXPIRED:
|
||||||
|
if (state == SessionState::ACTIVE || INACTIVE) {
|
||||||
|
eph->sendSessionToFront(this);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SessionState::DISCONNECTED:
|
||||||
|
if (frontIdx != INT_MAX)
|
||||||
|
eph->removeSessionFromFront(this);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SessionHandler::~SessionHandler() {
|
||||||
|
session->removeStateCallback(ssc);
|
||||||
|
ssc->Release();
|
||||||
|
}
|
||||||
44
src/cont/contsessionclasses.h
Normal file
44
src/cont/contsessionclasses.h
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "global.h"
|
||||||
|
//#include "contclasses.h"
|
||||||
|
|
||||||
|
class EndpointHandler;
|
||||||
|
class Session;
|
||||||
|
class SessionStateCallback;
|
||||||
|
|
||||||
|
struct SessionVolumeInfo {
|
||||||
|
//SessionVolumeInfo(bool muted, float mainVolume);
|
||||||
|
bool muted;
|
||||||
|
float mainVolume;
|
||||||
|
NGuid caller;
|
||||||
|
std::atomic<bool> isNameChanged = false;
|
||||||
|
//size_t channels;
|
||||||
|
//std::vector<float> channelVolumes;
|
||||||
|
};
|
||||||
|
|
||||||
|
class SessionHandler {
|
||||||
|
public:
|
||||||
|
SessionHandler(EndpointHandler* eph, Session* session, size_t idx);
|
||||||
|
void setVolume(NGuid guid, int channel, int value);
|
||||||
|
float getVolume(int channel);
|
||||||
|
void setMute(NGuid guid, bool muted);
|
||||||
|
bool getMute();
|
||||||
|
void setFrontIndex(uint64_t frontIdx);
|
||||||
|
SessionState getState();
|
||||||
|
void setState(SessionState state);
|
||||||
|
uint64_t getFrontIndex();
|
||||||
|
std::wstring getName();
|
||||||
|
float getPeakVolume();
|
||||||
|
void setName(std::wstring newName);
|
||||||
|
void reviseSessionShowing(SessionState state);
|
||||||
|
SessionVolumeInfo* getVolumeInfo();
|
||||||
|
~SessionHandler();
|
||||||
|
private:
|
||||||
|
SessionVolumeInfo svi;
|
||||||
|
EndpointHandler* eph;
|
||||||
|
Session* session;
|
||||||
|
SessionStateCallback* ssc;
|
||||||
|
size_t idx;
|
||||||
|
uint64_t frontIdx = INT_MAX;
|
||||||
|
};
|
||||||
80
src/debug.h
80
src/debug.h
|
|
@ -2,9 +2,85 @@
|
||||||
|
|
||||||
#if defined (QT_DEBUG) || defined (DEBUG) || defined (_DEBUG)
|
#if defined (QT_DEBUG) || defined (DEBUG) || defined (_DEBUG)
|
||||||
|
|
||||||
|
#define PIPE_NAME "Mixerq-dev"
|
||||||
|
|
||||||
|
#ifdef INIT_FILELOG
|
||||||
|
std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> converter;
|
||||||
|
FILE* fileLog;
|
||||||
|
errno_t lfResult;
|
||||||
|
bool writable = false;
|
||||||
|
|
||||||
|
void inline initializeFileLogging() {
|
||||||
|
lfResult = fopen_s(&fileLog, "log.txt", "w");
|
||||||
|
if (!lfResult) writable = true;
|
||||||
|
else writable = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
extern std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> converter;
|
||||||
|
extern errno_t lfResult;
|
||||||
|
extern FILE* fileLog;
|
||||||
|
extern bool writable;
|
||||||
|
extern bool initializeFileLogging();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define initialize_file_log() initializeFileLogging()
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
std::bitset<sizeof(T) * 8> varToBitset(T info) {
|
||||||
|
std::bitset<sizeof(T) * 8> content(info);
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define print_as_binary(info) varToBitset<decltype(info)>(info).to_string()
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
#define log_debugcpp(str) do { \
|
#define log_debugcpp(str) do { \
|
||||||
std::cout << "[DEBUG]" << "(" << __FILE__ << ":" << __LINE__ << "): " << str << std::endl; \
|
std::cout << "[DEBUG]" << "(" << __FILE__ << ":" << __LINE__ << "): " << str << std::endl; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
#define log_wdebugcpp(str) do { \
|
||||||
|
std::wcout << "[DEBUG]" << "(" << __FILE__ << ":" << __LINE__ << "): " << str << std::endl; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#include <Windows.h>
|
||||||
|
#include <debugapi.h>
|
||||||
|
#define WIDE2(x) L##x
|
||||||
|
#define WIDE1(x) WIDE2(x)
|
||||||
|
#define WFILE WIDE1(__FILE__)
|
||||||
|
#define log_debugcpp(str) { \
|
||||||
|
OutputDebugStringA(std::string("[DEBUG] (" + std::string(__FILE__) + ":" + std::to_string(__LINE__) + "): " + std::string(str) + "\n").c_str()); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define log_wdebugcpp(str) do { \
|
||||||
|
OutputDebugStringW(std::wstring(L"[DEBUG] (" + std::wstring(WFILE) + L":" + std::to_wstring(__LINE__) + L"): " + std::wstring(str) +L"\n").c_str()); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#endif //_WIN32
|
||||||
|
|
||||||
|
#define log_to_file(fmt, cnt...) do { \
|
||||||
|
if(writable) fprintf_s(fileLog, fmt,##cnt); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define close_file_log_buffer() do { \
|
||||||
|
if(writable) { fflush(fileLog); fclose(fileLog); } \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
#else
|
#else
|
||||||
#define log_debugcpp(str)
|
#define log_debugcpp(str)
|
||||||
#endif
|
#define log_wdebugcpp(str)
|
||||||
|
#define print_as_binary(info)
|
||||||
|
#define log_to_file(fmt, cnt...)
|
||||||
|
#define initialize_file_log() false
|
||||||
|
#define close_file_log_buffer()
|
||||||
|
#define PIPE_NAME "Mixerq"
|
||||||
|
#endif //DEBUG
|
||||||
|
|
||||||
|
/* Here as a quick reference, in case smthn similar is needed again */
|
||||||
|
/* typedef void (EndpointWidget::*epwMuteFunc)(bool muted); */
|
||||||
|
/* Typedef void (EndpointWidget::*epwMainVolumeFunc)(float newValue); */
|
||||||
|
/* typedef void (EndpointWidget::*epwChannelVolumeFunc)(uint32_t channel, float newValue); */
|
||||||
|
/* typedef void (EndpointWidget::*epwToggleFrontFunc)(bool active); */
|
||||||
|
|
||||||
|
|
|
||||||
110
src/global.h
110
src/global.h
|
|
@ -1,15 +1,117 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
//TODO enum capullo
|
#define __STDC_WANT_LIB_EXT1__ 1
|
||||||
#define ENDPOINT_MASTER_VOLUME -1
|
#include <stdio.h>
|
||||||
#define ENDPOINT_LEFT_CHANNEL_VOLUME 0
|
#include <errno.h>
|
||||||
#define ENDPOINT_RIGHT_CHANNEL_VOLUME 1
|
#include <limits.h>
|
||||||
|
#include <codecvt>
|
||||||
|
#include <vector>
|
||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
#include <bitset>
|
||||||
|
#include <locale>
|
||||||
|
#include <map>
|
||||||
|
#include <thread>
|
||||||
|
#include <deque>
|
||||||
|
|
||||||
|
#include "debug.h"
|
||||||
|
//#include "settings.h"
|
||||||
|
|
||||||
|
//TODO: Use tr();? QTranslator
|
||||||
|
#define APP_NAME "MixerQ"
|
||||||
|
#define LAPP_NAME L"MixerQ"
|
||||||
|
|
||||||
#define STRING_MUTE "Mute"
|
#define STRING_MUTE "Mute"
|
||||||
#define STRING_UNMUTE "Unmute"
|
#define STRING_UNMUTE "Unmute"
|
||||||
|
#define STRING_QUIT "Quit"
|
||||||
|
#define STRING_TITLE "Mixer Fachero"
|
||||||
|
|
||||||
|
#define STRING_ROLE_CONSOLE "Console"
|
||||||
|
#define STRING_ROLE_MULTIMEDIA "Multimedia"
|
||||||
|
#define STRING_ROLE_COMMUNICATIONS "Communications"
|
||||||
|
#define STRING_ROLE_ALL "All"
|
||||||
|
|
||||||
|
#define STRING_SYSTEM_SOUNDS "System Sounds"
|
||||||
|
#define LSTRING_SYSTEM_SOUNDS L"System Sounds"
|
||||||
|
|
||||||
|
#define STRING_CP "Open Control Panel"
|
||||||
|
#define STRING_ABOUT "About"
|
||||||
|
#define STRING_STARTUP "Run at startup"
|
||||||
|
#define STRING_CHANNELS "Show endpoint channels"
|
||||||
|
|
||||||
|
#define STRING_NOENDPOINT "No active endpoints"
|
||||||
|
|
||||||
|
#define LSTRING_UNNAMED_SESSION L"Unnamed session"
|
||||||
|
|
||||||
//INIT BACK
|
//INIT BACK
|
||||||
|
|
||||||
|
enum SettingsTargetDirectory {
|
||||||
|
HOME_DIR = 0,
|
||||||
|
APP_PATH = (1 << 0),
|
||||||
|
CUSTOM = (1 << 1),
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ProcessedNativeEvent {
|
||||||
|
NONE = 0,
|
||||||
|
COLORS = (1 << 0),
|
||||||
|
};
|
||||||
|
|
||||||
|
enum AudioChannel {
|
||||||
|
CHANNEL_LEFT = (1 << 0),
|
||||||
|
CHANNEL_RIGHT = (1 << 1),
|
||||||
|
CHANNEL_MAIN = ~0,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum EndpointState {
|
||||||
|
ENDPOINT_ACTIVE = (1 << 0),
|
||||||
|
ENDPOINT_DISABLED = (1 << 1),
|
||||||
|
ENDPOINT_NOTPRESENT = (1 << 2),
|
||||||
|
ENDPOINT_UNPLUGGED = (1 << 3),
|
||||||
|
ENDPOINT_ALL = 0x0F
|
||||||
|
};
|
||||||
|
|
||||||
|
enum SessionState {
|
||||||
|
ACTIVE = (1 << 0),
|
||||||
|
INACTIVE = (1 << 1),
|
||||||
|
EXPIRED = (1 << 2),
|
||||||
|
DISCONNECTED = (1 << 3),
|
||||||
|
ALL = 0x0F
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Flows {
|
||||||
|
FLOW_PLAYBACK = (1 << 0),
|
||||||
|
FLOW_CAPTURE = (1 << 1),
|
||||||
|
FLOW_BOTH = (1 << 2),
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Roles {
|
||||||
|
ROLE_CONSOLE = (1 << 0),
|
||||||
|
ROLE_MULTIMEDIA = (1 << 1),
|
||||||
|
ROLE_COMMUNICATIONS = (1 << 2),
|
||||||
|
ROLE_ALL = 0x07,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct NGuid {
|
||||||
|
//todo: still leaking?
|
||||||
|
uint32_t data1;
|
||||||
|
uint16_t data2;
|
||||||
|
uint16_t data3;
|
||||||
|
unsigned char data4[8];
|
||||||
|
|
||||||
|
|
||||||
|
/* void freeData4(){ */
|
||||||
|
/* int i = 0; */
|
||||||
|
/* do{ */
|
||||||
|
/* if(this->data4 + i != nullptr) free(data4 + i); */
|
||||||
|
/* i++; */
|
||||||
|
/* }while (i < 8); */
|
||||||
|
/* } */
|
||||||
|
};
|
||||||
|
namespace ini {
|
||||||
|
class UserSettings;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern ini::UserSettings *set;
|
||||||
class OverseerHandler;
|
class OverseerHandler;
|
||||||
extern OverseerHandler *osh;
|
extern OverseerHandler *osh;
|
||||||
|
|
||||||
|
|
|
||||||
19
src/qt/meterslider.h
Normal file
19
src/qt/meterslider.h
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
#include <QSlider>
|
||||||
|
|
||||||
|
class MeterSlider : public QSlider {
|
||||||
|
Q_OBJECT
|
||||||
|
private:
|
||||||
|
~MeterSlider();
|
||||||
|
float peakValue;
|
||||||
|
|
||||||
|
friend class MixerStyle;
|
||||||
|
protected:
|
||||||
|
bool event(QEvent* ev) override;
|
||||||
|
void paintEvent(QPaintEvent *event) override;
|
||||||
|
|
||||||
|
public:
|
||||||
|
//MeterSlider(Qt::Orientation orientation, QWidget *parent = nullptr);
|
||||||
|
//MeterSlider(QWidget* parent = nullptr) : MeterSlider(Qt::Vertical, parent){};
|
||||||
|
void setPeakValue(float peakValue);
|
||||||
|
using QSlider::QSlider;
|
||||||
|
};
|
||||||
1485
src/qt/qtclasses.cpp
1485
src/qt/qtclasses.cpp
File diff suppressed because it is too large
Load diff
|
|
@ -1,63 +1,244 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#ifndef MAINWINDOW_H
|
|
||||||
#define MAINWINDOW_H
|
|
||||||
|
|
||||||
#include <vector>
|
#include "qtcommon.h"
|
||||||
#include <QMainWindow>
|
|
||||||
#include <QApplication>
|
|
||||||
#include <QLabel>
|
|
||||||
#include <QSlider>
|
|
||||||
#include <QGridLayout>
|
|
||||||
#include <QPushButton>
|
|
||||||
#include "contclasses.h"
|
#include "contclasses.h"
|
||||||
//#include <Q>
|
#include "settings.h"
|
||||||
//#include <QWidgets>
|
|
||||||
|
|
||||||
|
class MeterSlider;
|
||||||
|
|
||||||
class EndpointWidget : public QWidget {
|
enum SpawnPos {
|
||||||
|
LEFT = (1 << 1),
|
||||||
|
RIGHT = (0 << 1),
|
||||||
|
UP = (1 << 0),
|
||||||
|
DOWN = (0 << 0)
|
||||||
|
};
|
||||||
|
|
||||||
|
enum CustomQEvent {
|
||||||
|
EndpointWidgetObsolete = 1001,
|
||||||
|
EndpointWidgetCreated = 1002,
|
||||||
|
EndpointDefaultChange = 1003,
|
||||||
|
SessionWidgetCreated = 1004,
|
||||||
|
SessionWidgetObsolete = 1005,
|
||||||
|
RecomposeMainWindow = 1006,
|
||||||
|
EndpointRoleChange = 1007
|
||||||
|
};
|
||||||
|
|
||||||
|
class DarkModeEventFilter : public QAbstractNativeEventFilter {
|
||||||
|
|
||||||
|
public:
|
||||||
|
bool nativeEventFilter(const QByteArray &eventType, void *message, qintptr *) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class CustomWidgetEvent : public QEvent {
|
||||||
|
|
||||||
|
public:
|
||||||
|
CustomWidgetEvent(QEvent::Type type, T payload);
|
||||||
|
T payload;
|
||||||
|
};
|
||||||
|
//Q_DECLARE_METATYPE(EndpointWidgetEvent)
|
||||||
|
|
||||||
|
class ExtendedCheckBox : public QCheckBox {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
private:
|
||||||
|
QIcon icons;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void customEvent(QEvent* ev) override;
|
||||||
|
void paintEvent(QPaintEvent* event) override;
|
||||||
|
|
||||||
|
public:
|
||||||
|
//c++11: this inherits all parent's constructors unconditionally
|
||||||
|
using QCheckBox::QCheckBox;
|
||||||
|
void addIcon(char* const path, QIcon::State state);
|
||||||
|
//alternative being calling parent ctor directly after declaring child ctor:
|
||||||
|
//B(int x) : A(x) { }
|
||||||
|
};
|
||||||
|
|
||||||
|
class SessionWidget : public QWidget {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
SessionWidget(uint64_t idx, SessionHandler* sh, QWidget *parent /* = nullptr */);
|
||||||
|
~SessionWidget();
|
||||||
|
void calculateSize(uint64_t width, uint64_t height);
|
||||||
|
std::wstring getName();
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void updateMainVolume(int newValue);
|
||||||
|
void updateMute(int checked);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QLabel *mainLabel = nullptr;
|
||||||
|
MeterSlider *mainSlider = nullptr;
|
||||||
|
uint64_t idx;
|
||||||
|
QHBoxLayout *widgetLayout = nullptr;
|
||||||
|
ExtendedCheckBox *muteButton = nullptr;
|
||||||
|
SessionHandler* sh;
|
||||||
|
QTimer* volumePoller = nullptr;
|
||||||
|
QSpacerItem* widthSpacer;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ChannelWidget : public QWidget {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
EndpointWidget(EndpointHandler* eph, QWidget *parent = nullptr);
|
ChannelWidget(uint32_t channelCount, EndpointHandler* eph, QWidget *parent = nullptr);
|
||||||
|
//QSize minimumSizeHint() const override;
|
||||||
|
//void setMinimum(QSize minimum);
|
||||||
|
void updateChannel(int channel);
|
||||||
|
uint32_t getChannelCount() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
const double roundingFactor = 0.005;
|
||||||
|
EndpointHandler* eph;
|
||||||
|
uint32_t channelCount;
|
||||||
|
std::vector<QSlider*> channelSliders;
|
||||||
|
std::vector<QLabel*> channelLabels;
|
||||||
|
QGridLayout *widgetLayout;
|
||||||
|
QSize minimum;
|
||||||
|
};
|
||||||
|
|
||||||
|
class EndpointWidget : public QWidget {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
EndpointWidget(EndpointHandler* eph, QWidget *parent = nullptr, uint64_t idx = INT_MAX);
|
||||||
|
//QSize minimumSizeHint() const override;
|
||||||
|
//void setMinimum(uint64_t height, double heightRatio);
|
||||||
|
void updateChannelsVisibility();
|
||||||
|
EndpointHandler* getEndpointHandler();
|
||||||
|
std::map<Roles, ExtendedCheckBox*> getDefaultRolesWidgets();
|
||||||
|
|
||||||
|
void setIndex(uint64_t idx);
|
||||||
|
uint64_t getIndex();
|
||||||
|
//void setVolume(int channel, float volume);
|
||||||
|
void calculateSize(uint64_t width, uint64_t height);
|
||||||
|
|
||||||
|
~EndpointWidget();
|
||||||
|
//void updateMainVolume(float newValue);
|
||||||
|
//void updateVolume(uint32_t channel, float newValue);
|
||||||
|
//void updateMute(bool muted);
|
||||||
|
|
||||||
//void populateEndpointWidget(EndpointHandler *eph);
|
//void populateEndpointWidget(EndpointHandler *eph);
|
||||||
//void setEndpointHandlers(std::vector<EndpointHandler*> *ephs);
|
//void setEndpointHandlers(std::vector<EndpointHandler*> *ephs);
|
||||||
|
|
||||||
|
//protected:
|
||||||
|
//bool event(QEvent* ev) override;
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void updateMainVolume(int newValue);
|
||||||
|
void updateMute(int checked);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void customEvent(QEvent* ev) override;
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void addSessionWidget(CustomWidgetEvent<SessionHandler*>* ev);
|
||||||
|
void removeSessionWidget(CustomWidgetEvent<SessionHandler*>* ev);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
EndpointHandler* eph;
|
int row;
|
||||||
QPushButton *muteButton = nullptr;
|
const int sessionCol = 2;
|
||||||
QLabel *mainLabel = nullptr, *leftChannelLabel = nullptr, *rightChannelLabel = nullptr;
|
QCheckBox *muteButton = nullptr;
|
||||||
QSlider *mainSlider = nullptr;
|
QLabel *mainLabel = nullptr;
|
||||||
QSlider *leftChannelSlider = nullptr;
|
QLabel *mainVolumeLabel = nullptr;
|
||||||
QSlider *rightChannelSlider = nullptr;
|
MeterSlider *mainSlider = nullptr;
|
||||||
QGridLayout *layout = nullptr;
|
std::vector<QSlider*> channelSliders;
|
||||||
|
std::vector<QLabel*> channelLabels;
|
||||||
|
QGridLayout *widgetLayout = nullptr;
|
||||||
QGridLayout *mainMuteLayout = nullptr;
|
QGridLayout *mainMuteLayout = nullptr;
|
||||||
|
std::map<Roles, ExtendedCheckBox*> defaultRolesCheckBoxes;
|
||||||
|
|
||||||
|
EndpointHandler* eph;
|
||||||
|
size_t defaultRolesVectorSize = 4;
|
||||||
|
QTimer* timer = nullptr;
|
||||||
|
uint64_t idx;
|
||||||
|
ChannelWidget* cw = nullptr;
|
||||||
|
std::vector<SessionWidget*> sessionWidgets;
|
||||||
|
QSize minimum;
|
||||||
//std::vector<EndpointHandler*> *ephs;
|
//std::vector<EndpointHandler*> *ephs;
|
||||||
//std::vector<QSlider> *sliders;
|
//std::vector<QSlider> *sliders;
|
||||||
|
|
||||||
//public slots:
|
|
||||||
// void setEndpointHandlers(std::vector<EndpointHandler*> *ephs);
|
|
||||||
|
|
||||||
//signals:
|
//signals:
|
||||||
//void valueChanged(int value);
|
//void valueChanged(int value);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class HeaderWidget : public QWidget {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
HeaderWidget(QWidget *parent = nullptr);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QGridLayout *widgetLayout;
|
||||||
|
//QPushButton *about;
|
||||||
|
#ifdef WIN32
|
||||||
|
QPushButton *openCP;
|
||||||
|
QCheckBox *startup;
|
||||||
|
QCheckBox *channels;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
class MainWindow : public QMainWindow {
|
class MainWindow : public QMainWindow {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
//QWidget *centralWidget;
|
//QWidget *centralWidget;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
MainWindow(std::vector<EndpointHandler*> *ephs, QWidget *parent = nullptr);
|
MainWindow(QWidget *parent = nullptr);
|
||||||
|
void reloadEndpointWidgets();
|
||||||
|
void compose(bool isVisible);
|
||||||
|
void updateColor(uint8_t r, uint8_t g, uint8_t b, uint8_t a);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void closeEvent(QCloseEvent *event) override;
|
||||||
|
void customEvent(QEvent* ev) override;
|
||||||
|
QRect setSizePosition(QScreen* screen, int width, int height);
|
||||||
|
QScreen* getCurrentScreen();
|
||||||
|
void createLayout(QGridLayout *newLayout);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void trayIconActivated(QSystemTrayIcon::ActivationReason reason);
|
||||||
|
void removeEndpointWidget(CustomWidgetEvent<uint64_t>* ev);
|
||||||
|
void addEndpointWidget(CustomWidgetEvent<EndpointHandler*>* ev);
|
||||||
|
void reorderEndpointWidgetCollection();
|
||||||
|
//TODO: destroy/empty existing EndpointWidgets
|
||||||
//void setEndpointHandlers(std::vector<EndpointHandler*> *ephs);
|
//void setEndpointHandlers(std::vector<EndpointHandler*> *ephs);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
//std::vector<EndpointHandler*> *ephs;
|
//std::vector<EndpointHandler*> *ephs;
|
||||||
|
bool eventFilter(QObject *object, QEvent *event) override;
|
||||||
|
void flushRoleChanges();
|
||||||
|
void changeFrontDefaults(Roles role, EndpointWidget* newDef, EndpointWidget* oldDef);
|
||||||
|
|
||||||
std::vector<EndpointWidget*> ews;
|
std::vector<EndpointWidget*> ews;
|
||||||
QWidget *widget;
|
std::deque<std::pair<Roles, std::wstring>> roleBucketList;
|
||||||
QGridLayout *layout;
|
std::mutex roleBucketMutex;
|
||||||
//QLabel *pintas;
|
QWidget *containerWidget;
|
||||||
|
QGridLayout *widgetLayout;
|
||||||
|
|
||||||
|
QSystemTrayIcon *trayIcon;
|
||||||
|
QMenu *trayIconMenu;
|
||||||
|
QAction *trayIconMenuQuit;
|
||||||
|
QAction *trayIconMenuOpenCP;
|
||||||
|
QTimer *ewsUpdateTimer;
|
||||||
|
static constexpr uint64_t ewsUpdateTimerFrequency = 500;
|
||||||
|
double widthRatio = 0.28;
|
||||||
|
double dpr = 1.0;
|
||||||
|
bool recentlyClosed = false;
|
||||||
|
uint8_t recentlyClosedTimerFrequency = 1000;
|
||||||
|
QTimer *recentlyClosedTimer;
|
||||||
|
|
||||||
|
QScrollArea *scrollArea;
|
||||||
|
HeaderWidget* hw;
|
||||||
|
QToolBar *mainMenuBar;
|
||||||
|
QScreen *screen;
|
||||||
|
QSpacerItem* lastRowSpacer;
|
||||||
|
QLabel* noEndpoints = nullptr;
|
||||||
|
|
||||||
|
QFont font;
|
||||||
|
friend class EndpointWidget;
|
||||||
//public slots:
|
//public slots:
|
||||||
// void setEndpointHandlers(std::vector<EndpointHandler*> *ephs);
|
// void setEndpointHandlers(std::vector<EndpointHandler*> *ephs);
|
||||||
|
|
||||||
|
|
@ -65,5 +246,3 @@ private:
|
||||||
//void valueChanged(int value);
|
//void valueChanged(int value);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
|
||||||
254
src/qt/qtcommon.h
Normal file
254
src/qt/qtcommon.h
Normal file
|
|
@ -0,0 +1,254 @@
|
||||||
|
#pragma once
|
||||||
|
#include <QLocalSocket>
|
||||||
|
#include <QLocalServer>
|
||||||
|
#include <QString>
|
||||||
|
#include <QFile>
|
||||||
|
#include <QStringList>
|
||||||
|
#include <QStyleFactory>
|
||||||
|
#include <QPalette>
|
||||||
|
|
||||||
|
#include <QMainWindow>
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QCloseEvent>
|
||||||
|
|
||||||
|
#include <QIcon>
|
||||||
|
#include <QSystemTrayIcon>
|
||||||
|
#include <QMenu>
|
||||||
|
//#include <QMessageBox>
|
||||||
|
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QSlider>
|
||||||
|
#include <QGridLayout>
|
||||||
|
#include <QPushButton>
|
||||||
|
#include <QCheckBox>
|
||||||
|
#include <QTimer>
|
||||||
|
#include <QScrollArea>
|
||||||
|
#include <QScrollBar>
|
||||||
|
#include <QSize>
|
||||||
|
#include <QMenuBar>
|
||||||
|
#include <QMenu>
|
||||||
|
#include <QScreen>
|
||||||
|
#include <QToolBar>
|
||||||
|
#include <QWindow>
|
||||||
|
#include <QPainter>
|
||||||
|
#include <QStyle>
|
||||||
|
#include <QStyleOptionComplex>
|
||||||
|
#include <QStyleOptionSlider>
|
||||||
|
#include <QStylePainter>
|
||||||
|
#include <QStyleOptionSlider>
|
||||||
|
#include <QFontMetrics>
|
||||||
|
#include <QProxyStyle>
|
||||||
|
#include <QPixmapCache>
|
||||||
|
#include <QLatin1Char>
|
||||||
|
#include <QLatin1String>
|
||||||
|
#include <QFontDatabase>
|
||||||
|
#include <QAbstractNativeEventFilter>
|
||||||
|
#include <QAbstractEventDispatcher>
|
||||||
|
#include <QSvgRenderer>
|
||||||
|
//#include <QScrollbarStyleAnimation>
|
||||||
|
//#include <QScrollBar>
|
||||||
|
/*
|
||||||
|
* #else
|
||||||
|
* class QSlider;
|
||||||
|
* class QLabel;
|
||||||
|
* class QGridLayout;
|
||||||
|
* class QPushButton;
|
||||||
|
* class QWidget;
|
||||||
|
* class QMainWindow;
|
||||||
|
* #endif
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "global.h"
|
||||||
|
|
||||||
|
enum CustomComplexControl {
|
||||||
|
CC_MeterSlider = 0xf0000001
|
||||||
|
};
|
||||||
|
|
||||||
|
enum CustomControlElement {
|
||||||
|
CE_ExtendedCheckBox = 0xf0000001
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace StylingHelper {
|
||||||
|
|
||||||
|
static inline void setBackgroundColor(bool lightMode) {
|
||||||
|
//QApplication* app = (QApplication*)QApplication::instance();
|
||||||
|
QPalette pal = QGuiApplication::palette();
|
||||||
|
if(lightMode) {
|
||||||
|
pal.setColor(QPalette::Window, Qt::white);
|
||||||
|
pal.setColor(QPalette::WindowText, Qt::black);
|
||||||
|
} else {
|
||||||
|
pal.setColor(QPalette::Window, Qt::black);
|
||||||
|
pal.setColor(QPalette::WindowText, Qt::white);
|
||||||
|
}
|
||||||
|
QGuiApplication::setPalette(pal);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void setAccentColor(bool lightMode) {
|
||||||
|
//QApplication* app = (QApplication*)QApplication::instance();
|
||||||
|
QPalette pal = QGuiApplication::palette();
|
||||||
|
if(lightMode) {
|
||||||
|
pal.setColor(QPalette::Window, Qt::white);
|
||||||
|
pal.setColor(QPalette::WindowText, Qt::black);
|
||||||
|
} else {
|
||||||
|
pal.setColor(QPalette::Window, Qt::black);
|
||||||
|
pal.setColor(QPalette::WindowText, Qt::white);
|
||||||
|
}
|
||||||
|
QGuiApplication::setPalette(pal);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool argbToDiscreteValues(uint32_t color, uint8_t *r, uint8_t *g, uint8_t *b, uint8_t *a) {
|
||||||
|
if(!r || !g || !b || !a) return false;
|
||||||
|
|
||||||
|
*a = (color >> 24) & 0xFF;
|
||||||
|
*r = (color >> 16) & 0xFF;
|
||||||
|
*g = (color >> 8) & 0xFF;
|
||||||
|
*b = color & 0xFF;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline QLatin1String operator""_L1(const char* ch, uint64_t) {
|
||||||
|
return QLatin1String(ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline qreal calculateDpi(const QStyleOption *option) {
|
||||||
|
#ifndef Q_OS_DARWIN
|
||||||
|
// Prioritize the application override, except for on macOS where
|
||||||
|
// we have historically not supported the AA_Use96Dpi flag.
|
||||||
|
if (QCoreApplication::testAttribute(Qt::AA_Use96Dpi))
|
||||||
|
return 96;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Expect that QStyleOption::QFontMetrics::QFont has the correct DPI set
|
||||||
|
if (option)
|
||||||
|
return option->fontMetrics.fontDpi();
|
||||||
|
|
||||||
|
// Fall back to historical Qt behavior: hardcoded 72 DPI on mac,
|
||||||
|
// primary screen DPI on other platforms.
|
||||||
|
#ifdef Q_OS_DARWIN
|
||||||
|
return qstyleBaseDpi;
|
||||||
|
#else
|
||||||
|
return QGuiApplication::primaryScreen()->physicalDotsPerInch();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline qreal calculateDpi() {
|
||||||
|
return QFontMetrics(QApplication::font()).fontDpi();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* #ifdef Q_OS_DARWIN
|
||||||
|
* static const qreal qstyleBaseDpi = 72;
|
||||||
|
* #else
|
||||||
|
* static const qreal qstyleBaseDpi = 96;
|
||||||
|
* #endif
|
||||||
|
*/
|
||||||
|
|
||||||
|
//Q_GUI_EXPORT int qt_defaultDpiX() const;
|
||||||
|
|
||||||
|
|
||||||
|
static inline qreal dpiScaled(qreal value, qreal dpi) {
|
||||||
|
static const qreal qstyleBaseDpi = 96;
|
||||||
|
return value * dpi / qstyleBaseDpi;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline qreal dpiScaled(qreal value, const QPaintDevice *device) {
|
||||||
|
return dpiScaled(value, device->logicalDpiX());
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline qreal dpiScaled(qreal value, const QStyleOption *option) {
|
||||||
|
return dpiScaled(value, calculateDpi(option));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool isMacSystemPalette(const QPalette &pal) {
|
||||||
|
Q_UNUSED(pal);
|
||||||
|
#if defined(Q_OS_MACOS)
|
||||||
|
const QPalette *themePalette = QGuiApplicationPrivate::platformTheme()->palette();
|
||||||
|
if (themePalette && themePalette->color(QPalette::Normal, QPalette::Highlight) ==
|
||||||
|
pal.color(QPalette::Normal, QPalette::Highlight) &&
|
||||||
|
themePalette->color(QPalette::Normal, QPalette::HighlightedText) ==
|
||||||
|
pal.color(QPalette::Normal, QPalette::HighlightedText))
|
||||||
|
return true;
|
||||||
|
#endif
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline QColor highlight(const QPalette &pal) {
|
||||||
|
if (isMacSystemPalette(pal))
|
||||||
|
return QColor(60, 140, 230);
|
||||||
|
return pal.color(QPalette::Highlight);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline QColor highlightedOutline(const QPalette &pal) {
|
||||||
|
QColor highlightedOutline = highlight(pal).darker(125);
|
||||||
|
if (highlightedOutline.value() > 160)
|
||||||
|
highlightedOutline.setHsl(highlightedOutline.hue(), highlightedOutline.saturation(), 160);
|
||||||
|
return highlightedOutline;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline QColor getOutline(const QPalette &pal) {
|
||||||
|
if (pal.window().style() == Qt::TexturePattern)
|
||||||
|
return QColor(0, 0, 0, 160);
|
||||||
|
return pal.window().color().darker(140);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline QColor getButtonColor(const QPalette &pal) {
|
||||||
|
QColor buttonColor = pal.button().color();
|
||||||
|
int val = qGray(buttonColor.rgb());
|
||||||
|
buttonColor = buttonColor.lighter(100 + qMax(1, (180 - val)/6));
|
||||||
|
buttonColor.setHsv(buttonColor.hue(), buttonColor.saturation() * 0.75, buttonColor.value());
|
||||||
|
return buttonColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline QColor innerContrastLine() {
|
||||||
|
return QColor(255, 255, 255, 30);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline QPixmap styleCachePixmap(const QSize &size, qreal pixelRatio) {
|
||||||
|
//not api
|
||||||
|
QPixmap cachePixmap = QPixmap(size * pixelRatio);
|
||||||
|
cachePixmap.setDevicePixelRatio(pixelRatio);
|
||||||
|
cachePixmap.fill(Qt::transparent);
|
||||||
|
return cachePixmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline QColor backgroundColor(const QPalette &pal, const QWidget* widget)
|
||||||
|
{
|
||||||
|
#if QT_CONFIG(scrollarea)
|
||||||
|
if (qobject_cast<const QScrollBar *>(widget) && widget->parent() &&
|
||||||
|
qobject_cast<const QAbstractScrollArea *>(widget->parent()->parent()))
|
||||||
|
return widget->parentWidget()->parentWidget()->palette().color(QPalette::Base);
|
||||||
|
#else
|
||||||
|
Q_UNUSED(widget);
|
||||||
|
#endif
|
||||||
|
return pal.color(QPalette::Base);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline QPixmap svg2Pixmap(const QString& svgContent,
|
||||||
|
const QSize& size,
|
||||||
|
QPainter::CompositionMode mode = QPainter::CompositionMode_SourceOver)
|
||||||
|
{
|
||||||
|
QSvgRenderer rr(svgContent);
|
||||||
|
QImage image(size.width(), size.height(), QImage::Format_ARGB32);
|
||||||
|
QPainter painter(&image);
|
||||||
|
painter.setCompositionMode(mode);
|
||||||
|
image.fill(Qt::transparent);
|
||||||
|
rr.render(&painter);
|
||||||
|
return QPixmap::fromImage(image);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline QScreen* getCurrentScreen() {
|
||||||
|
//note: Using cursor pos as screen detector. Flawed.
|
||||||
|
QPoint cursorPos = QCursor::pos();
|
||||||
|
|
||||||
|
for (QScreen *screen : QGuiApplication::screens()) {
|
||||||
|
QRect screenRect = screen->geometry();
|
||||||
|
if (screenRect.contains(cursorPos)) {
|
||||||
|
return screen;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return QGuiApplication::primaryScreen();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
903
src/qt/qtvisuals.h
Normal file
903
src/qt/qtvisuals.h
Normal file
|
|
@ -0,0 +1,903 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "qtcommon.h"
|
||||||
|
#include "meterslider.h"
|
||||||
|
|
||||||
|
using namespace StylingHelper;
|
||||||
|
|
||||||
|
class MixerStyle : public QProxyStyle {
|
||||||
|
|
||||||
|
public:
|
||||||
|
using QProxyStyle::QProxyStyle;
|
||||||
|
|
||||||
|
//void drawComplexControl(ComplexControl cc, const QStyleOptionComplex *option,
|
||||||
|
// QPainter *painter, const QWidget *widget) const override;
|
||||||
|
//Click on slider = move handle to click pos
|
||||||
|
int styleHint(QStyle::StyleHint hint, const QStyleOption* option = 0, const QWidget* widget = 0,
|
||||||
|
QStyleHintReturn* returnData = 0) const {
|
||||||
|
if (hint == QStyle::SH_Slider_AbsoluteSetButtons)
|
||||||
|
return (Qt::LeftButton | Qt::MiddleButton | Qt::RightButton);
|
||||||
|
return baseStyle()->styleHint(hint, option, widget, returnData);
|
||||||
|
}
|
||||||
|
|
||||||
|
QRect subControlRect(ComplexControl control,
|
||||||
|
const QStyleOptionComplex *option,
|
||||||
|
SubControl subControl,
|
||||||
|
const QWidget *widget) const {
|
||||||
|
QRect rect = QCommonStyle::subControlRect(CC_Slider, option, subControl, widget);
|
||||||
|
|
||||||
|
switch (control) {
|
||||||
|
#if QT_CONFIG(slider)
|
||||||
|
case CC_MeterSlider:
|
||||||
|
if (const QStyleOptionSlider *slider = qstyleoption_cast<const QStyleOptionSlider *>(option)) {
|
||||||
|
int tickSize = proxy()->pixelMetric(PM_SliderTickmarkOffset, option, widget);
|
||||||
|
switch (subControl) {
|
||||||
|
case SC_SliderHandle: {
|
||||||
|
const bool bothTicks = (slider->tickPosition & QSlider::TicksBothSides) == QSlider::TicksBothSides;
|
||||||
|
if (slider->orientation == Qt::Horizontal) {
|
||||||
|
rect.setHeight(baseStyle()->pixelMetric(PM_SliderThickness, option, widget));
|
||||||
|
rect.setWidth(baseStyle()->pixelMetric(PM_SliderLength, option, widget));
|
||||||
|
int centerY = slider->rect.center().y() - rect.height() / 2;
|
||||||
|
if (!bothTicks) {
|
||||||
|
if (slider->tickPosition & QSlider::TicksAbove)
|
||||||
|
centerY += tickSize;
|
||||||
|
if (slider->tickPosition & QSlider::TicksBelow)
|
||||||
|
centerY -= tickSize - 1;
|
||||||
|
}
|
||||||
|
rect.moveTop(centerY);
|
||||||
|
} else {
|
||||||
|
rect.setWidth(baseStyle()->pixelMetric(PM_SliderThickness, option, widget));
|
||||||
|
rect.setHeight(baseStyle()->pixelMetric(PM_SliderLength, option, widget));
|
||||||
|
int centerX = slider->rect.center().x() - rect.width() / 2;
|
||||||
|
if (!bothTicks) {
|
||||||
|
if (slider->tickPosition & QSlider::TicksAbove)
|
||||||
|
centerX += tickSize;
|
||||||
|
if (slider->tickPosition & QSlider::TicksBelow)
|
||||||
|
centerX -= tickSize - 1;
|
||||||
|
}
|
||||||
|
rect.moveLeft(centerX);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SC_SliderGroove: {
|
||||||
|
QPoint grooveCenter = slider->rect.center();
|
||||||
|
//rect.setWidth(std::abs(grooveCenter.x()) * 2);
|
||||||
|
const int grooveThickness = dpiScaled(7, option); //QStyleHelper::dpiScaled(7, option);
|
||||||
|
const bool bothTicks = (slider->tickPosition & QSlider::TicksBothSides) == QSlider::TicksBothSides;
|
||||||
|
if (slider->orientation == Qt::Horizontal) {
|
||||||
|
rect.setHeight(grooveThickness);
|
||||||
|
if (!bothTicks) {
|
||||||
|
if (slider->tickPosition & QSlider::TicksAbove)
|
||||||
|
grooveCenter.ry() += tickSize;
|
||||||
|
if (slider->tickPosition & QSlider::TicksBelow)
|
||||||
|
grooveCenter.ry() -= tickSize - 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
rect.setWidth(grooveThickness);
|
||||||
|
if (!bothTicks) {
|
||||||
|
if (slider->tickPosition & QSlider::TicksAbove)
|
||||||
|
grooveCenter.rx() += tickSize;
|
||||||
|
if (slider->tickPosition & QSlider::TicksBelow)
|
||||||
|
grooveCenter.rx() -= tickSize - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rect.moveCenter(grooveCenter);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rect;
|
||||||
|
break;
|
||||||
|
#endif // QT_CONFIG(slider)
|
||||||
|
#if QT_CONFIG(scrollbar)
|
||||||
|
case CC_ScrollBar:
|
||||||
|
if (const QStyleOptionSlider *scrollbar = qstyleoption_cast<const QStyleOptionSlider *>(option)) {
|
||||||
|
QRect scrollBarRect = scrollbar->rect;
|
||||||
|
const uint64_t offset = 7;
|
||||||
|
scrollBarRect.setWidth(scrollBarRect.width() / 2);
|
||||||
|
scrollBarRect.setHeight(scrollBarRect.height() - 15);
|
||||||
|
int maxlen = ((scrollbar->orientation == Qt::Horizontal) ?
|
||||||
|
scrollBarRect.width() : scrollBarRect.height());
|
||||||
|
int sliderlen;
|
||||||
|
|
||||||
|
// calculate slider length
|
||||||
|
if (scrollbar->maximum != scrollbar->minimum) {
|
||||||
|
uint range = scrollbar->maximum - scrollbar->minimum;
|
||||||
|
sliderlen = (qint64(scrollbar->pageStep) * maxlen) / (range + scrollbar->pageStep);
|
||||||
|
|
||||||
|
int slidermin = baseStyle()->pixelMetric(PM_ScrollBarSliderMin, scrollbar, widget);
|
||||||
|
if (sliderlen < slidermin || range > INT_MAX / 2)
|
||||||
|
sliderlen = slidermin;
|
||||||
|
if (sliderlen > maxlen)
|
||||||
|
sliderlen = maxlen;
|
||||||
|
} else {
|
||||||
|
sliderlen = maxlen;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sliderstart = sliderPositionFromValue(scrollbar->minimum,
|
||||||
|
scrollbar->maximum,
|
||||||
|
scrollbar->sliderPosition,
|
||||||
|
maxlen - sliderlen,
|
||||||
|
scrollbar->upsideDown);
|
||||||
|
|
||||||
|
switch (subControl) {
|
||||||
|
/*
|
||||||
|
* case SC_ScrollBarSubLine: // top/left button
|
||||||
|
* if (scrollbar->orientation == Qt::Horizontal) {
|
||||||
|
* int buttonWidth = qMin(scrollBarRect.width() / 2, sbextent);
|
||||||
|
* rect.setRect(0, 0, buttonWidth, scrollBarRect.height());
|
||||||
|
* } else {
|
||||||
|
* int buttonHeight = qMin(scrollBarRect.height() / 2, sbextent);
|
||||||
|
* rect.setRect(0, 0, scrollBarRect.width(), buttonHeight);
|
||||||
|
* }
|
||||||
|
* break;
|
||||||
|
* case SC_ScrollBarAddLine: // bottom/right button
|
||||||
|
* if (scrollbar->orientation == Qt::Horizontal) {
|
||||||
|
* int buttonWidth = qMin(scrollBarRect.width()/2, sbextent);
|
||||||
|
* rect.setRect(scrollBarRect.width() - buttonWidth, 0, buttonWidth, scrollBarRect.height());
|
||||||
|
* } else {
|
||||||
|
* int buttonHeight = qMin(scrollBarRect.height()/2, sbextent);
|
||||||
|
* rect.setRect(0, scrollBarRect.height() - buttonHeight, scrollBarRect.width(), buttonHeight);
|
||||||
|
* }
|
||||||
|
* break;
|
||||||
|
*/
|
||||||
|
case SC_ScrollBarSubPage: // between top/left button and slider
|
||||||
|
if (scrollbar->orientation == Qt::Horizontal)
|
||||||
|
rect.setRect(0, 0, sliderstart, scrollBarRect.height());
|
||||||
|
else
|
||||||
|
rect.setRect(0, 0, scrollBarRect.width(), sliderstart);
|
||||||
|
break;
|
||||||
|
case SC_ScrollBarAddPage: // between bottom/right button and slider
|
||||||
|
if (scrollbar->orientation == Qt::Horizontal)
|
||||||
|
rect.setRect(sliderstart + sliderlen, 0,
|
||||||
|
maxlen - sliderstart - sliderlen, scrollBarRect.height());
|
||||||
|
else
|
||||||
|
rect.setRect(0, sliderstart + sliderlen, scrollBarRect.width(),
|
||||||
|
maxlen - sliderstart - sliderlen);
|
||||||
|
break;
|
||||||
|
case SC_ScrollBarGroove:
|
||||||
|
if (scrollbar->orientation == Qt::Horizontal)
|
||||||
|
rect.setRect(offset, 0, scrollBarRect.width(),
|
||||||
|
scrollBarRect.height());
|
||||||
|
else
|
||||||
|
rect.setRect(0, offset, scrollBarRect.width(),
|
||||||
|
scrollBarRect.height() );
|
||||||
|
break;
|
||||||
|
case SC_ScrollBarSlider:
|
||||||
|
if (scrollbar->orientation == Qt::Horizontal)
|
||||||
|
rect.setRect(sliderstart + offset, 0, sliderlen, scrollBarRect.height());
|
||||||
|
else
|
||||||
|
rect.setRect(0, sliderstart + offset, scrollBarRect.width(), sliderlen);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
rect = visualRect(scrollbar->direction, scrollBarRect, rect);
|
||||||
|
return rect;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
#endif // QT_CONFIG(scrollbar)
|
||||||
|
default:
|
||||||
|
return baseStyle()->subControlRect(control, option, subControl, widget);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return QRect();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void drawControl(ControlElement element, const QStyleOption *opt,
|
||||||
|
QPainter *p, const QWidget *widget) const
|
||||||
|
{
|
||||||
|
switch(element) {
|
||||||
|
case CE_ExtendedCheckBox:
|
||||||
|
if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
|
||||||
|
QStyleOptionButton subopt = *btn;
|
||||||
|
subopt.rect = subElementRect(SE_CheckBoxIndicator, btn, widget);
|
||||||
|
//proxy()->drawPrimitive(PE_IndicatorCheckBox, &subopt, p, widget);
|
||||||
|
subopt.rect = subElementRect(SE_CheckBoxContents, btn, widget);
|
||||||
|
|
||||||
|
//proxy()->drawControl(CE_CheckBoxLabel, &subopt, p, widget);
|
||||||
|
int alignment = visualAlignment(btn->direction, Qt::AlignLeft | Qt::AlignVCenter);
|
||||||
|
|
||||||
|
if (!proxy()->styleHint(SH_UnderlineShortcut, btn, widget))
|
||||||
|
alignment |= Qt::TextHideMnemonic;
|
||||||
|
QPixmap pix;
|
||||||
|
QRect textRect = btn->rect;
|
||||||
|
if (!btn->icon.isNull()) {
|
||||||
|
pix = btn->icon.pixmap(btn->iconSize, StylingHelper::getCurrentScreen()->devicePixelRatio(),
|
||||||
|
QIcon::Mode::Normal, btn->state & State_On ? QIcon::On : QIcon::Off);
|
||||||
|
proxy()->drawItemPixmap(p, btn->rect, alignment, pix);
|
||||||
|
if (btn->direction == Qt::RightToLeft)
|
||||||
|
textRect.setRight(textRect.right() - btn->iconSize.width() - 4);
|
||||||
|
else
|
||||||
|
textRect.setLeft(textRect.left() + btn->iconSize.width() + 4);
|
||||||
|
}
|
||||||
|
if (!btn->text.isEmpty()){
|
||||||
|
proxy()->drawItemText(p, textRect, alignment | Qt::TextShowMnemonic,
|
||||||
|
btn->palette, btn->state & State_Enabled, btn->text, QPalette::WindowText);
|
||||||
|
}
|
||||||
|
//
|
||||||
|
if (btn->state & State_HasFocus) {
|
||||||
|
QStyleOptionFocusRect fropt;
|
||||||
|
fropt.QStyleOption::operator=(*btn);
|
||||||
|
fropt.rect = subElementRect(SE_CheckBoxFocusRect, btn, widget);
|
||||||
|
proxy()->drawPrimitive(PE_FrameFocusRect, &fropt, p, widget);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
baseStyle()->drawControl(element, opt, p, widget);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void drawComplexControl(ComplexControl cc, const QStyleOptionComplex *option,
|
||||||
|
QPainter *painter, const QWidget *widget) const {
|
||||||
|
QColor outline;
|
||||||
|
switch (cc) {
|
||||||
|
#if QT_CONFIG(slider)
|
||||||
|
case CC_MeterSlider:
|
||||||
|
if (const QStyleOptionSlider *slider = qstyleoption_cast<const QStyleOptionSlider *>(option)) {
|
||||||
|
const qreal dpr = painter->device()->devicePixelRatio();
|
||||||
|
const QColor buttonColor = getButtonColor(option->palette);
|
||||||
|
QRect groove = this->subControlRect(static_cast<QStyle::ComplexControl>(CC_MeterSlider), option, SC_SliderGroove, widget);
|
||||||
|
QRect handle = this->subControlRect(static_cast<QStyle::ComplexControl>(CC_MeterSlider), option, SC_SliderHandle, widget);
|
||||||
|
|
||||||
|
bool horizontal = slider->orientation == Qt::Horizontal;
|
||||||
|
bool ticksAbove = slider->tickPosition & QSlider::TicksAbove;
|
||||||
|
bool ticksBelow = slider->tickPosition & QSlider::TicksBelow;
|
||||||
|
QColor activeHighlight = highlight(option->palette);
|
||||||
|
QPixmap cache;
|
||||||
|
QBrush oldBrush = painter->brush();
|
||||||
|
QPen oldPen = painter->pen();
|
||||||
|
QColor shadowAlpha(Qt::black);
|
||||||
|
shadowAlpha.setAlpha(10);
|
||||||
|
|
||||||
|
if (option->state & State_HasFocus && option->state & State_KeyboardFocusChange)
|
||||||
|
outline = highlightedOutline(option->palette);
|
||||||
|
|
||||||
|
if ((option->subControls & SC_SliderGroove) && groove.isValid()) {
|
||||||
|
QColor grooveColor;
|
||||||
|
grooveColor.setHsv(buttonColor.hue(),
|
||||||
|
qMin(255, (int)(buttonColor.saturation())),
|
||||||
|
qMin(255, (int)(buttonColor.value()*0.9)));
|
||||||
|
QString groovePixmapName = "slider_groove" + QString::number(groove.width());//QStyleHelper::uniqueName("slider_groove"_L1, option, groove.size(), dpr);
|
||||||
|
QRect pixmapRect(0, 0, groove.width(), groove.height());
|
||||||
|
|
||||||
|
// draw background groove
|
||||||
|
if (!QPixmapCache::find(groovePixmapName, &cache)) {
|
||||||
|
cache = styleCachePixmap(pixmapRect.size(), dpr);
|
||||||
|
QPainter groovePainter(&cache);
|
||||||
|
groovePainter.setRenderHint(QPainter::Antialiasing, true);
|
||||||
|
groovePainter.translate(0.5, 0.5);
|
||||||
|
QLinearGradient gradient;
|
||||||
|
if (horizontal) {
|
||||||
|
gradient.setStart(pixmapRect.center().x(), pixmapRect.top());
|
||||||
|
gradient.setFinalStop(pixmapRect.center().x(), pixmapRect.bottom());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
gradient.setStart(pixmapRect.left(), pixmapRect.center().y());
|
||||||
|
gradient.setFinalStop(pixmapRect.right(), pixmapRect.center().y());
|
||||||
|
}
|
||||||
|
groovePainter.setPen(QPen(outline));
|
||||||
|
gradient.setColorAt(0, grooveColor.darker(110));
|
||||||
|
gradient.setColorAt(1, grooveColor.lighter(110));//palette.button().color().darker(115));
|
||||||
|
groovePainter.setBrush(gradient);
|
||||||
|
groovePainter.drawRoundedRect(pixmapRect.adjusted(1, 1, -2, -2), 1, 1);
|
||||||
|
groovePainter.end();
|
||||||
|
QPixmapCache::insert(groovePixmapName, cache);
|
||||||
|
}
|
||||||
|
painter->drawPixmap(groove.topLeft(), cache);
|
||||||
|
|
||||||
|
// draw groove lines (vol + unattenuated vol)
|
||||||
|
const MeterSlider* widgetCast = qobject_cast<const MeterSlider*>(widget);
|
||||||
|
if (widgetCast) {
|
||||||
|
QRect clipRect;
|
||||||
|
//if (!groovePixmapName.isEmpty()) groovePixmapName += QLatin1String("_unattenuated");
|
||||||
|
//groovePixmapName += "_unattenuated"_L1;
|
||||||
|
//lf (!QPixmapCache::find(groovePixmapName, &cache)) {
|
||||||
|
cache = styleCachePixmap(pixmapRect.size(), dpr);
|
||||||
|
QPainter groovePainter(&cache);
|
||||||
|
QLinearGradient gradient;
|
||||||
|
if (horizontal) {
|
||||||
|
gradient.setStart(pixmapRect.center().x(), pixmapRect.top());
|
||||||
|
gradient.setFinalStop(pixmapRect.center().x(), pixmapRect.bottom());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
gradient.setStart(pixmapRect.left(), pixmapRect.center().y());
|
||||||
|
gradient.setFinalStop(pixmapRect.right(), pixmapRect.center().y());
|
||||||
|
}
|
||||||
|
QColor highlight = QColor(30,30,30,100); //this->highlight(option->palette);
|
||||||
|
QColor highlightedoutline = highlight.darker(140);
|
||||||
|
QColor grooveOutline = outline;
|
||||||
|
if (qGray(grooveOutline.rgb()) > qGray(highlightedoutline.rgb()))
|
||||||
|
grooveOutline = highlightedoutline;
|
||||||
|
|
||||||
|
float peakValue = ((MeterSlider*)widget)->peakValue;
|
||||||
|
groovePainter.setRenderHint(QPainter::Antialiasing, true);
|
||||||
|
groovePainter.translate(0.5, 0.5);
|
||||||
|
groovePainter.setPen(QPen(grooveOutline));
|
||||||
|
gradient.setColorAt(0, highlight);
|
||||||
|
gradient.setColorAt(1, highlight.lighter(130));
|
||||||
|
groovePainter.setBrush(gradient);
|
||||||
|
groovePainter.drawRoundedRect(pixmapRect.adjusted(
|
||||||
|
1, 1,
|
||||||
|
-pixmapRect.width() + (pixmapRect.width() * peakValue),
|
||||||
|
-2), 1, 1);
|
||||||
|
groovePainter.setPen(innerContrastLine());
|
||||||
|
groovePainter.setBrush(Qt::green);
|
||||||
|
double stepWidth = (double)widgetCast->width() * ((double)widgetCast->singleStep() / (widgetCast->maximum() - widgetCast->minimum()));
|
||||||
|
groovePainter.drawRoundedRect(pixmapRect.adjusted(
|
||||||
|
1, 1,
|
||||||
|
-pixmapRect.width() + ((widgetCast->width() - ((widgetCast->maximum() - widgetCast->value()) * stepWidth)) * peakValue),
|
||||||
|
-2), 1, 1);
|
||||||
|
|
||||||
|
groovePainter.end();
|
||||||
|
//QPixmapCache::insert(groovePixmapName, cache);
|
||||||
|
//}
|
||||||
|
//}
|
||||||
|
if (horizontal) {
|
||||||
|
if (slider->upsideDown)
|
||||||
|
clipRect = QRect(handle.right(), groove.top(), groove.right() - handle.right(), groove.height());
|
||||||
|
else
|
||||||
|
clipRect = QRect(groove.left() + 2, groove.top() + 2,
|
||||||
|
groove.right() - 2, 2);
|
||||||
|
} else {
|
||||||
|
if (slider->upsideDown)
|
||||||
|
clipRect = QRect(groove.left(), handle.bottom(), groove.width(), groove.height() - (handle.bottom() - slider->rect.top()));
|
||||||
|
else
|
||||||
|
clipRect = QRect(groove.left(), groove.top(), groove.width(), handle.top() - groove.top());
|
||||||
|
}
|
||||||
|
painter->save();
|
||||||
|
painter->setClipRect(clipRect.adjusted(0, 0, 1, 1), Qt::IntersectClip);
|
||||||
|
painter->drawPixmap(groove.topLeft(), cache);
|
||||||
|
painter->restore();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (option->subControls & SC_SliderTickmarks) {
|
||||||
|
painter->save();
|
||||||
|
painter->translate(slider->rect.x(), slider->rect.y());
|
||||||
|
painter->setPen(outline);
|
||||||
|
int tickSize = proxy()->pixelMetric(PM_SliderTickmarkOffset, option, widget);
|
||||||
|
int available = proxy()->pixelMetric(PM_SliderSpaceAvailable, slider, widget);
|
||||||
|
int interval = slider->tickInterval;
|
||||||
|
if (interval <= 0) {
|
||||||
|
interval = slider->singleStep;
|
||||||
|
if (QStyle::sliderPositionFromValue(slider->minimum, slider->maximum, interval,
|
||||||
|
available)
|
||||||
|
- QStyle::sliderPositionFromValue(slider->minimum, slider->maximum,
|
||||||
|
0, available) < 3)
|
||||||
|
interval = slider->pageStep;
|
||||||
|
}
|
||||||
|
if (interval <= 0)
|
||||||
|
interval = 1;
|
||||||
|
|
||||||
|
int v = slider->minimum;
|
||||||
|
int len = proxy()->pixelMetric(PM_SliderLength, slider, widget);
|
||||||
|
QVector<QLine> lines;
|
||||||
|
while (v <= slider->maximum + 1) {
|
||||||
|
if (v == slider->maximum + 1 && interval == 1)
|
||||||
|
break;
|
||||||
|
const int v_ = qMin(v, slider->maximum);
|
||||||
|
int pos = sliderPositionFromValue(slider->minimum, slider->maximum,
|
||||||
|
v_, (horizontal
|
||||||
|
? slider->rect.width()
|
||||||
|
: slider->rect.height()) - len,
|
||||||
|
slider->upsideDown) + len / 2;
|
||||||
|
int extra = 2 - ((v_ == slider->minimum || v_ == slider->maximum) ? 1 : 0);
|
||||||
|
|
||||||
|
if (horizontal) {
|
||||||
|
if (ticksAbove) {
|
||||||
|
lines += QLine(pos, slider->rect.top() + extra,
|
||||||
|
pos, slider->rect.top() + tickSize);
|
||||||
|
}
|
||||||
|
if (ticksBelow) {
|
||||||
|
lines += QLine(pos, slider->rect.bottom() - extra,
|
||||||
|
pos, slider->rect.bottom() - tickSize);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (ticksAbove) {
|
||||||
|
lines += QLine(slider->rect.left() + extra, pos,
|
||||||
|
slider->rect.left() + tickSize, pos);
|
||||||
|
}
|
||||||
|
if (ticksBelow) {
|
||||||
|
lines += QLine(slider->rect.right() - extra, pos,
|
||||||
|
slider->rect.right() - tickSize, pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// in the case where maximum is max int
|
||||||
|
int nextInterval = v + interval;
|
||||||
|
if (nextInterval < v)
|
||||||
|
break;
|
||||||
|
v = nextInterval;
|
||||||
|
}
|
||||||
|
painter->drawLines(lines);
|
||||||
|
painter->restore();
|
||||||
|
}
|
||||||
|
// draw handle
|
||||||
|
if ((option->subControls & SC_SliderHandle) ) {
|
||||||
|
QString handlePixmapName = "slider_handle" + QString::number(handle.height());//QStyleHelper::uniqueName("slider_handle"_L1, option,//handle.size(), dpr);
|
||||||
|
if (!QPixmapCache::find(handlePixmapName, &cache)) {
|
||||||
|
cache = styleCachePixmap(handle.size(), dpr);
|
||||||
|
QRect pixmapRect(0, 0, handle.width(), handle.height());
|
||||||
|
QPainter handlePainter(&cache);
|
||||||
|
QRect gradRect = pixmapRect.adjusted(2, 2, -2, -2);
|
||||||
|
|
||||||
|
// gradient fill
|
||||||
|
QRect r = pixmapRect.adjusted(1, 1, -2, -2);
|
||||||
|
QLinearGradient gradient = qt_fusion_gradient(gradRect, getButtonColor(option->palette),horizontal ? TopDown : FromLeft);
|
||||||
|
|
||||||
|
handlePainter.setRenderHint(QPainter::Antialiasing, true);
|
||||||
|
handlePainter.translate(0.5, 0.5);
|
||||||
|
|
||||||
|
handlePainter.setPen(Qt::NoPen);
|
||||||
|
handlePainter.setBrush(QColor(0, 0, 0, 40));
|
||||||
|
handlePainter.drawRect(horizontal ? r.adjusted(-1, 2, 1, -2) : r.adjusted(2, -1, -2, 1));
|
||||||
|
|
||||||
|
handlePainter.setPen(QPen(getOutline(option->palette)));
|
||||||
|
if (option->state & State_HasFocus && option->state & State_KeyboardFocusChange)
|
||||||
|
handlePainter.setPen(QPen(highlightedOutline(option->palette)));
|
||||||
|
|
||||||
|
handlePainter.setBrush(gradient);
|
||||||
|
handlePainter.drawRoundedRect(r, 2, 2);
|
||||||
|
handlePainter.setBrush(Qt::NoBrush);
|
||||||
|
handlePainter.setPen(innerContrastLine());
|
||||||
|
handlePainter.drawRoundedRect(r.adjusted(1, 1, -1, -1), 2, 2);
|
||||||
|
|
||||||
|
QColor cornerAlpha = outline.darker(120);
|
||||||
|
cornerAlpha.setAlpha(80);
|
||||||
|
|
||||||
|
//handle shadow
|
||||||
|
handlePainter.setPen(shadowAlpha);
|
||||||
|
handlePainter.drawLine(QPoint(r.left() + 2, r.bottom() + 1), QPoint(r.right() - 2, r.bottom() + 1));
|
||||||
|
handlePainter.drawLine(QPoint(r.right() + 1, r.bottom() - 3), QPoint(r.right() + 1, r.top() + 4));
|
||||||
|
handlePainter.drawLine(QPoint(r.right() - 1, r.bottom()), QPoint(r.right() + 1, r.bottom() - 2));
|
||||||
|
|
||||||
|
handlePainter.end();
|
||||||
|
QPixmapCache::insert(handlePixmapName, cache);
|
||||||
|
}
|
||||||
|
|
||||||
|
painter->drawPixmap(handle.topLeft(), cache);
|
||||||
|
|
||||||
|
}
|
||||||
|
painter->setBrush(oldBrush);
|
||||||
|
painter->setPen(oldPen);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CC_ScrollBar:
|
||||||
|
painter->save();
|
||||||
|
if (const QStyleOptionSlider *scrollBar = qstyleoption_cast<const QStyleOptionSlider *>(option)) {
|
||||||
|
bool wasActive = false;
|
||||||
|
qreal expandScale = 1.0;
|
||||||
|
qreal expandOffset = -1.0;
|
||||||
|
QObject *styleObject = option->styleObject;
|
||||||
|
|
||||||
|
QColor buttonColor = calculateButtonColor(option->palette);
|
||||||
|
QColor gradientStartColor = buttonColor.lighter(104);
|
||||||
|
QColor gradientStopColor = buttonColor.darker(102);
|
||||||
|
|
||||||
|
bool transient = styleHint(SH_ScrollBar_Transient, option, widget);
|
||||||
|
bool horizontal = scrollBar->orientation == Qt::Horizontal;
|
||||||
|
bool sunken = scrollBar->state & State_Sunken;
|
||||||
|
|
||||||
|
QRect scrollBarSubLine = subControlRect(cc, scrollBar, SC_ScrollBarSubLine, widget);
|
||||||
|
QRect scrollBarAddLine = subControlRect(cc, scrollBar, SC_ScrollBarAddLine, widget);
|
||||||
|
QRect scrollBarSlider = subControlRect(cc, scrollBar, SC_ScrollBarSlider, widget);
|
||||||
|
QRect scrollBarGroove = subControlRect(cc, scrollBar, SC_ScrollBarGroove, widget);
|
||||||
|
|
||||||
|
QRect rect = option->rect;
|
||||||
|
outline = highlightedOutline(option->palette);
|
||||||
|
QColor alphaOutline = outline;
|
||||||
|
alphaOutline.setAlpha(180);
|
||||||
|
|
||||||
|
QColor arrowColor = option->palette.windowText().color();
|
||||||
|
//QColor arrowColor = QColor(188,143,143,100);
|
||||||
|
arrowColor.setAlpha(160);
|
||||||
|
|
||||||
|
const QColor appBgColor = QGuiApplication::palette().window().color();
|
||||||
|
const bool isDarkBg = appBgColor.red() < 128 && appBgColor.green() < 128 && appBgColor.blue() < 128;
|
||||||
|
|
||||||
|
if (transient) {
|
||||||
|
if (horizontal) {
|
||||||
|
rect.setY(rect.y() + 4.5 - expandOffset);
|
||||||
|
scrollBarSlider.setY(scrollBarSlider.y() + 4.5 - expandOffset);
|
||||||
|
scrollBarGroove.setY(scrollBarGroove.y() + 4.5 - expandOffset);
|
||||||
|
|
||||||
|
rect.setHeight(rect.height() * expandScale);
|
||||||
|
scrollBarGroove.setHeight(scrollBarGroove.height() * expandScale);
|
||||||
|
} else {
|
||||||
|
rect.setX(rect.x() + 4.5 - expandOffset);
|
||||||
|
scrollBarSlider.setX(scrollBarSlider.x() + 4.5 - expandOffset);
|
||||||
|
scrollBarGroove.setX(scrollBarGroove.x() + 4.5 - expandOffset);
|
||||||
|
|
||||||
|
rect.setWidth(rect.width() * expandScale);
|
||||||
|
scrollBarGroove.setWidth(scrollBarGroove.width() * expandScale);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Paint groove
|
||||||
|
if ((!transient || scrollBar->activeSubControls || wasActive) && scrollBar->subControls & SC_ScrollBarGroove) {
|
||||||
|
QLinearGradient gradient(rect.center().x(), rect.top(),
|
||||||
|
rect.center().x(), rect.bottom());
|
||||||
|
if (!horizontal)
|
||||||
|
gradient = QLinearGradient(rect.left(), rect.center().y(),
|
||||||
|
rect.right(), rect.center().y());
|
||||||
|
if (!transient || !isDarkBg) {
|
||||||
|
gradient.setColorAt(0, buttonColor.darker(107));
|
||||||
|
gradient.setColorAt(0.1, buttonColor.darker(105));
|
||||||
|
gradient.setColorAt(0.9, buttonColor.darker(105));
|
||||||
|
gradient.setColorAt(1, buttonColor.darker(107));
|
||||||
|
} else {
|
||||||
|
gradient.setColorAt(0, appBgColor.lighter(157));
|
||||||
|
gradient.setColorAt(0.1, appBgColor.lighter(155));
|
||||||
|
gradient.setColorAt(0.9, appBgColor.lighter(155));
|
||||||
|
gradient.setColorAt(1, appBgColor.lighter(157));
|
||||||
|
}
|
||||||
|
|
||||||
|
painter->save();
|
||||||
|
//painter->fillRect(rect, gradient);
|
||||||
|
painter->setPen(Qt::NoPen);
|
||||||
|
painter->setPen(alphaOutline);
|
||||||
|
|
||||||
|
QColor subtleEdge = alphaOutline;
|
||||||
|
subtleEdge.setAlpha(40);
|
||||||
|
painter->setPen(subtleEdge);
|
||||||
|
//painter->setBrush(Qt::NoBrush);
|
||||||
|
painter->setOpacity(0.3);
|
||||||
|
painter->setBrush(Qt::gray);
|
||||||
|
painter->drawRoundedRect(scrollBarGroove, 5, 5);
|
||||||
|
//painter->drawRoundedRect(scrollBarGroove, 5, 5);
|
||||||
|
painter->restore();
|
||||||
|
}
|
||||||
|
|
||||||
|
QRect pixmapRect = scrollBarSlider;
|
||||||
|
QColor highlightColor = option->palette.highlight().color();
|
||||||
|
/*
|
||||||
|
* QLinearGradient gradient(pixmapRect.center().x(), pixmapRect.top(),
|
||||||
|
* pixmapRect.center().x(), pixmapRect.bottom());
|
||||||
|
* if (!horizontal)
|
||||||
|
* gradient = QLinearGradient(pixmapRect.left(), pixmapRect.center().y(),
|
||||||
|
* pixmapRect.right(), pixmapRect.center().y());
|
||||||
|
*/
|
||||||
|
|
||||||
|
//QLinearGradient highlightedGradient = gradient;
|
||||||
|
|
||||||
|
QColor heldColor = 0xc4e3d7e0;//Qt::gray;//osh->isLightMode() ? Qt::white : Qt::black;
|
||||||
|
//gradient.setColorAt(0, option->palette.highlight().color());
|
||||||
|
//gradient.setColorAt(1, option->palette.highlight().color());
|
||||||
|
|
||||||
|
//highlightedGradient.setColorAt(0, gradientStartColor.darker(102));
|
||||||
|
//highlightedGradient.setColorAt(1, gradientStopColor.lighter(102));
|
||||||
|
|
||||||
|
// Paint slider
|
||||||
|
if (scrollBar->subControls & SC_ScrollBarSlider) {
|
||||||
|
log_debugcpp("Final scrollbar paint if");
|
||||||
|
if (transient) {
|
||||||
|
QRect rect = scrollBarSlider.adjusted(horizontal ? 1 : 2, horizontal ? 2 : 1, -1, -1);
|
||||||
|
painter->setPen(Qt::NoPen);
|
||||||
|
painter->setBrush(isDarkBg ? lightShade() : darkShade());
|
||||||
|
int r = qMin(rect.width(), rect.height()) / 2;
|
||||||
|
|
||||||
|
painter->save();
|
||||||
|
painter->setRenderHint(QPainter::Antialiasing, true);
|
||||||
|
painter->drawRoundedRect(rect, r, r);
|
||||||
|
painter->restore();
|
||||||
|
} else {
|
||||||
|
QRect pixmapRect = scrollBarSlider;
|
||||||
|
painter->setPen(QPen(alphaOutline));
|
||||||
|
if (option->state & State_Sunken
|
||||||
|
&& scrollBar->activeSubControls & SC_ScrollBarSlider)
|
||||||
|
painter->setBrush(heldColor);
|
||||||
|
else if (option->state & State_MouseOver
|
||||||
|
&& scrollBar->activeSubControls & SC_ScrollBarSlider) {
|
||||||
|
painter->setBrush(highlightColor);
|
||||||
|
}
|
||||||
|
else //if (!isDarkBg)
|
||||||
|
|
||||||
|
if(!isDarkBg)
|
||||||
|
painter->setBrush(Qt::black);
|
||||||
|
else painter->setBrush(Qt::white);
|
||||||
|
//else
|
||||||
|
// painter->setBrush(heldColor);
|
||||||
|
|
||||||
|
painter->drawRoundedRect(pixmapRect.adjusted(horizontal ? -1 : 0, horizontal ? 0 : -1, horizontal ? 0 : -1, horizontal ? -1 : 0), 5, 5);
|
||||||
|
|
||||||
|
painter->setPen(innerContrastLine());
|
||||||
|
painter->drawRoundedRect(scrollBarSlider.adjusted(horizontal ? 0 : 1, horizontal ? 1 : 0, -1, -1), 5, 5);
|
||||||
|
|
||||||
|
// Outer shadow
|
||||||
|
// painter->setPen(subtleEdge);
|
||||||
|
// if (horizontal) {
|
||||||
|
//// painter->drawLine(scrollBarSlider.topLeft() + QPoint(-2, 0), scrollBarSlider.bottomLeft() + QPoint(2, 0));
|
||||||
|
//// painter->drawLine(scrollBarSlider.topRight() + QPoint(-2, 0), scrollBarSlider.bottomRight() + QPoint(2, 0));
|
||||||
|
// } else {
|
||||||
|
//// painter->drawLine(pixmapRect.topLeft() + QPoint(0, -2), pixmapRect.bottomLeft() + QPoint(0, -2));
|
||||||
|
//// painter->drawLine(pixmapRect.topRight() + QPoint(0, 2), pixmapRect.bottomRight() + QPoint(0, 2));
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* // The SubLine (up/left) buttons
|
||||||
|
* if (!transient && scrollBar->subControls & SC_ScrollBarSubLine) {
|
||||||
|
* if ((scrollBar->activeSubControls & SC_ScrollBarSubLine) && sunken)
|
||||||
|
* painter->setBrush(gradientStopColor);
|
||||||
|
* else if ((scrollBar->activeSubControls & SC_ScrollBarSubLine))
|
||||||
|
* painter->setBrush(highlightedGradient);
|
||||||
|
* else
|
||||||
|
* painter->setBrush(gradient);
|
||||||
|
*
|
||||||
|
* painter->setPen(Qt::NoPen);
|
||||||
|
* painter->drawRoundedRect(scrollBarSubLine.adjusted(horizontal ? 0 : 1, horizontal ? 1 : 0, 0, 0), 1, 1);
|
||||||
|
* painter->setPen(QPen(alphaOutline));
|
||||||
|
* if (option->state & State_Horizontal) {
|
||||||
|
* painter->drawRect(scrollBarSubLine.adjusted(horizontal ? 0 : 1, 0, horizontal ? 1 : 0, horizontal ? -1 : 0));
|
||||||
|
* } else {
|
||||||
|
* painter->drawRoundedRect(scrollBarSubLine.adjusted(0, 0, horizontal ? 0 : -1, 0), 1, 1);
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* QRect upRect = scrollBarSubLine.adjusted(horizontal ? 0 : 1, horizontal ? 1 : 0, horizontal ? -2 : -1, horizontal ? -1 : -2);
|
||||||
|
* painter->setBrush(Qt::NoBrush);
|
||||||
|
* painter->setPen(innerContrastLine());
|
||||||
|
* painter->drawRect(upRect);
|
||||||
|
*
|
||||||
|
* // Arrows
|
||||||
|
* Qt::ArrowType arrowType = Qt::UpArrow;
|
||||||
|
* if (option->state & State_Horizontal)
|
||||||
|
* arrowType = option->direction == Qt::LeftToRight ? Qt::LeftArrow : Qt::RightArrow;
|
||||||
|
* qt_fusion_draw_arrow(arrowType, painter, option, upRect, arrowColor);
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* // The AddLine (down/right) button
|
||||||
|
* if (!transient && scrollBar->subControls & SC_ScrollBarAddLine) {
|
||||||
|
* if ((scrollBar->activeSubControls & SC_ScrollBarAddLine) && sunken)
|
||||||
|
* painter->setBrush(gradientStopColor);
|
||||||
|
* else if ((scrollBar->activeSubControls & SC_ScrollBarAddLine))
|
||||||
|
* painter->setBrush(midColor2);
|
||||||
|
* else
|
||||||
|
* painter->setBrush(gradient);
|
||||||
|
*
|
||||||
|
* painter->setPen(Qt::NoPen);
|
||||||
|
* painter->drawRect(scrollBarAddLine.adjusted(horizontal ? 0 : 1, horizontal ? 1 : 0, 0, 0));
|
||||||
|
* painter->setPen(QPen(alphaOutline, 1));
|
||||||
|
* if (option->state & State_Horizontal) {
|
||||||
|
* painter->drawRect(scrollBarAddLine.adjusted(horizontal ? -1 : 0, 0, horizontal ? -1 : 0, horizontal ? -1 : 0));
|
||||||
|
* } else {
|
||||||
|
* painter->drawRect(scrollBarAddLine.adjusted(0, horizontal ? 0 : -1, horizontal ? 0 : -1, horizontal ? 0 : -1));
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* QRect downRect = scrollBarAddLine.adjusted(1, 1, -1, -1);
|
||||||
|
* painter->setPen(innerContrastLine());
|
||||||
|
* painter->setBrush(Qt::NoBrush);
|
||||||
|
* painter->drawRect(downRect);
|
||||||
|
*
|
||||||
|
* Qt::ArrowType arrowType = Qt::DownArrow;
|
||||||
|
* if (option->state & State_Horizontal)
|
||||||
|
* arrowType = option->direction == Qt::LeftToRight ? Qt::RightArrow : Qt::LeftArrow;
|
||||||
|
* qt_fusion_draw_arrow(arrowType, painter, option, downRect, arrowColor);
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
|
||||||
|
}
|
||||||
|
painter->restore();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
baseStyle()->drawComplexControl(cc, option, painter, widget);
|
||||||
|
#endif // QT_CONFIG(slider)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
enum Direction {
|
||||||
|
TopDown,
|
||||||
|
FromLeft,
|
||||||
|
BottomUp,
|
||||||
|
FromRight
|
||||||
|
};
|
||||||
|
|
||||||
|
static QLinearGradient qt_fusion_gradient(const QRect &rect, const QBrush &baseColor, Direction direction = TopDown)
|
||||||
|
{
|
||||||
|
int x = rect.center().x();
|
||||||
|
int y = rect.center().y();
|
||||||
|
QLinearGradient gradient;
|
||||||
|
switch (direction) {
|
||||||
|
case FromLeft:
|
||||||
|
gradient = QLinearGradient(rect.left(), y, rect.right(), y);
|
||||||
|
break;
|
||||||
|
case FromRight:
|
||||||
|
gradient = QLinearGradient(rect.right(), y, rect.left(), y);
|
||||||
|
break;
|
||||||
|
case BottomUp:
|
||||||
|
gradient = QLinearGradient(x, rect.bottom(), x, rect.top());
|
||||||
|
break;
|
||||||
|
case TopDown:
|
||||||
|
default:
|
||||||
|
gradient = QLinearGradient(x, rect.top(), x, rect.bottom());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (baseColor.gradient())
|
||||||
|
gradient.setStops(baseColor.gradient()->stops());
|
||||||
|
else {
|
||||||
|
QColor gradientStartColor = baseColor.color().lighter(124);
|
||||||
|
QColor gradientStopColor = baseColor.color().lighter(102);
|
||||||
|
gradient.setColorAt(0, gradientStartColor);
|
||||||
|
gradient.setColorAt(1, gradientStopColor);
|
||||||
|
// Uncomment for adding shiny shading
|
||||||
|
// QColor midColor1 = mergedColors(gradientStartColor, gradientStopColor, 55);
|
||||||
|
// QColor midColor2 = mergedColors(gradientStartColor, gradientStopColor, 45);
|
||||||
|
// gradient.setColorAt(0.5, midColor1);
|
||||||
|
// gradient.setColorAt(0.501, midColor2);
|
||||||
|
}
|
||||||
|
return gradient;
|
||||||
|
}
|
||||||
|
|
||||||
|
QColor highlightedOutline(const QPalette &pal) const {
|
||||||
|
QColor highlightedOutline = highlight(pal);//.darker(25);//QColor(Qt::green);
|
||||||
|
if (highlightedOutline.value() > 160)
|
||||||
|
highlightedOutline.setHsl(highlightedOutline.hue(), highlightedOutline.saturation(), 160);
|
||||||
|
return highlightedOutline;
|
||||||
|
}
|
||||||
|
|
||||||
|
QColor calculateButtonColor(const QPalette &pal) const {
|
||||||
|
QColor buttonColor = pal.button().color();
|
||||||
|
int val = qGray(buttonColor.rgb());
|
||||||
|
buttonColor = buttonColor.lighter(100 + qMax(1, (180 - val)/6));
|
||||||
|
buttonColor.setHsv(buttonColor.hue(), buttonColor.saturation() * 0.75, buttonColor.value());
|
||||||
|
return buttonColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Used for grip handles
|
||||||
|
QColor lightShade() const {
|
||||||
|
return QColor(255, 255, 255, 90);
|
||||||
|
}
|
||||||
|
|
||||||
|
QColor darkShade() const {
|
||||||
|
return QColor(0, 0, 0, 60);
|
||||||
|
}
|
||||||
|
|
||||||
|
QColor innerContrastLine() const {
|
||||||
|
return QColor(255, 255, 255, 30);
|
||||||
|
}
|
||||||
|
|
||||||
|
static QColor mergedColors(const QColor &colorA, const QColor &colorB, int factor = 50) {
|
||||||
|
const int maxFactor = 100;
|
||||||
|
QColor tmp = colorA;
|
||||||
|
tmp.setRed((tmp.red() * factor) / maxFactor + (colorB.red() * (maxFactor - factor)) / maxFactor);
|
||||||
|
tmp.setGreen((tmp.green() * factor) / maxFactor + (colorB.green() * (maxFactor - factor)) / maxFactor);
|
||||||
|
tmp.setBlue((tmp.blue() * factor) / maxFactor + (colorB.blue() * (maxFactor - factor)) / maxFactor);
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void qt_fusion_draw_arrow(Qt::ArrowType type, QPainter *painter, const QStyleOption *option, const QRect &rect, const QColor &color)
|
||||||
|
{
|
||||||
|
if (rect.isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
const qreal dpi = calculateDpi(option);
|
||||||
|
const qreal dpr = painter->device()->devicePixelRatio();
|
||||||
|
const int arrowWidth = int(dpiScaled(14, dpi));
|
||||||
|
const int arrowHeight = int(dpiScaled(8, dpi));
|
||||||
|
|
||||||
|
const int arrowMax = qMin(arrowHeight, arrowWidth);
|
||||||
|
const int rectMax = qMin(rect.height(), rect.width());
|
||||||
|
const int size = qMin(arrowMax, rectMax);
|
||||||
|
|
||||||
|
QPixmap cachePixmap;
|
||||||
|
const QString cacheKey = "fusion-arrow"_L1 + QString::number(rect.size().width()) + QString::number(rect.size().height()) + QString::number(type);
|
||||||
|
|
||||||
|
if (!QPixmapCache::find(cacheKey, &cachePixmap)) {
|
||||||
|
cachePixmap = styleCachePixmap(rect.size(), dpr);
|
||||||
|
QPainter cachePainter(&cachePixmap);
|
||||||
|
|
||||||
|
QRectF arrowRect;
|
||||||
|
arrowRect.setWidth(size);
|
||||||
|
arrowRect.setHeight(arrowHeight * size / arrowWidth);
|
||||||
|
if (type == Qt::LeftArrow || type == Qt::RightArrow)
|
||||||
|
arrowRect = arrowRect.transposed();
|
||||||
|
arrowRect.moveTo((rect.width() - arrowRect.width()) / 2.0,
|
||||||
|
(rect.height() - arrowRect.height()) / 2.0);
|
||||||
|
|
||||||
|
std::array<QPointF, 3> triangle;
|
||||||
|
switch (type) {
|
||||||
|
case Qt::DownArrow:
|
||||||
|
triangle = {arrowRect.topLeft(), arrowRect.topRight(), QPointF(arrowRect.center().x(), arrowRect.bottom())};
|
||||||
|
break;
|
||||||
|
case Qt::RightArrow:
|
||||||
|
triangle = {arrowRect.topLeft(), arrowRect.bottomLeft(), QPointF(arrowRect.right(), arrowRect.center().y())};
|
||||||
|
break;
|
||||||
|
case Qt::LeftArrow:
|
||||||
|
triangle = {arrowRect.topRight(), arrowRect.bottomRight(), QPointF(arrowRect.left(), arrowRect.center().y())};
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
triangle = {arrowRect.bottomLeft(), arrowRect.bottomRight(), QPointF(arrowRect.center().x(), arrowRect.top())};
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
cachePainter.setPen(Qt::NoPen);
|
||||||
|
cachePainter.setBrush(color);
|
||||||
|
cachePainter.setRenderHint(QPainter::Antialiasing);
|
||||||
|
cachePainter.drawPolygon(triangle.data(), int(triangle.size()));
|
||||||
|
|
||||||
|
QPixmapCache::insert(cacheKey, cachePixmap);
|
||||||
|
}
|
||||||
|
|
||||||
|
painter->drawPixmap(rect, cachePixmap);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* void MixerStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex *opt,
|
||||||
|
* QPainter *p, const QWidget *widget) const {
|
||||||
|
* switch (cc) {
|
||||||
|
* #if QT_CONFIG(slider)
|
||||||
|
* case CC_Slider:
|
||||||
|
* if (const QStyleOptionSlider *slider = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
|
||||||
|
* if (slider->subControls == SC_SliderTickmarks) {
|
||||||
|
* int tickOffset = proxy()->pixelMetric(PM_SliderTickmarkOffset, slider, widget);
|
||||||
|
* int ticks = slider->tickPosition;
|
||||||
|
* int thickness = proxy()->pixelMetric(PM_SliderControlThickness, slider, widget);
|
||||||
|
* int len = proxy()->pixelMetric(PM_SliderLength, slider, widget);
|
||||||
|
* int available = proxy()->pixelMetric(PM_SliderSpaceAvailable, slider, widget);
|
||||||
|
* int interval = slider->tickInterval;
|
||||||
|
* if (interval <= 0) {
|
||||||
|
* interval = slider->singleStep;
|
||||||
|
* if (QStyle::sliderPositionFromValue(slider->minimum, slider->maximum, interval,
|
||||||
|
* available)
|
||||||
|
* - QStyle::sliderPositionFromValue(slider->minimum, slider->maximum,
|
||||||
|
* 0, available) < 3)
|
||||||
|
* interval = slider->pageStep;
|
||||||
|
* }
|
||||||
|
* if (!interval)
|
||||||
|
* interval = 1;
|
||||||
|
* int fudge = len / 2;
|
||||||
|
* int pos;
|
||||||
|
* // Since there is no subrect for tickmarks do a translation here.
|
||||||
|
* p->save();
|
||||||
|
* p->translate(slider->rect.x(), slider->rect.y());
|
||||||
|
* p->setPen(slider->palette.windowText().color());
|
||||||
|
* int v = slider->minimum;
|
||||||
|
* while (v <= slider->maximum + 1) {
|
||||||
|
* if (v == slider->maximum + 1 && interval == 1)
|
||||||
|
* break;
|
||||||
|
* const int v_ = qMin(v, slider->maximum);
|
||||||
|
* pos = QStyle::sliderPositionFromValue(slider->minimum, slider->maximum,
|
||||||
|
* v_, available) + fudge;
|
||||||
|
* if (slider->orientation == Qt::Horizontal) {
|
||||||
|
* if (ticks & QSlider::TicksAbove)
|
||||||
|
* p->drawLine(pos, 0, pos, tickOffset - 2);
|
||||||
|
* if (ticks & QSlider::TicksBelow)
|
||||||
|
* p->drawLine(pos, tickOffset + thickness + 1, pos,
|
||||||
|
* slider->rect.height()-1);
|
||||||
|
* } else {
|
||||||
|
* if (ticks & QSlider::TicksAbove)
|
||||||
|
* p->drawLine(0, pos, tickOffset - 2, pos);
|
||||||
|
* if (ticks & QSlider::TicksBelow)
|
||||||
|
* p->drawLine(tickOffset + thickness + 1, pos,
|
||||||
|
* slider->rect.width()-1, pos);
|
||||||
|
* }
|
||||||
|
* // in the case where maximum is max int
|
||||||
|
* int nextInterval = v + interval;
|
||||||
|
* if (nextInterval < v)
|
||||||
|
* break;
|
||||||
|
* v = nextInterval;
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* p->restore();
|
||||||
|
* break;
|
||||||
|
* default:
|
||||||
|
* baseStyle()->drawComplexControl(cc, opt, p, widget);
|
||||||
|
* break;
|
||||||
|
* }
|
||||||
|
* #endif // QT_CONFIG(slider)
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
|
||||||
|
//void MixerStyle::
|
||||||
|
|
||||||
|
|
@ -1,39 +1,145 @@
|
||||||
#include <iostream>
|
//#include "contclasses.h"
|
||||||
#include <vector>
|
#define INIT_FILELOG
|
||||||
|
#include "qtcommon.h"
|
||||||
//#include <stdio.h>
|
|
||||||
//#include <stdlib.h>
|
|
||||||
|
|
||||||
//#include <qapplicationstatic.h>
|
|
||||||
#include <QApplication>
|
|
||||||
#include <QMainWindow>
|
|
||||||
|
|
||||||
#include "qtclasses.h"
|
#include "qtclasses.h"
|
||||||
|
#include "qtvisuals.h"
|
||||||
|
#include "settings.h"
|
||||||
|
|
||||||
OverseerHandler *osh = new OverseerHandler();
|
OverseerHandler *osh = nullptr;
|
||||||
|
ini::UserSettings *set = nullptr;
|
||||||
QApplication* createApplication(int &argc, char *argv[])
|
|
||||||
{
|
bool startupRun = false;
|
||||||
|
bool onStartup = false;
|
||||||
|
char* userSettingsPath = nullptr;
|
||||||
|
|
||||||
|
QApplication* createApplication(int &argc, char *argv[]) {
|
||||||
return new QApplication(argc, argv);
|
return new QApplication(argc, argv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isInstanceRunning(QString appName) {
|
||||||
|
QLocalSocket socket;
|
||||||
|
socket.connectToServer(appName);
|
||||||
|
bool isOpen = socket.isOpen();
|
||||||
|
socket.close();
|
||||||
|
return isOpen;
|
||||||
|
}
|
||||||
|
|
||||||
|
QLocalServer* startInstanceServer(QString appName) {
|
||||||
|
QLocalServer* server = new QLocalServer;
|
||||||
|
server->setSocketOptions(QLocalServer::WorldAccessOption);
|
||||||
|
server->listen(appName);
|
||||||
|
return server;
|
||||||
|
}
|
||||||
|
|
||||||
|
void closeDebugFileLog() {
|
||||||
|
close_file_log_buffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
void parseCmdArgs(int argc, char* argv[]) {
|
||||||
|
if(argc == 1) return;
|
||||||
|
//char* configPath = nullptr;
|
||||||
|
char* arg[] = { (char*)"--config-path=", (char*)"--change-startup" };
|
||||||
|
|
||||||
|
for (int i = 1; i < argc; i++) {
|
||||||
|
if(strstr(argv[i], arg[0])) {
|
||||||
|
userSettingsPath = argv[i] + strlen(arg[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(strstr(argv[i], arg[1])) {
|
||||||
|
if (++i >= argc) return;
|
||||||
|
switch (argv[i][0]) {
|
||||||
|
case '0':
|
||||||
|
startupRun = true;
|
||||||
|
onStartup = false;
|
||||||
|
break;
|
||||||
|
case '1':
|
||||||
|
startupRun = true;
|
||||||
|
onStartup = true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* set_terminate
|
||||||
|
* void closeDebugFileLog2() {
|
||||||
|
* close_file_log_buffer();
|
||||||
|
* abort();
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
|
||||||
int main (int argc, char* argv[]) {
|
int main (int argc, char* argv[]) {
|
||||||
//QApplication::setStyle("windowsvista");
|
/*
|
||||||
//INIT CONT
|
* Debug: logging report file
|
||||||
std::vector<Endpoint*> epts = OverseerHandler::getOverseer()->getPlaybackEndpoints();
|
*/
|
||||||
std::vector<EndpointHandler*>* ephs = new std::vector<EndpointHandler*>;
|
initialize_file_log();
|
||||||
for(unsigned int i = 0; i < epts.size(); i++){
|
atexit(closeDebugFileLog);
|
||||||
EndpointHandler *eph = new EndpointHandler(epts.at(i));
|
|
||||||
ephs->push_back(eph);
|
QApplication::setStyle(new MixerStyle(QStyleFactory::create("Fusion")));
|
||||||
|
//QApplication::setFont(font);
|
||||||
|
//QPalette palette = QGuiApplication::palette();
|
||||||
|
|
||||||
|
//palette.setColor(QPalette::Active, QPalette::Highlight, QColor(255, 192, 203, 200));
|
||||||
|
//QColor(30,30,30,100));
|
||||||
|
//QGuiApplication::setPalette(palette);
|
||||||
|
osh = new OverseerHandler();
|
||||||
|
osh->populateSystemValues();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Arg parsing: (admin?) startup change run
|
||||||
|
*/
|
||||||
|
parseCmdArgs(argc, argv);
|
||||||
|
if (startupRun) {
|
||||||
|
if (!isInstanceRunning(PIPE_NAME)) exit(-1);
|
||||||
|
//if (startupChangeInfo->permissionChangeScope == NONE) exit(-1);
|
||||||
|
osh->updateStartupConfig(onStartup);
|
||||||
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Check if running
|
||||||
|
//https://stackoverflow.com/questions/48060989/qt-show-application-if-currently-running
|
||||||
|
if (!isInstanceRunning(PIPE_NAME))
|
||||||
|
startInstanceServer(PIPE_NAME);
|
||||||
|
else exit(0);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Config file init
|
||||||
|
*/
|
||||||
|
if (userSettingsPath)
|
||||||
|
set = ini::UserSettings::createSettings(userSettingsPath, true);
|
||||||
|
|
||||||
|
if (set)
|
||||||
|
OverseerHandler::settingsPath = std::string(userSettingsPath);
|
||||||
|
else setConfigDirToDefaults();
|
||||||
|
|
||||||
|
StylingHelper::setBackgroundColor(osh->isLightMode());
|
||||||
|
//qRegisterMetaType<EndpointWidgetEvent>();
|
||||||
|
|
||||||
|
//INIT CONT
|
||||||
|
log_debugcpp("main init");
|
||||||
|
osh->createEndpointHandlers();
|
||||||
|
log_debugcpp("Reloaded endpoint handlers");
|
||||||
|
|
||||||
osh->setEndpointHandlers(ephs);
|
|
||||||
//INIT FRONT
|
//INIT FRONT
|
||||||
QScopedPointer<QApplication> app(createApplication(argc, argv));
|
QScopedPointer<QApplication> app(createApplication(argc, argv));
|
||||||
MainWindow window = MainWindow(ephs);
|
|
||||||
//window.setEndpointHandlers(ephs);
|
MainWindow window = MainWindow();
|
||||||
app->setStyle("windowsvista");
|
//window.setSizePolicy(QSizePolicy::Fixed, QSizePolicy::QSizePolicy::MinimumExpanding)
|
||||||
window.show();
|
QApplication::setQuitOnLastWindowClosed(false);
|
||||||
|
|
||||||
|
DarkModeEventFilter* darkMode = new DarkModeEventFilter();
|
||||||
|
QAbstractEventDispatcher::instance()->installNativeEventFilter(darkMode);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* QFile styleFile(":/assets/style.qss");
|
||||||
|
* styleFile.open(QFile::ReadOnly);
|
||||||
|
* QString styleSheet { QLatin1String(styleFile.readAll()) };
|
||||||
|
*/
|
||||||
|
|
||||||
return app->exec();
|
return app->exec();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
231
src/settings.cpp
Normal file
231
src/settings.cpp
Normal file
|
|
@ -0,0 +1,231 @@
|
||||||
|
#include "settings.h"
|
||||||
|
#include "msinclude.h"
|
||||||
|
|
||||||
|
namespace ini {
|
||||||
|
|
||||||
|
wchar_t* Utf8toUtf16(const char* str, uint64_t* size = nullptr) {
|
||||||
|
if(!str || str[0] == '\0') return nullptr;
|
||||||
|
int sizeNeeded = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0);
|
||||||
|
if(size) *size = sizeNeeded;
|
||||||
|
wchar_t* utf16 = (wchar_t*)calloc(sizeNeeded, sizeof(wchar_t));
|
||||||
|
MultiByteToWideChar(CP_UTF8, 0, str, -1, utf16, sizeNeeded);
|
||||||
|
return utf16;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
UserSettings::UserSettings(char* textContents) {
|
||||||
|
//Parsing values
|
||||||
|
bool isCRLF = false;
|
||||||
|
char *curLine = textContents;
|
||||||
|
char *separator = nullptr, *key = nullptr, *value = nullptr;
|
||||||
|
while(curLine) {
|
||||||
|
char* nextLine = strchr(curLine, '\n');
|
||||||
|
if(nextLine == curLine + 1 || nextLine == curLine + 2)
|
||||||
|
goto nextIteration;
|
||||||
|
if (nextLine && (isCRLF || *(nextLine - 1) == '\r')) {
|
||||||
|
isCRLF = true;
|
||||||
|
*(nextLine - 1) = '\0';
|
||||||
|
} else if (nextLine) *nextLine = '\0'; // temporarily terminate the current line
|
||||||
|
log_debugcpp("[SET] curLine: " + std::string(curLine) + " ");
|
||||||
|
|
||||||
|
separator = strchr(curLine, '=');
|
||||||
|
if(!separator)
|
||||||
|
goto nextIteration;
|
||||||
|
*separator = '\0';
|
||||||
|
key = trimAndAllocate(curLine);
|
||||||
|
value = trimAndAllocate(separator + 1);
|
||||||
|
values.try_emplace(key, value);
|
||||||
|
log_debugcpp("[SET] ini Map size: " + std::to_string(values.size()));
|
||||||
|
*separator = '=';
|
||||||
|
|
||||||
|
nextIteration:
|
||||||
|
if (nextLine) { // then restore newline-char, just to be tidy
|
||||||
|
if (isCRLF)
|
||||||
|
*(nextLine - 1) = '\r';
|
||||||
|
else *nextLine = '\n';
|
||||||
|
}
|
||||||
|
curLine = nextLine ? (nextLine + 1) : NULL;
|
||||||
|
}
|
||||||
|
free(textContents);
|
||||||
|
}
|
||||||
|
|
||||||
|
char* const UserSettings::getValue(char* key, uint64_t len) {
|
||||||
|
if (auto search = values.find(key); search != values.end())
|
||||||
|
return (char* const) search->second;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UserSettings::setValue(char* key, char* value, uint64_t valueSize, uint64_t keySize) {
|
||||||
|
char *newValue, *newKey;
|
||||||
|
if (auto search = values.find(key); search != values.end()) {
|
||||||
|
if(!(strcmp(value, search->second))) return;
|
||||||
|
newValue = (char*)calloc(valueSize, sizeof(char));
|
||||||
|
if (!(search->second == pos || search->second == neg)) {
|
||||||
|
free(search->second);
|
||||||
|
}
|
||||||
|
search->second = newValue;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
newValue = (char*)calloc(valueSize, sizeof(char));
|
||||||
|
newKey = (char*)calloc(keySize, sizeof(char));
|
||||||
|
values.insert(std::make_pair(newKey, newValue));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UserSettings::setValue(char* key, bool value, uint64_t keySize) {
|
||||||
|
char *newKey;
|
||||||
|
log_debugcpp("[SET] Pos value: " + std::to_string((intptr_t)pos));
|
||||||
|
log_debugcpp("[SET] Neg value: " + std::to_string((intptr_t)neg));
|
||||||
|
if (auto search = values.find(key); search != values.end()) {
|
||||||
|
log_debugcpp("[SET] Previous value: " + std::to_string((intptr_t)values[key]));
|
||||||
|
if (!(search->second == pos || search->second == neg)) {
|
||||||
|
free(search->second);
|
||||||
|
}
|
||||||
|
if (value)
|
||||||
|
search->second = pos;
|
||||||
|
else search->second = neg;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
newKey = (char*)calloc(keySize, sizeof(char));
|
||||||
|
memcpy(newKey, key, keySize * sizeof(char));
|
||||||
|
values.insert(std::make_pair(newKey, value ? pos : neg));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UserSettings::save(const char* path) {
|
||||||
|
if(!path) return false;
|
||||||
|
uint64_t convertedPathSize = 0;
|
||||||
|
wchar_t* utf16Path = Utf8toUtf16(path, &convertedPathSize);
|
||||||
|
if(!utf16Path) return false;
|
||||||
|
|
||||||
|
#define releaseBeforeReturn() do { \
|
||||||
|
CloseHandle(settingsHandle); \
|
||||||
|
settingsHandle = nullptr; \
|
||||||
|
free(utf16Path); \
|
||||||
|
free(text); \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
//We initially reserve 1024B for flushing. If storage is exceeded, more same-size chunks are allocated
|
||||||
|
const uint64_t chunkSize = 1024;
|
||||||
|
char* text = (char*)calloc(chunkSize, sizeof(char));
|
||||||
|
uint64_t mapSize = values.size();
|
||||||
|
uint64_t chunks = 1;
|
||||||
|
uint64_t keySize = 0, valueSize = 0, totalSize = 0, previousStepSize = 0;
|
||||||
|
//for(std::pair<char*, char*> entry : values) {
|
||||||
|
std::unordered_map<char*, char*, Djb12Hasher, StrcmpEqual>::iterator it;
|
||||||
|
for (it = values.begin(); it != values.end(); it++) {
|
||||||
|
keySize = strlen(it->first);
|
||||||
|
valueSize = strlen(it->second);
|
||||||
|
totalSize += valueSize + keySize + (it == values.begin() ? 1 : 2); //newline and separator
|
||||||
|
|
||||||
|
if(totalSize > (chunkSize * chunks)) {
|
||||||
|
text = (char*)realloc(text, (++chunks * chunkSize));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(it != values.begin())
|
||||||
|
memcpy(text + previousStepSize++, "\n", sizeof(char));
|
||||||
|
memcpy(text + previousStepSize, it->first, sizeof(char) * keySize);
|
||||||
|
memcpy(text + previousStepSize + keySize, "=", sizeof(char));
|
||||||
|
memcpy(text + previousStepSize + 1 + keySize, it->second, sizeof(char) * valueSize);
|
||||||
|
|
||||||
|
previousStepSize = totalSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
HANDLE settingsHandle = nullptr;
|
||||||
|
settingsHandle = CreateFile2(
|
||||||
|
utf16Path,
|
||||||
|
GENERIC_READ | GENERIC_WRITE,
|
||||||
|
0,
|
||||||
|
CREATE_ALWAYS,
|
||||||
|
NULL);
|
||||||
|
if(settingsHandle == INVALID_HANDLE_VALUE) {
|
||||||
|
log_debugcpp("[SET] Can't save to file: " + std::to_string(GetLastError()));
|
||||||
|
releaseBeforeReturn();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD bytesWritten;
|
||||||
|
BOOL writeSuccess = WriteFile(
|
||||||
|
settingsHandle,
|
||||||
|
text,
|
||||||
|
totalSize,
|
||||||
|
&bytesWritten,
|
||||||
|
nullptr
|
||||||
|
);
|
||||||
|
|
||||||
|
releaseBeforeReturn();
|
||||||
|
if (writeSuccess == TRUE) return true;
|
||||||
|
else return false;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
#undef releaseBeforeReturn
|
||||||
|
}
|
||||||
|
|
||||||
|
UserSettings::~UserSettings() {
|
||||||
|
//if(textContents) free(textContents);
|
||||||
|
for(std::pair<char*, char*> entry : values) {
|
||||||
|
free(entry.first);
|
||||||
|
if (!(entry.second == pos || entry.second == neg))
|
||||||
|
free(entry.second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UserSettings* UserSettings::createSettings(const char* path, bool create) {
|
||||||
|
if(!path) return nullptr;
|
||||||
|
wchar_t* utf16Path = Utf8toUtf16(path);
|
||||||
|
if(!utf16Path) return nullptr;
|
||||||
|
|
||||||
|
#define releaseBeforeReturn() do { \
|
||||||
|
CloseHandle(settingsHandle); \
|
||||||
|
settingsHandle = nullptr; \
|
||||||
|
free(utf16Path); \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
char* textContents;
|
||||||
|
HANDLE settingsHandle = nullptr;
|
||||||
|
settingsHandle = CreateFile2(
|
||||||
|
utf16Path,
|
||||||
|
GENERIC_READ | GENERIC_WRITE,
|
||||||
|
0,
|
||||||
|
(create ? OPEN_ALWAYS : OPEN_EXISTING),
|
||||||
|
NULL);
|
||||||
|
if(settingsHandle == INVALID_HANDLE_VALUE) {
|
||||||
|
std::string createString = std::string(create ? (char*)"create" : (char*)"open");
|
||||||
|
log_debugcpp("[SET] Can't create settings file: " + std::to_string(GetLastError()));
|
||||||
|
log_debugcpp("[SET] Can't " + createString + \
|
||||||
|
" settings file on: " + std::string(path) + \
|
||||||
|
", error: " + std::to_string(GetLastError()));
|
||||||
|
releaseBeforeReturn();
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Calculating file size and reading file
|
||||||
|
uint64_t fileSize;
|
||||||
|
LARGE_INTEGER fileSizeStruct;
|
||||||
|
if(!GetFileSizeEx(settingsHandle, &fileSizeStruct)) {
|
||||||
|
releaseBeforeReturn();
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
fileSize = fileSizeStruct.QuadPart;
|
||||||
|
|
||||||
|
uint32_t bytesRead = 0;
|
||||||
|
uint64_t textContentsSize = fileSize + 1;
|
||||||
|
textContents = (char*)calloc(textContentsSize, sizeof(char));
|
||||||
|
if (ReadFile(settingsHandle, textContents, fileSize,
|
||||||
|
(LPDWORD)&bytesRead, NULL) != TRUE) {
|
||||||
|
releaseBeforeReturn();
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
releaseBeforeReturn();
|
||||||
|
return new UserSettings(textContents);
|
||||||
|
|
||||||
|
//textContents.assign(tempTextContents);
|
||||||
|
//free(tempTextContents);
|
||||||
|
#undef releaseBeforeReturn
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
71
src/settings.h
Normal file
71
src/settings.h
Normal file
|
|
@ -0,0 +1,71 @@
|
||||||
|
#pragma once
|
||||||
|
#include "global.h"
|
||||||
|
|
||||||
|
namespace ini {
|
||||||
|
|
||||||
|
//Trims spaces, LF and CRLF
|
||||||
|
static inline char* trimAndAllocate(const char* in, uint64_t len = 0) {
|
||||||
|
if (!in) return nullptr;
|
||||||
|
|
||||||
|
uint64_t startingPos = 0, lastPos = 0;
|
||||||
|
bool foundStart = false;
|
||||||
|
for(int i = 0; ;i++) {
|
||||||
|
char c = in[i];
|
||||||
|
if ((len > 0 && startingPos == (len - 1)) || (len > 0 && lastPos == (len - 1))) return nullptr;
|
||||||
|
if ((c != ' ' || c != '\r' || c != '\n') && !foundStart) {
|
||||||
|
foundStart = true;
|
||||||
|
lastPos = startingPos;
|
||||||
|
}
|
||||||
|
if (foundStart && (c == ' ' || c == '\r' || c == '\n')) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(!foundStart)
|
||||||
|
startingPos++;
|
||||||
|
else lastPos++;
|
||||||
|
}
|
||||||
|
if(!(lastPos - startingPos)) return nullptr;
|
||||||
|
|
||||||
|
char* trimmedString = (char*)calloc(lastPos - startingPos + 1, sizeof(char));
|
||||||
|
memcpy(trimmedString, in + startingPos, lastPos - startingPos);
|
||||||
|
return trimmedString;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Djb12Hasher {
|
||||||
|
size_t operator()(char* str) const {
|
||||||
|
unsigned long hash = 5381;
|
||||||
|
int c;
|
||||||
|
|
||||||
|
while (c = *str++)
|
||||||
|
hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
|
||||||
|
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct StrcmpEqual {
|
||||||
|
bool operator()(char* key1, char* key2) const {
|
||||||
|
return (!strcmp(key1, key2));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class UserSettings {
|
||||||
|
|
||||||
|
public:
|
||||||
|
static UserSettings* createSettings(const char* path = nullptr, bool create = false);
|
||||||
|
~UserSettings();
|
||||||
|
|
||||||
|
char* const getValue(char* key, uint64_t len = 0);
|
||||||
|
void setValue(char* key, char* value, uint64_t valueSize, uint64_t keySize); //'\0' included
|
||||||
|
void setValue(char* key, bool value, uint64_t keySize); //'\0' included
|
||||||
|
|
||||||
|
bool save(const char* path);
|
||||||
|
protected:
|
||||||
|
|
||||||
|
private:
|
||||||
|
UserSettings(char* text = nullptr);
|
||||||
|
std::unordered_map<char*, char*, Djb12Hasher, StrcmpEqual> values;
|
||||||
|
char* pos = "true";
|
||||||
|
char* neg = "false";
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue