1 /*
2  * Copyright © 2011 Tim Wiederhake
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 /**
25  * \file eventdemo.c
26  * \brief Demonstrate the use of Wayland's toytoolkit.
27  *
28  * Heavily commented demo program that can report all events that are
29  * dispatched to the window. For other functionality, eg. opengl/egl,
30  * drag and drop, etc. have a look at the other demos.
31  * \author Tim Wiederhake
32  */
33 
34 #include "config.h"
35 
36 #include <stdio.h>
37 #include <stdlib.h>
38 
39 #include <cairo.h>
40 
41 #include "shared/helpers.h"
42 #include "window.h"
43 
44 /** window title */
45 static char *title = "EventDemo";
46 
47 /** window width */
48 static int width = 500;
49 
50 /** window height */
51 static int height = 400;
52 
53 /** set if window has no borders */
54 static int noborder = 0;
55 
56 /** if non-zero, maximum window width */
57 static int width_max = 0;
58 
59 /** if non-zero, maximum window height */
60 static int height_max = 0;
61 
62 /** set to log redrawing */
63 static int log_redraw = 0;
64 
65 /** set to log resizing */
66 static int log_resize = 0;
67 
68 /** set to log keyboard focus */
69 static int log_focus = 0;
70 
71 /** set to log key events */
72 static int log_key = 0;
73 
74 /** set to log button events */
75 static int log_button = 0;
76 
77 /** set to log axis events */
78 static int log_axis = 0;
79 
80 /** set to log motion events */
81 static int log_motion = 0;
82 
83 /**
84  * \struct eventdemo
85  * \brief Holds all data the program needs per window
86  *
87  * In this demo the struct holds the position of a
88  * red rectangle that is drawn in the window's area.
89  */
90 struct eventdemo {
91 	struct window *window;
92 	struct widget *widget;
93 	struct display *display;
94 
95 	int x, y, w, h;
96 };
97 
98 /**
99  * \brief CALLBACK function, Wayland requests the window to redraw.
100  * \param widget widget to be redrawn
101  * \param data user data associated to the window
102  *
103  * Draws a red rectangle as demonstration of per-window data.
104  */
105 static void
redraw_handler(struct widget * widget,void * data)106 redraw_handler(struct widget *widget, void *data)
107 {
108 	struct eventdemo *e = data;
109 	cairo_surface_t *surface;
110 	cairo_t *cr;
111 	struct rectangle rect;
112 
113 	if (log_redraw)
114 		printf("redraw\n");
115 
116 	widget_get_allocation(e->widget, &rect);
117 	surface = window_get_surface(e->window);
118 
119 	cr = cairo_create(surface);
120 	cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
121 
122 	cairo_rectangle(cr, rect.x, rect.y, rect.width, rect.height);
123 	cairo_set_source_rgba(cr, 0, 0, 0, 0.8);
124 	cairo_fill(cr);
125 
126 	cairo_rectangle(cr, e->x, e->y, e->w, e->h);
127 	cairo_set_source_rgba(cr, 1.0, 0, 0, 1);
128 	cairo_fill(cr);
129 
130 	cairo_destroy(cr);
131 	cairo_surface_destroy(surface);
132 }
133 
134 /**
135  * \brief CALLBACK function, Wayland requests the window to resize.
136  * \param widget widget to be resized
137  * \param width desired width
138  * \param height desired height
139  * \param data user data associated to the window
140  */
141 
142 static void
resize_handler(struct widget * widget,int32_t width,int32_t height,void * data)143 resize_handler(struct widget *widget,
144 	       int32_t width, int32_t height, void *data)
145 {
146 	struct eventdemo *e = data;
147 	if (log_resize)
148 		printf("resize width: %d, height: %d\n", width, height);
149 
150 	/* if a maximum width is set, constrain to it */
151 	if (width_max && width_max < width)
152 		width = width_max;
153 
154 	/* if a maximum height is set, constrain to it */
155 	if (height_max && height_max < height)
156 		height = height_max;
157 
158 	/* set the new window dimensions */
159 	widget_set_size(e->widget, width, height);
160 }
161 
162 /**
163  * \brief CALLBACK function, Wayland informs about keyboard focus change
164  * \param window window
165  * \param device device that caused the focus change
166  * \param data user data associated to the window
167  */
168 static void
keyboard_focus_handler(struct window * window,struct input * device,void * data)169 keyboard_focus_handler(struct window *window,
170 		       struct input *device, void *data)
171 {
172 	int32_t x, y;
173 	struct eventdemo *e = data;
174 
175 	if (log_focus) {
176 		if (device) {
177 			input_get_position(device, &x, &y);
178 			printf("focus x: %d, y: %d\n", x, y);
179 		} else {
180 			printf("focus lost\n");
181 		}
182 	}
183 
184 	window_schedule_redraw(e->window);
185 }
186 
187 /**
188  * \brief CALLBACK function, Wayland informs about key event
189  * \param window window
190  * \param key keycode
191  * \param unicode associated character
192  * \param state pressed or released
193  * \param modifiers modifiers: ctrl, alt, meta etc.
194  * \param data user data associated to the window
195  */
196 static void
key_handler(struct window * window,struct input * input,uint32_t time,uint32_t key,uint32_t unicode,enum wl_keyboard_key_state state,void * data)197 key_handler(struct window *window, struct input *input, uint32_t time,
198             uint32_t key, uint32_t unicode, enum wl_keyboard_key_state state,
199 	    void *data)
200 {
201 	uint32_t modifiers = input_get_modifiers(input);
202 
203 	if (!log_key)
204 		return;
205 
206 	printf("key key: %d, unicode: %d, state: %s, modifiers: 0x%x\n",
207 	       key, unicode,
208 	       (state == WL_KEYBOARD_KEY_STATE_PRESSED) ? "pressed" :
209 							  "released",
210 	       modifiers);
211 }
212 
213 /**
214  * \brief CALLBACK function, Wayland informs about button event
215  * \param widget widget
216  * \param input input device that caused the button event
217  * \param time time the event happened
218  * \param button button
219  * \param state pressed or released
220  * \param data user data associated to the window
221  */
222 static void
button_handler(struct widget * widget,struct input * input,uint32_t time,uint32_t button,enum wl_pointer_button_state state,void * data)223 button_handler(struct widget *widget, struct input *input, uint32_t time,
224 	       uint32_t button, enum wl_pointer_button_state state, void *data)
225 {
226 	int32_t x, y;
227 
228 	if (!log_button)
229 		return;
230 
231 	input_get_position(input, &x, &y);
232 	printf("button time: %d, button: %d, state: %s, x: %d, y: %d\n",
233 	       time, button,
234 	       (state == WL_POINTER_BUTTON_STATE_PRESSED) ? "pressed" :
235 							    "released",
236 	       x, y);
237 }
238 
239 /**
240  * \brief CALLBACK function, Wayland informs about axis event
241  * \param widget widget
242  * \param input input device that caused the axis event
243  * \param time time the event happened
244  * \param axis vertical or horizontal
245  * \param value amount of scrolling
246  * \param data user data associated to the widget
247  */
248 static void
axis_handler(struct widget * widget,struct input * input,uint32_t time,uint32_t axis,wl_fixed_t value,void * data)249 axis_handler(struct widget *widget, struct input *input, uint32_t time,
250 	     uint32_t axis, wl_fixed_t value, void *data)
251 {
252 	if (!log_axis)
253 		return;
254 
255 	printf("axis time: %d, axis: %s, value: %f\n",
256 	       time,
257 	       axis == WL_POINTER_AXIS_VERTICAL_SCROLL ? "vertical" :
258 							 "horizontal",
259 	       wl_fixed_to_double(value));
260 }
261 
262 /**
263  * \brief CALLBACK function, Waylands informs about pointer motion
264  * \param widget widget
265  * \param input input device that caused the motion event
266  * \param time time the event happened
267  * \param x absolute x position
268  * \param y absolute y position
269  * \param sx x position relative to the window
270  * \param sy y position relative to the window
271  * \param data user data associated to the window
272  *
273  * Demonstrates the use of different cursors
274  */
275 static int
motion_handler(struct widget * widget,struct input * input,uint32_t time,float x,float y,void * data)276 motion_handler(struct widget *widget, struct input *input, uint32_t time,
277 	       float x, float y, void *data)
278 {
279 	struct eventdemo *e = data;
280 
281 	if (log_motion) {
282 		printf("motion time: %d, x: %f, y: %f\n", time, x, y);
283 	}
284 
285 	if (x > e->x && x < e->x + e->w)
286 		if (y > e->y && y < e->y + e->h)
287 			return CURSOR_HAND1;
288 
289 	return CURSOR_LEFT_PTR;
290 }
291 
292 /**
293  * \brief Create and initialise a new eventdemo window.
294  * The returned eventdemo instance should be destroyed using \c eventdemo_destroy().
295  * \param d associated display
296  */
297 static struct eventdemo *
eventdemo_create(struct display * d)298 eventdemo_create(struct display *d)
299 {
300 	struct eventdemo *e;
301 
302 	e = malloc(sizeof (struct eventdemo));
303 	if (e == NULL)
304 		return NULL;
305 
306 	e->window = window_create(d);
307 
308 	if (noborder) {
309 		/* Demonstrate how to create a borderless window.
310 		 * Move windows with META + left mouse button.
311 		 */
312 		e->widget = window_add_widget(e->window, e);
313 	} else {
314 		e->widget = window_frame_create(e->window, e);
315 		window_set_title(e->window, title);
316 	}
317 	e->display = d;
318 
319 	/* The eventdemo window draws a red rectangle as a demonstration
320 	 * of per-window data. The dimensions of that rectangle are set
321 	 * here.
322 	 */
323 	e->x = width * 1.0 / 4.0;
324 	e->w = width * 2.0 / 4.0;
325 	e->y = height * 1.0 / 4.0;
326 	e->h = height * 2.0 / 4.0;
327 
328 	/* Connect the user data to the window */
329 	window_set_user_data(e->window, e);
330 
331 	/* Set the callback redraw handler for the window */
332 	widget_set_redraw_handler(e->widget, redraw_handler);
333 
334 	/* Set the callback resize handler for the window */
335 	widget_set_resize_handler(e->widget, resize_handler);
336 
337 	/* Set the callback focus handler for the window */
338 	window_set_keyboard_focus_handler(e->window,
339 					  keyboard_focus_handler);
340 
341 	/* Set the callback key handler for the window */
342 	window_set_key_handler(e->window, key_handler);
343 
344 	/* Set the callback button handler for the window */
345 	widget_set_button_handler(e->widget, button_handler);
346 
347 	/* Set the callback motion handler for the window */
348 	widget_set_motion_handler(e->widget, motion_handler);
349 
350 	/* Set the callback axis handler for the window */
351 	widget_set_axis_handler(e->widget, axis_handler);
352 
353 	/* Initial drawing of the window */
354 	window_schedule_resize(e->window, width, height);
355 
356 	return e;
357 }
358 /**
359  * \brief Destroy eventdemo instance previously created by \c eventdemo_create().
360  * \param eventdemo eventdemo instance to destroy
361  */
eventdemo_destroy(struct eventdemo * eventdemo)362 static void eventdemo_destroy(struct eventdemo * eventdemo)
363 {
364 	widget_destroy(eventdemo->widget);
365 	window_destroy(eventdemo->window);
366 	free(eventdemo);
367 }
368 /**
369  * \brief command line options for eventdemo
370  */
371 static const struct weston_option eventdemo_options[] = {
372 	{ WESTON_OPTION_STRING, "title", 0, &title },
373 	{ WESTON_OPTION_INTEGER, "width", 'w', &width },
374 	{ WESTON_OPTION_INTEGER, "height", 'h', &height },
375 	{ WESTON_OPTION_INTEGER, "max-width", 0, &width_max },
376 	{ WESTON_OPTION_INTEGER, "max-height", 0, &height_max },
377 	{ WESTON_OPTION_BOOLEAN, "no-border", 'b', &noborder },
378 	{ WESTON_OPTION_BOOLEAN, "log-redraw", 0, &log_redraw },
379 	{ WESTON_OPTION_BOOLEAN, "log-resize", 0, &log_resize },
380 	{ WESTON_OPTION_BOOLEAN, "log-focus", 0, &log_focus },
381 	{ WESTON_OPTION_BOOLEAN, "log-key", 0, &log_key },
382 	{ WESTON_OPTION_BOOLEAN, "log-button", 0, &log_button },
383 	{ WESTON_OPTION_BOOLEAN, "log-axis", 0, &log_axis },
384 	{ WESTON_OPTION_BOOLEAN, "log-motion", 0, &log_motion },
385 };
386 
387 /**
388  * \brief Connects to the display, creates the window and hands over
389  * to the main loop.
390  */
391 int
main(int argc,char * argv[])392 main(int argc, char *argv[])
393 {
394 	struct display *d;
395 	struct eventdemo *e;
396 
397 	if (parse_options(eventdemo_options,
398 			  ARRAY_LENGTH(eventdemo_options), &argc, argv) > 1) {
399 		unsigned k;
400 		printf("Usage: %s [OPTIONS]\n\n", argv[0]);
401 		for (k = 0; k < ARRAY_LENGTH(eventdemo_options); k++) {
402 			const struct weston_option* p = &eventdemo_options[k];
403 			if (p->name) {
404 				printf("  --%s", p->name);
405 				if (p->type != WESTON_OPTION_BOOLEAN)
406 					printf("=VALUE");
407 				putchar('\n');
408 			}
409 			if (p->short_name) {
410 				printf("  -%c", p->short_name);
411 				if (p->type != WESTON_OPTION_BOOLEAN)
412 					printf("VALUE");
413 				putchar('\n');
414 			}
415 		}
416 		return 1;
417 	}
418 
419 	if (!log_redraw && !log_resize && !log_focus && !log_key &&
420 	    !log_button && !log_axis && !log_motion)
421 	  log_redraw = log_resize = log_focus = log_key =
422 	    log_button = log_axis = log_motion = 1;
423 
424 	/* Connect to the display and have the arguments parsed */
425 	d = display_create(&argc, argv);
426 	if (d == NULL) {
427 		fprintf(stderr, "failed to create display: %m\n");
428 		return -1;
429 	}
430 
431 	/* Create new eventdemo window */
432 	e = eventdemo_create(d);
433 	if (e == NULL) {
434 		fprintf(stderr, "failed to create eventdemo: %m\n");
435 		return -1;
436 	}
437 
438 	display_run(d);
439 
440 	/* Release resources */
441 	eventdemo_destroy(e);
442 	display_destroy(d);
443 
444 	return 0;
445 }
446