blob: 247232b2d98e618f9e4b59e8d8d9144ee23651e6 [file] [log] [blame]
Alexander Larsson73469ed2013-05-28 16:23:34 +02001/*
2 * Copyright © 2008 Kristian Høgsberg
3 * Copyright © 2012 Intel Corporation
4 *
5 * Permission to use, copy, modify, distribute, and sell this software and its
6 * documentation for any purpose is hereby granted without fee, provided that
7 * the above copyright notice appear in all copies and that both that copyright
8 * notice and this permission notice appear in supporting documentation, and
9 * that the name of the copyright holders not be used in advertising or
10 * publicity pertaining to distribution of the software without specific,
11 * written prior permission. The copyright holders make no representations
12 * about the suitability of this software for any purpose. It is provided "as
13 * is" without express or implied warranty.
14 *
15 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
17 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
18 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
19 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
20 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
21 * OF THIS SOFTWARE.
22 */
23
24#include <stdint.h>
25#include <stdio.h>
26#include <stdlib.h>
27#include <stdarg.h>
28#include <string.h>
29#include <math.h>
30#include <cairo.h>
31
32#include <linux/input.h>
33#include <wayland-client.h>
34#include "window.h"
Jason Ekstrand2bb72fe2014-04-02 19:53:52 -050035#include "fullscreen-shell-client-protocol.h"
36
37struct fs_output {
38 struct wl_list link;
39 struct output *output;
40};
Alexander Larsson73469ed2013-05-28 16:23:34 +020041
42struct fullscreen {
43 struct display *display;
44 struct window *window;
45 struct widget *widget;
Jason Ekstrand2bb72fe2014-04-02 19:53:52 -050046 struct _wl_fullscreen_shell *fshell;
47 enum _wl_fullscreen_shell_present_method present_method;
Alexander Larsson73469ed2013-05-28 16:23:34 +020048 int width, height;
49 int fullscreen;
50 float pointer_x, pointer_y;
Jason Ekstrand2bb72fe2014-04-02 19:53:52 -050051
52 struct wl_list output_list;
53 struct fs_output *current_output;
Alexander Larsson73469ed2013-05-28 16:23:34 +020054};
55
56static void
57fullscreen_handler(struct window *window, void *data)
58{
59 struct fullscreen *fullscreen = data;
60
61 fullscreen->fullscreen ^= 1;
62 window_set_fullscreen(window, fullscreen->fullscreen);
63}
64
65static void
66resize_handler(struct widget *widget, int width, int height, void *data)
67{
68 struct fullscreen *fullscreen = data;
69
70 widget_set_size(widget, fullscreen->width, fullscreen->height);
71}
72
73static void
74draw_string(cairo_t *cr,
75 const char *fmt, ...)
76{
77 char buffer[4096];
78 char *p, *end;
79 va_list argp;
80 cairo_text_extents_t text_extents;
81 cairo_font_extents_t font_extents;
82
83 cairo_save(cr);
84
85 cairo_select_font_face(cr, "sans",
86 CAIRO_FONT_SLANT_NORMAL,
87 CAIRO_FONT_WEIGHT_NORMAL);
88 cairo_set_font_size(cr, 14);
89
90 cairo_font_extents (cr, &font_extents);
91
92 va_start(argp, fmt);
93
94 vsnprintf(buffer, sizeof(buffer), fmt, argp);
95
96 p = buffer;
97 while (*p) {
98 end = strchr(p, '\n');
99 if (end)
100 *end = 0;
101
102 cairo_show_text(cr, p);
103 cairo_text_extents (cr, p, &text_extents);
104 cairo_rel_move_to (cr, -text_extents.x_advance, font_extents.height);
105
106 if (end)
107 p = end + 1;
108 else
109 break;
110 }
111
112 va_end(argp);
113
114 cairo_restore(cr);
115
116}
117
118static void
119redraw_handler(struct widget *widget, void *data)
120{
121 struct fullscreen *fullscreen = data;
122 struct rectangle allocation;
123 cairo_surface_t *surface;
124 cairo_t *cr;
125 int i;
126 double x, y, border;
Jason Ekstrand2bb72fe2014-04-02 19:53:52 -0500127 const char *method_name[] = { "default", "center", "zoom", "zoom_crop", "stretch"};
Alexander Larsson73469ed2013-05-28 16:23:34 +0200128
129 surface = window_get_surface(fullscreen->window);
130 if (surface == NULL ||
131 cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS) {
132 fprintf(stderr, "failed to create cairo egl surface\n");
133 return;
134 }
135
136 widget_get_allocation(fullscreen->widget, &allocation);
137
138 cr = widget_cairo_create(widget);
139
140 cairo_set_source_rgb(cr, 0, 0, 0);
141 cairo_paint (cr);
142
143 cairo_set_source_rgb(cr, 0, 0, 1);
144 cairo_set_line_width (cr, 10);
145 cairo_rectangle(cr, 5, 5, allocation.width - 10, allocation.height - 10);
146 cairo_stroke (cr);
147
148 cairo_move_to(cr,
149 allocation.x + 15,
150 allocation.y + 25);
151 cairo_set_source_rgb(cr, 1, 1, 1);
152
Jason Ekstrand2bb72fe2014-04-02 19:53:52 -0500153 if (fullscreen->fshell) {
154 draw_string(cr,
155 "Surface size: %d, %d\n"
156 "Scale: %d, transform: %d\n"
157 "Pointer: %f,%f\n"
158 "Output: %s, present method: %s\n"
159 "Keys: (s)cale, (t)ransform, si(z)e, (m)ethod,\n"
160 " (o)utput, modes(w)itch, (q)uit\n",
161 fullscreen->width, fullscreen->height,
162 window_get_buffer_scale (fullscreen->window),
163 window_get_buffer_transform (fullscreen->window),
164 fullscreen->pointer_x, fullscreen->pointer_y,
165 method_name[fullscreen->present_method],
166 fullscreen->current_output ? output_get_model(fullscreen->current_output->output): "null");
167 } else {
168 draw_string(cr,
169 "Surface size: %d, %d\n"
170 "Scale: %d, transform: %d\n"
171 "Pointer: %f,%f\n"
172 "Fullscreen: %d\n"
173 "Keys: (s)cale, (t)ransform, si(z)e, (f)ullscreen, (q)uit\n",
174 fullscreen->width, fullscreen->height,
175 window_get_buffer_scale (fullscreen->window),
176 window_get_buffer_transform (fullscreen->window),
177 fullscreen->pointer_x, fullscreen->pointer_y,
178 fullscreen->fullscreen);
179 }
Alexander Larsson73469ed2013-05-28 16:23:34 +0200180
181 y = 100;
182 i = 0;
183 while (y + 60 < fullscreen->height) {
184 border = (i++ % 2 == 0) ? 1 : 0.5;
185
186 x = 50;
187 cairo_set_line_width (cr, border);
188 while (x + 70 < fullscreen->width) {
189 if (fullscreen->pointer_x >= x && fullscreen->pointer_x < x + 50 &&
190 fullscreen->pointer_y >= y && fullscreen->pointer_y < y + 40) {
191 cairo_set_source_rgb(cr, 1, 0, 0);
192 cairo_rectangle(cr,
193 x, y,
194 50, 40);
195 cairo_fill(cr);
196 }
197 cairo_set_source_rgb(cr, 0, 1, 0);
198 cairo_rectangle(cr,
199 x + border/2.0, y + border/2.0,
200 50, 40);
201 cairo_stroke(cr);
202 x += 60;
203 }
204
205 y += 50;
206 }
207
208 cairo_destroy(cr);
209}
210
211static void
212key_handler(struct window *window, struct input *input, uint32_t time,
213 uint32_t key, uint32_t sym, enum wl_keyboard_key_state state,
214 void *data)
215{
216 struct fullscreen *fullscreen = data;
217 int transform, scale;
218 static int current_size = 0;
Jason Ekstrand2bb72fe2014-04-02 19:53:52 -0500219 struct fs_output *fsout;
220 struct wl_output *wl_output;
Alexander Larsson73469ed2013-05-28 16:23:34 +0200221 int widths[] = { 640, 320, 800, 400 };
222 int heights[] = { 480, 240, 600, 300 };
223
224 if (state == WL_KEYBOARD_KEY_STATE_RELEASED)
225 return;
226
227 switch (sym) {
228 case XKB_KEY_t:
229 transform = window_get_buffer_transform (window);
230 transform = (transform + 1) % 8;
231 window_set_buffer_transform(window, transform);
232 window_schedule_redraw(window);
233 break;
234
235 case XKB_KEY_s:
236 scale = window_get_buffer_scale (window);
237 if (scale == 1)
238 scale = 2;
239 else
240 scale = 1;
241 window_set_buffer_scale(window, scale);
242 window_schedule_redraw(window);
243 break;
244
245 case XKB_KEY_z:
246 current_size = (current_size + 1) % 4;
247 fullscreen->width = widths[current_size];
248 fullscreen->height = heights[current_size];
249 window_schedule_resize(fullscreen->window,
250 fullscreen->width, fullscreen->height);
251 break;
252
Jason Ekstrand2bb72fe2014-04-02 19:53:52 -0500253 case XKB_KEY_m:
254 if (!fullscreen->fshell)
255 break;
256
257 wl_output = NULL;
258 if (fullscreen->current_output)
259 wl_output = output_get_wl_output(fullscreen->current_output->output);
260 fullscreen->present_method = (fullscreen->present_method + 1) % 5;
261 _wl_fullscreen_shell_present_surface(fullscreen->fshell,
262 window_get_wl_surface(fullscreen->window),
263 fullscreen->present_method,
264 wl_output);
265 window_schedule_redraw(window);
266 break;
267
268 case XKB_KEY_o:
269 if (!fullscreen->fshell)
270 break;
271
272 fsout = fullscreen->current_output;
273 wl_output = fsout ? output_get_wl_output(fsout->output) : NULL;
274
275 /* Clear the current presentation */
276 _wl_fullscreen_shell_present_surface(fullscreen->fshell, NULL,
277 0, wl_output);
278
279 if (fullscreen->current_output) {
280 if (fullscreen->current_output->link.next == &fullscreen->output_list)
281 fsout = NULL;
282 else
283 fsout = wl_container_of(fullscreen->current_output->link.next,
284 fsout, link);
285 } else {
286 fsout = wl_container_of(fullscreen->output_list.next,
287 fsout, link);
288 }
289
290 fullscreen->current_output = fsout;
291 wl_output = fsout ? output_get_wl_output(fsout->output) : NULL;
292 _wl_fullscreen_shell_present_surface(fullscreen->fshell,
293 window_get_wl_surface(fullscreen->window),
294 fullscreen->present_method,
295 wl_output);
296 window_schedule_redraw(window);
297 break;
298
299 case XKB_KEY_w:
300 if (!fullscreen->fshell || !fullscreen->current_output)
301 break;
302
303 wl_output = NULL;
304 if (fullscreen->current_output)
305 wl_output = output_get_wl_output(fullscreen->current_output->output);
306 _wl_fullscreen_shell_mode_feedback_destroy(
307 _wl_fullscreen_shell_present_surface_for_mode(fullscreen->fshell,
308 window_get_wl_surface(fullscreen->window),
309 wl_output, 0));
310 window_schedule_redraw(window);
311 break;
312
Alexander Larsson73469ed2013-05-28 16:23:34 +0200313 case XKB_KEY_f:
Jason Ekstrand2bb72fe2014-04-02 19:53:52 -0500314 if (fullscreen->fshell)
315 break;
Alexander Larsson73469ed2013-05-28 16:23:34 +0200316 fullscreen->fullscreen ^= 1;
317 window_set_fullscreen(window, fullscreen->fullscreen);
318 break;
319
320 case XKB_KEY_q:
321 exit (0);
322 break;
323 }
324}
325
326static int
327motion_handler(struct widget *widget,
328 struct input *input,
329 uint32_t time,
330 float x,
331 float y, void *data)
332{
333 struct fullscreen *fullscreen = data;
334
335 fullscreen->pointer_x = x;
336 fullscreen->pointer_y = y;
337
338 widget_schedule_redraw(widget);
339 return 0;
340}
341
342
343static void
344button_handler(struct widget *widget,
345 struct input *input, uint32_t time,
346 uint32_t button, enum wl_pointer_button_state state, void *data)
347{
348 struct fullscreen *fullscreen = data;
349
350 switch (button) {
351 case BTN_LEFT:
352 if (state == WL_POINTER_BUTTON_STATE_PRESSED)
353 window_move(fullscreen->window, input,
354 display_get_serial(fullscreen->display));
355 break;
356 case BTN_RIGHT:
357 if (state == WL_POINTER_BUTTON_STATE_PRESSED)
358 window_show_frame_menu(fullscreen->window, input, time);
359 break;
360 }
361}
362
363static void
Rusty Lynch1084da52013-08-15 09:10:08 -0700364touch_handler(struct widget *widget, struct input *input,
365 uint32_t serial, uint32_t time, int32_t id,
366 float x, float y, void *data)
367{
368 struct fullscreen *fullscreen = data;
Jasper St. Pierre01eaaac2013-11-12 20:19:57 -0500369 window_move(fullscreen->window, input, display_get_serial(fullscreen->display));
Rusty Lynch1084da52013-08-15 09:10:08 -0700370}
371
372static void
Alexander Larsson73469ed2013-05-28 16:23:34 +0200373usage(int error_code)
374{
375 fprintf(stderr, "Usage: fullscreen [OPTIONS]\n\n"
376 " -w <width>\tSet window width to <width>\n"
377 " -h <height>\tSet window height to <height>\n"
378 " --help\tShow this help text\n\n");
379
380 exit(error_code);
381}
382
Jason Ekstrand2bb72fe2014-04-02 19:53:52 -0500383static void
384output_handler(struct output *output, void *data)
385{
386 struct fullscreen *fullscreen = data;
387 struct fs_output *fsout;
388
389 /* If we've already seen this one, don't add it to the list */
390 wl_list_for_each(fsout, &fullscreen->output_list, link)
391 if (fsout->output == output)
392 return;
393
394 fsout = calloc(1, sizeof *fsout);
395 fsout->output = output;
396 wl_list_insert(&fullscreen->output_list, &fsout->link);
397}
398
399static void
400global_handler(struct display *display, uint32_t id, const char *interface,
401 uint32_t version, void *data)
402{
403 struct fullscreen *fullscreen = data;
404
405 if (strcmp(interface, "_wl_fullscreen_shell") == 0) {
406 fullscreen->fshell = display_bind(display, id,
407 &_wl_fullscreen_shell_interface,
408 1);
409 }
410}
411
Alexander Larsson73469ed2013-05-28 16:23:34 +0200412int main(int argc, char *argv[])
413{
414 struct fullscreen fullscreen;
415 struct display *d;
416 int i;
417
418 fullscreen.width = 640;
419 fullscreen.height = 480;
420 fullscreen.fullscreen = 0;
Jason Ekstrand2bb72fe2014-04-02 19:53:52 -0500421 fullscreen.present_method = _WL_FULLSCREEN_SHELL_PRESENT_METHOD_DEFAULT;
422 wl_list_init(&fullscreen.output_list);
423 fullscreen.current_output = NULL;
Alexander Larsson73469ed2013-05-28 16:23:34 +0200424
425 for (i = 1; i < argc; i++) {
426 if (strcmp(argv[i], "-w") == 0) {
427 if (++i >= argc)
428 usage(EXIT_FAILURE);
429
430 fullscreen.width = atol(argv[i]);
431 } else if (strcmp(argv[i], "-h") == 0) {
432 if (++i >= argc)
433 usage(EXIT_FAILURE);
434
435 fullscreen.height = atol(argv[i]);
436 } else if (strcmp(argv[i], "--help") == 0)
437 usage(EXIT_SUCCESS);
438 else
439 usage(EXIT_FAILURE);
440 }
441
442 d = display_create(&argc, argv);
443 if (d == NULL) {
444 fprintf(stderr, "failed to create display: %m\n");
445 return -1;
446 }
447
448 fullscreen.display = d;
Jason Ekstrand2bb72fe2014-04-02 19:53:52 -0500449 fullscreen.fshell = NULL;
450 display_set_user_data(fullscreen.display, &fullscreen);
451 display_set_global_handler(fullscreen.display, global_handler);
452 display_set_output_configure_handler(fullscreen.display, output_handler);
453
454 if (fullscreen.fshell) {
455 fullscreen.window = window_create_custom(d);
456 _wl_fullscreen_shell_present_surface(fullscreen.fshell,
457 window_get_wl_surface(fullscreen.window),
458 fullscreen.present_method,
459 NULL);
460
461 } else {
462 fullscreen.window = window_create(d);
463 }
464
Alexander Larsson73469ed2013-05-28 16:23:34 +0200465 fullscreen.widget =
466 window_add_widget(fullscreen.window, &fullscreen);
467
468 window_set_title(fullscreen.window, "Fullscreen");
Alexander Larsson73469ed2013-05-28 16:23:34 +0200469
470 widget_set_transparent(fullscreen.widget, 0);
471 widget_set_default_cursor(fullscreen.widget, CURSOR_LEFT_PTR);
472
473 widget_set_resize_handler(fullscreen.widget, resize_handler);
474 widget_set_redraw_handler(fullscreen.widget, redraw_handler);
475 widget_set_button_handler(fullscreen.widget, button_handler);
476 widget_set_motion_handler(fullscreen.widget, motion_handler);
477
Rusty Lynch1084da52013-08-15 09:10:08 -0700478 widget_set_touch_down_handler(fullscreen.widget, touch_handler);
479
Alexander Larsson73469ed2013-05-28 16:23:34 +0200480 window_set_key_handler(fullscreen.window, key_handler);
481 window_set_fullscreen_handler(fullscreen.window, fullscreen_handler);
482
483 window_set_user_data(fullscreen.window, &fullscreen);
484 /* Hack to set minimum allocation so we can shrink later */
485 window_schedule_resize(fullscreen.window,
486 1, 1);
487 window_schedule_resize(fullscreen.window,
488 fullscreen.width, fullscreen.height);
489
490 display_run(d);
491
492 return 0;
493}