2 * Copyright © 2008 Kristian Høgsberg
3 * Copyright © 2012-2013 Collabora, Ltd.
4 * Copyright © 2013 Jason Ekstrand
6 * Permission to use, copy, modify, distribute, and sell this software and its
7 * documentation for any purpose is hereby granted without fee, provided that
8 * the above copyright notice appear in all copies and that both that copyright
9 * notice and this permission notice appear in supporting documentation, and
10 * that the name of the copyright holders not be used in advertising or
11 * publicity pertaining to distribution of the software without specific,
12 * written prior permission. The copyright holders make no representations
13 * about the suitability of this software for any purpose. It is provided "as
14 * is" without express or implied warranty.
16 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
19 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
20 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
21 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
29 #include <wayland-util.h>
30 #include <linux/input.h>
32 #include "cairo-util.h"
34 enum frame_button_flags {
35 FRAME_BUTTON_ALIGN_RIGHT = 0x1,
36 FRAME_BUTTON_DECORATED = 0x2,
37 FRAME_BUTTON_CLICK_DOWN = 0x4,
42 struct wl_list link; /* buttons_list */
44 cairo_surface_t *icon;
45 enum frame_button_flags flags;
54 enum frame_status status_effect;
57 struct frame_pointer_button {
60 enum theme_location press_location;
61 struct frame_button *frame_button;
64 struct frame_pointer {
70 struct frame_button *hover_button;
71 struct wl_list down_buttons;
80 struct frame_button *button;
84 int32_t width, height;
91 int32_t width, height;
99 struct wl_list buttons;
100 struct wl_list pointers;
101 struct wl_list touches;
104 static struct frame_button *
105 frame_button_create(struct frame *frame, const char *icon,
106 enum frame_status status_effect,
107 enum frame_button_flags flags)
109 struct frame_button *button;
111 button = calloc(1, sizeof *button);
115 button->icon = cairo_image_surface_create_from_png(icon);
121 button->frame = frame;
122 button->flags = flags;
123 button->status_effect = status_effect;
125 wl_list_insert(frame->buttons.prev, &button->link);
131 frame_button_destroy(struct frame_button *button)
133 cairo_surface_destroy(button->icon);
138 frame_button_enter(struct frame_button *button)
140 if (!button->hover_count)
141 button->frame->status |= FRAME_STATUS_REPAINT;
142 button->hover_count++;
146 frame_button_leave(struct frame_button *button, struct frame_pointer *pointer)
148 button->hover_count--;
149 if (!button->hover_count)
150 button->frame->status |= FRAME_STATUS_REPAINT;
154 frame_button_press(struct frame_button *button)
156 if (!button->press_count)
157 button->frame->status |= FRAME_STATUS_REPAINT;
158 button->press_count++;
160 if (button->flags & FRAME_BUTTON_CLICK_DOWN)
161 button->frame->status |= button->status_effect;
165 frame_button_release(struct frame_button *button)
167 button->press_count--;
168 if (button->press_count)
171 button->frame->status |= FRAME_STATUS_REPAINT;
173 if (!(button->flags & FRAME_BUTTON_CLICK_DOWN))
174 button->frame->status |= button->status_effect;
178 frame_button_cancel(struct frame_button *button)
180 button->press_count--;
181 if (!button->press_count)
182 button->frame->status |= FRAME_STATUS_REPAINT;
186 frame_button_repaint(struct frame_button *button, cairo_t *cr)
190 if (!button->allocation.width)
192 if (!button->allocation.height)
195 x = button->allocation.x;
196 y = button->allocation.y;
200 if (button->flags & FRAME_BUTTON_DECORATED) {
201 cairo_set_line_width(cr, 1);
203 cairo_set_source_rgb(cr, 0.0, 0.0, 0.0);
204 cairo_rectangle(cr, x, y, 25, 16);
206 cairo_stroke_preserve(cr);
208 if (button->press_count) {
209 cairo_set_source_rgb(cr, 0.7, 0.7, 0.7);
210 } else if (button->hover_count) {
211 cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
213 cairo_set_source_rgb(cr, 0.88, 0.88, 0.88);
221 cairo_set_source_surface(cr, button->icon, x, y);
227 static struct frame_pointer *
228 frame_pointer_get(struct frame *frame, void *data)
230 struct frame_pointer *pointer;
232 wl_list_for_each(pointer, &frame->pointers, link)
233 if (pointer->data == data)
236 pointer = calloc(1, sizeof *pointer);
240 pointer->data = data;
241 wl_list_init(&pointer->down_buttons);
242 wl_list_insert(&frame->pointers, &pointer->link);
248 frame_pointer_destroy(struct frame_pointer *pointer)
250 wl_list_remove(&pointer->link);
254 static struct frame_touch *
255 frame_touch_get(struct frame *frame, void *data)
257 struct frame_touch *touch;
259 wl_list_for_each(touch, &frame->touches, link)
260 if (touch->data == data)
263 touch = calloc(1, sizeof *touch);
268 wl_list_insert(&frame->touches, &touch->link);
274 frame_touch_destroy(struct frame_touch *touch)
276 wl_list_remove(&touch->link);
281 frame_destroy(struct frame *frame)
283 struct frame_button *button, *next;
284 struct frame_touch *touch, *next_touch;
285 struct frame_pointer *pointer, *next_pointer;
287 wl_list_for_each_safe(button, next, &frame->buttons, link)
288 frame_button_destroy(button);
290 wl_list_for_each_safe(touch, next_touch, &frame->touches, link)
291 frame_touch_destroy(touch);
293 wl_list_for_each_safe(pointer, next_pointer, &frame->pointers, link)
294 frame_pointer_destroy(pointer);
301 frame_create(struct theme *t, int32_t width, int32_t height, uint32_t buttons,
305 struct frame_button *button;
307 frame = calloc(1, sizeof *frame);
311 frame->width = width;
312 frame->height = height;
315 frame->status = FRAME_STATUS_REPAINT;
316 frame->geometry_dirty = 1;
318 wl_list_init(&frame->buttons);
319 wl_list_init(&frame->pointers);
320 wl_list_init(&frame->touches);
323 frame->title = strdup(title);
329 button = frame_button_create(frame,
330 DATADIR "/weston/icon_window.png",
332 FRAME_BUTTON_CLICK_DOWN);
337 if (buttons & FRAME_BUTTON_CLOSE) {
338 button = frame_button_create(frame,
339 DATADIR "/weston/sign_close.png",
341 FRAME_BUTTON_ALIGN_RIGHT |
342 FRAME_BUTTON_DECORATED);
347 if (buttons & FRAME_BUTTON_MAXIMIZE) {
348 button = frame_button_create(frame,
349 DATADIR "/weston/sign_maximize.png",
350 FRAME_STATUS_MAXIMIZE,
351 FRAME_BUTTON_ALIGN_RIGHT |
352 FRAME_BUTTON_DECORATED);
357 if (buttons & FRAME_BUTTON_MINIMIZE) {
358 button = frame_button_create(frame,
359 DATADIR "/weston/sign_minimize.png",
360 FRAME_STATUS_MINIMIZE,
361 FRAME_BUTTON_ALIGN_RIGHT |
362 FRAME_BUTTON_DECORATED);
370 frame_destroy(frame);
375 frame_set_title(struct frame *frame, const char *title)
388 frame->geometry_dirty = 1;
389 frame->status |= FRAME_STATUS_REPAINT;
395 frame_set_flag(struct frame *frame, enum frame_flag flag)
397 if (flag & FRAME_FLAG_MAXIMIZED && !(frame->flags & FRAME_FLAG_MAXIMIZED))
398 frame->geometry_dirty = 1;
400 frame->flags |= flag;
401 frame->status |= FRAME_STATUS_REPAINT;
405 frame_unset_flag(struct frame *frame, enum frame_flag flag)
407 if (flag & FRAME_FLAG_MAXIMIZED && frame->flags & FRAME_FLAG_MAXIMIZED)
408 frame->geometry_dirty = 1;
410 frame->flags &= ~flag;
411 frame->status |= FRAME_STATUS_REPAINT;
415 frame_resize(struct frame *frame, int32_t width, int32_t height)
417 frame->width = width;
418 frame->height = height;
420 frame->geometry_dirty = 1;
421 frame->status |= FRAME_STATUS_REPAINT;
425 frame_resize_inside(struct frame *frame, int32_t width, int32_t height)
427 struct theme *t = frame->theme;
428 int decoration_width, decoration_height, titlebar_height;
430 if (frame->title || !wl_list_empty(&frame->buttons))
431 titlebar_height = t->titlebar_height;
433 titlebar_height = t->width;
435 if (frame->flags & FRAME_FLAG_MAXIMIZED) {
436 decoration_width = t->width * 2;
437 decoration_height = t->width + titlebar_height;
439 decoration_width = (t->width + t->margin) * 2;
440 decoration_height = t->width +
441 titlebar_height + t->margin * 2;
444 frame_resize(frame, width + decoration_width,
445 height + decoration_height);
449 frame_width(struct frame *frame)
455 frame_height(struct frame *frame)
457 return frame->height;
461 frame_refresh_geometry(struct frame *frame)
463 struct frame_button *button;
464 struct theme *t = frame->theme;
465 int x_l, x_r, y, w, h, titlebar_height;
466 int32_t decoration_width, decoration_height;
468 if (!frame->geometry_dirty)
471 if (frame->title || !wl_list_empty(&frame->buttons))
472 titlebar_height = t->titlebar_height;
474 titlebar_height = t->width;
476 if (frame->flags & FRAME_FLAG_MAXIMIZED) {
477 decoration_width = t->width * 2;
478 decoration_height = t->width + titlebar_height;
480 frame->interior.x = t->width;
481 frame->interior.y = titlebar_height;
482 frame->interior.width = frame->width - decoration_width;
483 frame->interior.height = frame->height - decoration_height;
485 frame->opaque_margin = 0;
486 frame->shadow_margin = 0;
488 decoration_width = (t->width + t->margin) * 2;
489 decoration_height = t->width + titlebar_height + t->margin * 2;
491 frame->interior.x = t->width + t->margin;
492 frame->interior.y = titlebar_height + t->margin;
493 frame->interior.width = frame->width - decoration_width;
494 frame->interior.height = frame->height - decoration_height;
496 frame->opaque_margin = t->margin + t->frame_radius;
497 frame->shadow_margin = t->margin;
500 x_r = frame->width - t->width - frame->shadow_margin;
501 x_l = t->width + frame->shadow_margin;
502 y = t->width + frame->shadow_margin;
503 wl_list_for_each(button, &frame->buttons, link) {
504 const int button_padding = 4;
505 w = cairo_image_surface_get_width(button->icon);
506 h = cairo_image_surface_get_height(button->icon);
508 if (button->flags & FRAME_BUTTON_DECORATED)
511 if (button->flags & FRAME_BUTTON_ALIGN_RIGHT) {
514 button->allocation.x = x_r;
515 button->allocation.y = y;
516 button->allocation.width = w + 1;
517 button->allocation.height = h + 1;
519 x_r -= button_padding;
521 button->allocation.x = x_l;
522 button->allocation.y = y;
523 button->allocation.width = w + 1;
524 button->allocation.height = h + 1;
527 x_l += button_padding;
531 frame->geometry_dirty = 0;
535 frame_interior(struct frame *frame, int32_t *x, int32_t *y,
536 int32_t *width, int32_t *height)
538 frame_refresh_geometry(frame);
541 *x = frame->interior.x;
543 *y = frame->interior.y;
545 *width = frame->interior.width;
547 *height = frame->interior.height;
551 frame_input_rect(struct frame *frame, int32_t *x, int32_t *y,
552 int32_t *width, int32_t *height)
554 frame_refresh_geometry(frame);
557 *x = frame->shadow_margin;
559 *y = frame->shadow_margin;
561 *width = frame->width - frame->shadow_margin * 2;
563 *height = frame->height - frame->shadow_margin * 2;
567 frame_opaque_rect(struct frame *frame, int32_t *x, int32_t *y,
568 int32_t *width, int32_t *height)
570 frame_refresh_geometry(frame);
573 *x = frame->opaque_margin;
575 *y = frame->opaque_margin;
577 *width = frame->width - frame->opaque_margin * 2;
579 *height = frame->height - frame->opaque_margin * 2;
583 frame_get_shadow_margin(struct frame *frame)
585 frame_refresh_geometry(frame);
587 return frame->shadow_margin;
591 frame_status(struct frame *frame)
593 return frame->status;
597 frame_status_clear(struct frame *frame, enum frame_status status)
599 frame->status &= ~status;
602 static struct frame_button *
603 frame_find_button(struct frame *frame, int x, int y)
605 struct frame_button *button;
608 wl_list_for_each(button, &frame->buttons, link) {
609 rel_x = x - button->allocation.x;
610 rel_y = y - button->allocation.y;
612 if (0 <= rel_x && rel_x < button->allocation.width &&
613 0 <= rel_y && rel_y < button->allocation.height)
621 frame_pointer_enter(struct frame *frame, void *data, int x, int y)
623 return frame_pointer_motion(frame, data, x, y);
627 frame_pointer_motion(struct frame *frame, void *data, int x, int y)
629 struct frame_pointer *pointer = frame_pointer_get(frame, data);
630 struct frame_button *button = frame_find_button(frame, x, y);
631 enum theme_location location;
633 location = theme_get_location(frame->theme, x, y,
634 frame->width, frame->height,
635 frame->flags & FRAME_FLAG_MAXIMIZED ?
636 THEME_FRAME_MAXIMIZED : 0);
643 if (pointer->hover_button == button)
646 if (pointer->hover_button)
647 frame_button_leave(pointer->hover_button, pointer);
649 pointer->hover_button = button;
651 if (pointer->hover_button)
652 frame_button_enter(pointer->hover_button);
658 frame_pointer_button_destroy(struct frame_pointer_button *button)
660 wl_list_remove(&button->link);
665 frame_pointer_button_press(struct frame *frame, struct frame_pointer *pointer,
666 struct frame_pointer_button *button)
668 if (button->button == BTN_RIGHT) {
669 if (button->press_location == THEME_LOCATION_TITLEBAR)
670 frame->status |= FRAME_STATUS_MENU;
672 frame_pointer_button_destroy(button);
674 } else if (button->button == BTN_LEFT) {
675 if (pointer->hover_button) {
676 frame_button_press(pointer->hover_button);
678 switch (button->press_location) {
679 case THEME_LOCATION_TITLEBAR:
680 frame->status |= FRAME_STATUS_MOVE;
682 frame_pointer_button_destroy(button);
684 case THEME_LOCATION_RESIZING_TOP:
685 case THEME_LOCATION_RESIZING_BOTTOM:
686 case THEME_LOCATION_RESIZING_LEFT:
687 case THEME_LOCATION_RESIZING_RIGHT:
688 case THEME_LOCATION_RESIZING_TOP_LEFT:
689 case THEME_LOCATION_RESIZING_TOP_RIGHT:
690 case THEME_LOCATION_RESIZING_BOTTOM_LEFT:
691 case THEME_LOCATION_RESIZING_BOTTOM_RIGHT:
692 frame->status |= FRAME_STATUS_RESIZE;
694 frame_pointer_button_destroy(button);
704 frame_pointer_button_release(struct frame *frame, struct frame_pointer *pointer,
705 struct frame_pointer_button *button)
707 if (button->button == BTN_LEFT && button->frame_button) {
708 if (button->frame_button == pointer->hover_button)
709 frame_button_release(button->frame_button);
711 frame_button_cancel(button->frame_button);
716 frame_pointer_button_cancel(struct frame *frame, struct frame_pointer *pointer,
717 struct frame_pointer_button *button)
719 if (button->frame_button)
720 frame_button_cancel(button->frame_button);
724 frame_pointer_leave(struct frame *frame, void *data)
726 struct frame_pointer *pointer = frame_pointer_get(frame, data);
727 struct frame_pointer_button *button, *next;
731 if (pointer->hover_button)
732 frame_button_leave(pointer->hover_button, pointer);
734 wl_list_for_each_safe(button, next, &pointer->down_buttons, link) {
735 frame_pointer_button_cancel(frame, pointer, button);
736 frame_pointer_button_destroy(button);
739 frame_pointer_destroy(pointer);
743 frame_pointer_button(struct frame *frame, void *data,
744 uint32_t btn, enum frame_button_state state)
746 struct frame_pointer *pointer = frame_pointer_get(frame, data);
747 struct frame_pointer_button *button;
748 enum theme_location location = THEME_LOCATION_EXTERIOR;
753 location = theme_get_location(frame->theme, pointer->x, pointer->y,
754 frame->width, frame->height,
755 frame->flags & FRAME_FLAG_MAXIMIZED ?
756 THEME_FRAME_MAXIMIZED : 0);
758 if (state == FRAME_BUTTON_PRESSED) {
759 button = malloc(sizeof *button);
763 button->button = btn;
764 button->press_location = location;
765 button->frame_button = pointer->hover_button;
766 wl_list_insert(&pointer->down_buttons, &button->link);
768 frame_pointer_button_press(frame, pointer, button);
769 } else if (state == FRAME_BUTTON_RELEASED) {
771 wl_list_for_each(button, &pointer->down_buttons, link)
772 if (button->button == btn)
774 /* Make sure we didn't hit the end */
775 if (&button->link == &pointer->down_buttons)
778 location = button->press_location;
779 frame_pointer_button_release(frame, pointer, button);
780 frame_pointer_button_destroy(button);
787 frame_touch_down(struct frame *frame, void *data, int32_t id, int x, int y)
789 struct frame_touch *touch = frame_touch_get(frame, data);
790 struct frame_button *button = frame_find_button(frame, x, y);
791 enum theme_location location;
796 if (touch && button) {
797 touch->button = button;
798 frame_button_press(touch->button);
802 location = theme_get_location(frame->theme, x, y,
803 frame->width, frame->height,
804 frame->flags & FRAME_FLAG_MAXIMIZED ?
805 THEME_FRAME_MAXIMIZED : 0);
808 case THEME_LOCATION_TITLEBAR:
809 frame->status |= FRAME_STATUS_MOVE;
811 case THEME_LOCATION_RESIZING_TOP:
812 case THEME_LOCATION_RESIZING_BOTTOM:
813 case THEME_LOCATION_RESIZING_LEFT:
814 case THEME_LOCATION_RESIZING_RIGHT:
815 case THEME_LOCATION_RESIZING_TOP_LEFT:
816 case THEME_LOCATION_RESIZING_TOP_RIGHT:
817 case THEME_LOCATION_RESIZING_BOTTOM_LEFT:
818 case THEME_LOCATION_RESIZING_BOTTOM_RIGHT:
819 frame->status |= FRAME_STATUS_RESIZE;
827 frame_touch_up(struct frame *frame, void *data, int32_t id)
829 struct frame_touch *touch = frame_touch_get(frame, data);
834 if (touch && touch->button) {
835 frame_button_release(touch->button);
836 frame_touch_destroy(touch);
841 frame_double_click(struct frame *frame, void *data,
842 uint32_t btn, enum frame_button_state state)
844 struct frame_pointer *pointer = frame_pointer_get(frame, data);
845 struct frame_button *button;
846 enum theme_location location = THEME_LOCATION_EXTERIOR;
848 location = theme_get_location(frame->theme, pointer->x, pointer->y,
849 frame->width, frame->height,
850 frame->flags & FRAME_FLAG_MAXIMIZED ?
851 THEME_FRAME_MAXIMIZED : 0);
853 button = frame_find_button(frame, pointer->x, pointer->y);
855 if (location != THEME_LOCATION_TITLEBAR || btn != BTN_LEFT)
858 if (state == FRAME_BUTTON_PRESSED) {
860 frame_button_press(button);
862 frame->status |= FRAME_STATUS_MAXIMIZE;
863 } else if (state == FRAME_BUTTON_RELEASED) {
865 frame_button_release(button);
872 frame_repaint(struct frame *frame, cairo_t *cr)
874 struct frame_button *button;
877 frame_refresh_geometry(frame);
879 if (frame->flags & FRAME_FLAG_MAXIMIZED)
880 flags |= THEME_FRAME_MAXIMIZED;
882 if (frame->flags & FRAME_FLAG_ACTIVE)
883 flags |= THEME_FRAME_ACTIVE;
886 theme_render_frame(frame->theme, cr, frame->width, frame->height,
887 frame->title, &frame->buttons, flags);
890 wl_list_for_each(button, &frame->buttons, link)
891 frame_button_repaint(button, cr);
893 frame_status_clear(frame, FRAME_STATUS_REPAINT);