19 #include <X11/Xutil.h>
20 #include <X11/Xatom.h>
21 #include <X11/extensions/shape.h>
22 #include <X11/cursorfont.h>
24 #include <winpr/assert.h>
25 #include <winpr/cast.h>
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"
34 #include <freerdp/log.h>
35 #define TAG CLIENT_TAG("x11")
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"
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
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
56 typedef BOOL (*OnClick)(xfFloatbar*);
76 int last_motion_x_root;
77 int last_motion_y_root;
79 xfFloatbarButton* buttons[4];
90 static xfFloatbarButton* xf_floatbar_new_button(xfFloatbar* floatbar,
int type);
92 static BOOL xf_floatbar_button_onclick_close(xfFloatbar* floatbar)
97 return freerdp_abort_connect_context(&floatbar->xfc->common.context);
100 static BOOL xf_floatbar_button_onclick_minimize(xfFloatbar* floatbar)
102 xfContext* xfc = NULL;
104 if (!floatbar || !floatbar->xfc)
108 xf_SetWindowMinimized(xfc, xfc->window);
112 static BOOL xf_floatbar_button_onclick_restore(xfFloatbar* floatbar)
117 xf_toggle_fullscreen(floatbar->xfc);
121 static BOOL xf_floatbar_button_onclick_locked(xfFloatbar* floatbar)
126 floatbar->locked = (floatbar->locked) ? FALSE : TRUE;
127 return xf_floatbar_hide_and_show(floatbar);
130 BOOL xf_floatbar_set_root_y(xfFloatbar* floatbar,
int y)
135 floatbar->last_motion_y_root = y;
139 BOOL xf_floatbar_hide_and_show(xfFloatbar* floatbar)
141 xfContext* xfc = NULL;
143 if (!floatbar || !floatbar->xfc)
146 if (!floatbar->created)
151 WINPR_ASSERT(xfc->display);
153 if (!floatbar->locked)
155 if ((floatbar->mode == XF_FLOATBAR_MODE_NONE) && (floatbar->last_motion_y_root > 10) &&
156 (floatbar->y > (FLOATBAR_HEIGHT * -1)))
158 floatbar->y = floatbar->y - 1;
159 XMoveWindow(xfc->display, floatbar->handle, floatbar->x, floatbar->y);
161 else if (floatbar->y < 0 && (floatbar->last_motion_y_root < 10))
163 floatbar->y = floatbar->y + 1;
164 XMoveWindow(xfc->display, floatbar->handle, floatbar->x, floatbar->y);
171 static BOOL create_floatbar(xfFloatbar* floatbar)
173 xfContext* xfc = NULL;
175 XWindowAttributes attr = { 0 };
177 WINPR_ASSERT(floatbar);
178 if (floatbar->created)
183 WINPR_ASSERT(xfc->display);
185 status = XGetWindowAttributes(xfc->display, floatbar->root_window, &attr);
188 WLog_WARN(TAG,
"XGetWindowAttributes failed");
191 floatbar->x = attr.x + attr.width / 2 - FLOATBAR_DEFAULT_WIDTH / 2;
194 if (((floatbar->flags & 0x0004) == 0) && !floatbar->locked)
195 floatbar->y = -FLOATBAR_HEIGHT + 1;
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 |
211 floatbar->created = TRUE;
215 BOOL xf_floatbar_toggle_fullscreen(xfFloatbar* floatbar,
bool fullscreen)
218 bool visible = False;
219 xfContext* xfc = NULL;
221 if (!floatbar || !floatbar->xfc)
225 WINPR_ASSERT(xfc->display);
228 if (floatbar->flags & 0x0001)
231 visible |= ((floatbar->flags & 0x0010) != 0) && fullscreen;
233 visible |= ((floatbar->flags & 0x0020) != 0) && !fullscreen;
238 if (!create_floatbar(floatbar))
241 XMapWindow(xfc->display, floatbar->handle);
242 size = ARRAYSIZE(floatbar->buttons);
244 for (
int i = 0; i < size; i++)
246 xfFloatbarButton* button = floatbar->buttons[i];
247 XMapWindow(xfc->display, button->handle);
251 if (((floatbar->flags & 0x0004) == 0) && !floatbar->locked)
252 floatbar->y = -FLOATBAR_HEIGHT + 1;
254 xf_floatbar_hide_and_show(floatbar);
256 else if (floatbar->created)
258 XUnmapSubwindows(xfc->display, floatbar->handle);
259 XUnmapWindow(xfc->display, floatbar->handle);
265 xfFloatbarButton* xf_floatbar_new_button(xfFloatbar* floatbar,
int type)
267 xfFloatbarButton* button = NULL;
269 WINPR_ASSERT(floatbar);
270 WINPR_ASSERT(floatbar->xfc);
271 WINPR_ASSERT(floatbar->xfc->display);
272 WINPR_ASSERT(floatbar->handle);
274 button = (xfFloatbarButton*)calloc(1,
sizeof(xfFloatbarButton));
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;
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;
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;
294 case XF_FLOATBAR_BUTTON_LOCKED:
295 button->x = FLOATBAR_BORDER;
296 button->onclick = xf_floatbar_button_onclick_locked;
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);
314 xfFloatbar* xf_floatbar_new(xfContext* xfc, Window window,
const char* name, DWORD flags)
317 WINPR_ASSERT(xfc->display);
321 if ((flags & 0x0001) == 0)
331 xfFloatbar* floatbar = (xfFloatbar*)calloc(1,
sizeof(xfFloatbar));
336 floatbar->title = _strdup(name);
338 if (!floatbar->title)
341 floatbar->root_window = window;
342 floatbar->flags = flags;
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)
353 WLog_ERR(TAG,
"Failed to create fontset");
355 XFreeStringList(missingList);
358 WINPR_PRAGMA_DIAG_PUSH
359 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
360 xf_floatbar_free(floatbar);
361 WINPR_PRAGMA_DIAG_POP
365 static unsigned long xf_floatbar_get_color(xfFloatbar* floatbar,
char* rgb_value)
369 WINPR_ASSERT(floatbar);
370 WINPR_ASSERT(floatbar->xfc);
372 Display* display = floatbar->xfc->display;
373 WINPR_ASSERT(display);
375 Colormap cmap = DefaultColormap(display, XDefaultScreen(display));
376 XParseColor(display, cmap, rgb_value, &color);
377 XAllocColor(display, cmap, &color);
381 static void xf_floatbar_event_expose(xfFloatbar* floatbar)
386 XPoint shape[5] = { 0 };
387 XPoint border[5] = { 0 };
389 WINPR_ASSERT(floatbar);
390 WINPR_ASSERT(floatbar->xfc);
392 Display* display = floatbar->xfc->display;
393 WINPR_ASSERT(display);
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);
404 shape[1].x = WINPR_ASSERTING_INT_CAST(
short, floatbar->width);
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;
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;
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));
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);
433 XSetForeground(display, gc, xf_floatbar_get_color(floatbar, FLOATBAR_COLOR_BACKGROUND));
434 XFillPolygon(display, floatbar->handle, gc, shape, 4, 0, CoordModeOrigin);
436 XSetForeground(display, gc, xf_floatbar_get_color(floatbar, FLOATBAR_COLOR_BORDER));
437 XDrawLines(display, floatbar->handle, gc, border, 5, CoordModeOrigin);
439 const size_t len = strnlen(floatbar->title, MAX_PATH);
440 XSetForeground(display, gc, xf_floatbar_get_color(floatbar, FLOATBAR_COLOR_FOREGROUND));
442 WINPR_ASSERT(len <= INT32_MAX / 2);
443 const int fx = floatbar->width / 2 - (int)len * 2;
444 if (floatbar->fontSet != NULL)
446 XmbDrawString(display, floatbar->handle, floatbar->fontSet, gc, fx, 15, floatbar->title,
451 XDrawString(display, floatbar->handle, gc, fx, 15, floatbar->title, (
int)len);
453 XFreeGC(display, gc);
454 XFreeGC(display, shape_gc);
457 static xfFloatbarButton* xf_floatbar_get_button(xfFloatbar* floatbar, Window window)
459 WINPR_ASSERT(floatbar);
460 const size_t size = ARRAYSIZE(floatbar->buttons);
462 for (
size_t i = 0; i < size; i++)
464 xfFloatbarButton* button = floatbar->buttons[i];
465 if (button->handle == window)
474 static void xf_floatbar_button_update_positon(xfFloatbar* floatbar)
476 xfFloatbarButton* button = NULL;
477 WINPR_ASSERT(floatbar);
478 xfContext* xfc = floatbar->xfc;
479 const size_t size = ARRAYSIZE(floatbar->buttons);
481 for (
size_t i = 0; i < size; i++)
483 button = floatbar->buttons[i];
485 switch (button->type)
487 case XF_FLOATBAR_BUTTON_CLOSE:
489 floatbar->width - FLOATBAR_BORDER - FLOATBAR_BUTTON_WIDTH * button->type;
492 case XF_FLOATBAR_BUTTON_RESTORE:
494 floatbar->width - FLOATBAR_BORDER - FLOATBAR_BUTTON_WIDTH * button->type;
497 case XF_FLOATBAR_BUTTON_MINIMIZE:
499 floatbar->width - FLOATBAR_BORDER - FLOATBAR_BUTTON_WIDTH * button->type;
507 WINPR_ASSERT(xfc->display);
508 XMoveWindow(xfc->display, button->handle, button->x, button->y);
509 xf_floatbar_event_expose(floatbar);
513 static void xf_floatbar_button_event_expose(xfFloatbar* floatbar, Window window)
515 xfFloatbarButton* button = xf_floatbar_get_button(floatbar, window);
516 static unsigned char* bits;
519 xfContext* xfc = floatbar->xfc;
525 WINPR_ASSERT(xfc->display);
526 WINPR_ASSERT(xfc->window);
528 gc = XCreateGC(xfc->display, button->handle, 0, 0);
529 floatbar = xfc->window->floatbar;
530 WINPR_ASSERT(floatbar);
532 switch (button->type)
534 case XF_FLOATBAR_BUTTON_CLOSE:
538 case XF_FLOATBAR_BUTTON_RESTORE:
542 case XF_FLOATBAR_BUTTON_MINIMIZE:
543 bits = minimize_bits;
546 case XF_FLOATBAR_BUTTON_LOCKED:
547 if (floatbar->locked)
558 pattern = XCreateBitmapFromData(xfc->display, button->handle, (
const char*)bits,
559 FLOATBAR_BUTTON_WIDTH, FLOATBAR_BUTTON_WIDTH);
561 if (!(button->focus))
562 XSetForeground(xfc->display, gc,
563 xf_floatbar_get_color(floatbar, FLOATBAR_COLOR_BACKGROUND));
565 XSetForeground(xfc->display, gc, xf_floatbar_get_color(floatbar, FLOATBAR_COLOR_BORDER));
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);
574 static void xf_floatbar_button_event_buttonpress(xfFloatbar* floatbar,
const XButtonEvent* event)
577 xfFloatbarButton* button = xf_floatbar_get_button(floatbar, event->window);
580 button->clicked = TRUE;
583 static void xf_floatbar_button_event_buttonrelease(xfFloatbar* floatbar,
const XButtonEvent* event)
585 xfFloatbarButton* button = NULL;
587 WINPR_ASSERT(floatbar);
590 button = xf_floatbar_get_button(floatbar, event->window);
595 button->onclick(floatbar);
596 button->clicked = FALSE;
600 static void xf_floatbar_event_buttonpress(xfFloatbar* floatbar,
const XButtonEvent* event)
602 WINPR_ASSERT(floatbar);
605 switch (event->button)
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;
613 floatbar->mode = XF_FLOATBAR_MODE_DRAGGING;
622 static void xf_floatbar_event_buttonrelease(xfFloatbar* floatbar,
const XButtonEvent* event)
624 WINPR_ASSERT(floatbar);
627 switch (event->button)
630 floatbar->mode = XF_FLOATBAR_MODE_NONE;
638 static void xf_floatbar_resize(xfFloatbar* floatbar,
const XMotionEvent* event)
644 WINPR_ASSERT(floatbar);
647 xfContext* xfc = floatbar->xfc;
649 WINPR_ASSERT(xfc->display);
652 movement =
event->x_root - floatbar->last_motion_x_root;
655 if (floatbar->mode == XF_FLOATBAR_MODE_RESIZE_LEFT)
657 x = floatbar->x + movement;
658 width = floatbar->width + movement * -1;
663 width = floatbar->width + movement;
667 if (FLOATBAR_MIN_WIDTH < width)
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));
673 floatbar->width = width;
677 static void xf_floatbar_dragging(xfFloatbar* floatbar,
const XMotionEvent* event)
682 WINPR_ASSERT(floatbar);
684 xfContext* xfc = floatbar->xfc;
686 WINPR_ASSERT(xfc->window);
687 WINPR_ASSERT(xfc->display);
690 movement =
event->x_root - floatbar->last_motion_x_root;
691 x = floatbar->x + movement;
694 if (x < 0 || (x + floatbar->width) > xfc->window->width)
698 XMoveWindow(xfc->display, floatbar->handle, x, 0);
700 floatbar->last_motion_x_root = floatbar->last_motion_x_root + movement;
704 static void xf_floatbar_event_motionnotify(xfFloatbar* floatbar,
const XMotionEvent* event)
709 WINPR_ASSERT(floatbar);
712 xfContext* xfc = floatbar->xfc;
714 WINPR_ASSERT(xfc->display);
716 mode = floatbar->mode;
717 cursor = XCreateFontCursor(xfc->display, XC_arrow);
719 if ((event->state & Button1Mask) && (mode > XF_FLOATBAR_MODE_DRAGGING))
721 xf_floatbar_resize(floatbar, event);
723 else if ((event->state & Button1Mask) && (mode == XF_FLOATBAR_MODE_DRAGGING))
725 xf_floatbar_dragging(floatbar, event);
729 if (event->x <= FLOATBAR_BORDER || event->x >= floatbar->width - FLOATBAR_BORDER)
730 cursor = XCreateFontCursor(xfc->display, XC_sb_h_double_arrow);
733 XDefineCursor(xfc->display, xfc->window->handle, cursor);
734 XFreeCursor(xfc->display, cursor);
735 floatbar->last_motion_x_root =
event->x_root;
738 static void xf_floatbar_button_event_focusin(xfFloatbar* floatbar,
const XAnyEvent* event)
740 xfFloatbarButton* button = NULL;
742 WINPR_ASSERT(floatbar);
745 button = xf_floatbar_get_button(floatbar, event->window);
749 button->focus = TRUE;
750 xf_floatbar_button_event_expose(floatbar, event->window);
754 static void xf_floatbar_button_event_focusout(xfFloatbar* floatbar,
const XAnyEvent* event)
756 xfFloatbarButton* button = NULL;
758 WINPR_ASSERT(floatbar);
761 button = xf_floatbar_get_button(floatbar, event->window);
765 button->focus = FALSE;
766 xf_floatbar_button_event_expose(floatbar, event->window);
770 static void xf_floatbar_event_focusout(xfFloatbar* floatbar)
772 WINPR_ASSERT(floatbar);
773 xfContext* xfc = floatbar->xfc;
778 WINPR_ASSERT(xfc->window);
779 WINPR_ASSERT(xfc->pointer);
780 XDefineCursor(xfc->display, xfc->window->handle, xfc->pointer->cursor);
784 BOOL xf_floatbar_check_event(xfFloatbar* floatbar,
const XEvent* event)
786 if (!floatbar || !floatbar->xfc || !event)
789 if (!floatbar->created)
792 if (event->xany.window == floatbar->handle)
795 size_t size = ARRAYSIZE(floatbar->buttons);
797 for (
size_t i = 0; i < size; i++)
799 const xfFloatbarButton* button = floatbar->buttons[i];
801 if (event->xany.window == button->handle)
808 BOOL xf_floatbar_event_process(xfFloatbar* floatbar,
const XEvent* event)
810 if (!floatbar || !floatbar->xfc || !event)
813 if (!floatbar->created)
819 if (event->xexpose.window == floatbar->handle)
820 xf_floatbar_event_expose(floatbar);
822 xf_floatbar_button_event_expose(floatbar, event->xexpose.window);
827 xf_floatbar_event_motionnotify(floatbar, &event->xmotion);
831 if (event->xany.window == floatbar->handle)
832 xf_floatbar_event_buttonpress(floatbar, &event->xbutton);
834 xf_floatbar_button_event_buttonpress(floatbar, &event->xbutton);
839 if (event->xany.window == floatbar->handle)
840 xf_floatbar_event_buttonrelease(floatbar, &event->xbutton);
842 xf_floatbar_button_event_buttonrelease(floatbar, &event->xbutton);
848 if (event->xany.window != floatbar->handle)
849 xf_floatbar_button_event_focusin(floatbar, &event->xany);
855 if (event->xany.window == floatbar->handle)
856 xf_floatbar_event_focusout(floatbar);
858 xf_floatbar_button_event_focusout(floatbar, &event->xany);
862 case ConfigureNotify:
863 if (event->xany.window == floatbar->handle)
864 xf_floatbar_button_update_positon(floatbar);
869 if (event->xany.window == floatbar->handle)
870 xf_floatbar_button_update_positon(floatbar);
878 return floatbar->handle ==
event->xany.window;
881 static void xf_floatbar_button_free(xfContext* xfc, xfFloatbarButton* button)
889 WINPR_ASSERT(xfc->display);
890 XUnmapWindow(xfc->display, button->handle);
891 XDestroyWindow(xfc->display, button->handle);
897 void xf_floatbar_free(xfFloatbar* floatbar)
900 xfContext* xfc = NULL;
905 free(floatbar->title);
909 size = ARRAYSIZE(floatbar->buttons);
911 for (
size_t i = 0; i < size; i++)
913 xf_floatbar_button_free(xfc, floatbar->buttons[i]);
914 floatbar->buttons[i] = NULL;
917 if (floatbar->handle)
919 WINPR_ASSERT(xfc->display);
920 XUnmapWindow(xfc->display, floatbar->handle);
921 XDestroyWindow(xfc->display, floatbar->handle);
927 BOOL xf_floatbar_is_locked(xfFloatbar* floatbar)
931 return floatbar->mode != XF_FLOATBAR_MODE_NONE;