• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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