blob: fa8028a9f148fbe9301d532ce0659848bb206dbb [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;
Jason Ekstrand7a17d422014-04-02 19:53:53 -050053 int focussed, 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) {
Jason Ekstrand7a17d422014-04-02 19:53:53 -0500192 if (fullscreen->focussed &&
193 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
Jason Ekstrand7a17d422014-04-02 19:53:53 -0500212 if (fullscreen->focussed && fullscreen->draw_cursor) {
213 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
392 fullscreen->focussed++;
393
394 fullscreen->pointer_x = x;
395 fullscreen->pointer_y = y;
396
397 widget_schedule_redraw(widget);
398
399 return fullscreen->draw_cursor ? CURSOR_BLANK : CURSOR_LEFT_PTR;
400}
401
402static void
403leave_handler(struct widget *widget,
404 struct input *input, void *data)
405{
406 struct fullscreen *fullscreen = data;
407
408 fullscreen->focussed--;
409
410 widget_schedule_redraw(widget);
411}
Alexander Larsson73469ed2013-05-28 16:23:34 +0200412
413static void
414button_handler(struct widget *widget,
415 struct input *input, uint32_t time,
416 uint32_t button, enum wl_pointer_button_state state, void *data)
417{
418 struct fullscreen *fullscreen = data;
419
420 switch (button) {
421 case BTN_LEFT:
422 if (state == WL_POINTER_BUTTON_STATE_PRESSED)
423 window_move(fullscreen->window, input,
424 display_get_serial(fullscreen->display));
425 break;
426 case BTN_RIGHT:
427 if (state == WL_POINTER_BUTTON_STATE_PRESSED)
428 window_show_frame_menu(fullscreen->window, input, time);
429 break;
430 }
431}
432
433static void
Rusty Lynch1084da52013-08-15 09:10:08 -0700434touch_handler(struct widget *widget, struct input *input,
435 uint32_t serial, uint32_t time, int32_t id,
436 float x, float y, void *data)
437{
438 struct fullscreen *fullscreen = data;
Jasper St. Pierre01eaaac2013-11-12 20:19:57 -0500439 window_move(fullscreen->window, input, display_get_serial(fullscreen->display));
Rusty Lynch1084da52013-08-15 09:10:08 -0700440}
441
442static void
Jason Ekstrand7a17d422014-04-02 19:53:53 -0500443fshell_capability_handler(void *data, struct _wl_fullscreen_shell *fshell,
444 uint32_t capability)
445{
446 struct fullscreen *fullscreen = data;
447
448 switch (capability) {
449 case _WL_FULLSCREEN_SHELL_CAPABILITY_CURSOR_PLANE:
450 fullscreen->draw_cursor = 0;
451 break;
452 default:
453 break;
454 }
455}
456
457struct _wl_fullscreen_shell_listener fullscreen_shell_listener = {
458 fshell_capability_handler
459};
460
461static void
Alexander Larsson73469ed2013-05-28 16:23:34 +0200462usage(int error_code)
463{
464 fprintf(stderr, "Usage: fullscreen [OPTIONS]\n\n"
465 " -w <width>\tSet window width to <width>\n"
466 " -h <height>\tSet window height to <height>\n"
467 " --help\tShow this help text\n\n");
468
469 exit(error_code);
470}
471
Jason Ekstrand2bb72fe2014-04-02 19:53:52 -0500472static void
473output_handler(struct output *output, void *data)
474{
475 struct fullscreen *fullscreen = data;
476 struct fs_output *fsout;
477
478 /* If we've already seen this one, don't add it to the list */
479 wl_list_for_each(fsout, &fullscreen->output_list, link)
480 if (fsout->output == output)
481 return;
482
483 fsout = calloc(1, sizeof *fsout);
484 fsout->output = output;
485 wl_list_insert(&fullscreen->output_list, &fsout->link);
486}
487
488static void
489global_handler(struct display *display, uint32_t id, const char *interface,
490 uint32_t version, void *data)
491{
492 struct fullscreen *fullscreen = data;
493
494 if (strcmp(interface, "_wl_fullscreen_shell") == 0) {
495 fullscreen->fshell = display_bind(display, id,
496 &_wl_fullscreen_shell_interface,
497 1);
Jason Ekstrand7a17d422014-04-02 19:53:53 -0500498 _wl_fullscreen_shell_add_listener(fullscreen->fshell,
499 &fullscreen_shell_listener,
500 fullscreen);
Jason Ekstrand2bb72fe2014-04-02 19:53:52 -0500501 }
502}
503
Alexander Larsson73469ed2013-05-28 16:23:34 +0200504int main(int argc, char *argv[])
505{
506 struct fullscreen fullscreen;
507 struct display *d;
508 int i;
509
510 fullscreen.width = 640;
511 fullscreen.height = 480;
512 fullscreen.fullscreen = 0;
Jason Ekstrand7a17d422014-04-02 19:53:53 -0500513 fullscreen.focussed = 0;
Jason Ekstrand2bb72fe2014-04-02 19:53:52 -0500514 fullscreen.present_method = _WL_FULLSCREEN_SHELL_PRESENT_METHOD_DEFAULT;
515 wl_list_init(&fullscreen.output_list);
516 fullscreen.current_output = NULL;
Alexander Larsson73469ed2013-05-28 16:23:34 +0200517
518 for (i = 1; i < argc; i++) {
519 if (strcmp(argv[i], "-w") == 0) {
520 if (++i >= argc)
521 usage(EXIT_FAILURE);
522
523 fullscreen.width = atol(argv[i]);
524 } else if (strcmp(argv[i], "-h") == 0) {
525 if (++i >= argc)
526 usage(EXIT_FAILURE);
527
528 fullscreen.height = atol(argv[i]);
529 } else if (strcmp(argv[i], "--help") == 0)
530 usage(EXIT_SUCCESS);
531 else
532 usage(EXIT_FAILURE);
533 }
534
535 d = display_create(&argc, argv);
536 if (d == NULL) {
537 fprintf(stderr, "failed to create display: %m\n");
538 return -1;
539 }
540
541 fullscreen.display = d;
Jason Ekstrand2bb72fe2014-04-02 19:53:52 -0500542 fullscreen.fshell = NULL;
543 display_set_user_data(fullscreen.display, &fullscreen);
544 display_set_global_handler(fullscreen.display, global_handler);
545 display_set_output_configure_handler(fullscreen.display, output_handler);
546
547 if (fullscreen.fshell) {
548 fullscreen.window = window_create_custom(d);
549 _wl_fullscreen_shell_present_surface(fullscreen.fshell,
550 window_get_wl_surface(fullscreen.window),
551 fullscreen.present_method,
552 NULL);
Jason Ekstrand7a17d422014-04-02 19:53:53 -0500553 /* If we get the CURSOR_PLANE capability, we'll change this */
554 fullscreen.draw_cursor = 1;
Jason Ekstrand2bb72fe2014-04-02 19:53:52 -0500555 } else {
556 fullscreen.window = window_create(d);
Jason Ekstrand7a17d422014-04-02 19:53:53 -0500557 fullscreen.draw_cursor = 0;
Jason Ekstrand2bb72fe2014-04-02 19:53:52 -0500558 }
559
Alexander Larsson73469ed2013-05-28 16:23:34 +0200560 fullscreen.widget =
561 window_add_widget(fullscreen.window, &fullscreen);
562
563 window_set_title(fullscreen.window, "Fullscreen");
Alexander Larsson73469ed2013-05-28 16:23:34 +0200564
565 widget_set_transparent(fullscreen.widget, 0);
Alexander Larsson73469ed2013-05-28 16:23:34 +0200566
Jason Ekstrand7a17d422014-04-02 19:53:53 -0500567 widget_set_default_cursor(fullscreen.widget, CURSOR_LEFT_PTR);
Alexander Larsson73469ed2013-05-28 16:23:34 +0200568 widget_set_resize_handler(fullscreen.widget, resize_handler);
569 widget_set_redraw_handler(fullscreen.widget, redraw_handler);
570 widget_set_button_handler(fullscreen.widget, button_handler);
571 widget_set_motion_handler(fullscreen.widget, motion_handler);
Jason Ekstrand7a17d422014-04-02 19:53:53 -0500572 widget_set_enter_handler(fullscreen.widget, enter_handler);
573 widget_set_leave_handler(fullscreen.widget, leave_handler);
Alexander Larsson73469ed2013-05-28 16:23:34 +0200574
Rusty Lynch1084da52013-08-15 09:10:08 -0700575 widget_set_touch_down_handler(fullscreen.widget, touch_handler);
576
Alexander Larsson73469ed2013-05-28 16:23:34 +0200577 window_set_key_handler(fullscreen.window, key_handler);
578 window_set_fullscreen_handler(fullscreen.window, fullscreen_handler);
579
580 window_set_user_data(fullscreen.window, &fullscreen);
581 /* Hack to set minimum allocation so we can shrink later */
582 window_schedule_resize(fullscreen.window,
583 1, 1);
584 window_schedule_resize(fullscreen.window,
585 fullscreen.width, fullscreen.height);
586
587 display_run(d);
588
589 return 0;
590}