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