1 /*
2 * Copyright © 2010 Intel Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
22 */
23
24 #include "config.h"
25
26 #include <stdbool.h>
27 #include <stdint.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <cairo.h>
32 #include <math.h>
33 #include <assert.h>
34 #include <errno.h>
35
36 #include <linux/input.h>
37 #include <wayland-client.h>
38
39 #include "window.h"
40 #include "shared/xalloc.h"
41
42 struct spring {
43 double current;
44 double target;
45 double previous;
46 };
47
48 struct resizor {
49 struct display *display;
50 struct window *window;
51 struct widget *widget;
52 struct window *menu;
53 struct spring width;
54 struct spring height;
55 struct wl_callback *frame_callback;
56 bool pointer_locked;
57 bool locked_frame_callback_registered;
58 struct input *locked_input;
59 float pointer_x;
60 float pointer_y;
61 };
62
63 static void
spring_update(struct spring * spring)64 spring_update(struct spring *spring)
65 {
66 double current, force;
67
68 current = spring->current;
69 force = (spring->target - current) / 20.0 +
70 (spring->previous - current);
71
72 spring->current = current + (current - spring->previous) + force;
73 spring->previous = current;
74 }
75
76 static int
spring_done(struct spring * spring)77 spring_done(struct spring *spring)
78 {
79 return fabs(spring->previous - spring->target) < 0.1;
80 }
81
82 static const struct wl_callback_listener listener;
83
84 static void
frame_callback(void * data,struct wl_callback * callback,uint32_t time)85 frame_callback(void *data, struct wl_callback *callback, uint32_t time)
86 {
87 struct resizor *resizor = data;
88
89 assert(!callback || callback == resizor->frame_callback);
90
91 if (resizor->frame_callback) {
92 wl_callback_destroy(resizor->frame_callback);
93 resizor->frame_callback = NULL;
94 }
95
96 if (window_is_maximized(resizor->window))
97 return;
98
99 spring_update(&resizor->width);
100 spring_update(&resizor->height);
101
102 widget_schedule_resize(resizor->widget,
103 resizor->width.current + 0.5,
104 resizor->height.current + 0.5);
105
106 if (!spring_done(&resizor->width) || !spring_done(&resizor->height)) {
107 resizor->frame_callback =
108 wl_surface_frame(
109 window_get_wl_surface(resizor->window));
110 wl_callback_add_listener(resizor->frame_callback, &listener,
111 resizor);
112 }
113 }
114
115 static const struct wl_callback_listener listener = {
116 frame_callback
117 };
118
119 static void
redraw_handler(struct widget * widget,void * data)120 redraw_handler(struct widget *widget, void *data)
121 {
122 struct resizor *resizor = data;
123 cairo_surface_t *surface;
124 cairo_t *cr;
125 struct rectangle allocation;
126
127 widget_get_allocation(resizor->widget, &allocation);
128
129 surface = window_get_surface(resizor->window);
130
131 cr = cairo_create(surface);
132 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
133 cairo_rectangle(cr,
134 allocation.x,
135 allocation.y,
136 allocation.width,
137 allocation.height);
138 cairo_set_source_rgba(cr, 0, 0, 0, 0.8);
139 cairo_fill(cr);
140 cairo_destroy(cr);
141
142 cairo_surface_destroy(surface);
143 }
144
145 static void
keyboard_focus_handler(struct window * window,struct input * device,void * data)146 keyboard_focus_handler(struct window *window,
147 struct input *device, void *data)
148 {
149 struct resizor *resizor = data;
150
151 window_schedule_redraw(resizor->window);
152 }
153
154 static void
key_handler(struct window * window,struct input * input,uint32_t time,uint32_t key,uint32_t sym,enum wl_keyboard_key_state state,void * data)155 key_handler(struct window *window, struct input *input, uint32_t time,
156 uint32_t key, uint32_t sym, enum wl_keyboard_key_state state,
157 void *data)
158 {
159 struct resizor *resizor = data;
160 struct rectangle allocation;
161
162 if (state == WL_KEYBOARD_KEY_STATE_RELEASED)
163 return;
164
165 window_get_allocation(resizor->window, &allocation);
166 resizor->width.current = allocation.width;
167 if (spring_done(&resizor->width))
168 resizor->width.target = allocation.width;
169 resizor->height.current = allocation.height;
170 if (spring_done(&resizor->height))
171 resizor->height.target = allocation.height;
172
173 switch (sym) {
174 case XKB_KEY_Up:
175 if (allocation.height < 400)
176 break;
177
178 resizor->height.target = allocation.height - 200;
179 break;
180
181 case XKB_KEY_Down:
182 if (allocation.height > 1000)
183 break;
184
185 resizor->height.target = allocation.height + 200;
186 break;
187
188 case XKB_KEY_Left:
189 if (allocation.width < 400)
190 break;
191
192 resizor->width.target = allocation.width - 200;
193 break;
194
195 case XKB_KEY_Right:
196 if (allocation.width > 1000)
197 break;
198
199 resizor->width.target = allocation.width + 200;
200 break;
201
202 case XKB_KEY_Escape:
203 display_exit(resizor->display);
204 break;
205 }
206
207 if (!resizor->frame_callback)
208 frame_callback(resizor, NULL, 0);
209 }
210
211 static void
menu_func(void * data,struct input * input,int index)212 menu_func(void *data, struct input *input, int index)
213 {
214 fprintf(stderr, "picked entry %d\n", index);
215 }
216
217 static void
show_menu(struct resizor * resizor,struct input * input,uint32_t time)218 show_menu(struct resizor *resizor, struct input *input, uint32_t time)
219 {
220 int32_t x, y;
221 static const char *entries[] = {
222 "Roy", "Pris", "Leon", "Zhora"
223 };
224
225 input_get_position(input, &x, &y);
226 window_show_menu(resizor->display, input, time, resizor->window,
227 x - 10, y - 10, menu_func, entries, 4);
228 }
229
230 static void
locked_pointer_handle_motion(struct window * window,struct input * input,uint32_t time,float dx,float dy,void * data)231 locked_pointer_handle_motion(struct window *window,
232 struct input *input,
233 uint32_t time,
234 float dx,
235 float dy,
236 void *data)
237 {
238 struct resizor *resizor = data;
239
240 resizor->width.current += dx;
241 resizor->width.previous = resizor->width.current;
242 resizor->width.target = resizor->width.current;
243
244 resizor->height.current += dy;
245 resizor->height.previous = resizor->height.current;
246 resizor->height.target = resizor->height.current;
247
248 widget_schedule_resize(resizor->widget,
249 resizor->width.current,
250 resizor->height.current);
251 }
252
253 static void
handle_pointer_locked(struct window * window,struct input * input,void * data)254 handle_pointer_locked(struct window *window, struct input *input, void *data)
255 {
256 struct resizor *resizor = data;
257
258 resizor->pointer_locked = true;
259 input_set_pointer_image(input, CURSOR_BLANK);
260 }
261
262 static void
handle_pointer_unlocked(struct window * window,struct input * input,void * data)263 handle_pointer_unlocked(struct window *window, struct input *input, void *data)
264 {
265 struct resizor *resizor = data;
266
267 resizor->pointer_locked = false;
268 input_set_pointer_image(input, CURSOR_LEFT_PTR);
269 }
270
271 static const struct wl_callback_listener locked_pointer_frame_listener;
272
273 static void
locked_pointer_frame_callback(void * data,struct wl_callback * callback,uint32_t time)274 locked_pointer_frame_callback(void *data,
275 struct wl_callback *callback,
276 uint32_t time)
277 {
278 struct resizor *resizor = data;
279 struct wl_surface *surface;
280 struct rectangle allocation;
281 float x, y;
282
283 if (resizor->pointer_locked) {
284 widget_get_allocation(resizor->widget, &allocation);
285
286 x = resizor->pointer_x + (allocation.width - allocation.x);
287 y = resizor->pointer_y + (allocation.height - allocation.y);
288
289 widget_set_locked_pointer_cursor_hint(resizor->widget, x, y);
290 }
291
292 wl_callback_destroy(callback);
293
294 surface = window_get_wl_surface(resizor->window);
295 callback = wl_surface_frame(surface);
296 wl_callback_add_listener(callback,
297 &locked_pointer_frame_listener,
298 resizor);
299 }
300
301 static const struct wl_callback_listener locked_pointer_frame_listener = {
302 locked_pointer_frame_callback
303 };
304
305 static void
button_handler(struct widget * widget,struct input * input,uint32_t time,uint32_t button,enum wl_pointer_button_state state,void * data)306 button_handler(struct widget *widget,
307 struct input *input, uint32_t time,
308 uint32_t button, enum wl_pointer_button_state state, void *data)
309 {
310 struct resizor *resizor = data;
311 struct rectangle allocation;
312 struct wl_surface *surface;
313 struct wl_callback *callback;
314
315 if (button == BTN_RIGHT && state == WL_POINTER_BUTTON_STATE_PRESSED) {
316 show_menu(resizor, input, time);
317 } else if (button == BTN_LEFT &&
318 state == WL_POINTER_BUTTON_STATE_PRESSED) {
319 window_get_allocation(resizor->window, &allocation);
320
321 resizor->width.current = allocation.width;
322 resizor->width.previous = allocation.width;
323 resizor->width.target = allocation.width;
324
325 resizor->height.current = allocation.height;
326 resizor->height.previous = allocation.height;
327 resizor->height.target = allocation.height;
328
329 window_lock_pointer(resizor->window, input);
330 window_set_pointer_locked_handler(resizor->window,
331 handle_pointer_locked,
332 handle_pointer_unlocked);
333 resizor->locked_input = input;
334
335 if (resizor->locked_frame_callback_registered)
336 return;
337
338 surface = window_get_wl_surface(resizor->window);
339 callback = wl_surface_frame(surface);
340 wl_callback_add_listener(callback,
341 &locked_pointer_frame_listener,
342 resizor);
343 resizor->locked_frame_callback_registered = true;
344 } else if (button == BTN_LEFT &&
345 state == WL_POINTER_BUTTON_STATE_RELEASED) {
346 input_set_pointer_image(input, CURSOR_LEFT_PTR);
347 window_unlock_pointer(resizor->window);
348 }
349 }
350
351 static void
set_cursor_inv_offset(struct resizor * resizor,float x,float y)352 set_cursor_inv_offset(struct resizor *resizor, float x, float y)
353 {
354 struct rectangle allocation;
355
356 widget_get_allocation(resizor->widget, &allocation);
357
358 resizor->pointer_x = x - (allocation.width - allocation.x);
359 resizor->pointer_y = y - (allocation.height - allocation.y);
360 }
361
362 static int
enter_handler(struct widget * widget,struct input * input,float x,float y,void * data)363 enter_handler(struct widget *widget,
364 struct input *input,
365 float x, float y, void *data)
366 {
367 struct resizor *resizor = data;
368
369 set_cursor_inv_offset(resizor, x , y);
370
371 return CURSOR_LEFT_PTR;
372 }
373
374 static int
motion_handler(struct widget * widget,struct input * input,uint32_t time,float x,float y,void * data)375 motion_handler(struct widget *widget,
376 struct input *input, uint32_t time,
377 float x, float y, void *data)
378 {
379 struct resizor *resizor = data;
380
381 set_cursor_inv_offset(resizor, x , y);
382
383 return CURSOR_LEFT_PTR;
384 }
385
386 static struct resizor *
resizor_create(struct display * display)387 resizor_create(struct display *display)
388 {
389 struct resizor *resizor;
390
391 resizor = xzalloc(sizeof *resizor);
392 resizor->window = window_create(display);
393 resizor->widget = window_frame_create(resizor->window, resizor);
394 window_set_title(resizor->window, "Wayland Resizor");
395 resizor->display = display;
396
397 window_set_key_handler(resizor->window, key_handler);
398 window_set_user_data(resizor->window, resizor);
399 widget_set_redraw_handler(resizor->widget, redraw_handler);
400 window_set_keyboard_focus_handler(resizor->window,
401 keyboard_focus_handler);
402
403 widget_set_enter_handler(resizor->widget, enter_handler);
404 widget_set_motion_handler(resizor->widget, motion_handler);
405
406 window_set_locked_pointer_motion_handler(
407 resizor->window, locked_pointer_handle_motion);
408
409 widget_set_button_handler(resizor->widget, button_handler);
410
411 resizor->height.previous = 400;
412 resizor->height.current = 400;
413 resizor->height.target = 400;
414
415 resizor->width.previous = 400;
416 resizor->width.current = 400;
417 resizor->width.target = 400;
418
419 widget_schedule_resize(resizor->widget, 400, 400);
420
421 return resizor;
422 }
423
424 static void
resizor_destroy(struct resizor * resizor)425 resizor_destroy(struct resizor *resizor)
426 {
427 if (resizor->frame_callback)
428 wl_callback_destroy(resizor->frame_callback);
429
430 widget_destroy(resizor->widget);
431 window_destroy(resizor->window);
432 free(resizor);
433 }
434
435 int
main(int argc,char * argv[])436 main(int argc, char *argv[])
437 {
438 struct display *display;
439 struct resizor *resizor;
440
441 display = display_create(&argc, argv);
442 if (display == NULL) {
443 fprintf(stderr, "failed to create display: %s\n",
444 strerror(errno));
445 return -1;
446 }
447
448 resizor = resizor_create(display);
449
450 display_run(display);
451
452 resizor_destroy(resizor);
453 display_destroy(display);
454
455 return 0;
456 }
457