mirror of
https://github.com/kunkundi/crossdesk.git
synced 2026-11-11 02:06:38 +08:00
[feat] separate Windows taskbar groups for main and remote control windows, refs #148
This commit is contained in:
@@ -62,6 +62,7 @@
|
||||
#include "platform/windows/gui/shutdown_session_guard.h"
|
||||
#include "platform/windows/gui/tray/win_tray.h"
|
||||
#include "platform/windows/gui/window_icons.h"
|
||||
#include "platform/windows/gui/window_taskbar.h"
|
||||
#include "platform/windows/service/autostart_control.h"
|
||||
#include "platform/windows/service/interactive_desktop.h"
|
||||
#include "platform/windows/service/unattended_config.h"
|
||||
@@ -3882,6 +3883,11 @@ void GuiApplication::SyncStreamWindow() {
|
||||
if (!ui_->stream) {
|
||||
return;
|
||||
}
|
||||
// Assign the window's taskbar group before its first show or restoration.
|
||||
// Reapply when Slint recreates the HWND; the helper skips configured handles.
|
||||
#if _WIN32
|
||||
ConfigureWindowsStreamTaskbar((*ui_->stream)->window().win32_hwnd());
|
||||
#endif
|
||||
// A wall takeover hides an existing stream window without destroying it.
|
||||
// Opening a recent device must also restore that existing window.
|
||||
if (need_to_create_stream_window_) {
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
#include "window_taskbar.h"
|
||||
|
||||
#include <commctrl.h>
|
||||
#include <propkey.h>
|
||||
#include <propsys.h>
|
||||
#include <propvarutil.h>
|
||||
#include <shellapi.h>
|
||||
#include <wrl/client.h>
|
||||
|
||||
namespace crossdesk {
|
||||
namespace {
|
||||
|
||||
constexpr wchar_t kStreamAppId[] = L"CrossDesk.RemoteControl";
|
||||
constexpr UINT_PTR kTaskbarSubclassId = 1;
|
||||
|
||||
void ClearTaskbarProperties(IPropertyStore* properties) {
|
||||
const PROPVARIANT empty{};
|
||||
properties->SetValue(PKEY_AppUserModel_ID, empty);
|
||||
properties->SetValue(PKEY_AppUserModel_PreventPinning, empty);
|
||||
}
|
||||
|
||||
LRESULT CALLBACK TaskbarSubclassProc(HWND window, UINT message, WPARAM wparam,
|
||||
LPARAM lparam, UINT_PTR subclass_id,
|
||||
DWORD_PTR reference_data) {
|
||||
auto* properties = reinterpret_cast<IPropertyStore*>(reference_data);
|
||||
if (message == WM_DESTROY) {
|
||||
// Window property stores require explicit clearing before destruction.
|
||||
ClearTaskbarProperties(properties);
|
||||
}
|
||||
if (message == WM_NCDESTROY) {
|
||||
RemoveWindowSubclass(window, TaskbarSubclassProc, subclass_id);
|
||||
properties->Release();
|
||||
}
|
||||
return DefSubclassProc(window, message, wparam, lparam);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool ConfigureWindowsStreamTaskbar(HWND window) {
|
||||
if (!window || !IsWindow(window)) return false;
|
||||
DWORD_PTR existing = 0;
|
||||
if (GetWindowSubclass(window, TaskbarSubclassProc, kTaskbarSubclassId,
|
||||
&existing)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
Microsoft::WRL::ComPtr<IPropertyStore> properties;
|
||||
if (FAILED(SHGetPropertyStoreForWindow(window, IID_PPV_ARGS(&properties)))) {
|
||||
return false;
|
||||
}
|
||||
if (!SetWindowSubclass(window, TaskbarSubclassProc, kTaskbarSubclassId,
|
||||
reinterpret_cast<DWORD_PTR>(properties.Get()))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// A live session cannot be recreated by launching the executable. Keep
|
||||
// pinning on the main application's button instead of creating a shortcut
|
||||
// that claims to reopen a remote session but only opens the connection page.
|
||||
PROPVARIANT prevent_pinning{};
|
||||
InitPropVariantFromBoolean(TRUE, &prevent_pinning);
|
||||
HRESULT result = properties->SetValue(PKEY_AppUserModel_PreventPinning,
|
||||
prevent_pinning);
|
||||
PROPVARIANT app_id{};
|
||||
if (SUCCEEDED(result)) result = InitPropVariantFromString(kStreamAppId, &app_id);
|
||||
if (SUCCEEDED(result)) result = properties->SetValue(PKEY_AppUserModel_ID, app_id);
|
||||
PropVariantClear(&app_id);
|
||||
if (FAILED(result)) {
|
||||
ClearTaskbarProperties(properties.Get());
|
||||
RemoveWindowSubclass(window, TaskbarSubclassProc, kTaskbarSubclassId);
|
||||
return false;
|
||||
}
|
||||
// SetValue applies immediately; this store does not require Commit(). The
|
||||
// subclass retains the store until this HWND is destroyed, even if Slint
|
||||
// later creates a new native window for the same component.
|
||||
properties.Detach();
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace crossdesk
|
||||
@@ -0,0 +1,15 @@
|
||||
#ifndef CROSSDESK_WINDOWS_WINDOW_TASKBAR_H_
|
||||
#define CROSSDESK_WINDOWS_WINDOW_TASKBAR_H_
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
namespace crossdesk {
|
||||
|
||||
// Give the remote control window its own taskbar group, leaving the main
|
||||
// window's shortcut grouping intact. Call on the UI thread before showing a
|
||||
// native window; repeated calls are harmless, including after hide/show.
|
||||
bool ConfigureWindowsStreamTaskbar(HWND window);
|
||||
|
||||
} // namespace crossdesk
|
||||
|
||||
#endif // CROSSDESK_WINDOWS_WINDOW_TASKBAR_H_
|
||||
@@ -686,6 +686,7 @@ function setup_targets()
|
||||
add_files("apps/desktop/src/platform/windows/gui/tray/win_tray.cpp",
|
||||
"apps/desktop/src/platform/windows/gui/slint_backend.cpp",
|
||||
"apps/desktop/src/platform/windows/gui/window_icons.cpp",
|
||||
"apps/desktop/src/platform/windows/gui/window_taskbar.cpp",
|
||||
"apps/desktop/src/platform/windows/gui/shutdown_session_guard.cpp",
|
||||
"apps/desktop/src/platform/windows/gui/slint_renderer_probe.cpp",
|
||||
"apps/desktop/src/platform/common/gui/opengl_video_renderer.cpp",
|
||||
|
||||
Reference in New Issue
Block a user