20 #include <winpr/crt.h>
21 #include <winpr/windows.h>
23 #include "wf_client.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
43 #define BUTTON_CLOSE 3
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];
96 static 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;
110 static 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);
135 static 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);
153 static 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))
176 static 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))
199 static 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);
217 static BOOL update_locked_state(wfFloatBar* floatbar)
224 button = floatbar->buttons[3];
226 if (!button_set_locked(button, floatbar->locked))
232 static 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);
262 static 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);
280 static 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);
303 static 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);
324 static 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];
341 static 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);
382 DrawText(hdc, floatbar->wfc->window_title, wcslen(floatbar->wfc->window_title),
384 DT_CENTER | DT_VCENTER | DT_END_ELLIPSIS | DT_NOPREFIX | DT_SINGLELINE);
388 for (
int i = 0; i < BTN_MAX; i++)
389 button_paint(floatbar->buttons[i], hdc);
394 static LRESULT CALLBACK floatbar_proc(
const HWND hWnd,
const UINT Msg,
const WPARAM wParam,
397 static int dragging = FALSE;
398 static int lbtn_dwn = FALSE;
399 static int btn_dwn_x = 0;
400 static wfFloatBar* floatbar;
401 static TRACKMOUSEEVENT tme;
407 NONCLIENTMETRICS ncm;
408 int xScreen = GetSystemMetrics(SM_CXSCREEN);
413 floatbar = ((wfFloatBar*)((CREATESTRUCT*)lParam)->lpCreateParams);
414 floatbar->hwnd = hWnd;
415 GetWindowRect(floatbar->hwnd, &floatbar->rect);
416 floatbar->width = floatbar->rect.right - floatbar->rect.left;
417 floatbar->height = floatbar->rect.bottom - floatbar->rect.top;
419 floatbar->hdcmem = CreateCompatibleDC(hdc);
420 ReleaseDC(hWnd, hdc);
421 tme.cbSize =
sizeof(TRACKMOUSEEVENT);
422 tme.dwFlags = TME_LEAVE;
423 tme.hwndTrack = hWnd;
424 tme.dwHoverTime = HOVER_DEFAULT;
426 GetClientRect(hWnd, &floatbar->textRect);
427 InflateRect(&floatbar->textRect, -TEXT_X, 0);
428 SetBkMode(hdc, TRANSPARENT);
429 SetTextColor(hdc, RGB(255, 255, 255));
430 ncm.cbSize =
sizeof(NONCLIENTMETRICS);
431 SystemParametersInfo(SPI_GETNONCLIENTMETRICS,
sizeof(NONCLIENTMETRICS), &ncm, 0);
432 SelectObject(hdc, CreateFontIndirect(&ncm.lfCaptionFont));
433 floatbar_trigger_hide(floatbar);
437 hdc = BeginPaint(hWnd, &ps);
438 floatbar_paint(floatbar, hdc);
443 pos_x = lParam & 0xffff;
444 pos_y = (lParam >> 16) & 0xffff;
445 button = floatbar_get_button(floatbar, pos_x, pos_y);
451 btn_dwn_x = lParam & 0xffff;
459 pos_x = lParam & 0xffff;
460 pos_y = (lParam >> 16) & 0xffff;
466 button = floatbar_get_button(floatbar, pos_x, pos_y);
477 pos_x = lParam & 0xffff;
478 pos_y = (lParam >> 16) & 0xffff;
480 if (!floatbar->locked)
481 floatbar_animation(floatbar, TRUE);
485 floatbar->rect.left = floatbar->rect.left + (lParam & 0xffff) - btn_dwn_x;
487 if (floatbar->rect.left < 0)
488 floatbar->rect.left = 0;
489 else if (floatbar->rect.left > xScreen - floatbar->width)
490 floatbar->rect.left = xScreen - floatbar->width;
492 MoveWindow(hWnd, floatbar->rect.left, 0, floatbar->width, floatbar->height, TRUE);
496 for (
int i = 0; i < BTN_MAX; i++)
498 if (floatbar->buttons[i] != NULL)
500 floatbar->buttons[i]->active = FALSE;
504 button = floatbar_get_button(floatbar, pos_x, pos_y);
507 button->active = TRUE;
509 InvalidateRect(hWnd, NULL, FALSE);
513 TrackMouseEvent(&tme);
516 case WM_CAPTURECHANGED:
522 for (
int i = 0; i < BTN_MAX; i++)
524 if (floatbar->buttons[i] != NULL)
526 floatbar->buttons[i]->active = FALSE;
530 InvalidateRect(hWnd, NULL, FALSE);
532 floatbar_trigger_hide(floatbar);
540 floatbar_animation(floatbar, FALSE);
543 case TIMER_ANIMAT_SHOW:
546 MoveWindow(floatbar->hwnd, floatbar->rect.left, -floatbar->offset,
547 floatbar->width, floatbar->height, TRUE);
549 if (floatbar->offset <= 0)
550 floatbar_show(floatbar);
555 case TIMER_ANIMAT_HIDE:
558 MoveWindow(floatbar->hwnd, floatbar->rect.left, -floatbar->offset,
559 floatbar->width, floatbar->height, TRUE);
561 if (floatbar->offset >= floatbar->height - 2)
562 floatbar_hide(floatbar);
574 DeleteDC(floatbar->hdcmem);
579 return DefWindowProc(hWnd, Msg, wParam, lParam);
585 static BOOL floatbar_window_create(wfFloatBar* floatbar)
597 if (!GetWindowRect(floatbar->parent, &rect))
600 x = (rect.right - rect.left - BACKGROUND_W) / 2;
601 wnd_cls.cbSize =
sizeof(WNDCLASSEX);
602 wnd_cls.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
603 wnd_cls.lpfnWndProc = floatbar_proc;
604 wnd_cls.cbClsExtra = 0;
605 wnd_cls.cbWndExtra = 0;
606 wnd_cls.hIcon = LoadIcon(NULL, IDI_APPLICATION);
607 wnd_cls.hCursor = LoadCursor(floatbar->root_window, IDC_ARROW);
608 wnd_cls.hbrBackground = NULL;
609 wnd_cls.lpszMenuName = NULL;
610 wnd_cls.lpszClassName = L
"floatbar";
611 wnd_cls.hInstance = floatbar->root_window;
612 wnd_cls.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
613 RegisterClassEx(&wnd_cls);
614 barWnd = CreateWindowEx(WS_EX_TOPMOST, L
"floatbar", L
"floatbar", WS_CHILD, x, 0, BACKGROUND_W,
615 BACKGROUND_H, floatbar->parent, NULL, floatbar->root_window, floatbar);
622 pt[1].x = BACKGROUND_W;
624 pt[2].x = BACKGROUND_W - BACKGROUND_H;
625 pt[2].y = BACKGROUND_H;
626 pt[3].x = BACKGROUND_H;
627 pt[3].y = BACKGROUND_H;
628 hRgn = CreatePolygonRgn(pt, 4, ALTERNATE);
629 SetWindowRgn(barWnd, hRgn, TRUE);
633 void wf_floatbar_free(wfFloatBar* floatbar)
641 wfFloatBar* wf_floatbar_new(wfContext* wfc, HINSTANCE window, DWORD flags)
643 wfFloatBar* floatbar;
646 if ((flags & 0x0001) == 0)
653 floatbar = (wfFloatBar*)calloc(1,
sizeof(wfFloatBar));
658 floatbar->root_window = window;
659 floatbar->flags = flags;
661 floatbar->locked = (flags & 0x0002) != 0;
662 floatbar->shown = (flags & 0x0006) != 0;
663 floatbar->hwnd = NULL;
664 floatbar->parent = wfc->hwnd;
665 floatbar->hdcmem = NULL;
667 if (wfc->fullscreen_toggle)
669 floatbar->buttons[0] =
670 floatbar_create_button(floatbar, BUTTON_MINIMIZE, IDB_MINIMIZE, IDB_MINIMIZE_ACT,
671 MINIMIZE_X, BUTTON_Y, BUTTON_HEIGHT, BUTTON_WIDTH);
672 floatbar->buttons[1] =
673 floatbar_create_button(floatbar, BUTTON_RESTORE, IDB_RESTORE, IDB_RESTORE_ACT,
674 RESTORE_X, BUTTON_Y, BUTTON_HEIGHT, BUTTON_WIDTH);
678 floatbar->buttons[0] = NULL;
679 floatbar->buttons[1] = NULL;
682 floatbar->buttons[2] = floatbar_create_button(floatbar, BUTTON_CLOSE, IDB_CLOSE, IDB_CLOSE_ACT,
683 CLOSE_X, BUTTON_Y, BUTTON_HEIGHT, BUTTON_WIDTH);
684 floatbar->buttons[3] =
685 floatbar_create_lock_button(floatbar, IDB_UNLOCK, IDB_UNLOCK_ACT, IDB_LOCK, IDB_LOCK_ACT,
686 LOCK_X, BUTTON_Y, BUTTON_HEIGHT, BUTTON_WIDTH);
688 if (!floatbar_window_create(floatbar))
691 if (!update_locked_state(floatbar))
694 if (!wf_floatbar_toggle_fullscreen(
700 wf_floatbar_free(floatbar);
704 BOOL wf_floatbar_toggle_fullscreen(wfFloatBar* floatbar, BOOL fullscreen)
706 BOOL show_fs, show_wn;
711 show_fs = (floatbar->flags & 0x0010) != 0;
712 show_wn = (floatbar->flags & 0x0020) != 0;
714 if ((show_fs && fullscreen) || (show_wn && !fullscreen))
716 ShowWindow(floatbar->hwnd, SW_SHOWNORMAL);
720 floatbar_show(floatbar);
722 floatbar_hide(floatbar);
726 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.