aboutsummaryrefslogtreecommitdiff
path: root/Src/Winamp/dwm.cpp
diff options
context:
space:
mode:
authorJef <jef@targetspot.com>2024-09-24 08:54:57 -0400
committerJef <jef@targetspot.com>2024-09-24 08:54:57 -0400
commit20d28e80a5c861a9d5f449ea911ab75b4f37ad0d (patch)
tree12f17f78986871dd2cfb0a56e5e93b545c1ae0d0 /Src/Winamp/dwm.cpp
parent537bcbc86291b32fc04ae4133ce4d7cac8ebe9a7 (diff)
downloadwinamp-20d28e80a5c861a9d5f449ea911ab75b4f37ad0d.tar.gz
Initial community commit
Diffstat (limited to 'Src/Winamp/dwm.cpp')
-rw-r--r--Src/Winamp/dwm.cpp386
1 files changed, 386 insertions, 0 deletions
diff --git a/Src/Winamp/dwm.cpp b/Src/Winamp/dwm.cpp
new file mode 100644
index 00000000..03d94c52
--- /dev/null
+++ b/Src/Winamp/dwm.cpp
@@ -0,0 +1,386 @@
+#include "main.h"
+#include "config.h"
+#include "wintheme.h"
+#include <shobjidl.h>
+#include <tataki/canvas/bltcanvas.h>
+#include <tataki/bitmap/bitmap.h>
+#include "../Agave/Language/api_language.h"
+
+typedef HRESULT(WINAPI *DWMREGISTERTHUMBNAIL)(HWND hwndDestination, HWND hwndSource, void **phThumbnailId);
+typedef HRESULT(WINAPI *DWMUPATETHUMBNAILPROPERTIES)(void* hThumbnailId, void* ptnProperties);
+typedef HRESULT(WINAPI *DWMUNREGISTERTHUMBNAIL)(void *hThumbnailId);
+typedef HRESULT(WINAPI *DWMSETWINDOWATTRIBUTE)(HWND hwnd, DWORD dwAttribute, LPCVOID pvAttribute, DWORD cbAttribute);
+typedef HRESULT (WINAPI *DWMENABLEMMCSS)(BOOL fEnableMMCSS);
+typedef HRESULT (WINAPI *DWMSETICONICTHUMBNAIL)(HWND hwnd, HBITMAP hbmp, DWORD dwSITFlags);
+typedef HRESULT (WINAPI *DWMINVALIDATEICONICBITMAPS)( HWND hwnd);
+typedef HRESULT (WINAPI *DWMSETICONICLIVEPREVIEWBITMAP )(HWND hwnd, HBITMAP hbmp, POINT *pptClient, DWORD dwSITFlags);
+static HMODULE dwmapi;
+static void *thumbnail;
+static DWMREGISTERTHUMBNAIL regThumbnail;
+static DWMUPATETHUMBNAILPROPERTIES updateProp;
+static DWMUNREGISTERTHUMBNAIL unregThumbnail;
+static DWMSETWINDOWATTRIBUTE setWindowAttribute;
+static DWMENABLEMMCSS dwmEnableMMCSS;
+static DWMSETICONICTHUMBNAIL dwmSetIconicThumbnail;
+static DWMINVALIDATEICONICBITMAPS dwmInvalidateIconicBitmaps;
+static DWMSETICONICLIVEPREVIEWBITMAP dwmSetIconicLivePreviewBitmap;
+
+HIMAGELIST toolbarIcons = NULL;
+
+BOOL atti_present=false;
+static bool triedLoad=false;
+static bool LoadDWMApi()
+{
+ if (!triedLoad)
+ {
+ wchar_t gen_win7shell_path[MAX_PATH] = {0};
+ PathCombineW(gen_win7shell_path, PLUGINDIR, L"gen_win7shell.dll");
+ HMODULE gen_win7shell = LoadLibraryW(gen_win7shell_path);
+ if (gen_win7shell)
+ {
+ atti_present=true;
+ FreeLibrary(gen_win7shell);
+ }
+
+ dwmapi = LoadLibraryA("dwmapi.dll");
+
+ regThumbnail = (DWMREGISTERTHUMBNAIL)GetProcAddress(dwmapi, "DwmRegisterThumbnail");
+ updateProp = (DWMUPATETHUMBNAILPROPERTIES)GetProcAddress(dwmapi, "DwmUpdateThumbnailProperties");
+ unregThumbnail = (DWMUNREGISTERTHUMBNAIL)GetProcAddress(dwmapi, "DwmUnregisterThumbnail");
+ setWindowAttribute = (DWMSETWINDOWATTRIBUTE)GetProcAddress(dwmapi, "DwmSetWindowAttribute");
+ dwmEnableMMCSS = (DWMENABLEMMCSS)GetProcAddress(dwmapi, "DwmEnableMMCSS");
+ dwmSetIconicThumbnail = (DWMSETICONICTHUMBNAIL)GetProcAddress(dwmapi, "DwmSetIconicThumbnail");
+ dwmInvalidateIconicBitmaps = (DWMINVALIDATEICONICBITMAPS)GetProcAddress(dwmapi, "DwmInvalidateIconicBitmaps");
+ dwmSetIconicLivePreviewBitmap = (DWMSETICONICLIVEPREVIEWBITMAP)GetProcAddress(dwmapi, "DwmSetIconicLivePreviewBitmap");
+
+ triedLoad = true;
+ }
+
+ return dwmapi && regThumbnail && updateProp && unregThumbnail && setWindowAttribute && dwmEnableMMCSS;
+}
+
+bool LoadToolbarIcons()
+{
+ //toolbarIcons already loaded
+ if (toolbarIcons != NULL)
+ {
+ return true;
+ }
+
+ //load toolbarIcons
+ toolbarIcons = ImageList_Create(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), ILC_COLOR32, 5, 0);
+ if (toolbarIcons == NULL)
+ return false;
+
+ for (int i = 0; i < 5; i++)
+ {
+ HICON hIcon = LoadIconW(hMainInstance, MAKEINTRESOURCE(IDI_TBICON1+i));
+ if (hIcon != NULL)
+ ImageList_AddIcon(toolbarIcons, hIcon);
+ // no need to call DestroyIcon(..) if using LoadIcon(..)
+ // as the OS will free things anyway - might be cause of
+ // the random button disappearing issue...?
+ //DestroyIcon(hIcon);
+ }
+
+ return true;
+}
+
+static BOOL taskbar_inited = FALSE;
+void OnTaskbarButtonCreated(BOOL force)
+{
+ if (pTaskbar3 || (SUCCEEDED(CoCreateInstance(CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER,
+ IID_PPV_ARGS(&pTaskbar3))) && pTaskbar3))
+ {
+ if (force)
+ {
+ taskbar_inited = TRUE;
+ pTaskbar3->HrInit();
+ }
+ if (taskbar_inited)
+ {
+ RegisterThumbnailTab(IsWindow(g_dialog_box_parent) ? g_dialog_box_parent : hMainWindow);
+ }
+ }
+}
+
+void UnregisterThumbnailTab(HWND hWnd)
+{
+ if (LoadDWMApi() && !atti_present)
+ {
+ if (!IsVistaOrLower() && IsWindow(hWnd) && pTaskbar3 != NULL)
+ {
+ if (taskbar_inited)
+ pTaskbar3->UnregisterTab(hWnd);
+ }
+ }
+}
+
+static void addToolbarButtons(HWND hWnd, BOOL update)
+{
+ THUMBBUTTON thbButtons[5];
+ DWORD dwMask = THB_BITMAP | THB_TOOLTIP;
+
+ thbButtons[0].dwMask = (THUMBBUTTONMASK)dwMask;
+ thbButtons[0].iId = 0;
+ thbButtons[0].iBitmap = 0;
+ StringCbCopyW(thbButtons[0].szTip, sizeof(thbButtons[0].szTip), getStringW(IDS_WIN7TOOLBAR_TOOLTIP_PREVIOUS, NULL, 0));
+
+ thbButtons[1].dwMask = (THUMBBUTTONMASK)dwMask;
+ thbButtons[1].iId = 1;
+ thbButtons[1].iBitmap = 1;
+ StringCbCopyW(thbButtons[1].szTip, sizeof(thbButtons[1].szTip), getStringW(IDS_WIN7TOOLBAR_TOOLTIP_PLAY, NULL, 0));
+
+ thbButtons[2].dwMask = (THUMBBUTTONMASK)dwMask;
+ thbButtons[2].iId = 2;
+ thbButtons[2].iBitmap = 2;
+ StringCbCopyW(thbButtons[2].szTip, sizeof(thbButtons[2].szTip), getStringW(IDS_WIN7TOOLBAR_TOOLTIP_PAUSE, NULL, 0));
+
+ thbButtons[3].dwMask = (THUMBBUTTONMASK)dwMask;
+ thbButtons[3].iId = 3;
+ thbButtons[3].iBitmap = 3;
+ StringCbCopyW(thbButtons[3].szTip, sizeof(thbButtons[3].szTip), getStringW(IDS_WIN7TOOLBAR_TOOLTIP_STOP, NULL, 0));
+
+ thbButtons[4].dwMask = (THUMBBUTTONMASK)dwMask;
+ thbButtons[4].iId = 4;
+ thbButtons[4].iBitmap = 4;
+ StringCbCopyW(thbButtons[4].szTip, sizeof(thbButtons[4].szTip), getStringW(IDS_WIN7TOOLBAR_TOOLTIP_NEXT, NULL, 0));
+
+ if (update)
+ pTaskbar3->ThumbBarUpdateButtons(hWnd, ARRAYSIZE(thbButtons), thbButtons);
+ else
+ pTaskbar3->ThumbBarAddButtons(hWnd, ARRAYSIZE(thbButtons), thbButtons);
+}
+
+void RegisterThumbnailTab(HWND hWnd)
+{
+ if (LoadDWMApi() && !atti_present)
+ {
+ if (dwmInvalidateIconicBitmaps) // even if DWM is loaded, this only exists on win7 (NT6.1)
+ dwmInvalidateIconicBitmaps(hMainWindow);
+
+ if (!IsWindow(hWnd))
+ {
+ hWnd = hMainWindow;
+ }
+
+ if (hWnd != hMainWindow)
+ {
+ wchar_t title[512] = {0};
+ GetWindowTextW(hMainWindow, title, sizeof(title));
+ SetWindowTextW(hWnd, title);
+
+#ifdef WIN64
+ HICON hIcon = (HICON)GetClassLongPtr(hMainWindow, GCLP_HICONSM);
+#else
+ HICON hIcon = (HICON)GetClassLong(hMainWindow, GCL_HICONSM);
+#endif
+
+
+ SendMessageW(hWnd, WM_SETICON, (WPARAM)ICON_SMALL, (LPARAM)hIcon);
+ }
+
+ if (IsWindow(hWnd) && IsWindow(hMainWindow))
+ {
+ BOOL dwm_setting = FALSE;
+ setWindowAttribute(hWnd, DWMWA_FORCE_ICONIC_REPRESENTATION, &dwm_setting, sizeof(dwm_setting));
+ setWindowAttribute(hWnd, DWMWA_HAS_ICONIC_BITMAP, &dwm_setting, sizeof(dwm_setting));
+
+ if (!IsVistaOrLower() && pTaskbar3 != NULL)
+ {
+ // shouldn't fail, but there's a case on loading where it can due to timing quirks
+ // so for that we then allow the regsistation to still happen (hence the dup code)
+ HRESULT hr = pTaskbar3->RegisterTab(hWnd, hMainWindow);
+ if (SUCCEEDED(hr))
+ {
+ if (SUCCEEDED(pTaskbar3->SetTabOrder(hWnd, NULL)))
+ {
+ pTaskbar3->SetTabActive(hWnd, hMainWindow, 0);
+
+ if (LoadToolbarIcons())
+ {
+ HRESULT hr = pTaskbar3->ThumbBarSetImageList(hWnd, toolbarIcons);
+ if (SUCCEEDED(hr))
+ {
+ addToolbarButtons(hWnd, false);
+ }
+ }
+ }
+ }
+ else
+ {
+ if (SUCCEEDED(pTaskbar3->SetTabOrder(hWnd, NULL)))
+ {
+ pTaskbar3->SetTabActive(hWnd, hMainWindow, 0);
+
+ if (LoadToolbarIcons())
+ {
+ HRESULT hr = pTaskbar3->ThumbBarSetImageList(hWnd, toolbarIcons);
+ if (SUCCEEDED(hr))
+ {
+ addToolbarButtons(hWnd, false);
+ }
+ }
+ }
+ }
+ }
+
+ if (hWnd != hMainWindow)
+ {
+ dwm_setting = TRUE;
+ setWindowAttribute(hMainWindow, DWMWA_FORCE_ICONIC_REPRESENTATION, &dwm_setting, sizeof(dwm_setting));
+ setWindowAttribute(hMainWindow, DWMWA_HAS_ICONIC_BITMAP, &dwm_setting, sizeof(dwm_setting));
+ }
+ }
+ }
+}
+
+void DisableVistaPreview()
+{
+ if (LoadDWMApi())
+ {
+ BOOL blah=TRUE;
+ setWindowAttribute(hMainWindow, DWMWA_FORCE_ICONIC_REPRESENTATION, &blah, sizeof(blah));
+ setWindowAttribute(hMainWindow, DWMWA_HAS_ICONIC_BITMAP, &blah, sizeof(blah));
+ }
+}
+
+static bool done_the_dance=false;
+void DoTheVistaVideoDance()
+{
+ if (!done_the_dance && LoadDWMApi())
+ {
+ dwmEnableMMCSS(TRUE); // the magic "make my program not suck" function
+ /* TODO:
+ DWM_PRESENT_PARAMETERS dpp;
+ memset(&dpp, 0, sizeof(dpp));
+ dpp.cbSize = sizeof(dpp);
+ dpp.fQueue = true;
+ dpp.cBuffer = 8;
+ dpp.fUseSourceRate = false;
+ dpp.cRefreshesPerFrame = 1;
+ dpp.eSampling = DWM_SOURCE_FRAME_SAMPLING_POINT;
+ HRESULT hr = DwmSetPresentParameters(hWnd, &dpp);
+ */
+ // TODO also, unrelated, but check out AvSetMmThreadCharacteristics sometime.
+ }
+ done_the_dance = true;
+}
+
+static void Adjust(int bmpw, int bmph, RECT &r)
+{
+ // maintain 'square' stretching
+ int w = r.right - r.left;
+ int h = r.bottom - r.top;
+ double aspX = (double)(w)/(double)bmpw;
+ double aspY = (double)(h)/(double)bmph;
+ double asp = min(aspX, aspY);
+ int newW = (int)(bmpw*asp);
+ int newH = (int)(bmph*asp);
+ r.left = (w - newW)/2;
+ r.top = (h - newH)/2;
+ r.right = r.left + newW;
+ r.bottom = r.top + newH;
+}
+
+void RefreshIconicThumbnail()
+{
+ if (LoadDWMApi() && !atti_present)
+ {
+ if (dwmInvalidateIconicBitmaps) // even if DWM is loaded, this only exists on win7 (NT6.1)
+ dwmInvalidateIconicBitmaps(hMainWindow);
+ }
+}
+
+void OnIconicThumbnail(int width, int height)
+{
+ static BltCanvas *iconic_thumbnail_bitmap=0;
+
+ HWND hWnd = g_dialog_box_parent?g_dialog_box_parent:hMainWindow;
+
+ RECT client_size;
+ GetClientRect(hWnd, &client_size);
+
+ if (!iconic_thumbnail_bitmap)
+ {
+ iconic_thumbnail_bitmap = new BltCanvas(client_size.right, client_size.bottom, hMainWindow);
+ }
+ else
+ {
+ iconic_thumbnail_bitmap->DestructiveResize(client_size.right, client_size.bottom);
+ }
+
+ SendMessageW(hWnd, WM_PRINTCLIENT, (WPARAM) iconic_thumbnail_bitmap->getHDC(), PRF_CHILDREN | PRF_CLIENT | /*PRF_ERASEBKGND |*/ PRF_NONCLIENT /*| PRF_OWNED*/);
+
+ void *bits=0;
+ BITMAPINFO bmi = {0};
+ bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ bmi.bmiHeader.biWidth = width;
+ bmi.bmiHeader.biHeight = -height;
+ bmi.bmiHeader.biPlanes = 1;
+ bmi.bmiHeader.biBitCount = 32;
+ bmi.bmiHeader.biCompression = BI_RGB;
+ HBITMAP hbmp = CreateDIBSection(iconic_thumbnail_bitmap->getHDC(), &bmi, DIB_RGB_COLORS, &bits, NULL, 0);
+
+ if (hbmp)
+ {
+ BltCanvas resizedBitmap(hbmp);
+ int x=0, y=0;
+
+ RECT dest;
+ dest.left = x;
+ dest.top = y;
+ dest.right = width;
+ dest.bottom = height;
+ resizedBitmap.drawRect(&dest, 1, 0);
+ Adjust(client_size.right, client_size.bottom, dest);
+ iconic_thumbnail_bitmap->stretchToRectAlpha(&resizedBitmap, &client_size, &dest);
+ dwmSetIconicThumbnail(hMainWindow, hbmp, 0);
+ }
+}
+
+void OnThumbnailPreview()
+{
+ static BltCanvas *thumbnail_preview_bitmap=0;
+
+ HWND hWnd = g_dialog_box_parent?g_dialog_box_parent:hMainWindow;
+
+ RECT client_size;
+ GetClientRect(hWnd, &client_size);
+
+ if (!thumbnail_preview_bitmap)
+ {
+ thumbnail_preview_bitmap = new BltCanvas(client_size.right, client_size.bottom, hWnd);
+ }
+ else
+ {
+ thumbnail_preview_bitmap->DestructiveResize(client_size.right, client_size.bottom);
+ }
+
+ SendMessageW(hWnd, WM_PRINT, (WPARAM) thumbnail_preview_bitmap->getHDC(), PRF_CHILDREN | PRF_CLIENT | PRF_ERASEBKGND | PRF_NONCLIENT /*| PRF_OWNED*/);
+
+ void *bits=0;
+ BITMAPINFO bmi = {0};
+ bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ bmi.bmiHeader.biWidth = client_size.right - client_size.left;
+ bmi.bmiHeader.biHeight = client_size.top - client_size.bottom;
+ bmi.bmiHeader.biPlanes = 1;
+ bmi.bmiHeader.biBitCount = 32;
+ bmi.bmiHeader.biCompression = BI_RGB;
+ HBITMAP hbmp = CreateDIBSection(thumbnail_preview_bitmap->getHDC(), &bmi, DIB_RGB_COLORS, &bits, NULL, 0);
+
+ if (hbmp)
+ {
+ POINT offset;
+ offset.x = client_size.left;
+ offset.y = client_size.top;
+ if (dwmSetIconicLivePreviewBitmap(hWnd, hbmp, &offset, 1) == S_OK)
+ {
+ MessageBoxA(NULL, "winamp/live", "winamp/live", MB_OK);
+ }
+ else
+ {
+ MessageBoxA(NULL, "winamp/no live", "winamp/no live", MB_OK);
+ }
+ }
+} \ No newline at end of file