blob: 789d24364130564e32e28023b6974748a788b2e6 [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
Andrew Wedgbury9cd661e2014-04-07 12:40:35 +010024#include "config.h"
25
Alexander Larsson73469ed2013-05-28 16:23:34 +020026#include <stdint.h>
27#include <stdio.h>
28#include <stdlib.h>
29#include <stdarg.h>
30#include <string.h>
31#include <math.h>
32#include <cairo.h>
33
34#include <linux/input.h>
35#include <wayland-client.h>
36#include "window.h"
Jason Ekstrand2bb72fe2014-04-02 19:53:52 -050037#include "fullscreen-shell-client-protocol.h"
38
39struct fs_output {
40 struct wl_list link;
41 struct output *output;
42};
Alexander Larsson73469ed2013-05-28 16:23:34 +020043
44struct fullscreen {
45 struct display *display;
46 struct window *window;
47 struct widget *widget;
Jason Ekstrand2bb72fe2014-04-02 19:53:52 -050048 struct _wl_fullscreen_shell *fshell;
49 enum _wl_fullscreen_shell_present_method present_method;
Alexander Larsson73469ed2013-05-28 16:23:34 +020050 int width, height;
51 int fullscreen;
52 float pointer_x, pointer_y;
Jasper St. Pierreaf314bb2014-05-12 11:23:44 -040053 int draw_cursor;
Jason Ekstrand2bb72fe2014-04-02 19:53:52 -050054
55 struct wl_list output_list;
56 struct fs_output *current_output;
Alexander Larsson73469ed2013-05-28 16:23:34 +020057};
58
59static void
60fullscreen_handler(struct window *window, void *data)
61{
62 struct fullscreen *fullscreen = data;
63
64 fullscreen->fullscreen ^= 1;
65 window_set_fullscreen(window, fullscreen->fullscreen);
66}
67
68static void
69resize_handler(struct widget *widget, int width, int height, void *data)
70{
71 struct fullscreen *fullscreen = data;
72
73 widget_set_size(widget, fullscreen->width, fullscreen->height);
74}
75
76static void
77draw_string(cairo_t *cr,
78 const char *fmt, ...)
79{
80 char buffer[4096];
81 char *p, *end;
82 va_list argp;
83 cairo_text_extents_t text_extents;
84 cairo_font_extents_t font_extents;
85
86 cairo_save(cr);
87
88 cairo_select_font_face(cr, "sans",
89 CAIRO_FONT_SLANT_NORMAL,
90 CAIRO_FONT_WEIGHT_NORMAL);
91 cairo_set_font_size(cr, 14);
92
93 cairo_font_extents (cr, &font_extents);
94
95 va_start(argp, fmt);
96
97 vsnprintf(buffer, sizeof(buffer), fmt, argp);
98
99 p = buffer;
100 while (*p) {
101 end = strchr(p, '\n');
102 if (end)
103 *end = 0;
104
105 cairo_show_text(cr, p);
106 cairo_text_extents (cr, p, &text_extents);
107 cairo_rel_move_to (cr, -text_extents.x_advance, font_extents.height);
108
109 if (end)
110 p = end + 1;
111 else
112 break;
113 }
114
115 va_end(argp);
116
117 cairo_restore(cr);
118
119}
120
121static void
122redraw_handler(struct widget *widget, void *data)
123{
124 struct fullscreen *fullscreen = data;
125 struct rectangle allocation;
126 cairo_surface_t *surface;
127 cairo_t *cr;
128 int i;
129 double x, y, border;
Jason Ekstrand2bb72fe2014-04-02 19:53:52 -0500130 const char *method_name[] = { "default", "center", "zoom", "zoom_crop", "stretch"};
Alexander Larsson73469ed2013-05-28 16:23:34 +0200131
132 surface = window_get_surface(fullscreen->window);
133 if (surface == NULL ||
134 cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS) {
135 fprintf(stderr, "failed to create cairo egl surface\n");
136 return;
137 }
138
139 widget_get_allocation(fullscreen->widget, &allocation);
140
141 cr = widget_cairo_create(widget);
142
143 cairo_set_source_rgb(cr, 0, 0, 0);
144 cairo_paint (cr);
145
146 cairo_set_source_rgb(cr, 0, 0, 1);
147 cairo_set_line_width (cr, 10);
148 cairo_rectangle(cr, 5, 5, allocation.width - 10, allocation.height - 10);
149 cairo_stroke (cr);
150
151 cairo_move_to(cr,
152 allocation.x + 15,
153 allocation.y + 25);
154 cairo_set_source_rgb(cr, 1, 1, 1);
155
Jason Ekstrand2bb72fe2014-04-02 19:53:52 -0500156 if (fullscreen->fshell) {
157 draw_string(cr,
158 "Surface size: %d, %d\n"
159 "Scale: %d, transform: %d\n"
160 "Pointer: %f,%f\n"
161 "Output: %s, present method: %s\n"
162 "Keys: (s)cale, (t)ransform, si(z)e, (m)ethod,\n"
163 " (o)utput, modes(w)itch, (q)uit\n",
164 fullscreen->width, fullscreen->height,
165 window_get_buffer_scale (fullscreen->window),
166 window_get_buffer_transform (fullscreen->window),
167 fullscreen->pointer_x, fullscreen->pointer_y,
168 method_name[fullscreen->present_method],
169 fullscreen->current_output ? output_get_model(fullscreen->current_output->output): "null");
170 } else {
171 draw_string(cr,
172 "Surface size: %d, %d\n"
173 "Scale: %d, transform: %d\n"
174 "Pointer: %f,%f\n"
175 "Fullscreen: %d\n"
176 "Keys: (s)cale, (t)ransform, si(z)e, (f)ullscreen, (q)uit\n",
177 fullscreen->width, fullscreen->height,
178 window_get_buffer_scale (fullscreen->window),
179 window_get_buffer_transform (fullscreen->window),
180 fullscreen->pointer_x, fullscreen->pointer_y,
181 fullscreen->fullscreen);
182 }
Alexander Larsson73469ed2013-05-28 16:23:34 +0200183
184 y = 100;
185 i = 0;
186 while (y + 60 < fullscreen->height) {
187 border = (i++ % 2 == 0) ? 1 : 0.5;
188
189 x = 50;
190 cairo_set_line_width (cr, border);
191 while (x + 70 < fullscreen->width) {
Jasper St. Pierreaf314bb2014-05-12 11:23:44 -0400192 if (window_has_focus(fullscreen->window) &&
Jason Ekstrand7a17d422014-04-02 19:53:53 -0500193 fullscreen->pointer_x >= x && fullscreen->pointer_x < x + 50 &&
Alexander Larsson73469ed2013-05-28 16:23:34 +0200194 fullscreen->pointer_y >= y && fullscreen->pointer_y < y + 40) {
195 cairo_set_source_rgb(cr, 1, 0, 0);
196 cairo_rectangle(cr,
197 x, y,
198 50, 40);
199 cairo_fill(cr);
200 }
201 cairo_set_source_rgb(cr, 0, 1, 0);
202 cairo_rectangle(cr,
203 x + border/2.0, y + border/2.0,
204 50, 40);
205 cairo_stroke(cr);
206 x += 60;
207 }
208
209 y += 50;
210 }
211
Jasper St. Pierreaf314bb2014-05-12 11:23:44 -0400212 if (window_has_focus(fullscreen->window) && fullscreen->draw_cursor) {
Jason Ekstrand7a17d422014-04-02 19:53:53 -0500213 cairo_set_source_rgb(cr, 1, 1, 1);
214 cairo_set_line_width (cr, 8);
215 cairo_move_to(cr,
216 fullscreen->pointer_x - 12,
217 fullscreen->pointer_y - 12);
218 cairo_line_to(cr,
219 fullscreen->pointer_x + 12,
220 fullscreen->pointer_y + 12);
221 cairo_stroke(cr);
222
223 cairo_move_to(cr,
224 fullscreen->pointer_x + 12,
225 fullscreen->pointer_y - 12);
226 cairo_line_to(cr,
227 fullscreen->pointer_x - 12,
228 fullscreen->pointer_y + 12);
229 cairo_stroke(cr);
230
231 cairo_set_source_rgb(cr, 0, 0, 0);
232 cairo_set_line_width (cr, 4);
233 cairo_move_to(cr,
234 fullscreen->pointer_x - 10,
235 fullscreen->pointer_y - 10);
236 cairo_line_to(cr,
237 fullscreen->pointer_x + 10,
238 fullscreen->pointer_y + 10);
239 cairo_stroke(cr);
240
241 cairo_move_to(cr,
242 fullscreen->pointer_x + 10,
243 fullscreen->pointer_y - 10);
244 cairo_line_to(cr,
245 fullscreen->pointer_x - 10,
246 fullscreen->pointer_y + 10);
247 cairo_stroke(cr);
248 }
249
Alexander Larsson73469ed2013-05-28 16:23:34 +0200250 cairo_destroy(cr);
251}
252
253static void
254key_handler(struct window *window, struct input *input, uint32_t time,
255 uint32_t key, uint32_t sym, enum wl_keyboard_key_state state,
256 void *data)
257{
258 struct fullscreen *fullscreen = data;
259 int transform, scale;
260 static int current_size = 0;
Jason Ekstrand2bb72fe2014-04-02 19:53:52 -0500261 struct fs_output *fsout;
262 struct wl_output *wl_output;
Alexander Larsson73469ed2013-05-28 16:23:34 +0200263 int widths[] = { 640, 320, 800, 400 };
264 int heights[] = { 480, 240, 600, 300 };
265
266 if (state == WL_KEYBOARD_KEY_STATE_RELEASED)
267 return;
268
269 switch (sym) {
270 case XKB_KEY_t:
271 transform = window_get_buffer_transform (window);
272 transform = (transform + 1) % 8;
273 window_set_buffer_transform(window, transform);
274 window_schedule_redraw(window);
275 break;
276
277 case XKB_KEY_s:
278 scale = window_get_buffer_scale (window);
279 if (scale == 1)
280 scale = 2;
281 else
282 scale = 1;
283 window_set_buffer_scale(window, scale);
284 window_schedule_redraw(window);
285 break;
286
287 case XKB_KEY_z:
288 current_size = (current_size + 1) % 4;
289 fullscreen->width = widths[current_size];
290 fullscreen->height = heights[current_size];
291 window_schedule_resize(fullscreen->window,
292 fullscreen->width, fullscreen->height);
293 break;
294
Jason Ekstrand2bb72fe2014-04-02 19:53:52 -0500295 case XKB_KEY_m:
296 if (!fullscreen->fshell)
297 break;
298
299 wl_output = NULL;
300 if (fullscreen->current_output)
301 wl_output = output_get_wl_output(fullscreen->current_output->output);
302 fullscreen->present_method = (fullscreen->present_method + 1) % 5;
303 _wl_fullscreen_shell_present_surface(fullscreen->fshell,
304 window_get_wl_surface(fullscreen->window),
305 fullscreen->present_method,
306 wl_output);
307 window_schedule_redraw(window);
308 break;
309
310 case XKB_KEY_o:
311 if (!fullscreen->fshell)
312 break;
313
314 fsout = fullscreen->current_output;
315 wl_output = fsout ? output_get_wl_output(fsout->output) : NULL;
316
317 /* Clear the current presentation */
318 _wl_fullscreen_shell_present_surface(fullscreen->fshell, NULL,
319 0, wl_output);
320
321 if (fullscreen->current_output) {
322 if (fullscreen->current_output->link.next == &fullscreen->output_list)
323 fsout = NULL;
324 else
325 fsout = wl_container_of(fullscreen->current_output->link.next,
326 fsout, link);
327 } else {
328 fsout = wl_container_of(fullscreen->output_list.next,
329 fsout, link);
330 }
331
332 fullscreen->current_output = fsout;
333 wl_output = fsout ? output_get_wl_output(fsout->output) : NULL;
334 _wl_fullscreen_shell_present_surface(fullscreen->fshell,
335 window_get_wl_surface(fullscreen->window),
336 fullscreen->present_method,
337 wl_output);
338 window_schedule_redraw(window);
339 break;
340
341 case XKB_KEY_w:
342 if (!fullscreen->fshell || !fullscreen->current_output)
343 break;
344
345 wl_output = NULL;
346 if (fullscreen->current_output)
347 wl_output = output_get_wl_output(fullscreen->current_output->output);
348 _wl_fullscreen_shell_mode_feedback_destroy(
349 _wl_fullscreen_shell_present_surface_for_mode(fullscreen->fshell,
350 window_get_wl_surface(fullscreen->window),
351 wl_output, 0));
352 window_schedule_redraw(window);
353 break;
354
Alexander Larsson73469ed2013-05-28 16:23:34 +0200355 case XKB_KEY_f:
Jason Ekstrand2bb72fe2014-04-02 19:53:52 -0500356 if (fullscreen->fshell)
357 break;
Alexander Larsson73469ed2013-05-28 16:23:34 +0200358 fullscreen->fullscreen ^= 1;
359 window_set_fullscreen(window, fullscreen->fullscreen);
360 break;
361
362 case XKB_KEY_q:
363 exit (0);
364 break;
365 }
366}
367
368static int
369motion_handler(struct widget *widget,
370 struct input *input,
371 uint32_t time,
372 float x,
373 float y, void *data)
374{
375 struct fullscreen *fullscreen = data;
376
377 fullscreen->pointer_x = x;
378 fullscreen->pointer_y = y;
379
380 widget_schedule_redraw(widget);
Jason Ekstrand7a17d422014-04-02 19:53:53 -0500381
382 return fullscreen->draw_cursor ? CURSOR_BLANK : CURSOR_LEFT_PTR;
Alexander Larsson73469ed2013-05-28 16:23:34 +0200383}
384
Jason Ekstrand7a17d422014-04-02 19:53:53 -0500385static int
386enter_handler(struct widget *widget,
387 struct input *input,
388 float x, float y, void *data)
389{
390 struct fullscreen *fullscreen = data;
391
Jason Ekstrand7a17d422014-04-02 19:53:53 -0500392 fullscreen->pointer_x = x;
393 fullscreen->pointer_y = y;
394
395 widget_schedule_redraw(widget);
396
397 return fullscreen->draw_cursor ? CURSOR_BLANK : CURSOR_LEFT_PTR;
398}
399
400static void
Alexander Larsson73469ed2013-05-28 16:23:34 +0200401button_handler(struct widget *widget,
402 struct input *input, uint32_t time,
403 uint32_t button, enum wl_pointer_button_state state, void *data)
404{
405 struct fullscreen *fullscreen = data;
406
407 switch (button) {
408 case BTN_LEFT:
409 if (state == WL_POINTER_BUTTON_STATE_PRESSED)
410 window_move(fullscreen->window, input,
411 display_get_serial(fullscreen->display));
412 break;
413 case BTN_RIGHT:
414 if (state == WL_POINTER_BUTTON_STATE_PRESSED)
415 window_show_frame_menu(fullscreen->window, input, time);
416 break;
417 }
418}
419
420static void
Rusty Lynch1084da52013-08-15 09:10:08 -0700421touch_handler(struct widget *widget, struct input *input,
422 uint32_t serial, uint32_t time, int32_t id,
423 float x, float y, void *data)
424{
425 struct fullscreen *fullscreen = data;
Jasper St. Pierre01eaaac2013-11-12 20:19:57 -0500426 window_move(fullscreen->window, input, display_get_serial(fullscreen->display));
Rusty Lynch1084da52013-08-15 09:10:08 -0700427}
428
429static void
Jason Ekstrand7a17d422014-04-02 19:53:53 -0500430fshell_capability_handler(void *data, struct _wl_fullscreen_shell *fshell,
431 uint32_t capability)
432{
433 struct fullscreen *fullscreen = data;
434
435 switch (capability) {
436 case _WL_FULLSCREEN_SHELL_CAPABILITY_CURSOR_PLANE:
437 fullscreen->draw_cursor = 0;
438 break;
439 default:
440 break;
441 }
442}
443
444struct _wl_fullscreen_shell_listener fullscreen_shell_listener = {
445 fshell_capability_handler
446};
447
448static void
Alexander Larsson73469ed2013-05-28 16:23:34 +0200449usage(int error_code)
450{
451 fprintf(stderr, "Usage: fullscreen [OPTIONS]\n\n"
452 " -w <width>\tSet window width to <width>\n"
453 " -h <height>\tSet window height to <height>\n"
454 " --help\tShow this help text\n\n");
455
456 exit(error_code);
457}
458
Jason Ekstrand2bb72fe2014-04-02 19:53:52 -0500459static void
460output_handler(struct output *output, void *data)
461{
462 struct fullscreen *fullscreen = data;
463 struct fs_output *fsout;
464
465 /* If we've already seen this one, don't add it to the list */
466 wl_list_for_each(fsout, &fullscreen->output_list, link)
467 if (fsout->output == output)
468 return;
469
470 fsout = calloc(1, sizeof *fsout);
471 fsout->output = output;
472 wl_list_insert(&fullscreen->output_list, &fsout->link);
473}
474
475static void
476global_handler(struct display *display, uint32_t id, const char *interface,
477 uint32_t version, void *data)
478{
479 struct fullscreen *fullscreen = data;
480
481 if (strcmp(interface, "_wl_fullscreen_shell") == 0) {
482 fullscreen->fshell = display_bind(display, id,
483 &_wl_fullscreen_shell_interface,
484 1);
Jason Ekstrand7a17d422014-04-02 19:53:53 -0500485 _wl_fullscreen_shell_add_listener(fullscreen->fshell,
486 &fullscreen_shell_listener,
487 fullscreen);
Jason Ekstrand2bb72fe2014-04-02 19:53:52 -0500488 }
489}
490
Alexander Larsson73469ed2013-05-28 16:23:34 +0200491int main(int argc, char *argv[])
492{
493 struct fullscreen fullscreen;
494 struct display *d;
495 int i;
496
497 fullscreen.width = 640;
498 fullscreen.height = 480;
499 fullscreen.fullscreen = 0;
Jason Ekstrand2bb72fe2014-04-02 19:53:52 -0500500 fullscreen.present_method = _WL_FULLSCREEN_SHELL_PRESENT_METHOD_DEFAULT;
501 wl_list_init(&fullscreen.output_list);
502 fullscreen.current_output = NULL;
Alexander Larsson73469ed2013-05-28 16:23:34 +0200503
504 for (i = 1; i < argc; i++) {
505 if (strcmp(argv[i], "-w") == 0) {
506 if (++i >= argc)
507 usage(EXIT_FAILURE);
508
509 fullscreen.width = atol(argv[i]);
510 } else if (strcmp(argv[i], "-h") == 0) {
511 if (++i >= argc)
512 usage(EXIT_FAILURE);
513
514 fullscreen.height = atol(argv[i]);
515 } else if (strcmp(argv[i], "--help") == 0)
516 usage(EXIT_SUCCESS);
517 else
518 usage(EXIT_FAILURE);
519 }
520
521 d = display_create(&argc, argv);
522 if (d == NULL) {
523 fprintf(stderr, "failed to create display: %m\n");
524 return -1;
525 }
526
527 fullscreen.display = d;
Jason Ekstrand2bb72fe2014-04-02 19:53:52 -0500528 fullscreen.fshell = NULL;
529 display_set_user_data(fullscreen.display, &fullscreen);
530 display_set_global_handler(fullscreen.display, global_handler);
531 display_set_output_configure_handler(fullscreen.display, output_handler);
532
533 if (fullscreen.fshell) {
534 fullscreen.window = window_create_custom(d);
535 _wl_fullscreen_shell_present_surface(fullscreen.fshell,
536 window_get_wl_surface(fullscreen.window),
537 fullscreen.present_method,
538 NULL);
Jason Ekstrand7a17d422014-04-02 19:53:53 -0500539 /* If we get the CURSOR_PLANE capability, we'll change this */
540 fullscreen.draw_cursor = 1;
Jason Ekstrand2bb72fe2014-04-02 19:53:52 -0500541 } else {
542 fullscreen.window = window_create(d);
Jason Ekstrand7a17d422014-04-02 19:53:53 -0500543 fullscreen.draw_cursor = 0;
Jason Ekstrand2bb72fe2014-04-02 19:53:52 -0500544 }
545
Alexander Larsson73469ed2013-05-28 16:23:34 +0200546 fullscreen.widget =
547 window_add_widget(fullscreen.window, &fullscreen);
548
549 window_set_title(fullscreen.window, "Fullscreen");
Alexander Larsson73469ed2013-05-28 16:23:34 +0200550
551 widget_set_transparent(fullscreen.widget, 0);
Alexander Larsson73469ed2013-05-28 16:23:34 +0200552
Jason Ekstrand7a17d422014-04-02 19:53:53 -0500553 widget_set_default_cursor(fullscreen.widget, CURSOR_LEFT_PTR);
Alexander Larsson73469ed2013-05-28 16:23:34 +0200554 widget_set_resize_handler(fullscreen.widget, resize_handler);
555 widget_set_redraw_handler(fullscreen.widget, redraw_handler);
556 widget_set_button_handler(fullscreen.widget, button_handler);
557 widget_set_motion_handler(fullscreen.widget, motion_handler);
Jason Ekstrand7a17d422014-04-02 19:53:53 -0500558 widget_set_enter_handler(fullscreen.widget, enter_handler);
Alexander Larsson73469ed2013-05-28 16:23:34 +0200559
Rusty Lynch1084da52013-08-15 09:10:08 -0700560 widget_set_touch_down_handler(fullscreen.widget, touch_handler);
561
Alexander Larsson73469ed2013-05-28 16:23:34 +0200562 window_set_key_handler(fullscreen.window, key_handler);
563 window_set_fullscreen_handler(fullscreen.window, fullscreen_handler);
564
565 window_set_user_data(fullscreen.window, &fullscreen);
566 /* Hack to set minimum allocation so we can shrink later */
567 window_schedule_resize(fullscreen.window,
568 1, 1);
569 window_schedule_resize(fullscreen.window,
570 fullscreen.width, fullscreen.height);
571
572 display_run(d);
573
574 return 0;
575}