blob: 4179b0a81de815bc56d8eb851e230a8b4b7cb98c [file] [log] [blame]
Jason Ekstrand01c9ec32013-10-13 19:08:39 -05001/*
2 * Copyright © 2008 Kristian Høgsberg
3 * Copyright © 2012-2013 Collabora, Ltd.
4 * Copyright © 2013 Jason Ekstrand
5 *
Bryce Harrington6c6164c2015-06-11 14:20:17 -07006 * 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:
Jason Ekstrand01c9ec32013-10-13 19:08:39 -050013 *
Bryce Harrington6c6164c2015-06-11 14:20:17 -070014 * 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.
Jason Ekstrand01c9ec32013-10-13 19:08:39 -050026 */
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
37enum frame_button_flags {
38 FRAME_BUTTON_ALIGN_RIGHT = 0x1,
39 FRAME_BUTTON_DECORATED = 0x2,
40 FRAME_BUTTON_CLICK_DOWN = 0x4,
41};
42
43struct 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
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -050060struct 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
Jason Ekstrand01c9ec32013-10-13 19:08:39 -050067struct frame_pointer {
68 struct wl_list link;
69 void *data;
70
71 int x, y;
72
73 struct frame_button *hover_button;
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -050074 struct wl_list down_buttons;
Jason Ekstrand01c9ec32013-10-13 19:08:39 -050075};
76
Jason Ekstrand3f66cf92013-10-13 19:08:40 -050077struct frame_touch {
78 struct wl_list link;
79 void *data;
80
81 int x, y;
82
83 struct frame_button *button;
84};
85
Jason Ekstrand01c9ec32013-10-13 19:08:39 -050086struct 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;
Jason Ekstrand3f66cf92013-10-13 19:08:40 -0500104 struct wl_list touches;
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500105};
106
107static struct frame_button *
108frame_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
133static void
134frame_button_destroy(struct frame_button *button)
135{
136 cairo_surface_destroy(button->icon);
137 free(button);
138}
139
140static void
141frame_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
148static void
149frame_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;
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500154}
155
156static void
157frame_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
167static void
168frame_button_release(struct frame_button *button)
169{
170 button->press_count--;
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500171 if (button->press_count)
172 return;
173
174 button->frame->status |= FRAME_STATUS_REPAINT;
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500175
176 if (!(button->flags & FRAME_BUTTON_CLICK_DOWN))
177 button->frame->status |= button->status_effect;
178}
179
180static void
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500181frame_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
188static void
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500189frame_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
230static struct frame_pointer *
231frame_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;
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500244 wl_list_init(&pointer->down_buttons);
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500245 wl_list_insert(&frame->pointers, &pointer->link);
246
247 return pointer;
248}
249
250static void
251frame_pointer_destroy(struct frame_pointer *pointer)
252{
253 wl_list_remove(&pointer->link);
254 free(pointer);
255}
256
Jason Ekstrand3f66cf92013-10-13 19:08:40 -0500257static struct frame_touch *
258frame_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
276static void
277frame_touch_destroy(struct frame_touch *touch)
278{
279 wl_list_remove(&touch->link);
280 free(touch);
281}
282
U. Artie Eoff107de962014-01-17 11:19:46 -0800283void
284frame_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
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500303struct frame *
304frame_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
U. Artie Eoff107de962014-01-17 11:19:46 -0800321 wl_list_init(&frame->buttons);
322 wl_list_init(&frame->pointers);
323 wl_list_init(&frame->touches);
324
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500325 if (title) {
326 frame->title = strdup(title);
327 if (!frame->title)
328 goto free_frame;
329 }
330
Kristian Høgsberg89f4bc42013-10-23 22:12:13 -0700331 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 }
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500339
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
372free_frame:
U. Artie Eoff107de962014-01-17 11:19:46 -0800373 frame_destroy(frame);
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500374 return NULL;
375}
376
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500377int
378frame_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
Boyan Ding9c5aedf2014-07-04 15:19:23 +0800391 frame->geometry_dirty = 1;
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500392 frame->status |= FRAME_STATUS_REPAINT;
393
394 return 0;
395}
396
397void
398frame_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
407void
408frame_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
417void
418frame_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
427void
428frame_resize_inside(struct frame *frame, int32_t width, int32_t height)
429{
430 struct theme *t = frame->theme;
Kristian Høgsberg89f4bc42013-10-23 22:12:13 -0700431 int decoration_width, decoration_height, titlebar_height;
432
Boyan Dingc4902122014-07-04 15:19:22 +0800433 if (frame->title || !wl_list_empty(&frame->buttons))
Kristian Høgsberg89f4bc42013-10-23 22:12:13 -0700434 titlebar_height = t->titlebar_height;
435 else
436 titlebar_height = t->width;
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500437
438 if (frame->flags & FRAME_FLAG_MAXIMIZED) {
439 decoration_width = t->width * 2;
Kristian Høgsberg89f4bc42013-10-23 22:12:13 -0700440 decoration_height = t->width + titlebar_height;
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500441 } else {
442 decoration_width = (t->width + t->margin) * 2;
443 decoration_height = t->width +
Kristian Høgsberg89f4bc42013-10-23 22:12:13 -0700444 titlebar_height + t->margin * 2;
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500445 }
446
447 frame_resize(frame, width + decoration_width,
448 height + decoration_height);
449}
450
451int32_t
452frame_width(struct frame *frame)
453{
454 return frame->width;
455}
456
457int32_t
458frame_height(struct frame *frame)
459{
460 return frame->height;
461}
462
463static void
464frame_refresh_geometry(struct frame *frame)
465{
466 struct frame_button *button;
467 struct theme *t = frame->theme;
Kristian Høgsberg89f4bc42013-10-23 22:12:13 -0700468 int x_l, x_r, y, w, h, titlebar_height;
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500469 int32_t decoration_width, decoration_height;
470
471 if (!frame->geometry_dirty)
472 return;
473
Boyan Dingc4902122014-07-04 15:19:22 +0800474 if (frame->title || !wl_list_empty(&frame->buttons))
Kristian Høgsberg89f4bc42013-10-23 22:12:13 -0700475 titlebar_height = t->titlebar_height;
476 else
477 titlebar_height = t->width;
478
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500479 if (frame->flags & FRAME_FLAG_MAXIMIZED) {
480 decoration_width = t->width * 2;
Kristian Høgsberg89f4bc42013-10-23 22:12:13 -0700481 decoration_height = t->width + titlebar_height;
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500482
483 frame->interior.x = t->width;
Kristian Høgsberg89f4bc42013-10-23 22:12:13 -0700484 frame->interior.y = titlebar_height;
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500485 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;
Kristian Høgsberg89f4bc42013-10-23 22:12:13 -0700492 decoration_height = t->width + titlebar_height + t->margin * 2;
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500493
494 frame->interior.x = t->width + t->margin;
Kristian Høgsberg89f4bc42013-10-23 22:12:13 -0700495 frame->interior.y = titlebar_height + t->margin;
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500496 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
537void
538frame_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
553void
554frame_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
569void
570frame_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
Jasper St. Pierre74073452014-02-01 18:36:41 -0500585int
586frame_get_shadow_margin(struct frame *frame)
587{
588 frame_refresh_geometry(frame);
589
590 return frame->shadow_margin;
591}
592
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500593uint32_t
594frame_status(struct frame *frame)
595{
596 return frame->status;
597}
598
599void
600frame_status_clear(struct frame *frame, enum frame_status status)
601{
602 frame->status &= ~status;
603}
604
605static struct frame_button *
606frame_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
623enum theme_location
624frame_pointer_enter(struct frame *frame, void *data, int x, int y)
625{
626 return frame_pointer_motion(frame, data, x, y);
627}
628
629enum theme_location
630frame_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
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500652 pointer->hover_button = button;
653
654 if (pointer->hover_button)
655 frame_button_enter(pointer->hover_button);
656
657 return location;
658}
659
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500660static void
661frame_pointer_button_destroy(struct frame_pointer_button *button)
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500662{
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500663 wl_list_remove(&button->link);
664 free(button);
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500665}
666
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500667static void
668frame_pointer_button_press(struct frame *frame, struct frame_pointer *pointer,
669 struct frame_pointer_button *button)
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500670{
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500671 if (button->button == BTN_RIGHT) {
672 if (button->press_location == THEME_LOCATION_TITLEBAR)
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500673 frame->status |= FRAME_STATUS_MENU;
674
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500675 frame_pointer_button_destroy(button);
676
677 } else if (button->button == BTN_LEFT) {
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500678 if (pointer->hover_button) {
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500679 frame_button_press(pointer->hover_button);
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500680 } else {
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500681 switch (button->press_location) {
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500682 case THEME_LOCATION_TITLEBAR:
683 frame->status |= FRAME_STATUS_MOVE;
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500684
685 frame_pointer_button_destroy(button);
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500686 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;
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500696
697 frame_pointer_button_destroy(button);
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500698 break;
699 default:
700 break;
701 }
702 }
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500703 }
704}
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500705
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500706static void
707frame_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
718static void
719frame_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
726void
727frame_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
745enum theme_location
746frame_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;
U. Artie Eoff6d71c3c2014-01-17 14:44:05 -0800751 enum theme_location location = THEME_LOCATION_EXTERIOR;
752
753 if (!pointer)
754 return location;
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500755
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
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500761 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);
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500784 }
785
786 return location;
787}
788
789void
Jason Ekstrand3f66cf92013-10-13 19:08:40 -0500790frame_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
U. Artie Eoff6d71c3c2014-01-17 14:44:05 -0800799 if (touch && button) {
Jason Ekstrand3f66cf92013-10-13 19:08:40 -0500800 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
829void
830frame_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
U. Artie Eoff6d71c3c2014-01-17 14:44:05 -0800837 if (touch && touch->button) {
Jason Ekstrand3f66cf92013-10-13 19:08:40 -0500838 frame_button_release(touch->button);
839 frame_touch_destroy(touch);
Jason Ekstrand3f66cf92013-10-13 19:08:40 -0500840 }
841}
842
Xiong Zhangbfb4ade2014-06-12 11:06:25 +0800843enum theme_location
844frame_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
Jason Ekstrand3f66cf92013-10-13 19:08:40 -0500874void
Xiong Zhang382de462014-06-12 11:06:26 +0800875frame_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
912void
913frame_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
923void
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500924frame_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,
Boyan Ding850a5142014-08-05 15:22:04 +0800939 frame->title, &frame->buttons, flags);
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500940 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}