FreeRDP
Loading...
Searching...
No Matches
xf_floatbar.c
1
18#include <X11/Xlib.h>
19#include <X11/Xutil.h>
20#include <X11/Xatom.h>
21#include <X11/extensions/shape.h>
22#include <X11/cursorfont.h>
23
24#include <winpr/assert.h>
25#include <winpr/cast.h>
26
27#include "xf_floatbar.h"
28#include "resource/close.xbm"
29#include "resource/lock.xbm"
30#include "resource/unlock.xbm"
31#include "resource/minimize.xbm"
32#include "resource/restore.xbm"
33
34#include <freerdp/log.h>
35#define TAG CLIENT_TAG("x11")
36
37#define FLOATBAR_HEIGHT 26
38#define FLOATBAR_DEFAULT_WIDTH 576
39#define FLOATBAR_MIN_WIDTH 200
40#define FLOATBAR_BORDER 24
41#define FLOATBAR_BUTTON_WIDTH 24
42#define FLOATBAR_COLOR_BACKGROUND "RGB:31/6c/a9"
43#define FLOATBAR_COLOR_BORDER "RGB:75/9a/c8"
44#define FLOATBAR_COLOR_FOREGROUND "RGB:FF/FF/FF"
45
46#define XF_FLOATBAR_MODE_NONE 0
47#define XF_FLOATBAR_MODE_DRAGGING 1
48#define XF_FLOATBAR_MODE_RESIZE_LEFT 2
49#define XF_FLOATBAR_MODE_RESIZE_RIGHT 3
50
51#define XF_FLOATBAR_BUTTON_CLOSE 1
52#define XF_FLOATBAR_BUTTON_RESTORE 2
53#define XF_FLOATBAR_BUTTON_MINIMIZE 3
54#define XF_FLOATBAR_BUTTON_LOCKED 4
55
56typedef BOOL (*OnClick)(xfFloatbar*);
57
58typedef struct
59{
60 int x;
61 int y;
62 int type;
63 bool focus;
64 bool clicked;
65 OnClick onclick;
66 Window handle;
67} xfFloatbarButton;
68
69struct xf_floatbar
70{
71 int x;
72 int y;
73 int width;
74 int height;
75 int mode;
76 int last_motion_x_root;
77 int last_motion_y_root;
78 BOOL locked;
79 xfFloatbarButton* buttons[4];
80 Window handle;
81 BOOL hasCursor;
82 xfContext* xfc;
83 DWORD flags;
84 BOOL created;
85 Window root_window;
86 char* title;
87 XFontSet fontSet;
88};
89
90static xfFloatbarButton* xf_floatbar_new_button(xfFloatbar* floatbar, int type);
91
92static BOOL xf_floatbar_button_onclick_close(xfFloatbar* floatbar)
93{
94 if (!floatbar)
95 return FALSE;
96
97 return freerdp_abort_connect_context(&floatbar->xfc->common.context);
98}
99
100static BOOL xf_floatbar_button_onclick_minimize(xfFloatbar* floatbar)
101{
102 xfContext* xfc = NULL;
103
104 if (!floatbar || !floatbar->xfc)
105 return FALSE;
106
107 xfc = floatbar->xfc;
108 xf_SetWindowMinimized(xfc, xfc->window);
109 return TRUE;
110}
111
112static BOOL xf_floatbar_button_onclick_restore(xfFloatbar* floatbar)
113{
114 if (!floatbar)
115 return FALSE;
116
117 xf_toggle_fullscreen(floatbar->xfc);
118 return TRUE;
119}
120
121static BOOL xf_floatbar_button_onclick_locked(xfFloatbar* floatbar)
122{
123 if (!floatbar)
124 return FALSE;
125
126 floatbar->locked = (floatbar->locked) ? FALSE : TRUE;
127 return xf_floatbar_hide_and_show(floatbar);
128}
129
130BOOL xf_floatbar_set_root_y(xfFloatbar* floatbar, int y)
131{
132 if (!floatbar)
133 return FALSE;
134
135 floatbar->last_motion_y_root = y;
136 return TRUE;
137}
138
139BOOL xf_floatbar_hide_and_show(xfFloatbar* floatbar)
140{
141 xfContext* xfc = NULL;
142
143 if (!floatbar || !floatbar->xfc)
144 return FALSE;
145
146 if (!floatbar->created)
147 return TRUE;
148
149 xfc = floatbar->xfc;
150 WINPR_ASSERT(xfc);
151 WINPR_ASSERT(xfc->display);
152
153 if (!floatbar->locked)
154 {
155 if ((floatbar->mode == XF_FLOATBAR_MODE_NONE) && (floatbar->last_motion_y_root > 10) &&
156 (floatbar->y > (FLOATBAR_HEIGHT * -1)))
157 {
158 floatbar->y = floatbar->y - 1;
159 XMoveWindow(xfc->display, floatbar->handle, floatbar->x, floatbar->y);
160 }
161 else if (floatbar->y < 0 && (floatbar->last_motion_y_root < 10))
162 {
163 floatbar->y = floatbar->y + 1;
164 XMoveWindow(xfc->display, floatbar->handle, floatbar->x, floatbar->y);
165 }
166 }
167
168 return TRUE;
169}
170
171static BOOL create_floatbar(xfFloatbar* floatbar)
172{
173 xfContext* xfc = NULL;
174 Status status = 0;
175 XWindowAttributes attr = { 0 };
176
177 WINPR_ASSERT(floatbar);
178 if (floatbar->created)
179 return TRUE;
180
181 xfc = floatbar->xfc;
182 WINPR_ASSERT(xfc);
183 WINPR_ASSERT(xfc->display);
184
185 status = XGetWindowAttributes(xfc->display, floatbar->root_window, &attr);
186 if (status == 0)
187 {
188 WLog_WARN(TAG, "XGetWindowAttributes failed");
189 return FALSE;
190 }
191 floatbar->x = attr.x + attr.width / 2 - FLOATBAR_DEFAULT_WIDTH / 2;
192 floatbar->y = 0;
193
194 if (((floatbar->flags & 0x0004) == 0) && !floatbar->locked)
195 floatbar->y = -FLOATBAR_HEIGHT + 1;
196
197 floatbar->handle =
198 XCreateWindow(xfc->display, floatbar->root_window, floatbar->x, 0, FLOATBAR_DEFAULT_WIDTH,
199 FLOATBAR_HEIGHT, 0, CopyFromParent, InputOutput, CopyFromParent, 0, NULL);
200 floatbar->width = FLOATBAR_DEFAULT_WIDTH;
201 floatbar->height = FLOATBAR_HEIGHT;
202 floatbar->mode = XF_FLOATBAR_MODE_NONE;
203 floatbar->buttons[0] = xf_floatbar_new_button(floatbar, XF_FLOATBAR_BUTTON_CLOSE);
204 floatbar->buttons[1] = xf_floatbar_new_button(floatbar, XF_FLOATBAR_BUTTON_RESTORE);
205 floatbar->buttons[2] = xf_floatbar_new_button(floatbar, XF_FLOATBAR_BUTTON_MINIMIZE);
206 floatbar->buttons[3] = xf_floatbar_new_button(floatbar, XF_FLOATBAR_BUTTON_LOCKED);
207 XSelectInput(xfc->display, floatbar->handle,
208 ExposureMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask |
209 FocusChangeMask | LeaveWindowMask | EnterWindowMask | StructureNotifyMask |
210 PropertyChangeMask);
211 floatbar->created = TRUE;
212 return TRUE;
213}
214
215BOOL xf_floatbar_toggle_fullscreen(xfFloatbar* floatbar, bool fullscreen)
216{
217 int size = 0;
218 bool visible = False;
219 xfContext* xfc = NULL;
220
221 if (!floatbar || !floatbar->xfc)
222 return FALSE;
223
224 xfc = floatbar->xfc;
225 WINPR_ASSERT(xfc->display);
226
227 /* Only visible if enabled */
228 if (floatbar->flags & 0x0001)
229 {
230 /* Visible if fullscreen and flag visible in fullscreen mode */
231 visible |= ((floatbar->flags & 0x0010) != 0) && fullscreen;
232 /* Visible if window and flag visible in window mode */
233 visible |= ((floatbar->flags & 0x0020) != 0) && !fullscreen;
234 }
235
236 if (visible)
237 {
238 if (!create_floatbar(floatbar))
239 return FALSE;
240
241 XMapWindow(xfc->display, floatbar->handle);
242 size = ARRAYSIZE(floatbar->buttons);
243
244 for (int i = 0; i < size; i++)
245 {
246 xfFloatbarButton* button = floatbar->buttons[i];
247 XMapWindow(xfc->display, button->handle);
248 }
249
250 /* If default is hidden (and not sticky) don't show on fullscreen state changes */
251 if (((floatbar->flags & 0x0004) == 0) && !floatbar->locked)
252 floatbar->y = -FLOATBAR_HEIGHT + 1;
253
254 xf_floatbar_hide_and_show(floatbar);
255 }
256 else if (floatbar->created)
257 {
258 XUnmapSubwindows(xfc->display, floatbar->handle);
259 XUnmapWindow(xfc->display, floatbar->handle);
260 }
261
262 return TRUE;
263}
264
265xfFloatbarButton* xf_floatbar_new_button(xfFloatbar* floatbar, int type)
266{
267 xfFloatbarButton* button = NULL;
268
269 WINPR_ASSERT(floatbar);
270 WINPR_ASSERT(floatbar->xfc);
271 WINPR_ASSERT(floatbar->xfc->display);
272 WINPR_ASSERT(floatbar->handle);
273
274 button = (xfFloatbarButton*)calloc(1, sizeof(xfFloatbarButton));
275 button->type = type;
276
277 switch (type)
278 {
279 case XF_FLOATBAR_BUTTON_CLOSE:
280 button->x = floatbar->width - FLOATBAR_BORDER - FLOATBAR_BUTTON_WIDTH * type;
281 button->onclick = xf_floatbar_button_onclick_close;
282 break;
283
284 case XF_FLOATBAR_BUTTON_RESTORE:
285 button->x = floatbar->width - FLOATBAR_BORDER - FLOATBAR_BUTTON_WIDTH * type;
286 button->onclick = xf_floatbar_button_onclick_restore;
287 break;
288
289 case XF_FLOATBAR_BUTTON_MINIMIZE:
290 button->x = floatbar->width - FLOATBAR_BORDER - FLOATBAR_BUTTON_WIDTH * type;
291 button->onclick = xf_floatbar_button_onclick_minimize;
292 break;
293
294 case XF_FLOATBAR_BUTTON_LOCKED:
295 button->x = FLOATBAR_BORDER;
296 button->onclick = xf_floatbar_button_onclick_locked;
297 break;
298
299 default:
300 break;
301 }
302
303 button->y = 0;
304 button->focus = FALSE;
305 button->handle = XCreateWindow(floatbar->xfc->display, floatbar->handle, button->x, 0,
306 FLOATBAR_BUTTON_WIDTH, FLOATBAR_BUTTON_WIDTH, 0, CopyFromParent,
307 InputOutput, CopyFromParent, 0, NULL);
308 XSelectInput(floatbar->xfc->display, button->handle,
309 ExposureMask | ButtonPressMask | ButtonReleaseMask | FocusChangeMask |
310 LeaveWindowMask | EnterWindowMask | StructureNotifyMask);
311 return button;
312}
313
314xfFloatbar* xf_floatbar_new(xfContext* xfc, Window window, const char* name, DWORD flags)
315{
316 WINPR_ASSERT(xfc);
317 WINPR_ASSERT(xfc->display);
318 WINPR_ASSERT(name);
319
320 /* Floatbar not enabled */
321 if ((flags & 0x0001) == 0)
322 return NULL;
323
324 if (!xfc)
325 return NULL;
326
327 /* Force disable with remote app */
328 if (xfc->remote_app)
329 return NULL;
330
331 xfFloatbar* floatbar = (xfFloatbar*)calloc(1, sizeof(xfFloatbar));
332
333 if (!floatbar)
334 return NULL;
335
336 floatbar->title = _strdup(name);
337
338 if (!floatbar->title)
339 goto fail;
340
341 floatbar->root_window = window;
342 floatbar->flags = flags;
343 floatbar->xfc = xfc;
344 floatbar->locked = (flags & 0x0002) != 0 ? TRUE : FALSE;
345 xf_floatbar_toggle_fullscreen(floatbar, FALSE);
346 char** missingList = NULL;
347 int missingCount = 0;
348 char* defString = NULL;
349 floatbar->fontSet = XCreateFontSet(floatbar->xfc->display, "-*-*-*-*-*-*-*-*-*-*-*-*-*-*",
350 &missingList, &missingCount, &defString);
351 if (floatbar->fontSet == NULL)
352 {
353 WLog_ERR(TAG, "Failed to create fontset");
354 }
355 XFreeStringList(missingList);
356 return floatbar;
357fail:
358 WINPR_PRAGMA_DIAG_PUSH
359 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
360 xf_floatbar_free(floatbar);
361 WINPR_PRAGMA_DIAG_POP
362 return NULL;
363}
364
365static unsigned long xf_floatbar_get_color(xfFloatbar* floatbar, char* rgb_value)
366{
367 XColor color;
368
369 WINPR_ASSERT(floatbar);
370 WINPR_ASSERT(floatbar->xfc);
371
372 Display* display = floatbar->xfc->display;
373 WINPR_ASSERT(display);
374
375 Colormap cmap = DefaultColormap(display, XDefaultScreen(display));
376 XParseColor(display, cmap, rgb_value, &color);
377 XAllocColor(display, cmap, &color);
378 return color.pixel;
379}
380
381static void xf_floatbar_event_expose(xfFloatbar* floatbar)
382{
383 GC gc = NULL;
384 GC shape_gc = NULL;
385 Pixmap pmap = 0;
386 XPoint shape[5] = { 0 };
387 XPoint border[5] = { 0 };
388
389 WINPR_ASSERT(floatbar);
390 WINPR_ASSERT(floatbar->xfc);
391
392 Display* display = floatbar->xfc->display;
393 WINPR_ASSERT(display);
394
395 /* create the pixmap that we'll use for shaping the window */
396 pmap = XCreatePixmap(display, floatbar->handle,
397 WINPR_ASSERTING_INT_CAST(uint32_t, floatbar->width),
398 WINPR_ASSERTING_INT_CAST(uint32_t, floatbar->height), 1);
399 gc = XCreateGC(display, floatbar->handle, 0, 0);
400 shape_gc = XCreateGC(display, pmap, 0, 0);
401 /* points for drawing the floatbar */
402 shape[0].x = 0;
403 shape[0].y = 0;
404 shape[1].x = WINPR_ASSERTING_INT_CAST(short, floatbar->width);
405 shape[1].y = 0;
406 shape[2].x = WINPR_ASSERTING_INT_CAST(short, shape[1].x - FLOATBAR_BORDER);
407 shape[2].y = FLOATBAR_HEIGHT;
408 shape[3].x = WINPR_ASSERTING_INT_CAST(short, shape[0].x + FLOATBAR_BORDER);
409 shape[3].y = FLOATBAR_HEIGHT;
410 shape[4].x = shape[0].x;
411 shape[4].y = shape[0].y;
412 /* points for drawing the border of the floatbar */
413 border[0].x = shape[0].x;
414 border[0].y = WINPR_ASSERTING_INT_CAST(short, shape[0].y - 1);
415 border[1].x = WINPR_ASSERTING_INT_CAST(short, shape[1].x - 1);
416 border[1].y = WINPR_ASSERTING_INT_CAST(short, shape[1].y - 1);
417 border[2].x = shape[2].x;
418 border[2].y = WINPR_ASSERTING_INT_CAST(short, shape[2].y - 1);
419 border[3].x = WINPR_ASSERTING_INT_CAST(short, shape[3].x - 1);
420 border[3].y = WINPR_ASSERTING_INT_CAST(short, shape[3].y - 1);
421 border[4].x = border[0].x;
422 border[4].y = border[0].y;
423 /* Fill all pixels with 0 */
424 XSetForeground(display, shape_gc, 0);
425 XFillRectangle(display, pmap, shape_gc, 0, 0,
426 WINPR_ASSERTING_INT_CAST(uint32_t, floatbar->width),
427 WINPR_ASSERTING_INT_CAST(uint32_t, floatbar->height));
428 /* Fill all pixels which should be shown with 1 */
429 XSetForeground(display, shape_gc, 1);
430 XFillPolygon(display, pmap, shape_gc, shape, 5, 0, CoordModeOrigin);
431 XShapeCombineMask(display, floatbar->handle, ShapeBounding, 0, 0, pmap, ShapeSet);
432 /* draw the float bar */
433 XSetForeground(display, gc, xf_floatbar_get_color(floatbar, FLOATBAR_COLOR_BACKGROUND));
434 XFillPolygon(display, floatbar->handle, gc, shape, 4, 0, CoordModeOrigin);
435 /* draw an border for the floatbar */
436 XSetForeground(display, gc, xf_floatbar_get_color(floatbar, FLOATBAR_COLOR_BORDER));
437 XDrawLines(display, floatbar->handle, gc, border, 5, CoordModeOrigin);
438 /* draw the host name connected to (limit to maximum file name) */
439 const size_t len = strnlen(floatbar->title, MAX_PATH);
440 XSetForeground(display, gc, xf_floatbar_get_color(floatbar, FLOATBAR_COLOR_FOREGROUND));
441
442 WINPR_ASSERT(len <= INT32_MAX / 2);
443 const int fx = floatbar->width / 2 - (int)len * 2;
444 if (floatbar->fontSet != NULL)
445 {
446 XmbDrawString(display, floatbar->handle, floatbar->fontSet, gc, fx, 15, floatbar->title,
447 (int)len);
448 }
449 else
450 {
451 XDrawString(display, floatbar->handle, gc, fx, 15, floatbar->title, (int)len);
452 }
453 XFreeGC(display, gc);
454 XFreeGC(display, shape_gc);
455}
456
457static xfFloatbarButton* xf_floatbar_get_button(xfFloatbar* floatbar, Window window)
458{
459 WINPR_ASSERT(floatbar);
460 const size_t size = ARRAYSIZE(floatbar->buttons);
461
462 for (size_t i = 0; i < size; i++)
463 {
464 xfFloatbarButton* button = floatbar->buttons[i];
465 if (button->handle == window)
466 {
467 return button;
468 }
469 }
470
471 return NULL;
472}
473
474static void xf_floatbar_button_update_positon(xfFloatbar* floatbar)
475{
476 xfFloatbarButton* button = NULL;
477 WINPR_ASSERT(floatbar);
478 xfContext* xfc = floatbar->xfc;
479 const size_t size = ARRAYSIZE(floatbar->buttons);
480
481 for (size_t i = 0; i < size; i++)
482 {
483 button = floatbar->buttons[i];
484
485 switch (button->type)
486 {
487 case XF_FLOATBAR_BUTTON_CLOSE:
488 button->x =
489 floatbar->width - FLOATBAR_BORDER - FLOATBAR_BUTTON_WIDTH * button->type;
490 break;
491
492 case XF_FLOATBAR_BUTTON_RESTORE:
493 button->x =
494 floatbar->width - FLOATBAR_BORDER - FLOATBAR_BUTTON_WIDTH * button->type;
495 break;
496
497 case XF_FLOATBAR_BUTTON_MINIMIZE:
498 button->x =
499 floatbar->width - FLOATBAR_BORDER - FLOATBAR_BUTTON_WIDTH * button->type;
500 break;
501
502 default:
503 break;
504 }
505
506 WINPR_ASSERT(xfc);
507 WINPR_ASSERT(xfc->display);
508 XMoveWindow(xfc->display, button->handle, button->x, button->y);
509 xf_floatbar_event_expose(floatbar);
510 }
511}
512
513static void xf_floatbar_button_event_expose(xfFloatbar* floatbar, Window window)
514{
515 xfFloatbarButton* button = xf_floatbar_get_button(floatbar, window);
516 static unsigned char* bits;
517 GC gc = NULL;
518 Pixmap pattern = 0;
519 xfContext* xfc = floatbar->xfc;
520
521 if (!button)
522 return;
523
524 WINPR_ASSERT(xfc);
525 WINPR_ASSERT(xfc->display);
526 WINPR_ASSERT(xfc->window);
527
528 gc = XCreateGC(xfc->display, button->handle, 0, 0);
529 floatbar = xfc->window->floatbar;
530 WINPR_ASSERT(floatbar);
531
532 switch (button->type)
533 {
534 case XF_FLOATBAR_BUTTON_CLOSE:
535 bits = close_bits;
536 break;
537
538 case XF_FLOATBAR_BUTTON_RESTORE:
539 bits = restore_bits;
540 break;
541
542 case XF_FLOATBAR_BUTTON_MINIMIZE:
543 bits = minimize_bits;
544 break;
545
546 case XF_FLOATBAR_BUTTON_LOCKED:
547 if (floatbar->locked)
548 bits = lock_bits;
549 else
550 bits = unlock_bits;
551
552 break;
553
554 default:
555 break;
556 }
557
558 pattern = XCreateBitmapFromData(xfc->display, button->handle, (const char*)bits,
559 FLOATBAR_BUTTON_WIDTH, FLOATBAR_BUTTON_WIDTH);
560
561 if (!(button->focus))
562 XSetForeground(xfc->display, gc,
563 xf_floatbar_get_color(floatbar, FLOATBAR_COLOR_BACKGROUND));
564 else
565 XSetForeground(xfc->display, gc, xf_floatbar_get_color(floatbar, FLOATBAR_COLOR_BORDER));
566
567 XSetBackground(xfc->display, gc, xf_floatbar_get_color(floatbar, FLOATBAR_COLOR_FOREGROUND));
568 XCopyPlane(xfc->display, pattern, button->handle, gc, 0, 0, FLOATBAR_BUTTON_WIDTH,
569 FLOATBAR_BUTTON_WIDTH, 0, 0, 1);
570 XFreePixmap(xfc->display, pattern);
571 XFreeGC(xfc->display, gc);
572}
573
574static void xf_floatbar_button_event_buttonpress(xfFloatbar* floatbar, const XButtonEvent* event)
575{
576 WINPR_ASSERT(event);
577 xfFloatbarButton* button = xf_floatbar_get_button(floatbar, event->window);
578
579 if (button)
580 button->clicked = TRUE;
581}
582
583static void xf_floatbar_button_event_buttonrelease(xfFloatbar* floatbar, const XButtonEvent* event)
584{
585 xfFloatbarButton* button = NULL;
586
587 WINPR_ASSERT(floatbar);
588 WINPR_ASSERT(event);
589
590 button = xf_floatbar_get_button(floatbar, event->window);
591
592 if (button)
593 {
594 if (button->clicked)
595 button->onclick(floatbar);
596 button->clicked = FALSE;
597 }
598}
599
600static void xf_floatbar_event_buttonpress(xfFloatbar* floatbar, const XButtonEvent* event)
601{
602 WINPR_ASSERT(floatbar);
603 WINPR_ASSERT(event);
604
605 switch (event->button)
606 {
607 case Button1:
608 if (event->x <= FLOATBAR_BORDER)
609 floatbar->mode = XF_FLOATBAR_MODE_RESIZE_LEFT;
610 else if (event->x >= (floatbar->width - FLOATBAR_BORDER))
611 floatbar->mode = XF_FLOATBAR_MODE_RESIZE_RIGHT;
612 else
613 floatbar->mode = XF_FLOATBAR_MODE_DRAGGING;
614
615 break;
616
617 default:
618 break;
619 }
620}
621
622static void xf_floatbar_event_buttonrelease(xfFloatbar* floatbar, const XButtonEvent* event)
623{
624 WINPR_ASSERT(floatbar);
625 WINPR_ASSERT(event);
626
627 switch (event->button)
628 {
629 case Button1:
630 floatbar->mode = XF_FLOATBAR_MODE_NONE;
631 break;
632
633 default:
634 break;
635 }
636}
637
638static void xf_floatbar_resize(xfFloatbar* floatbar, const XMotionEvent* event)
639{
640 int x = 0;
641 int width = 0;
642 int movement = 0;
643
644 WINPR_ASSERT(floatbar);
645 WINPR_ASSERT(event);
646
647 xfContext* xfc = floatbar->xfc;
648 WINPR_ASSERT(xfc);
649 WINPR_ASSERT(xfc->display);
650
651 /* calculate movement which happened on the root window */
652 movement = event->x_root - floatbar->last_motion_x_root;
653
654 /* set x and width depending if movement happens on the left or right */
655 if (floatbar->mode == XF_FLOATBAR_MODE_RESIZE_LEFT)
656 {
657 x = floatbar->x + movement;
658 width = floatbar->width + movement * -1;
659 }
660 else
661 {
662 x = floatbar->x;
663 width = floatbar->width + movement;
664 }
665
666 /* only resize and move window if still above minimum width */
667 if (FLOATBAR_MIN_WIDTH < width)
668 {
669 XMoveResizeWindow(xfc->display, floatbar->handle, x, 0,
670 WINPR_ASSERTING_INT_CAST(uint32_t, width),
671 WINPR_ASSERTING_INT_CAST(uint32_t, floatbar->height));
672 floatbar->x = x;
673 floatbar->width = width;
674 }
675}
676
677static void xf_floatbar_dragging(xfFloatbar* floatbar, const XMotionEvent* event)
678{
679 int x = 0;
680 int movement = 0;
681
682 WINPR_ASSERT(floatbar);
683 WINPR_ASSERT(event);
684 xfContext* xfc = floatbar->xfc;
685 WINPR_ASSERT(xfc);
686 WINPR_ASSERT(xfc->window);
687 WINPR_ASSERT(xfc->display);
688
689 /* calculate movement and new x position */
690 movement = event->x_root - floatbar->last_motion_x_root;
691 x = floatbar->x + movement;
692
693 /* do nothing if floatbar would be moved out of the window */
694 if (x < 0 || (x + floatbar->width) > xfc->window->width)
695 return;
696
697 /* move window to new x position */
698 XMoveWindow(xfc->display, floatbar->handle, x, 0);
699 /* update struct values for the next event */
700 floatbar->last_motion_x_root = floatbar->last_motion_x_root + movement;
701 floatbar->x = x;
702}
703
704static void xf_floatbar_event_motionnotify(xfFloatbar* floatbar, const XMotionEvent* event)
705{
706 int mode = 0;
707 Cursor cursor = 0;
708
709 WINPR_ASSERT(floatbar);
710 WINPR_ASSERT(event);
711
712 xfContext* xfc = floatbar->xfc;
713 WINPR_ASSERT(xfc);
714 WINPR_ASSERT(xfc->display);
715
716 mode = floatbar->mode;
717 cursor = XCreateFontCursor(xfc->display, XC_arrow);
718
719 if ((event->state & Button1Mask) && (mode > XF_FLOATBAR_MODE_DRAGGING))
720 {
721 xf_floatbar_resize(floatbar, event);
722 }
723 else if ((event->state & Button1Mask) && (mode == XF_FLOATBAR_MODE_DRAGGING))
724 {
725 xf_floatbar_dragging(floatbar, event);
726 }
727 else
728 {
729 if (event->x <= FLOATBAR_BORDER || event->x >= floatbar->width - FLOATBAR_BORDER)
730 cursor = XCreateFontCursor(xfc->display, XC_sb_h_double_arrow);
731 }
732
733 XDefineCursor(xfc->display, xfc->window->handle, cursor);
734 XFreeCursor(xfc->display, cursor);
735 floatbar->last_motion_x_root = event->x_root;
736}
737
738static void xf_floatbar_button_event_focusin(xfFloatbar* floatbar, const XAnyEvent* event)
739{
740 xfFloatbarButton* button = NULL;
741
742 WINPR_ASSERT(floatbar);
743 WINPR_ASSERT(event);
744
745 button = xf_floatbar_get_button(floatbar, event->window);
746
747 if (button)
748 {
749 button->focus = TRUE;
750 xf_floatbar_button_event_expose(floatbar, event->window);
751 }
752}
753
754static void xf_floatbar_button_event_focusout(xfFloatbar* floatbar, const XAnyEvent* event)
755{
756 xfFloatbarButton* button = NULL;
757
758 WINPR_ASSERT(floatbar);
759 WINPR_ASSERT(event);
760
761 button = xf_floatbar_get_button(floatbar, event->window);
762
763 if (button)
764 {
765 button->focus = FALSE;
766 xf_floatbar_button_event_expose(floatbar, event->window);
767 }
768}
769
770static void xf_floatbar_event_focusout(xfFloatbar* floatbar)
771{
772 WINPR_ASSERT(floatbar);
773 xfContext* xfc = floatbar->xfc;
774 WINPR_ASSERT(xfc);
775
776 if (xfc->pointer)
777 {
778 WINPR_ASSERT(xfc->window);
779 WINPR_ASSERT(xfc->pointer);
780 XDefineCursor(xfc->display, xfc->window->handle, xfc->pointer->cursor);
781 }
782}
783
784BOOL xf_floatbar_check_event(xfFloatbar* floatbar, const XEvent* event)
785{
786 if (!floatbar || !floatbar->xfc || !event)
787 return FALSE;
788
789 if (!floatbar->created)
790 return FALSE;
791
792 if (event->xany.window == floatbar->handle)
793 return TRUE;
794
795 size_t size = ARRAYSIZE(floatbar->buttons);
796
797 for (size_t i = 0; i < size; i++)
798 {
799 const xfFloatbarButton* button = floatbar->buttons[i];
800
801 if (event->xany.window == button->handle)
802 return TRUE;
803 }
804
805 return FALSE;
806}
807
808BOOL xf_floatbar_event_process(xfFloatbar* floatbar, const XEvent* event)
809{
810 if (!floatbar || !floatbar->xfc || !event)
811 return FALSE;
812
813 if (!floatbar->created)
814 return FALSE;
815
816 switch (event->type)
817 {
818 case Expose:
819 if (event->xexpose.window == floatbar->handle)
820 xf_floatbar_event_expose(floatbar);
821 else
822 xf_floatbar_button_event_expose(floatbar, event->xexpose.window);
823
824 break;
825
826 case MotionNotify:
827 xf_floatbar_event_motionnotify(floatbar, &event->xmotion);
828 break;
829
830 case ButtonPress:
831 if (event->xany.window == floatbar->handle)
832 xf_floatbar_event_buttonpress(floatbar, &event->xbutton);
833 else
834 xf_floatbar_button_event_buttonpress(floatbar, &event->xbutton);
835
836 break;
837
838 case ButtonRelease:
839 if (event->xany.window == floatbar->handle)
840 xf_floatbar_event_buttonrelease(floatbar, &event->xbutton);
841 else
842 xf_floatbar_button_event_buttonrelease(floatbar, &event->xbutton);
843
844 break;
845
846 case EnterNotify:
847 case FocusIn:
848 if (event->xany.window != floatbar->handle)
849 xf_floatbar_button_event_focusin(floatbar, &event->xany);
850
851 break;
852
853 case LeaveNotify:
854 case FocusOut:
855 if (event->xany.window == floatbar->handle)
856 xf_floatbar_event_focusout(floatbar);
857 else
858 xf_floatbar_button_event_focusout(floatbar, &event->xany);
859
860 break;
861
862 case ConfigureNotify:
863 if (event->xany.window == floatbar->handle)
864 xf_floatbar_button_update_positon(floatbar);
865
866 break;
867
868 case PropertyNotify:
869 if (event->xany.window == floatbar->handle)
870 xf_floatbar_button_update_positon(floatbar);
871
872 break;
873
874 default:
875 break;
876 }
877
878 return floatbar->handle == event->xany.window;
879}
880
881static void xf_floatbar_button_free(xfContext* xfc, xfFloatbarButton* button)
882{
883 if (!button)
884 return;
885
886 if (button->handle)
887 {
888 WINPR_ASSERT(xfc);
889 WINPR_ASSERT(xfc->display);
890 XUnmapWindow(xfc->display, button->handle);
891 XDestroyWindow(xfc->display, button->handle);
892 }
893
894 free(button);
895}
896
897void xf_floatbar_free(xfFloatbar* floatbar)
898{
899 size_t size = 0;
900 xfContext* xfc = NULL;
901
902 if (!floatbar)
903 return;
904
905 free(floatbar->title);
906 xfc = floatbar->xfc;
907 WINPR_ASSERT(xfc);
908
909 size = ARRAYSIZE(floatbar->buttons);
910
911 for (size_t i = 0; i < size; i++)
912 {
913 xf_floatbar_button_free(xfc, floatbar->buttons[i]);
914 floatbar->buttons[i] = NULL;
915 }
916
917 if (floatbar->handle)
918 {
919 WINPR_ASSERT(xfc->display);
920 XUnmapWindow(xfc->display, floatbar->handle);
921 XDestroyWindow(xfc->display, floatbar->handle);
922 }
923
924 free(floatbar);
925}
926
927BOOL xf_floatbar_is_locked(xfFloatbar* floatbar)
928{
929 if (!floatbar)
930 return FALSE;
931 return floatbar->mode != XF_FLOATBAR_MODE_NONE;
932}