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