|  |  |  | /*
 | 
					
						
							|  |  |  |  * Copyright © 2008 Kristian Høgsberg
 | 
					
						
							|  |  |  |  * Copyright © 2012-2013 Collabora, Ltd.
 | 
					
						
							|  |  |  |  * Copyright © 2013 Jason Ekstrand
 | 
					
						
							|  |  |  |  *
 | 
					
						
							|  |  |  |  * Permission to use, copy, modify, distribute, and sell this software and its
 | 
					
						
							|  |  |  |  * documentation for any purpose is hereby granted without fee, provided that
 | 
					
						
							|  |  |  |  * the above copyright notice appear in all copies and that both that copyright
 | 
					
						
							|  |  |  |  * notice and this permission notice appear in supporting documentation, and
 | 
					
						
							|  |  |  |  * that the name of the copyright holders not be used in advertising or
 | 
					
						
							|  |  |  |  * publicity pertaining to distribution of the software without specific,
 | 
					
						
							|  |  |  |  * written prior permission.  The copyright holders make no representations
 | 
					
						
							|  |  |  |  * about the suitability of this software for any purpose.  It is provided "as
 | 
					
						
							|  |  |  |  * is" without express or implied warranty.
 | 
					
						
							|  |  |  |  *
 | 
					
						
							|  |  |  |  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 | 
					
						
							|  |  |  |  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
 | 
					
						
							|  |  |  |  * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
 | 
					
						
							|  |  |  |  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
 | 
					
						
							|  |  |  |  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
 | 
					
						
							|  |  |  |  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
 | 
					
						
							|  |  |  |  * OF THIS SOFTWARE.
 | 
					
						
							|  |  |  |  */
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "config.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <stdlib.h>
 | 
					
						
							|  |  |  | #include <string.h>
 | 
					
						
							|  |  |  | #include <wayland-util.h>
 | 
					
						
							|  |  |  | #include <linux/input.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "cairo-util.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | enum frame_button_flags {
 | 
					
						
							|  |  |  | 	FRAME_BUTTON_ALIGN_RIGHT = 0x1,
 | 
					
						
							|  |  |  | 	FRAME_BUTTON_DECORATED = 0x2,
 | 
					
						
							|  |  |  | 	FRAME_BUTTON_CLICK_DOWN = 0x4,
 | 
					
						
							|  |  |  | };
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct frame_button {
 | 
					
						
							|  |  |  | 	struct frame *frame;
 | 
					
						
							|  |  |  | 	struct wl_list link;	/* buttons_list */
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	cairo_surface_t *icon;
 | 
					
						
							|  |  |  | 	enum frame_button_flags flags;
 | 
					
						
							|  |  |  | 	int hover_count;
 | 
					
						
							|  |  |  | 	int press_count;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	struct {
 | 
					
						
							|  |  |  | 		int x, y;
 | 
					
						
							|  |  |  | 		int width, height;
 | 
					
						
							|  |  |  | 	} allocation;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	enum frame_status status_effect;
 | 
					
						
							|  |  |  | };
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct frame_pointer_button {
 | 
					
						
							|  |  |  | 	struct wl_list link;
 | 
					
						
							|  |  |  | 	uint32_t button;
 | 
					
						
							|  |  |  | 	enum theme_location press_location;
 | 
					
						
							|  |  |  | 	struct frame_button *frame_button;
 | 
					
						
							|  |  |  | };
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct frame_pointer {
 | 
					
						
							|  |  |  | 	struct wl_list link;
 | 
					
						
							|  |  |  | 	void *data;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	int x, y;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	struct frame_button *hover_button;
 | 
					
						
							|  |  |  | 	struct wl_list down_buttons;
 | 
					
						
							|  |  |  | };
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct frame_touch {
 | 
					
						
							|  |  |  | 	struct wl_list link;
 | 
					
						
							|  |  |  | 	void *data;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	int x, y;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	struct frame_button *button;
 | 
					
						
							|  |  |  | };
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct frame {
 | 
					
						
							|  |  |  | 	int32_t width, height;
 | 
					
						
							|  |  |  | 	char *title;
 | 
					
						
							|  |  |  | 	uint32_t flags;
 | 
					
						
							|  |  |  | 	struct theme *theme;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	struct {
 | 
					
						
							|  |  |  | 		int32_t x, y;
 | 
					
						
							|  |  |  | 		int32_t width, height;
 | 
					
						
							|  |  |  | 	} interior;
 | 
					
						
							|  |  |  | 	int shadow_margin;
 | 
					
						
							|  |  |  | 	int opaque_margin;
 | 
					
						
							|  |  |  | 	int geometry_dirty;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	uint32_t status;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	struct wl_list buttons;
 | 
					
						
							|  |  |  | 	struct wl_list pointers;
 | 
					
						
							|  |  |  | 	struct wl_list touches;
 | 
					
						
							|  |  |  | };
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct frame_button *
 | 
					
						
							|  |  |  | frame_button_create(struct frame *frame, const char *icon,
 | 
					
						
							|  |  |  | 		    enum frame_status status_effect,
 | 
					
						
							|  |  |  | 		    enum frame_button_flags flags)
 | 
					
						
							|  |  |  | {
 | 
					
						
							|  |  |  | 	struct frame_button *button;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	button = calloc(1, sizeof *button);
 | 
					
						
							|  |  |  | 	if (!button)
 | 
					
						
							|  |  |  | 		return NULL;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	button->icon = cairo_image_surface_create_from_png(icon);
 | 
					
						
							|  |  |  | 	if (!button->icon) {
 | 
					
						
							|  |  |  | 		free(button);
 | 
					
						
							|  |  |  | 		return NULL;
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	button->frame = frame;
 | 
					
						
							|  |  |  | 	button->flags = flags;
 | 
					
						
							|  |  |  | 	button->status_effect = status_effect;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	wl_list_insert(frame->buttons.prev, &button->link);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return button;
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void
 | 
					
						
							|  |  |  | frame_button_destroy(struct frame_button *button)
 | 
					
						
							|  |  |  | {
 | 
					
						
							|  |  |  | 	cairo_surface_destroy(button->icon);
 | 
					
						
							|  |  |  | 	free(button);
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void
 | 
					
						
							|  |  |  | frame_button_enter(struct frame_button *button)
 | 
					
						
							|  |  |  | {
 | 
					
						
							|  |  |  | 	if (!button->hover_count)
 | 
					
						
							|  |  |  | 		button->frame->status |= FRAME_STATUS_REPAINT;
 | 
					
						
							|  |  |  | 	button->hover_count++;
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void
 | 
					
						
							|  |  |  | frame_button_leave(struct frame_button *button, struct frame_pointer *pointer)
 | 
					
						
							|  |  |  | {
 | 
					
						
							|  |  |  | 	button->hover_count--;
 | 
					
						
							|  |  |  | 	if (!button->hover_count)
 | 
					
						
							|  |  |  | 		button->frame->status |= FRAME_STATUS_REPAINT;
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void
 | 
					
						
							|  |  |  | frame_button_press(struct frame_button *button)
 | 
					
						
							|  |  |  | {
 | 
					
						
							|  |  |  | 	if (!button->press_count)
 | 
					
						
							|  |  |  | 		button->frame->status |= FRAME_STATUS_REPAINT;
 | 
					
						
							|  |  |  | 	button->press_count++;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (button->flags & FRAME_BUTTON_CLICK_DOWN)
 | 
					
						
							|  |  |  | 		button->frame->status |= button->status_effect;
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void
 | 
					
						
							|  |  |  | frame_button_release(struct frame_button *button)
 | 
					
						
							|  |  |  | {
 | 
					
						
							|  |  |  | 	button->press_count--;
 | 
					
						
							|  |  |  | 	if (button->press_count)
 | 
					
						
							|  |  |  | 		return;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	button->frame->status |= FRAME_STATUS_REPAINT;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!(button->flags & FRAME_BUTTON_CLICK_DOWN))
 | 
					
						
							|  |  |  | 		button->frame->status |= button->status_effect;
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void
 | 
					
						
							|  |  |  | frame_button_cancel(struct frame_button *button)
 | 
					
						
							|  |  |  | {
 | 
					
						
							|  |  |  | 	button->press_count--;
 | 
					
						
							|  |  |  | 	if (!button->press_count)
 | 
					
						
							|  |  |  | 		button->frame->status |= FRAME_STATUS_REPAINT;
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void
 | 
					
						
							|  |  |  | frame_button_repaint(struct frame_button *button, cairo_t *cr)
 | 
					
						
							|  |  |  | {
 | 
					
						
							|  |  |  | 	int x, y;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!button->allocation.width)
 | 
					
						
							|  |  |  | 		return;
 | 
					
						
							|  |  |  | 	if (!button->allocation.height)
 | 
					
						
							|  |  |  | 		return;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	x = button->allocation.x;
 | 
					
						
							|  |  |  | 	y = button->allocation.y;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	cairo_save(cr);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (button->flags & FRAME_BUTTON_DECORATED) {
 | 
					
						
							|  |  |  | 		cairo_set_line_width(cr, 1);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		cairo_set_source_rgb(cr, 0.0, 0.0, 0.0);
 | 
					
						
							|  |  |  | 		cairo_rectangle(cr, x, y, 25, 16);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		cairo_stroke_preserve(cr);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (button->press_count) {
 | 
					
						
							|  |  |  | 			cairo_set_source_rgb(cr, 0.7, 0.7, 0.7);
 | 
					
						
							|  |  |  | 		} else if (button->hover_count) {
 | 
					
						
							|  |  |  | 			cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
 | 
					
						
							|  |  |  | 		} else {
 | 
					
						
							|  |  |  | 			cairo_set_source_rgb(cr, 0.88, 0.88, 0.88);
 | 
					
						
							|  |  |  | 		}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		cairo_fill (cr);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		x += 4;
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	cairo_set_source_surface(cr, button->icon, x, y);
 | 
					
						
							|  |  |  | 	cairo_paint(cr);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	cairo_restore(cr);
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct frame_pointer *
 | 
					
						
							|  |  |  | frame_pointer_get(struct frame *frame, void *data)
 | 
					
						
							|  |  |  | {
 | 
					
						
							|  |  |  | 	struct frame_pointer *pointer;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	wl_list_for_each(pointer, &frame->pointers, link)
 | 
					
						
							|  |  |  | 		if (pointer->data == data)
 | 
					
						
							|  |  |  | 			return pointer;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	pointer = calloc(1, sizeof *pointer);
 | 
					
						
							|  |  |  | 	if (!pointer)
 | 
					
						
							|  |  |  | 		return NULL;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	pointer->data = data;
 | 
					
						
							|  |  |  | 	wl_list_init(&pointer->down_buttons);
 | 
					
						
							|  |  |  | 	wl_list_insert(&frame->pointers, &pointer->link);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return pointer;
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void
 | 
					
						
							|  |  |  | frame_pointer_destroy(struct frame_pointer *pointer)
 | 
					
						
							|  |  |  | {
 | 
					
						
							|  |  |  | 	wl_list_remove(&pointer->link);
 | 
					
						
							|  |  |  | 	free(pointer);
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct frame_touch *
 | 
					
						
							|  |  |  | frame_touch_get(struct frame *frame, void *data)
 | 
					
						
							|  |  |  | {
 | 
					
						
							|  |  |  | 	struct frame_touch *touch;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	wl_list_for_each(touch, &frame->touches, link)
 | 
					
						
							|  |  |  | 		if (touch->data == data)
 | 
					
						
							|  |  |  | 			return touch;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	touch = calloc(1, sizeof *touch);
 | 
					
						
							|  |  |  | 	if (!touch)
 | 
					
						
							|  |  |  | 		return NULL;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	touch->data = data;
 | 
					
						
							|  |  |  | 	wl_list_insert(&frame->touches, &touch->link);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return touch;
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void
 | 
					
						
							|  |  |  | frame_touch_destroy(struct frame_touch *touch)
 | 
					
						
							|  |  |  | {
 | 
					
						
							|  |  |  | 	wl_list_remove(&touch->link);
 | 
					
						
							|  |  |  | 	free(touch);
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void
 | 
					
						
							|  |  |  | frame_destroy(struct frame *frame)
 | 
					
						
							|  |  |  | {
 | 
					
						
							|  |  |  | 	struct frame_button *button, *next;
 | 
					
						
							|  |  |  | 	struct frame_touch *touch, *next_touch;
 | 
					
						
							|  |  |  | 	struct frame_pointer *pointer, *next_pointer;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	wl_list_for_each_safe(button, next, &frame->buttons, link)
 | 
					
						
							|  |  |  | 		frame_button_destroy(button);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	wl_list_for_each_safe(touch, next_touch, &frame->touches, link)
 | 
					
						
							|  |  |  | 		frame_touch_destroy(touch);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	wl_list_for_each_safe(pointer, next_pointer, &frame->pointers, link)
 | 
					
						
							|  |  |  | 		frame_pointer_destroy(pointer);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	free(frame->title);
 | 
					
						
							|  |  |  | 	free(frame);
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct frame *
 | 
					
						
							|  |  |  | frame_create(struct theme *t, int32_t width, int32_t height, uint32_t buttons,
 | 
					
						
							|  |  |  | 	     const char *title)
 | 
					
						
							|  |  |  | {
 | 
					
						
							|  |  |  | 	struct frame *frame;
 | 
					
						
							|  |  |  | 	struct frame_button *button;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	frame = calloc(1, sizeof *frame);
 | 
					
						
							|  |  |  | 	if (!frame)
 | 
					
						
							|  |  |  | 		return NULL;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	frame->width = width;
 | 
					
						
							|  |  |  | 	frame->height = height;
 | 
					
						
							|  |  |  | 	frame->flags = 0;
 | 
					
						
							|  |  |  | 	frame->theme = t;
 | 
					
						
							|  |  |  | 	frame->status = FRAME_STATUS_REPAINT;
 | 
					
						
							|  |  |  | 	frame->geometry_dirty = 1;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	wl_list_init(&frame->buttons);
 | 
					
						
							|  |  |  | 	wl_list_init(&frame->pointers);
 | 
					
						
							|  |  |  | 	wl_list_init(&frame->touches);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (title) {
 | 
					
						
							|  |  |  | 		frame->title = strdup(title);
 | 
					
						
							|  |  |  | 		if (!frame->title)
 | 
					
						
							|  |  |  | 			goto free_frame;
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (title) {
 | 
					
						
							|  |  |  | 		button = frame_button_create(frame,
 | 
					
						
							|  |  |  | 					     DATADIR "/weston/icon_window.png",
 | 
					
						
							|  |  |  | 					     FRAME_STATUS_MENU,
 | 
					
						
							|  |  |  | 					     FRAME_BUTTON_CLICK_DOWN);
 | 
					
						
							|  |  |  | 		if (!button)
 | 
					
						
							|  |  |  | 			goto free_frame;
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (buttons & FRAME_BUTTON_CLOSE) {
 | 
					
						
							|  |  |  | 		button = frame_button_create(frame,
 | 
					
						
							|  |  |  | 					     DATADIR "/weston/sign_close.png",
 | 
					
						
							|  |  |  | 					     FRAME_STATUS_CLOSE,
 | 
					
						
							|  |  |  | 					     FRAME_BUTTON_ALIGN_RIGHT |
 | 
					
						
							|  |  |  | 					     FRAME_BUTTON_DECORATED);
 | 
					
						
							|  |  |  | 		if (!button)
 | 
					
						
							|  |  |  | 			goto free_frame;
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (buttons & FRAME_BUTTON_MAXIMIZE) {
 | 
					
						
							|  |  |  | 		button = frame_button_create(frame,
 | 
					
						
							|  |  |  | 					     DATADIR "/weston/sign_maximize.png",
 | 
					
						
							|  |  |  | 					     FRAME_STATUS_MAXIMIZE,
 | 
					
						
							|  |  |  | 					     FRAME_BUTTON_ALIGN_RIGHT |
 | 
					
						
							|  |  |  | 					     FRAME_BUTTON_DECORATED);
 | 
					
						
							|  |  |  | 		if (!button)
 | 
					
						
							|  |  |  | 			goto free_frame;
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (buttons & FRAME_BUTTON_MINIMIZE) {
 | 
					
						
							|  |  |  | 		button = frame_button_create(frame,
 | 
					
						
							|  |  |  | 					     DATADIR "/weston/sign_minimize.png",
 | 
					
						
							|  |  |  | 					     FRAME_STATUS_MINIMIZE,
 | 
					
						
							|  |  |  | 					     FRAME_BUTTON_ALIGN_RIGHT |
 | 
					
						
							|  |  |  | 					     FRAME_BUTTON_DECORATED);
 | 
					
						
							|  |  |  | 		if (!button)
 | 
					
						
							|  |  |  | 			goto free_frame;
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return frame;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | free_frame:
 | 
					
						
							|  |  |  | 	frame_destroy(frame);
 | 
					
						
							|  |  |  | 	return NULL;
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int
 | 
					
						
							|  |  |  | frame_set_title(struct frame *frame, const char *title)
 | 
					
						
							|  |  |  | {
 | 
					
						
							|  |  |  | 	char *dup = NULL;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (title) {
 | 
					
						
							|  |  |  | 		dup = strdup(title);
 | 
					
						
							|  |  |  | 		if (!dup)
 | 
					
						
							|  |  |  | 			return -1;
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	free(frame->title);
 | 
					
						
							|  |  |  | 	frame->title = dup;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	frame->geometry_dirty = 1;
 | 
					
						
							|  |  |  | 	frame->status |= FRAME_STATUS_REPAINT;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0;
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void
 | 
					
						
							|  |  |  | frame_set_flag(struct frame *frame, enum frame_flag flag)
 | 
					
						
							|  |  |  | {
 | 
					
						
							|  |  |  | 	if (flag & FRAME_FLAG_MAXIMIZED && !(frame->flags & FRAME_FLAG_MAXIMIZED))
 | 
					
						
							|  |  |  | 		frame->geometry_dirty = 1;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	frame->flags |= flag;
 | 
					
						
							|  |  |  | 	frame->status |= FRAME_STATUS_REPAINT;
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void
 | 
					
						
							|  |  |  | frame_unset_flag(struct frame *frame, enum frame_flag flag)
 | 
					
						
							|  |  |  | {
 | 
					
						
							|  |  |  | 	if (flag & FRAME_FLAG_MAXIMIZED && frame->flags & FRAME_FLAG_MAXIMIZED)
 | 
					
						
							|  |  |  | 		frame->geometry_dirty = 1;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	frame->flags &= ~flag;
 | 
					
						
							|  |  |  | 	frame->status |= FRAME_STATUS_REPAINT;
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void
 | 
					
						
							|  |  |  | frame_resize(struct frame *frame, int32_t width, int32_t height)
 | 
					
						
							|  |  |  | {
 | 
					
						
							|  |  |  | 	frame->width = width;
 | 
					
						
							|  |  |  | 	frame->height = height;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	frame->geometry_dirty = 1;
 | 
					
						
							|  |  |  | 	frame->status |= FRAME_STATUS_REPAINT;
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void
 | 
					
						
							|  |  |  | frame_resize_inside(struct frame *frame, int32_t width, int32_t height)
 | 
					
						
							|  |  |  | {
 | 
					
						
							|  |  |  | 	struct theme *t = frame->theme;
 | 
					
						
							|  |  |  | 	int decoration_width, decoration_height, titlebar_height;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (frame->title || !wl_list_empty(&frame->buttons))
 | 
					
						
							|  |  |  | 		titlebar_height = t->titlebar_height;
 | 
					
						
							|  |  |  | 	else
 | 
					
						
							|  |  |  | 		titlebar_height = t->width;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (frame->flags & FRAME_FLAG_MAXIMIZED) {
 | 
					
						
							|  |  |  | 		decoration_width = t->width * 2;
 | 
					
						
							|  |  |  | 		decoration_height = t->width + titlebar_height;
 | 
					
						
							|  |  |  | 	} else {
 | 
					
						
							|  |  |  | 		decoration_width = (t->width + t->margin) * 2;
 | 
					
						
							|  |  |  | 		decoration_height = t->width +
 | 
					
						
							|  |  |  | 			titlebar_height + t->margin * 2;
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	frame_resize(frame, width + decoration_width,
 | 
					
						
							|  |  |  | 		     height + decoration_height);
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int32_t
 | 
					
						
							|  |  |  | frame_width(struct frame *frame)
 | 
					
						
							|  |  |  | {
 | 
					
						
							|  |  |  | 	return frame->width;
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int32_t
 | 
					
						
							|  |  |  | frame_height(struct frame *frame)
 | 
					
						
							|  |  |  | {
 | 
					
						
							|  |  |  | 	return frame->height;
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void
 | 
					
						
							|  |  |  | frame_refresh_geometry(struct frame *frame)
 | 
					
						
							|  |  |  | {
 | 
					
						
							|  |  |  | 	struct frame_button *button;
 | 
					
						
							|  |  |  | 	struct theme *t = frame->theme;
 | 
					
						
							|  |  |  | 	int x_l, x_r, y, w, h, titlebar_height;
 | 
					
						
							|  |  |  | 	int32_t decoration_width, decoration_height;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!frame->geometry_dirty)
 | 
					
						
							|  |  |  | 		return;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (frame->title || !wl_list_empty(&frame->buttons))
 | 
					
						
							|  |  |  | 		titlebar_height = t->titlebar_height;
 | 
					
						
							|  |  |  | 	else
 | 
					
						
							|  |  |  | 		titlebar_height = t->width;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (frame->flags & FRAME_FLAG_MAXIMIZED) {
 | 
					
						
							|  |  |  | 		decoration_width = t->width * 2;
 | 
					
						
							|  |  |  | 		decoration_height = t->width + titlebar_height;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		frame->interior.x = t->width;
 | 
					
						
							|  |  |  | 		frame->interior.y = titlebar_height;
 | 
					
						
							|  |  |  | 		frame->interior.width = frame->width - decoration_width;
 | 
					
						
							|  |  |  | 		frame->interior.height = frame->height - decoration_height;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		frame->opaque_margin = 0;
 | 
					
						
							|  |  |  | 		frame->shadow_margin = 0;
 | 
					
						
							|  |  |  | 	} else {
 | 
					
						
							|  |  |  | 		decoration_width = (t->width + t->margin) * 2;
 | 
					
						
							|  |  |  | 		decoration_height = t->width + titlebar_height + t->margin * 2;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		frame->interior.x = t->width + t->margin;
 | 
					
						
							|  |  |  | 		frame->interior.y = titlebar_height + t->margin;
 | 
					
						
							|  |  |  | 		frame->interior.width = frame->width - decoration_width;
 | 
					
						
							|  |  |  | 		frame->interior.height = frame->height - decoration_height;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		frame->opaque_margin = t->margin + t->frame_radius;
 | 
					
						
							|  |  |  | 		frame->shadow_margin = t->margin;
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	x_r = frame->width - t->width - frame->shadow_margin;
 | 
					
						
							|  |  |  | 	x_l = t->width + frame->shadow_margin;
 | 
					
						
							|  |  |  | 	y = t->width + frame->shadow_margin;
 | 
					
						
							|  |  |  | 	wl_list_for_each(button, &frame->buttons, link) {
 | 
					
						
							|  |  |  | 		const int button_padding = 4;
 | 
					
						
							|  |  |  | 		w = cairo_image_surface_get_width(button->icon);
 | 
					
						
							|  |  |  | 		h = cairo_image_surface_get_height(button->icon);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (button->flags & FRAME_BUTTON_DECORATED)
 | 
					
						
							|  |  |  | 			w += 10;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (button->flags & FRAME_BUTTON_ALIGN_RIGHT) {
 | 
					
						
							|  |  |  | 			x_r -= w;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			button->allocation.x = x_r;
 | 
					
						
							|  |  |  | 			button->allocation.y = y;
 | 
					
						
							|  |  |  | 			button->allocation.width = w + 1;
 | 
					
						
							|  |  |  | 			button->allocation.height = h + 1;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			x_r -= button_padding;
 | 
					
						
							|  |  |  | 		} else {
 | 
					
						
							|  |  |  | 			button->allocation.x = x_l;
 | 
					
						
							|  |  |  | 			button->allocation.y = y;
 | 
					
						
							|  |  |  | 			button->allocation.width = w + 1;
 | 
					
						
							|  |  |  | 			button->allocation.height = h + 1;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			x_l += w;
 | 
					
						
							|  |  |  | 			x_l += button_padding;
 | 
					
						
							|  |  |  | 		}
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	frame->geometry_dirty = 0;
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void
 | 
					
						
							|  |  |  | frame_interior(struct frame *frame, int32_t *x, int32_t *y,
 | 
					
						
							|  |  |  | 		int32_t *width, int32_t *height)
 | 
					
						
							|  |  |  | {
 | 
					
						
							|  |  |  | 	frame_refresh_geometry(frame);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (x)
 | 
					
						
							|  |  |  | 		*x = frame->interior.x;
 | 
					
						
							|  |  |  | 	if (y)
 | 
					
						
							|  |  |  | 		*y = frame->interior.y;
 | 
					
						
							|  |  |  | 	if (width)
 | 
					
						
							|  |  |  | 		*width = frame->interior.width;
 | 
					
						
							|  |  |  | 	if (height)
 | 
					
						
							|  |  |  | 		*height = frame->interior.height;
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void
 | 
					
						
							|  |  |  | frame_input_rect(struct frame *frame, int32_t *x, int32_t *y,
 | 
					
						
							|  |  |  | 		 int32_t *width, int32_t *height)
 | 
					
						
							|  |  |  | {
 | 
					
						
							|  |  |  | 	frame_refresh_geometry(frame);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (x)
 | 
					
						
							|  |  |  | 		*x = frame->shadow_margin;
 | 
					
						
							|  |  |  | 	if (y)
 | 
					
						
							|  |  |  | 		*y = frame->shadow_margin;
 | 
					
						
							|  |  |  | 	if (width)
 | 
					
						
							|  |  |  | 		*width = frame->width - frame->shadow_margin * 2;
 | 
					
						
							|  |  |  | 	if (height)
 | 
					
						
							|  |  |  | 		*height = frame->height - frame->shadow_margin * 2;
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void
 | 
					
						
							|  |  |  | frame_opaque_rect(struct frame *frame, int32_t *x, int32_t *y,
 | 
					
						
							|  |  |  | 		  int32_t *width, int32_t *height)
 | 
					
						
							|  |  |  | {
 | 
					
						
							|  |  |  | 	frame_refresh_geometry(frame);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (x)
 | 
					
						
							|  |  |  | 		*x = frame->opaque_margin;
 | 
					
						
							|  |  |  | 	if (y)
 | 
					
						
							|  |  |  | 		*y = frame->opaque_margin;
 | 
					
						
							|  |  |  | 	if (width)
 | 
					
						
							|  |  |  | 		*width = frame->width - frame->opaque_margin * 2;
 | 
					
						
							|  |  |  | 	if (height)
 | 
					
						
							|  |  |  | 		*height = frame->height - frame->opaque_margin * 2;
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int
 | 
					
						
							|  |  |  | frame_get_shadow_margin(struct frame *frame)
 | 
					
						
							|  |  |  | {
 | 
					
						
							|  |  |  | 	frame_refresh_geometry(frame);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return frame->shadow_margin;
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | uint32_t
 | 
					
						
							|  |  |  | frame_status(struct frame *frame)
 | 
					
						
							|  |  |  | {
 | 
					
						
							|  |  |  | 	return frame->status;
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void
 | 
					
						
							|  |  |  | frame_status_clear(struct frame *frame, enum frame_status status)
 | 
					
						
							|  |  |  | {
 | 
					
						
							|  |  |  | 	frame->status &= ~status;
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct frame_button *
 | 
					
						
							|  |  |  | frame_find_button(struct frame *frame, int x, int y)
 | 
					
						
							|  |  |  | {
 | 
					
						
							|  |  |  | 	struct frame_button *button;
 | 
					
						
							|  |  |  | 	int rel_x, rel_y;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	wl_list_for_each(button, &frame->buttons, link) {
 | 
					
						
							|  |  |  | 		rel_x = x - button->allocation.x;
 | 
					
						
							|  |  |  | 		rel_y = y - button->allocation.y;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (0 <= rel_x && rel_x < button->allocation.width &&
 | 
					
						
							|  |  |  | 		    0 <= rel_y && rel_y < button->allocation.height)
 | 
					
						
							|  |  |  | 			return button;
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return NULL;
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | enum theme_location
 | 
					
						
							|  |  |  | frame_pointer_enter(struct frame *frame, void *data, int x, int y)
 | 
					
						
							|  |  |  | {
 | 
					
						
							|  |  |  | 	return frame_pointer_motion(frame, data, x, y);
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | enum theme_location
 | 
					
						
							|  |  |  | frame_pointer_motion(struct frame *frame, void *data, int x, int y)
 | 
					
						
							|  |  |  | {
 | 
					
						
							|  |  |  | 	struct frame_pointer *pointer = frame_pointer_get(frame, data);
 | 
					
						
							|  |  |  | 	struct frame_button *button = frame_find_button(frame, x, y);
 | 
					
						
							|  |  |  | 	enum theme_location location;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	location = theme_get_location(frame->theme, x, y,
 | 
					
						
							|  |  |  | 				      frame->width, frame->height,
 | 
					
						
							|  |  |  | 				      frame->flags & FRAME_FLAG_MAXIMIZED ?
 | 
					
						
							|  |  |  | 				      THEME_FRAME_MAXIMIZED : 0);
 | 
					
						
							|  |  |  | 	if (!pointer)
 | 
					
						
							|  |  |  | 		return location;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	pointer->x = x;
 | 
					
						
							|  |  |  | 	pointer->y = y;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (pointer->hover_button == button)
 | 
					
						
							|  |  |  | 		return location;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (pointer->hover_button)
 | 
					
						
							|  |  |  | 		frame_button_leave(pointer->hover_button, pointer);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	pointer->hover_button = button;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (pointer->hover_button)
 | 
					
						
							|  |  |  | 		frame_button_enter(pointer->hover_button);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return location;
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void
 | 
					
						
							|  |  |  | frame_pointer_button_destroy(struct frame_pointer_button *button)
 | 
					
						
							|  |  |  | {
 | 
					
						
							|  |  |  | 	wl_list_remove(&button->link);
 | 
					
						
							|  |  |  | 	free(button);
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void
 | 
					
						
							|  |  |  | frame_pointer_button_press(struct frame *frame, struct frame_pointer *pointer,
 | 
					
						
							|  |  |  | 			   struct frame_pointer_button *button)
 | 
					
						
							|  |  |  | {
 | 
					
						
							|  |  |  | 	if (button->button == BTN_RIGHT) {
 | 
					
						
							|  |  |  | 		if (button->press_location == THEME_LOCATION_TITLEBAR)
 | 
					
						
							|  |  |  | 			frame->status |= FRAME_STATUS_MENU;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		frame_pointer_button_destroy(button);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	} else if (button->button == BTN_LEFT) {
 | 
					
						
							|  |  |  | 		if (pointer->hover_button) {
 | 
					
						
							|  |  |  | 			frame_button_press(pointer->hover_button);
 | 
					
						
							|  |  |  | 		} else {
 | 
					
						
							|  |  |  | 			switch (button->press_location) {
 | 
					
						
							|  |  |  | 			case THEME_LOCATION_TITLEBAR:
 | 
					
						
							|  |  |  | 				frame->status |= FRAME_STATUS_MOVE;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				frame_pointer_button_destroy(button);
 | 
					
						
							|  |  |  | 				break;
 | 
					
						
							|  |  |  | 			case THEME_LOCATION_RESIZING_TOP:
 | 
					
						
							|  |  |  | 			case THEME_LOCATION_RESIZING_BOTTOM:
 | 
					
						
							|  |  |  | 			case THEME_LOCATION_RESIZING_LEFT:
 | 
					
						
							|  |  |  | 			case THEME_LOCATION_RESIZING_RIGHT:
 | 
					
						
							|  |  |  | 			case THEME_LOCATION_RESIZING_TOP_LEFT:
 | 
					
						
							|  |  |  | 			case THEME_LOCATION_RESIZING_TOP_RIGHT:
 | 
					
						
							|  |  |  | 			case THEME_LOCATION_RESIZING_BOTTOM_LEFT:
 | 
					
						
							|  |  |  | 			case THEME_LOCATION_RESIZING_BOTTOM_RIGHT:
 | 
					
						
							|  |  |  | 				frame->status |= FRAME_STATUS_RESIZE;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				frame_pointer_button_destroy(button);
 | 
					
						
							|  |  |  | 				break;
 | 
					
						
							|  |  |  | 			default:
 | 
					
						
							|  |  |  | 				break;
 | 
					
						
							|  |  |  | 			}
 | 
					
						
							|  |  |  | 		}
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void
 | 
					
						
							|  |  |  | frame_pointer_button_release(struct frame *frame, struct frame_pointer *pointer,
 | 
					
						
							|  |  |  | 			     struct frame_pointer_button *button)
 | 
					
						
							|  |  |  | {
 | 
					
						
							|  |  |  | 	if (button->button == BTN_LEFT && button->frame_button) {
 | 
					
						
							|  |  |  | 		if (button->frame_button == pointer->hover_button)
 | 
					
						
							|  |  |  | 			frame_button_release(button->frame_button);
 | 
					
						
							|  |  |  | 		else
 | 
					
						
							|  |  |  | 			frame_button_cancel(button->frame_button);
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void
 | 
					
						
							|  |  |  | frame_pointer_button_cancel(struct frame *frame, struct frame_pointer *pointer,
 | 
					
						
							|  |  |  | 			    struct frame_pointer_button *button)
 | 
					
						
							|  |  |  | {
 | 
					
						
							|  |  |  | 	if (button->frame_button)
 | 
					
						
							|  |  |  | 		frame_button_cancel(button->frame_button);
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void
 | 
					
						
							|  |  |  | frame_pointer_leave(struct frame *frame, void *data)
 | 
					
						
							|  |  |  | {
 | 
					
						
							|  |  |  | 	struct frame_pointer *pointer = frame_pointer_get(frame, data);
 | 
					
						
							|  |  |  | 	struct frame_pointer_button *button, *next;
 | 
					
						
							|  |  |  | 	if (!pointer)
 | 
					
						
							|  |  |  | 		return;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (pointer->hover_button)
 | 
					
						
							|  |  |  | 		frame_button_leave(pointer->hover_button, pointer);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	wl_list_for_each_safe(button, next, &pointer->down_buttons, link) {
 | 
					
						
							|  |  |  | 		frame_pointer_button_cancel(frame, pointer, button);
 | 
					
						
							|  |  |  | 		frame_pointer_button_destroy(button);
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	frame_pointer_destroy(pointer);
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | enum theme_location
 | 
					
						
							|  |  |  | frame_pointer_button(struct frame *frame, void *data,
 | 
					
						
							|  |  |  | 		     uint32_t btn, enum frame_button_state state)
 | 
					
						
							|  |  |  | {
 | 
					
						
							|  |  |  | 	struct frame_pointer *pointer = frame_pointer_get(frame, data);
 | 
					
						
							|  |  |  | 	struct frame_pointer_button *button;
 | 
					
						
							|  |  |  | 	enum theme_location location = THEME_LOCATION_EXTERIOR;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!pointer)
 | 
					
						
							|  |  |  | 		return location;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	location = theme_get_location(frame->theme, pointer->x, pointer->y,
 | 
					
						
							|  |  |  | 				      frame->width, frame->height,
 | 
					
						
							|  |  |  | 				      frame->flags & FRAME_FLAG_MAXIMIZED ?
 | 
					
						
							|  |  |  | 				      THEME_FRAME_MAXIMIZED : 0);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (state == FRAME_BUTTON_PRESSED) {
 | 
					
						
							|  |  |  | 		button = malloc(sizeof *button);
 | 
					
						
							|  |  |  | 		if (!button)
 | 
					
						
							|  |  |  | 			return location;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		button->button = btn;
 | 
					
						
							|  |  |  | 		button->press_location = location;
 | 
					
						
							|  |  |  | 		button->frame_button = pointer->hover_button;
 | 
					
						
							|  |  |  | 		wl_list_insert(&pointer->down_buttons, &button->link);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		frame_pointer_button_press(frame, pointer, button);
 | 
					
						
							|  |  |  | 	} else if (state == FRAME_BUTTON_RELEASED) {
 | 
					
						
							|  |  |  | 		button = NULL;
 | 
					
						
							|  |  |  | 		wl_list_for_each(button, &pointer->down_buttons, link)
 | 
					
						
							|  |  |  | 			if (button->button == btn)
 | 
					
						
							|  |  |  | 				break;
 | 
					
						
							|  |  |  | 		/* Make sure we didn't hit the end */
 | 
					
						
							|  |  |  | 		if (&button->link == &pointer->down_buttons)
 | 
					
						
							|  |  |  | 			return location;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		location = button->press_location;
 | 
					
						
							|  |  |  | 		frame_pointer_button_release(frame, pointer, button);
 | 
					
						
							|  |  |  | 		frame_pointer_button_destroy(button);
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return location;
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void
 | 
					
						
							|  |  |  | frame_touch_down(struct frame *frame, void *data, int32_t id, int x, int y)
 | 
					
						
							|  |  |  | {
 | 
					
						
							|  |  |  | 	struct frame_touch *touch = frame_touch_get(frame, data);
 | 
					
						
							|  |  |  | 	struct frame_button *button = frame_find_button(frame, x, y);
 | 
					
						
							|  |  |  | 	enum theme_location location;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (id > 0)
 | 
					
						
							|  |  |  | 		return;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (touch && button) {
 | 
					
						
							|  |  |  | 		touch->button = button;
 | 
					
						
							|  |  |  | 		frame_button_press(touch->button);
 | 
					
						
							|  |  |  | 		return;
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	location = theme_get_location(frame->theme, x, y,
 | 
					
						
							|  |  |  | 				      frame->width, frame->height,
 | 
					
						
							|  |  |  | 				      frame->flags & FRAME_FLAG_MAXIMIZED ?
 | 
					
						
							|  |  |  | 				      THEME_FRAME_MAXIMIZED : 0);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	switch (location) {
 | 
					
						
							|  |  |  | 	case THEME_LOCATION_TITLEBAR:
 | 
					
						
							|  |  |  | 		frame->status |= FRAME_STATUS_MOVE;
 | 
					
						
							|  |  |  | 		break;
 | 
					
						
							|  |  |  | 	case THEME_LOCATION_RESIZING_TOP:
 | 
					
						
							|  |  |  | 	case THEME_LOCATION_RESIZING_BOTTOM:
 | 
					
						
							|  |  |  | 	case THEME_LOCATION_RESIZING_LEFT:
 | 
					
						
							|  |  |  | 	case THEME_LOCATION_RESIZING_RIGHT:
 | 
					
						
							|  |  |  | 	case THEME_LOCATION_RESIZING_TOP_LEFT:
 | 
					
						
							|  |  |  | 	case THEME_LOCATION_RESIZING_TOP_RIGHT:
 | 
					
						
							|  |  |  | 	case THEME_LOCATION_RESIZING_BOTTOM_LEFT:
 | 
					
						
							|  |  |  | 	case THEME_LOCATION_RESIZING_BOTTOM_RIGHT:
 | 
					
						
							|  |  |  | 		frame->status |= FRAME_STATUS_RESIZE;
 | 
					
						
							|  |  |  | 		break;
 | 
					
						
							|  |  |  | 	default:
 | 
					
						
							|  |  |  | 		break;
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void
 | 
					
						
							|  |  |  | frame_touch_up(struct frame *frame, void *data, int32_t id)
 | 
					
						
							|  |  |  | {
 | 
					
						
							|  |  |  | 	struct frame_touch *touch = frame_touch_get(frame, data);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (id > 0)
 | 
					
						
							|  |  |  | 		return;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (touch && touch->button) {
 | 
					
						
							|  |  |  | 		frame_button_release(touch->button);
 | 
					
						
							|  |  |  | 		frame_touch_destroy(touch);
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | enum theme_location
 | 
					
						
							|  |  |  | frame_double_click(struct frame *frame, void *data,
 | 
					
						
							|  |  |  | 		   uint32_t btn, enum frame_button_state state)
 | 
					
						
							|  |  |  | {
 | 
					
						
							|  |  |  | 	struct frame_pointer *pointer = frame_pointer_get(frame, data);
 | 
					
						
							|  |  |  | 	struct frame_button *button;
 | 
					
						
							|  |  |  | 	enum theme_location location = THEME_LOCATION_EXTERIOR;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	location = theme_get_location(frame->theme, pointer->x, pointer->y,
 | 
					
						
							|  |  |  | 				      frame->width, frame->height,
 | 
					
						
							|  |  |  | 				      frame->flags & FRAME_FLAG_MAXIMIZED ?
 | 
					
						
							|  |  |  | 				      THEME_FRAME_MAXIMIZED : 0);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	button = frame_find_button(frame, pointer->x, pointer->y);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (location != THEME_LOCATION_TITLEBAR || btn != BTN_LEFT)
 | 
					
						
							|  |  |  | 		return location;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (state == FRAME_BUTTON_PRESSED) {
 | 
					
						
							|  |  |  | 		if (button)
 | 
					
						
							|  |  |  | 			frame_button_press(button);
 | 
					
						
							|  |  |  | 		else
 | 
					
						
							|  |  |  | 			frame->status |= FRAME_STATUS_MAXIMIZE;
 | 
					
						
							|  |  |  | 	} else if (state == FRAME_BUTTON_RELEASED) {
 | 
					
						
							|  |  |  | 		if (button)
 | 
					
						
							|  |  |  | 			frame_button_release(button);
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return location;
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void
 | 
					
						
							|  |  |  | frame_repaint(struct frame *frame, cairo_t *cr)
 | 
					
						
							|  |  |  | {
 | 
					
						
							|  |  |  | 	struct frame_button *button;
 | 
					
						
							|  |  |  | 	uint32_t flags = 0;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	frame_refresh_geometry(frame);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (frame->flags & FRAME_FLAG_MAXIMIZED)
 | 
					
						
							|  |  |  | 		flags |= THEME_FRAME_MAXIMIZED;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (frame->flags & FRAME_FLAG_ACTIVE)
 | 
					
						
							|  |  |  | 		flags |= THEME_FRAME_ACTIVE;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	cairo_save(cr);
 | 
					
						
							|  |  |  | 	theme_render_frame(frame->theme, cr, frame->width, frame->height,
 | 
					
						
							|  |  |  | 			   frame->title, &frame->buttons, flags);
 | 
					
						
							|  |  |  | 	cairo_restore(cr);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	wl_list_for_each(button, &frame->buttons, link)
 | 
					
						
							|  |  |  | 		frame_button_repaint(button, cr);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	frame_status_clear(frame, FRAME_STATUS_REPAINT);
 | 
					
						
							|  |  |  | }
 |