blob: eb0cd77a3f700be17bd099e20d222c732ebb25bf [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
Jussi Kukkonen649bbce2016-07-19 14:16:27 +030030#include <stdint.h>
Jason Ekstrand01c9ec32013-10-13 19:08:39 -050031#include <stdlib.h>
32#include <string.h>
33#include <wayland-util.h>
34#include <linux/input.h>
35
36#include "cairo-util.h"
37
38enum frame_button_flags {
39 FRAME_BUTTON_ALIGN_RIGHT = 0x1,
40 FRAME_BUTTON_DECORATED = 0x2,
41 FRAME_BUTTON_CLICK_DOWN = 0x4,
42};
43
44struct frame_button {
45 struct frame *frame;
46 struct wl_list link; /* buttons_list */
47
48 cairo_surface_t *icon;
49 enum frame_button_flags flags;
50 int hover_count;
51 int press_count;
52
53 struct {
54 int x, y;
55 int width, height;
56 } allocation;
57
58 enum frame_status status_effect;
59};
60
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -050061struct frame_pointer_button {
62 struct wl_list link;
63 uint32_t button;
64 enum theme_location press_location;
65 struct frame_button *frame_button;
66};
67
Jason Ekstrand01c9ec32013-10-13 19:08:39 -050068struct frame_pointer {
69 struct wl_list link;
70 void *data;
71
72 int x, y;
73
74 struct frame_button *hover_button;
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -050075 struct wl_list down_buttons;
Jason Ekstrand01c9ec32013-10-13 19:08:39 -050076};
77
Jason Ekstrand3f66cf92013-10-13 19:08:40 -050078struct frame_touch {
79 struct wl_list link;
80 void *data;
81
82 int x, y;
83
84 struct frame_button *button;
85};
86
Jason Ekstrand01c9ec32013-10-13 19:08:39 -050087struct frame {
88 int32_t width, height;
89 char *title;
90 uint32_t flags;
91 struct theme *theme;
92
93 struct {
94 int32_t x, y;
95 int32_t width, height;
96 } interior;
97 int shadow_margin;
98 int opaque_margin;
99 int geometry_dirty;
100
101 uint32_t status;
102
103 struct wl_list buttons;
104 struct wl_list pointers;
Jason Ekstrand3f66cf92013-10-13 19:08:40 -0500105 struct wl_list touches;
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500106};
107
108static struct frame_button *
109frame_button_create(struct frame *frame, const char *icon,
110 enum frame_status status_effect,
111 enum frame_button_flags flags)
112{
113 struct frame_button *button;
114
115 button = calloc(1, sizeof *button);
116 if (!button)
117 return NULL;
118
119 button->icon = cairo_image_surface_create_from_png(icon);
120 if (!button->icon) {
121 free(button);
122 return NULL;
123 }
124
125 button->frame = frame;
126 button->flags = flags;
127 button->status_effect = status_effect;
128
129 wl_list_insert(frame->buttons.prev, &button->link);
130
131 return button;
132}
133
134static void
135frame_button_destroy(struct frame_button *button)
136{
137 cairo_surface_destroy(button->icon);
138 free(button);
139}
140
141static void
142frame_button_enter(struct frame_button *button)
143{
144 if (!button->hover_count)
145 button->frame->status |= FRAME_STATUS_REPAINT;
146 button->hover_count++;
147}
148
149static void
150frame_button_leave(struct frame_button *button, struct frame_pointer *pointer)
151{
152 button->hover_count--;
153 if (!button->hover_count)
154 button->frame->status |= FRAME_STATUS_REPAINT;
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500155}
156
157static void
158frame_button_press(struct frame_button *button)
159{
160 if (!button->press_count)
161 button->frame->status |= FRAME_STATUS_REPAINT;
162 button->press_count++;
163
164 if (button->flags & FRAME_BUTTON_CLICK_DOWN)
165 button->frame->status |= button->status_effect;
166}
167
168static void
169frame_button_release(struct frame_button *button)
170{
171 button->press_count--;
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500172 if (button->press_count)
173 return;
174
175 button->frame->status |= FRAME_STATUS_REPAINT;
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500176
177 if (!(button->flags & FRAME_BUTTON_CLICK_DOWN))
178 button->frame->status |= button->status_effect;
179}
180
181static void
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500182frame_button_cancel(struct frame_button *button)
183{
184 button->press_count--;
185 if (!button->press_count)
186 button->frame->status |= FRAME_STATUS_REPAINT;
187}
188
189static void
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500190frame_button_repaint(struct frame_button *button, cairo_t *cr)
191{
192 int x, y;
193
194 if (!button->allocation.width)
195 return;
196 if (!button->allocation.height)
197 return;
198
199 x = button->allocation.x;
200 y = button->allocation.y;
201
202 cairo_save(cr);
203
204 if (button->flags & FRAME_BUTTON_DECORATED) {
205 cairo_set_line_width(cr, 1);
206
207 cairo_set_source_rgb(cr, 0.0, 0.0, 0.0);
208 cairo_rectangle(cr, x, y, 25, 16);
209
210 cairo_stroke_preserve(cr);
211
212 if (button->press_count) {
213 cairo_set_source_rgb(cr, 0.7, 0.7, 0.7);
214 } else if (button->hover_count) {
215 cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
216 } else {
217 cairo_set_source_rgb(cr, 0.88, 0.88, 0.88);
218 }
219
220 cairo_fill (cr);
221
222 x += 4;
223 }
224
225 cairo_set_source_surface(cr, button->icon, x, y);
226 cairo_paint(cr);
227
228 cairo_restore(cr);
229}
230
231static struct frame_pointer *
232frame_pointer_get(struct frame *frame, void *data)
233{
234 struct frame_pointer *pointer;
235
236 wl_list_for_each(pointer, &frame->pointers, link)
237 if (pointer->data == data)
238 return pointer;
239
240 pointer = calloc(1, sizeof *pointer);
241 if (!pointer)
242 return NULL;
243
244 pointer->data = data;
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500245 wl_list_init(&pointer->down_buttons);
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500246 wl_list_insert(&frame->pointers, &pointer->link);
247
248 return pointer;
249}
250
251static void
252frame_pointer_destroy(struct frame_pointer *pointer)
253{
254 wl_list_remove(&pointer->link);
255 free(pointer);
256}
257
Jason Ekstrand3f66cf92013-10-13 19:08:40 -0500258static struct frame_touch *
259frame_touch_get(struct frame *frame, void *data)
260{
261 struct frame_touch *touch;
262
263 wl_list_for_each(touch, &frame->touches, link)
264 if (touch->data == data)
265 return touch;
266
267 touch = calloc(1, sizeof *touch);
268 if (!touch)
269 return NULL;
270
271 touch->data = data;
272 wl_list_insert(&frame->touches, &touch->link);
273
274 return touch;
275}
276
277static void
278frame_touch_destroy(struct frame_touch *touch)
279{
280 wl_list_remove(&touch->link);
281 free(touch);
282}
283
U. Artie Eoff107de962014-01-17 11:19:46 -0800284void
285frame_destroy(struct frame *frame)
286{
287 struct frame_button *button, *next;
288 struct frame_touch *touch, *next_touch;
289 struct frame_pointer *pointer, *next_pointer;
290
291 wl_list_for_each_safe(button, next, &frame->buttons, link)
292 frame_button_destroy(button);
293
294 wl_list_for_each_safe(touch, next_touch, &frame->touches, link)
295 frame_touch_destroy(touch);
296
297 wl_list_for_each_safe(pointer, next_pointer, &frame->pointers, link)
298 frame_pointer_destroy(pointer);
299
300 free(frame->title);
301 free(frame);
302}
303
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500304struct frame *
305frame_create(struct theme *t, int32_t width, int32_t height, uint32_t buttons,
306 const char *title)
307{
308 struct frame *frame;
309 struct frame_button *button;
310
311 frame = calloc(1, sizeof *frame);
312 if (!frame)
313 return NULL;
314
315 frame->width = width;
316 frame->height = height;
317 frame->flags = 0;
318 frame->theme = t;
319 frame->status = FRAME_STATUS_REPAINT;
320 frame->geometry_dirty = 1;
321
U. Artie Eoff107de962014-01-17 11:19:46 -0800322 wl_list_init(&frame->buttons);
323 wl_list_init(&frame->pointers);
324 wl_list_init(&frame->touches);
325
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500326 if (title) {
327 frame->title = strdup(title);
328 if (!frame->title)
329 goto free_frame;
330 }
331
Kristian Høgsberg89f4bc42013-10-23 22:12:13 -0700332 if (title) {
333 button = frame_button_create(frame,
334 DATADIR "/weston/icon_window.png",
335 FRAME_STATUS_MENU,
336 FRAME_BUTTON_CLICK_DOWN);
337 if (!button)
338 goto free_frame;
339 }
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500340
341 if (buttons & FRAME_BUTTON_CLOSE) {
342 button = frame_button_create(frame,
343 DATADIR "/weston/sign_close.png",
344 FRAME_STATUS_CLOSE,
345 FRAME_BUTTON_ALIGN_RIGHT |
346 FRAME_BUTTON_DECORATED);
347 if (!button)
348 goto free_frame;
349 }
350
351 if (buttons & FRAME_BUTTON_MAXIMIZE) {
352 button = frame_button_create(frame,
353 DATADIR "/weston/sign_maximize.png",
354 FRAME_STATUS_MAXIMIZE,
355 FRAME_BUTTON_ALIGN_RIGHT |
356 FRAME_BUTTON_DECORATED);
357 if (!button)
358 goto free_frame;
359 }
360
361 if (buttons & FRAME_BUTTON_MINIMIZE) {
362 button = frame_button_create(frame,
363 DATADIR "/weston/sign_minimize.png",
364 FRAME_STATUS_MINIMIZE,
365 FRAME_BUTTON_ALIGN_RIGHT |
366 FRAME_BUTTON_DECORATED);
367 if (!button)
368 goto free_frame;
369 }
370
371 return frame;
372
373free_frame:
U. Artie Eoff107de962014-01-17 11:19:46 -0800374 frame_destroy(frame);
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500375 return NULL;
376}
377
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500378int
379frame_set_title(struct frame *frame, const char *title)
380{
381 char *dup = NULL;
382
383 if (title) {
384 dup = strdup(title);
385 if (!dup)
386 return -1;
387 }
388
389 free(frame->title);
390 frame->title = dup;
391
Boyan Ding9c5aedf2014-07-04 15:19:23 +0800392 frame->geometry_dirty = 1;
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500393 frame->status |= FRAME_STATUS_REPAINT;
394
395 return 0;
396}
397
398void
399frame_set_flag(struct frame *frame, enum frame_flag flag)
400{
401 if (flag & FRAME_FLAG_MAXIMIZED && !(frame->flags & FRAME_FLAG_MAXIMIZED))
402 frame->geometry_dirty = 1;
403
404 frame->flags |= flag;
405 frame->status |= FRAME_STATUS_REPAINT;
406}
407
408void
409frame_unset_flag(struct frame *frame, enum frame_flag flag)
410{
411 if (flag & FRAME_FLAG_MAXIMIZED && frame->flags & FRAME_FLAG_MAXIMIZED)
412 frame->geometry_dirty = 1;
413
414 frame->flags &= ~flag;
415 frame->status |= FRAME_STATUS_REPAINT;
416}
417
418void
419frame_resize(struct frame *frame, int32_t width, int32_t height)
420{
421 frame->width = width;
422 frame->height = height;
423
424 frame->geometry_dirty = 1;
425 frame->status |= FRAME_STATUS_REPAINT;
426}
427
428void
429frame_resize_inside(struct frame *frame, int32_t width, int32_t height)
430{
431 struct theme *t = frame->theme;
Kristian Høgsberg89f4bc42013-10-23 22:12:13 -0700432 int decoration_width, decoration_height, titlebar_height;
433
Boyan Dingc4902122014-07-04 15:19:22 +0800434 if (frame->title || !wl_list_empty(&frame->buttons))
Kristian Høgsberg89f4bc42013-10-23 22:12:13 -0700435 titlebar_height = t->titlebar_height;
436 else
437 titlebar_height = t->width;
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500438
439 if (frame->flags & FRAME_FLAG_MAXIMIZED) {
440 decoration_width = t->width * 2;
Kristian Høgsberg89f4bc42013-10-23 22:12:13 -0700441 decoration_height = t->width + titlebar_height;
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500442 } else {
443 decoration_width = (t->width + t->margin) * 2;
444 decoration_height = t->width +
Kristian Høgsberg89f4bc42013-10-23 22:12:13 -0700445 titlebar_height + t->margin * 2;
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500446 }
447
448 frame_resize(frame, width + decoration_width,
449 height + decoration_height);
450}
451
452int32_t
453frame_width(struct frame *frame)
454{
455 return frame->width;
456}
457
458int32_t
459frame_height(struct frame *frame)
460{
461 return frame->height;
462}
463
464static void
465frame_refresh_geometry(struct frame *frame)
466{
467 struct frame_button *button;
468 struct theme *t = frame->theme;
Kristian Høgsberg89f4bc42013-10-23 22:12:13 -0700469 int x_l, x_r, y, w, h, titlebar_height;
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500470 int32_t decoration_width, decoration_height;
471
472 if (!frame->geometry_dirty)
473 return;
474
Boyan Dingc4902122014-07-04 15:19:22 +0800475 if (frame->title || !wl_list_empty(&frame->buttons))
Kristian Høgsberg89f4bc42013-10-23 22:12:13 -0700476 titlebar_height = t->titlebar_height;
477 else
478 titlebar_height = t->width;
479
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500480 if (frame->flags & FRAME_FLAG_MAXIMIZED) {
481 decoration_width = t->width * 2;
Kristian Høgsberg89f4bc42013-10-23 22:12:13 -0700482 decoration_height = t->width + titlebar_height;
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500483
484 frame->interior.x = t->width;
Kristian Høgsberg89f4bc42013-10-23 22:12:13 -0700485 frame->interior.y = titlebar_height;
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500486 frame->interior.width = frame->width - decoration_width;
487 frame->interior.height = frame->height - decoration_height;
488
489 frame->opaque_margin = 0;
490 frame->shadow_margin = 0;
491 } else {
492 decoration_width = (t->width + t->margin) * 2;
Kristian Høgsberg89f4bc42013-10-23 22:12:13 -0700493 decoration_height = t->width + titlebar_height + t->margin * 2;
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500494
495 frame->interior.x = t->width + t->margin;
Kristian Høgsberg89f4bc42013-10-23 22:12:13 -0700496 frame->interior.y = titlebar_height + t->margin;
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500497 frame->interior.width = frame->width - decoration_width;
498 frame->interior.height = frame->height - decoration_height;
499
500 frame->opaque_margin = t->margin + t->frame_radius;
501 frame->shadow_margin = t->margin;
502 }
503
504 x_r = frame->width - t->width - frame->shadow_margin;
505 x_l = t->width + frame->shadow_margin;
506 y = t->width + frame->shadow_margin;
507 wl_list_for_each(button, &frame->buttons, link) {
508 const int button_padding = 4;
509 w = cairo_image_surface_get_width(button->icon);
510 h = cairo_image_surface_get_height(button->icon);
511
512 if (button->flags & FRAME_BUTTON_DECORATED)
513 w += 10;
514
515 if (button->flags & FRAME_BUTTON_ALIGN_RIGHT) {
516 x_r -= w;
517
518 button->allocation.x = x_r;
519 button->allocation.y = y;
520 button->allocation.width = w + 1;
521 button->allocation.height = h + 1;
522
523 x_r -= button_padding;
524 } else {
525 button->allocation.x = x_l;
526 button->allocation.y = y;
527 button->allocation.width = w + 1;
528 button->allocation.height = h + 1;
529
530 x_l += w;
531 x_l += button_padding;
532 }
533 }
534
535 frame->geometry_dirty = 0;
536}
537
538void
539frame_interior(struct frame *frame, int32_t *x, int32_t *y,
540 int32_t *width, int32_t *height)
541{
542 frame_refresh_geometry(frame);
543
544 if (x)
545 *x = frame->interior.x;
546 if (y)
547 *y = frame->interior.y;
548 if (width)
549 *width = frame->interior.width;
550 if (height)
551 *height = frame->interior.height;
552}
553
554void
555frame_input_rect(struct frame *frame, int32_t *x, int32_t *y,
556 int32_t *width, int32_t *height)
557{
558 frame_refresh_geometry(frame);
559
560 if (x)
561 *x = frame->shadow_margin;
562 if (y)
563 *y = frame->shadow_margin;
564 if (width)
565 *width = frame->width - frame->shadow_margin * 2;
566 if (height)
567 *height = frame->height - frame->shadow_margin * 2;
568}
569
570void
571frame_opaque_rect(struct frame *frame, int32_t *x, int32_t *y,
572 int32_t *width, int32_t *height)
573{
574 frame_refresh_geometry(frame);
575
576 if (x)
577 *x = frame->opaque_margin;
578 if (y)
579 *y = frame->opaque_margin;
580 if (width)
581 *width = frame->width - frame->opaque_margin * 2;
582 if (height)
583 *height = frame->height - frame->opaque_margin * 2;
584}
585
Jasper St. Pierre74073452014-02-01 18:36:41 -0500586int
587frame_get_shadow_margin(struct frame *frame)
588{
589 frame_refresh_geometry(frame);
590
591 return frame->shadow_margin;
592}
593
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500594uint32_t
595frame_status(struct frame *frame)
596{
597 return frame->status;
598}
599
600void
601frame_status_clear(struct frame *frame, enum frame_status status)
602{
603 frame->status &= ~status;
604}
605
606static struct frame_button *
607frame_find_button(struct frame *frame, int x, int y)
608{
609 struct frame_button *button;
610 int rel_x, rel_y;
611
612 wl_list_for_each(button, &frame->buttons, link) {
613 rel_x = x - button->allocation.x;
614 rel_y = y - button->allocation.y;
615
616 if (0 <= rel_x && rel_x < button->allocation.width &&
617 0 <= rel_y && rel_y < button->allocation.height)
618 return button;
619 }
620
621 return NULL;
622}
623
624enum theme_location
625frame_pointer_enter(struct frame *frame, void *data, int x, int y)
626{
627 return frame_pointer_motion(frame, data, x, y);
628}
629
630enum theme_location
631frame_pointer_motion(struct frame *frame, void *data, int x, int y)
632{
633 struct frame_pointer *pointer = frame_pointer_get(frame, data);
634 struct frame_button *button = frame_find_button(frame, x, y);
635 enum theme_location location;
636
637 location = theme_get_location(frame->theme, x, y,
638 frame->width, frame->height,
639 frame->flags & FRAME_FLAG_MAXIMIZED ?
640 THEME_FRAME_MAXIMIZED : 0);
641 if (!pointer)
642 return location;
643
644 pointer->x = x;
645 pointer->y = y;
646
647 if (pointer->hover_button == button)
648 return location;
649
650 if (pointer->hover_button)
651 frame_button_leave(pointer->hover_button, pointer);
652
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500653 pointer->hover_button = button;
654
655 if (pointer->hover_button)
656 frame_button_enter(pointer->hover_button);
657
658 return location;
659}
660
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500661static void
662frame_pointer_button_destroy(struct frame_pointer_button *button)
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500663{
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500664 wl_list_remove(&button->link);
665 free(button);
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500666}
667
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500668static void
669frame_pointer_button_press(struct frame *frame, struct frame_pointer *pointer,
670 struct frame_pointer_button *button)
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500671{
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500672 if (button->button == BTN_RIGHT) {
673 if (button->press_location == THEME_LOCATION_TITLEBAR)
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500674 frame->status |= FRAME_STATUS_MENU;
675
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500676 frame_pointer_button_destroy(button);
677
678 } else if (button->button == BTN_LEFT) {
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500679 if (pointer->hover_button) {
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500680 frame_button_press(pointer->hover_button);
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500681 } else {
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500682 switch (button->press_location) {
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500683 case THEME_LOCATION_TITLEBAR:
684 frame->status |= FRAME_STATUS_MOVE;
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500685
686 frame_pointer_button_destroy(button);
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500687 break;
688 case THEME_LOCATION_RESIZING_TOP:
689 case THEME_LOCATION_RESIZING_BOTTOM:
690 case THEME_LOCATION_RESIZING_LEFT:
691 case THEME_LOCATION_RESIZING_RIGHT:
692 case THEME_LOCATION_RESIZING_TOP_LEFT:
693 case THEME_LOCATION_RESIZING_TOP_RIGHT:
694 case THEME_LOCATION_RESIZING_BOTTOM_LEFT:
695 case THEME_LOCATION_RESIZING_BOTTOM_RIGHT:
696 frame->status |= FRAME_STATUS_RESIZE;
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500697
698 frame_pointer_button_destroy(button);
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500699 break;
700 default:
701 break;
702 }
703 }
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500704 }
705}
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500706
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500707static void
708frame_pointer_button_release(struct frame *frame, struct frame_pointer *pointer,
709 struct frame_pointer_button *button)
710{
711 if (button->button == BTN_LEFT && button->frame_button) {
712 if (button->frame_button == pointer->hover_button)
713 frame_button_release(button->frame_button);
714 else
715 frame_button_cancel(button->frame_button);
716 }
717}
718
719static void
720frame_pointer_button_cancel(struct frame *frame, struct frame_pointer *pointer,
721 struct frame_pointer_button *button)
722{
723 if (button->frame_button)
724 frame_button_cancel(button->frame_button);
725}
726
727void
728frame_pointer_leave(struct frame *frame, void *data)
729{
730 struct frame_pointer *pointer = frame_pointer_get(frame, data);
731 struct frame_pointer_button *button, *next;
732 if (!pointer)
733 return;
734
735 if (pointer->hover_button)
736 frame_button_leave(pointer->hover_button, pointer);
737
738 wl_list_for_each_safe(button, next, &pointer->down_buttons, link) {
739 frame_pointer_button_cancel(frame, pointer, button);
740 frame_pointer_button_destroy(button);
741 }
742
743 frame_pointer_destroy(pointer);
744}
745
746enum theme_location
747frame_pointer_button(struct frame *frame, void *data,
Quentin Glidicd8b17bc2016-07-10 11:00:55 +0200748 uint32_t btn, enum wl_pointer_button_state state)
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500749{
750 struct frame_pointer *pointer = frame_pointer_get(frame, data);
751 struct frame_pointer_button *button;
U. Artie Eoff6d71c3c2014-01-17 14:44:05 -0800752 enum theme_location location = THEME_LOCATION_EXTERIOR;
753
754 if (!pointer)
755 return location;
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500756
757 location = theme_get_location(frame->theme, pointer->x, pointer->y,
758 frame->width, frame->height,
759 frame->flags & FRAME_FLAG_MAXIMIZED ?
760 THEME_FRAME_MAXIMIZED : 0);
761
Quentin Glidicd8b17bc2016-07-10 11:00:55 +0200762 if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500763 button = malloc(sizeof *button);
764 if (!button)
765 return location;
766
767 button->button = btn;
768 button->press_location = location;
769 button->frame_button = pointer->hover_button;
770 wl_list_insert(&pointer->down_buttons, &button->link);
771
772 frame_pointer_button_press(frame, pointer, button);
Quentin Glidicd8b17bc2016-07-10 11:00:55 +0200773 } else if (state == WL_POINTER_BUTTON_STATE_RELEASED) {
Jason Ekstrand0bdd58f2013-10-27 22:25:03 -0500774 button = NULL;
775 wl_list_for_each(button, &pointer->down_buttons, link)
776 if (button->button == btn)
777 break;
778 /* Make sure we didn't hit the end */
779 if (&button->link == &pointer->down_buttons)
780 return location;
781
782 location = button->press_location;
783 frame_pointer_button_release(frame, pointer, button);
784 frame_pointer_button_destroy(button);
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500785 }
786
787 return location;
788}
789
Derek Foreman96906412015-11-06 15:56:07 -0600790enum theme_location
Jason Ekstrand3f66cf92013-10-13 19:08:40 -0500791frame_touch_down(struct frame *frame, void *data, int32_t id, int x, int y)
792{
793 struct frame_touch *touch = frame_touch_get(frame, data);
794 struct frame_button *button = frame_find_button(frame, x, y);
795 enum theme_location location;
796
Jason Ekstrand3f66cf92013-10-13 19:08:40 -0500797 location = theme_get_location(frame->theme, x, y,
798 frame->width, frame->height,
799 frame->flags & FRAME_FLAG_MAXIMIZED ?
800 THEME_FRAME_MAXIMIZED : 0);
801
Derek Foreman96906412015-11-06 15:56:07 -0600802 if (id > 0)
803 return location;
804
805 if (touch && button) {
806 touch->button = button;
807 frame_button_press(touch->button);
808 return location;
809 }
810
Jason Ekstrand3f66cf92013-10-13 19:08:40 -0500811 switch (location) {
812 case THEME_LOCATION_TITLEBAR:
813 frame->status |= FRAME_STATUS_MOVE;
814 break;
815 case THEME_LOCATION_RESIZING_TOP:
816 case THEME_LOCATION_RESIZING_BOTTOM:
817 case THEME_LOCATION_RESIZING_LEFT:
818 case THEME_LOCATION_RESIZING_RIGHT:
819 case THEME_LOCATION_RESIZING_TOP_LEFT:
820 case THEME_LOCATION_RESIZING_TOP_RIGHT:
821 case THEME_LOCATION_RESIZING_BOTTOM_LEFT:
822 case THEME_LOCATION_RESIZING_BOTTOM_RIGHT:
823 frame->status |= FRAME_STATUS_RESIZE;
824 break;
825 default:
826 break;
827 }
Derek Foreman96906412015-11-06 15:56:07 -0600828 return location;
Jason Ekstrand3f66cf92013-10-13 19:08:40 -0500829}
830
831void
832frame_touch_up(struct frame *frame, void *data, int32_t id)
833{
834 struct frame_touch *touch = frame_touch_get(frame, data);
835
836 if (id > 0)
837 return;
838
U. Artie Eoff6d71c3c2014-01-17 14:44:05 -0800839 if (touch && touch->button) {
Jason Ekstrand3f66cf92013-10-13 19:08:40 -0500840 frame_button_release(touch->button);
841 frame_touch_destroy(touch);
Jason Ekstrand3f66cf92013-10-13 19:08:40 -0500842 }
843}
844
Xiong Zhangbfb4ade2014-06-12 11:06:25 +0800845enum theme_location
846frame_double_click(struct frame *frame, void *data,
Quentin Glidicd8b17bc2016-07-10 11:00:55 +0200847 uint32_t btn, enum wl_pointer_button_state state)
Xiong Zhangbfb4ade2014-06-12 11:06:25 +0800848{
849 struct frame_pointer *pointer = frame_pointer_get(frame, data);
850 struct frame_button *button;
851 enum theme_location location = THEME_LOCATION_EXTERIOR;
852
853 location = theme_get_location(frame->theme, pointer->x, pointer->y,
854 frame->width, frame->height,
855 frame->flags & FRAME_FLAG_MAXIMIZED ?
856 THEME_FRAME_MAXIMIZED : 0);
857
858 button = frame_find_button(frame, pointer->x, pointer->y);
859
860 if (location != THEME_LOCATION_TITLEBAR || btn != BTN_LEFT)
861 return location;
862
Quentin Glidicd8b17bc2016-07-10 11:00:55 +0200863 if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
Xiong Zhangbfb4ade2014-06-12 11:06:25 +0800864 if (button)
865 frame_button_press(button);
866 else
867 frame->status |= FRAME_STATUS_MAXIMIZE;
Quentin Glidicd8b17bc2016-07-10 11:00:55 +0200868 } else if (state == WL_POINTER_BUTTON_STATE_RELEASED) {
Xiong Zhangbfb4ade2014-06-12 11:06:25 +0800869 if (button)
870 frame_button_release(button);
871 }
872
873 return location;
874}
875
Jason Ekstrand3f66cf92013-10-13 19:08:40 -0500876void
Xiong Zhang382de462014-06-12 11:06:26 +0800877frame_double_touch_down(struct frame *frame, void *data, int32_t id,
878 int x, int y)
879{
880 struct frame_touch *touch = frame_touch_get(frame, data);
881 struct frame_button *button = frame_find_button(frame, x, y);
882 enum theme_location location;
883
884 if (touch && button) {
885 touch->button = button;
886 frame_button_press(touch->button);
887 return;
888 }
889
890 location = theme_get_location(frame->theme, x, y,
891 frame->width, frame->height,
892 frame->flags & FRAME_FLAG_MAXIMIZED ?
893 THEME_FRAME_MAXIMIZED : 0);
894
895 switch (location) {
896 case THEME_LOCATION_TITLEBAR:
897 frame->status |= FRAME_STATUS_MAXIMIZE;
898 break;
899 case THEME_LOCATION_RESIZING_TOP:
900 case THEME_LOCATION_RESIZING_BOTTOM:
901 case THEME_LOCATION_RESIZING_LEFT:
902 case THEME_LOCATION_RESIZING_RIGHT:
903 case THEME_LOCATION_RESIZING_TOP_LEFT:
904 case THEME_LOCATION_RESIZING_TOP_RIGHT:
905 case THEME_LOCATION_RESIZING_BOTTOM_LEFT:
906 case THEME_LOCATION_RESIZING_BOTTOM_RIGHT:
907 frame->status |= FRAME_STATUS_RESIZE;
908 break;
909 default:
910 break;
911 }
912}
913
914void
915frame_double_touch_up(struct frame *frame, void *data, int32_t id)
916{
917 struct frame_touch *touch = frame_touch_get(frame, data);
918
919 if (touch && touch->button) {
920 frame_button_release(touch->button);
921 frame_touch_destroy(touch);
922 }
923}
924
925void
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500926frame_repaint(struct frame *frame, cairo_t *cr)
927{
928 struct frame_button *button;
929 uint32_t flags = 0;
930
931 frame_refresh_geometry(frame);
932
933 if (frame->flags & FRAME_FLAG_MAXIMIZED)
934 flags |= THEME_FRAME_MAXIMIZED;
935
936 if (frame->flags & FRAME_FLAG_ACTIVE)
937 flags |= THEME_FRAME_ACTIVE;
938
939 cairo_save(cr);
940 theme_render_frame(frame->theme, cr, frame->width, frame->height,
Boyan Ding850a5142014-08-05 15:22:04 +0800941 frame->title, &frame->buttons, flags);
Jason Ekstrand01c9ec32013-10-13 19:08:39 -0500942 cairo_restore(cr);
943
944 wl_list_for_each(button, &frame->buttons, link)
945 frame_button_repaint(button, cr);
946
947 frame_status_clear(frame, FRAME_STATUS_REPAINT);
948}