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 #ifdef HAVE_DIX_CONFIG_H
27 #include <dix-config.h>
28 #endif
29
30 #include "xwayland.h"
31 #include <randrstr.h>
32
33 #define ALL_ROTATIONS (RR_Rotate_0 | \
34 RR_Rotate_90 | \
35 RR_Rotate_180 | \
36 RR_Rotate_270 | \
37 RR_Reflect_X | \
38 RR_Reflect_Y)
39
40 static void xwl_output_get_xdg_output(struct xwl_output *xwl_output);
41
42 static Rotation
wl_transform_to_xrandr(enum wl_output_transform transform)43 wl_transform_to_xrandr(enum wl_output_transform transform)
44 {
45 switch (transform) {
46 default:
47 case WL_OUTPUT_TRANSFORM_NORMAL:
48 return RR_Rotate_0;
49 case WL_OUTPUT_TRANSFORM_90:
50 return RR_Rotate_90;
51 case WL_OUTPUT_TRANSFORM_180:
52 return RR_Rotate_180;
53 case WL_OUTPUT_TRANSFORM_270:
54 return RR_Rotate_270;
55 case WL_OUTPUT_TRANSFORM_FLIPPED:
56 return RR_Reflect_X | RR_Rotate_0;
57 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
58 return RR_Reflect_X | RR_Rotate_90;
59 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
60 return RR_Reflect_X | RR_Rotate_180;
61 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
62 return RR_Reflect_X | RR_Rotate_270;
63 }
64 }
65
66 static int
wl_subpixel_to_xrandr(int subpixel)67 wl_subpixel_to_xrandr(int subpixel)
68 {
69 switch (subpixel) {
70 default:
71 case WL_OUTPUT_SUBPIXEL_UNKNOWN:
72 return SubPixelUnknown;
73 case WL_OUTPUT_SUBPIXEL_NONE:
74 return SubPixelNone;
75 case WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB:
76 return SubPixelHorizontalRGB;
77 case WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR:
78 return SubPixelHorizontalBGR;
79 case WL_OUTPUT_SUBPIXEL_VERTICAL_RGB:
80 return SubPixelVerticalRGB;
81 case WL_OUTPUT_SUBPIXEL_VERTICAL_BGR:
82 return SubPixelVerticalBGR;
83 }
84 }
85
86 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)87 output_handle_geometry(void *data, struct wl_output *wl_output, int x, int y,
88 int physical_width, int physical_height, int subpixel,
89 const char *make, const char *model, int transform)
90 {
91 struct xwl_output *xwl_output = data;
92
93 RROutputSetPhysicalSize(xwl_output->randr_output,
94 physical_width, physical_height);
95 RROutputSetSubpixelOrder(xwl_output->randr_output,
96 wl_subpixel_to_xrandr(subpixel));
97
98 /* Apply the change from wl_output only if xdg-output is not supported */
99 if (!xwl_output->xdg_output) {
100 xwl_output->x = x;
101 xwl_output->y = y;
102 }
103 xwl_output->rotation = wl_transform_to_xrandr(transform);
104 }
105
106 static void
output_handle_mode(void * data,struct wl_output * wl_output,uint32_t flags,int width,int height,int refresh)107 output_handle_mode(void *data, struct wl_output *wl_output, uint32_t flags,
108 int width, int height, int refresh)
109 {
110 struct xwl_output *xwl_output = data;
111
112 if (!(flags & WL_OUTPUT_MODE_CURRENT))
113 return;
114
115 /* Apply the change from wl_output only if xdg-output is not supported */
116 if (!xwl_output->xdg_output) {
117 xwl_output->width = width;
118 xwl_output->height = height;
119 }
120 xwl_output->refresh = refresh;
121 }
122
123 static inline void
output_get_new_size(struct xwl_output * xwl_output,Bool need_rotate,int * height,int * width)124 output_get_new_size(struct xwl_output *xwl_output,
125 Bool need_rotate,
126 int *height, int *width)
127 {
128 int output_width, output_height;
129
130 if (!need_rotate || (xwl_output->rotation & (RR_Rotate_0 | RR_Rotate_180))) {
131 output_width = xwl_output->width;
132 output_height = xwl_output->height;
133 } else {
134 output_width = xwl_output->height;
135 output_height = xwl_output->width;
136 }
137
138 if (*width < xwl_output->x + output_width)
139 *width = xwl_output->x + output_width;
140
141 if (*height < xwl_output->y + output_height)
142 *height = xwl_output->y + output_height;
143 }
144
145 static int
xwl_set_pixmap_visit_window(WindowPtr window,void * data)146 xwl_set_pixmap_visit_window(WindowPtr window, void *data)
147 {
148 ScreenPtr screen = window->drawable.pScreen;
149
150 if (screen->GetWindowPixmap(window) == data) {
151 screen->SetWindowPixmap(window, screen->GetScreenPixmap(screen));
152 return WT_WALKCHILDREN;
153 }
154
155 return WT_DONTWALKCHILDREN;
156 }
157
158 static void
update_backing_pixmaps(struct xwl_screen * xwl_screen,int width,int height)159 update_backing_pixmaps(struct xwl_screen *xwl_screen, int width, int height)
160 {
161 ScreenPtr pScreen = xwl_screen->screen;
162 WindowPtr pRoot = pScreen->root;
163 PixmapPtr old_pixmap, new_pixmap;
164
165 old_pixmap = pScreen->GetScreenPixmap(pScreen);
166 new_pixmap = pScreen->CreatePixmap(pScreen, width, height,
167 pScreen->rootDepth,
168 CREATE_PIXMAP_USAGE_BACKING_PIXMAP);
169 pScreen->SetScreenPixmap(new_pixmap);
170
171 if (old_pixmap) {
172 TraverseTree(pRoot, xwl_set_pixmap_visit_window, old_pixmap);
173 pScreen->DestroyPixmap(old_pixmap);
174 }
175
176 pScreen->ResizeWindow(pRoot, 0, 0, width, height, NULL);
177 }
178
179 static void
update_screen_size(struct xwl_output * xwl_output,int width,int height)180 update_screen_size(struct xwl_output *xwl_output, int width, int height)
181 {
182 struct xwl_screen *xwl_screen = xwl_output->xwl_screen;
183
184 if (xwl_screen->root_clip_mode == ROOT_CLIP_FULL)
185 SetRootClip(xwl_screen->screen, ROOT_CLIP_NONE);
186
187 if (!xwl_screen->rootless && xwl_screen->screen->root)
188 update_backing_pixmaps (xwl_screen, width, height);
189
190 xwl_screen->width = width;
191 xwl_screen->height = height;
192 xwl_screen->screen->width = width;
193 xwl_screen->screen->height = height;
194 xwl_screen->screen->mmWidth = (width * 25.4) / monitorResolution;
195 xwl_screen->screen->mmHeight = (height * 25.4) / monitorResolution;
196
197 SetRootClip(xwl_screen->screen, xwl_screen->root_clip_mode);
198
199 if (xwl_screen->screen->root) {
200 BoxRec box = { 0, 0, width, height };
201
202 xwl_screen->screen->root->drawable.width = width;
203 xwl_screen->screen->root->drawable.height = height;
204 RegionReset(&xwl_screen->screen->root->winSize, &box);
205 RRScreenSizeNotify(xwl_screen->screen);
206 }
207
208 update_desktop_dimensions();
209 }
210
211 static void
apply_output_change(struct xwl_output * xwl_output)212 apply_output_change(struct xwl_output *xwl_output)
213 {
214 struct xwl_screen *xwl_screen = xwl_output->xwl_screen;
215 struct xwl_output *it;
216 int mode_width, mode_height;
217 int width = 0, height = 0, has_this_output = 0;
218 RRModePtr randr_mode;
219 Bool need_rotate;
220
221 /* Clear out the "done" received flags */
222 xwl_output->wl_output_done = FALSE;
223 xwl_output->xdg_output_done = FALSE;
224
225 /* xdg-output sends output size in compositor space. so already rotated */
226 need_rotate = (xwl_output->xdg_output == NULL);
227
228 /* We need to rotate back the logical size for the mode */
229 if (need_rotate || xwl_output->rotation & (RR_Rotate_0 | RR_Rotate_180)) {
230 mode_width = xwl_output->width;
231 mode_height = xwl_output->height;
232 } else {
233 mode_width = xwl_output->height;
234 mode_height = xwl_output->width;
235 }
236
237 randr_mode = xwayland_cvt(mode_width, mode_height,
238 xwl_output->refresh / 1000.0, 0, 0);
239 RROutputSetModes(xwl_output->randr_output, &randr_mode, 1, 1);
240 RRCrtcNotify(xwl_output->randr_crtc, randr_mode,
241 xwl_output->x, xwl_output->y,
242 xwl_output->rotation, NULL, 1, &xwl_output->randr_output);
243
244 xorg_list_for_each_entry(it, &xwl_screen->output_list, link) {
245 /* output done event is sent even when some property
246 * of output is changed. That means that we may already
247 * have this output. If it is true, we must not add it
248 * into the output_list otherwise we'll corrupt it */
249 if (it == xwl_output)
250 has_this_output = 1;
251
252 output_get_new_size(it, need_rotate, &height, &width);
253 }
254
255 if (!has_this_output) {
256 xorg_list_append(&xwl_output->link, &xwl_screen->output_list);
257
258 /* we did not check this output for new screen size, do it now */
259 output_get_new_size(xwl_output, need_rotate, &height, &width);
260
261 --xwl_screen->expecting_event;
262 }
263
264 update_screen_size(xwl_output, width, height);
265 }
266
267 static void
output_handle_done(void * data,struct wl_output * wl_output)268 output_handle_done(void *data, struct wl_output *wl_output)
269 {
270 struct xwl_output *xwl_output = data;
271
272 xwl_output->wl_output_done = TRUE;
273 /* Apply the changes from wl_output only if both "done" events are received,
274 * or if xdg-output is not supported.
275 */
276 if (xwl_output->xdg_output_done || !xwl_output->xdg_output)
277 apply_output_change(xwl_output);
278 }
279
280 static void
output_handle_scale(void * data,struct wl_output * wl_output,int32_t factor)281 output_handle_scale(void *data, struct wl_output *wl_output, int32_t factor)
282 {
283 }
284
285 static const struct wl_output_listener output_listener = {
286 output_handle_geometry,
287 output_handle_mode,
288 output_handle_done,
289 output_handle_scale
290 };
291
292 static void
xdg_output_handle_logical_position(void * data,struct zxdg_output_v1 * xdg_output,int32_t x,int32_t y)293 xdg_output_handle_logical_position(void *data, struct zxdg_output_v1 *xdg_output,
294 int32_t x, int32_t y)
295 {
296 struct xwl_output *xwl_output = data;
297
298 xwl_output->x = x;
299 xwl_output->y = y;
300 }
301
302 static void
xdg_output_handle_logical_size(void * data,struct zxdg_output_v1 * xdg_output,int32_t width,int32_t height)303 xdg_output_handle_logical_size(void *data, struct zxdg_output_v1 *xdg_output,
304 int32_t width, int32_t height)
305 {
306 struct xwl_output *xwl_output = data;
307
308 xwl_output->width = width;
309 xwl_output->height = height;
310 }
311
312 static void
xdg_output_handle_done(void * data,struct zxdg_output_v1 * xdg_output)313 xdg_output_handle_done(void *data, struct zxdg_output_v1 *xdg_output)
314 {
315 struct xwl_output *xwl_output = data;
316
317 xwl_output->xdg_output_done = TRUE;
318 if (xwl_output->wl_output_done)
319 apply_output_change(xwl_output);
320 }
321
322 static const struct zxdg_output_v1_listener xdg_output_listener = {
323 xdg_output_handle_logical_position,
324 xdg_output_handle_logical_size,
325 xdg_output_handle_done,
326 };
327
328 struct xwl_output *
xwl_output_create(struct xwl_screen * xwl_screen,uint32_t id)329 xwl_output_create(struct xwl_screen *xwl_screen, uint32_t id)
330 {
331 struct xwl_output *xwl_output;
332 static int serial;
333 char name[256];
334
335 xwl_output = calloc(1, sizeof *xwl_output);
336 if (xwl_output == NULL) {
337 ErrorF("%s ENOMEM\n", __func__);
338 return NULL;
339 }
340
341 xwl_output->output = wl_registry_bind(xwl_screen->registry, id,
342 &wl_output_interface, 2);
343 if (!xwl_output->output) {
344 ErrorF("Failed binding wl_output\n");
345 goto err;
346 }
347
348 xwl_output->server_output_id = id;
349 wl_output_add_listener(xwl_output->output, &output_listener, xwl_output);
350
351 snprintf(name, sizeof name, "XWAYLAND%d", serial++);
352
353 xwl_output->xwl_screen = xwl_screen;
354 xwl_output->randr_crtc = RRCrtcCreate(xwl_screen->screen, xwl_output);
355 if (!xwl_output->randr_crtc) {
356 ErrorF("Failed creating RandR CRTC\n");
357 goto err;
358 }
359 RRCrtcSetRotations (xwl_output->randr_crtc, ALL_ROTATIONS);
360
361 xwl_output->randr_output = RROutputCreate(xwl_screen->screen, name,
362 strlen(name), xwl_output);
363 if (!xwl_output->randr_output) {
364 ErrorF("Failed creating RandR Output\n");
365 goto err;
366 }
367
368 RRCrtcGammaSetSize(xwl_output->randr_crtc, 256);
369 RROutputSetCrtcs(xwl_output->randr_output, &xwl_output->randr_crtc, 1);
370 RROutputSetConnection(xwl_output->randr_output, RR_Connected);
371
372 /* We want the output to be in the list as soon as created so we can
373 * use it when binding to the xdg-output protocol...
374 */
375 xorg_list_append(&xwl_output->link, &xwl_screen->output_list);
376 --xwl_screen->expecting_event;
377
378 if (xwl_screen->xdg_output_manager)
379 xwl_output_get_xdg_output(xwl_output);
380
381 return xwl_output;
382
383 err:
384 if (xwl_output->randr_crtc)
385 RRCrtcDestroy(xwl_output->randr_crtc);
386 if (xwl_output->output)
387 wl_output_destroy(xwl_output->output);
388 free(xwl_output);
389 return NULL;
390 }
391
392 void
xwl_output_destroy(struct xwl_output * xwl_output)393 xwl_output_destroy(struct xwl_output *xwl_output)
394 {
395 wl_output_destroy(xwl_output->output);
396 free(xwl_output);
397 }
398
399 void
xwl_output_remove(struct xwl_output * xwl_output)400 xwl_output_remove(struct xwl_output *xwl_output)
401 {
402 struct xwl_output *it;
403 struct xwl_screen *xwl_screen = xwl_output->xwl_screen;
404 int width = 0, height = 0;
405 Bool need_rotate = (xwl_output->xdg_output == NULL);
406
407 xorg_list_del(&xwl_output->link);
408
409 xorg_list_for_each_entry(it, &xwl_screen->output_list, link)
410 output_get_new_size(it, need_rotate, &height, &width);
411 update_screen_size(xwl_output, width, height);
412
413 RRCrtcDestroy(xwl_output->randr_crtc);
414 RROutputDestroy(xwl_output->randr_output);
415
416 xwl_output_destroy(xwl_output);
417 }
418
419 static Bool
xwl_randr_get_info(ScreenPtr pScreen,Rotation * rotations)420 xwl_randr_get_info(ScreenPtr pScreen, Rotation * rotations)
421 {
422 *rotations = ALL_ROTATIONS;
423
424 return TRUE;
425 }
426
427 static Bool
xwl_randr_set_config(ScreenPtr pScreen,Rotation rotation,int rate,RRScreenSizePtr pSize)428 xwl_randr_set_config(ScreenPtr pScreen,
429 Rotation rotation, int rate, RRScreenSizePtr pSize)
430 {
431 return FALSE;
432 }
433
434 Bool
xwl_screen_init_output(struct xwl_screen * xwl_screen)435 xwl_screen_init_output(struct xwl_screen *xwl_screen)
436 {
437 rrScrPrivPtr rp;
438
439 if (!RRScreenInit(xwl_screen->screen))
440 return FALSE;
441
442 RRScreenSetSizeRange(xwl_screen->screen, 16, 16, 32767, 32767);
443
444 rp = rrGetScrPriv(xwl_screen->screen);
445 rp->rrGetInfo = xwl_randr_get_info;
446 rp->rrSetConfig = xwl_randr_set_config;
447
448 return TRUE;
449 }
450
451 static void
xwl_output_get_xdg_output(struct xwl_output * xwl_output)452 xwl_output_get_xdg_output(struct xwl_output *xwl_output)
453 {
454 struct xwl_screen *xwl_screen = xwl_output->xwl_screen;
455
456 xwl_output->xdg_output =
457 zxdg_output_manager_v1_get_xdg_output (xwl_screen->xdg_output_manager,
458 xwl_output->output);
459
460 zxdg_output_v1_add_listener(xwl_output->xdg_output,
461 &xdg_output_listener,
462 xwl_output);
463 }
464
465 void
xwl_screen_init_xdg_output(struct xwl_screen * xwl_screen)466 xwl_screen_init_xdg_output(struct xwl_screen *xwl_screen)
467 {
468 struct xwl_output *it;
469
470 assert(xwl_screen->xdg_output_manager);
471
472 xorg_list_for_each_entry(it, &xwl_screen->output_list, link)
473 xwl_output_get_xdg_output(it);
474 }
475