99namespace {
1010constexpr const wchar_t * kWndClass = L" TenBoxFloatingToolbar" ;
1111
12- constexpr int kBarHeight = 56 ;
12+ constexpr int kBarHeight = 62 ;
1313constexpr int kBtnH = 38 ;
14- constexpr int kPad = 12 ;
15- constexpr int kGripW = 52 ;
14+ constexpr int kPad = 10 ;
15+ constexpr int kGripW = 56 ;
1616constexpr int kVmBtnMinW = 280 ;
1717constexpr int kIconBtnW = 40 ;
1818constexpr int kRightPadding = 14 ;
1919constexpr UINT_PTR kHideTimerId = 1 ;
20- constexpr DWORD kAutoHideMs = 3000 ;
20+ constexpr DWORD kAutoHideMs = 1500 ;
2121
22- enum BtnId { kBtnVm = 301 , kBtnDpi = 302 , kBtnPin = 303 , kBtnExit = 304 };
22+ enum BtnId { kBtnDrag = 300 , kBtnVm = 301 , kBtnDpi = 302 , kBtnPin = 303 , kBtnExit = 304 };
2323}
2424
2525HWND FloatingToolbar::Create (HINSTANCE hinst, HWND fullscreen_hwnd) {
@@ -55,11 +55,11 @@ HWND FloatingToolbar::Create(HINSTANCE hinst, HWND fullscreen_hwnd) {
5555
5656 // Drag handle — TenBox icon
5757 st->drag_handle = CreateWindowExW (0 , WC_STATICW , L" " ,
58- WS_CHILD | WS_VISIBLE | SS_ICON | SS_CENTERIMAGE ,
59- 0 , 0 , 0 , 0 , hwnd, nullptr , hinst, nullptr );
58+ WS_CHILD | WS_VISIBLE | SS_ICON | SS_CENTERIMAGE | SS_NOTIFY ,
59+ 0 , 0 , 0 , 0 , hwnd, reinterpret_cast < HMENU >( kBtnDrag ) , hinst, nullptr );
6060 {
6161 HICON icon = static_cast <HICON >(LoadImageW (hinst, MAKEINTRESOURCEW (IDI_APP_ICON ),
62- IMAGE_ICON , 48 , 48 , LR_SHARED ));
62+ IMAGE_ICON , 54 , 54 , LR_SHARED ));
6363 SendMessageW (st->drag_handle , STM_SETICON , reinterpret_cast <WPARAM >(icon), 0 );
6464 }
6565
@@ -121,6 +121,8 @@ HWND FloatingToolbar::Create(HINSTANCE hinst, HWND fullscreen_hwnd) {
121121 AddTool (st->btn_exit , L" ✕ 退出全屏 (或长按 ESC 2 秒)" );
122122 AddTool (st->btn_vm , L" 切换虚拟机" );
123123
124+ AddTool (st->drag_handle , L" 可拖拽至窗口边缘以吸附" );
125+
124126 return hwnd;
125127}
126128
@@ -181,7 +183,7 @@ void FloatingToolbar::SetVmInfo(HWND hwnd, const std::string& current_id, const
181183 if (new_w < 420 ) new_w = 420 ;
182184 st->tb_width = new_w;
183185
184- SetWindowPos (hwnd, nullptr , 0 , 0 , st->tb_width , kBarHeight , SWP_NOMOVE | SWP_NOZORDER );
186+ SetWindowPos (hwnd, nullptr , 0 , 0 , st->tb_width , kBarHeight , SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE );
185187 LayoutButtons (hwnd);
186188 UpdatePosition (hwnd);
187189 InvalidateRect (hwnd, nullptr , TRUE ); // force full redraw, erase background
@@ -196,9 +198,11 @@ void FloatingToolbar::SetDpiZoomState(HWND hwnd, bool enabled) {
196198}
197199
198200void FloatingToolbar::OnFullscreenDeactivated (HWND hwnd) {
199- auto * st = GetState (hwnd);
200- if (!st) return ;
201- if (!st->pinned ) HideBar (hwnd);
201+ ShowWindow (hwnd, SW_HIDE );
202+ }
203+
204+ void FloatingToolbar::OnFullscreenActivated (HWND hwnd) {
205+ ShowBar (hwnd);
202206}
203207
204208FloatingToolbar::ToolbarState* FloatingToolbar::GetState (HWND hwnd) {
@@ -226,7 +230,7 @@ void FloatingToolbar::ShowBar(HWND hwnd) {
226230 st->tab_mode = false ;
227231 // Restore full size
228232 SetWindowPos (hwnd, HWND_TOPMOST , 0 , 0 , st->tb_width , st->tb_height ,
229- SWP_NOMOVE | SWP_NOZORDER | SWP_SHOWWINDOW );
233+ SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_SHOWWINDOW );
230234 InvalidateRect (hwnd, nullptr , TRUE );
231235 // Show all children
232236 ShowWindow (st->drag_handle , SW_SHOW );
@@ -293,9 +297,10 @@ void FloatingToolbar::LayoutButtons(HWND hwnd) {
293297 rx -= kIconBtnW + 2 ; MoveWindow (st->btn_pin , rx, y, kIconBtnW , kBtnH , FALSE );
294298 rx -= kIconBtnW + 2 ; MoveWindow (st->btn_dpi , rx, y, kIconBtnW , kBtnH , FALSE );
295299
296- // Drag handle at left
300+ // Drag handle at left — taller to fill more vertical space
297301 int lx = kPad ;
298- MoveWindow (st->drag_handle , lx, y, kGripW , kBtnH , FALSE );
302+ int grip_h = kBarHeight - 10 ;
303+ MoveWindow (st->drag_handle , lx, 5 , kGripW , grip_h, FALSE );
299304 lx += kGripW + 2 ;
300305
301306 // VM button fills space between drag handle and icon buttons
@@ -304,7 +309,7 @@ void FloatingToolbar::LayoutButtons(HWND hwnd) {
304309 MoveWindow (st->btn_vm , lx, y, vm_w, kBtnH , FALSE );
305310
306311 st->tb_height = kBarHeight ;
307- SetWindowPos (hwnd, nullptr , 0 , 0 , st->tb_width , kBarHeight , SWP_NOMOVE | SWP_NOZORDER );
312+ SetWindowPos (hwnd, nullptr , 0 , 0 , st->tb_width , kBarHeight , SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE );
308313}
309314
310315void FloatingToolbar::UpdatePosition (HWND hwnd) {
@@ -396,7 +401,7 @@ void FloatingToolbar::SnapToNearestEdge(HWND hwnd) {
396401
397402void FloatingToolbar::CheckMouseNearEdge (HWND hwnd, POINT cursor) {
398403 auto * st = GetState (hwnd);
399- if (!st || !st->fullscreen_parent ) return ;
404+ if (!st || !st->fullscreen_parent || st-> dragging ) return ;
400405 RECT pr;
401406 GetWindowRect (st->fullscreen_parent , &pr);
402407 int screen_w = pr.right - pr.left ;
@@ -498,7 +503,7 @@ LRESULT CALLBACK FloatingToolbar::WndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM
498503 ClientToScreen (hwnd, &pt);
499504 int dx = pt.x - st->drag_start .x , dy = pt.y - st->drag_start .y ;
500505 RECT rc; GetWindowRect (hwnd, &rc);
501- SetWindowPos (hwnd, nullptr , rc.left + dx, rc.top + dy, 0 , 0 , SWP_NOSIZE | SWP_NOZORDER );
506+ SetWindowPos (hwnd, nullptr , rc.left + dx, rc.top + dy, 0 , 0 , SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE );
502507 st->drag_start = pt;
503508 }
504509 return 0 ;
@@ -520,6 +525,13 @@ LRESULT CALLBACK FloatingToolbar::WndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM
520525 if (st && !st->pinned ) { KillAutoHideTimer (hwnd); StartAutoHideTimer (hwnd); }
521526 UINT id = LOWORD (wp);
522527 switch (id) {
528+ case kBtnDrag :
529+ if (st && !st->dragging ) {
530+ st->dragging = true ;
531+ GetCursorPos (&st->drag_start );
532+ SetCapture (hwnd);
533+ }
534+ return 0 ;
523535 case kBtnVm : {
524536 if (st->running_vm_ids .empty ()) break ;
525537 HMENU menu = CreatePopupMenu ();
0 commit comments