Blame client/X11/xf_floatbar.c

Packit 1fb8d4
/**
Packit 1fb8d4
 * FreeRDP: A Remote Desktop Protocol Implementation
Packit 1fb8d4
 * X11 Windows
Packit 1fb8d4
 *
Packit 1fb8d4
 * Licensed under the Apache License, Version 2.0 (the "License");n
Packit 1fb8d4
 * you may not use this file except in compliance with the License.
Packit 1fb8d4
 * You may obtain a copy of the License at
Packit 1fb8d4
 *
Packit 1fb8d4
 *     http://www.apache.org/licenses/LICENSE-2.0
Packit 1fb8d4
 *
Packit 1fb8d4
 * Unless required by applicable law or agreed to in writing, software
Packit 1fb8d4
 * distributed under the License is distributed on an "AS IS" BASIS,
Packit 1fb8d4
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Packit 1fb8d4
 * See the License for the specific language governing permissions and
Packit 1fb8d4
 * limitations under the License.
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
#include <X11/Xlib.h>
Packit 1fb8d4
#include <X11/Xutil.h>
Packit 1fb8d4
#include <X11/Xatom.h>
Packit 1fb8d4
#include <X11/extensions/shape.h>
Packit 1fb8d4
#include <X11/cursorfont.h>
Packit 1fb8d4
Packit 1fb8d4
#include "xf_floatbar.h"
Packit 1fb8d4
#include "resource/close.xbm"
Packit 1fb8d4
#include "resource/lock.xbm"
Packit 1fb8d4
#include "resource/unlock.xbm"
Packit 1fb8d4
#include "resource/minimize.xbm"
Packit 1fb8d4
#include "resource/restore.xbm"
Packit 1fb8d4
Packit 1fb8d4
#define TAG CLIENT_TAG("x11")
Packit 1fb8d4
Packit Service 5a9772
#define FLOATBAR_HEIGHT 26
Packit Service 5a9772
#define FLOATBAR_DEFAULT_WIDTH 576
Packit Service 5a9772
#define FLOATBAR_MIN_WIDTH 200
Packit Service 5a9772
#define FLOATBAR_BORDER 24
Packit Service 5a9772
#define FLOATBAR_BUTTON_WIDTH 24
Packit Service 5a9772
#define FLOATBAR_COLOR_BACKGROUND "RGB:31/6c/a9"
Packit Service 5a9772
#define FLOATBAR_COLOR_BORDER "RGB:75/9a/c8"
Packit Service 5a9772
#define FLOATBAR_COLOR_FOREGROUND "RGB:FF/FF/FF"
Packit 1fb8d4
Packit 1fb8d4
#ifdef WITH_DEBUG_X11
Packit 1fb8d4
#define DEBUG_X11(...) WLog_DBG(TAG, __VA_ARGS__)
Packit 1fb8d4
#else
Packit Service 5a9772
#define DEBUG_X11(...) \
Packit Service 5a9772
	do                 \
Packit Service 5a9772
	{                  \
Packit Service 5a9772
	} while (0)
Packit 1fb8d4
#endif
Packit 1fb8d4
Packit Service 5a9772
#define XF_FLOATBAR_MODE_NONE 0
Packit Service 5a9772
#define XF_FLOATBAR_MODE_DRAGGING 1
Packit Service 5a9772
#define XF_FLOATBAR_MODE_RESIZE_LEFT 2
Packit Service 5a9772
#define XF_FLOATBAR_MODE_RESIZE_RIGHT 3
Packit 1fb8d4
Packit Service 5a9772
#define XF_FLOATBAR_BUTTON_CLOSE 1
Packit Service 5a9772
#define XF_FLOATBAR_BUTTON_RESTORE 2
Packit 1fb8d4
#define XF_FLOATBAR_BUTTON_MINIMIZE 3
Packit Service 5a9772
#define XF_FLOATBAR_BUTTON_LOCKED 4
Packit Service 5a9772
Packit Service 5a9772
typedef BOOL (*OnClick)(xfFloatbar*);
Packit 1fb8d4
Packit 1fb8d4
typedef struct xf_floatbar_button xfFloatbarButton;
Packit 1fb8d4
Packit 1fb8d4
struct xf_floatbar
Packit 1fb8d4
{
Packit 1fb8d4
	int x;
Packit 1fb8d4
	int y;
Packit 1fb8d4
	int width;
Packit 1fb8d4
	int height;
Packit 1fb8d4
	int mode;
Packit 1fb8d4
	int last_motion_x_root;
Packit 1fb8d4
	int last_motion_y_root;
Packit 1fb8d4
	bool locked;
Packit 1fb8d4
	xfFloatbarButton* buttons[4];
Packit 1fb8d4
	Window handle;
Packit Service 5a9772
	BOOL hasCursor;
Packit Service 5a9772
	xfContext* xfc;
Packit Service 5a9772
	DWORD flags;
Packit Service 5a9772
	BOOL created;
Packit Service 5a9772
	Window root_window;
Packit Service 5a9772
	char* title;
Packit 1fb8d4
};
Packit 1fb8d4
Packit 1fb8d4
struct xf_floatbar_button
Packit 1fb8d4
{
Packit 1fb8d4
	int x;
Packit 1fb8d4
	int y;
Packit 1fb8d4
	int type;
Packit 1fb8d4
	bool focus;
Packit 1fb8d4
	bool clicked;
Packit 1fb8d4
	OnClick onclick;
Packit 1fb8d4
	Window handle;
Packit 1fb8d4
};
Packit 1fb8d4
Packit Service 5a9772
static xfFloatbarButton* xf_floatbar_new_button(xfFloatbar* floatbar, int type);
Packit Service 5a9772
Packit Service 5a9772
static BOOL xf_floatbar_button_onclick_close(xfFloatbar* floatbar)
Packit 1fb8d4
{
Packit Service 5a9772
	if (!floatbar)
Packit Service 5a9772
		return FALSE;
Packit Service 5a9772
Packit Service 5a9772
	return freerdp_abort_connect(floatbar->xfc->context.instance);
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static BOOL xf_floatbar_button_onclick_minimize(xfFloatbar* floatbar)
Packit 1fb8d4
{
Packit Service 5a9772
	xfContext* xfc;
Packit Service 5a9772
Packit Service 5a9772
	if (!floatbar || !floatbar->xfc)
Packit Service 5a9772
		return FALSE;
Packit Service 5a9772
Packit Service 5a9772
	xfc = floatbar->xfc;
Packit 1fb8d4
	xf_SetWindowMinimized(xfc, xfc->window);
Packit Service 5a9772
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static BOOL xf_floatbar_button_onclick_restore(xfFloatbar* floatbar)
Packit 1fb8d4
{
Packit Service 5a9772
	if (!floatbar)
Packit Service 5a9772
		return FALSE;
Packit Service 5a9772
Packit Service 5a9772
	xf_toggle_fullscreen(floatbar->xfc);
Packit Service 5a9772
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static BOOL xf_floatbar_button_onclick_locked(xfFloatbar* floatbar)
Packit 1fb8d4
{
Packit Service 5a9772
	if (!floatbar)
Packit Service 5a9772
		return FALSE;
Packit Service 5a9772
Packit 1fb8d4
	floatbar->locked = (floatbar->locked) ? FALSE : TRUE;
Packit Service 5a9772
	return xf_floatbar_hide_and_show(floatbar);
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
BOOL xf_floatbar_set_root_y(xfFloatbar* floatbar, int y)
Packit 1fb8d4
{
Packit Service 5a9772
	if (!floatbar)
Packit Service 5a9772
		return FALSE;
Packit Service 5a9772
Packit 1fb8d4
	floatbar->last_motion_y_root = y;
Packit Service 5a9772
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
BOOL xf_floatbar_hide_and_show(xfFloatbar* floatbar)
Packit 1fb8d4
{
Packit Service 5a9772
	xfContext* xfc;
Packit Service 5a9772
Packit Service 5a9772
	if (!floatbar || !floatbar->xfc)
Packit Service 5a9772
		return FALSE;
Packit Service 5a9772
Packit Service 5a9772
	if (!floatbar->created)
Packit Service 5a9772
		return TRUE;
Packit Service 5a9772
Packit Service 5a9772
	xfc = floatbar->xfc;
Packit 1fb8d4
Packit 1fb8d4
	if (!floatbar->locked)
Packit 1fb8d4
	{
Packit Service 5a9772
		if ((floatbar->mode == XF_FLOATBAR_MODE_NONE) && (floatbar->last_motion_y_root > 10) &&
Packit 1fb8d4
		    (floatbar->y > (FLOATBAR_HEIGHT * -1)))
Packit 1fb8d4
		{
Packit 1fb8d4
			floatbar->y = floatbar->y - 1;
Packit 1fb8d4
			XMoveWindow(xfc->display, floatbar->handle, floatbar->x, floatbar->y);
Packit 1fb8d4
		}
Packit 1fb8d4
		else if (floatbar->y < 0 && (floatbar->last_motion_y_root < 10))
Packit 1fb8d4
		{
Packit 1fb8d4
			floatbar->y = floatbar->y + 1;
Packit 1fb8d4
			XMoveWindow(xfc->display, floatbar->handle, floatbar->x, floatbar->y);
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit Service 5a9772
Packit Service 5a9772
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static BOOL create_floatbar(xfFloatbar* floatbar)
Packit Service 5a9772
{
Packit Service 5a9772
	xfContext* xfc;
Packit Service 5a9772
	Status status;
Packit Service 5a9772
	XWindowAttributes attr;
Packit Service 5a9772
Packit Service 5a9772
	if (floatbar->created)
Packit Service 5a9772
		return TRUE;
Packit Service 5a9772
Packit Service 5a9772
	xfc = floatbar->xfc;
Packit Service 5a9772
	status = XGetWindowAttributes(xfc->display, floatbar->root_window, &attr);
Packit Service 5a9772
	floatbar->x = attr.x + attr.width / 2 - FLOATBAR_DEFAULT_WIDTH / 2;
Packit Service 5a9772
	floatbar->y = 0;
Packit Service 5a9772
Packit Service 5a9772
	if (((floatbar->flags & 0x0004) == 0) && !floatbar->locked)
Packit Service 5a9772
		floatbar->y = -FLOATBAR_HEIGHT + 1;
Packit Service 5a9772
Packit Service 5a9772
	floatbar->handle =
Packit Service 5a9772
	    XCreateWindow(xfc->display, floatbar->root_window, floatbar->x, 0, FLOATBAR_DEFAULT_WIDTH,
Packit Service 5a9772
	                  FLOATBAR_HEIGHT, 0, CopyFromParent, InputOutput, CopyFromParent, 0, NULL);
Packit Service 5a9772
	floatbar->width = FLOATBAR_DEFAULT_WIDTH;
Packit Service 5a9772
	floatbar->height = FLOATBAR_HEIGHT;
Packit Service 5a9772
	floatbar->mode = XF_FLOATBAR_MODE_NONE;
Packit Service 5a9772
	floatbar->buttons[0] = xf_floatbar_new_button(floatbar, XF_FLOATBAR_BUTTON_CLOSE);
Packit Service 5a9772
	floatbar->buttons[1] = xf_floatbar_new_button(floatbar, XF_FLOATBAR_BUTTON_RESTORE);
Packit Service 5a9772
	floatbar->buttons[2] = xf_floatbar_new_button(floatbar, XF_FLOATBAR_BUTTON_MINIMIZE);
Packit Service 5a9772
	floatbar->buttons[3] = xf_floatbar_new_button(floatbar, XF_FLOATBAR_BUTTON_LOCKED);
Packit Service 5a9772
	XSelectInput(xfc->display, floatbar->handle,
Packit Service 5a9772
	             ExposureMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask |
Packit Service 5a9772
	                 FocusChangeMask | LeaveWindowMask | EnterWindowMask | StructureNotifyMask |
Packit Service 5a9772
	                 PropertyChangeMask);
Packit Service 5a9772
	floatbar->created = TRUE;
Packit Service 5a9772
	return TRUE;
Packit Service 5a9772
}
Packit Service 5a9772
Packit Service 5a9772
BOOL xf_floatbar_toggle_fullscreen(xfFloatbar* floatbar, bool fullscreen)
Packit 1fb8d4
{
Packit 1fb8d4
	int i, size;
Packit Service 5a9772
	bool visible = False;
Packit Service 5a9772
	xfContext* xfc;
Packit Service 5a9772
Packit Service 5a9772
	if (!floatbar || !floatbar->xfc)
Packit Service 5a9772
		return FALSE;
Packit Service 5a9772
Packit Service 5a9772
	xfc = floatbar->xfc;
Packit Service 5a9772
Packit Service 5a9772
	/* Only visible if enabled */
Packit Service 5a9772
	if (floatbar->flags & 0x0001)
Packit Service 5a9772
	{
Packit Service 5a9772
		/* Visible if fullscreen and flag visible in fullscreen mode */
Packit Service 5a9772
		visible |= ((floatbar->flags & 0x0010) != 0) && fullscreen;
Packit Service 5a9772
		/* Visible if window and flag visible in window mode */
Packit Service 5a9772
		visible |= ((floatbar->flags & 0x0020) != 0) && !fullscreen;
Packit Service 5a9772
	}
Packit 1fb8d4
Packit 1fb8d4
	if (visible)
Packit 1fb8d4
	{
Packit Service 5a9772
		if (!create_floatbar(floatbar))
Packit Service 5a9772
			return FALSE;
Packit Service 5a9772
Packit 1fb8d4
		XMapWindow(xfc->display, floatbar->handle);
Packit 1fb8d4
		size = ARRAYSIZE(floatbar->buttons);
Packit 1fb8d4
Packit 1fb8d4
		for (i = 0; i < size; i++)
Packit 1fb8d4
		{
Packit 1fb8d4
			XMapWindow(xfc->display, floatbar->buttons[i]->handle);
Packit 1fb8d4
		}
Packit Service 5a9772
Packit Service 5a9772
		/* If default is hidden (and not sticky) don't show on fullscreen state changes */
Packit Service 5a9772
		if (((floatbar->flags & 0x0004) == 0) && !floatbar->locked)
Packit Service 5a9772
			floatbar->y = -FLOATBAR_HEIGHT + 1;
Packit Service 5a9772
Packit Service 5a9772
		xf_floatbar_hide_and_show(floatbar);
Packit 1fb8d4
	}
Packit Service 5a9772
	else if (floatbar->created)
Packit 1fb8d4
	{
Packit 1fb8d4
		XUnmapSubwindows(xfc->display, floatbar->handle);
Packit 1fb8d4
		XUnmapWindow(xfc->display, floatbar->handle);
Packit 1fb8d4
	}
Packit Service 5a9772
Packit Service 5a9772
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
xfFloatbarButton* xf_floatbar_new_button(xfFloatbar* floatbar, int type)
Packit 1fb8d4
{
Packit 1fb8d4
	xfFloatbarButton* button;
Packit Service 5a9772
	button = (xfFloatbarButton*)calloc(1, sizeof(xfFloatbarButton));
Packit 1fb8d4
	button->type = type;
Packit 1fb8d4
Packit 1fb8d4
	switch (type)
Packit 1fb8d4
	{
Packit 1fb8d4
		case XF_FLOATBAR_BUTTON_CLOSE:
Packit 1fb8d4
			button->x = floatbar->width - FLOATBAR_BORDER - FLOATBAR_BUTTON_WIDTH * type;
Packit 1fb8d4
			button->onclick = xf_floatbar_button_onclick_close;
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case XF_FLOATBAR_BUTTON_RESTORE:
Packit 1fb8d4
			button->x = floatbar->width - FLOATBAR_BORDER - FLOATBAR_BUTTON_WIDTH * type;
Packit 1fb8d4
			button->onclick = xf_floatbar_button_onclick_restore;
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case XF_FLOATBAR_BUTTON_MINIMIZE:
Packit 1fb8d4
			button->x = floatbar->width - FLOATBAR_BORDER - FLOATBAR_BUTTON_WIDTH * type;
Packit 1fb8d4
			button->onclick = xf_floatbar_button_onclick_minimize;
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case XF_FLOATBAR_BUTTON_LOCKED:
Packit 1fb8d4
			button->x = FLOATBAR_BORDER;
Packit 1fb8d4
			button->onclick = xf_floatbar_button_onclick_locked;
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		default:
Packit 1fb8d4
			break;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	button->y = 0;
Packit 1fb8d4
	button->focus = FALSE;
Packit Service 5a9772
	button->handle = XCreateWindow(floatbar->xfc->display, floatbar->handle, button->x, 0,
Packit Service 5a9772
	                               FLOATBAR_BUTTON_WIDTH, FLOATBAR_BUTTON_WIDTH, 0, CopyFromParent,
Packit Service 5a9772
	                               InputOutput, CopyFromParent, 0, NULL);
Packit Service 5a9772
	XSelectInput(floatbar->xfc->display, button->handle,
Packit Service 5a9772
	             ExposureMask | ButtonPressMask | ButtonReleaseMask | FocusChangeMask |
Packit Service 5a9772
	                 LeaveWindowMask | EnterWindowMask | StructureNotifyMask);
Packit 1fb8d4
	return button;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
xfFloatbar* xf_floatbar_new(xfContext* xfc, Window window, const char* name, DWORD flags)
Packit 1fb8d4
{
Packit 1fb8d4
	xfFloatbar* floatbar;
Packit Service 5a9772
Packit Service 5a9772
	/* Floatbar not enabled */
Packit Service 5a9772
	if ((flags & 0x0001) == 0)
Packit Service 5a9772
		return NULL;
Packit Service 5a9772
Packit 1fb8d4
	if (!xfc)
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
Packit Service 5a9772
	/* Force disable with remote app */
Packit Service 5a9772
	if (xfc->remote_app)
Packit Service 5a9772
		return NULL;
Packit 1fb8d4
Packit Service 5a9772
	floatbar = (xfFloatbar*)calloc(1, sizeof(xfFloatbar));
Packit 1fb8d4
Packit Service 5a9772
	if (!floatbar)
Packit Service 5a9772
		return NULL;
Packit Service 5a9772
Packit Service 5a9772
	floatbar->title = _strdup(name);
Packit Service 5a9772
Packit Service 5a9772
	if (!floatbar->title)
Packit Service 5a9772
		goto fail;
Packit Service 5a9772
Packit Service 5a9772
	floatbar->root_window = window;
Packit Service 5a9772
	floatbar->flags = flags;
Packit Service 5a9772
	floatbar->xfc = xfc;
Packit Service 5a9772
	floatbar->locked = flags & 0x0002;
Packit Service 5a9772
	xf_floatbar_toggle_fullscreen(floatbar, FALSE);
Packit 1fb8d4
	return floatbar;
Packit Service 5a9772
fail:
Packit Service 5a9772
	xf_floatbar_free(floatbar);
Packit Service 5a9772
	return NULL;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static unsigned long xf_floatbar_get_color(xfFloatbar* floatbar, char* rgb_value)
Packit 1fb8d4
{
Packit 1fb8d4
	Colormap cmap;
Packit 1fb8d4
	XColor color;
Packit Service 5a9772
	Display* display = floatbar->xfc->display;
Packit Service 5a9772
	cmap = DefaultColormap(display, XDefaultScreen(display));
Packit Service 5a9772
	XParseColor(display, cmap, rgb_value, &color;;
Packit Service 5a9772
	XAllocColor(display, cmap, &color;;
Packit 1fb8d4
	return color.pixel;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static void xf_floatbar_event_expose(xfFloatbar* floatbar)
Packit 1fb8d4
{
Packit 1fb8d4
	GC gc, shape_gc;
Packit 1fb8d4
	Pixmap pmap;
Packit 1fb8d4
	XPoint shape[5], border[5];
Packit 1fb8d4
	int len;
Packit Service 5a9772
	Display* display = floatbar->xfc->display;
Packit Service 5a9772
Packit 1fb8d4
	/* create the pixmap that we'll use for shaping the window */
Packit Service 5a9772
	pmap = XCreatePixmap(display, floatbar->handle, floatbar->width, floatbar->height, 1);
Packit Service 5a9772
	gc = XCreateGC(display, floatbar->handle, 0, 0);
Packit Service 5a9772
	shape_gc = XCreateGC(display, pmap, 0, 0);
Packit 1fb8d4
	/* points for drawing the floatbar */
Packit 1fb8d4
	shape[0].x = 0;
Packit 1fb8d4
	shape[0].y = 0;
Packit 1fb8d4
	shape[1].x = floatbar->width;
Packit 1fb8d4
	shape[1].y = 0;
Packit 1fb8d4
	shape[2].x = shape[1].x - FLOATBAR_BORDER;
Packit 1fb8d4
	shape[2].y = FLOATBAR_HEIGHT;
Packit 1fb8d4
	shape[3].x = shape[0].x + FLOATBAR_BORDER;
Packit 1fb8d4
	shape[3].y = FLOATBAR_HEIGHT;
Packit 1fb8d4
	shape[4].x = shape[0].x;
Packit 1fb8d4
	shape[4].y = shape[0].y;
Packit 1fb8d4
	/* points for drawing the border of the floatbar */
Packit 1fb8d4
	border[0].x = shape[0].x;
Packit 1fb8d4
	border[0].y = shape[0].y - 1;
Packit 1fb8d4
	border[1].x = shape[1].x - 1;
Packit 1fb8d4
	border[1].y = shape[1].y - 1;
Packit 1fb8d4
	border[2].x = shape[2].x;
Packit 1fb8d4
	border[2].y = shape[2].y - 1;
Packit 1fb8d4
	border[3].x = shape[3].x - 1;
Packit 1fb8d4
	border[3].y = shape[3].y - 1;
Packit 1fb8d4
	border[4].x = border[0].x;
Packit 1fb8d4
	border[4].y = border[0].y;
Packit 1fb8d4
	/* Fill all pixels with 0 */
Packit Service 5a9772
	XSetForeground(display, shape_gc, 0);
Packit Service 5a9772
	XFillRectangle(display, pmap, shape_gc, 0, 0, floatbar->width, floatbar->height);
Packit 1fb8d4
	/* Fill all pixels which should be shown with 1 */
Packit Service 5a9772
	XSetForeground(display, shape_gc, 1);
Packit Service 5a9772
	XFillPolygon(display, pmap, shape_gc, shape, 5, 0, CoordModeOrigin);
Packit Service 5a9772
	XShapeCombineMask(display, floatbar->handle, ShapeBounding, 0, 0, pmap, ShapeSet);
Packit 1fb8d4
	/* draw the float bar */
Packit Service 5a9772
	XSetForeground(display, gc, xf_floatbar_get_color(floatbar, FLOATBAR_COLOR_BACKGROUND));
Packit Service 5a9772
	XFillPolygon(display, floatbar->handle, gc, shape, 4, 0, CoordModeOrigin);
Packit 1fb8d4
	/* draw an border for the floatbar */
Packit Service 5a9772
	XSetForeground(display, gc, xf_floatbar_get_color(floatbar, FLOATBAR_COLOR_BORDER));
Packit Service 5a9772
	XDrawLines(display, floatbar->handle, gc, border, 5, CoordModeOrigin);
Packit Service 5a9772
	/* draw the host name connected to (limit to maximum file name) */
Packit Service 5a9772
	len = strnlen(floatbar->title, MAX_PATH);
Packit Service 5a9772
	XSetForeground(display, gc, xf_floatbar_get_color(floatbar, FLOATBAR_COLOR_FOREGROUND));
Packit Service 5a9772
	XDrawString(display, floatbar->handle, gc, floatbar->width / 2 - len * 2, 15, floatbar->title,
Packit Service 5a9772
	            len);
Packit Service 5a9772
	XFreeGC(display, gc);
Packit Service 5a9772
	XFreeGC(display, shape_gc);
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static xfFloatbarButton* xf_floatbar_get_button(xfFloatbar* floatbar, Window window)
Packit 1fb8d4
{
Packit 1fb8d4
	int i, size;
Packit 1fb8d4
	size = ARRAYSIZE(floatbar->buttons);
Packit 1fb8d4
Packit 1fb8d4
	for (i = 0; i < size; i++)
Packit 1fb8d4
	{
Packit Service 5a9772
		if (floatbar->buttons[i]->handle == window)
Packit 1fb8d4
		{
Packit 1fb8d4
			return floatbar->buttons[i];
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return NULL;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static void xf_floatbar_button_update_positon(xfFloatbar* floatbar)
Packit 1fb8d4
{
Packit 1fb8d4
	xfFloatbarButton* button;
Packit 1fb8d4
	int i, size;
Packit Service 5a9772
	xfContext* xfc = floatbar->xfc;
Packit 1fb8d4
	size = ARRAYSIZE(floatbar->buttons);
Packit 1fb8d4
Packit 1fb8d4
	for (i = 0; i < size; i++)
Packit 1fb8d4
	{
Packit 1fb8d4
		button = floatbar->buttons[i];
Packit 1fb8d4
Packit 1fb8d4
		switch (button->type)
Packit 1fb8d4
		{
Packit 1fb8d4
			case XF_FLOATBAR_BUTTON_CLOSE:
Packit Service 5a9772
				button->x =
Packit Service 5a9772
				    floatbar->width - FLOATBAR_BORDER - FLOATBAR_BUTTON_WIDTH * button->type;
Packit 1fb8d4
				break;
Packit 1fb8d4
Packit 1fb8d4
			case XF_FLOATBAR_BUTTON_RESTORE:
Packit Service 5a9772
				button->x =
Packit Service 5a9772
				    floatbar->width - FLOATBAR_BORDER - FLOATBAR_BUTTON_WIDTH * button->type;
Packit 1fb8d4
				break;
Packit 1fb8d4
Packit 1fb8d4
			case XF_FLOATBAR_BUTTON_MINIMIZE:
Packit Service 5a9772
				button->x =
Packit Service 5a9772
				    floatbar->width - FLOATBAR_BORDER - FLOATBAR_BUTTON_WIDTH * button->type;
Packit 1fb8d4
				break;
Packit 1fb8d4
Packit 1fb8d4
			default:
Packit 1fb8d4
				break;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		XMoveWindow(xfc->display, button->handle, button->x, button->y);
Packit Service 5a9772
		xf_floatbar_event_expose(floatbar);
Packit 1fb8d4
	}
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static void xf_floatbar_button_event_expose(xfFloatbar* floatbar, Window window)
Packit 1fb8d4
{
Packit Service 5a9772
	xfFloatbarButton* button = xf_floatbar_get_button(floatbar, window);
Packit 1fb8d4
	static unsigned char* bits;
Packit 1fb8d4
	GC gc;
Packit 1fb8d4
	Pixmap pattern;
Packit Service 5a9772
	xfContext* xfc = floatbar->xfc;
Packit 1fb8d4
Packit 1fb8d4
	if (!button)
Packit 1fb8d4
		return;
Packit 1fb8d4
Packit 1fb8d4
	gc = XCreateGC(xfc->display, button->handle, 0, 0);
Packit 1fb8d4
	floatbar = xfc->window->floatbar;
Packit 1fb8d4
Packit 1fb8d4
	switch (button->type)
Packit 1fb8d4
	{
Packit 1fb8d4
		case XF_FLOATBAR_BUTTON_CLOSE:
Packit 1fb8d4
			bits = close_bits;
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case XF_FLOATBAR_BUTTON_RESTORE:
Packit 1fb8d4
			bits = restore_bits;
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case XF_FLOATBAR_BUTTON_MINIMIZE:
Packit 1fb8d4
			bits = minimize_bits;
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case XF_FLOATBAR_BUTTON_LOCKED:
Packit 1fb8d4
			if (floatbar->locked)
Packit 1fb8d4
				bits = lock_bits;
Packit 1fb8d4
			else
Packit 1fb8d4
				bits = unlock_bits;
Packit 1fb8d4
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		default:
Packit 1fb8d4
			break;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	pattern = XCreateBitmapFromData(xfc->display, button->handle, (const char*)bits,
Packit 1fb8d4
	                                FLOATBAR_BUTTON_WIDTH, FLOATBAR_BUTTON_WIDTH);
Packit 1fb8d4
Packit 1fb8d4
	if (!(button->focus))
Packit Service 5a9772
		XSetForeground(xfc->display, gc,
Packit Service 5a9772
		               xf_floatbar_get_color(floatbar, FLOATBAR_COLOR_BACKGROUND));
Packit 1fb8d4
	else
Packit Service 5a9772
		XSetForeground(xfc->display, gc, xf_floatbar_get_color(floatbar, FLOATBAR_COLOR_BORDER));
Packit 1fb8d4
Packit Service 5a9772
	XSetBackground(xfc->display, gc, xf_floatbar_get_color(floatbar, FLOATBAR_COLOR_FOREGROUND));
Packit 1fb8d4
	XCopyPlane(xfc->display, pattern, button->handle, gc, 0, 0, FLOATBAR_BUTTON_WIDTH,
Packit 1fb8d4
	           FLOATBAR_BUTTON_WIDTH, 0, 0, 1);
Packit 1fb8d4
	XFreePixmap(xfc->display, pattern);
Packit 1fb8d4
	XFreeGC(xfc->display, gc);
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static void xf_floatbar_button_event_buttonpress(xfFloatbar* floatbar, const XButtonEvent* event)
Packit 1fb8d4
{
Packit Service 5a9772
	xfFloatbarButton* button = xf_floatbar_get_button(floatbar, event->window);
Packit 1fb8d4
Packit 1fb8d4
	if (button)
Packit 1fb8d4
		button->clicked = TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static void xf_floatbar_button_event_buttonrelease(xfFloatbar* floatbar, const XButtonEvent* event)
Packit 1fb8d4
{
Packit 1fb8d4
	xfFloatbarButton* button;
Packit Service 5a9772
	button = xf_floatbar_get_button(floatbar, event->window);
Packit 1fb8d4
Packit 1fb8d4
	if (button)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (button->clicked)
Packit Service 5a9772
			button->onclick(floatbar);
Packit Service 5a9772
		button->clicked = FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static void xf_floatbar_event_buttonpress(xfFloatbar* floatbar, const XButtonEvent* event)
Packit 1fb8d4
{
Packit Service 5a9772
	switch (event->button)
Packit 1fb8d4
	{
Packit 1fb8d4
		case Button1:
Packit Service 5a9772
			if (event->x <= FLOATBAR_BORDER)
Packit 1fb8d4
				floatbar->mode = XF_FLOATBAR_MODE_RESIZE_LEFT;
Packit Service 5a9772
			else if (event->x >= (floatbar->width - FLOATBAR_BORDER))
Packit 1fb8d4
				floatbar->mode = XF_FLOATBAR_MODE_RESIZE_RIGHT;
Packit 1fb8d4
			else
Packit 1fb8d4
				floatbar->mode = XF_FLOATBAR_MODE_DRAGGING;
Packit 1fb8d4
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		default:
Packit 1fb8d4
			break;
Packit 1fb8d4
	}
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static void xf_floatbar_event_buttonrelease(xfFloatbar* floatbar, const XButtonEvent* event)
Packit 1fb8d4
{
Packit Service 5a9772
	switch (event->button)
Packit 1fb8d4
	{
Packit 1fb8d4
		case Button1:
Packit Service 5a9772
			floatbar->mode = XF_FLOATBAR_MODE_NONE;
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		default:
Packit 1fb8d4
			break;
Packit 1fb8d4
	}
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static void xf_floatbar_resize(xfFloatbar* floatbar, const XMotionEvent* event)
Packit 1fb8d4
{
Packit 1fb8d4
	int x, width, movement;
Packit Service 5a9772
	xfContext* xfc = floatbar->xfc;
Packit 1fb8d4
	/* calculate movement which happened on the root window */
Packit Service 5a9772
	movement = event->x_root - floatbar->last_motion_x_root;
Packit 1fb8d4
Packit 1fb8d4
	/* set x and width depending if movement happens on the left or right  */
Packit 1fb8d4
	if (floatbar->mode == XF_FLOATBAR_MODE_RESIZE_LEFT)
Packit 1fb8d4
	{
Packit 1fb8d4
		x = floatbar->x + movement;
Packit 1fb8d4
		width = floatbar->width + movement * -1;
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit 1fb8d4
		x = floatbar->x;
Packit 1fb8d4
		width = floatbar->width + movement;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	/* only resize and move window if still above minimum width */
Packit 1fb8d4
	if (FLOATBAR_MIN_WIDTH < width)
Packit 1fb8d4
	{
Packit 1fb8d4
		XMoveResizeWindow(xfc->display, floatbar->handle, x, 0, width, floatbar->height);
Packit 1fb8d4
		floatbar->x = x;
Packit 1fb8d4
		floatbar->width = width;
Packit 1fb8d4
	}
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static void xf_floatbar_dragging(xfFloatbar* floatbar, const XMotionEvent* event)
Packit 1fb8d4
{
Packit 1fb8d4
	int x, movement;
Packit Service 5a9772
	xfContext* xfc = floatbar->xfc;
Packit 1fb8d4
	/* calculate movement and new x position */
Packit Service 5a9772
	movement = event->x_root - floatbar->last_motion_x_root;
Packit 1fb8d4
	x = floatbar->x + movement;
Packit 1fb8d4
Packit 1fb8d4
	/* do nothing if floatbar would be moved out of the window */
Packit 1fb8d4
	if (x < 0 || (x + floatbar->width) > xfc->window->width)
Packit 1fb8d4
		return;
Packit 1fb8d4
Packit 1fb8d4
	/* move window to new x position */
Packit 1fb8d4
	XMoveWindow(xfc->display, floatbar->handle, x, 0);
Packit 1fb8d4
	/* update struct values for the next event */
Packit 1fb8d4
	floatbar->last_motion_x_root = floatbar->last_motion_x_root + movement;
Packit 1fb8d4
	floatbar->x = x;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static void xf_floatbar_event_motionnotify(xfFloatbar* floatbar, const XMotionEvent* event)
Packit 1fb8d4
{
Packit 1fb8d4
	int mode;
Packit 1fb8d4
	Cursor cursor;
Packit Service 5a9772
	xfContext* xfc = floatbar->xfc;
Packit Service 5a9772
	mode = floatbar->mode;
Packit 1fb8d4
	cursor = XCreateFontCursor(xfc->display, XC_arrow);
Packit 1fb8d4
Packit Service 5a9772
	if ((event->state & Button1Mask) && (mode > XF_FLOATBAR_MODE_DRAGGING))
Packit 1fb8d4
	{
Packit Service 5a9772
		xf_floatbar_resize(floatbar, event);
Packit 1fb8d4
	}
Packit Service 5a9772
	else if ((event->state & Button1Mask) && (mode == XF_FLOATBAR_MODE_DRAGGING))
Packit 1fb8d4
	{
Packit Service 5a9772
		xf_floatbar_dragging(floatbar, event);
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit Service 5a9772
		if (event->x <= FLOATBAR_BORDER || event->x >= floatbar->width - FLOATBAR_BORDER)
Packit 1fb8d4
			cursor = XCreateFontCursor(xfc->display, XC_sb_h_double_arrow);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	XDefineCursor(xfc->display, xfc->window->handle, cursor);
Packit 1fb8d4
	XFreeCursor(xfc->display, cursor);
Packit Service 5a9772
	floatbar->last_motion_x_root = event->x_root;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static void xf_floatbar_button_event_focusin(xfFloatbar* floatbar, const XAnyEvent* event)
Packit 1fb8d4
{
Packit 1fb8d4
	xfFloatbarButton* button;
Packit Service 5a9772
	button = xf_floatbar_get_button(floatbar, event->window);
Packit 1fb8d4
Packit 1fb8d4
	if (button)
Packit 1fb8d4
	{
Packit 1fb8d4
		button->focus = TRUE;
Packit Service 5a9772
		xf_floatbar_button_event_expose(floatbar, event->window);
Packit 1fb8d4
	}
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static void xf_floatbar_button_event_focusout(xfFloatbar* floatbar, const XAnyEvent* event)
Packit 1fb8d4
{
Packit 1fb8d4
	xfFloatbarButton* button;
Packit Service 5a9772
	button = xf_floatbar_get_button(floatbar, event->window);
Packit 1fb8d4
Packit 1fb8d4
	if (button)
Packit 1fb8d4
	{
Packit 1fb8d4
		button->focus = FALSE;
Packit Service 5a9772
		xf_floatbar_button_event_expose(floatbar, event->window);
Packit 1fb8d4
	}
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static void xf_floatbar_event_focusout(xfFloatbar* floatbar)
Packit 1fb8d4
{
Packit Service 5a9772
	xfContext* xfc = floatbar->xfc;
Packit Service 5a9772
Packit Service 5a9772
	if (xfc->pointer)
Packit Service 5a9772
	{
Packit Service 5a9772
		XDefineCursor(xfc->display, xfc->window->handle, xfc->pointer->cursor);
Packit Service 5a9772
	}
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
BOOL xf_floatbar_check_event(xfFloatbar* floatbar, const XEvent* event)
Packit 1fb8d4
{
Packit 1fb8d4
	xfFloatbarButton* button;
Packit 1fb8d4
	size_t i, size;
Packit 1fb8d4
Packit Service 5a9772
	if (!floatbar || !floatbar->xfc || !event)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit Service 5a9772
	if (!floatbar->created)
Packit Service 5a9772
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (event->xany.window == floatbar->handle)
Packit 1fb8d4
		return TRUE;
Packit 1fb8d4
Packit 1fb8d4
	size = ARRAYSIZE(floatbar->buttons);
Packit 1fb8d4
Packit 1fb8d4
	for (i = 0; i < size; i++)
Packit 1fb8d4
	{
Packit 1fb8d4
		button = floatbar->buttons[i];
Packit 1fb8d4
Packit 1fb8d4
		if (event->xany.window == button->handle)
Packit 1fb8d4
			return TRUE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return FALSE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
BOOL xf_floatbar_event_process(xfFloatbar* floatbar, const XEvent* event)
Packit 1fb8d4
{
Packit Service 5a9772
	if (!floatbar || !floatbar->xfc || !event)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit Service 5a9772
	if (!floatbar->created)
Packit Service 5a9772
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	switch (event->type)
Packit 1fb8d4
	{
Packit 1fb8d4
		case Expose:
Packit Service 5a9772
			if (event->xexpose.window == floatbar->handle)
Packit Service 5a9772
				xf_floatbar_event_expose(floatbar);
Packit 1fb8d4
			else
Packit Service 5a9772
				xf_floatbar_button_event_expose(floatbar, event->xexpose.window);
Packit 1fb8d4
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case MotionNotify:
Packit Service 5a9772
			xf_floatbar_event_motionnotify(floatbar, &event->xmotion);
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case ButtonPress:
Packit 1fb8d4
			if (event->xany.window == floatbar->handle)
Packit Service 5a9772
				xf_floatbar_event_buttonpress(floatbar, &event->xbutton);
Packit 1fb8d4
			else
Packit Service 5a9772
				xf_floatbar_button_event_buttonpress(floatbar, &event->xbutton);
Packit 1fb8d4
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case ButtonRelease:
Packit 1fb8d4
			if (event->xany.window == floatbar->handle)
Packit Service 5a9772
				xf_floatbar_event_buttonrelease(floatbar, &event->xbutton);
Packit 1fb8d4
			else
Packit Service 5a9772
				xf_floatbar_button_event_buttonrelease(floatbar, &event->xbutton);
Packit 1fb8d4
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case EnterNotify:
Packit 1fb8d4
		case FocusIn:
Packit 1fb8d4
			if (event->xany.window != floatbar->handle)
Packit Service 5a9772
				xf_floatbar_button_event_focusin(floatbar, &event->xany);
Packit 1fb8d4
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case LeaveNotify:
Packit 1fb8d4
		case FocusOut:
Packit 1fb8d4
			if (event->xany.window == floatbar->handle)
Packit Service 5a9772
				xf_floatbar_event_focusout(floatbar);
Packit 1fb8d4
			else
Packit Service 5a9772
				xf_floatbar_button_event_focusout(floatbar, &event->xany);
Packit 1fb8d4
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case ConfigureNotify:
Packit 1fb8d4
			if (event->xany.window == floatbar->handle)
Packit Service 5a9772
				xf_floatbar_button_update_positon(floatbar);
Packit 1fb8d4
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case PropertyNotify:
Packit 1fb8d4
			if (event->xany.window == floatbar->handle)
Packit Service 5a9772
				xf_floatbar_button_update_positon(floatbar);
Packit 1fb8d4
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		default:
Packit 1fb8d4
			break;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return floatbar->handle == event->xany.window;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static void xf_floatbar_button_free(xfContext* xfc, xfFloatbarButton* button)
Packit 1fb8d4
{
Packit 1fb8d4
	if (!button)
Packit 1fb8d4
		return;
Packit 1fb8d4
Packit 1fb8d4
	if (button->handle)
Packit 1fb8d4
	{
Packit 1fb8d4
		XUnmapWindow(xfc->display, button->handle);
Packit 1fb8d4
		XDestroyWindow(xfc->display, button->handle);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	free(button);
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
void xf_floatbar_free(xfFloatbar* floatbar)
Packit 1fb8d4
{
Packit 1fb8d4
	size_t i, size;
Packit Service 5a9772
	xfContext* xfc;
Packit 1fb8d4
Packit 1fb8d4
	if (!floatbar)
Packit 1fb8d4
		return;
Packit 1fb8d4
Packit Service 5a9772
	free(floatbar->title);
Packit Service 5a9772
	xfc = floatbar->xfc;
Packit Service 5a9772
	size = ARRAYSIZE(floatbar->buttons);
Packit 1fb8d4
Packit 1fb8d4
	for (i = 0; i < size; i++)
Packit 1fb8d4
	{
Packit 1fb8d4
		xf_floatbar_button_free(xfc, floatbar->buttons[i]);
Packit 1fb8d4
		floatbar->buttons[i] = NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (floatbar->handle)
Packit 1fb8d4
	{
Packit 1fb8d4
		XUnmapWindow(xfc->display, floatbar->handle);
Packit 1fb8d4
		XDestroyWindow(xfc->display, floatbar->handle);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	free(floatbar);
Packit 1fb8d4
}