1 /*
2 * Copyright © 2011-2014 Intel Corporation
3 *
4 * Permission to use, copy, modify, distribute, and sell this software
5 * and its documentation for any purpose is hereby granted without
6 * fee, provided that the above copyright notice appear in all copies
7 * and that both that copyright notice and this permission notice
8 * appear in supporting documentation, and that the name of the
9 * copyright holders not be used in advertising or publicity
10 * pertaining to distribution of the software without specific,
11 * written prior permission. The copyright holders make no
12 * representations about the suitability of this software for any
13 * purpose. It is provided "as is" without express or implied
14 * warranty.
15 *
16 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
17 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
18 * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
19 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
20 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
21 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
22 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
23 * SOFTWARE.
24 */
25
26 #include <xwayland-config.h>
27
28 #include <randrstr.h>
29 #include <X11/Xatom.h>
30
31 #include "xwayland-cvt.h"
32 #include "xwayland-output.h"
33 #include "xwayland-screen.h"
34 #include "xwayland-window.h"
35
36 #include "xdg-output-unstable-v1-client-protocol.h"
37
38 #define ALL_ROTATIONS (RR_Rotate_0 | \
39 RR_Rotate_90 | \
40 RR_Rotate_180 | \
41 RR_Rotate_270 | \
42 RR_Reflect_X | \
43 RR_Reflect_Y)
44
45 static void xwl_output_get_xdg_output(struct xwl_output *xwl_output);
46
47 static Rotation
wl_transform_to_xrandr(enum wl_output_transform transform)48 wl_transform_to_xrandr(enum wl_output_transform transform)
49 {
50 switch (transform) {
51 default:
52 case WL_OUTPUT_TRANSFORM_NORMAL:
53 return RR_Rotate_0;
54 case WL_OUTPUT_TRANSFORM_90:
55 return RR_Rotate_90;
56 case WL_OUTPUT_TRANSFORM_180:
57 return RR_Rotate_180;
58 case WL_OUTPUT_TRANSFORM_270:
59 return RR_Rotate_270;
60 case WL_OUTPUT_TRANSFORM_FLIPPED:
61 return RR_Reflect_X | RR_Rotate_0;
62 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
63 return RR_Reflect_X | RR_Rotate_90;
64 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
65 return RR_Reflect_X | RR_Rotate_180;
66 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
67 return RR_Reflect_X | RR_Rotate_270;
68 }
69 }
70
71 static int
wl_subpixel_to_xrandr(int subpixel)72 wl_subpixel_to_xrandr(int subpixel)
73 {
74 switch (subpixel) {
75 default:
76 case WL_OUTPUT_SUBPIXEL_UNKNOWN:
77 return SubPixelUnknown;
78 case WL_OUTPUT_SUBPIXEL_NONE:
79 return SubPixelNone;
80 case WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB:
81 return SubPixelHorizontalRGB;
82 case WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR:
83 return SubPixelHorizontalBGR;
84 case WL_OUTPUT_SUBPIXEL_VERTICAL_RGB:
85 return SubPixelVerticalRGB;
86 case WL_OUTPUT_SUBPIXEL_VERTICAL_BGR:
87 return SubPixelVerticalBGR;
88 }
89 }
90
91 static void
output_handle_geometry(void * data,struct wl_output * wl_output,int x,int y,int physical_width,int physical_height,int subpixel,const char * make,const char * model,int transform)92 output_handle_geometry(void *data, struct wl_output *wl_output, int x, int y,
93 int physical_width, int physical_height, int subpixel,
94 const char *make, const char *model, int transform)
95 {
96 struct xwl_output *xwl_output = data;
97
98 RROutputSetPhysicalSize(xwl_output->randr_output,
99 physical_width, physical_height);
100 RROutputSetSubpixelOrder(xwl_output->randr_output,
101 wl_subpixel_to_xrandr(subpixel));
102
103 /* Apply the change from wl_output only if xdg-output is not supported */
104 if (!xwl_output->xdg_output) {
105 xwl_output->x = x;
106 xwl_output->y = y;
107 }
108 xwl_output->rotation = wl_transform_to_xrandr(transform);
109 }
110
111 static void
output_handle_mode(void * data,struct wl_output * wl_output,uint32_t flags,int width,int height,int refresh)112 output_handle_mode(void *data, struct wl_output *wl_output, uint32_t flags,
113 int width, int height, int refresh)
114 {
115 struct xwl_output *xwl_output = data;
116
117 if (!(flags & WL_OUTPUT_MODE_CURRENT))
118 return;
119
120 /* Apply the change from wl_output only if xdg-output is not supported */
121 if (!xwl_output->xdg_output) {
122 xwl_output->width = width;
123 xwl_output->height = height;
124 }
125 xwl_output->refresh = refresh;
126 }
127
128 /**
129 * Decides on the maximum expanse of an output in logical space (i.e. in the
130 * Wayland compositor plane) respective to some fix width and height values. The
131 * function sets the provided values to these maxima on return.
132 */
133 static inline void
output_get_new_size(struct xwl_output * xwl_output,int * width,int * height)134 output_get_new_size(struct xwl_output *xwl_output, int *width, int *height)
135 {
136 int output_width, output_height;
137
138 /* When we have xdg-output support the stored size is already rotated. */
139 if (xwl_output->xdg_output
140 || (xwl_output->rotation & (RR_Rotate_0 | RR_Rotate_180))) {
141 output_width = xwl_output->width;
142 output_height = xwl_output->height;
143 } else {
144 output_width = xwl_output->height;
145 output_height = xwl_output->width;
146 }
147
148 if (*width < xwl_output->x + output_width)
149 *width = xwl_output->x + output_width;
150
151 if (*height < xwl_output->y + output_height)
152 *height = xwl_output->y + output_height;
153 }
154
155 static int
xwl_set_pixmap_visit_window(WindowPtr window,void * data)156 xwl_set_pixmap_visit_window(WindowPtr window, void *data)
157 {
158 ScreenPtr screen = window->drawable.pScreen;
159
160 if (screen->GetWindowPixmap(window) == data) {
161 screen->SetWindowPixmap(window, screen->GetScreenPixmap(screen));
162 return WT_WALKCHILDREN;
163 }
164
165 return WT_DONTWALKCHILDREN;
166 }
167
168 static void
update_backing_pixmaps(struct xwl_screen * xwl_screen,int width,int height)169 update_backing_pixmaps(struct xwl_screen *xwl_screen, int width, int height)
170 {
171 ScreenPtr pScreen = xwl_screen->screen;
172 WindowPtr pRoot = pScreen->root;
173 PixmapPtr old_pixmap, new_pixmap;
174
175 old_pixmap = pScreen->GetScreenPixmap(pScreen);
176 new_pixmap = pScreen->CreatePixmap(pScreen, width, height,
177 pScreen->rootDepth,
178 CREATE_PIXMAP_USAGE_BACKING_PIXMAP);
179 pScreen->SetScreenPixmap(new_pixmap);
180
181 if (old_pixmap) {
182 TraverseTree(pRoot, xwl_set_pixmap_visit_window, old_pixmap);
183 pScreen->DestroyPixmap(old_pixmap);
184 }
185
186 pScreen->ResizeWindow(pRoot, 0, 0, width, height, NULL);
187 }
188
189 static void
update_screen_size(struct xwl_output * xwl_output,int width,int height)190 update_screen_size(struct xwl_output *xwl_output, int width, int height)
191 {
192 struct xwl_screen *xwl_screen = xwl_output->xwl_screen;
193
194 if (xwl_screen->root_clip_mode == ROOT_CLIP_FULL)
195 SetRootClip(xwl_screen->screen, ROOT_CLIP_NONE);
196
197 if (!xwl_screen->rootless && xwl_screen->screen->root)
198 update_backing_pixmaps (xwl_screen, width, height);
199
200 xwl_screen->width = width;
201 xwl_screen->height = height;
202 xwl_screen->screen->width = width;
203 xwl_screen->screen->height = height;
204 xwl_screen->screen->mmWidth = (width * 25.4) / monitorResolution;
205 xwl_screen->screen->mmHeight = (height * 25.4) / monitorResolution;
206
207 SetRootClip(xwl_screen->screen, xwl_screen->root_clip_mode);
208
209 if (xwl_screen->screen->root) {
210 BoxRec box = { 0, 0, width, height };
211
212 xwl_screen->screen->root->drawable.width = width;
213 xwl_screen->screen->root->drawable.height = height;
214 RegionReset(&xwl_screen->screen->root->winSize, &box);
215 RRScreenSizeNotify(xwl_screen->screen);
216 }
217
218 update_desktop_dimensions();
219 }
220
221 struct xwl_emulated_mode *
xwl_output_get_emulated_mode_for_client(struct xwl_output * xwl_output,ClientPtr client)222 xwl_output_get_emulated_mode_for_client(struct xwl_output *xwl_output,
223 ClientPtr client)
224 {
225 struct xwl_client *xwl_client = xwl_client_get(client);
226 int i;
227
228 if (!xwl_output)
229 return NULL;
230
231 for (i = 0; i < XWL_CLIENT_MAX_EMULATED_MODES; i++) {
232 if (xwl_client->emulated_modes[i].server_output_id ==
233 xwl_output->server_output_id)
234 return &xwl_client->emulated_modes[i];
235 }
236
237 return NULL;
238 }
239
240 static void
xwl_output_add_emulated_mode_for_client(struct xwl_output * xwl_output,ClientPtr client,RRModePtr mode,Bool from_vidmode)241 xwl_output_add_emulated_mode_for_client(struct xwl_output *xwl_output,
242 ClientPtr client,
243 RRModePtr mode,
244 Bool from_vidmode)
245 {
246 struct xwl_client *xwl_client = xwl_client_get(client);
247 struct xwl_emulated_mode *emulated_mode;
248 int i;
249
250 emulated_mode = xwl_output_get_emulated_mode_for_client(xwl_output, client);
251 if (!emulated_mode) {
252 /* Find a free spot in the emulated modes array */
253 for (i = 0; i < XWL_CLIENT_MAX_EMULATED_MODES; i++) {
254 if (xwl_client->emulated_modes[i].server_output_id == 0) {
255 emulated_mode = &xwl_client->emulated_modes[i];
256 break;
257 }
258 }
259 }
260 if (!emulated_mode) {
261 static Bool warned;
262
263 if (!warned) {
264 ErrorF("Ran out of space for emulated-modes, not adding mode");
265 warned = TRUE;
266 }
267
268 return;
269 }
270
271 emulated_mode->server_output_id = xwl_output->server_output_id;
272 emulated_mode->width = mode->mode.width;
273 emulated_mode->height = mode->mode.height;
274 emulated_mode->from_vidmode = from_vidmode;
275 }
276
277 static void
xwl_output_remove_emulated_mode_for_client(struct xwl_output * xwl_output,ClientPtr client)278 xwl_output_remove_emulated_mode_for_client(struct xwl_output *xwl_output,
279 ClientPtr client)
280 {
281 struct xwl_emulated_mode *emulated_mode;
282
283 emulated_mode = xwl_output_get_emulated_mode_for_client(xwl_output, client);
284 if (emulated_mode) {
285 DebugF("XWAYLAND: xwl_output_remove_emulated_mode: %dx%d\n",
286 emulated_mode->width, emulated_mode->height);
287 memset(emulated_mode, 0, sizeof(*emulated_mode));
288 }
289 }
290
291 /* From hw/xfree86/common/xf86DefModeSet.c with some obscure modes dropped */
292 const int32_t xwl_output_fake_modes[][2] = {
293 /* 4:3 (1.33) */
294 { 2048, 1536 },
295 { 1920, 1440 },
296 { 1600, 1200 },
297 { 1440, 1080 },
298 { 1400, 1050 },
299 { 1280, 1024 }, /* 5:4 (1.25) */
300 { 1280, 960 },
301 { 1152, 864 },
302 { 1024, 768 },
303 { 800, 600 },
304 { 640, 480 },
305 { 320, 240 },
306 /* 16:10 (1.6) */
307 { 2560, 1600 },
308 { 1920, 1200 },
309 { 1680, 1050 },
310 { 1440, 900 },
311 { 1280, 800 },
312 { 720, 480 }, /* 3:2 (1.5) */
313 { 640, 400 },
314 { 320, 200 },
315 /* 16:9 (1.77) */
316 { 5120, 2880 },
317 { 4096, 2304 },
318 { 3840, 2160 },
319 { 3200, 1800 },
320 { 2880, 1620 },
321 { 2560, 1440 },
322 { 2048, 1152 },
323 { 1920, 1080 },
324 { 1600, 900 },
325 { 1368, 768 },
326 { 1280, 720 },
327 { 1024, 576 },
328 { 864, 486 },
329 { 720, 400 },
330 { 640, 350 },
331 };
332
333 /* Build an array with RRModes the first mode is the actual output mode, the
334 * rest are fake modes from the xwl_output_fake_modes list. We do this for apps
335 * which want to change resolution when they go fullscreen.
336 * When an app requests a mode-change, we fake it using WPviewport.
337 */
338 static RRModePtr *
output_get_rr_modes(struct xwl_output * xwl_output,int32_t width,int32_t height,int * count)339 output_get_rr_modes(struct xwl_output *xwl_output,
340 int32_t width, int32_t height,
341 int *count)
342 {
343 struct xwl_screen *xwl_screen = xwl_output->xwl_screen;
344 RRModePtr *rr_modes;
345 int i;
346
347 rr_modes = xallocarray(ARRAY_SIZE(xwl_output_fake_modes) + 1, sizeof(RRModePtr));
348 if (!rr_modes)
349 goto err;
350
351 /* Add actual output mode */
352 rr_modes[0] = xwayland_cvt(width, height, xwl_output->refresh / 1000.0, 0, 0);
353 if (!rr_modes[0])
354 goto err;
355
356 *count = 1;
357
358 if (!xwl_screen_has_resolution_change_emulation(xwl_screen))
359 return rr_modes;
360
361 /* Add fake modes */
362 for (i = 0; i < ARRAY_SIZE(xwl_output_fake_modes); i++) {
363 /* Skip actual output mode, already added */
364 if (xwl_output_fake_modes[i][0] == width &&
365 xwl_output_fake_modes[i][1] == height)
366 continue;
367
368 /* Skip modes which are too big, avoid downscaling */
369 if (xwl_output_fake_modes[i][0] > width ||
370 xwl_output_fake_modes[i][1] > height)
371 continue;
372
373 rr_modes[*count] = xwayland_cvt(xwl_output_fake_modes[i][0],
374 xwl_output_fake_modes[i][1],
375 xwl_output->refresh / 1000.0, 0, 0);
376 if (!rr_modes[*count])
377 goto err;
378
379 (*count)++;
380 }
381
382 return rr_modes;
383 err:
384 FatalError("Failed to allocate memory for list of RR modes");
385 }
386
387 RRModePtr
xwl_output_find_mode(struct xwl_output * xwl_output,int32_t width,int32_t height)388 xwl_output_find_mode(struct xwl_output *xwl_output,
389 int32_t width, int32_t height)
390 {
391 RROutputPtr output = xwl_output->randr_output;
392 int i;
393
394 /* width & height -1 means we want the actual output mode, which is idx 0 */
395 if (width == -1 && height == -1 && output->modes)
396 return output->modes[0];
397
398 for (i = 0; i < output->numModes; i++) {
399 if (output->modes[i]->mode.width == width && output->modes[i]->mode.height == height)
400 return output->modes[i];
401 }
402
403 ErrorF("XWAYLAND: mode %dx%d is not available\n", width, height);
404 return NULL;
405 }
406
407 struct xwl_output_randr_emu_prop {
408 Atom atom;
409 uint32_t rects[XWL_CLIENT_MAX_EMULATED_MODES][4];
410 int rect_count;
411 };
412
413 static void
xwl_output_randr_emu_prop(struct xwl_screen * xwl_screen,ClientPtr client,struct xwl_output_randr_emu_prop * prop)414 xwl_output_randr_emu_prop(struct xwl_screen *xwl_screen, ClientPtr client,
415 struct xwl_output_randr_emu_prop *prop)
416 {
417 static const char atom_name[] = "_XWAYLAND_RANDR_EMU_MONITOR_RECTS";
418 struct xwl_emulated_mode *emulated_mode;
419 struct xwl_output *xwl_output;
420 int index = 0;
421
422 prop->atom = MakeAtom(atom_name, strlen(atom_name), TRUE);
423
424 xorg_list_for_each_entry(xwl_output, &xwl_screen->output_list, link) {
425 emulated_mode = xwl_output_get_emulated_mode_for_client(xwl_output, client);
426 if (!emulated_mode)
427 continue;
428
429 prop->rects[index][0] = xwl_output->x;
430 prop->rects[index][1] = xwl_output->y;
431 prop->rects[index][2] = emulated_mode->width;
432 prop->rects[index][3] = emulated_mode->height;
433 index++;
434 }
435
436 prop->rect_count = index;
437 }
438
439 static void
xwl_output_set_randr_emu_prop(WindowPtr window,struct xwl_output_randr_emu_prop * prop)440 xwl_output_set_randr_emu_prop(WindowPtr window,
441 struct xwl_output_randr_emu_prop *prop)
442 {
443 if (prop->rect_count) {
444 dixChangeWindowProperty(serverClient, window, prop->atom,
445 XA_CARDINAL, 32, PropModeReplace,
446 prop->rect_count * 4, prop->rects, TRUE);
447 } else {
448 DeleteProperty(serverClient, window, prop->atom);
449 }
450 }
451
452 static void
xwl_output_set_randr_emu_prop_callback(void * resource,XID id,void * user_data)453 xwl_output_set_randr_emu_prop_callback(void *resource, XID id, void *user_data)
454 {
455 if (xwl_window_is_toplevel(resource))
456 xwl_output_set_randr_emu_prop(resource, user_data);
457 }
458
459 static void
xwl_output_set_randr_emu_props(struct xwl_screen * xwl_screen,ClientPtr client)460 xwl_output_set_randr_emu_props(struct xwl_screen *xwl_screen, ClientPtr client)
461 {
462 struct xwl_output_randr_emu_prop prop = {};
463
464 xwl_output_randr_emu_prop(xwl_screen, client, &prop);
465 FindClientResourcesByType(client, RT_WINDOW,
466 xwl_output_set_randr_emu_prop_callback, &prop);
467 }
468
469 void
xwl_output_set_window_randr_emu_props(struct xwl_screen * xwl_screen,WindowPtr window)470 xwl_output_set_window_randr_emu_props(struct xwl_screen *xwl_screen,
471 WindowPtr window)
472 {
473 struct xwl_output_randr_emu_prop prop = {};
474
475 xwl_output_randr_emu_prop(xwl_screen, wClient(window), &prop);
476 xwl_output_set_randr_emu_prop(window, &prop);
477 }
478
479 void
xwl_output_set_emulated_mode(struct xwl_output * xwl_output,ClientPtr client,RRModePtr mode,Bool from_vidmode)480 xwl_output_set_emulated_mode(struct xwl_output *xwl_output, ClientPtr client,
481 RRModePtr mode, Bool from_vidmode)
482 {
483 DebugF("XWAYLAND: xwl_output_set_emulated_mode from %s: %dx%d\n",
484 from_vidmode ? "vidmode" : "randr",
485 mode->mode.width, mode->mode.height);
486
487 /* modes[0] is the actual (not-emulated) output mode */
488 if (mode == xwl_output->randr_output->modes[0])
489 xwl_output_remove_emulated_mode_for_client(xwl_output, client);
490 else
491 xwl_output_add_emulated_mode_for_client(xwl_output, client, mode, from_vidmode);
492
493 xwl_screen_check_resolution_change_emulation(xwl_output->xwl_screen);
494
495 xwl_output_set_randr_emu_props(xwl_output->xwl_screen, client);
496 }
497
498 static void
apply_output_change(struct xwl_output * xwl_output)499 apply_output_change(struct xwl_output *xwl_output)
500 {
501 struct xwl_screen *xwl_screen = xwl_output->xwl_screen;
502 struct xwl_output *it;
503 int mode_width, mode_height, count;
504 int width = 0, height = 0, has_this_output = 0;
505 RRModePtr *randr_modes;
506
507 /* Clear out the "done" received flags */
508 xwl_output->wl_output_done = FALSE;
509 xwl_output->xdg_output_done = FALSE;
510
511 /* When we have received an xdg-output for the mode size we might need to
512 * rotate back the stored logical size it provided.
513 */
514 if (xwl_output->xdg_output == NULL
515 || xwl_output->rotation & (RR_Rotate_0 | RR_Rotate_180)) {
516 mode_width = xwl_output->width;
517 mode_height = xwl_output->height;
518 } else {
519 mode_width = xwl_output->height;
520 mode_height = xwl_output->width;
521 }
522
523 /* Build a fresh modes array using the current refresh rate */
524 randr_modes = output_get_rr_modes(xwl_output, mode_width, mode_height, &count);
525 RROutputSetModes(xwl_output->randr_output, randr_modes, count, 1);
526 RRCrtcNotify(xwl_output->randr_crtc, randr_modes[0],
527 xwl_output->x, xwl_output->y,
528 xwl_output->rotation, NULL, 1, &xwl_output->randr_output);
529 /* RROutputSetModes takes ownership of the passed in modes, so we only
530 * have to free the pointer array.
531 */
532 free(randr_modes);
533
534 xorg_list_for_each_entry(it, &xwl_screen->output_list, link) {
535 /* output done event is sent even when some property
536 * of output is changed. That means that we may already
537 * have this output. If it is true, we must not add it
538 * into the output_list otherwise we'll corrupt it */
539 if (it == xwl_output)
540 has_this_output = 1;
541
542 output_get_new_size(it, &width, &height);
543 }
544
545 if (!has_this_output) {
546 xorg_list_append(&xwl_output->link, &xwl_screen->output_list);
547
548 /* we did not check this output for new screen size, do it now */
549 output_get_new_size(xwl_output, &width, &height);
550
551 --xwl_screen->expecting_event;
552 }
553
554 update_screen_size(xwl_output, width, height);
555 }
556
557 static void
output_handle_done(void * data,struct wl_output * wl_output)558 output_handle_done(void *data, struct wl_output *wl_output)
559 {
560 struct xwl_output *xwl_output = data;
561
562 xwl_output->wl_output_done = TRUE;
563 /* Apply the changes from wl_output only if both "done" events are received,
564 * if xdg-output is not supported or if xdg-output version is high enough.
565 */
566 if (xwl_output->xdg_output_done || !xwl_output->xdg_output ||
567 zxdg_output_v1_get_version(xwl_output->xdg_output) >= 3)
568 apply_output_change(xwl_output);
569 }
570
571 static void
output_handle_scale(void * data,struct wl_output * wl_output,int32_t factor)572 output_handle_scale(void *data, struct wl_output *wl_output, int32_t factor)
573 {
574 }
575
576 static const struct wl_output_listener output_listener = {
577 output_handle_geometry,
578 output_handle_mode,
579 output_handle_done,
580 output_handle_scale
581 };
582
583 static void
xdg_output_handle_logical_position(void * data,struct zxdg_output_v1 * xdg_output,int32_t x,int32_t y)584 xdg_output_handle_logical_position(void *data, struct zxdg_output_v1 *xdg_output,
585 int32_t x, int32_t y)
586 {
587 struct xwl_output *xwl_output = data;
588
589 xwl_output->x = x;
590 xwl_output->y = y;
591 }
592
593 static void
xdg_output_handle_logical_size(void * data,struct zxdg_output_v1 * xdg_output,int32_t width,int32_t height)594 xdg_output_handle_logical_size(void *data, struct zxdg_output_v1 *xdg_output,
595 int32_t width, int32_t height)
596 {
597 struct xwl_output *xwl_output = data;
598
599 xwl_output->width = width;
600 xwl_output->height = height;
601 }
602
603 static void
xdg_output_handle_done(void * data,struct zxdg_output_v1 * xdg_output)604 xdg_output_handle_done(void *data, struct zxdg_output_v1 *xdg_output)
605 {
606 struct xwl_output *xwl_output = data;
607
608 xwl_output->xdg_output_done = TRUE;
609 if (xwl_output->wl_output_done &&
610 zxdg_output_v1_get_version(xdg_output) < 3)
611 apply_output_change(xwl_output);
612 }
613
614 static void
xdg_output_handle_name(void * data,struct zxdg_output_v1 * xdg_output,const char * name)615 xdg_output_handle_name(void *data, struct zxdg_output_v1 *xdg_output,
616 const char *name)
617 {
618 }
619
620 static void
xdg_output_handle_description(void * data,struct zxdg_output_v1 * xdg_output,const char * description)621 xdg_output_handle_description(void *data, struct zxdg_output_v1 *xdg_output,
622 const char *description)
623 {
624 }
625
626 static const struct zxdg_output_v1_listener xdg_output_listener = {
627 xdg_output_handle_logical_position,
628 xdg_output_handle_logical_size,
629 xdg_output_handle_done,
630 xdg_output_handle_name,
631 xdg_output_handle_description,
632 };
633
634 struct xwl_output *
xwl_output_create(struct xwl_screen * xwl_screen,uint32_t id)635 xwl_output_create(struct xwl_screen *xwl_screen, uint32_t id)
636 {
637 struct xwl_output *xwl_output;
638 static int serial;
639 char name[256];
640
641 xwl_output = calloc(1, sizeof *xwl_output);
642 if (xwl_output == NULL) {
643 ErrorF("%s ENOMEM\n", __func__);
644 return NULL;
645 }
646
647 xwl_output->output = wl_registry_bind(xwl_screen->registry, id,
648 &wl_output_interface, 2);
649 if (!xwl_output->output) {
650 ErrorF("Failed binding wl_output\n");
651 goto err;
652 }
653
654 xwl_output->server_output_id = id;
655 wl_output_add_listener(xwl_output->output, &output_listener, xwl_output);
656
657 snprintf(name, sizeof name, "XWAYLAND%d", serial++);
658
659 xwl_output->xwl_screen = xwl_screen;
660 xwl_output->randr_crtc = RRCrtcCreate(xwl_screen->screen, xwl_output);
661 if (!xwl_output->randr_crtc) {
662 ErrorF("Failed creating RandR CRTC\n");
663 goto err;
664 }
665 RRCrtcSetRotations (xwl_output->randr_crtc, ALL_ROTATIONS);
666
667 xwl_output->randr_output = RROutputCreate(xwl_screen->screen, name,
668 strlen(name), xwl_output);
669 if (!xwl_output->randr_output) {
670 ErrorF("Failed creating RandR Output\n");
671 goto err;
672 }
673
674 RRCrtcGammaSetSize(xwl_output->randr_crtc, 256);
675 RROutputSetCrtcs(xwl_output->randr_output, &xwl_output->randr_crtc, 1);
676 RROutputSetConnection(xwl_output->randr_output, RR_Connected);
677
678 /* We want the output to be in the list as soon as created so we can
679 * use it when binding to the xdg-output protocol...
680 */
681 xorg_list_append(&xwl_output->link, &xwl_screen->output_list);
682 --xwl_screen->expecting_event;
683
684 if (xwl_screen->xdg_output_manager)
685 xwl_output_get_xdg_output(xwl_output);
686
687 return xwl_output;
688
689 err:
690 if (xwl_output->randr_crtc)
691 RRCrtcDestroy(xwl_output->randr_crtc);
692 if (xwl_output->output)
693 wl_output_destroy(xwl_output->output);
694 free(xwl_output);
695 return NULL;
696 }
697
698 void
xwl_output_destroy(struct xwl_output * xwl_output)699 xwl_output_destroy(struct xwl_output *xwl_output)
700 {
701 wl_output_destroy(xwl_output->output);
702 free(xwl_output);
703 }
704
705 void
xwl_output_remove(struct xwl_output * xwl_output)706 xwl_output_remove(struct xwl_output *xwl_output)
707 {
708 struct xwl_output *it;
709 struct xwl_screen *xwl_screen = xwl_output->xwl_screen;
710 int width = 0, height = 0;
711
712 xorg_list_del(&xwl_output->link);
713
714 xorg_list_for_each_entry(it, &xwl_screen->output_list, link)
715 output_get_new_size(it, &width, &height);
716 update_screen_size(xwl_output, width, height);
717
718 RRCrtcDestroy(xwl_output->randr_crtc);
719 RROutputDestroy(xwl_output->randr_output);
720
721 xwl_output_destroy(xwl_output);
722 }
723
724 static Bool
xwl_randr_get_info(ScreenPtr pScreen,Rotation * rotations)725 xwl_randr_get_info(ScreenPtr pScreen, Rotation * rotations)
726 {
727 *rotations = ALL_ROTATIONS;
728
729 return TRUE;
730 }
731
732 #ifdef RANDR_10_INTERFACE
733 static Bool
xwl_randr_set_config(ScreenPtr pScreen,Rotation rotation,int rate,RRScreenSizePtr pSize)734 xwl_randr_set_config(ScreenPtr pScreen,
735 Rotation rotation, int rate, RRScreenSizePtr pSize)
736 {
737 return FALSE;
738 }
739 #endif
740
741 #if RANDR_12_INTERFACE
742 static Bool
xwl_randr_screen_set_size(ScreenPtr pScreen,CARD16 width,CARD16 height,CARD32 mmWidth,CARD32 mmHeight)743 xwl_randr_screen_set_size(ScreenPtr pScreen,
744 CARD16 width,
745 CARD16 height,
746 CARD32 mmWidth, CARD32 mmHeight)
747 {
748 return TRUE;
749 }
750
751 static Bool
xwl_randr_crtc_set(ScreenPtr pScreen,RRCrtcPtr crtc,RRModePtr new_mode,int x,int y,Rotation rotation,int numOutputs,RROutputPtr * outputs)752 xwl_randr_crtc_set(ScreenPtr pScreen,
753 RRCrtcPtr crtc,
754 RRModePtr new_mode,
755 int x,
756 int y,
757 Rotation rotation,
758 int numOutputs, RROutputPtr * outputs)
759 {
760 struct xwl_output *xwl_output = crtc->devPrivate;
761 RRModePtr mode;
762
763 if (new_mode) {
764 mode = xwl_output_find_mode(xwl_output,
765 new_mode->mode.width,
766 new_mode->mode.height);
767 } else {
768 mode = xwl_output_find_mode(xwl_output, -1, -1);
769 }
770 if (!mode)
771 return FALSE;
772
773 xwl_output_set_emulated_mode(xwl_output, GetCurrentClient(), mode, FALSE);
774
775 /* A real randr implementation would call:
776 * RRCrtcNotify(xwl_output->randr_crtc, mode, xwl_output->x, xwl_output->y,
777 * xwl_output->rotation, NULL, 1, &xwl_output->randr_output);
778 * here to update the mode reported to clients querying the randr settings
779 * but that influences *all* clients and we do randr mode change emulation
780 * on a per client basis. So we just return success here.
781 */
782
783 return TRUE;
784 }
785
786 static Bool
xwl_randr_crtc_set_gamma(ScreenPtr pScreen,RRCrtcPtr crtc)787 xwl_randr_crtc_set_gamma(ScreenPtr pScreen, RRCrtcPtr crtc)
788 {
789 return TRUE;
790 }
791
792 static Bool
xwl_randr_crtc_get_gamma(ScreenPtr pScreen,RRCrtcPtr crtc)793 xwl_randr_crtc_get_gamma(ScreenPtr pScreen, RRCrtcPtr crtc)
794 {
795 return TRUE;
796 }
797
798 static Bool
xwl_randr_output_set_property(ScreenPtr pScreen,RROutputPtr output,Atom property,RRPropertyValuePtr value)799 xwl_randr_output_set_property(ScreenPtr pScreen,
800 RROutputPtr output,
801 Atom property,
802 RRPropertyValuePtr value)
803 {
804 return TRUE;
805 }
806
807 static Bool
xwl_output_validate_mode(ScreenPtr pScreen,RROutputPtr output,RRModePtr mode)808 xwl_output_validate_mode(ScreenPtr pScreen,
809 RROutputPtr output,
810 RRModePtr mode)
811 {
812 return TRUE;
813 }
814
815 static void
xwl_randr_mode_destroy(ScreenPtr pScreen,RRModePtr mode)816 xwl_randr_mode_destroy(ScreenPtr pScreen, RRModePtr mode)
817 {
818 return;
819 }
820 #endif
821
822 Bool
xwl_screen_init_output(struct xwl_screen * xwl_screen)823 xwl_screen_init_output(struct xwl_screen *xwl_screen)
824 {
825 rrScrPrivPtr rp;
826
827 if (!RRScreenInit(xwl_screen->screen))
828 return FALSE;
829
830 RRScreenSetSizeRange(xwl_screen->screen, 16, 16, 32767, 32767);
831
832 rp = rrGetScrPriv(xwl_screen->screen);
833 rp->rrGetInfo = xwl_randr_get_info;
834
835 #if RANDR_10_INTERFACE
836 rp->rrSetConfig = xwl_randr_set_config;
837 #endif
838
839 #if RANDR_12_INTERFACE
840 rp->rrScreenSetSize = xwl_randr_screen_set_size;
841 rp->rrCrtcSet = xwl_randr_crtc_set;
842 rp->rrCrtcSetGamma = xwl_randr_crtc_set_gamma;
843 rp->rrCrtcGetGamma = xwl_randr_crtc_get_gamma;
844 rp->rrOutputSetProperty = xwl_randr_output_set_property;
845 rp->rrOutputValidateMode = xwl_output_validate_mode;
846 rp->rrModeDestroy = xwl_randr_mode_destroy;
847 #endif
848
849 return TRUE;
850 }
851
852 static void
xwl_output_get_xdg_output(struct xwl_output * xwl_output)853 xwl_output_get_xdg_output(struct xwl_output *xwl_output)
854 {
855 struct xwl_screen *xwl_screen = xwl_output->xwl_screen;
856
857 xwl_output->xdg_output =
858 zxdg_output_manager_v1_get_xdg_output (xwl_screen->xdg_output_manager,
859 xwl_output->output);
860
861 zxdg_output_v1_add_listener(xwl_output->xdg_output,
862 &xdg_output_listener,
863 xwl_output);
864 }
865
866 void
xwl_screen_init_xdg_output(struct xwl_screen * xwl_screen)867 xwl_screen_init_xdg_output(struct xwl_screen *xwl_screen)
868 {
869 struct xwl_output *it;
870
871 assert(xwl_screen->xdg_output_manager);
872
873 xorg_list_for_each_entry(it, &xwl_screen->output_list, link)
874 xwl_output_get_xdg_output(it);
875 }
876