1 /*
2  * Copyright © 2008 Kristian Høgsberg
3  * Copyright © 2012-2013 Collabora, Ltd.
4  * Copyright © 2013 Jason Ekstrand
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining
7  * a copy of this software and associated documentation files (the
8  * "Software"), to deal in the Software without restriction, including
9  * without limitation the rights to use, copy, modify, merge, publish,
10  * distribute, sublicense, and/or sell copies of the Software, and to
11  * permit persons to whom the Software is furnished to do so, subject to
12  * the following conditions:
13  *
14  * The above copyright notice and this permission notice (including the
15  * next paragraph) shall be included in all copies or substantial
16  * portions of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21  * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
22  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
23  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25  * SOFTWARE.
26  */
27 
28 #include "config.h"
29 
30 #include <stdlib.h>
31 #include <string.h>
32 #include <wayland-util.h>
33 #include <linux/input.h>
34 
35 #include "cairo-util.h"
36 
37 enum frame_button_flags {
38 	FRAME_BUTTON_ALIGN_RIGHT = 0x1,
39 	FRAME_BUTTON_DECORATED = 0x2,
40 	FRAME_BUTTON_CLICK_DOWN = 0x4,
41 };
42 
43 struct frame_button {
44 	struct frame *frame;
45 	struct wl_list link;	/* buttons_list */
46 
47 	cairo_surface_t *icon;
48 	enum frame_button_flags flags;
49 	int hover_count;
50 	int press_count;
51 
52 	struct {
53 		int x, y;
54 		int width, height;
55 	} allocation;
56 
57 	enum frame_status status_effect;
58 };
59 
60 struct frame_pointer_button {
61 	struct wl_list link;
62 	uint32_t button;
63 	enum theme_location press_location;
64 	struct frame_button *frame_button;
65 };
66 
67 struct frame_pointer {
68 	struct wl_list link;
69 	void *data;
70 
71 	int x, y;
72 
73 	struct frame_button *hover_button;
74 	struct wl_list down_buttons;
75 };
76 
77 struct frame_touch {
78 	struct wl_list link;
79 	void *data;
80 
81 	int x, y;
82 
83 	struct frame_button *button;
84 };
85 
86 struct frame {
87 	int32_t width, height;
88 	char *title;
89 	uint32_t flags;
90 	struct theme *theme;
91 
92 	struct {
93 		int32_t x, y;
94 		int32_t width, height;
95 	} interior;
96 	int shadow_margin;
97 	int opaque_margin;
98 	int geometry_dirty;
99 
100 	uint32_t status;
101 
102 	struct wl_list buttons;
103 	struct wl_list pointers;
104 	struct wl_list touches;
105 };
106 
107 static struct frame_button *
frame_button_create(struct frame * frame,const char * icon,enum frame_status status_effect,enum frame_button_flags flags)108 frame_button_create(struct frame *frame, const char *icon,
109 		    enum frame_status status_effect,
110 		    enum frame_button_flags flags)
111 {
112 	struct frame_button *button;
113 
114 	button = calloc(1, sizeof *button);
115 	if (!button)
116 		return NULL;
117 
118 	button->icon = cairo_image_surface_create_from_png(icon);
119 	if (!button->icon) {
120 		free(button);
121 		return NULL;
122 	}
123 
124 	button->frame = frame;
125 	button->flags = flags;
126 	button->status_effect = status_effect;
127 
128 	wl_list_insert(frame->buttons.prev, &button->link);
129 
130 	return button;
131 }
132 
133 static void
frame_button_destroy(struct frame_button * button)134 frame_button_destroy(struct frame_button *button)
135 {
136 	cairo_surface_destroy(button->icon);
137 	free(button);
138 }
139 
140 static void
frame_button_enter(struct frame_button * button)141 frame_button_enter(struct frame_button *button)
142 {
143 	if (!button->hover_count)
144 		button->frame->status |= FRAME_STATUS_REPAINT;
145 	button->hover_count++;
146 }
147 
148 static void
frame_button_leave(struct frame_button * button,struct frame_pointer * pointer)149 frame_button_leave(struct frame_button *button, struct frame_pointer *pointer)
150 {
151 	button->hover_count--;
152 	if (!button->hover_count)
153 		button->frame->status |= FRAME_STATUS_REPAINT;
154 }
155 
156 static void
frame_button_press(struct frame_button * button)157 frame_button_press(struct frame_button *button)
158 {
159 	if (!button->press_count)
160 		button->frame->status |= FRAME_STATUS_REPAINT;
161 	button->press_count++;
162 
163 	if (button->flags & FRAME_BUTTON_CLICK_DOWN)
164 		button->frame->status |= button->status_effect;
165 }
166 
167 static void
frame_button_release(struct frame_button * button)168 frame_button_release(struct frame_button *button)
169 {
170 	button->press_count--;
171 	if (button->press_count)
172 		return;
173 
174 	button->frame->status |= FRAME_STATUS_REPAINT;
175 
176 	if (!(button->flags & FRAME_BUTTON_CLICK_DOWN))
177 		button->frame->status |= button->status_effect;
178 }
179 
180 static void
frame_button_cancel(struct frame_button * button)181 frame_button_cancel(struct frame_button *button)
182 {
183 	button->press_count--;
184 	if (!button->press_count)
185 		button->frame->status |= FRAME_STATUS_REPAINT;
186 }
187 
188 static void
frame_button_repaint(struct frame_button * button,cairo_t * cr)189 frame_button_repaint(struct frame_button *button, cairo_t *cr)
190 {
191 	int x, y;
192 
193 	if (!button->allocation.width)
194 		return;
195 	if (!button->allocation.height)
196 		return;
197 
198 	x = button->allocation.x;
199 	y = button->allocation.y;
200 
201 	cairo_save(cr);
202 
203 	if (button->flags & FRAME_BUTTON_DECORATED) {
204 		cairo_set_line_width(cr, 1);
205 
206 		cairo_set_source_rgb(cr, 0.0, 0.0, 0.0);
207 		cairo_rectangle(cr, x, y, 25, 16);
208 
209 		cairo_stroke_preserve(cr);
210 
211 		if (button->press_count) {
212 			cairo_set_source_rgb(cr, 0.7, 0.7, 0.7);
213 		} else if (button->hover_count) {
214 			cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
215 		} else {
216 			cairo_set_source_rgb(cr, 0.88, 0.88, 0.88);
217 		}
218 
219 		cairo_fill (cr);
220 
221 		x += 4;
222 	}
223 
224 	cairo_set_source_surface(cr, button->icon, x, y);
225 	cairo_paint(cr);
226 
227 	cairo_restore(cr);
228 }
229 
230 static struct frame_pointer *
frame_pointer_get(struct frame * frame,void * data)231 frame_pointer_get(struct frame *frame, void *data)
232 {
233 	struct frame_pointer *pointer;
234 
235 	wl_list_for_each(pointer, &frame->pointers, link)
236 		if (pointer->data == data)
237 			return pointer;
238 
239 	pointer = calloc(1, sizeof *pointer);
240 	if (!pointer)
241 		return NULL;
242 
243 	pointer->data = data;
244 	wl_list_init(&pointer->down_buttons);
245 	wl_list_insert(&frame->pointers, &pointer->link);
246 
247 	return pointer;
248 }
249 
250 static void
frame_pointer_destroy(struct frame_pointer * pointer)251 frame_pointer_destroy(struct frame_pointer *pointer)
252 {
253 	wl_list_remove(&pointer->link);
254 	free(pointer);
255 }
256 
257 static struct frame_touch *
frame_touch_get(struct frame * frame,void * data)258 frame_touch_get(struct frame *frame, void *data)
259 {
260 	struct frame_touch *touch;
261 
262 	wl_list_for_each(touch, &frame->touches, link)
263 		if (touch->data == data)
264 			return touch;
265 
266 	touch = calloc(1, sizeof *touch);
267 	if (!touch)
268 		return NULL;
269 
270 	touch->data = data;
271 	wl_list_insert(&frame->touches, &touch->link);
272 
273 	return touch;
274 }
275 
276 static void
frame_touch_destroy(struct frame_touch * touch)277 frame_touch_destroy(struct frame_touch *touch)
278 {
279 	wl_list_remove(&touch->link);
280 	free(touch);
281 }
282 
283 void
frame_destroy(struct frame * frame)284 frame_destroy(struct frame *frame)
285 {
286 	struct frame_button *button, *next;
287 	struct frame_touch *touch, *next_touch;
288 	struct frame_pointer *pointer, *next_pointer;
289 
290 	wl_list_for_each_safe(button, next, &frame->buttons, link)
291 		frame_button_destroy(button);
292 
293 	wl_list_for_each_safe(touch, next_touch, &frame->touches, link)
294 		frame_touch_destroy(touch);
295 
296 	wl_list_for_each_safe(pointer, next_pointer, &frame->pointers, link)
297 		frame_pointer_destroy(pointer);
298 
299 	free(frame->title);
300 	free(frame);
301 }
302 
303 struct frame *
frame_create(struct theme * t,int32_t width,int32_t height,uint32_t buttons,const char * title)304 frame_create(struct theme *t, int32_t width, int32_t height, uint32_t buttons,
305 	     const char *title)
306 {
307 	struct frame *frame;
308 	struct frame_button *button;
309 
310 	frame = calloc(1, sizeof *frame);
311 	if (!frame)
312 		return NULL;
313 
314 	frame->width = width;
315 	frame->height = height;
316 	frame->flags = 0;
317 	frame->theme = t;
318 	frame->status = FRAME_STATUS_REPAINT;
319 	frame->geometry_dirty = 1;
320 
321 	wl_list_init(&frame->buttons);
322 	wl_list_init(&frame->pointers);
323 	wl_list_init(&frame->touches);
324 
325 	if (title) {
326 		frame->title = strdup(title);
327 		if (!frame->title)
328 			goto free_frame;
329 	}
330 
331 	if (title) {
332 		button = frame_button_create(frame,
333 					     DATADIR "/weston/icon_window.png",
334 					     FRAME_STATUS_MENU,
335 					     FRAME_BUTTON_CLICK_DOWN);
336 		if (!button)
337 			goto free_frame;
338 	}
339 
340 	if (buttons & FRAME_BUTTON_CLOSE) {
341 		button = frame_button_create(frame,
342 					     DATADIR "/weston/sign_close.png",
343 					     FRAME_STATUS_CLOSE,
344 					     FRAME_BUTTON_ALIGN_RIGHT |
345 					     FRAME_BUTTON_DECORATED);
346 		if (!button)
347 			goto free_frame;
348 	}
349 
350 	if (buttons & FRAME_BUTTON_MAXIMIZE) {
351 		button = frame_button_create(frame,
352 					     DATADIR "/weston/sign_maximize.png",
353 					     FRAME_STATUS_MAXIMIZE,
354 					     FRAME_BUTTON_ALIGN_RIGHT |
355 					     FRAME_BUTTON_DECORATED);
356 		if (!button)
357 			goto free_frame;
358 	}
359 
360 	if (buttons & FRAME_BUTTON_MINIMIZE) {
361 		button = frame_button_create(frame,
362 					     DATADIR "/weston/sign_minimize.png",
363 					     FRAME_STATUS_MINIMIZE,
364 					     FRAME_BUTTON_ALIGN_RIGHT |
365 					     FRAME_BUTTON_DECORATED);
366 		if (!button)
367 			goto free_frame;
368 	}
369 
370 	return frame;
371 
372 free_frame:
373 	frame_destroy(frame);
374 	return NULL;
375 }
376 
377 int
frame_set_title(struct frame * frame,const char * title)378 frame_set_title(struct frame *frame, const char *title)
379 {
380 	char *dup = NULL;
381 
382 	if (title) {
383 		dup = strdup(title);
384 		if (!dup)
385 			return -1;
386 	}
387 
388 	free(frame->title);
389 	frame->title = dup;
390 
391 	frame->geometry_dirty = 1;
392 	frame->status |= FRAME_STATUS_REPAINT;
393 
394 	return 0;
395 }
396 
397 void
frame_set_flag(struct frame * frame,enum frame_flag flag)398 frame_set_flag(struct frame *frame, enum frame_flag flag)
399 {
400 	if (flag & FRAME_FLAG_MAXIMIZED && !(frame->flags & FRAME_FLAG_MAXIMIZED))
401 		frame->geometry_dirty = 1;
402 
403 	frame->flags |= flag;
404 	frame->status |= FRAME_STATUS_REPAINT;
405 }
406 
407 void
frame_unset_flag(struct frame * frame,enum frame_flag flag)408 frame_unset_flag(struct frame *frame, enum frame_flag flag)
409 {
410 	if (flag & FRAME_FLAG_MAXIMIZED && frame->flags & FRAME_FLAG_MAXIMIZED)
411 		frame->geometry_dirty = 1;
412 
413 	frame->flags &= ~flag;
414 	frame->status |= FRAME_STATUS_REPAINT;
415 }
416 
417 void
frame_resize(struct frame * frame,int32_t width,int32_t height)418 frame_resize(struct frame *frame, int32_t width, int32_t height)
419 {
420 	frame->width = width;
421 	frame->height = height;
422 
423 	frame->geometry_dirty = 1;
424 	frame->status |= FRAME_STATUS_REPAINT;
425 }
426 
427 void
frame_resize_inside(struct frame * frame,int32_t width,int32_t height)428 frame_resize_inside(struct frame *frame, int32_t width, int32_t height)
429 {
430 	struct theme *t = frame->theme;
431 	int decoration_width, decoration_height, titlebar_height;
432 
433 	if (frame->title || !wl_list_empty(&frame->buttons))
434 		titlebar_height = t->titlebar_height;
435 	else
436 		titlebar_height = t->width;
437 
438 	if (frame->flags & FRAME_FLAG_MAXIMIZED) {
439 		decoration_width = t->width * 2;
440 		decoration_height = t->width + titlebar_height;
441 	} else {
442 		decoration_width = (t->width + t->margin) * 2;
443 		decoration_height = t->width +
444 			titlebar_height + t->margin * 2;
445 	}
446 
447 	frame_resize(frame, width + decoration_width,
448 		     height + decoration_height);
449 }
450 
451 int32_t
frame_width(struct frame * frame)452 frame_width(struct frame *frame)
453 {
454 	return frame->width;
455 }
456 
457 int32_t
frame_height(struct frame * frame)458 frame_height(struct frame *frame)
459 {
460 	return frame->height;
461 }
462 
463 static void
frame_refresh_geometry(struct frame * frame)464 frame_refresh_geometry(struct frame *frame)
465 {
466 	struct frame_button *button;
467 	struct theme *t = frame->theme;
468 	int x_l, x_r, y, w, h, titlebar_height;
469 	int32_t decoration_width, decoration_height;
470 
471 	if (!frame->geometry_dirty)
472 		return;
473 
474 	if (frame->title || !wl_list_empty(&frame->buttons))
475 		titlebar_height = t->titlebar_height;
476 	else
477 		titlebar_height = t->width;
478 
479 	if (frame->flags & FRAME_FLAG_MAXIMIZED) {
480 		decoration_width = t->width * 2;
481 		decoration_height = t->width + titlebar_height;
482 
483 		frame->interior.x = t->width;
484 		frame->interior.y = titlebar_height;
485 		frame->interior.width = frame->width - decoration_width;
486 		frame->interior.height = frame->height - decoration_height;
487 
488 		frame->opaque_margin = 0;
489 		frame->shadow_margin = 0;
490 	} else {
491 		decoration_width = (t->width + t->margin) * 2;
492 		decoration_height = t->width + titlebar_height + t->margin * 2;
493 
494 		frame->interior.x = t->width + t->margin;
495 		frame->interior.y = titlebar_height + t->margin;
496 		frame->interior.width = frame->width - decoration_width;
497 		frame->interior.height = frame->height - decoration_height;
498 
499 		frame->opaque_margin = t->margin + t->frame_radius;
500 		frame->shadow_margin = t->margin;
501 	}
502 
503 	x_r = frame->width - t->width - frame->shadow_margin;
504 	x_l = t->width + frame->shadow_margin;
505 	y = t->width + frame->shadow_margin;
506 	wl_list_for_each(button, &frame->buttons, link) {
507 		const int button_padding = 4;
508 		w = cairo_image_surface_get_width(button->icon);
509 		h = cairo_image_surface_get_height(button->icon);
510 
511 		if (button->flags & FRAME_BUTTON_DECORATED)
512 			w += 10;
513 
514 		if (button->flags & FRAME_BUTTON_ALIGN_RIGHT) {
515 			x_r -= w;
516 
517 			button->allocation.x = x_r;
518 			button->allocation.y = y;
519 			button->allocation.width = w + 1;
520 			button->allocation.height = h + 1;
521 
522 			x_r -= button_padding;
523 		} else {
524 			button->allocation.x = x_l;
525 			button->allocation.y = y;
526 			button->allocation.width = w + 1;
527 			button->allocation.height = h + 1;
528 
529 			x_l += w;
530 			x_l += button_padding;
531 		}
532 	}
533 
534 	frame->geometry_dirty = 0;
535 }
536 
537 void
frame_interior(struct frame * frame,int32_t * x,int32_t * y,int32_t * width,int32_t * height)538 frame_interior(struct frame *frame, int32_t *x, int32_t *y,
539 		int32_t *width, int32_t *height)
540 {
541 	frame_refresh_geometry(frame);
542 
543 	if (x)
544 		*x = frame->interior.x;
545 	if (y)
546 		*y = frame->interior.y;
547 	if (width)
548 		*width = frame->interior.width;
549 	if (height)
550 		*height = frame->interior.height;
551 }
552 
553 void
frame_input_rect(struct frame * frame,int32_t * x,int32_t * y,int32_t * width,int32_t * height)554 frame_input_rect(struct frame *frame, int32_t *x, int32_t *y,
555 		 int32_t *width, int32_t *height)
556 {
557 	frame_refresh_geometry(frame);
558 
559 	if (x)
560 		*x = frame->shadow_margin;
561 	if (y)
562 		*y = frame->shadow_margin;
563 	if (width)
564 		*width = frame->width - frame->shadow_margin * 2;
565 	if (height)
566 		*height = frame->height - frame->shadow_margin * 2;
567 }
568 
569 void
frame_opaque_rect(struct frame * frame,int32_t * x,int32_t * y,int32_t * width,int32_t * height)570 frame_opaque_rect(struct frame *frame, int32_t *x, int32_t *y,
571 		  int32_t *width, int32_t *height)
572 {
573 	frame_refresh_geometry(frame);
574 
575 	if (x)
576 		*x = frame->opaque_margin;
577 	if (y)
578 		*y = frame->opaque_margin;
579 	if (width)
580 		*width = frame->width - frame->opaque_margin * 2;
581 	if (height)
582 		*height = frame->height - frame->opaque_margin * 2;
583 }
584 
585 int
frame_get_shadow_margin(struct frame * frame)586 frame_get_shadow_margin(struct frame *frame)
587 {
588 	frame_refresh_geometry(frame);
589 
590 	return frame->shadow_margin;
591 }
592 
593 uint32_t
frame_status(struct frame * frame)594 frame_status(struct frame *frame)
595 {
596 	return frame->status;
597 }
598 
599 void
frame_status_clear(struct frame * frame,enum frame_status status)600 frame_status_clear(struct frame *frame, enum frame_status status)
601 {
602 	frame->status &= ~status;
603 }
604 
605 static struct frame_button *
frame_find_button(struct frame * frame,int x,int y)606 frame_find_button(struct frame *frame, int x, int y)
607 {
608 	struct frame_button *button;
609 	int rel_x, rel_y;
610 
611 	wl_list_for_each(button, &frame->buttons, link) {
612 		rel_x = x - button->allocation.x;
613 		rel_y = y - button->allocation.y;
614 
615 		if (0 <= rel_x && rel_x < button->allocation.width &&
616 		    0 <= rel_y && rel_y < button->allocation.height)
617 			return button;
618 	}
619 
620 	return NULL;
621 }
622 
623 enum theme_location
frame_pointer_enter(struct frame * frame,void * data,int x,int y)624 frame_pointer_enter(struct frame *frame, void *data, int x, int y)
625 {
626 	return frame_pointer_motion(frame, data, x, y);
627 }
628 
629 enum theme_location
frame_pointer_motion(struct frame * frame,void * data,int x,int y)630 frame_pointer_motion(struct frame *frame, void *data, int x, int y)
631 {
632 	struct frame_pointer *pointer = frame_pointer_get(frame, data);
633 	struct frame_button *button = frame_find_button(frame, x, y);
634 	enum theme_location location;
635 
636 	location = theme_get_location(frame->theme, x, y,
637 				      frame->width, frame->height,
638 				      frame->flags & FRAME_FLAG_MAXIMIZED ?
639 				      THEME_FRAME_MAXIMIZED : 0);
640 	if (!pointer)
641 		return location;
642 
643 	pointer->x = x;
644 	pointer->y = y;
645 
646 	if (pointer->hover_button == button)
647 		return location;
648 
649 	if (pointer->hover_button)
650 		frame_button_leave(pointer->hover_button, pointer);
651 
652 	pointer->hover_button = button;
653 
654 	if (pointer->hover_button)
655 		frame_button_enter(pointer->hover_button);
656 
657 	return location;
658 }
659 
660 static void
frame_pointer_button_destroy(struct frame_pointer_button * button)661 frame_pointer_button_destroy(struct frame_pointer_button *button)
662 {
663 	wl_list_remove(&button->link);
664 	free(button);
665 }
666 
667 static void
frame_pointer_button_press(struct frame * frame,struct frame_pointer * pointer,struct frame_pointer_button * button)668 frame_pointer_button_press(struct frame *frame, struct frame_pointer *pointer,
669 			   struct frame_pointer_button *button)
670 {
671 	if (button->button == BTN_RIGHT) {
672 		if (button->press_location == THEME_LOCATION_TITLEBAR)
673 			frame->status |= FRAME_STATUS_MENU;
674 
675 		frame_pointer_button_destroy(button);
676 
677 	} else if (button->button == BTN_LEFT) {
678 		if (pointer->hover_button) {
679 			frame_button_press(pointer->hover_button);
680 		} else {
681 			switch (button->press_location) {
682 			case THEME_LOCATION_TITLEBAR:
683 				frame->status |= FRAME_STATUS_MOVE;
684 
685 				frame_pointer_button_destroy(button);
686 				break;
687 			case THEME_LOCATION_RESIZING_TOP:
688 			case THEME_LOCATION_RESIZING_BOTTOM:
689 			case THEME_LOCATION_RESIZING_LEFT:
690 			case THEME_LOCATION_RESIZING_RIGHT:
691 			case THEME_LOCATION_RESIZING_TOP_LEFT:
692 			case THEME_LOCATION_RESIZING_TOP_RIGHT:
693 			case THEME_LOCATION_RESIZING_BOTTOM_LEFT:
694 			case THEME_LOCATION_RESIZING_BOTTOM_RIGHT:
695 				frame->status |= FRAME_STATUS_RESIZE;
696 
697 				frame_pointer_button_destroy(button);
698 				break;
699 			default:
700 				break;
701 			}
702 		}
703 	}
704 }
705 
706 static void
frame_pointer_button_release(struct frame * frame,struct frame_pointer * pointer,struct frame_pointer_button * button)707 frame_pointer_button_release(struct frame *frame, struct frame_pointer *pointer,
708 			     struct frame_pointer_button *button)
709 {
710 	if (button->button == BTN_LEFT && button->frame_button) {
711 		if (button->frame_button == pointer->hover_button)
712 			frame_button_release(button->frame_button);
713 		else
714 			frame_button_cancel(button->frame_button);
715 	}
716 }
717 
718 static void
frame_pointer_button_cancel(struct frame * frame,struct frame_pointer * pointer,struct frame_pointer_button * button)719 frame_pointer_button_cancel(struct frame *frame, struct frame_pointer *pointer,
720 			    struct frame_pointer_button *button)
721 {
722 	if (button->frame_button)
723 		frame_button_cancel(button->frame_button);
724 }
725 
726 void
frame_pointer_leave(struct frame * frame,void * data)727 frame_pointer_leave(struct frame *frame, void *data)
728 {
729 	struct frame_pointer *pointer = frame_pointer_get(frame, data);
730 	struct frame_pointer_button *button, *next;
731 	if (!pointer)
732 		return;
733 
734 	if (pointer->hover_button)
735 		frame_button_leave(pointer->hover_button, pointer);
736 
737 	wl_list_for_each_safe(button, next, &pointer->down_buttons, link) {
738 		frame_pointer_button_cancel(frame, pointer, button);
739 		frame_pointer_button_destroy(button);
740 	}
741 
742 	frame_pointer_destroy(pointer);
743 }
744 
745 enum theme_location
frame_pointer_button(struct frame * frame,void * data,uint32_t btn,enum frame_button_state state)746 frame_pointer_button(struct frame *frame, void *data,
747 		     uint32_t btn, enum frame_button_state state)
748 {
749 	struct frame_pointer *pointer = frame_pointer_get(frame, data);
750 	struct frame_pointer_button *button;
751 	enum theme_location location = THEME_LOCATION_EXTERIOR;
752 
753 	if (!pointer)
754 		return location;
755 
756 	location = theme_get_location(frame->theme, pointer->x, pointer->y,
757 				      frame->width, frame->height,
758 				      frame->flags & FRAME_FLAG_MAXIMIZED ?
759 				      THEME_FRAME_MAXIMIZED : 0);
760 
761 	if (state == FRAME_BUTTON_PRESSED) {
762 		button = malloc(sizeof *button);
763 		if (!button)
764 			return location;
765 
766 		button->button = btn;
767 		button->press_location = location;
768 		button->frame_button = pointer->hover_button;
769 		wl_list_insert(&pointer->down_buttons, &button->link);
770 
771 		frame_pointer_button_press(frame, pointer, button);
772 	} else if (state == FRAME_BUTTON_RELEASED) {
773 		button = NULL;
774 		wl_list_for_each(button, &pointer->down_buttons, link)
775 			if (button->button == btn)
776 				break;
777 		/* Make sure we didn't hit the end */
778 		if (&button->link == &pointer->down_buttons)
779 			return location;
780 
781 		location = button->press_location;
782 		frame_pointer_button_release(frame, pointer, button);
783 		frame_pointer_button_destroy(button);
784 	}
785 
786 	return location;
787 }
788 
789 void
frame_touch_down(struct frame * frame,void * data,int32_t id,int x,int y)790 frame_touch_down(struct frame *frame, void *data, int32_t id, int x, int y)
791 {
792 	struct frame_touch *touch = frame_touch_get(frame, data);
793 	struct frame_button *button = frame_find_button(frame, x, y);
794 	enum theme_location location;
795 
796 	if (id > 0)
797 		return;
798 
799 	if (touch && button) {
800 		touch->button = button;
801 		frame_button_press(touch->button);
802 		return;
803 	}
804 
805 	location = theme_get_location(frame->theme, x, y,
806 				      frame->width, frame->height,
807 				      frame->flags & FRAME_FLAG_MAXIMIZED ?
808 				      THEME_FRAME_MAXIMIZED : 0);
809 
810 	switch (location) {
811 	case THEME_LOCATION_TITLEBAR:
812 		frame->status |= FRAME_STATUS_MOVE;
813 		break;
814 	case THEME_LOCATION_RESIZING_TOP:
815 	case THEME_LOCATION_RESIZING_BOTTOM:
816 	case THEME_LOCATION_RESIZING_LEFT:
817 	case THEME_LOCATION_RESIZING_RIGHT:
818 	case THEME_LOCATION_RESIZING_TOP_LEFT:
819 	case THEME_LOCATION_RESIZING_TOP_RIGHT:
820 	case THEME_LOCATION_RESIZING_BOTTOM_LEFT:
821 	case THEME_LOCATION_RESIZING_BOTTOM_RIGHT:
822 		frame->status |= FRAME_STATUS_RESIZE;
823 		break;
824 	default:
825 		break;
826 	}
827 }
828 
829 void
frame_touch_up(struct frame * frame,void * data,int32_t id)830 frame_touch_up(struct frame *frame, void *data, int32_t id)
831 {
832 	struct frame_touch *touch = frame_touch_get(frame, data);
833 
834 	if (id > 0)
835 		return;
836 
837 	if (touch && touch->button) {
838 		frame_button_release(touch->button);
839 		frame_touch_destroy(touch);
840 	}
841 }
842 
843 enum theme_location
frame_double_click(struct frame * frame,void * data,uint32_t btn,enum frame_button_state state)844 frame_double_click(struct frame *frame, void *data,
845 		   uint32_t btn, enum frame_button_state state)
846 {
847 	struct frame_pointer *pointer = frame_pointer_get(frame, data);
848 	struct frame_button *button;
849 	enum theme_location location = THEME_LOCATION_EXTERIOR;
850 
851 	location = theme_get_location(frame->theme, pointer->x, pointer->y,
852 				      frame->width, frame->height,
853 				      frame->flags & FRAME_FLAG_MAXIMIZED ?
854 				      THEME_FRAME_MAXIMIZED : 0);
855 
856 	button = frame_find_button(frame, pointer->x, pointer->y);
857 
858 	if (location != THEME_LOCATION_TITLEBAR || btn != BTN_LEFT)
859 		return location;
860 
861 	if (state == FRAME_BUTTON_PRESSED) {
862 		if (button)
863 			frame_button_press(button);
864 		else
865 			frame->status |= FRAME_STATUS_MAXIMIZE;
866 	} else if (state == FRAME_BUTTON_RELEASED) {
867 		if (button)
868 			frame_button_release(button);
869 	}
870 
871 	return location;
872 }
873 
874 void
frame_double_touch_down(struct frame * frame,void * data,int32_t id,int x,int y)875 frame_double_touch_down(struct frame *frame, void *data, int32_t id,
876 			int x, int y)
877 {
878 	struct frame_touch *touch = frame_touch_get(frame, data);
879 	struct frame_button *button = frame_find_button(frame, x, y);
880 	enum theme_location location;
881 
882 	if (touch && button) {
883 		touch->button = button;
884 		frame_button_press(touch->button);
885 		return;
886 	}
887 
888 	location = theme_get_location(frame->theme, x, y,
889 				      frame->width, frame->height,
890 				      frame->flags & FRAME_FLAG_MAXIMIZED ?
891 				      THEME_FRAME_MAXIMIZED : 0);
892 
893 	switch (location) {
894 	case THEME_LOCATION_TITLEBAR:
895 		frame->status |= FRAME_STATUS_MAXIMIZE;
896 		break;
897 	case THEME_LOCATION_RESIZING_TOP:
898 	case THEME_LOCATION_RESIZING_BOTTOM:
899 	case THEME_LOCATION_RESIZING_LEFT:
900 	case THEME_LOCATION_RESIZING_RIGHT:
901 	case THEME_LOCATION_RESIZING_TOP_LEFT:
902 	case THEME_LOCATION_RESIZING_TOP_RIGHT:
903 	case THEME_LOCATION_RESIZING_BOTTOM_LEFT:
904 	case THEME_LOCATION_RESIZING_BOTTOM_RIGHT:
905 		frame->status |= FRAME_STATUS_RESIZE;
906 		break;
907 	default:
908 		break;
909 	}
910 }
911 
912 void
frame_double_touch_up(struct frame * frame,void * data,int32_t id)913 frame_double_touch_up(struct frame *frame, void *data, int32_t id)
914 {
915 	struct frame_touch *touch = frame_touch_get(frame, data);
916 
917 	if (touch && touch->button) {
918 		frame_button_release(touch->button);
919 		frame_touch_destroy(touch);
920 	}
921 }
922 
923 void
frame_repaint(struct frame * frame,cairo_t * cr)924 frame_repaint(struct frame *frame, cairo_t *cr)
925 {
926 	struct frame_button *button;
927 	uint32_t flags = 0;
928 
929 	frame_refresh_geometry(frame);
930 
931 	if (frame->flags & FRAME_FLAG_MAXIMIZED)
932 		flags |= THEME_FRAME_MAXIMIZED;
933 
934 	if (frame->flags & FRAME_FLAG_ACTIVE)
935 		flags |= THEME_FRAME_ACTIVE;
936 
937 	cairo_save(cr);
938 	theme_render_frame(frame->theme, cr, frame->width, frame->height,
939 			   frame->title, &frame->buttons, flags);
940 	cairo_restore(cr);
941 
942 	wl_list_for_each(button, &frame->buttons, link)
943 		frame_button_repaint(button, cr);
944 
945 	frame_status_clear(frame, FRAME_STATUS_REPAINT);
946 }
947