21#include <winpr/windows.h>
24#include "wf_floatbar.h"
26#include "resource/resource.h"
29#pragma comment(lib, "Msimg32.lib")
32#define TAG CLIENT_TAG("windows.floatbar")
36#define TIMER_ANIMAT_SHOW 2
37#define TIMER_ANIMAT_HIDE 3
40#define BUTTON_LOCKPIN 0
41#define BUTTON_MINIMIZE 1
42#define BUTTON_RESTORE 2
47#define BACKGROUND_W 576
48#define BACKGROUND_H 27
49#define BUTTON_OFFSET 5
51#define BUTTON_WIDTH 23
52#define BUTTON_HEIGHT 21
53#define BUTTON_SPACING 1
55#define LOCK_X (BACKGROUND_H + BUTTON_OFFSET)
56#define CLOSE_X ((BACKGROUND_W - (BACKGROUND_H + BUTTON_OFFSET)) - BUTTON_WIDTH)
57#define RESTORE_X (CLOSE_X - (BUTTON_WIDTH + BUTTON_SPACING))
58#define MINIMIZE_X (RESTORE_X - (BUTTON_WIDTH + BUTTON_SPACING))
59#define TEXT_X (BACKGROUND_H + ((BUTTON_WIDTH + BUTTON_SPACING) * 3) + 5)
72 HBITMAP locked_bmp_act;
74 HBITMAP unlocked_bmp_act;
79 HINSTANCE root_window;
88 Button* buttons[BTN_MAX];
96static BOOL floatbar_kill_timers(wfFloatBar* floatbar)
98 UINT_PTR timers[] = { TIMER_HIDE, TIMER_ANIMAT_HIDE, TIMER_ANIMAT_SHOW };
103 for (
size_t x = 0; x < ARRAYSIZE(timers); x++)
104 KillTimer(floatbar->hwnd, timers[x]);
106 floatbar->animating = 0;
110static BOOL floatbar_animation(wfFloatBar*
const floatbar,
const BOOL show)
112 UINT_PTR timer = show ? TIMER_ANIMAT_SHOW : TIMER_ANIMAT_HIDE;
117 if (floatbar->shown == show)
120 if (floatbar->animating == timer)
123 floatbar->animating = timer;
125 if (SetTimer(floatbar->hwnd, timer, USER_TIMER_MINIMUM, NULL) == 0)
127 DWORD err = GetLastError();
128 WLog_ERR(TAG,
"SetTimer failed with %08" PRIx32, err);
135static BOOL floatbar_trigger_hide(wfFloatBar* floatbar)
137 if (!floatbar_kill_timers(floatbar))
140 if (!floatbar->locked && floatbar->shown)
142 if (SetTimer(floatbar->hwnd, TIMER_HIDE, 3000, NULL) == 0)
144 DWORD err = GetLastError();
145 WLog_ERR(TAG,
"SetTimer failed with %08" PRIx32, err);
153static BOOL floatbar_hide(wfFloatBar* floatbar)
155 if (!floatbar_kill_timers(floatbar))
158 floatbar->offset = floatbar->height - 2;
160 if (!MoveWindow(floatbar->hwnd, floatbar->rect.left, -floatbar->offset, floatbar->width,
161 floatbar->height, TRUE))
163 DWORD err = GetLastError();
164 WLog_ERR(TAG,
"MoveWindow failed with %08" PRIx32, err);
168 floatbar->shown = FALSE;
170 if (!floatbar_trigger_hide(floatbar))
176static BOOL floatbar_show(wfFloatBar* floatbar)
178 if (!floatbar_kill_timers(floatbar))
181 floatbar->offset = 0;
183 if (!MoveWindow(floatbar->hwnd, floatbar->rect.left, -floatbar->offset, floatbar->width,
184 floatbar->height, TRUE))
186 DWORD err = GetLastError();
187 WLog_ERR(TAG,
"MoveWindow failed with %08" PRIx32, err);
191 floatbar->shown = TRUE;
193 if (!floatbar_trigger_hide(floatbar))
199static BOOL button_set_locked(Button* button, BOOL locked)
203 button->bmp = button->locked_bmp;
204 button->bmp_act = button->locked_bmp_act;
208 button->bmp = button->unlocked_bmp;
209 button->bmp_act = button->unlocked_bmp_act;
212 InvalidateRect(button->floatbar->hwnd, NULL, FALSE);
213 UpdateWindow(button->floatbar->hwnd);
217static BOOL update_locked_state(wfFloatBar* floatbar)
224 button = floatbar->buttons[3];
226 if (!button_set_locked(button, floatbar->locked))
232static int button_hit(Button*
const button)
234 wfFloatBar*
const floatbar = button->floatbar;
236 switch (button->type)
239 floatbar->locked = !floatbar->locked;
240 update_locked_state(floatbar);
243 case BUTTON_MINIMIZE:
244 ShowWindow(floatbar->parent, SW_MINIMIZE);
248 wf_toggle_fullscreen(floatbar->wfc);
252 SendMessage(floatbar->parent, WM_DESTROY, 0, 0);
262static int button_paint(
const Button*
const button,
const HDC hdc)
266 wfFloatBar* floatbar = button->floatbar;
268 SelectObject(floatbar->hdcmem, button->active ? button->bmp_act : button->bmp);
269 bf.BlendOp = AC_SRC_OVER;
271 bf.SourceConstantAlpha = 255;
272 bf.AlphaFormat = AC_SRC_ALPHA;
273 AlphaBlend(hdc, button->x, button->y, button->w, button->h, floatbar->hdcmem, 0, 0,
274 button->w, button->h, bf);
280static Button* floatbar_create_button(wfFloatBar*
const floatbar,
const int type,
const int resid,
281 const int resid_act,
const int x,
const int y,
const int h,
284 Button* button = (Button*)calloc(1,
sizeof(Button));
289 button->floatbar = floatbar;
295 button->active = FALSE;
296 button->bmp = (HBITMAP)LoadImage(floatbar->root_window, MAKEINTRESOURCE(resid), IMAGE_BITMAP, 0,
298 button->bmp_act = (HBITMAP)LoadImage(floatbar->root_window, MAKEINTRESOURCE(resid_act),
299 IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR);
303static Button* floatbar_create_lock_button(wfFloatBar*
const floatbar,
const int unlock_resid,
304 const int unlock_resid_act,
const int lock_resid,
305 const int lock_resid_act,
const int x,
const int y,
306 const int h,
const int w)
308 Button* button = floatbar_create_button(floatbar, BUTTON_LOCKPIN, unlock_resid,
309 unlock_resid_act, x, y, h, w);
314 button->unlocked_bmp = button->bmp;
315 button->unlocked_bmp_act = button->bmp_act;
316 button->locked_bmp = (HBITMAP)LoadImage(floatbar->wfc->hInstance, MAKEINTRESOURCE(lock_resid),
317 IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR);
318 button->locked_bmp_act =
319 (HBITMAP)LoadImage(floatbar->wfc->hInstance, MAKEINTRESOURCE(lock_resid_act), IMAGE_BITMAP,
320 0, 0, LR_DEFAULTCOLOR);
324static Button* floatbar_get_button(
const wfFloatBar*
const floatbar,
const int x,
const int y)
326 if ((y > BUTTON_Y) && (y < BUTTON_Y + BUTTON_HEIGHT))
328 for (
int i = 0; i < BTN_MAX; i++)
330 if ((floatbar->buttons[i] != NULL) && (x > floatbar->buttons[i]->x) &&
331 (x < floatbar->buttons[i]->x + floatbar->buttons[i]->w))
333 return floatbar->buttons[i];
341static BOOL floatbar_paint(wfFloatBar*
const floatbar,
const HDC hdc)
346 GRADIENT_RECT gradientRect = { 0, 1 };
347 COLORREF rgbTop = RGB(117, 154, 198);
348 COLORREF rgbBottom = RGB(6, 55, 120);
351 int bottom = BACKGROUND_H - 1;
352 int right = BACKGROUND_W - 1;
353 const int angleOffset = BACKGROUND_H - 1;
354 TRIVERTEX triVertext[2] = { { left, top, GetRValue(rgbTop) << 8, GetGValue(rgbTop) << 8,
355 GetBValue(rgbTop) << 8, 0x0000 },
356 { right, bottom, GetRValue(rgbBottom) << 8,
357 GetGValue(rgbBottom) << 8, GetBValue(rgbBottom) << 8, 0x0000 } };
362 GradientFill(hdc, triVertext, 2, &gradientRect, 1, GRADIENT_FILL_RECT_V);
364 hpen = CreatePen(PS_SOLID, 1, RGB(71, 71, 71));
365 orig = SelectObject(hdc, hpen);
366 MoveToEx(hdc, left, top, NULL);
367 LineTo(hdc, left + angleOffset, bottom);
368 LineTo(hdc, right - angleOffset, bottom);
369 LineTo(hdc, right + 1, top - 1);
371 hpen = CreatePen(PS_SOLID, 1, RGB(107, 141, 184));
372 SelectObject(hdc, hpen);
376 MoveToEx(hdc, left, top, NULL);
377 LineTo(hdc, left + (angleOffset - 1), bottom);
378 LineTo(hdc, right - (angleOffset - 1), bottom);
379 LineTo(hdc, right + 1, top - 1);
381 SelectObject(hdc, orig);
383 const size_t wlen = wcslen(floatbar->wfc->window_title);
384 DrawText(hdc, floatbar->wfc->window_title, WINPR_ASSERTING_INT_CAST(
int, wlen),
386 DT_CENTER | DT_VCENTER | DT_END_ELLIPSIS | DT_NOPREFIX | DT_SINGLELINE);
390 for (
int i = 0; i < BTN_MAX; i++)
391 button_paint(floatbar->buttons[i], hdc);
396static LRESULT CALLBACK floatbar_proc(
const HWND hWnd,
const UINT Msg,
const WPARAM wParam,
399 static int dragging = FALSE;
400 static int lbtn_dwn = FALSE;
401 static int btn_dwn_x = 0;
402 static wfFloatBar* floatbar;
403 static TRACKMOUSEEVENT tme;
409 NONCLIENTMETRICS ncm;
410 int xScreen = GetSystemMetrics(SM_CXSCREEN);
415 floatbar = ((wfFloatBar*)((CREATESTRUCT*)lParam)->lpCreateParams);
416 floatbar->hwnd = hWnd;
417 GetWindowRect(floatbar->hwnd, &floatbar->rect);
418 floatbar->width = floatbar->rect.right - floatbar->rect.left;
419 floatbar->height = floatbar->rect.bottom - floatbar->rect.top;
421 floatbar->hdcmem = CreateCompatibleDC(hdc);
422 ReleaseDC(hWnd, hdc);
423 tme.cbSize =
sizeof(TRACKMOUSEEVENT);
424 tme.dwFlags = TME_LEAVE;
425 tme.hwndTrack = hWnd;
426 tme.dwHoverTime = HOVER_DEFAULT;
428 GetClientRect(hWnd, &floatbar->textRect);
429 InflateRect(&floatbar->textRect, -TEXT_X, 0);
430 SetBkMode(hdc, TRANSPARENT);
431 SetTextColor(hdc, RGB(255, 255, 255));
432 ncm.cbSize =
sizeof(NONCLIENTMETRICS);
433 SystemParametersInfo(SPI_GETNONCLIENTMETRICS,
sizeof(NONCLIENTMETRICS), &ncm, 0);
434 SelectObject(hdc, CreateFontIndirect(&ncm.lfCaptionFont));
435 floatbar_trigger_hide(floatbar);
439 hdc = BeginPaint(hWnd, &ps);
440 floatbar_paint(floatbar, hdc);
445 pos_x = lParam & 0xffff;
446 pos_y = (lParam >> 16) & 0xffff;
447 button = floatbar_get_button(floatbar, pos_x, pos_y);
453 btn_dwn_x = lParam & 0xffff;
461 pos_x = lParam & 0xffff;
462 pos_y = (lParam >> 16) & 0xffff;
468 button = floatbar_get_button(floatbar, pos_x, pos_y);
479 pos_x = lParam & 0xffff;
480 pos_y = (lParam >> 16) & 0xffff;
482 if (!floatbar->locked)
483 floatbar_animation(floatbar, TRUE);
487 floatbar->rect.left = floatbar->rect.left + (lParam & 0xffff) - btn_dwn_x;
489 if (floatbar->rect.left < 0)
490 floatbar->rect.left = 0;
491 else if (floatbar->rect.left > xScreen - floatbar->width)
492 floatbar->rect.left = xScreen - floatbar->width;
494 MoveWindow(hWnd, floatbar->rect.left, 0, floatbar->width, floatbar->height, TRUE);
498 for (
int i = 0; i < BTN_MAX; i++)
500 if (floatbar->buttons[i] != NULL)
502 floatbar->buttons[i]->active = FALSE;
506 button = floatbar_get_button(floatbar, pos_x, pos_y);
509 button->active = TRUE;
511 InvalidateRect(hWnd, NULL, FALSE);
515 TrackMouseEvent(&tme);
518 case WM_CAPTURECHANGED:
524 for (
int i = 0; i < BTN_MAX; i++)
526 if (floatbar->buttons[i] != NULL)
528 floatbar->buttons[i]->active = FALSE;
532 InvalidateRect(hWnd, NULL, FALSE);
534 floatbar_trigger_hide(floatbar);
542 floatbar_animation(floatbar, FALSE);
545 case TIMER_ANIMAT_SHOW:
548 MoveWindow(floatbar->hwnd, floatbar->rect.left, -floatbar->offset,
549 floatbar->width, floatbar->height, TRUE);
551 if (floatbar->offset <= 0)
552 floatbar_show(floatbar);
557 case TIMER_ANIMAT_HIDE:
560 MoveWindow(floatbar->hwnd, floatbar->rect.left, -floatbar->offset,
561 floatbar->width, floatbar->height, TRUE);
563 if (floatbar->offset >= floatbar->height - 2)
564 floatbar_hide(floatbar);
576 DeleteDC(floatbar->hdcmem);
581 return DefWindowProc(hWnd, Msg, wParam, lParam);
587static BOOL floatbar_window_create(wfFloatBar* floatbar)
599 if (!GetWindowRect(floatbar->parent, &rect))
602 x = (rect.right - rect.left - BACKGROUND_W) / 2;
603 wnd_cls.cbSize =
sizeof(WNDCLASSEX);
604 wnd_cls.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
605 wnd_cls.lpfnWndProc = floatbar_proc;
606 wnd_cls.cbClsExtra = 0;
607 wnd_cls.cbWndExtra = 0;
608 wnd_cls.hIcon = LoadIcon(NULL, IDI_APPLICATION);
609 wnd_cls.hCursor = LoadCursor(floatbar->root_window, IDC_ARROW);
610 wnd_cls.hbrBackground = NULL;
611 wnd_cls.lpszMenuName = NULL;
612 wnd_cls.lpszClassName = L
"floatbar";
613 wnd_cls.hInstance = floatbar->root_window;
614 wnd_cls.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
615 RegisterClassEx(&wnd_cls);
616 barWnd = CreateWindowEx(WS_EX_TOPMOST, L
"floatbar", L
"floatbar", WS_CHILD, x, 0, BACKGROUND_W,
617 BACKGROUND_H, floatbar->parent, NULL, floatbar->root_window, floatbar);
624 pt[1].x = BACKGROUND_W;
626 pt[2].x = BACKGROUND_W - BACKGROUND_H;
627 pt[2].y = BACKGROUND_H;
628 pt[3].x = BACKGROUND_H;
629 pt[3].y = BACKGROUND_H;
630 hRgn = CreatePolygonRgn(pt, 4, ALTERNATE);
631 SetWindowRgn(barWnd, hRgn, TRUE);
635void wf_floatbar_free(wfFloatBar* floatbar)
643wfFloatBar* wf_floatbar_new(wfContext* wfc, HINSTANCE window, DWORD flags)
645 wfFloatBar* floatbar;
648 if ((flags & 0x0001) == 0)
655 floatbar = (wfFloatBar*)calloc(1,
sizeof(wfFloatBar));
660 floatbar->root_window = window;
661 floatbar->flags = flags;
663 floatbar->locked = (flags & 0x0002) != 0;
664 floatbar->shown = (flags & 0x0006) != 0;
665 floatbar->hwnd = NULL;
666 floatbar->parent = wfc->hwnd;
667 floatbar->hdcmem = NULL;
669 if (wfc->fullscreen_toggle)
671 floatbar->buttons[0] =
672 floatbar_create_button(floatbar, BUTTON_MINIMIZE, IDB_MINIMIZE, IDB_MINIMIZE_ACT,
673 MINIMIZE_X, BUTTON_Y, BUTTON_HEIGHT, BUTTON_WIDTH);
674 floatbar->buttons[1] =
675 floatbar_create_button(floatbar, BUTTON_RESTORE, IDB_RESTORE, IDB_RESTORE_ACT,
676 RESTORE_X, BUTTON_Y, BUTTON_HEIGHT, BUTTON_WIDTH);
680 floatbar->buttons[0] = NULL;
681 floatbar->buttons[1] = NULL;
684 floatbar->buttons[2] = floatbar_create_button(floatbar, BUTTON_CLOSE, IDB_CLOSE, IDB_CLOSE_ACT,
685 CLOSE_X, BUTTON_Y, BUTTON_HEIGHT, BUTTON_WIDTH);
686 floatbar->buttons[3] =
687 floatbar_create_lock_button(floatbar, IDB_UNLOCK, IDB_UNLOCK_ACT, IDB_LOCK, IDB_LOCK_ACT,
688 LOCK_X, BUTTON_Y, BUTTON_HEIGHT, BUTTON_WIDTH);
690 if (!floatbar_window_create(floatbar))
693 if (!update_locked_state(floatbar))
696 if (!wf_floatbar_toggle_fullscreen(
702 wf_floatbar_free(floatbar);
706BOOL wf_floatbar_toggle_fullscreen(wfFloatBar* floatbar, BOOL fullscreen)
708 BOOL show_fs, show_wn;
713 show_fs = (floatbar->flags & 0x0010) != 0;
714 show_wn = (floatbar->flags & 0x0020) != 0;
716 if ((show_fs && fullscreen) || (show_wn && !fullscreen))
718 ShowWindow(floatbar->hwnd, SW_SHOWNORMAL);
722 floatbar_show(floatbar);
724 floatbar_hide(floatbar);
728 ShowWindow(floatbar->hwnd, SW_HIDE);
FREERDP_API BOOL freerdp_settings_get_bool(const rdpSettings *settings, FreeRDP_Settings_Keys_Bool id)
Returns a boolean settings value.