desktop-shell: Fix black edges on scaled desktop pattern
[profile/ivi/weston-ivi-shell.git] / clients / resizor.c
1 /*
2  * Copyright © 2010 Intel Corporation
3  *
4  * Permission to use, copy, modify, distribute, and sell this software and its
5  * documentation for any purpose is hereby granted without fee, provided that
6  * the above copyright notice appear in all copies and that both that copyright
7  * notice and this permission notice appear in supporting documentation, and
8  * that the name of the copyright holders not be used in advertising or
9  * publicity pertaining to distribution of the software without specific,
10  * written prior permission.  The copyright holders make no representations
11  * about the suitability of this software for any purpose.  It is provided "as
12  * is" without express or implied warranty.
13  *
14  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16  * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
20  * OF THIS SOFTWARE.
21  */
22
23 #include "config.h"
24
25 #include <stdint.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <cairo.h>
30 #include <math.h>
31 #include <assert.h>
32
33 #include <linux/input.h>
34 #include <wayland-client.h>
35
36 #include "window.h"
37
38 struct spring {
39         double current;
40         double target;
41         double previous;
42 };
43
44 struct resizor {
45         struct display *display;
46         struct window *window;
47         struct widget *widget;
48         struct window *menu;
49         struct spring width;
50         struct spring height;
51         struct wl_callback *frame_callback;
52 };
53
54 static void
55 spring_update(struct spring *spring)
56 {
57         double current, force;
58
59         current = spring->current;
60         force = (spring->target - current) / 20.0 +
61                 (spring->previous - current);
62
63         spring->current = current + (current - spring->previous) + force;
64         spring->previous = current;
65 }
66
67 static int
68 spring_done(struct spring *spring)
69 {
70         return fabs(spring->previous - spring->target) < 0.1;
71 }
72
73 static const struct wl_callback_listener listener;
74
75 static void
76 frame_callback(void *data, struct wl_callback *callback, uint32_t time)
77 {
78         struct resizor *resizor = data;
79
80         assert(!callback || callback == resizor->frame_callback);
81
82         if (resizor->frame_callback) {
83                 wl_callback_destroy(resizor->frame_callback);
84                 resizor->frame_callback = NULL;
85         }
86
87         if (window_is_maximized(resizor->window))
88                 return;
89
90         spring_update(&resizor->width);
91         spring_update(&resizor->height);
92
93         widget_schedule_resize(resizor->widget,
94                                resizor->width.current + 0.5,
95                                resizor->height.current + 0.5);
96
97         if (!spring_done(&resizor->width) || !spring_done(&resizor->height)) {
98                 resizor->frame_callback =
99                         wl_surface_frame(
100                                 window_get_wl_surface(resizor->window));
101                 wl_callback_add_listener(resizor->frame_callback, &listener,
102                                          resizor);
103         }
104 }
105
106 static const struct wl_callback_listener listener = {
107         frame_callback
108 };
109
110 static void
111 redraw_handler(struct widget *widget, void *data)
112 {
113         struct resizor *resizor = data;
114         cairo_surface_t *surface;
115         cairo_t *cr;
116         struct rectangle allocation;
117
118         widget_get_allocation(resizor->widget, &allocation);
119
120         surface = window_get_surface(resizor->window);
121
122         cr = cairo_create(surface);
123         cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
124         cairo_rectangle(cr,
125                         allocation.x,
126                         allocation.y,
127                         allocation.width,
128                         allocation.height);
129         cairo_set_source_rgba(cr, 0, 0, 0, 0.8);
130         cairo_fill(cr);
131         cairo_destroy(cr);
132
133         cairo_surface_destroy(surface);
134 }
135
136 static void
137 keyboard_focus_handler(struct window *window,
138                        struct input *device, void *data)
139 {
140         struct resizor *resizor = data;
141
142         window_schedule_redraw(resizor->window);
143 }
144
145 static void
146 key_handler(struct window *window, struct input *input, uint32_t time,
147             uint32_t key, uint32_t sym, enum wl_keyboard_key_state state,
148             void *data)
149 {
150         struct resizor *resizor = data;
151         struct rectangle allocation;
152
153         if (state == WL_KEYBOARD_KEY_STATE_RELEASED)
154                 return;
155
156         window_get_allocation(resizor->window, &allocation);
157         resizor->width.current = allocation.width;
158         if (spring_done(&resizor->width))
159                 resizor->width.target = allocation.width;
160         resizor->height.current = allocation.height;
161         if (spring_done(&resizor->height))
162                 resizor->height.target = allocation.height;
163
164         switch (sym) {
165         case XKB_KEY_Up:
166                 if (allocation.height < 400)
167                         break;
168
169                 resizor->height.target = allocation.height - 200;
170                 break;
171
172         case XKB_KEY_Down:
173                 if (allocation.height > 1000)
174                         break;
175
176                 resizor->height.target = allocation.height + 200;
177                 break;
178
179         case XKB_KEY_Left:
180                 if (allocation.width < 400)
181                         break;
182
183                 resizor->width.target = allocation.width - 200;
184                 break;
185
186         case XKB_KEY_Right:
187                 if (allocation.width > 1000)
188                         break;
189
190                 resizor->width.target = allocation.width + 200;
191                 break;
192
193         case XKB_KEY_Escape:
194                 display_exit(resizor->display);
195                 break;
196         }
197
198         if (!resizor->frame_callback)
199                 frame_callback(resizor, NULL, 0);
200 }
201
202 static void
203 menu_func(struct window *window,
204           struct input *input, int index, void *user_data)
205 {
206         fprintf(stderr, "picked entry %d\n", index);
207 }
208
209 static void
210 show_menu(struct resizor *resizor, struct input *input, uint32_t time)
211 {
212         int32_t x, y;
213         static const char *entries[] = {
214                 "Roy", "Pris", "Leon", "Zhora"
215         };
216
217         input_get_position(input, &x, &y);
218         window_show_menu(resizor->display, input, time, resizor->window,
219                          x - 10, y - 10, menu_func, entries, 4);
220 }
221
222 static void
223 button_handler(struct widget *widget,
224                struct input *input, uint32_t time,
225                uint32_t button, enum wl_pointer_button_state state, void *data)
226 {
227         struct resizor *resizor = data;
228
229         switch (button) {
230         case BTN_RIGHT:
231                 if (state == WL_POINTER_BUTTON_STATE_PRESSED)
232                         show_menu(resizor, input, time);
233                 break;
234         }
235 }
236
237 static struct resizor *
238 resizor_create(struct display *display)
239 {
240         struct resizor *resizor;
241
242         resizor = xzalloc(sizeof *resizor);
243         resizor->window = window_create(display);
244         resizor->widget = window_frame_create(resizor->window, resizor);
245         window_set_title(resizor->window, "Wayland Resizor");
246         resizor->display = display;
247
248         window_set_key_handler(resizor->window, key_handler);
249         window_set_user_data(resizor->window, resizor);
250         widget_set_redraw_handler(resizor->widget, redraw_handler);
251         window_set_keyboard_focus_handler(resizor->window,
252                                           keyboard_focus_handler);
253
254         widget_set_button_handler(resizor->widget, button_handler);
255
256         resizor->height.previous = 400;
257         resizor->height.current = 400;
258         resizor->height.target = 400;
259
260         resizor->width.previous = 400;
261         resizor->width.current = 400;
262         resizor->width.target = 400;
263
264         widget_schedule_resize(resizor->widget, 400, 400);
265
266         return resizor;
267 }
268
269 static void
270 resizor_destroy(struct resizor *resizor)
271 {
272         if (resizor->frame_callback)
273                 wl_callback_destroy(resizor->frame_callback);
274
275         widget_destroy(resizor->widget);
276         window_destroy(resizor->window);
277         free(resizor);
278 }
279
280 int
281 main(int argc, char *argv[])
282 {
283         struct display *display;
284         struct resizor *resizor;
285
286         display = display_create(&argc, argv);
287         if (display == NULL) {
288                 fprintf(stderr, "failed to create display: %m\n");
289                 return -1;
290         }
291
292         resizor = resizor_create(display);
293
294         display_run(display);
295
296         resizor_destroy(resizor);
297         display_destroy(display);
298
299         return 0;
300 }