File: | xrandr.c |
Location: | line 2289, column 34 |
Description: | Assigned value is garbage or undefined |
1 | /* | |||
2 | * Copyright © 2001 Keith Packard, member of The XFree86 Project, Inc. | |||
3 | * Copyright © 2002 Hewlett Packard Company, Inc. | |||
4 | * Copyright © 2006 Intel Corporation | |||
5 | * Copyright © 2013 NVIDIA Corporation | |||
6 | * | |||
7 | * Permission to use, copy, modify, distribute, and sell this software and its | |||
8 | * documentation for any purpose is hereby granted without fee, provided that | |||
9 | * the above copyright notice appear in all copies and that both that copyright | |||
10 | * notice and this permission notice appear in supporting documentation, and | |||
11 | * that the name of the copyright holders not be used in advertising or | |||
12 | * publicity pertaining to distribution of the software without specific, | |||
13 | * written prior permission. The copyright holders make no representations | |||
14 | * about the suitability of this software for any purpose. It is provided "as | |||
15 | * is" without express or implied warranty. | |||
16 | * | |||
17 | * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, | |||
18 | * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO | |||
19 | * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR | |||
20 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, | |||
21 | * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER | |||
22 | * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE | |||
23 | * OF THIS SOFTWARE. | |||
24 | * | |||
25 | * Thanks to Jim Gettys who wrote most of the client side code, | |||
26 | * and part of the server code for randr. | |||
27 | */ | |||
28 | ||||
29 | #include <stdio.h> | |||
30 | #include <X11/Xlib.h> | |||
31 | #include <X11/Xlibint.h> | |||
32 | #include <X11/Xproto.h> | |||
33 | #include <X11/Xatom.h> | |||
34 | #include <X11/extensions/Xrandr.h> | |||
35 | #include <X11/extensions/Xrender.h> /* we share subpixel information */ | |||
36 | #include <strings.h> | |||
37 | #include <string.h> | |||
38 | #include <stdlib.h> | |||
39 | #include <stdint.h> | |||
40 | #include <inttypes.h> | |||
41 | #include <stdarg.h> | |||
42 | #include <math.h> | |||
43 | ||||
44 | #ifdef HAVE_CONFIG_H1 | |||
45 | #include "config.h" | |||
46 | #endif | |||
47 | ||||
48 | static char *program_name; | |||
49 | static Display *dpy; | |||
50 | static Window root; | |||
51 | static int screen = -1; | |||
52 | static Boolint verbose = False0; | |||
53 | static Boolint automatic = False0; | |||
54 | static Boolint properties = False0; | |||
55 | static Boolint grab_server = True1; | |||
56 | static Boolint no_primary = False0; | |||
57 | ||||
58 | static const char *direction[5] = { | |||
59 | "normal", | |||
60 | "left", | |||
61 | "inverted", | |||
62 | "right", | |||
63 | "\n"}; | |||
64 | ||||
65 | static const char *reflections[5] = { | |||
66 | "normal", | |||
67 | "x", | |||
68 | "y", | |||
69 | "xy", | |||
70 | "\n"}; | |||
71 | ||||
72 | /* subpixel order */ | |||
73 | static const char *order[6] = { | |||
74 | "unknown", | |||
75 | "horizontal rgb", | |||
76 | "horizontal bgr", | |||
77 | "vertical rgb", | |||
78 | "vertical bgr", | |||
79 | "no subpixels"}; | |||
80 | ||||
81 | static const struct { | |||
82 | const char *string; | |||
83 | unsigned long flag; | |||
84 | } mode_flags[] = { | |||
85 | { "+HSync", RR_HSyncPositive0x00000001 }, | |||
86 | { "-HSync", RR_HSyncNegative0x00000002 }, | |||
87 | { "+VSync", RR_VSyncPositive0x00000004 }, | |||
88 | { "-VSync", RR_VSyncNegative0x00000008 }, | |||
89 | { "Interlace", RR_Interlace0x00000010 }, | |||
90 | { "DoubleScan", RR_DoubleScan0x00000020 }, | |||
91 | { "CSync", RR_CSync0x00000040 }, | |||
92 | { "+CSync", RR_CSyncPositive0x00000080 }, | |||
93 | { "-CSync", RR_CSyncNegative0x00000100 }, | |||
94 | { NULL((void*)0), 0 } | |||
95 | }; | |||
96 | ||||
97 | static void | |||
98 | usage(void) | |||
99 | { | |||
100 | printf("usage: %s [options]\n%s", program_name, | |||
101 | " where options are:\n" | |||
102 | " --display <display> or -d <display>\n" | |||
103 | " --help\n" | |||
104 | " -o <normal,inverted,left,right,0,1,2,3>\n" | |||
105 | " or --orientation <normal,inverted,left,right,0,1,2,3>\n" | |||
106 | " -q or --query\n" | |||
107 | " -s <size>/<width>x<height> or --size <size>/<width>x<height>\n" | |||
108 | " -r <rate> or --rate <rate> or --refresh <rate>\n" | |||
109 | " -v or --version\n" | |||
110 | " -x (reflect in x)\n" | |||
111 | " -y (reflect in y)\n" | |||
112 | " --screen <screen>\n" | |||
113 | " --verbose\n" | |||
114 | " --current\n" | |||
115 | " --dryrun\n" | |||
116 | " --nograb\n" | |||
117 | " --prop or --properties\n" | |||
118 | " --fb <width>x<height>\n" | |||
119 | " --fbmm <width>x<height>\n" | |||
120 | " --dpi <dpi>/<output>\n" | |||
121 | " --output <output>\n" | |||
122 | " --auto\n" | |||
123 | " --mode <mode>\n" | |||
124 | " --preferred\n" | |||
125 | " --pos <x>x<y>\n" | |||
126 | " --rate <rate> or --refresh <rate>\n" | |||
127 | " --reflect normal,x,y,xy\n" | |||
128 | " --rotate normal,inverted,left,right\n" | |||
129 | " --left-of <output>\n" | |||
130 | " --right-of <output>\n" | |||
131 | " --above <output>\n" | |||
132 | " --below <output>\n" | |||
133 | " --same-as <output>\n" | |||
134 | " --set <property> <value>\n" | |||
135 | " --scale <x>x<y>\n" | |||
136 | " --scale-from <w>x<h>\n" | |||
137 | " --transform <a>,<b>,<c>,<d>,<e>,<f>,<g>,<h>,<i>\n" | |||
138 | " --off\n" | |||
139 | " --crtc <crtc>\n" | |||
140 | " --panning <w>x<h>[+<x>+<y>[/<track:w>x<h>+<x>+<y>[/<border:l>/<t>/<r>/<b>]]]\n" | |||
141 | " --gamma <r>:<g>:<b>\n" | |||
142 | " --brightness <value>\n" | |||
143 | " --primary\n" | |||
144 | " --noprimary\n" | |||
145 | " --newmode <name> <clock MHz>\n" | |||
146 | " <hdisp> <hsync-start> <hsync-end> <htotal>\n" | |||
147 | " <vdisp> <vsync-start> <vsync-end> <vtotal>\n" | |||
148 | " [flags...]\n" | |||
149 | " Valid flags: +HSync -HSync +VSync -VSync\n" | |||
150 | " +CSync -CSync CSync Interlace DoubleScan\n" | |||
151 | " --rmmode <name>\n" | |||
152 | " --addmode <output> <name>\n" | |||
153 | " --delmode <output> <name>\n" | |||
154 | " --listproviders\n" | |||
155 | " --setprovideroutputsource <prov-xid> <source-xid>\n" | |||
156 | " --setprovideroffloadsink <prov-xid> <sink-xid>\n" | |||
157 | " --listmonitors\n" | |||
158 | " --listactivemonitors\n" | |||
159 | " --setmonitor <name> {auto|<w>/<mmw>x<h>/<mmh>+<x>+<y>} {none|<output>,<output>,...}\n" | |||
160 | " --delmonitor <name>\n"); | |||
161 | } | |||
162 | ||||
163 | static void _X_NORETURN__attribute((noreturn)) _X_ATTRIBUTE_PRINTF(1,2)__attribute__((__format__(__printf__,1,2))) | |||
164 | fatal (const char *format, ...) | |||
165 | { | |||
166 | va_list ap; | |||
167 | ||||
168 | va_start (ap, format)__builtin_va_start(ap, format); | |||
169 | fprintf (stderr__stderrp, "%s: ", program_name); | |||
170 | vfprintf (stderr__stderrp, format, ap); | |||
171 | va_end (ap)__builtin_va_end(ap); | |||
172 | exit (1); | |||
173 | /*NOTREACHED*/ | |||
174 | } | |||
175 | ||||
176 | static void _X_ATTRIBUTE_PRINTF(1,2)__attribute__((__format__(__printf__,1,2))) | |||
177 | warning (const char *format, ...) | |||
178 | { | |||
179 | va_list ap; | |||
180 | ||||
181 | va_start (ap, format)__builtin_va_start(ap, format); | |||
182 | fprintf (stderr__stderrp, "%s: ", program_name); | |||
183 | vfprintf (stderr__stderrp, format, ap); | |||
184 | va_end (ap)__builtin_va_end(ap); | |||
185 | } | |||
186 | ||||
187 | static void _X_NORETURN__attribute((noreturn)) _X_ATTRIBUTE_PRINTF(1,2)__attribute__((__format__(__printf__,1,2))) | |||
188 | argerr (const char *format, ...) | |||
189 | { | |||
190 | va_list ap; | |||
191 | ||||
192 | va_start (ap, format)__builtin_va_start(ap, format); | |||
193 | fprintf (stderr__stderrp, "%s: ", program_name); | |||
194 | vfprintf (stderr__stderrp, format, ap); | |||
195 | fprintf (stderr__stderrp, "Try '%s --help' for more information.\n", program_name); | |||
196 | va_end (ap)__builtin_va_end(ap); | |||
197 | exit (1); | |||
198 | /*NOTREACHED*/ | |||
199 | } | |||
200 | ||||
201 | /* Because fmin requires C99 suppport */ | |||
202 | static inline double dmin (double x, double y) | |||
203 | { | |||
204 | return x < y ? x : y; | |||
205 | } | |||
206 | ||||
207 | static const char * | |||
208 | rotation_name (Rotation rotation) | |||
209 | { | |||
210 | int i; | |||
211 | ||||
212 | if ((rotation & 0xf) == 0) | |||
213 | return "normal"; | |||
214 | for (i = 0; i < 4; i++) | |||
215 | if (rotation & (1 << i)) | |||
216 | return direction[i]; | |||
217 | return "invalid rotation"; | |||
218 | } | |||
219 | ||||
220 | static const char * | |||
221 | reflection_name (Rotation rotation) | |||
222 | { | |||
223 | rotation &= (RR_Reflect_X16|RR_Reflect_Y32); | |||
224 | switch (rotation) { | |||
225 | case 0: | |||
226 | return "none"; | |||
227 | case RR_Reflect_X16: | |||
228 | return "X axis"; | |||
229 | case RR_Reflect_Y32: | |||
230 | return "Y axis"; | |||
231 | case RR_Reflect_X16|RR_Reflect_Y32: | |||
232 | return "X and Y axis"; | |||
233 | } | |||
234 | return "invalid reflection"; | |||
235 | } | |||
236 | ||||
237 | static const char * | |||
238 | capability_name (int cap_bit) | |||
239 | { | |||
240 | switch (cap_bit) { | |||
241 | case RR_Capability_SourceOutput1: | |||
242 | return "Source Output"; | |||
243 | case RR_Capability_SinkOutput2: | |||
244 | return "Sink Output"; | |||
245 | case RR_Capability_SourceOffload4: | |||
246 | return "Source Offload"; | |||
247 | case RR_Capability_SinkOffload8: | |||
248 | return "Sink Offload"; | |||
249 | } | |||
250 | return "invalid capability"; | |||
251 | } | |||
252 | ||||
253 | typedef enum _relation { | |||
254 | relation_left_of, | |||
255 | relation_right_of, | |||
256 | relation_above, | |||
257 | relation_below, | |||
258 | relation_same_as, | |||
259 | } relation_t; | |||
260 | ||||
261 | typedef struct { | |||
262 | int x, y, width, height; | |||
263 | } rectangle_t; | |||
264 | ||||
265 | typedef struct { | |||
266 | int x1, y1, x2, y2; | |||
267 | } box_t; | |||
268 | ||||
269 | typedef struct { | |||
270 | int x, y; | |||
271 | } point_t; | |||
272 | ||||
273 | typedef enum _changes { | |||
274 | changes_none = 0, | |||
275 | changes_crtc = (1 << 0), | |||
276 | changes_mode = (1 << 1), | |||
277 | changes_relation = (1 << 2), | |||
278 | changes_position = (1 << 3), | |||
279 | changes_rotation = (1 << 4), | |||
280 | changes_reflection = (1 << 5), | |||
281 | changes_automatic = (1 << 6), | |||
282 | changes_refresh = (1 << 7), | |||
283 | changes_property = (1 << 8), | |||
284 | changes_transform = (1 << 9), | |||
285 | changes_panning = (1 << 10), | |||
286 | changes_gamma = (1 << 11), | |||
287 | changes_primary = (1 << 12), | |||
288 | } changes_t; | |||
289 | ||||
290 | typedef enum _name_kind { | |||
291 | name_none = 0, | |||
292 | name_string = (1 << 0), | |||
293 | name_xid = (1 << 1), | |||
294 | name_index = (1 << 2), | |||
295 | name_preferred = (1 << 3), | |||
296 | } name_kind_t; | |||
297 | ||||
298 | typedef struct { | |||
299 | name_kind_t kind; | |||
300 | char *string; | |||
301 | XID xid; | |||
302 | int index; | |||
303 | } name_t; | |||
304 | ||||
305 | typedef struct _crtc crtc_t; | |||
306 | typedef struct _output output_t; | |||
307 | typedef struct _transform transform_t; | |||
308 | typedef struct _umode umode_t; | |||
309 | typedef struct _output_prop output_prop_t; | |||
310 | typedef struct _provider provider_t; | |||
311 | typedef struct _monitors monitors_t; | |||
312 | typedef struct _umonitor umonitor_t; | |||
313 | ||||
314 | struct _transform { | |||
315 | XTransform transform; | |||
316 | const char *filter; | |||
317 | int nparams; | |||
318 | XFixed *params; | |||
319 | }; | |||
320 | ||||
321 | struct _crtc { | |||
322 | name_t crtc; | |||
323 | Boolint changing; | |||
324 | XRRCrtcInfo *crtc_info; | |||
325 | ||||
326 | XRRModeInfo *mode_info; | |||
327 | XRRPanning *panning_info; | |||
328 | int x; | |||
329 | int y; | |||
330 | Rotation rotation; | |||
331 | output_t **outputs; | |||
332 | int noutput; | |||
333 | transform_t current_transform, pending_transform; | |||
334 | }; | |||
335 | ||||
336 | struct _output_prop { | |||
337 | struct _output_prop *next; | |||
338 | char *name; | |||
339 | char *value; | |||
340 | }; | |||
341 | ||||
342 | struct _output { | |||
343 | struct _output *next; | |||
344 | ||||
345 | changes_t changes; | |||
346 | ||||
347 | output_prop_t *props; | |||
348 | ||||
349 | name_t output; | |||
350 | XRROutputInfo *output_info; | |||
351 | ||||
352 | name_t crtc; | |||
353 | crtc_t *crtc_info; | |||
354 | crtc_t *current_crtc_info; | |||
355 | ||||
356 | name_t mode; | |||
357 | double refresh; | |||
358 | XRRModeInfo *mode_info; | |||
359 | ||||
360 | name_t addmode; | |||
361 | ||||
362 | relation_t relation; | |||
363 | char *relative_to; | |||
364 | ||||
365 | int x, y; | |||
366 | Rotation rotation; | |||
367 | ||||
368 | XRRPanning panning; | |||
369 | ||||
370 | Boolint automatic; | |||
371 | int scale_from_w, scale_from_h; | |||
372 | transform_t transform; | |||
373 | ||||
374 | struct { | |||
375 | float red; | |||
376 | float green; | |||
377 | float blue; | |||
378 | } gamma; | |||
379 | ||||
380 | float brightness; | |||
381 | ||||
382 | Boolint primary; | |||
383 | ||||
384 | Boolint found; | |||
385 | }; | |||
386 | ||||
387 | typedef enum _umode_action { | |||
388 | umode_create, umode_destroy, umode_add, umode_delete | |||
389 | } umode_action_t; | |||
390 | ||||
391 | ||||
392 | struct _umode { | |||
393 | struct _umode *next; | |||
394 | ||||
395 | umode_action_t action; | |||
396 | XRRModeInfo mode; | |||
397 | name_t output; | |||
398 | name_t name; | |||
399 | }; | |||
400 | ||||
401 | struct _provider { | |||
402 | name_t provider; | |||
403 | XRRProviderInfo *info; | |||
404 | }; | |||
405 | ||||
406 | struct _monitors { | |||
407 | int n; | |||
408 | XRRMonitorInfo *monitors; | |||
409 | }; | |||
410 | ||||
411 | struct _umonitor { | |||
412 | struct _umonitor *next; | |||
413 | char *name; | |||
414 | Boolint set; | |||
415 | Boolint primary; | |||
416 | int x, y, width, height; | |||
417 | int mmwidth, mmheight; | |||
418 | int noutput; | |||
419 | name_t *outputs; | |||
420 | }; | |||
421 | ||||
422 | static const char *connection[3] = { | |||
423 | "connected", | |||
424 | "disconnected", | |||
425 | "unknown connection"}; | |||
426 | ||||
427 | #define OUTPUT_NAME1 1 | |||
428 | ||||
429 | #define CRTC_OFF2 2 | |||
430 | #define CRTC_UNSET3 3 | |||
431 | #define CRTC_INDEX0x40000000 0x40000000 | |||
432 | ||||
433 | #define MODE_NAME1 1 | |||
434 | #define MODE_OFF2 2 | |||
435 | #define MODE_UNSET3 3 | |||
436 | #define MODE_PREF4 4 | |||
437 | ||||
438 | #define POS_UNSET-1 -1 | |||
439 | ||||
440 | static output_t *all_outputs = NULL((void*)0); | |||
441 | static output_t **all_outputs_tail = &all_outputs; | |||
442 | static crtc_t *crtcs; | |||
443 | static provider_t *providers; | |||
444 | static umode_t *umodes; | |||
445 | static int num_crtcs, num_providers; | |||
446 | static XRRScreenResources *res; | |||
447 | static int fb_width = 0, fb_height = 0; | |||
448 | static int fb_width_mm = 0, fb_height_mm = 0; | |||
449 | static double dpi = 0; | |||
450 | static char *dpi_output_name = NULL((void*)0); | |||
451 | static Boolint dryrun = False0; | |||
452 | static int minWidth, maxWidth, minHeight, maxHeight; | |||
453 | static Boolint has_1_2 = False0; | |||
454 | static Boolint has_1_3 = False0; | |||
455 | static Boolint has_1_4 = False0; | |||
456 | static Boolint has_1_5 = False0; | |||
457 | static name_t provider_name, output_source_provider_name, offload_sink_provider_name; | |||
458 | static monitors_t *monitors; | |||
459 | static umonitor_t *umonitors; | |||
460 | ||||
461 | static int | |||
462 | mode_height (XRRModeInfo *mode_info, Rotation rotation) | |||
463 | { | |||
464 | switch (rotation & 0xf) { | |||
465 | case RR_Rotate_01: | |||
466 | case RR_Rotate_1804: | |||
467 | return mode_info->height; | |||
468 | case RR_Rotate_902: | |||
469 | case RR_Rotate_2708: | |||
470 | return mode_info->width; | |||
471 | default: | |||
472 | return 0; | |||
473 | } | |||
474 | } | |||
475 | ||||
476 | static int | |||
477 | mode_width (XRRModeInfo *mode_info, Rotation rotation) | |||
478 | { | |||
479 | switch (rotation & 0xf) { | |||
480 | case RR_Rotate_01: | |||
481 | case RR_Rotate_1804: | |||
482 | return mode_info->width; | |||
483 | case RR_Rotate_902: | |||
484 | case RR_Rotate_2708: | |||
485 | return mode_info->height; | |||
486 | default: | |||
487 | return 0; | |||
488 | } | |||
489 | } | |||
490 | ||||
491 | static Boolint | |||
492 | transform_point (XTransform *transform, double *xp, double *yp) | |||
493 | { | |||
494 | double vector[3]; | |||
495 | double result[3]; | |||
496 | int i, j; | |||
497 | double v; | |||
498 | ||||
499 | vector[0] = *xp; | |||
500 | vector[1] = *yp; | |||
501 | vector[2] = 1; | |||
502 | for (j = 0; j < 3; j++) | |||
503 | { | |||
504 | v = 0; | |||
505 | for (i = 0; i < 3; i++) | |||
506 | v += (XFixedToDouble (transform->matrix[j][i])(((XDouble) (transform->matrix[j][i])) / 65536) * vector[i]); | |||
507 | result[j] = v; | |||
508 | } | |||
509 | if (!result[2]) | |||
510 | return False0; | |||
511 | for (j = 0; j < 2; j++) { | |||
512 | vector[j] = result[j] / result[2]; | |||
513 | if (vector[j] > 32767 || vector[j] < -32767) | |||
514 | return False0; | |||
515 | } | |||
516 | *xp = vector[0]; | |||
517 | *yp = vector[1]; | |||
518 | return True1; | |||
519 | } | |||
520 | ||||
521 | static void | |||
522 | path_bounds (XTransform *transform, point_t *points, int npoints, box_t *box) | |||
523 | { | |||
524 | int i; | |||
525 | box_t point; | |||
526 | ||||
527 | for (i = 0; i < npoints; i++) { | |||
528 | double x, y; | |||
529 | x = points[i].x; | |||
530 | y = points[i].y; | |||
531 | transform_point (transform, &x, &y); | |||
532 | point.x1 = floor (x); | |||
533 | point.y1 = floor (y); | |||
534 | point.x2 = ceil (x); | |||
535 | point.y2 = ceil (y); | |||
536 | if (i == 0) | |||
537 | *box = point; | |||
538 | else { | |||
539 | if (point.x1 < box->x1) box->x1 = point.x1; | |||
540 | if (point.y1 < box->y1) box->y1 = point.y1; | |||
541 | if (point.x2 > box->x2) box->x2 = point.x2; | |||
542 | if (point.y2 > box->y2) box->y2 = point.y2; | |||
543 | } | |||
544 | } | |||
545 | } | |||
546 | ||||
547 | static void | |||
548 | mode_geometry (XRRModeInfo *mode_info, Rotation rotation, | |||
549 | XTransform *transform, | |||
550 | box_t *bounds) | |||
551 | { | |||
552 | point_t rect[4]; | |||
553 | int width = mode_width (mode_info, rotation); | |||
554 | int height = mode_height (mode_info, rotation); | |||
555 | ||||
556 | rect[0].x = 0; | |||
557 | rect[0].y = 0; | |||
558 | rect[1].x = width; | |||
559 | rect[1].y = 0; | |||
560 | rect[2].x = width; | |||
561 | rect[2].y = height; | |||
562 | rect[3].x = 0; | |||
563 | rect[3].y = height; | |||
564 | path_bounds (transform, rect, 4, bounds); | |||
565 | } | |||
566 | ||||
567 | /* v refresh frequency in Hz */ | |||
568 | static double | |||
569 | mode_refresh (const XRRModeInfo *mode_info) | |||
570 | { | |||
571 | double rate; | |||
572 | double vTotal = mode_info->vTotal; | |||
573 | ||||
574 | if (mode_info->modeFlags & RR_DoubleScan0x00000020) { | |||
575 | /* doublescan doubles the number of lines */ | |||
576 | vTotal *= 2; | |||
577 | } | |||
578 | ||||
579 | if (mode_info->modeFlags & RR_Interlace0x00000010) { | |||
580 | /* interlace splits the frame into two fields */ | |||
581 | /* the field rate is what is typically reported by monitors */ | |||
582 | vTotal /= 2; | |||
583 | } | |||
584 | ||||
585 | if (mode_info->hTotal && vTotal) | |||
586 | rate = ((double) mode_info->dotClock / | |||
587 | ((double) mode_info->hTotal * (double) vTotal)); | |||
588 | else | |||
589 | rate = 0; | |||
590 | return rate; | |||
591 | } | |||
592 | ||||
593 | /* h sync frequency in Hz */ | |||
594 | static double | |||
595 | mode_hsync (const XRRModeInfo *mode_info) | |||
596 | { | |||
597 | double rate; | |||
598 | ||||
599 | if (mode_info->hTotal) | |||
600 | rate = (double) mode_info->dotClock / (double) mode_info->hTotal; | |||
601 | else | |||
602 | rate = 0; | |||
603 | return rate; | |||
604 | } | |||
605 | ||||
606 | static void | |||
607 | print_verbose_mode (const XRRModeInfo *mode, Boolint current, Boolint preferred) | |||
608 | { | |||
609 | int f; | |||
610 | ||||
611 | printf (" %s (0x%x) %6.3fMHz", | |||
612 | mode->name, (int)mode->id, | |||
613 | (double)mode->dotClock / 1000000.0); | |||
614 | for (f = 0; mode_flags[f].flag; f++) | |||
615 | if (mode->modeFlags & mode_flags[f].flag) | |||
616 | printf (" %s", mode_flags[f].string); | |||
617 | if (current) | |||
618 | printf (" *current"); | |||
619 | if (preferred) | |||
620 | printf (" +preferred"); | |||
621 | printf ("\n"); | |||
622 | printf (" h: width %4d start %4d end %4d total %4d skew %4d clock %6.2fKHz\n", | |||
623 | mode->width, mode->hSyncStart, mode->hSyncEnd, | |||
624 | mode->hTotal, mode->hSkew, mode_hsync (mode) / 1000); | |||
625 | printf (" v: height %4d start %4d end %4d total %4d clock %6.2fHz\n", | |||
626 | mode->height, mode->vSyncStart, mode->vSyncEnd, mode->vTotal, | |||
627 | mode_refresh (mode)); | |||
628 | } | |||
629 | ||||
630 | static void | |||
631 | init_name (name_t *name) | |||
632 | { | |||
633 | name->kind = name_none; | |||
634 | } | |||
635 | ||||
636 | static void | |||
637 | set_name_string (name_t *name, char *string) | |||
638 | { | |||
639 | name->kind |= name_string; | |||
640 | name->string = string; | |||
641 | } | |||
642 | ||||
643 | static void | |||
644 | set_name_xid (name_t *name, XID xid) | |||
645 | { | |||
646 | name->kind |= name_xid; | |||
647 | name->xid = xid; | |||
648 | } | |||
649 | ||||
650 | static void | |||
651 | set_name_index (name_t *name, int idx) | |||
652 | { | |||
653 | name->kind |= name_index; | |||
654 | name->index = idx; | |||
655 | } | |||
656 | ||||
657 | static void | |||
658 | set_name_preferred (name_t *name) | |||
659 | { | |||
660 | name->kind |= name_preferred; | |||
661 | } | |||
662 | ||||
663 | static void | |||
664 | set_name_all (name_t *name, name_t *old) | |||
665 | { | |||
666 | if (old->kind & name_xid) | |||
667 | name->xid = old->xid; | |||
668 | if (old->kind & name_string) | |||
669 | name->string = old->string; | |||
670 | if (old->kind & name_index) | |||
671 | name->index = old->index; | |||
672 | name->kind |= old->kind; | |||
673 | } | |||
674 | ||||
675 | static void | |||
676 | set_name (name_t *name, char *string, name_kind_t valid) | |||
677 | { | |||
678 | unsigned int xid; /* don't make it XID (which is unsigned long): | |||
679 | scanf() takes unsigned int */ | |||
680 | int idx; | |||
681 | ||||
682 | if ((valid & name_xid) && sscanf (string, "0x%x", &xid) == 1) | |||
683 | set_name_xid (name, xid); | |||
684 | else if ((valid & name_index) && sscanf (string, "%d", &idx) == 1) | |||
685 | set_name_index (name, idx); | |||
686 | else if (valid & name_string) | |||
687 | set_name_string (name, string); | |||
688 | else | |||
689 | argerr ("invalid name '%s'\n", string); | |||
690 | } | |||
691 | ||||
692 | static int | |||
693 | print_name (const name_t *name) | |||
694 | { | |||
695 | name_kind_t kind = name->kind; | |||
696 | ||||
697 | if ((kind & name_xid)) return printf("XID 0x%x", (unsigned int)name->xid); | |||
698 | else if ((kind & name_string)) return printf("name %s", name->string); | |||
699 | else if ((kind & name_index)) return printf("index %d", name->index); | |||
700 | else return printf("unknown name"); | |||
701 | } | |||
702 | ||||
703 | static void | |||
704 | init_transform (transform_t *transform) | |||
705 | { | |||
706 | int x; | |||
707 | memset (&transform->transform, '\0', sizeof (transform->transform))__builtin___memset_chk (&transform->transform, '\0', sizeof (transform->transform), __builtin_object_size (&transform ->transform, 0)); | |||
708 | for (x = 0; x < 3; x++) | |||
709 | transform->transform.matrix[x][x] = XDoubleToFixed (1.0)((XFixed) ((1.0) * 65536)); | |||
710 | transform->filter = ""; | |||
711 | transform->nparams = 0; | |||
712 | transform->params = NULL((void*)0); | |||
713 | } | |||
714 | ||||
715 | static void | |||
716 | set_transform (transform_t *dest, | |||
717 | XTransform *transform, | |||
718 | const char *filter, | |||
719 | XFixed *params, | |||
720 | int nparams) | |||
721 | { | |||
722 | dest->transform = *transform; | |||
723 | /* note: this string is leaked */ | |||
724 | dest->filter = strdup (filter); | |||
725 | dest->nparams = nparams; | |||
726 | dest->params = malloc (nparams * sizeof (XFixed)); | |||
727 | memcpy (dest->params, params, nparams * sizeof (XFixed))__builtin___memcpy_chk (dest->params, params, nparams * sizeof (XFixed), __builtin_object_size (dest->params, 0)); | |||
728 | } | |||
729 | ||||
730 | static void | |||
731 | copy_transform (transform_t *dest, transform_t *src) | |||
732 | { | |||
733 | set_transform (dest, &src->transform, | |||
734 | src->filter, src->params, src->nparams); | |||
735 | } | |||
736 | ||||
737 | static Boolint | |||
738 | equal_transform (transform_t *a, transform_t *b) | |||
739 | { | |||
740 | if (memcmp (&a->transform, &b->transform, sizeof (XTransform)) != 0) | |||
741 | return False0; | |||
742 | if (strcmp (a->filter, b->filter) != 0) | |||
743 | return False0; | |||
744 | if (a->nparams != b->nparams) | |||
745 | return False0; | |||
746 | if (memcmp (a->params, b->params, a->nparams * sizeof (XFixed)) != 0) | |||
747 | return False0; | |||
748 | return True1; | |||
749 | } | |||
750 | ||||
751 | static output_t * | |||
752 | add_output (void) | |||
753 | { | |||
754 | output_t *output = calloc (1, sizeof (output_t)); | |||
755 | ||||
756 | if (!output) | |||
757 | fatal ("out of memory\n"); | |||
758 | output->next = NULL((void*)0); | |||
759 | output->found = False0; | |||
760 | output->brightness = 1.0; | |||
761 | *all_outputs_tail = output; | |||
762 | all_outputs_tail = &output->next; | |||
763 | return output; | |||
764 | } | |||
765 | ||||
766 | static output_t * | |||
767 | find_output (name_t *name) | |||
768 | { | |||
769 | output_t *output; | |||
770 | ||||
771 | for (output = all_outputs; output; output = output->next) | |||
772 | { | |||
773 | name_kind_t common = name->kind & output->output.kind; | |||
774 | ||||
775 | if ((common & name_xid) && name->xid == output->output.xid) | |||
776 | break; | |||
777 | if ((common & name_string) && !strcmp (name->string, output->output.string)) | |||
778 | break; | |||
779 | if ((common & name_index) && name->index == output->output.index) | |||
780 | break; | |||
781 | } | |||
782 | return output; | |||
783 | } | |||
784 | ||||
785 | static output_t * | |||
786 | find_output_by_xid (RROutput output) | |||
787 | { | |||
788 | name_t output_name; | |||
789 | ||||
790 | init_name (&output_name); | |||
791 | set_name_xid (&output_name, output); | |||
792 | return find_output (&output_name); | |||
793 | } | |||
794 | ||||
795 | static output_t * | |||
796 | find_output_by_name (char *name) | |||
797 | { | |||
798 | name_t output_name; | |||
799 | ||||
800 | init_name (&output_name); | |||
801 | set_name_string (&output_name, name); | |||
802 | return find_output (&output_name); | |||
803 | } | |||
804 | ||||
805 | static crtc_t * | |||
806 | find_crtc (name_t *name) | |||
807 | { | |||
808 | int c; | |||
809 | crtc_t *crtc = NULL((void*)0); | |||
810 | ||||
811 | for (c = 0; c < num_crtcs; c++) | |||
812 | { | |||
813 | name_kind_t common; | |||
814 | ||||
815 | crtc = &crtcs[c]; | |||
816 | common = name->kind & crtc->crtc.kind; | |||
817 | ||||
818 | if ((common & name_xid) && name->xid == crtc->crtc.xid) | |||
819 | break; | |||
820 | if ((common & name_string) && !strcmp (name->string, crtc->crtc.string)) | |||
821 | break; | |||
822 | if ((common & name_index) && name->index == crtc->crtc.index) | |||
823 | break; | |||
824 | crtc = NULL((void*)0); | |||
825 | } | |||
826 | return crtc; | |||
827 | } | |||
828 | ||||
829 | static crtc_t * | |||
830 | find_crtc_by_xid (RRCrtc crtc) | |||
831 | { | |||
832 | name_t crtc_name; | |||
833 | ||||
834 | init_name (&crtc_name); | |||
835 | set_name_xid (&crtc_name, crtc); | |||
836 | return find_crtc (&crtc_name); | |||
837 | } | |||
838 | ||||
839 | static XRRModeInfo * | |||
840 | find_mode (name_t *name, double refresh) | |||
841 | { | |||
842 | int m; | |||
843 | XRRModeInfo *best = NULL((void*)0); | |||
844 | double bestDist = 0; | |||
845 | ||||
846 | for (m = 0; m < res->nmode; m++) | |||
847 | { | |||
848 | XRRModeInfo *mode = &res->modes[m]; | |||
849 | if ((name->kind & name_xid) && name->xid == mode->id) | |||
850 | { | |||
851 | best = mode; | |||
852 | break; | |||
853 | } | |||
854 | if ((name->kind & name_string) && !strcmp (name->string, mode->name)) | |||
855 | { | |||
856 | double dist; | |||
857 | ||||
858 | if (refresh) | |||
859 | dist = fabs (mode_refresh (mode) - refresh); | |||
860 | else | |||
861 | dist = 0; | |||
862 | if (!best || dist < bestDist) | |||
863 | { | |||
864 | bestDist = dist; | |||
865 | best = mode; | |||
866 | } | |||
867 | } | |||
868 | } | |||
869 | return best; | |||
870 | } | |||
871 | ||||
872 | static XRRModeInfo * | |||
873 | find_mode_by_xid (RRMode mode) | |||
874 | { | |||
875 | name_t mode_name; | |||
876 | ||||
877 | init_name (&mode_name); | |||
878 | set_name_xid (&mode_name, mode); | |||
879 | return find_mode (&mode_name, 0); | |||
880 | } | |||
881 | ||||
882 | #if 0 | |||
883 | static XRRModeInfo * | |||
884 | find_mode_by_name (char *name) | |||
885 | { | |||
886 | name_t mode_name; | |||
887 | init_name (&mode_name); | |||
888 | set_name_string (&mode_name, name); | |||
889 | return find_mode (&mode_name, 0); | |||
890 | } | |||
891 | #endif | |||
892 | ||||
893 | static | |||
894 | XRRModeInfo * | |||
895 | find_mode_for_output (output_t *output, name_t *name) | |||
896 | { | |||
897 | XRROutputInfo *output_info = output->output_info; | |||
898 | int m; | |||
899 | XRRModeInfo *best = NULL((void*)0); | |||
900 | double bestDist = 0; | |||
901 | ||||
902 | for (m = 0; m < output_info->nmode; m++) | |||
903 | { | |||
904 | XRRModeInfo *mode; | |||
905 | ||||
906 | mode = find_mode_by_xid (output_info->modes[m]); | |||
907 | if (!mode) continue; | |||
908 | if ((name->kind & name_xid) && name->xid == mode->id) | |||
909 | { | |||
910 | best = mode; | |||
911 | break; | |||
912 | } | |||
913 | if ((name->kind & name_string) && !strcmp (name->string, mode->name)) | |||
914 | { | |||
915 | double dist; | |||
916 | ||||
917 | /* Stay away from doublescan modes unless refresh rate is specified. */ | |||
918 | if (!output->refresh && (mode->modeFlags & RR_DoubleScan0x00000020)) | |||
919 | continue; | |||
920 | ||||
921 | if (output->refresh) | |||
922 | dist = fabs (mode_refresh (mode) - output->refresh); | |||
923 | else | |||
924 | dist = 0; | |||
925 | if (!best || dist < bestDist) | |||
926 | { | |||
927 | bestDist = dist; | |||
928 | best = mode; | |||
929 | } | |||
930 | } | |||
931 | } | |||
932 | return best; | |||
933 | } | |||
934 | ||||
935 | static XRRModeInfo * | |||
936 | preferred_mode (output_t *output) | |||
937 | { | |||
938 | XRROutputInfo *output_info = output->output_info; | |||
939 | int m; | |||
940 | XRRModeInfo *best; | |||
941 | int bestDist; | |||
942 | ||||
943 | best = NULL((void*)0); | |||
944 | bestDist = 0; | |||
945 | for (m = 0; m < output_info->nmode; m++) | |||
946 | { | |||
947 | XRRModeInfo *mode_info = find_mode_by_xid (output_info->modes[m]); | |||
948 | int dist; | |||
949 | ||||
950 | if (m < output_info->npreferred) | |||
951 | dist = 0; | |||
952 | else if (output_info->mm_height) | |||
953 | dist = (1000 * DisplayHeight(dpy, screen)((&((_XPrivDisplay)(dpy))->screens[screen])->height ) / DisplayHeightMM(dpy, screen)((&((_XPrivDisplay)(dpy))->screens[screen])->mheight ) - | |||
954 | 1000 * mode_info->height / output_info->mm_height); | |||
955 | else | |||
956 | dist = DisplayHeight(dpy, screen)((&((_XPrivDisplay)(dpy))->screens[screen])->height ) - mode_info->height; | |||
957 | ||||
958 | if (dist < 0) dist = -dist; | |||
959 | if (!best || dist < bestDist) | |||
960 | { | |||
961 | best = mode_info; | |||
962 | bestDist = dist; | |||
963 | } | |||
964 | } | |||
965 | return best; | |||
966 | } | |||
967 | ||||
968 | static Boolint | |||
969 | output_can_use_crtc (output_t *output, crtc_t *crtc) | |||
970 | { | |||
971 | XRROutputInfo *output_info = output->output_info; | |||
972 | int c; | |||
973 | ||||
974 | for (c = 0; c < output_info->ncrtc; c++) | |||
975 | if (output_info->crtcs[c] == crtc->crtc.xid) | |||
976 | return True1; | |||
977 | return False0; | |||
978 | } | |||
979 | ||||
980 | static Boolint | |||
981 | output_can_use_mode (output_t *output, XRRModeInfo *mode) | |||
982 | { | |||
983 | XRROutputInfo *output_info = output->output_info; | |||
984 | int m; | |||
985 | ||||
986 | for (m = 0; m < output_info->nmode; m++) | |||
987 | if (output_info->modes[m] == mode->id) | |||
988 | return True1; | |||
989 | return False0; | |||
990 | } | |||
991 | ||||
992 | static Boolint | |||
993 | crtc_can_use_rotation (crtc_t *crtc, Rotation rotation) | |||
994 | { | |||
995 | Rotation rotations = crtc->crtc_info->rotations; | |||
996 | Rotation dir = rotation & (RR_Rotate_01|RR_Rotate_902|RR_Rotate_1804|RR_Rotate_2708); | |||
997 | Rotation reflect = rotation & (RR_Reflect_X16|RR_Reflect_Y32); | |||
998 | if (((rotations & dir) != 0) && ((rotations & reflect) == reflect)) | |||
999 | return True1; | |||
1000 | return False0; | |||
1001 | } | |||
1002 | ||||
1003 | #if 0 | |||
1004 | static Boolint | |||
1005 | crtc_can_use_transform (crtc_t *crtc, XTransform *transform) | |||
1006 | { | |||
1007 | int major, minor; | |||
1008 | ||||
1009 | XRRQueryVersion (dpy, &major, &minor); | |||
1010 | if (major > 1 || (major == 1 && minor >= 3)) | |||
1011 | return True1; | |||
1012 | return False0; | |||
1013 | } | |||
1014 | #endif | |||
1015 | ||||
1016 | /* | |||
1017 | * Report only rotations that are supported by all crtcs | |||
1018 | */ | |||
1019 | static Rotation | |||
1020 | output_rotations (output_t *output) | |||
1021 | { | |||
1022 | Boolint found = False0; | |||
1023 | Rotation rotation = RR_Rotate_01; | |||
1024 | XRROutputInfo *output_info = output->output_info; | |||
1025 | int c; | |||
1026 | ||||
1027 | for (c = 0; c < output_info->ncrtc; c++) | |||
1028 | { | |||
1029 | crtc_t *crtc = find_crtc_by_xid (output_info->crtcs[c]); | |||
1030 | if (crtc) | |||
1031 | { | |||
1032 | if (!found) { | |||
1033 | rotation = crtc->crtc_info->rotations; | |||
1034 | found = True1; | |||
1035 | } else | |||
1036 | rotation &= crtc->crtc_info->rotations; | |||
1037 | } | |||
1038 | } | |||
1039 | return rotation; | |||
1040 | } | |||
1041 | ||||
1042 | static Boolint | |||
1043 | output_can_use_rotation (output_t *output, Rotation rotation) | |||
1044 | { | |||
1045 | XRROutputInfo *output_info = output->output_info; | |||
1046 | int c; | |||
1047 | ||||
1048 | /* make sure all of the crtcs can use this rotation. | |||
1049 | * yes, this is not strictly necessary, but it is | |||
1050 | * simpler,and we expect most drivers to either | |||
1051 | * support rotation everywhere or nowhere | |||
1052 | */ | |||
1053 | for (c = 0; c < output_info->ncrtc; c++) | |||
1054 | { | |||
1055 | crtc_t *crtc = find_crtc_by_xid (output_info->crtcs[c]); | |||
1056 | if (crtc && !crtc_can_use_rotation (crtc, rotation)) | |||
1057 | return False0; | |||
1058 | } | |||
1059 | return True1; | |||
1060 | } | |||
1061 | ||||
1062 | static Boolint | |||
1063 | output_is_primary(output_t *output) | |||
1064 | { | |||
1065 | if (has_1_3) | |||
1066 | return XRRGetOutputPrimary(dpy, root) == output->output.xid; | |||
1067 | return False0; | |||
1068 | } | |||
1069 | ||||
1070 | /* Returns the index of the last value in an array < 0xffff */ | |||
1071 | static int | |||
1072 | find_last_non_clamped(CARD16 array[], int size) { | |||
1073 | int i; | |||
1074 | for (i = size - 1; i > 0; i--) { | |||
1075 | if (array[i] < 0xffff) | |||
1076 | return i; | |||
1077 | } | |||
1078 | return 0; | |||
1079 | } | |||
1080 | ||||
1081 | static void | |||
1082 | set_gamma_info(output_t *output) | |||
1083 | { | |||
1084 | XRRCrtcGamma *crtc_gamma; | |||
1085 | double i1, v1, i2, v2; | |||
1086 | int size, middle, last_best, last_red, last_green, last_blue; | |||
1087 | CARD16 *best_array; | |||
1088 | ||||
1089 | if (!output->crtc_info) | |||
1090 | return; | |||
1091 | ||||
1092 | size = XRRGetCrtcGammaSize(dpy, output->crtc_info->crtc.xid); | |||
1093 | if (!size) { | |||
1094 | warning("Failed to get size of gamma for output %s\n", output->output.string); | |||
1095 | return; | |||
1096 | } | |||
1097 | ||||
1098 | crtc_gamma = XRRGetCrtcGamma(dpy, output->crtc_info->crtc.xid); | |||
1099 | if (!crtc_gamma) { | |||
1100 | warning("Failed to get gamma for output %s\n", output->output.string); | |||
1101 | return; | |||
1102 | } | |||
1103 | ||||
1104 | /* | |||
1105 | * Here is a bit tricky because gamma is a whole curve for each | |||
1106 | * color. So, typically, we need to represent 3 * 256 values as 3 + 1 | |||
1107 | * values. Therefore, we approximate the gamma curve (v) by supposing | |||
1108 | * it always follows the way we set it: a power function (i^g) | |||
1109 | * multiplied by a brightness (b). | |||
1110 | * v = i^g * b | |||
1111 | * so g = (ln(v) - ln(b))/ln(i) | |||
1112 | * and b can be found using two points (v1,i1) and (v2, i2): | |||
1113 | * b = e^((ln(v2)*ln(i1) - ln(v1)*ln(i2))/ln(i1/i2)) | |||
1114 | * For the best resolution, we select i2 at the highest place not | |||
1115 | * clamped and i1 at i2/2. Note that if i2 = 1 (as in most normal | |||
1116 | * cases), then b = v2. | |||
1117 | */ | |||
1118 | last_red = find_last_non_clamped(crtc_gamma->red, size); | |||
1119 | last_green = find_last_non_clamped(crtc_gamma->green, size); | |||
1120 | last_blue = find_last_non_clamped(crtc_gamma->blue, size); | |||
1121 | best_array = crtc_gamma->red; | |||
1122 | last_best = last_red; | |||
1123 | if (last_green > last_best) { | |||
1124 | last_best = last_green; | |||
1125 | best_array = crtc_gamma->green; | |||
1126 | } | |||
1127 | if (last_blue > last_best) { | |||
1128 | last_best = last_blue; | |||
1129 | best_array = crtc_gamma->blue; | |||
1130 | } | |||
1131 | if (last_best == 0) | |||
1132 | last_best = 1; | |||
1133 | ||||
1134 | middle = last_best / 2; | |||
1135 | i1 = (double)(middle + 1) / size; | |||
1136 | v1 = (double)(best_array[middle]) / 65535; | |||
1137 | i2 = (double)(last_best + 1) / size; | |||
1138 | v2 = (double)(best_array[last_best]) / 65535; | |||
1139 | if (v2 < 0.0001) { /* The screen is black */ | |||
1140 | output->brightness = 0; | |||
1141 | output->gamma.red = 1; | |||
1142 | output->gamma.green = 1; | |||
1143 | output->gamma.blue = 1; | |||
1144 | } else { | |||
1145 | if ((last_best + 1) == size) | |||
1146 | output->brightness = v2; | |||
1147 | else | |||
1148 | output->brightness = exp((log(v2)*log(i1) - log(v1)*log(i2))/log(i1/i2)); | |||
1149 | output->gamma.red = log((double)(crtc_gamma->red[last_red / 2]) / output->brightness | |||
1150 | / 65535) / log((double)((last_red / 2) + 1) / size); | |||
1151 | output->gamma.green = log((double)(crtc_gamma->green[last_green / 2]) / output->brightness | |||
1152 | / 65535) / log((double)((last_green / 2) + 1) / size); | |||
1153 | output->gamma.blue = log((double)(crtc_gamma->blue[last_blue / 2]) / output->brightness | |||
1154 | / 65535) / log((double)((last_blue / 2) + 1) / size); | |||
1155 | } | |||
1156 | ||||
1157 | XRRFreeGamma(crtc_gamma); | |||
1158 | } | |||
1159 | ||||
1160 | static void | |||
1161 | set_output_info (output_t *output, RROutput xid, XRROutputInfo *output_info) | |||
1162 | { | |||
1163 | /* sanity check output info */ | |||
1164 | if (output_info->connection != RR_Disconnected1 && !output_info->nmode) | |||
1165 | warning ("Output %s is not disconnected but has no modes\n", | |||
1166 | output_info->name); | |||
1167 | ||||
1168 | /* set output name and info */ | |||
1169 | if (!(output->output.kind & name_xid)) | |||
1170 | set_name_xid (&output->output, xid); | |||
1171 | if (!(output->output.kind & name_string)) | |||
1172 | set_name_string (&output->output, output_info->name); | |||
1173 | output->output_info = output_info; | |||
1174 | ||||
1175 | /* set crtc name and info */ | |||
1176 | if (!(output->changes & changes_crtc)) | |||
1177 | set_name_xid (&output->crtc, output_info->crtc); | |||
1178 | ||||
1179 | if (output->crtc.kind == name_xid && output->crtc.xid == None0L) | |||
1180 | output->crtc_info = NULL((void*)0); | |||
1181 | else | |||
1182 | { | |||
1183 | output->crtc_info = find_crtc (&output->crtc); | |||
1184 | if (!output->crtc_info) | |||
1185 | { | |||
1186 | if (output->crtc.kind & name_xid) | |||
1187 | fatal ("cannot find crtc 0x%lx\n", output->crtc.xid); | |||
1188 | if (output->crtc.kind & name_index) | |||
1189 | fatal ("cannot find crtc %d\n", output->crtc.index); | |||
1190 | } | |||
1191 | if (!output_can_use_crtc (output, output->crtc_info)) | |||
1192 | fatal ("output %s cannot use crtc 0x%lx\n", output->output.string, | |||
1193 | output->crtc_info->crtc.xid); | |||
1194 | } | |||
1195 | ||||
1196 | /* set mode name and info */ | |||
1197 | if (!(output->changes & changes_mode)) | |||
1198 | { | |||
1199 | crtc_t *crtc = NULL((void*)0); | |||
1200 | ||||
1201 | if (output_info->crtc) | |||
1202 | crtc = find_crtc_by_xid(output_info->crtc); | |||
1203 | if (crtc && crtc->crtc_info) | |||
1204 | set_name_xid (&output->mode, crtc->crtc_info->mode); | |||
1205 | else if (output->crtc_info) | |||
1206 | set_name_xid (&output->mode, output->crtc_info->crtc_info->mode); | |||
1207 | else | |||
1208 | set_name_xid (&output->mode, None0L); | |||
1209 | if (output->mode.xid) | |||
1210 | { | |||
1211 | output->mode_info = find_mode_by_xid (output->mode.xid); | |||
1212 | if (!output->mode_info) | |||
1213 | fatal ("server did not report mode 0x%lx for output %s\n", | |||
1214 | output->mode.xid, output->output.string); | |||
1215 | } | |||
1216 | else | |||
1217 | output->mode_info = NULL((void*)0); | |||
1218 | } | |||
1219 | else if (output->mode.kind == name_xid && output->mode.xid == None0L) | |||
1220 | output->mode_info = NULL((void*)0); | |||
1221 | else | |||
1222 | { | |||
1223 | if (output->mode.kind == name_preferred) | |||
1224 | output->mode_info = preferred_mode (output); | |||
1225 | else | |||
1226 | output->mode_info = find_mode_for_output (output, &output->mode); | |||
1227 | if (!output->mode_info) | |||
1228 | { | |||
1229 | if (output->mode.kind & name_preferred) | |||
1230 | fatal ("cannot find preferred mode\n"); | |||
1231 | if (output->mode.kind & name_string) | |||
1232 | fatal ("cannot find mode %s\n", output->mode.string); | |||
1233 | if (output->mode.kind & name_xid) | |||
1234 | fatal ("cannot find mode 0x%lx\n", output->mode.xid); | |||
1235 | } | |||
1236 | if (!output_can_use_mode (output, output->mode_info)) | |||
1237 | fatal ("output %s cannot use mode %s\n", output->output.string, | |||
1238 | output->mode_info->name); | |||
1239 | } | |||
1240 | ||||
1241 | /* set position */ | |||
1242 | if (!(output->changes & changes_position)) | |||
1243 | { | |||
1244 | if (output->crtc_info) | |||
1245 | { | |||
1246 | output->x = output->crtc_info->crtc_info->x; | |||
1247 | output->y = output->crtc_info->crtc_info->y; | |||
1248 | } | |||
1249 | else | |||
1250 | { | |||
1251 | output->x = 0; | |||
1252 | output->y = 0; | |||
1253 | } | |||
1254 | } | |||
1255 | ||||
1256 | /* set rotation */ | |||
1257 | if (!(output->changes & changes_rotation)) | |||
1258 | { | |||
1259 | output->rotation &= ~0xf; | |||
1260 | if (output->crtc_info) | |||
1261 | output->rotation |= (output->crtc_info->crtc_info->rotation & 0xf); | |||
1262 | else | |||
1263 | output->rotation = RR_Rotate_01; | |||
1264 | } | |||
1265 | if (!(output->changes & changes_reflection)) | |||
1266 | { | |||
1267 | output->rotation &= ~(RR_Reflect_X16|RR_Reflect_Y32); | |||
1268 | if (output->crtc_info) | |||
1269 | output->rotation |= (output->crtc_info->crtc_info->rotation & | |||
1270 | (RR_Reflect_X16|RR_Reflect_Y32)); | |||
1271 | } | |||
1272 | if (!output_can_use_rotation (output, output->rotation)) | |||
1273 | fatal ("output %s cannot use rotation \"%s\" reflection \"%s\"\n", | |||
1274 | output->output.string, | |||
1275 | rotation_name (output->rotation), | |||
1276 | reflection_name (output->rotation)); | |||
1277 | ||||
1278 | /* set gamma */ | |||
1279 | if (!(output->changes & changes_gamma)) | |||
1280 | set_gamma_info(output); | |||
1281 | ||||
1282 | /* set transformation */ | |||
1283 | if (!(output->changes & changes_transform)) | |||
1284 | { | |||
1285 | if (output->crtc_info) | |||
1286 | copy_transform (&output->transform, &output->crtc_info->current_transform); | |||
1287 | else | |||
1288 | init_transform (&output->transform); | |||
1289 | } else { | |||
1290 | /* transform was already set for --scale or --transform */ | |||
1291 | ||||
1292 | /* for --scale-from, figure out the mode size and compute the transform | |||
1293 | * for the target framebuffer area */ | |||
1294 | if (output->scale_from_w > 0 && output->mode_info) { | |||
1295 | double sx = (double)output->scale_from_w / | |||
1296 | output->mode_info->width; | |||
1297 | double sy = (double)output->scale_from_h / | |||
1298 | output->mode_info->height; | |||
1299 | if (verbose) | |||
1300 | printf("scaling %s by %lfx%lf\n", output->output.string, sx, | |||
1301 | sy); | |||
1302 | init_transform (&output->transform); | |||
1303 | output->transform.transform.matrix[0][0] = XDoubleToFixed (sx)((XFixed) ((sx) * 65536)); | |||
1304 | output->transform.transform.matrix[1][1] = XDoubleToFixed (sy)((XFixed) ((sy) * 65536)); | |||
1305 | output->transform.transform.matrix[2][2] = XDoubleToFixed (1.0)((XFixed) ((1.0) * 65536)); | |||
1306 | if (sx != 1 || sy != 1) | |||
1307 | output->transform.filter = "bilinear"; | |||
1308 | else | |||
1309 | output->transform.filter = "nearest"; | |||
1310 | output->transform.nparams = 0; | |||
1311 | output->transform.params = NULL((void*)0); | |||
1312 | } | |||
1313 | } | |||
1314 | ||||
1315 | /* set primary */ | |||
1316 | if (!(output->changes & changes_primary)) | |||
1317 | output->primary = output_is_primary(output); | |||
1318 | } | |||
1319 | ||||
1320 | static void | |||
1321 | get_screen (Boolint current) | |||
1322 | { | |||
1323 | if (!has_1_2) | |||
1324 | fatal ("Server RandR version before 1.2\n"); | |||
1325 | ||||
1326 | if (res) | |||
1327 | return; | |||
1328 | ||||
1329 | XRRGetScreenSizeRange (dpy, root, &minWidth, &minHeight, | |||
1330 | &maxWidth, &maxHeight); | |||
1331 | ||||
1332 | if (current) | |||
1333 | res = XRRGetScreenResourcesCurrent (dpy, root); | |||
1334 | else | |||
1335 | res = XRRGetScreenResources (dpy, root); | |||
1336 | if (!res) fatal ("could not get screen resources"); | |||
1337 | } | |||
1338 | ||||
1339 | static void | |||
1340 | get_crtcs (void) | |||
1341 | { | |||
1342 | int c; | |||
1343 | ||||
1344 | num_crtcs = res->ncrtc; | |||
1345 | crtcs = calloc (num_crtcs, sizeof (crtc_t)); | |||
1346 | if (!crtcs) fatal ("out of memory\n"); | |||
1347 | ||||
1348 | for (c = 0; c < res->ncrtc; c++) | |||
1349 | { | |||
1350 | XRRCrtcInfo *crtc_info = XRRGetCrtcInfo (dpy, res, res->crtcs[c]); | |||
1351 | XRRCrtcTransformAttributes *attr; | |||
1352 | XRRPanning *panning_info = NULL((void*)0); | |||
1353 | ||||
1354 | if (has_1_3) { | |||
1355 | XRRPanning zero; | |||
1356 | memset(&zero, 0, sizeof(zero))__builtin___memset_chk (&zero, 0, sizeof(zero), __builtin_object_size (&zero, 0)); | |||
1357 | panning_info = XRRGetPanning (dpy, res, res->crtcs[c]); | |||
1358 | zero.timestamp = panning_info->timestamp; | |||
1359 | if (!memcmp(panning_info, &zero, sizeof(zero))) { | |||
1360 | Xfree(panning_info)free((panning_info)); | |||
1361 | panning_info = NULL((void*)0); | |||
1362 | } | |||
1363 | } | |||
1364 | ||||
1365 | set_name_xid (&crtcs[c].crtc, res->crtcs[c]); | |||
1366 | set_name_index (&crtcs[c].crtc, c); | |||
1367 | if (!crtc_info) fatal ("could not get crtc 0x%lx information\n", res->crtcs[c]); | |||
1368 | crtcs[c].crtc_info = crtc_info; | |||
1369 | crtcs[c].panning_info = panning_info; | |||
1370 | if (crtc_info->mode == None0L) | |||
1371 | { | |||
1372 | crtcs[c].mode_info = NULL((void*)0); | |||
1373 | crtcs[c].x = 0; | |||
1374 | crtcs[c].y = 0; | |||
1375 | crtcs[c].rotation = RR_Rotate_01; | |||
1376 | } | |||
1377 | if (XRRGetCrtcTransform (dpy, res->crtcs[c], &attr) && attr) { | |||
1378 | set_transform (&crtcs[c].current_transform, | |||
1379 | &attr->currentTransform, | |||
1380 | attr->currentFilter, | |||
1381 | attr->currentParams, | |||
1382 | attr->currentNparams); | |||
1383 | XFree (attr); | |||
1384 | } | |||
1385 | else | |||
1386 | { | |||
1387 | init_transform (&crtcs[c].current_transform); | |||
1388 | } | |||
1389 | copy_transform (&crtcs[c].pending_transform, &crtcs[c].current_transform); | |||
1390 | } | |||
1391 | } | |||
1392 | ||||
1393 | static void | |||
1394 | crtc_add_output (crtc_t *crtc, output_t *output) | |||
1395 | { | |||
1396 | if (crtc->outputs) | |||
1397 | crtc->outputs = realloc (crtc->outputs, (crtc->noutput + 1) * sizeof (output_t *)); | |||
1398 | else | |||
1399 | { | |||
1400 | crtc->outputs = malloc (sizeof (output_t *)); | |||
1401 | crtc->x = output->x; | |||
1402 | crtc->y = output->y; | |||
1403 | crtc->rotation = output->rotation; | |||
1404 | crtc->mode_info = output->mode_info; | |||
1405 | copy_transform (&crtc->pending_transform, &output->transform); | |||
1406 | } | |||
1407 | if (!crtc->outputs) fatal ("out of memory\n"); | |||
1408 | crtc->outputs[crtc->noutput++] = output; | |||
1409 | } | |||
1410 | ||||
1411 | static void | |||
1412 | set_crtcs (void) | |||
1413 | { | |||
1414 | output_t *output; | |||
1415 | ||||
1416 | for (output = all_outputs; output; output = output->next) | |||
1417 | { | |||
1418 | if (!output->mode_info) continue; | |||
1419 | crtc_add_output (output->crtc_info, output); | |||
1420 | } | |||
1421 | } | |||
1422 | ||||
1423 | static void | |||
1424 | set_panning (void) | |||
1425 | { | |||
1426 | output_t *output; | |||
1427 | ||||
1428 | for (output = all_outputs; output; output = output->next) | |||
1429 | { | |||
1430 | if (! output->crtc_info) | |||
1431 | continue; | |||
1432 | if (! (output->changes & changes_panning)) | |||
1433 | continue; | |||
1434 | if (! output->crtc_info->panning_info) | |||
1435 | output->crtc_info->panning_info = malloc (sizeof(XRRPanning)); | |||
1436 | memcpy (output->crtc_info->panning_info, &output->panning, sizeof(XRRPanning))__builtin___memcpy_chk (output->crtc_info->panning_info , &output->panning, sizeof(XRRPanning), __builtin_object_size (output->crtc_info->panning_info, 0)); | |||
1437 | output->crtc_info->changing = 1; | |||
1438 | } | |||
1439 | } | |||
1440 | ||||
1441 | static void | |||
1442 | set_gamma(void) | |||
1443 | { | |||
1444 | output_t *output; | |||
1445 | ||||
1446 | for (output = all_outputs; output; output = output->next) { | |||
1447 | int i, size; | |||
1448 | crtc_t *crtc; | |||
1449 | XRRCrtcGamma *crtc_gamma; | |||
1450 | float gammaRed; | |||
1451 | float gammaGreen; | |||
1452 | float gammaBlue; | |||
1453 | ||||
1454 | if (!(output->changes & changes_gamma)) | |||
1455 | continue; | |||
1456 | ||||
1457 | if (!output->crtc_info) { | |||
1458 | fatal("Need crtc to set gamma on.\n"); | |||
1459 | continue; | |||
1460 | } | |||
1461 | ||||
1462 | crtc = output->crtc_info; | |||
1463 | ||||
1464 | size = XRRGetCrtcGammaSize(dpy, crtc->crtc.xid); | |||
1465 | ||||
1466 | if (!size) { | |||
1467 | fatal("Gamma size is 0.\n"); | |||
1468 | continue; | |||
1469 | } | |||
1470 | ||||
1471 | /* | |||
1472 | * The gamma-correction lookup table managed through XRR[GS]etCrtcGamma | |||
1473 | * is 2^n in size, where 'n' is the number of significant bits in | |||
1474 | * the X Color. Because an X Color is 16 bits, size cannot be larger | |||
1475 | * than 2^16. | |||
1476 | */ | |||
1477 | if (size > 65536) { | |||
1478 | fatal("Gamma correction table is impossibly large.\n"); | |||
1479 | continue; | |||
1480 | } | |||
1481 | ||||
1482 | crtc_gamma = XRRAllocGamma(size); | |||
1483 | if (!crtc_gamma) { | |||
1484 | fatal("Gamma allocation failed.\n"); | |||
1485 | continue; | |||
1486 | } | |||
1487 | ||||
1488 | if (output->gamma.red == 0.0) | |||
1489 | output->gamma.red = 1.0; | |||
1490 | if (output->gamma.green == 0.0) | |||
1491 | output->gamma.green = 1.0; | |||
1492 | if (output->gamma.blue == 0.0) | |||
1493 | output->gamma.blue = 1.0; | |||
1494 | ||||
1495 | gammaRed = 1.0 / output->gamma.red; | |||
1496 | gammaGreen = 1.0 / output->gamma.green; | |||
1497 | gammaBlue = 1.0 / output->gamma.blue; | |||
1498 | ||||
1499 | for (i = 0; i < size; i++) { | |||
1500 | if (gammaRed == 1.0 && output->brightness == 1.0) | |||
1501 | crtc_gamma->red[i] = (double)i / (double)(size - 1) * 65535.0; | |||
1502 | else | |||
1503 | crtc_gamma->red[i] = dmin(pow((double)i/(double)(size - 1), | |||
1504 | gammaRed) * output->brightness, | |||
1505 | 1.0) * 65535.0; | |||
1506 | ||||
1507 | if (gammaGreen == 1.0 && output->brightness == 1.0) | |||
1508 | crtc_gamma->green[i] = (double)i / (double)(size - 1) * 65535.0; | |||
1509 | else | |||
1510 | crtc_gamma->green[i] = dmin(pow((double)i/(double)(size - 1), | |||
1511 | gammaGreen) * output->brightness, | |||
1512 | 1.0) * 65535.0; | |||
1513 | ||||
1514 | if (gammaBlue == 1.0 && output->brightness == 1.0) | |||
1515 | crtc_gamma->blue[i] = (double)i / (double)(size - 1) * 65535.0; | |||
1516 | else | |||
1517 | crtc_gamma->blue[i] = dmin(pow((double)i/(double)(size - 1), | |||
1518 | gammaBlue) * output->brightness, | |||
1519 | 1.0) * 65535.0; | |||
1520 | } | |||
1521 | ||||
1522 | XRRSetCrtcGamma(dpy, crtc->crtc.xid, crtc_gamma); | |||
1523 | ||||
1524 | free(crtc_gamma); | |||
1525 | } | |||
1526 | } | |||
1527 | ||||
1528 | static void | |||
1529 | set_primary(void) | |||
1530 | { | |||
1531 | output_t *output; | |||
1532 | ||||
1533 | if (no_primary) { | |||
1534 | XRRSetOutputPrimary(dpy, root, None0L); | |||
1535 | } else { | |||
1536 | for (output = all_outputs; output; output = output->next) { | |||
1537 | if (!(output->changes & changes_primary)) | |||
1538 | continue; | |||
1539 | if (output->primary) | |||
1540 | XRRSetOutputPrimary(dpy, root, output->output.xid); | |||
1541 | } | |||
1542 | } | |||
1543 | } | |||
1544 | ||||
1545 | static Statusint | |||
1546 | crtc_disable (crtc_t *crtc) | |||
1547 | { | |||
1548 | if (verbose) | |||
1549 | printf ("crtc %d: disable\n", crtc->crtc.index); | |||
1550 | ||||
1551 | if (dryrun) | |||
1552 | return RRSetConfigSuccess0; | |||
1553 | return XRRSetCrtcConfig (dpy, res, crtc->crtc.xid, CurrentTime0L, | |||
1554 | 0, 0, None0L, RR_Rotate_01, NULL((void*)0), 0); | |||
1555 | } | |||
1556 | ||||
1557 | static void | |||
1558 | crtc_set_transform (crtc_t *crtc, transform_t *transform) | |||
1559 | { | |||
1560 | int major, minor; | |||
1561 | ||||
1562 | XRRQueryVersion (dpy, &major, &minor); | |||
1563 | if (major > 1 || (major == 1 && minor >= 3)) | |||
1564 | XRRSetCrtcTransform (dpy, crtc->crtc.xid, | |||
1565 | &transform->transform, | |||
1566 | transform->filter, | |||
1567 | transform->params, | |||
1568 | transform->nparams); | |||
1569 | } | |||
1570 | ||||
1571 | static Statusint | |||
1572 | crtc_revert (crtc_t *crtc) | |||
1573 | { | |||
1574 | XRRCrtcInfo *crtc_info = crtc->crtc_info; | |||
1575 | ||||
1576 | if (verbose) | |||
1577 | printf ("crtc %d: revert\n", crtc->crtc.index); | |||
1578 | ||||
1579 | if (dryrun) | |||
1580 | return RRSetConfigSuccess0; | |||
1581 | ||||
1582 | if (!equal_transform (&crtc->current_transform, &crtc->pending_transform)) | |||
1583 | crtc_set_transform (crtc, &crtc->current_transform); | |||
1584 | return XRRSetCrtcConfig (dpy, res, crtc->crtc.xid, CurrentTime0L, | |||
1585 | crtc_info->x, crtc_info->y, | |||
1586 | crtc_info->mode, crtc_info->rotation, | |||
1587 | crtc_info->outputs, crtc_info->noutput); | |||
1588 | } | |||
1589 | ||||
1590 | static Statusint | |||
1591 | crtc_apply (crtc_t *crtc) | |||
1592 | { | |||
1593 | RROutput *rr_outputs; | |||
1594 | int o; | |||
1595 | Statusint s; | |||
1596 | RRMode mode = None0L; | |||
1597 | ||||
1598 | if (!crtc->changing || !crtc->mode_info) | |||
1599 | return RRSetConfigSuccess0; | |||
1600 | ||||
1601 | rr_outputs = calloc (crtc->noutput, sizeof (RROutput)); | |||
1602 | if (!rr_outputs) | |||
1603 | return BadAlloc11; | |||
1604 | for (o = 0; o < crtc->noutput; o++) | |||
1605 | rr_outputs[o] = crtc->outputs[o]->output.xid; | |||
1606 | mode = crtc->mode_info->id; | |||
1607 | if (verbose) { | |||
1608 | printf ("crtc %d: %12s %6.2f +%d+%d", crtc->crtc.index, | |||
1609 | crtc->mode_info->name, mode_refresh (crtc->mode_info), | |||
1610 | crtc->x, crtc->y); | |||
1611 | for (o = 0; o < crtc->noutput; o++) | |||
1612 | printf (" \"%s\"", crtc->outputs[o]->output.string); | |||
1613 | printf ("\n"); | |||
1614 | } | |||
1615 | ||||
1616 | if (dryrun) | |||
1617 | s = RRSetConfigSuccess0; | |||
1618 | else | |||
1619 | { | |||
1620 | if (!equal_transform (&crtc->current_transform, &crtc->pending_transform)) | |||
1621 | crtc_set_transform (crtc, &crtc->pending_transform); | |||
1622 | s = XRRSetCrtcConfig (dpy, res, crtc->crtc.xid, CurrentTime0L, | |||
1623 | crtc->x, crtc->y, mode, crtc->rotation, | |||
1624 | rr_outputs, crtc->noutput); | |||
1625 | if (s == RRSetConfigSuccess0 && crtc->panning_info) { | |||
1626 | if (has_1_3) | |||
1627 | s = XRRSetPanning (dpy, res, crtc->crtc.xid, crtc->panning_info); | |||
1628 | else | |||
1629 | fatal ("panning needs RandR 1.3\n"); | |||
1630 | } | |||
1631 | } | |||
1632 | free (rr_outputs); | |||
1633 | return s; | |||
1634 | } | |||
1635 | ||||
1636 | static void | |||
1637 | screen_revert (void) | |||
1638 | { | |||
1639 | if (verbose) | |||
1640 | printf ("screen %d: revert\n", screen); | |||
1641 | ||||
1642 | if (dryrun) | |||
1643 | return; | |||
1644 | XRRSetScreenSize (dpy, root, | |||
1645 | DisplayWidth (dpy, screen)((&((_XPrivDisplay)(dpy))->screens[screen])->width), | |||
1646 | DisplayHeight (dpy, screen)((&((_XPrivDisplay)(dpy))->screens[screen])->height ), | |||
1647 | DisplayWidthMM (dpy, screen)((&((_XPrivDisplay)(dpy))->screens[screen])->mwidth ), | |||
1648 | DisplayHeightMM (dpy, screen)((&((_XPrivDisplay)(dpy))->screens[screen])->mheight )); | |||
1649 | } | |||
1650 | ||||
1651 | static void | |||
1652 | screen_apply (void) | |||
1653 | { | |||
1654 | if (fb_width == DisplayWidth (dpy, screen)((&((_XPrivDisplay)(dpy))->screens[screen])->width) && | |||
1655 | fb_height == DisplayHeight (dpy, screen)((&((_XPrivDisplay)(dpy))->screens[screen])->height ) && | |||
1656 | fb_width_mm == DisplayWidthMM (dpy, screen)((&((_XPrivDisplay)(dpy))->screens[screen])->mwidth ) && | |||
1657 | fb_height_mm == DisplayHeightMM (dpy, screen)((&((_XPrivDisplay)(dpy))->screens[screen])->mheight )) | |||
1658 | { | |||
1659 | return; | |||
1660 | } | |||
1661 | if (verbose) | |||
1662 | printf ("screen %d: %dx%d %dx%d mm %6.2fdpi\n", screen, | |||
1663 | fb_width, fb_height, fb_width_mm, fb_height_mm, dpi); | |||
1664 | if (dryrun) | |||
1665 | return; | |||
1666 | XRRSetScreenSize (dpy, root, fb_width, fb_height, | |||
1667 | fb_width_mm, fb_height_mm); | |||
1668 | } | |||
1669 | ||||
1670 | static void | |||
1671 | revert (void) | |||
1672 | { | |||
1673 | int c; | |||
1674 | ||||
1675 | /* first disable all crtcs */ | |||
1676 | for (c = 0; c < res->ncrtc; c++) | |||
1677 | crtc_disable (&crtcs[c]); | |||
1678 | /* next reset screen size */ | |||
1679 | screen_revert (); | |||
1680 | /* now restore all crtcs */ | |||
1681 | for (c = 0; c < res->ncrtc; c++) | |||
1682 | crtc_revert (&crtcs[c]); | |||
1683 | } | |||
1684 | ||||
1685 | /* | |||
1686 | * uh-oh, something bad happened in the middle of changing | |||
1687 | * the configuration. Revert to the previous configuration | |||
1688 | * and bail | |||
1689 | */ | |||
1690 | static void _X_NORETURN__attribute((noreturn)) | |||
1691 | panic (Statusint s, crtc_t *crtc) | |||
1692 | { | |||
1693 | int c = crtc->crtc.index; | |||
1694 | const char *message; | |||
1695 | ||||
1696 | switch (s) { | |||
1697 | case RRSetConfigSuccess0: message = "succeeded"; break; | |||
1698 | case BadAlloc11: message = "out of memory"; break; | |||
1699 | case RRSetConfigFailed3: message = "failed"; break; | |||
1700 | case RRSetConfigInvalidConfigTime1: message = "invalid config time"; break; | |||
1701 | case RRSetConfigInvalidTime2: message = "invalid time"; break; | |||
1702 | default: message = "unknown failure"; break; | |||
1703 | } | |||
1704 | ||||
1705 | fprintf (stderr__stderrp, "%s: Configure crtc %d %s\n", program_name, c, message); | |||
1706 | revert (); | |||
1707 | exit (1); | |||
1708 | } | |||
1709 | ||||
1710 | static void | |||
1711 | apply (void) | |||
1712 | { | |||
1713 | Statusint s; | |||
1714 | int c; | |||
1715 | ||||
1716 | /* | |||
1717 | * Hold the server grabbed while messing with | |||
1718 | * the screen so that apps which notice the resize | |||
1719 | * event and ask for xinerama information from the server | |||
1720 | * receive up-to-date information | |||
1721 | */ | |||
1722 | if (grab_server) | |||
1723 | XGrabServer (dpy); | |||
1724 | ||||
1725 | /* | |||
1726 | * Turn off any crtcs which are to be disabled or which are | |||
1727 | * larger than the target size | |||
1728 | */ | |||
1729 | for (c = 0; c < res->ncrtc; c++) | |||
1730 | { | |||
1731 | crtc_t *crtc = &crtcs[c]; | |||
1732 | XRRCrtcInfo *crtc_info = crtc->crtc_info; | |||
1733 | ||||
1734 | /* if this crtc is already disabled, skip it */ | |||
1735 | if (crtc_info->mode == None0L) | |||
1736 | continue; | |||
1737 | ||||
1738 | /* | |||
1739 | * If this crtc is to be left enabled, make | |||
1740 | * sure the old size fits then new screen | |||
1741 | */ | |||
1742 | if (crtc->mode_info) | |||
1743 | { | |||
1744 | XRRModeInfo *old_mode = find_mode_by_xid (crtc_info->mode); | |||
1745 | int x, y, w, h; | |||
1746 | box_t bounds; | |||
1747 | ||||
1748 | if (!old_mode) | |||
1749 | panic (RRSetConfigFailed3, crtc); | |||
1750 | ||||
1751 | /* old position and size information */ | |||
1752 | mode_geometry (old_mode, crtc_info->rotation, | |||
1753 | &crtc->current_transform.transform, | |||
1754 | &bounds); | |||
1755 | ||||
1756 | x = crtc_info->x + bounds.x1; | |||
1757 | y = crtc_info->y + bounds.y1; | |||
1758 | w = bounds.x2 - bounds.x1; | |||
1759 | h = bounds.y2 - bounds.y1; | |||
1760 | ||||
1761 | /* if it fits, skip it */ | |||
1762 | if (x + w <= fb_width && y + h <= fb_height) | |||
1763 | continue; | |||
1764 | crtc->changing = True1; | |||
1765 | } | |||
1766 | s = crtc_disable (crtc); | |||
1767 | if (s != RRSetConfigSuccess0) | |||
1768 | panic (s, crtc); | |||
1769 | } | |||
1770 | ||||
1771 | /* | |||
1772 | * Set the screen size | |||
1773 | */ | |||
1774 | screen_apply (); | |||
1775 | ||||
1776 | /* | |||
1777 | * Set crtcs | |||
1778 | */ | |||
1779 | ||||
1780 | for (c = 0; c < res->ncrtc; c++) | |||
1781 | { | |||
1782 | crtc_t *crtc = &crtcs[c]; | |||
1783 | ||||
1784 | s = crtc_apply (crtc); | |||
1785 | if (s != RRSetConfigSuccess0) | |||
1786 | panic (s, crtc); | |||
1787 | } | |||
1788 | ||||
1789 | set_primary (); | |||
1790 | ||||
1791 | /* | |||
1792 | * Release the server grab and let all clients | |||
1793 | * respond to the updated state | |||
1794 | */ | |||
1795 | if (grab_server) | |||
1796 | XUngrabServer (dpy); | |||
1797 | } | |||
1798 | ||||
1799 | /* | |||
1800 | * Use current output state to complete the output list | |||
1801 | */ | |||
1802 | static void | |||
1803 | get_outputs (void) | |||
1804 | { | |||
1805 | int o; | |||
1806 | output_t *q; | |||
1807 | ||||
1808 | for (o = 0; o < res->noutput; o++) | |||
1809 | { | |||
1810 | XRROutputInfo *output_info = XRRGetOutputInfo (dpy, res, res->outputs[o]); | |||
1811 | output_t *output; | |||
1812 | name_t output_name; | |||
1813 | if (!output_info) fatal ("could not get output 0x%lx information\n", res->outputs[o]); | |||
1814 | set_name_xid (&output_name, res->outputs[o]); | |||
1815 | set_name_index (&output_name, o); | |||
1816 | set_name_string (&output_name, output_info->name); | |||
1817 | output = find_output (&output_name); | |||
1818 | if (!output) | |||
1819 | { | |||
1820 | output = add_output (); | |||
1821 | set_name_all (&output->output, &output_name); | |||
1822 | /* | |||
1823 | * When global --automatic mode is set, turn on connected but off | |||
1824 | * outputs, turn off disconnected but on outputs | |||
1825 | */ | |||
1826 | if (automatic) | |||
1827 | { | |||
1828 | switch (output_info->connection) { | |||
1829 | case RR_Connected0: | |||
1830 | if (!output_info->crtc) { | |||
1831 | output->changes |= changes_automatic; | |||
1832 | output->automatic = True1; | |||
1833 | } | |||
1834 | break; | |||
1835 | case RR_Disconnected1: | |||
1836 | if (output_info->crtc) | |||
1837 | { | |||
1838 | output->changes |= changes_automatic; | |||
1839 | output->automatic = True1; | |||
1840 | } | |||
1841 | break; | |||
1842 | } | |||
1843 | } | |||
1844 | } | |||
1845 | output->found = True1; | |||
1846 | ||||
1847 | /* | |||
1848 | * Automatic mode -- track connection state and enable/disable outputs | |||
1849 | * as necessary | |||
1850 | */ | |||
1851 | if (output->automatic) | |||
1852 | { | |||
1853 | switch (output_info->connection) { | |||
1854 | case RR_Connected0: | |||
1855 | case RR_UnknownConnection2: | |||
1856 | if ((!(output->changes & changes_mode))) | |||
1857 | { | |||
1858 | set_name_preferred (&output->mode); | |||
1859 | output->changes |= changes_mode; | |||
1860 | } | |||
1861 | break; | |||
1862 | case RR_Disconnected1: | |||
1863 | if ((!(output->changes & changes_mode))) | |||
1864 | { | |||
1865 | set_name_xid (&output->mode, None0L); | |||
1866 | set_name_xid (&output->crtc, None0L); | |||
1867 | output->changes |= changes_mode; | |||
1868 | output->changes |= changes_crtc; | |||
1869 | } | |||
1870 | break; | |||
1871 | } | |||
1872 | } | |||
1873 | ||||
1874 | set_output_info (output, res->outputs[o], output_info); | |||
1875 | } | |||
1876 | for (q = all_outputs; q; q = q->next) | |||
1877 | { | |||
1878 | if (!q->found) | |||
1879 | { | |||
1880 | fprintf(stderr__stderrp, "warning: output %s not found; ignoring\n", | |||
1881 | q->output.string); | |||
1882 | } | |||
1883 | } | |||
1884 | } | |||
1885 | ||||
1886 | static void | |||
1887 | mark_changing_crtcs (void) | |||
1888 | { | |||
1889 | int c; | |||
1890 | ||||
1891 | for (c = 0; c < num_crtcs; c++) | |||
1892 | { | |||
1893 | crtc_t *crtc = &crtcs[c]; | |||
1894 | int o; | |||
1895 | output_t *output; | |||
1896 | ||||
1897 | /* walk old output list (to catch disables) */ | |||
1898 | for (o = 0; o < crtc->crtc_info->noutput; o++) | |||
1899 | { | |||
1900 | output = find_output_by_xid (crtc->crtc_info->outputs[o]); | |||
1901 | if (!output) fatal ("cannot find output 0x%lx\n", | |||
1902 | crtc->crtc_info->outputs[o]); | |||
1903 | if (output->changes) | |||
1904 | crtc->changing = True1; | |||
1905 | } | |||
1906 | /* walk new output list */ | |||
1907 | for (o = 0; o < crtc->noutput; o++) | |||
1908 | { | |||
1909 | output = crtc->outputs[o]; | |||
1910 | if (output->changes) | |||
1911 | crtc->changing = True1; | |||
1912 | } | |||
1913 | } | |||
1914 | } | |||
1915 | ||||
1916 | /* | |||
1917 | * Test whether 'crtc' can be used for 'output' | |||
1918 | */ | |||
1919 | static Boolint | |||
1920 | check_crtc_for_output (crtc_t *crtc, output_t *output) | |||
1921 | { | |||
1922 | int c; | |||
1923 | int l; | |||
1924 | output_t *other; | |||
1925 | ||||
1926 | for (c = 0; c < output->output_info->ncrtc; c++) | |||
1927 | if (output->output_info->crtcs[c] == crtc->crtc.xid) | |||
1928 | break; | |||
1929 | if (c == output->output_info->ncrtc) | |||
1930 | return False0; | |||
1931 | for (other = all_outputs; other; other = other->next) | |||
1932 | { | |||
1933 | if (other == output) | |||
1934 | continue; | |||
1935 | ||||
1936 | if (other->mode_info == NULL((void*)0)) | |||
1937 | continue; | |||
1938 | ||||
1939 | if (other->crtc_info != crtc) | |||
1940 | continue; | |||
1941 | ||||
1942 | /* see if the output connected to the crtc can clone to this output */ | |||
1943 | for (l = 0; l < output->output_info->nclone; l++) | |||
1944 | if (output->output_info->clones[l] == other->output.xid) | |||
1945 | break; | |||
1946 | /* not on the list, can't clone */ | |||
1947 | if (l == output->output_info->nclone) | |||
1948 | return False0; | |||
1949 | } | |||
1950 | ||||
1951 | if (crtc->noutput) | |||
1952 | { | |||
1953 | /* make sure the state matches */ | |||
1954 | if (crtc->mode_info != output->mode_info) | |||
1955 | return False0; | |||
1956 | if (crtc->x != output->x) | |||
1957 | return False0; | |||
1958 | if (crtc->y != output->y) | |||
1959 | return False0; | |||
1960 | if (crtc->rotation != output->rotation) | |||
1961 | return False0; | |||
1962 | if (!equal_transform (&crtc->current_transform, &output->transform)) | |||
1963 | return False0; | |||
1964 | } | |||
1965 | else if (crtc->crtc_info->noutput) | |||
1966 | { | |||
1967 | /* make sure the state matches the already used state */ | |||
1968 | XRRModeInfo *mode = find_mode_by_xid (crtc->crtc_info->mode); | |||
1969 | ||||
1970 | if (mode != output->mode_info) | |||
1971 | return False0; | |||
1972 | if (crtc->crtc_info->x != output->x) | |||
1973 | return False0; | |||
1974 | if (crtc->crtc_info->y != output->y) | |||
1975 | return False0; | |||
1976 | if (crtc->crtc_info->rotation != output->rotation) | |||
1977 | return False0; | |||
1978 | } | |||
1979 | return True1; | |||
1980 | } | |||
1981 | ||||
1982 | static crtc_t * | |||
1983 | find_crtc_for_output (output_t *output) | |||
1984 | { | |||
1985 | int c; | |||
1986 | ||||
1987 | for (c = 0; c < output->output_info->ncrtc; c++) | |||
1988 | { | |||
1989 | crtc_t *crtc; | |||
1990 | ||||
1991 | crtc = find_crtc_by_xid (output->output_info->crtcs[c]); | |||
1992 | if (!crtc) fatal ("cannot find crtc 0x%lx\n", output->output_info->crtcs[c]); | |||
1993 | ||||
1994 | if (check_crtc_for_output (crtc, output)) | |||
1995 | return crtc; | |||
1996 | } | |||
1997 | return NULL((void*)0); | |||
1998 | } | |||
1999 | ||||
2000 | static void | |||
2001 | set_positions (void) | |||
2002 | { | |||
2003 | output_t *output; | |||
2004 | Boolint keep_going; | |||
2005 | Boolint any_set; | |||
2006 | int min_x, min_y; | |||
2007 | ||||
2008 | for (;;) | |||
2009 | { | |||
2010 | any_set = False0; | |||
2011 | keep_going = False0; | |||
2012 | for (output = all_outputs; output; output = output->next) | |||
2013 | { | |||
2014 | output_t *relation; | |||
2015 | name_t relation_name; | |||
2016 | ||||
2017 | if (!(output->changes & changes_relation)) continue; | |||
2018 | ||||
2019 | if (output->mode_info == NULL((void*)0)) continue; | |||
2020 | ||||
2021 | init_name (&relation_name); | |||
2022 | set_name_string (&relation_name, output->relative_to); | |||
2023 | relation = find_output (&relation_name); | |||
2024 | if (!relation) fatal ("cannot find output \"%s\"\n", output->relative_to); | |||
2025 | ||||
2026 | if (relation->mode_info == NULL((void*)0)) | |||
2027 | { | |||
2028 | output->x = 0; | |||
2029 | output->y = 0; | |||
2030 | output->changes |= changes_position; | |||
2031 | any_set = True1; | |||
2032 | continue; | |||
2033 | } | |||
2034 | /* | |||
2035 | * Make sure the dependent object has been set in place | |||
2036 | */ | |||
2037 | if ((relation->changes & changes_relation) && | |||
2038 | !(relation->changes & changes_position)) | |||
2039 | { | |||
2040 | keep_going = True1; | |||
2041 | continue; | |||
2042 | } | |||
2043 | ||||
2044 | switch (output->relation) { | |||
2045 | case relation_left_of: | |||
2046 | output->y = relation->y; | |||
2047 | output->x = relation->x - mode_width (output->mode_info, output->rotation); | |||
2048 | break; | |||
2049 | case relation_right_of: | |||
2050 | output->y = relation->y; | |||
2051 | output->x = relation->x + mode_width (relation->mode_info, relation->rotation); | |||
2052 | break; | |||
2053 | case relation_above: | |||
2054 | output->x = relation->x; | |||
2055 | output->y = relation->y - mode_height (output->mode_info, output->rotation); | |||
2056 | break; | |||
2057 | case relation_below: | |||
2058 | output->x = relation->x; | |||
2059 | output->y = relation->y + mode_height (relation->mode_info, relation->rotation); | |||
2060 | break; | |||
2061 | case relation_same_as: | |||
2062 | output->x = relation->x; | |||
2063 | output->y = relation->y; | |||
2064 | } | |||
2065 | output->changes |= changes_position; | |||
2066 | any_set = True1; | |||
2067 | } | |||
2068 | if (!keep_going) | |||
2069 | break; | |||
2070 | if (!any_set) | |||
2071 | fatal ("loop in relative position specifications\n"); | |||
2072 | } | |||
2073 | ||||
2074 | /* | |||
2075 | * Now normalize positions so the upper left corner of all outputs is at 0,0 | |||
2076 | */ | |||
2077 | min_x = 32768; | |||
2078 | min_y = 32768; | |||
2079 | for (output = all_outputs; output; output = output->next) | |||
2080 | { | |||
2081 | if (output->mode_info == NULL((void*)0)) continue; | |||
2082 | ||||
2083 | if (output->x < min_x) min_x = output->x; | |||
2084 | if (output->y < min_y) min_y = output->y; | |||
2085 | } | |||
2086 | if (min_x || min_y) | |||
2087 | { | |||
2088 | /* move all outputs */ | |||
2089 | for (output = all_outputs; output; output = output->next) | |||
2090 | { | |||
2091 | if (output->mode_info == NULL((void*)0)) continue; | |||
2092 | ||||
2093 | output->x -= min_x; | |||
2094 | output->y -= min_y; | |||
2095 | output->changes |= changes_position; | |||
2096 | } | |||
2097 | } | |||
2098 | } | |||
2099 | ||||
2100 | static void | |||
2101 | set_screen_size (void) | |||
2102 | { | |||
2103 | output_t *output; | |||
2104 | Boolint fb_specified = fb_width != 0 && fb_height != 0; | |||
2105 | ||||
2106 | for (output = all_outputs; output; output = output->next) | |||
2107 | { | |||
2108 | XRRModeInfo *mode_info = output->mode_info; | |||
2109 | int x, y, w, h; | |||
2110 | box_t bounds; | |||
2111 | ||||
2112 | if (!mode_info) continue; | |||
2113 | ||||
2114 | mode_geometry (mode_info, output->rotation, | |||
2115 | &output->transform.transform, | |||
2116 | &bounds); | |||
2117 | x = output->x + bounds.x1; | |||
2118 | y = output->y + bounds.y1; | |||
2119 | w = bounds.x2 - bounds.x1; | |||
2120 | h = bounds.y2 - bounds.y1; | |||
2121 | /* make sure output fits in specified size */ | |||
2122 | if (fb_specified) | |||
2123 | { | |||
2124 | if (x + w > fb_width || y + h > fb_height) | |||
2125 | warning ("specified screen %dx%d not large enough for output %s (%dx%d+%d+%d)\n", | |||
2126 | fb_width, fb_height, output->output.string, w, h, x, y); | |||
2127 | } | |||
2128 | /* fit fb to output */ | |||
2129 | else | |||
2130 | { | |||
2131 | XRRPanning *pan; | |||
2132 | if (x + w > fb_width) | |||
2133 | fb_width = x + w; | |||
2134 | if (y + h > fb_height) | |||
2135 | fb_height = y + h; | |||
2136 | if (output->changes & changes_panning) | |||
2137 | pan = &output->panning; | |||
2138 | else | |||
2139 | pan = output->crtc_info ? output->crtc_info->panning_info : NULL((void*)0); | |||
2140 | if (pan && pan->left + pan->width > fb_width) | |||
2141 | fb_width = pan->left + pan->width; | |||
2142 | if (pan && pan->top + pan->height > fb_height) | |||
2143 | fb_height = pan->top + pan->height; | |||
2144 | } | |||
2145 | } | |||
2146 | ||||
2147 | if (fb_width > maxWidth || fb_height > maxHeight) | |||
2148 | fatal ("screen cannot be larger than %dx%d (desired size %dx%d)\n", | |||
2149 | maxWidth, maxHeight, fb_width, fb_height); | |||
2150 | if (fb_specified) | |||
2151 | { | |||
2152 | if (fb_width < minWidth || fb_height < minHeight) | |||
2153 | fatal ("screen must be at least %dx%d\n", minWidth, minHeight); | |||
2154 | } | |||
2155 | else | |||
2156 | { | |||
2157 | if (fb_width < minWidth) fb_width = minWidth; | |||
2158 | if (fb_height < minHeight) fb_height = minHeight; | |||
2159 | } | |||
2160 | } | |||
2161 | ||||
2162 | ||||
2163 | static void | |||
2164 | disable_outputs (output_t *outputs) | |||
2165 | { | |||
2166 | while (outputs) | |||
2167 | { | |||
2168 | outputs->crtc_info = NULL((void*)0); | |||
2169 | outputs = outputs->next; | |||
2170 | } | |||
2171 | } | |||
2172 | ||||
2173 | /* | |||
2174 | * find the best mapping from output to crtc available | |||
2175 | */ | |||
2176 | static int | |||
2177 | pick_crtcs_score (output_t *outputs) | |||
2178 | { | |||
2179 | output_t *output; | |||
2180 | int best_score; | |||
2181 | int my_score; | |||
2182 | int score; | |||
2183 | crtc_t *best_crtc; | |||
2184 | int c; | |||
2185 | ||||
2186 | if (!outputs) | |||
2187 | return 0; | |||
2188 | ||||
2189 | output = outputs; | |||
2190 | outputs = outputs->next; | |||
2191 | /* | |||
2192 | * Score with this output disabled | |||
2193 | */ | |||
2194 | output->crtc_info = NULL((void*)0); | |||
2195 | best_score = pick_crtcs_score (outputs); | |||
2196 | if (output->mode_info == NULL((void*)0)) | |||
2197 | return best_score; | |||
2198 | ||||
2199 | best_crtc = NULL((void*)0); | |||
2200 | /* | |||
2201 | * Now score with this output any valid crtc | |||
2202 | */ | |||
2203 | for (c = 0; c < output->output_info->ncrtc; c++) | |||
2204 | { | |||
2205 | crtc_t *crtc; | |||
2206 | ||||
2207 | crtc = find_crtc_by_xid (output->output_info->crtcs[c]); | |||
2208 | if (!crtc) | |||
2209 | fatal ("cannot find crtc 0x%lx\n", output->output_info->crtcs[c]); | |||
2210 | ||||
2211 | /* reset crtc allocation for following outputs */ | |||
2212 | disable_outputs (outputs); | |||
2213 | if (!check_crtc_for_output (crtc, output)) | |||
2214 | continue; | |||
2215 | ||||
2216 | my_score = 1000; | |||
2217 | /* slight preference for existing connections */ | |||
2218 | if (crtc == output->current_crtc_info) | |||
2219 | my_score++; | |||
2220 | ||||
2221 | output->crtc_info = crtc; | |||
2222 | score = my_score + pick_crtcs_score (outputs); | |||
2223 | if (score > best_score) | |||
2224 | { | |||
2225 | best_crtc = crtc; | |||
2226 | best_score = score; | |||
2227 | } | |||
2228 | } | |||
2229 | if (output->crtc_info != best_crtc) | |||
2230 | output->crtc_info = best_crtc; | |||
2231 | /* | |||
2232 | * Reset other outputs based on this one using the best crtc | |||
2233 | */ | |||
2234 | (void) pick_crtcs_score (outputs); | |||
2235 | ||||
2236 | return best_score; | |||
2237 | } | |||
2238 | ||||
2239 | /* | |||
2240 | * Pick crtcs for any changing outputs that don't have one | |||
2241 | */ | |||
2242 | static void | |||
2243 | pick_crtcs (void) | |||
2244 | { | |||
2245 | output_t *output; | |||
2246 | int saved_crtc_noutput[num_crtcs]; | |||
2247 | int n; | |||
2248 | ||||
2249 | /* | |||
2250 | * First try to match up newly enabled outputs with spare crtcs | |||
2251 | */ | |||
2252 | for (output = all_outputs; output; output = output->next) | |||
| ||||
2253 | { | |||
2254 | if (output->changes && output->mode_info) | |||
2255 | { | |||
2256 | if (output->crtc_info) { | |||
2257 | if (output->crtc_info->crtc_info->noutput > 0 && | |||
2258 | (output->crtc_info->crtc_info->noutput > 1 || | |||
2259 | output != find_output_by_xid (output->crtc_info->crtc_info->outputs[0]))) | |||
2260 | break; | |||
2261 | } else { | |||
2262 | output->crtc_info = find_crtc_for_output (output); | |||
2263 | if (!output->crtc_info) | |||
2264 | break; | |||
2265 | } | |||
2266 | } | |||
2267 | } | |||
2268 | /* | |||
2269 | * Everyone is happy | |||
2270 | */ | |||
2271 | if (!output) | |||
2272 | return; | |||
2273 | /* | |||
2274 | * When the simple way fails, see if there is a way | |||
2275 | * to swap crtcs around and make things work | |||
2276 | */ | |||
2277 | for (output = all_outputs; output; output = output->next) | |||
2278 | output->current_crtc_info = output->crtc_info; | |||
2279 | ||||
2280 | /* Mark all CRTC as currently unused */ | |||
2281 | for (n = 0; n < num_crtcs; n++) { | |||
2282 | saved_crtc_noutput[n] = crtcs[n].crtc_info->noutput; | |||
2283 | crtcs[n].crtc_info->noutput = 0; | |||
2284 | } | |||
2285 | ||||
2286 | pick_crtcs_score (all_outputs); | |||
2287 | ||||
2288 | for (n = 0; n < num_crtcs; n++) | |||
2289 | crtcs[n].crtc_info->noutput = saved_crtc_noutput[n]; | |||
| ||||
2290 | ||||
2291 | for (output = all_outputs; output; output = output->next) | |||
2292 | { | |||
2293 | if (output->mode_info && !output->crtc_info) | |||
2294 | fatal ("cannot find crtc for output %s\n", output->output.string); | |||
2295 | if (!output->changes && output->crtc_info != output->current_crtc_info) | |||
2296 | output->changes |= changes_crtc; | |||
2297 | } | |||
2298 | } | |||
2299 | ||||
2300 | static int | |||
2301 | check_strtol(char *s) | |||
2302 | { | |||
2303 | char *endptr; | |||
2304 | int result = strtol(s, &endptr, 10); | |||
2305 | if (s == endptr) | |||
2306 | argerr ("failed to parse '%s' as a number\n", s); | |||
2307 | return result; | |||
2308 | } | |||
2309 | ||||
2310 | static double | |||
2311 | check_strtod(char *s) | |||
2312 | { | |||
2313 | char *endptr; | |||
2314 | double result = strtod(s, &endptr); | |||
2315 | if (s == endptr) | |||
2316 | argerr ("failed to parse '%s' as a number\n", s); | |||
2317 | return result; | |||
2318 | } | |||
2319 | ||||
2320 | ||||
2321 | static void * | |||
2322 | property_values_from_string(const char *str, const Atom type, const int format, | |||
2323 | int *returned_nitems) | |||
2324 | { | |||
2325 | char *token, *tmp; | |||
2326 | void *returned_bytes = NULL((void*)0); | |||
2327 | int nitems = 0, bytes_per_item; | |||
2328 | ||||
2329 | if (type != XA_INTEGER((Atom) 19) && type != XA_CARDINAL((Atom) 6)) | |||
2330 | return NULL((void*)0); | |||
2331 | ||||
2332 | /* compute memory needed for Xlib datatype (sigh) */ | |||
2333 | switch (format) { | |||
2334 | case 8: | |||
2335 | bytes_per_item = sizeof(char); | |||
2336 | break; | |||
2337 | case 16: | |||
2338 | bytes_per_item = sizeof(short); | |||
2339 | break; | |||
2340 | case 32: | |||
2341 | bytes_per_item = sizeof(long); | |||
2342 | break; | |||
2343 | default: | |||
2344 | return NULL((void*)0); | |||
2345 | } | |||
2346 | ||||
2347 | tmp = strdup (str); | |||
2348 | ||||
2349 | for (token = strtok (tmp, ","); token; token = strtok (NULL((void*)0), ",")) | |||
2350 | { | |||
2351 | char *endptr; | |||
2352 | long int val = strtol (token, &endptr, 0); | |||
2353 | ||||
2354 | if (token == endptr || *endptr != '\0') | |||
2355 | { | |||
2356 | argerr ("failed to parse '%s' as a number\n", token); | |||
2357 | } | |||
2358 | ||||
2359 | returned_bytes = realloc (returned_bytes, (nitems + 1) * bytes_per_item); | |||
2360 | ||||
2361 | if (type == XA_INTEGER((Atom) 19) && format == 8) | |||
2362 | { | |||
2363 | signed char *ptr = returned_bytes; | |||
2364 | ptr[nitems] = (char) val; | |||
2365 | } | |||
2366 | else if (type == XA_INTEGER((Atom) 19) && format == 16) | |||
2367 | { | |||
2368 | short *ptr = returned_bytes; | |||
2369 | ptr[nitems] = (short) val; | |||
2370 | } | |||
2371 | else if (type == XA_INTEGER((Atom) 19) && format == 32) | |||
2372 | { | |||
2373 | long *ptr = returned_bytes; | |||
2374 | ptr[nitems] = (long) val; | |||
2375 | } | |||
2376 | else if (type == XA_CARDINAL((Atom) 6) && format == 8) | |||
2377 | { | |||
2378 | unsigned char *ptr = returned_bytes; | |||
2379 | ptr[nitems] = (unsigned char) val; | |||
2380 | } | |||
2381 | else if (type == XA_CARDINAL((Atom) 6) && format == 16) | |||
2382 | { | |||
2383 | unsigned short *ptr = returned_bytes; | |||
2384 | ptr[nitems] = (unsigned short) val; | |||
2385 | } | |||
2386 | else if (type == XA_CARDINAL((Atom) 6) && format == 32) | |||
2387 | { | |||
2388 | unsigned long *ptr = returned_bytes; | |||
2389 | ptr[nitems] = (unsigned long) val; | |||
2390 | } | |||
2391 | else | |||
2392 | { | |||
2393 | free (tmp); | |||
2394 | free (returned_bytes); | |||
2395 | return NULL((void*)0); | |||
2396 | } | |||
2397 | ||||
2398 | nitems++; | |||
2399 | } | |||
2400 | ||||
2401 | free (tmp); | |||
2402 | ||||
2403 | *returned_nitems = nitems; | |||
2404 | return returned_bytes; | |||
2405 | } | |||
2406 | ||||
2407 | ||||
2408 | static void | |||
2409 | print_output_property_value(int value_format, /* 8, 16, 32 */ | |||
2410 | Atom value_type, /* XA_{ATOM,INTEGER,CARDINAL} */ | |||
2411 | const void *value_bytes) | |||
2412 | { | |||
2413 | if (value_type == XA_ATOM((Atom) 4) && value_format == 32) | |||
2414 | { | |||
2415 | const Atom *val = value_bytes; | |||
2416 | char *str = XGetAtomName (dpy, *val); | |||
2417 | if (str != NULL((void*)0)) | |||
2418 | { | |||
2419 | printf ("%s", str); | |||
2420 | XFree (str); | |||
2421 | return; | |||
2422 | } | |||
2423 | } | |||
2424 | ||||
2425 | if (value_type == XA_INTEGER((Atom) 19)) | |||
2426 | { | |||
2427 | if (value_format == 8) | |||
2428 | { | |||
2429 | const signed char *val = value_bytes; | |||
2430 | printf ("%d", *val); | |||
2431 | return; | |||
2432 | } | |||
2433 | if (value_format == 16) | |||
2434 | { | |||
2435 | const short *val = value_bytes; | |||
2436 | printf ("%d", *val); | |||
2437 | return; | |||
2438 | } | |||
2439 | if (value_format == 32) | |||
2440 | { | |||
2441 | const long *val = value_bytes; | |||
2442 | printf ("%ld", *val); | |||
2443 | return; | |||
2444 | } | |||
2445 | } | |||
2446 | ||||
2447 | if (value_type == XA_CARDINAL((Atom) 6)) | |||
2448 | { | |||
2449 | if (value_format == 8) | |||
2450 | { | |||
2451 | const unsigned char *val = value_bytes; | |||
2452 | printf ("%u", *val); | |||
2453 | return; | |||
2454 | } | |||
2455 | if (value_format == 16) | |||
2456 | { | |||
2457 | const unsigned short *val = value_bytes; | |||
2458 | printf ("%u", *val); | |||
2459 | return; | |||
2460 | } | |||
2461 | if (value_format == 32) | |||
2462 | { | |||
2463 | const unsigned long *val = value_bytes; | |||
2464 | printf ("%lu", *val); | |||
2465 | return; | |||
2466 | } | |||
2467 | } | |||
2468 | ||||
2469 | printf ("?"); | |||
2470 | } | |||
2471 | ||||
2472 | static void | |||
2473 | print_edid(int nitems, const unsigned char *prop) | |||
2474 | { | |||
2475 | int k; | |||
2476 | ||||
2477 | printf ("\n\t\t"); | |||
2478 | ||||
2479 | for (k = 0; k < nitems; k++) | |||
2480 | { | |||
2481 | if (k != 0 && (k % 16) == 0) | |||
2482 | { | |||
2483 | printf ("\n\t\t"); | |||
2484 | } | |||
2485 | ||||
2486 | printf("%02" PRIx8"hh" "x", prop[k]); | |||
2487 | } | |||
2488 | ||||
2489 | printf("\n"); | |||
2490 | } | |||
2491 | ||||
2492 | static void | |||
2493 | print_guid(const unsigned char *prop) | |||
2494 | { | |||
2495 | int k; | |||
2496 | ||||
2497 | printf("{"); | |||
2498 | ||||
2499 | for (k = 0; k < 16; k++) | |||
2500 | { | |||
2501 | printf("%02" PRIX8"hh" "X", prop[k]); | |||
2502 | if (k == 3 || k == 5 || k == 7 || k == 9) | |||
2503 | { | |||
2504 | printf("-"); | |||
2505 | } | |||
2506 | } | |||
2507 | ||||
2508 | printf("}\n"); | |||
2509 | } | |||
2510 | ||||
2511 | static void | |||
2512 | print_output_property(const char *atom_name, | |||
2513 | int value_format, | |||
2514 | Atom value_type, | |||
2515 | int nitems, | |||
2516 | const unsigned char *prop) | |||
2517 | { | |||
2518 | int bytes_per_item; | |||
2519 | int k; | |||
2520 | ||||
2521 | switch (value_format) { | |||
2522 | case 8: | |||
2523 | bytes_per_item = sizeof(char); | |||
2524 | break; | |||
2525 | case 16: | |||
2526 | bytes_per_item = sizeof(short); | |||
2527 | break; | |||
2528 | case 32: | |||
2529 | bytes_per_item = sizeof(long); | |||
2530 | break; | |||
2531 | default: | |||
2532 | return; | |||
2533 | } | |||
2534 | /* | |||
2535 | * Check for properties that need special formatting. | |||
2536 | */ | |||
2537 | if (strcmp (atom_name, "EDID") == 0 && value_format == 8 && | |||
2538 | value_type == XA_INTEGER((Atom) 19)) | |||
2539 | { | |||
2540 | print_edid (nitems, prop); | |||
2541 | return; | |||
2542 | } | |||
2543 | else if (strcmp (atom_name, "GUID") == 0 && value_format == 8 && | |||
2544 | value_type == XA_INTEGER((Atom) 19) && nitems == 16) | |||
2545 | { | |||
2546 | print_guid (prop); | |||
2547 | return; | |||
2548 | } | |||
2549 | ||||
2550 | for (k = 0; k < nitems; k++) | |||
2551 | { | |||
2552 | if (k != 0) | |||
2553 | { | |||
2554 | if ((k % 16) == 0) | |||
2555 | { | |||
2556 | printf ("\n\t\t"); | |||
2557 | } | |||
2558 | } | |||
2559 | print_output_property_value (value_format, value_type, | |||
2560 | prop + (k * bytes_per_item)); | |||
2561 | printf (" "); | |||
2562 | } | |||
2563 | ||||
2564 | printf ("\n"); | |||
2565 | } | |||
2566 | ||||
2567 | static void | |||
2568 | get_providers (void) | |||
2569 | { | |||
2570 | XRRProviderResources *pr; | |||
2571 | int i; | |||
2572 | ||||
2573 | if (!has_1_4 || providers) | |||
2574 | return; | |||
2575 | ||||
2576 | pr = XRRGetProviderResources(dpy, root); | |||
2577 | num_providers = pr->nproviders; | |||
2578 | providers = calloc (num_providers, sizeof (provider_t)); | |||
2579 | if (!providers) | |||
2580 | fatal ("out of memory\n"); | |||
2581 | ||||
2582 | for (i = 0; i < num_providers; i++) { | |||
2583 | provider_t *provider = &providers[i]; | |||
2584 | name_t *name = &provider->provider; | |||
2585 | XRRProviderInfo *info = XRRGetProviderInfo(dpy, res, pr->providers[i]); | |||
2586 | ||||
2587 | provider->info = info; | |||
2588 | set_name_xid (name, pr->providers[i]); | |||
2589 | set_name_index (name, i); | |||
2590 | set_name_string (name, info->name); | |||
2591 | } | |||
2592 | ||||
2593 | XRRFreeProviderResources(pr); | |||
2594 | } | |||
2595 | ||||
2596 | static provider_t * | |||
2597 | find_provider (name_t *name) | |||
2598 | { | |||
2599 | int i; | |||
2600 | ||||
2601 | if ((name->kind & name_xid) && name->xid == 0) | |||
2602 | return NULL((void*)0); | |||
2603 | for (i = 0; i < num_providers; i++) { | |||
2604 | provider_t *p = &providers[i]; | |||
2605 | name_kind_t common = name->kind & p->provider.kind; | |||
2606 | ||||
2607 | if ((common & name_xid) && name->xid == p->provider.xid) | |||
2608 | return p; | |||
2609 | if ((common & name_string) && !strcmp (name->string, p->provider.string)) | |||
2610 | return p; | |||
2611 | if ((common & name_index) && name->index == p->provider.index) | |||
2612 | return p; | |||
2613 | } | |||
2614 | ||||
2615 | printf ("Could not find provider with "); | |||
2616 | print_name (name); | |||
2617 | printf ("\n"); | |||
2618 | exit (1); | |||
2619 | } | |||
2620 | ||||
2621 | static void | |||
2622 | get_monitors(Boolint get_active) | |||
2623 | { | |||
2624 | XRRMonitorInfo *m; | |||
2625 | int n; | |||
2626 | ||||
2627 | if (!has_1_5 || monitors) | |||
2628 | return; | |||
2629 | ||||
2630 | m = XRRGetMonitors(dpy, root, get_active, &n); | |||
2631 | if (n == -1) | |||
2632 | fatal("get monitors failed\n"); | |||
2633 | monitors = calloc(1, sizeof (monitors_t)); | |||
2634 | monitors->n = n; | |||
2635 | monitors->monitors = m; | |||
2636 | } | |||
2637 | ||||
2638 | int | |||
2639 | main (int argc, char **argv) | |||
2640 | { | |||
2641 | XRRScreenSize *sizes; | |||
2642 | XRRScreenConfiguration *sc; | |||
2643 | int nsize; | |||
2644 | int nrate; | |||
2645 | short *rates; | |||
2646 | Statusint status = RRSetConfigFailed3; | |||
2647 | int rot = -1; | |||
2648 | int query = False0; | |||
2649 | int action_requested = False0; | |||
2650 | Rotation current_rotation; | |||
2651 | XEvent event; | |||
2652 | XRRScreenChangeNotifyEvent *sce; | |||
2653 | char *display_name = NULL((void*)0); | |||
2654 | int i; | |||
2655 | SizeID current_size; | |||
2656 | short current_rate; | |||
2657 | double rate = -1; | |||
2658 | int size = -1; | |||
2659 | int dirind = 0; | |||
2660 | Boolint setit = False0; | |||
2661 | Boolint version = False0; | |||
2662 | int event_base, error_base; | |||
2663 | int reflection = 0; | |||
2664 | int width = 0, height = 0; | |||
2665 | Boolint have_pixel_size = False0; | |||
2666 | int ret = 0; | |||
2667 | output_t *config_output = NULL((void*)0); | |||
2668 | Boolint setit_1_2 = False0; | |||
2669 | Boolint query_1_2 = False0; | |||
2670 | Boolint modeit = False0; | |||
2671 | Boolint propit = False0; | |||
2672 | Boolint query_1 = False0; | |||
2673 | Boolint list_providers = False0; | |||
2674 | Boolint provsetoutsource = False0; | |||
2675 | Boolint provsetoffsink = False0; | |||
2676 | Boolint monitorit = False0; | |||
2677 | Boolint list_monitors = False0; | |||
2678 | Boolint list_active_monitors = False0; | |||
2679 | int major, minor; | |||
2680 | Boolint current = False0; | |||
2681 | Boolint toggle_x = False0; | |||
2682 | Boolint toggle_y = False0; | |||
2683 | ||||
2684 | program_name = argv[0]; | |||
2685 | for (i = 1; i < argc; i++) { | |||
2686 | if (!strcmp ("-display", argv[i]) || !strcmp ("--display", argv[i]) || | |||
2687 | !strcmp ("-d", argv[i])) { | |||
2688 | if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]); | |||
2689 | display_name = argv[i]; | |||
2690 | continue; | |||
2691 | } | |||
2692 | if (!strcmp("-help", argv[i]) || !strcmp("--help", argv[i])) { | |||
2693 | usage(); | |||
2694 | exit(0); | |||
2695 | } | |||
2696 | if (!strcmp ("--verbose", argv[i])) { | |||
2697 | verbose = True1; | |||
2698 | continue; | |||
2699 | } | |||
2700 | if (!strcmp ("--dryrun", argv[i])) { | |||
2701 | dryrun = True1; | |||
2702 | verbose = True1; | |||
2703 | continue; | |||
2704 | } | |||
2705 | if (!strcmp ("--nograb", argv[i])) { | |||
2706 | grab_server = False0; | |||
2707 | continue; | |||
2708 | } | |||
2709 | if (!strcmp("--current", argv[i])) { | |||
2710 | current = True1; | |||
2711 | continue; | |||
2712 | } | |||
2713 | ||||
2714 | if (!strcmp ("-s", argv[i]) || !strcmp ("--size", argv[i])) { | |||
2715 | if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]); | |||
2716 | if (sscanf (argv[i], "%dx%d", &width, &height) == 2) { | |||
2717 | have_pixel_size = True1; | |||
2718 | } else { | |||
2719 | size = check_strtol(argv[i]); | |||
2720 | if (size < 0) argerr ("--size argument must be nonnegative\n"); | |||
2721 | } | |||
2722 | setit = True1; | |||
2723 | action_requested = True1; | |||
2724 | continue; | |||
2725 | } | |||
2726 | ||||
2727 | if (!strcmp ("-r", argv[i]) || | |||
2728 | !strcmp ("--rate", argv[i]) || | |||
2729 | !strcmp ("--refresh", argv[i])) | |||
2730 | { | |||
2731 | if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]); | |||
2732 | rate = check_strtod(argv[i]); | |||
2733 | setit = True1; | |||
2734 | if (config_output) | |||
2735 | { | |||
2736 | config_output->refresh = rate; | |||
2737 | config_output->changes |= changes_refresh; | |||
2738 | setit_1_2 = True1; | |||
2739 | } | |||
2740 | action_requested = True1; | |||
2741 | continue; | |||
2742 | } | |||
2743 | ||||
2744 | if (!strcmp ("-v", argv[i]) || !strcmp ("--version", argv[i])) { | |||
2745 | version = True1; | |||
2746 | action_requested = True1; | |||
2747 | continue; | |||
2748 | } | |||
2749 | ||||
2750 | if (!strcmp ("-x", argv[i])) { | |||
2751 | toggle_x = True1; | |||
2752 | setit = True1; | |||
2753 | action_requested = True1; | |||
2754 | continue; | |||
2755 | } | |||
2756 | if (!strcmp ("-y", argv[i])) { | |||
2757 | toggle_y = True1; | |||
2758 | setit = True1; | |||
2759 | action_requested = True1; | |||
2760 | continue; | |||
2761 | } | |||
2762 | if (!strcmp ("--screen", argv[i])) { | |||
2763 | if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]); | |||
2764 | screen = check_strtol(argv[i]); | |||
2765 | if (screen < 0) argerr ("--screen argument must be nonnegative\n"); | |||
2766 | continue; | |||
2767 | } | |||
2768 | if (!strcmp ("-q", argv[i]) || !strcmp ("--query", argv[i])) { | |||
2769 | query = True1; | |||
2770 | continue; | |||
2771 | } | |||
2772 | if (!strcmp ("-o", argv[i]) || !strcmp ("--orientation", argv[i])) { | |||
2773 | char *endptr; | |||
2774 | if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]); | |||
2775 | dirind = strtol(argv[i], &endptr, 10); | |||
2776 | if (argv[i] == endptr) { | |||
2777 | for (dirind = 0; dirind < 4; dirind++) { | |||
2778 | if (strcmp (direction[dirind], argv[i]) == 0) break; | |||
2779 | } | |||
2780 | } | |||
2781 | if ((dirind < 0) || (dirind > 3)) | |||
2782 | argerr ("%s: invalid argument '%s'\n", argv[i-1], argv[i]); | |||
2783 | rot = dirind; | |||
2784 | setit = True1; | |||
2785 | action_requested = True1; | |||
2786 | continue; | |||
2787 | } | |||
2788 | if (!strcmp ("--prop", argv[i]) || | |||
2789 | !strcmp ("--props", argv[i]) || | |||
2790 | !strcmp ("--madprops", argv[i]) || | |||
2791 | !strcmp ("--properties", argv[i])) | |||
2792 | { | |||
2793 | query_1_2 = True1; | |||
2794 | properties = True1; | |||
2795 | action_requested = True1; | |||
2796 | continue; | |||
2797 | } | |||
2798 | if (!strcmp ("--output", argv[i])) { | |||
2799 | if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]); | |||
2800 | ||||
2801 | config_output = find_output_by_name (argv[i]); | |||
2802 | if (!config_output) { | |||
2803 | config_output = add_output (); | |||
2804 | set_name (&config_output->output, argv[i], name_string|name_xid); | |||
2805 | } | |||
2806 | ||||
2807 | setit_1_2 = True1; | |||
2808 | action_requested = True1; | |||
2809 | continue; | |||
2810 | } | |||
2811 | if (!strcmp ("--crtc", argv[i])) { | |||
2812 | if (!config_output) argerr ("%s must be used after --output\n", argv[i]); | |||
2813 | if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]); | |||
2814 | set_name (&config_output->crtc, argv[i], name_xid|name_index); | |||
2815 | config_output->changes |= changes_crtc; | |||
2816 | continue; | |||
2817 | } | |||
2818 | if (!strcmp ("--mode", argv[i])) { | |||
2819 | if (!config_output) argerr ("%s must be used after --output\n", argv[i]); | |||
2820 | if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]); | |||
2821 | set_name (&config_output->mode, argv[i], name_string|name_xid); | |||
2822 | config_output->changes |= changes_mode; | |||
2823 | continue; | |||
2824 | } | |||
2825 | if (!strcmp ("--preferred", argv[i])) { | |||
2826 | if (!config_output) argerr ("%s must be used after --output\n", argv[i]); | |||
2827 | set_name_preferred (&config_output->mode); | |||
2828 | config_output->changes |= changes_mode; | |||
2829 | continue; | |||
2830 | } | |||
2831 | if (!strcmp ("--pos", argv[i])) { | |||
2832 | if (!config_output) argerr ("%s must be used after --output\n", argv[i]); | |||
2833 | if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]); | |||
2834 | if (sscanf (argv[i], "%dx%d", | |||
2835 | &config_output->x, &config_output->y) != 2) | |||
2836 | argerr ("failed to parse '%s' as a position\n", argv[i]); | |||
2837 | config_output->changes |= changes_position; | |||
2838 | continue; | |||
2839 | } | |||
2840 | if (!strcmp ("--rotation", argv[i]) || !strcmp ("--rotate", argv[i])) { | |||
2841 | if (!config_output) argerr ("%s must be used after --output\n", argv[i]); | |||
2842 | if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]); | |||
2843 | for (dirind = 0; dirind < 4; dirind++) { | |||
2844 | if (strcmp (direction[dirind], argv[i]) == 0) break; | |||
2845 | } | |||
2846 | if (dirind == 4) | |||
2847 | argerr ("%s: invalid argument '%s'\n", argv[i-1], argv[i]); | |||
2848 | config_output->rotation &= ~0xf; | |||
2849 | config_output->rotation |= 1 << dirind; | |||
2850 | config_output->changes |= changes_rotation; | |||
2851 | continue; | |||
2852 | } | |||
2853 | if (!strcmp ("--reflect", argv[i]) || !strcmp ("--reflection", argv[i])) { | |||
2854 | if (!config_output) argerr ("%s must be used after --output\n", argv[i]); | |||
2855 | if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]); | |||
2856 | for (dirind = 0; dirind < 4; dirind++) { | |||
2857 | if (strcmp (reflections[dirind], argv[i]) == 0) break; | |||
2858 | } | |||
2859 | if (dirind == 4) | |||
2860 | argerr ("%s: invalid argument '%s'\n", argv[i-1], argv[i]); | |||
2861 | config_output->rotation &= ~(RR_Reflect_X16|RR_Reflect_Y32); | |||
2862 | config_output->rotation |= dirind * RR_Reflect_X16; | |||
2863 | config_output->changes |= changes_reflection; | |||
2864 | continue; | |||
2865 | } | |||
2866 | if (!strcmp ("--left-of", argv[i])) { | |||
2867 | if (!config_output) argerr ("%s must be used after --output\n", argv[i]); | |||
2868 | if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]); | |||
2869 | config_output->relation = relation_left_of; | |||
2870 | config_output->relative_to = argv[i]; | |||
2871 | config_output->changes |= changes_relation; | |||
2872 | continue; | |||
2873 | } | |||
2874 | if (!strcmp ("--right-of", argv[i])) { | |||
2875 | if (!config_output) argerr ("%s must be used after --output\n", argv[i]); | |||
2876 | if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]); | |||
2877 | config_output->relation = relation_right_of; | |||
2878 | config_output->relative_to = argv[i]; | |||
2879 | config_output->changes |= changes_relation; | |||
2880 | continue; | |||
2881 | } | |||
2882 | if (!strcmp ("--above", argv[i])) { | |||
2883 | if (!config_output) argerr ("%s must be used after --output\n", argv[i]); | |||
2884 | if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]); | |||
2885 | config_output->relation = relation_above; | |||
2886 | config_output->relative_to = argv[i]; | |||
2887 | config_output->changes |= changes_relation; | |||
2888 | continue; | |||
2889 | } | |||
2890 | if (!strcmp ("--below", argv[i])) { | |||
2891 | if (!config_output) argerr ("%s must be used after --output\n", argv[i]); | |||
2892 | if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]); | |||
2893 | config_output->relation = relation_below; | |||
2894 | config_output->relative_to = argv[i]; | |||
2895 | config_output->changes |= changes_relation; | |||
2896 | continue; | |||
2897 | } | |||
2898 | if (!strcmp ("--same-as", argv[i])) { | |||
2899 | if (!config_output) argerr ("%s must be used after --output\n", argv[i]); | |||
2900 | if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]); | |||
2901 | config_output->relation = relation_same_as; | |||
2902 | config_output->relative_to = argv[i]; | |||
2903 | config_output->changes |= changes_relation; | |||
2904 | continue; | |||
2905 | } | |||
2906 | if (!strcmp ("--panning", argv[i])) { | |||
2907 | XRRPanning *pan; | |||
2908 | if (!config_output) argerr ("%s must be used after --output\n", argv[i]); | |||
2909 | if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]); | |||
2910 | pan = &config_output->panning; | |||
2911 | switch (sscanf (argv[i], "%dx%d+%d+%d/%dx%d+%d+%d/%d/%d/%d/%d", | |||
2912 | &pan->width, &pan->height, &pan->left, &pan->top, | |||
2913 | &pan->track_width, &pan->track_height, | |||
2914 | &pan->track_left, &pan->track_top, | |||
2915 | &pan->border_left, &pan->border_top, | |||
2916 | &pan->border_right, &pan->border_bottom)) { | |||
2917 | case 2: | |||
2918 | pan->left = pan->top = 0; | |||
2919 | /* fall through */ | |||
2920 | case 4: | |||
2921 | pan->track_left = pan->track_top = | |||
2922 | pan->track_width = pan->track_height = 0; | |||
2923 | /* fall through */ | |||
2924 | case 8: | |||
2925 | pan->border_left = pan->border_top = | |||
2926 | pan->border_right = pan->border_bottom = 0; | |||
2927 | /* fall through */ | |||
2928 | case 12: | |||
2929 | break; | |||
2930 | default: | |||
2931 | argerr ("%s: invalid argument '%s'\n", argv[i-1], argv[i]); | |||
2932 | } | |||
2933 | config_output->changes |= changes_panning; | |||
2934 | continue; | |||
2935 | } | |||
2936 | if (!strcmp ("--gamma", argv[i])) { | |||
2937 | if (!config_output) argerr ("%s must be used after --output\n", argv[i]); | |||
2938 | if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]); | |||
2939 | if (sscanf(argv[i], "%f:%f:%f", &config_output->gamma.red, | |||
2940 | &config_output->gamma.green, &config_output->gamma.blue) != 3) | |||
2941 | argerr ("%s: invalid argument '%s'\n", argv[i-1], argv[i]); | |||
2942 | config_output->changes |= changes_gamma; | |||
2943 | setit_1_2 = True1; | |||
2944 | continue; | |||
2945 | } | |||
2946 | if (!strcmp ("--brightness", argv[i])) { | |||
2947 | if (!config_output) argerr ("%s must be used after --output\n", argv[i]); | |||
2948 | if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]); | |||
2949 | if (sscanf(argv[i], "%f", &config_output->brightness) != 1) | |||
2950 | argerr ("%s: invalid argument '%s'\n", argv[i-1], argv[i]); | |||
2951 | config_output->changes |= changes_gamma; | |||
2952 | setit_1_2 = True1; | |||
2953 | continue; | |||
2954 | } | |||
2955 | if (!strcmp ("--primary", argv[i])) { | |||
2956 | if (!config_output) argerr ("%s must be used after --output\n", argv[i]); | |||
2957 | config_output->changes |= changes_primary; | |||
2958 | config_output->primary = True1; | |||
2959 | setit_1_2 = True1; | |||
2960 | continue; | |||
2961 | } | |||
2962 | if (!strcmp ("--noprimary", argv[i])) { | |||
2963 | no_primary = True1; | |||
2964 | setit_1_2 = True1; | |||
2965 | continue; | |||
2966 | } | |||
2967 | if (!strcmp ("--set", argv[i])) { | |||
2968 | output_prop_t *prop; | |||
2969 | if (!config_output) argerr ("%s must be used after --output\n", argv[i]); | |||
2970 | if (i+2 >= argc) argerr ("%s requires two arguments\n", argv[i]); | |||
2971 | prop = malloc (sizeof (output_prop_t)); | |||
2972 | prop->next = config_output->props; | |||
2973 | config_output->props = prop; | |||
2974 | prop->name = argv[++i]; | |||
2975 | prop->value = argv[++i]; | |||
2976 | propit = True1; | |||
2977 | config_output->changes |= changes_property; | |||
2978 | setit_1_2 = True1; | |||
2979 | continue; | |||
2980 | } | |||
2981 | if (!strcmp ("--scale", argv[i])) | |||
2982 | { | |||
2983 | double sx, sy; | |||
2984 | if (!config_output) argerr ("%s must be used after --output\n", argv[i]); | |||
2985 | if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]); | |||
2986 | if (sscanf (argv[i], "%lfx%lf", &sx, &sy) != 2) | |||
2987 | argerr ("failed to parse '%s' as a scaling factor\n", argv[i]); | |||
2988 | init_transform (&config_output->transform); | |||
2989 | config_output->transform.transform.matrix[0][0] = XDoubleToFixed (sx)((XFixed) ((sx) * 65536)); | |||
2990 | config_output->transform.transform.matrix[1][1] = XDoubleToFixed (sy)((XFixed) ((sy) * 65536)); | |||
2991 | config_output->transform.transform.matrix[2][2] = XDoubleToFixed (1.0)((XFixed) ((1.0) * 65536)); | |||
2992 | if (sx != 1 || sy != 1) | |||
2993 | config_output->transform.filter = "bilinear"; | |||
2994 | else | |||
2995 | config_output->transform.filter = "nearest"; | |||
2996 | config_output->transform.nparams = 0; | |||
2997 | config_output->transform.params = NULL((void*)0); | |||
2998 | config_output->changes |= changes_transform; | |||
2999 | continue; | |||
3000 | } | |||
3001 | if (!strcmp ("--scale-from", argv[i])) | |||
3002 | { | |||
3003 | int w, h; | |||
3004 | if (!config_output) argerr ("%s must be used after --output\n", argv[i]); | |||
3005 | if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]); | |||
3006 | if (sscanf (argv[i], "%dx%d", &w, &h) != 2) | |||
3007 | argerr ("failed to parse '%s' as a scale-from size\n", argv[i]); | |||
3008 | if (w <=0 || h <= 0) | |||
3009 | argerr ("--scale-from dimensions must be nonnegative\n"); | |||
3010 | config_output->scale_from_w = w; | |||
3011 | config_output->scale_from_h = h; | |||
3012 | config_output->changes |= changes_transform; | |||
3013 | continue; | |||
3014 | } | |||
3015 | if (!strcmp ("--transform", argv[i])) { | |||
3016 | double transform[3][3]; | |||
3017 | int k, l; | |||
3018 | if (!config_output) argerr ("%s must be used after --output\n", argv[i]); | |||
3019 | if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]); | |||
3020 | init_transform (&config_output->transform); | |||
3021 | if (strcmp (argv[i], "none") != 0) | |||
3022 | { | |||
3023 | if (sscanf(argv[i], "%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf", | |||
3024 | &transform[0][0],&transform[0][1],&transform[0][2], | |||
3025 | &transform[1][0],&transform[1][1],&transform[1][2], | |||
3026 | &transform[2][0],&transform[2][1],&transform[2][2]) | |||
3027 | != 9) | |||
3028 | argerr ("failed to parse '%s' as a transformation\n", argv[i]); | |||
3029 | init_transform (&config_output->transform); | |||
3030 | for (k = 0; k < 3; k++) | |||
3031 | for (l = 0; l < 3; l++) { | |||
3032 | config_output->transform.transform.matrix[k][l] = XDoubleToFixed (transform[k][l])((XFixed) ((transform[k][l]) * 65536)); | |||
3033 | } | |||
3034 | config_output->transform.filter = "bilinear"; | |||
3035 | config_output->transform.nparams = 0; | |||
3036 | config_output->transform.params = NULL((void*)0); | |||
3037 | } | |||
3038 | config_output->changes |= changes_transform; | |||
3039 | continue; | |||
3040 | } | |||
3041 | if (!strcmp ("--off", argv[i])) { | |||
3042 | if (!config_output) argerr ("%s must be used after --output\n", argv[i]); | |||
3043 | set_name_xid (&config_output->mode, None0L); | |||
3044 | set_name_xid (&config_output->crtc, None0L); | |||
3045 | config_output->changes |= changes_mode | changes_crtc; | |||
3046 | continue; | |||
3047 | } | |||
3048 | if (!strcmp ("--fb", argv[i])) { | |||
3049 | if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]); | |||
3050 | if (sscanf (argv[i], "%dx%d", | |||
3051 | &fb_width, &fb_height) != 2) | |||
3052 | argerr ("failed to parse '%s' as a framebuffer size\n", argv[i]); | |||
3053 | setit_1_2 = True1; | |||
3054 | action_requested = True1; | |||
3055 | continue; | |||
3056 | } | |||
3057 | if (!strcmp ("--fbmm", argv[i])) { | |||
3058 | if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]); | |||
3059 | if (sscanf (argv[i], "%dx%d", | |||
3060 | &fb_width_mm, &fb_height_mm) != 2) | |||
3061 | argerr ("failed to parse '%s' as a physical size\n", argv[i]); | |||
3062 | setit_1_2 = True1; | |||
3063 | action_requested = True1; | |||
3064 | continue; | |||
3065 | } | |||
3066 | if (!strcmp ("--dpi", argv[i])) { | |||
3067 | char *strtod_error; | |||
3068 | if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]); | |||
3069 | dpi = strtod(argv[i], &strtod_error); | |||
3070 | if (argv[i] == strtod_error) | |||
3071 | { | |||
3072 | dpi = 0.0; | |||
3073 | dpi_output_name = argv[i]; | |||
3074 | } | |||
3075 | setit_1_2 = True1; | |||
3076 | action_requested = True1; | |||
3077 | continue; | |||
3078 | } | |||
3079 | if (!strcmp ("--auto", argv[i])) { | |||
3080 | if (config_output) | |||
3081 | { | |||
3082 | config_output->automatic = True1; | |||
3083 | config_output->changes |= changes_automatic; | |||
3084 | } | |||
3085 | else | |||
3086 | automatic = True1; | |||
3087 | setit_1_2 = True1; | |||
3088 | action_requested = True1; | |||
3089 | continue; | |||
3090 | } | |||
3091 | if (!strcmp ("--q12", argv[i])) | |||
3092 | { | |||
3093 | query_1_2 = True1; | |||
3094 | continue; | |||
3095 | } | |||
3096 | if (!strcmp ("--q1", argv[i])) | |||
3097 | { | |||
3098 | query_1 = True1; | |||
3099 | continue; | |||
3100 | } | |||
3101 | if (!strcmp ("--newmode", argv[i])) | |||
3102 | { | |||
3103 | umode_t *m = calloc (1, sizeof (umode_t)); | |||
3104 | double clock; | |||
3105 | ||||
3106 | ++i; | |||
3107 | if (i + 9 >= argc) | |||
3108 | argerr ("failed to parse '%s' as a mode specification\n", argv[i]); | |||
3109 | m->mode.name = argv[i]; | |||
3110 | m->mode.nameLength = strlen (argv[i]); | |||
3111 | i++; | |||
3112 | clock = check_strtod(argv[i++]); | |||
3113 | m->mode.dotClock = clock * 1e6; | |||
3114 | ||||
3115 | m->mode.width = check_strtol(argv[i++]); | |||
3116 | m->mode.hSyncStart = check_strtol(argv[i++]); | |||
3117 | m->mode.hSyncEnd = check_strtol(argv[i++]); | |||
3118 | m->mode.hTotal = check_strtol(argv[i++]); | |||
3119 | m->mode.height = check_strtol(argv[i++]); | |||
3120 | m->mode.vSyncStart = check_strtol(argv[i++]); | |||
3121 | m->mode.vSyncEnd = check_strtol(argv[i++]); | |||
3122 | m->mode.vTotal = check_strtol(argv[i++]); | |||
3123 | m->mode.modeFlags = 0; | |||
3124 | while (i < argc) { | |||
3125 | int f; | |||
3126 | ||||
3127 | for (f = 0; mode_flags[f].string; f++) | |||
3128 | if (!strcasecmp (mode_flags[f].string, argv[i])) | |||
3129 | break; | |||
3130 | ||||
3131 | if (!mode_flags[f].string) | |||
3132 | break; | |||
3133 | m->mode.modeFlags |= mode_flags[f].flag; | |||
3134 | i++; | |||
3135 | } | |||
3136 | m->next = umodes; | |||
3137 | m->action = umode_create; | |||
3138 | umodes = m; | |||
3139 | modeit = True1; | |||
3140 | action_requested = True1; | |||
3141 | continue; | |||
3142 | } | |||
3143 | if (!strcmp ("--rmmode", argv[i])) | |||
3144 | { | |||
3145 | umode_t *m = calloc (1, sizeof (umode_t)); | |||
3146 | ||||
3147 | if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]); | |||
3148 | set_name (&m->name, argv[i], name_string|name_xid); | |||
3149 | m->action = umode_destroy; | |||
3150 | m->next = umodes; | |||
3151 | umodes = m; | |||
3152 | modeit = True1; | |||
3153 | action_requested = True1; | |||
3154 | continue; | |||
3155 | } | |||
3156 | if (!strcmp ("--addmode", argv[i])) | |||
3157 | { | |||
3158 | umode_t *m = calloc (1, sizeof (umode_t)); | |||
3159 | ||||
3160 | if (i+2 >= argc) argerr ("%s requires two arguments\n", argv[i]); | |||
3161 | set_name (&m->output, argv[++i], name_string|name_xid); | |||
3162 | set_name (&m->name, argv[++i], name_string|name_xid); | |||
3163 | m->action = umode_add; | |||
3164 | m->next = umodes; | |||
3165 | umodes = m; | |||
3166 | modeit = True1; | |||
3167 | action_requested = True1; | |||
3168 | continue; | |||
3169 | } | |||
3170 | if (!strcmp ("--delmode", argv[i])) | |||
3171 | { | |||
3172 | umode_t *m = calloc (1, sizeof (umode_t)); | |||
3173 | ||||
3174 | if (i+2 >= argc) argerr ("%s requires two arguments\n", argv[i]); | |||
3175 | set_name (&m->output, argv[++i], name_string|name_xid); | |||
3176 | set_name (&m->name, argv[++i], name_string|name_xid); | |||
3177 | m->action = umode_delete; | |||
3178 | m->next = umodes; | |||
3179 | umodes = m; | |||
3180 | modeit = True1; | |||
3181 | action_requested = True1; | |||
3182 | continue; | |||
3183 | } | |||
3184 | if (!strcmp ("--listproviders", argv[i])) | |||
3185 | { | |||
3186 | list_providers = True1; | |||
3187 | action_requested = True1; | |||
3188 | continue; | |||
3189 | } | |||
3190 | if (!strcmp("--setprovideroutputsource", argv[i])) | |||
3191 | { | |||
3192 | if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]); | |||
3193 | set_name (&provider_name, argv[i], name_string|name_xid|name_index); | |||
3194 | if (++i>=argc) | |||
3195 | set_name_xid (&output_source_provider_name, 0); | |||
3196 | else | |||
3197 | set_name (&output_source_provider_name, argv[i], name_string|name_xid|name_index); | |||
3198 | action_requested = True1; | |||
3199 | provsetoutsource = True1; | |||
3200 | continue; | |||
3201 | } | |||
3202 | if (!strcmp("--setprovideroffloadsink", argv[i])) | |||
3203 | { | |||
3204 | if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]); | |||
3205 | set_name (&provider_name, argv[i], name_string|name_xid|name_index); | |||
3206 | if (++i>=argc) | |||
3207 | set_name_xid (&offload_sink_provider_name, 0); | |||
3208 | else | |||
3209 | set_name (&offload_sink_provider_name, argv[i], name_string|name_xid|name_index); | |||
3210 | action_requested = True1; | |||
3211 | provsetoffsink = True1; | |||
3212 | continue; | |||
3213 | } | |||
3214 | if (!strcmp("--listmonitors", argv[i])) | |||
3215 | { | |||
3216 | list_monitors = True1; | |||
3217 | action_requested = True1; | |||
3218 | continue; | |||
3219 | } | |||
3220 | if (!strcmp("--listactivemonitors", argv[i])) | |||
3221 | { | |||
3222 | list_active_monitors = True1; | |||
3223 | action_requested = True1; | |||
3224 | continue; | |||
3225 | } | |||
3226 | if (!strcmp("--setmonitor", argv[i])) | |||
3227 | { | |||
3228 | umonitor_t *m = calloc(1, sizeof (umonitor_t)), **l; | |||
3229 | char *t; | |||
3230 | char *o; | |||
3231 | char *n; | |||
3232 | char *geom; | |||
3233 | ||||
3234 | if (i+3 >= argc) argerr("%s requires three argument\n", argv[i]); | |||
3235 | n = argv[++i]; | |||
3236 | if (*n == '*') { | |||
3237 | m->primary = True1; | |||
3238 | n++; | |||
3239 | } | |||
3240 | m->name = n; | |||
3241 | m->set = True1; | |||
3242 | geom = argv[++i]; | |||
3243 | ||||
3244 | if (strncmp (geom, "auto", 4) != 0) { | |||
3245 | if (sscanf(geom, "%d/%dx%d/%d+%d+%d", | |||
3246 | &m->width, &m->mmwidth, &m->height, &m->mmheight, &m->x, &m->y) != 6) | |||
3247 | argerr ("failed to parse '%s' as monitor geometry\n", argv[i]); | |||
3248 | } | |||
3249 | ||||
3250 | o = argv[++i]; | |||
3251 | if (strcmp(o, "none") != 0) { | |||
3252 | printf ("output list %s\n", o); | |||
3253 | for (; (t = strtok(o, ",")) != NULL((void*)0); o = NULL((void*)0)) { | |||
3254 | m->outputs = realloc(m->outputs, (m->noutput + 1) * sizeof (name_t)); | |||
3255 | printf ("add monitor %s\n", t); | |||
3256 | set_name(&m->outputs[m->noutput++], t, name_string|name_xid|name_index); | |||
3257 | printf ("output name %s\n", m->outputs[m->noutput-1].string); | |||
3258 | } | |||
3259 | } | |||
3260 | for (l = &umonitors; *l; l = &((*l)->next)); | |||
3261 | *l = m; | |||
3262 | action_requested = True1; | |||
3263 | monitorit = True1; | |||
3264 | continue; | |||
3265 | } | |||
3266 | if (!strcmp("--delmonitor", argv[i])) | |||
3267 | { | |||
3268 | umonitor_t *m = calloc(1, sizeof (umonitor_t)), **l; | |||
3269 | ||||
3270 | if (++i >= argc) argerr("%s requires an argument\n", argv[i-1]); | |||
3271 | ||||
3272 | m->name = argv[i]; | |||
3273 | m->set = False0; | |||
3274 | for (l = &umonitors; *l; l = &((*l)->next)); | |||
3275 | *l = m; | |||
3276 | action_requested = True1; | |||
3277 | monitorit = True1; | |||
3278 | continue; | |||
3279 | } | |||
3280 | ||||
3281 | argerr ("unrecognized option '%s'\n", argv[i]); | |||
3282 | } | |||
3283 | if (!action_requested) | |||
3284 | query = True1; | |||
3285 | if (verbose) | |||
3286 | { | |||
3287 | query = True1; | |||
3288 | if (setit && !setit_1_2) | |||
3289 | query_1 = True1; | |||
3290 | } | |||
3291 | if (version) | |||
3292 | printf("xrandr program version " VERSION"1.5.0" "\n"); | |||
3293 | ||||
3294 | dpy = XOpenDisplay (display_name); | |||
3295 | ||||
3296 | if (dpy == NULL((void*)0)) { | |||
3297 | fprintf (stderr__stderrp, "Can't open display %s\n", XDisplayName(display_name)); | |||
3298 | exit (1); | |||
3299 | } | |||
3300 | if (screen < 0) | |||
3301 | screen = DefaultScreen (dpy)(((_XPrivDisplay)(dpy))->default_screen); | |||
3302 | if (screen >= ScreenCount (dpy)(((_XPrivDisplay)(dpy))->nscreens)) { | |||
3303 | fprintf (stderr__stderrp, "Invalid screen number %d (display has %d)\n", | |||
3304 | screen, ScreenCount (dpy)(((_XPrivDisplay)(dpy))->nscreens)); | |||
3305 | exit (1); | |||
3306 | } | |||
3307 | ||||
3308 | root = RootWindow (dpy, screen)((&((_XPrivDisplay)(dpy))->screens[screen])->root); | |||
3309 | ||||
3310 | if (!XRRQueryExtension (dpy, &event_base, &error_base) || | |||
3311 | !XRRQueryVersion (dpy, &major, &minor)) | |||
3312 | { | |||
3313 | fprintf (stderr__stderrp, "RandR extension missing\n"); | |||
3314 | exit (1); | |||
3315 | } | |||
3316 | if (major > 1 || (major == 1 && minor >= 2)) | |||
3317 | has_1_2 = True1; | |||
3318 | if (major > 1 || (major == 1 && minor >= 3)) | |||
3319 | has_1_3 = True1; | |||
3320 | if (major > 1 || (major == 1 && minor >= 4)) | |||
3321 | has_1_4 = True1; | |||
3322 | if (major > 1 || (major == 1 && minor >= 5)) | |||
3323 | has_1_5 = True1; | |||
3324 | if (has_1_2 && modeit) | |||
3325 | { | |||
3326 | umode_t *m; | |||
3327 | ||||
3328 | get_screen (True1); | |||
3329 | get_crtcs(); | |||
3330 | get_outputs(); | |||
3331 | ||||
3332 | for (m = umodes; m; m = m->next) | |||
3333 | { | |||
3334 | XRRModeInfo *e; | |||
3335 | output_t *o; | |||
3336 | ||||
3337 | switch (m->action) { | |||
3338 | case umode_create: | |||
3339 | XRRCreateMode (dpy, root, &m->mode); | |||
3340 | break; | |||
3341 | case umode_destroy: | |||
3342 | e = find_mode (&m->name, 0); | |||
3343 | if (!e) | |||
3344 | fatal ("cannot find mode \"%s\"\n", m->name.string); | |||
3345 | XRRDestroyMode (dpy, e->id); | |||
3346 | break; | |||
3347 | case umode_add: | |||
3348 | o = find_output (&m->output); | |||
3349 | if (!o) | |||
3350 | fatal ("cannot find output \"%s\"\n", m->output.string); | |||
3351 | e = find_mode (&m->name, 0); | |||
3352 | if (!e) | |||
3353 | fatal ("cannot find mode \"%s\"\n", m->name.string); | |||
3354 | XRRAddOutputMode (dpy, o->output.xid, e->id); | |||
3355 | break; | |||
3356 | case umode_delete: | |||
3357 | o = find_output (&m->output); | |||
3358 | if (!o) | |||
3359 | fatal ("cannot find output \"%s\"\n", m->output.string); | |||
3360 | e = find_mode (&m->name, 0); | |||
3361 | if (!e) | |||
3362 | fatal ("cannot find mode \"%s\"\n", m->name.string); | |||
3363 | XRRDeleteOutputMode (dpy, o->output.xid, e->id); | |||
3364 | break; | |||
3365 | } | |||
3366 | } | |||
3367 | if (!propit && !setit_1_2 && !monitorit) | |||
3368 | { | |||
3369 | XSync (dpy, False0); | |||
3370 | exit (0); | |||
3371 | } | |||
3372 | } | |||
3373 | if (has_1_2 && propit) | |||
3374 | { | |||
3375 | output_t *output; | |||
3376 | ||||
3377 | get_screen (True1); | |||
3378 | get_crtcs(); | |||
3379 | get_outputs(); | |||
3380 | ||||
3381 | for (output = all_outputs; output; output = output->next) | |||
3382 | { | |||
3383 | output_prop_t *prop; | |||
3384 | ||||
3385 | for (prop = output->props; prop; prop = prop->next) | |||
3386 | { | |||
3387 | Atom name = XInternAtom (dpy, prop->name, False0); | |||
3388 | Atom type; | |||
3389 | int format = 0; | |||
3390 | unsigned char *data, *malloced_data = NULL((void*)0); | |||
3391 | int nelements; | |||
3392 | int int_value; | |||
3393 | unsigned long ulong_value; | |||
3394 | unsigned char *prop_data; | |||
3395 | int actual_format; | |||
3396 | unsigned long nitems, bytes_after; | |||
3397 | Atom actual_type; | |||
3398 | XRRPropertyInfo *propinfo; | |||
3399 | ||||
3400 | type = AnyPropertyType0L; | |||
3401 | ||||
3402 | if (XRRGetOutputProperty (dpy, output->output.xid, name, | |||
3403 | 0, 100, False0, False0, | |||
3404 | AnyPropertyType0L, | |||
3405 | &actual_type, &actual_format, | |||
3406 | &nitems, &bytes_after, &prop_data) == Success0 && | |||
3407 | ||||
3408 | (propinfo = XRRQueryOutputProperty(dpy, output->output.xid, | |||
3409 | name))) | |||
3410 | { | |||
3411 | type = actual_type; | |||
3412 | format = actual_format; | |||
3413 | } | |||
3414 | ||||
3415 | malloced_data = property_values_from_string | |||
3416 | (prop->value, type, actual_format, &nelements); | |||
3417 | ||||
3418 | if (malloced_data) | |||
3419 | { | |||
3420 | data = malloced_data; | |||
3421 | type = actual_type; | |||
3422 | format = actual_format; | |||
3423 | } | |||
3424 | else if (type == AnyPropertyType0L && | |||
3425 | (sscanf (prop->value, "%d", &int_value) == 1 || | |||
3426 | sscanf (prop->value, "0x%x", &int_value) == 1)) | |||
3427 | { | |||
3428 | type = XA_INTEGER((Atom) 19); | |||
3429 | ulong_value = int_value; | |||
3430 | data = (unsigned char *) &ulong_value; | |||
3431 | nelements = 1; | |||
3432 | format = 32; | |||
3433 | } | |||
3434 | else if (type == XA_ATOM((Atom) 4)) | |||
3435 | { | |||
3436 | ulong_value = XInternAtom (dpy, prop->value, False0); | |||
3437 | data = (unsigned char *) &ulong_value; | |||
3438 | nelements = 1; | |||
3439 | } | |||
3440 | else if (type == XA_STRING((Atom) 31) || type == AnyPropertyType0L) | |||
3441 | { | |||
3442 | type = XA_STRING((Atom) 31); | |||
3443 | data = (unsigned char *) prop->value; | |||
3444 | nelements = strlen (prop->value); | |||
3445 | format = 8; | |||
3446 | } | |||
3447 | else | |||
3448 | continue; | |||
3449 | XRRChangeOutputProperty (dpy, output->output.xid, | |||
3450 | name, type, format, PropModeReplace0, | |||
3451 | data, nelements); | |||
3452 | free (malloced_data); | |||
3453 | } | |||
3454 | } | |||
3455 | if (!setit_1_2) | |||
3456 | { | |||
3457 | XSync (dpy, False0); | |||
3458 | exit (0); | |||
3459 | } | |||
3460 | } | |||
3461 | if (provsetoutsource) | |||
3462 | { | |||
3463 | provider_t *provider, *source; | |||
3464 | ||||
3465 | if (!has_1_4) | |||
3466 | fatal ("--setprovideroutputsource requires RandR 1.4\n"); | |||
3467 | ||||
3468 | get_screen (True1); | |||
3469 | get_providers (); | |||
3470 | ||||
3471 | provider = find_provider (&provider_name); | |||
3472 | source = find_provider(&output_source_provider_name); | |||
3473 | ||||
3474 | XRRSetProviderOutputSource(dpy, provider->provider.xid, source ? source->provider.xid : 0); | |||
3475 | } | |||
3476 | if (provsetoffsink) | |||
3477 | { | |||
3478 | provider_t *provider, *sink; | |||
3479 | ||||
3480 | if (!has_1_4) | |||
3481 | fatal ("--setprovideroffloadsink requires RandR 1.4\n"); | |||
3482 | ||||
3483 | get_screen (True1); | |||
3484 | get_providers (); | |||
3485 | ||||
3486 | provider = find_provider (&provider_name); | |||
3487 | sink = find_provider(&offload_sink_provider_name); | |||
3488 | ||||
3489 | XRRSetProviderOffloadSink(dpy, provider->provider.xid, sink ? sink->provider.xid : 0); | |||
3490 | } | |||
3491 | if (setit_1_2) | |||
3492 | { | |||
3493 | get_screen (True1); | |||
3494 | get_crtcs (); | |||
3495 | get_outputs (); | |||
3496 | set_positions (); | |||
3497 | set_screen_size (); | |||
3498 | ||||
3499 | pick_crtcs (); | |||
3500 | ||||
3501 | /* | |||
3502 | * Assign outputs to crtcs | |||
3503 | */ | |||
3504 | set_crtcs (); | |||
3505 | ||||
3506 | /* | |||
3507 | * Mark changing crtcs | |||
3508 | */ | |||
3509 | mark_changing_crtcs (); | |||
3510 | ||||
3511 | /* | |||
3512 | * If an output was specified to track dpi, use it | |||
3513 | */ | |||
3514 | if (dpi_output_name) | |||
3515 | { | |||
3516 | output_t *dpi_output = find_output_by_name (dpi_output_name); | |||
3517 | XRROutputInfo *output_info; | |||
3518 | XRRModeInfo *mode_info; | |||
3519 | if (!dpi_output) | |||
3520 | fatal ("Cannot find output %s\n", dpi_output_name); | |||
3521 | output_info = dpi_output->output_info; | |||
3522 | mode_info = dpi_output->mode_info; | |||
3523 | if (output_info && mode_info && output_info->mm_height) | |||
3524 | { | |||
3525 | /* | |||
3526 | * When this output covers the whole screen, just use | |||
3527 | * the known physical size | |||
3528 | */ | |||
3529 | if (fb_width == mode_info->width && | |||
3530 | fb_height == mode_info->height) | |||
3531 | { | |||
3532 | fb_width_mm = output_info->mm_width; | |||
3533 | fb_height_mm = output_info->mm_height; | |||
3534 | } | |||
3535 | else | |||
3536 | { | |||
3537 | dpi = (25.4 * mode_info->height) / output_info->mm_height; | |||
3538 | } | |||
3539 | } | |||
3540 | } | |||
3541 | ||||
3542 | /* | |||
3543 | * Compute physical screen size | |||
3544 | */ | |||
3545 | if (fb_width_mm == 0 || fb_height_mm == 0) | |||
3546 | { | |||
3547 | if (fb_width != DisplayWidth (dpy, screen)((&((_XPrivDisplay)(dpy))->screens[screen])->width) || | |||
3548 | fb_height != DisplayHeight (dpy, screen)((&((_XPrivDisplay)(dpy))->screens[screen])->height ) || dpi != 0.0) | |||
3549 | { | |||
3550 | if (dpi <= 0) | |||
3551 | dpi = (25.4 * DisplayHeight (dpy, screen)((&((_XPrivDisplay)(dpy))->screens[screen])->height )) / DisplayHeightMM(dpy, screen)((&((_XPrivDisplay)(dpy))->screens[screen])->mheight ); | |||
3552 | ||||
3553 | fb_width_mm = (25.4 * fb_width) / dpi; | |||
3554 | fb_height_mm = (25.4 * fb_height) / dpi; | |||
3555 | } | |||
3556 | else | |||
3557 | { | |||
3558 | fb_width_mm = DisplayWidthMM (dpy, screen)((&((_XPrivDisplay)(dpy))->screens[screen])->mwidth ); | |||
3559 | fb_height_mm = DisplayHeightMM (dpy, screen)((&((_XPrivDisplay)(dpy))->screens[screen])->mheight ); | |||
3560 | } | |||
3561 | } | |||
3562 | ||||
3563 | /* | |||
3564 | * Set panning | |||
3565 | */ | |||
3566 | set_panning (); | |||
3567 | ||||
3568 | /* | |||
3569 | * Set gamma on crtc's that belong to the outputs. | |||
3570 | */ | |||
3571 | set_gamma (); | |||
3572 | ||||
3573 | /* | |||
3574 | * Now apply all of the changes | |||
3575 | */ | |||
3576 | apply (); | |||
3577 | ||||
3578 | if (!monitorit) { | |||
3579 | XSync (dpy, False0); | |||
3580 | exit (0); | |||
3581 | } | |||
3582 | } | |||
3583 | if (monitorit) { | |||
3584 | umonitor_t *u; | |||
3585 | Atom name; | |||
3586 | ||||
3587 | if (!has_1_5) { | |||
3588 | printf("RandR 1.5 not supported\n"); | |||
3589 | exit(0); | |||
3590 | } | |||
3591 | ||||
3592 | get_screen(True1); | |||
3593 | get_monitors(True1); | |||
3594 | get_crtcs(); | |||
3595 | get_outputs(); | |||
3596 | ||||
3597 | for (u = umonitors; u; u = u->next) { | |||
3598 | if (u->set) { | |||
3599 | XRRMonitorInfo *m; | |||
3600 | int o; | |||
3601 | ||||
3602 | name = XInternAtom(dpy, u->name, False0); | |||
3603 | m = XRRAllocateMonitor(dpy, u->noutput); | |||
3604 | ||||
3605 | m->name = name; | |||
3606 | m->primary = u->primary; | |||
3607 | m->x = u->x; | |||
3608 | m->y = u->y; | |||
3609 | m->width = u->width; | |||
3610 | m->height = u->height; | |||
3611 | m->mwidth = u->mmwidth; | |||
3612 | m->mheight = u->mmheight; | |||
3613 | for (o = 0; o < u->noutput; o++) { | |||
3614 | output_t *output = find_output(&u->outputs[o]); | |||
3615 | if (!output) | |||
3616 | fatal("cannot find output\n"); | |||
3617 | m->outputs[o] = output->output.xid; | |||
3618 | } | |||
3619 | ||||
3620 | XRRSetMonitor(dpy, root, m); | |||
3621 | ||||
3622 | XRRFreeMonitors(m); | |||
3623 | } else { | |||
3624 | int m; | |||
3625 | ||||
3626 | name = XInternAtom(dpy, u->name, True1); | |||
3627 | if (!name) { | |||
3628 | printf("No monitor named '%s'\n", u->name); | |||
3629 | } else { | |||
3630 | if (!monitors) | |||
3631 | printf ("No monitors\n"); | |||
3632 | else { | |||
3633 | for (m = 0; m < monitors->n; m++) { | |||
3634 | if (monitors->monitors[m].name == name) | |||
3635 | break; | |||
3636 | } | |||
3637 | if (m == monitors->n) | |||
3638 | printf("No monitor named '%s'\n", u->name); | |||
3639 | else | |||
3640 | XRRDeleteMonitor(dpy, root, name); | |||
3641 | } | |||
3642 | } | |||
3643 | } | |||
3644 | } | |||
3645 | XSync (dpy, False0); | |||
3646 | exit (0); | |||
3647 | } | |||
3648 | if (query_1_2 || (query && has_1_2 && !query_1)) | |||
3649 | { | |||
3650 | output_t *output; | |||
3651 | int m; | |||
3652 | ||||
3653 | #define ModeShown0x80000000 0x80000000 | |||
3654 | ||||
3655 | get_screen (current); | |||
3656 | get_crtcs (); | |||
3657 | get_outputs (); | |||
3658 | ||||
3659 | printf ("Screen %d: minimum %d x %d, current %d x %d, maximum %d x %d\n", | |||
3660 | screen, minWidth, minHeight, | |||
3661 | DisplayWidth (dpy, screen)((&((_XPrivDisplay)(dpy))->screens[screen])->width), DisplayHeight(dpy, screen)((&((_XPrivDisplay)(dpy))->screens[screen])->height ), | |||
3662 | maxWidth, maxHeight); | |||
3663 | ||||
3664 | for (output = all_outputs; output; output = output->next) | |||
3665 | { | |||
3666 | XRROutputInfo *output_info = output->output_info; | |||
3667 | crtc_t *cur_crtc = output->crtc_info; | |||
3668 | XRRCrtcInfo *crtc_info = cur_crtc ? cur_crtc->crtc_info : NULL((void*)0); | |||
3669 | XRRModeInfo *cur_mode = output->mode_info; | |||
3670 | Atom *props; | |||
3671 | int j, nprop; | |||
3672 | Boolint *mode_shown; | |||
3673 | Rotation rotations = output_rotations (output); | |||
3674 | ||||
3675 | printf ("%s %s", output_info->name, connection[output_info->connection]); | |||
3676 | if (output->primary) { | |||
3677 | printf(" primary"); | |||
3678 | } | |||
3679 | if (cur_mode) | |||
3680 | { | |||
3681 | if (crtc_info) { | |||
3682 | printf (" %dx%d+%d+%d", | |||
3683 | crtc_info->width, crtc_info->height, | |||
3684 | crtc_info->x, crtc_info->y); | |||
3685 | } else { | |||
3686 | printf (" %dx%d+%d+%d", | |||
3687 | cur_mode->width, cur_mode->height, output->x, | |||
3688 | output->y); | |||
3689 | } | |||
3690 | if (verbose) | |||
3691 | printf (" (0x%x)", (int)cur_mode->id); | |||
3692 | if (output->rotation != RR_Rotate_01 || verbose) | |||
3693 | { | |||
3694 | printf (" %s", | |||
3695 | rotation_name (output->rotation)); | |||
3696 | if (output->rotation & (RR_Reflect_X16|RR_Reflect_Y32)) | |||
3697 | printf (" %s", reflection_name (output->rotation)); | |||
3698 | } | |||
3699 | } | |||
3700 | if (rotations != RR_Rotate_01 || verbose) | |||
3701 | { | |||
3702 | Boolint first = True1; | |||
3703 | printf (" ("); | |||
3704 | for (i = 0; i < 4; i ++) { | |||
3705 | if ((rotations >> i) & 1) { | |||
3706 | if (!first) printf (" "); first = False0; | |||
3707 | printf("%s", direction[i]); | |||
3708 | } | |||
3709 | } | |||
3710 | if (rotations & RR_Reflect_X16) | |||
3711 | { | |||
3712 | if (!first) printf (" "); first = False0; | |||
3713 | printf ("x axis"); | |||
3714 | } | |||
3715 | if (rotations & RR_Reflect_Y32) | |||
3716 | { | |||
3717 | if (!first) printf (" "); | |||
3718 | printf ("y axis"); | |||
3719 | } | |||
3720 | printf (")"); | |||
3721 | } | |||
3722 | ||||
3723 | if (cur_mode) | |||
3724 | { | |||
3725 | printf (" %dmm x %dmm", | |||
3726 | (int)output_info->mm_width, (int)output_info->mm_height); | |||
3727 | } | |||
3728 | ||||
3729 | if (cur_crtc && cur_crtc->panning_info && | |||
3730 | cur_crtc->panning_info->width > 0) | |||
3731 | { | |||
3732 | XRRPanning *pan = cur_crtc->panning_info; | |||
3733 | printf (" panning %dx%d+%d+%d", | |||
3734 | pan->width, pan->height, pan->left, pan->top); | |||
3735 | if ((pan->track_width != 0 && | |||
3736 | (pan->track_left != pan->left || | |||
3737 | pan->track_width != pan->width || | |||
3738 | pan->border_left != 0 || | |||
3739 | pan->border_right != 0)) || | |||
3740 | (pan->track_height != 0 && | |||
3741 | (pan->track_top != pan->top || | |||
3742 | pan->track_height != pan->height || | |||
3743 | pan->border_top != 0 || | |||
3744 | pan->border_bottom != 0))) | |||
3745 | printf (" tracking %dx%d+%d+%d border %d/%d/%d/%d", | |||
3746 | pan->track_width, pan->track_height, | |||
3747 | pan->track_left, pan->track_top, | |||
3748 | pan->border_left, pan->border_top, | |||
3749 | pan->border_right, pan->border_bottom); | |||
3750 | } | |||
3751 | printf ("\n"); | |||
3752 | ||||
3753 | if (verbose) | |||
3754 | { | |||
3755 | printf ("\tIdentifier: 0x%x\n", (int)output->output.xid); | |||
3756 | printf ("\tTimestamp: %d\n", (int)output_info->timestamp); | |||
3757 | printf ("\tSubpixel: %s\n", order[output_info->subpixel_order]); | |||
3758 | if (output->gamma.red != 0.0 && output->gamma.green != 0.0 && output->gamma.blue != 0.0) { | |||
3759 | printf ("\tGamma: %#.2g:%#.2g:%#.2g\n", | |||
3760 | output->gamma.red, output->gamma.green, output->gamma.blue); | |||
3761 | printf ("\tBrightness: %#.2g\n", output->brightness); | |||
3762 | } | |||
3763 | printf ("\tClones: "); | |||
3764 | for (j = 0; j < output_info->nclone; j++) | |||
3765 | { | |||
3766 | output_t *clone = find_output_by_xid (output_info->clones[j]); | |||
3767 | ||||
3768 | if (clone) printf (" %s", clone->output.string); | |||
3769 | } | |||
3770 | printf ("\n"); | |||
3771 | if (output->crtc_info) | |||
3772 | printf ("\tCRTC: %d\n", output->crtc_info->crtc.index); | |||
3773 | printf ("\tCRTCs: "); | |||
3774 | for (j = 0; j < output_info->ncrtc; j++) | |||
3775 | { | |||
3776 | crtc_t *crtc = find_crtc_by_xid (output_info->crtcs[j]); | |||
3777 | if (crtc) | |||
3778 | printf (" %d", crtc->crtc.index); | |||
3779 | } | |||
3780 | printf ("\n"); | |||
3781 | if (output->crtc_info && output->crtc_info->panning_info) { | |||
3782 | XRRPanning *pan = output->crtc_info->panning_info; | |||
3783 | printf ("\tPanning: %dx%d+%d+%d\n", | |||
3784 | pan->width, pan->height, pan->left, pan->top); | |||
3785 | printf ("\tTracking: %dx%d+%d+%d\n", | |||
3786 | pan->track_width, pan->track_height, | |||
3787 | pan->track_left, pan->track_top); | |||
3788 | printf ("\tBorder: %d/%d/%d/%d\n", | |||
3789 | pan->border_left, pan->border_top, | |||
3790 | pan->border_right, pan->border_bottom); | |||
3791 | } | |||
3792 | } | |||
3793 | if (verbose) | |||
3794 | { | |||
3795 | int x, y; | |||
3796 | ||||
3797 | printf ("\tTransform: "); | |||
3798 | for (y = 0; y < 3; y++) | |||
3799 | { | |||
3800 | for (x = 0; x < 3; x++) | |||
3801 | printf (" %f", XFixedToDouble (output->transform.transform.matrix[y][x])(((XDouble) (output->transform.transform.matrix[y][x])) / 65536 )); | |||
3802 | if (y < 2) | |||
3803 | printf ("\n\t "); | |||
3804 | } | |||
3805 | if (output->transform.filter) | |||
3806 | printf ("\n\t filter: %s", output->transform.filter); | |||
3807 | printf ("\n"); | |||
3808 | } | |||
3809 | if (verbose || properties) | |||
3810 | { | |||
3811 | props = XRRListOutputProperties (dpy, output->output.xid, | |||
3812 | &nprop); | |||
3813 | for (j = 0; j < nprop; j++) { | |||
3814 | unsigned char *prop; | |||
3815 | int actual_format; | |||
3816 | unsigned long nitems, bytes_after; | |||
3817 | Atom actual_type; | |||
3818 | XRRPropertyInfo *propinfo; | |||
3819 | char *atom_name = XGetAtomName (dpy, props[j]); | |||
3820 | int k; | |||
3821 | ||||
3822 | XRRGetOutputProperty (dpy, output->output.xid, props[j], | |||
3823 | 0, 100, False0, False0, | |||
3824 | AnyPropertyType0L, | |||
3825 | &actual_type, &actual_format, | |||
3826 | &nitems, &bytes_after, &prop); | |||
3827 | ||||
3828 | propinfo = XRRQueryOutputProperty(dpy, output->output.xid, | |||
3829 | props[j]); | |||
3830 | ||||
3831 | printf ("\t%s: ", atom_name); | |||
3832 | ||||
3833 | print_output_property(atom_name, actual_format, | |||
3834 | actual_type, nitems, prop); | |||
3835 | ||||
3836 | if (propinfo->range && propinfo->num_values > 0) | |||
3837 | { | |||
3838 | printf ("\t\trange%s: ", | |||
3839 | (propinfo->num_values == 2) ? "" : "s"); | |||
3840 | for (k = 0; k < propinfo->num_values / 2; k++) | |||
3841 | { | |||
3842 | printf ("("); | |||
3843 | print_output_property_value (32, actual_type, | |||
3844 | (unsigned char *) &(propinfo->values[k * 2])); | |||
3845 | printf (", "); | |||
3846 | print_output_property_value (32, actual_type, | |||
3847 | (unsigned char *) &(propinfo->values[k * 2 + 1])); | |||
3848 | printf (")"); | |||
3849 | if (k < propinfo->num_values / 2 - 1) | |||
3850 | printf (", "); | |||
3851 | } | |||
3852 | printf ("\n"); | |||
3853 | } | |||
3854 | if (!propinfo->range && propinfo->num_values > 0) | |||
3855 | { | |||
3856 | printf ("\t\tsupported: "); | |||
3857 | for (k = 0; k < propinfo->num_values; k++) | |||
3858 | { | |||
3859 | print_output_property_value (32, actual_type, | |||
3860 | (unsigned char *) &(propinfo->values[k])); | |||
3861 | if (k < propinfo->num_values - 1) | |||
3862 | printf (", "); | |||
3863 | } | |||
3864 | printf ("\n"); | |||
3865 | } | |||
3866 | ||||
3867 | free(propinfo); | |||
3868 | } | |||
3869 | } | |||
3870 | ||||
3871 | if (verbose) | |||
3872 | { | |||
3873 | for (j = 0; j < output_info->nmode; j++) | |||
3874 | { | |||
3875 | XRRModeInfo *mode = find_mode_by_xid (output_info->modes[j]); | |||
3876 | ||||
3877 | print_verbose_mode (mode, mode == output->mode_info, | |||
3878 | j < output_info->npreferred); | |||
3879 | mode->modeFlags |= ModeShown0x80000000; | |||
3880 | } | |||
3881 | } | |||
3882 | else | |||
3883 | { | |||
3884 | mode_shown = calloc (output_info->nmode, sizeof (Boolint)); | |||
3885 | if (!mode_shown) fatal ("out of memory\n"); | |||
3886 | for (j = 0; j < output_info->nmode; j++) | |||
3887 | { | |||
3888 | XRRModeInfo *jmode, *kmode; | |||
3889 | int k; | |||
3890 | ||||
3891 | if (mode_shown[j]) continue; | |||
3892 | ||||
3893 | jmode = find_mode_by_xid (output_info->modes[j]); | |||
3894 | printf (" "); | |||
3895 | printf (" %-12s", jmode->name); | |||
3896 | for (k = j; k < output_info->nmode; k++) | |||
3897 | { | |||
3898 | if (mode_shown[k]) continue; | |||
3899 | kmode = find_mode_by_xid (output_info->modes[k]); | |||
3900 | if (strcmp (jmode->name, kmode->name) != 0) continue; | |||
3901 | mode_shown[k] = True1; | |||
3902 | kmode->modeFlags |= ModeShown0x80000000; | |||
3903 | printf (" %6.2f", mode_refresh (kmode)); | |||
3904 | if (kmode == output->mode_info) | |||
3905 | printf ("*"); | |||
3906 | else | |||
3907 | printf (" "); | |||
3908 | if (k < output_info->npreferred) | |||
3909 | printf ("+"); | |||
3910 | else | |||
3911 | printf (" "); | |||
3912 | } | |||
3913 | printf ("\n"); | |||
3914 | } | |||
3915 | free (mode_shown); | |||
3916 | } | |||
3917 | } | |||
3918 | for (m = 0; m < res->nmode; m++) | |||
3919 | { | |||
3920 | XRRModeInfo *mode = &res->modes[m]; | |||
3921 | ||||
3922 | if (!(mode->modeFlags & ModeShown0x80000000)) | |||
3923 | print_verbose_mode(mode, False0, False0); | |||
3924 | } | |||
3925 | exit (0); | |||
3926 | } | |||
3927 | if (list_providers) { | |||
3928 | int k; | |||
3929 | ||||
3930 | if (!has_1_4) { | |||
3931 | printf ("RandR 1.4 not supported\n"); | |||
3932 | exit (0); | |||
3933 | } | |||
3934 | ||||
3935 | get_screen (current); | |||
3936 | get_providers (); | |||
3937 | ||||
3938 | if (providers) { | |||
3939 | int j; | |||
3940 | ||||
3941 | printf("Providers: number : %d\n", num_providers); | |||
3942 | ||||
3943 | for (j = 0; j < num_providers; j++) { | |||
3944 | provider_t *provider = &providers[j]; | |||
3945 | XRRProviderInfo *info = provider->info; | |||
3946 | ||||
3947 | printf("Provider %d: id: 0x%x cap: 0x%x", j, (int)provider->provider.xid, info->capabilities); | |||
3948 | for (k = 0; k < 4; k++) | |||
3949 | if (info->capabilities & (1 << k)) | |||
3950 | printf(", %s", capability_name(1<<k)); | |||
3951 | ||||
3952 | printf(" crtcs: %d outputs: %d associated providers: %d name:%s\n", info->ncrtcs, info->noutputs, info->nassociatedproviders, info->name); | |||
3953 | } | |||
3954 | } | |||
3955 | } | |||
3956 | if (list_monitors || list_active_monitors) { | |||
3957 | ||||
3958 | if (!has_1_5) { | |||
3959 | printf("RandR 1.5 not supported\n"); | |||
3960 | exit(0); | |||
3961 | } | |||
3962 | ||||
3963 | get_screen(current); | |||
3964 | get_monitors(list_active_monitors ? True1 : False0); | |||
3965 | get_crtcs(); | |||
3966 | get_outputs(); | |||
3967 | ||||
3968 | if (monitors) { | |||
3969 | int m, o; | |||
3970 | ||||
3971 | printf("Monitors: %d\n", monitors->n); | |||
3972 | ||||
3973 | for (m = 0; m < monitors->n; m++) { | |||
3974 | printf (" %d: %s%s%s %d/%dx%d/%d+%d+%d ", | |||
3975 | m, | |||
3976 | monitors->monitors[m].automatic ? "+" : "", | |||
3977 | monitors->monitors[m].primary ? "*" : "", | |||
3978 | XGetAtomName(dpy, monitors->monitors[m].name), | |||
3979 | monitors->monitors[m].width, | |||
3980 | monitors->monitors[m].mwidth, | |||
3981 | monitors->monitors[m].height, | |||
3982 | monitors->monitors[m].mheight, | |||
3983 | monitors->monitors[m].x, | |||
3984 | monitors->monitors[m].y); | |||
3985 | for (o = 0; o < monitors->monitors[m].noutput; o++) { | |||
3986 | output_t *output = find_output_by_xid(monitors->monitors[m].outputs[o]); | |||
3987 | if (output) | |||
3988 | printf (" %s", output->output.string); | |||
3989 | else | |||
3990 | printf (" unknown output 0x%x\n", (CARD32) monitors->monitors[m].outputs[o]); | |||
3991 | } | |||
3992 | printf ("\n"); | |||
3993 | } | |||
3994 | } | |||
3995 | } | |||
3996 | ||||
3997 | sc = XRRGetScreenInfo (dpy, root); | |||
3998 | ||||
3999 | if (sc == NULL((void*)0)) | |||
4000 | exit (1); | |||
4001 | ||||
4002 | current_size = XRRConfigCurrentConfiguration (sc, ¤t_rotation); | |||
4003 | ||||
4004 | sizes = XRRConfigSizes(sc, &nsize); | |||
4005 | ||||
4006 | if (have_pixel_size) { | |||
4007 | for (size = 0; size < nsize; size++) | |||
4008 | { | |||
4009 | if (sizes[size].width == width && sizes[size].height == height) | |||
4010 | break; | |||
4011 | } | |||
4012 | if (size >= nsize) { | |||
4013 | fprintf (stderr__stderrp, | |||
4014 | "Size %dx%d not found in available modes\n", width, height); | |||
4015 | exit (1); | |||
4016 | } | |||
4017 | } | |||
4018 | else if (size < 0) | |||
4019 | size = current_size; | |||
4020 | else if (size >= nsize) { | |||
4021 | fprintf (stderr__stderrp, | |||
4022 | "Size index %d is too large, there are only %d sizes\n", | |||
4023 | size, nsize); | |||
4024 | exit (1); | |||
4025 | } | |||
4026 | ||||
4027 | if (rot < 0) | |||
4028 | { | |||
4029 | for (rot = 0; rot < 4; rot++) | |||
4030 | if (1 << rot == (current_rotation & 0xf)) | |||
4031 | break; | |||
4032 | } | |||
4033 | ||||
4034 | current_rate = XRRConfigCurrentRate (sc); | |||
4035 | ||||
4036 | if (rate < 0) | |||
4037 | { | |||
4038 | if (size == current_size) | |||
4039 | rate = current_rate; | |||
4040 | else | |||
4041 | rate = 0; | |||
4042 | } | |||
4043 | else | |||
4044 | { | |||
4045 | rates = XRRConfigRates (sc, size, &nrate); | |||
4046 | for (i = 0; i < nrate; i++) | |||
4047 | if (rate == rates[i]) | |||
4048 | break; | |||
4049 | if (i == nrate) { | |||
4050 | fprintf (stderr__stderrp, "Rate %.2f Hz not available for this size\n", rate); | |||
4051 | exit (1); | |||
4052 | } | |||
4053 | } | |||
4054 | ||||
4055 | if (version) { | |||
4056 | int major_version, minor_version; | |||
4057 | XRRQueryVersion (dpy, &major_version, &minor_version); | |||
4058 | printf("Server reports RandR version %d.%d\n", | |||
4059 | major_version, minor_version); | |||
4060 | } | |||
4061 | ||||
4062 | if (query || query_1) { | |||
4063 | printf(" SZ: Pixels Physical Refresh\n"); | |||
4064 | for (i = 0; i < nsize; i++) { | |||
4065 | int j; | |||
4066 | ||||
4067 | printf ("%c%-2d %5d x %-5d (%4dmm x%4dmm )", | |||
4068 | i == current_size ? '*' : ' ', | |||
4069 | i, sizes[i].width, sizes[i].height, | |||
4070 | sizes[i].mwidth, sizes[i].mheight); | |||
4071 | rates = XRRConfigRates (sc, i, &nrate); | |||
4072 | if (nrate) printf (" "); | |||
4073 | for (j = 0; j < nrate; j++) | |||
4074 | printf ("%c%-4d", | |||
4075 | i == current_size && rates[j] == current_rate ? '*' : ' ', | |||
4076 | rates[j]); | |||
4077 | printf ("\n"); | |||
4078 | } | |||
4079 | } | |||
4080 | ||||
4081 | { | |||
4082 | Rotation rotations = XRRConfigRotations(sc, ¤t_rotation); | |||
4083 | ||||
4084 | if (toggle_x && !(current_rotation & RR_Reflect_X16)) reflection |= RR_Reflect_X16; | |||
4085 | if (toggle_y && !(current_rotation & RR_Reflect_Y32)) reflection |= RR_Reflect_Y32; | |||
4086 | ||||
4087 | if (query) { | |||
4088 | printf("Current rotation - %s\n", | |||
4089 | rotation_name (current_rotation)); | |||
4090 | ||||
4091 | printf("Current reflection - %s\n", | |||
4092 | reflection_name (current_rotation)); | |||
4093 | ||||
4094 | printf ("Rotations possible - "); | |||
4095 | for (i = 0; i < 4; i ++) { | |||
4096 | if ((rotations >> i) & 1) printf("%s ", direction[i]); | |||
4097 | } | |||
4098 | printf ("\n"); | |||
4099 | ||||
4100 | printf ("Reflections possible - "); | |||
4101 | if (rotations & (RR_Reflect_X16|RR_Reflect_Y32)) | |||
4102 | { | |||
4103 | if (rotations & RR_Reflect_X16) printf ("X Axis "); | |||
4104 | if (rotations & RR_Reflect_Y32) printf ("Y Axis"); | |||
4105 | } | |||
4106 | else | |||
4107 | printf ("none"); | |||
4108 | printf ("\n"); | |||
4109 | } | |||
4110 | } | |||
4111 | ||||
4112 | if (verbose) { | |||
4113 | printf("Setting size to %d, rotation to %s\n", size, direction[rot]); | |||
4114 | ||||
4115 | printf ("Setting reflection on "); | |||
4116 | if (reflection) | |||
4117 | { | |||
4118 | if (reflection & RR_Reflect_X16) printf ("X Axis "); | |||
4119 | if (reflection & RR_Reflect_Y32) printf ("Y Axis"); | |||
4120 | } | |||
4121 | else | |||
4122 | printf ("neither axis"); | |||
4123 | printf ("\n"); | |||
4124 | } | |||
4125 | ||||
4126 | /* we should test configureNotify on the root window */ | |||
4127 | XSelectInput (dpy, root, StructureNotifyMask(1L<<17)); | |||
4128 | ||||
4129 | if (setit && !dryrun) XRRSelectInput (dpy, root, | |||
4130 | RRScreenChangeNotifyMask(1L << 0)); | |||
4131 | if (setit && !dryrun) { | |||
4132 | Rotation rotation = 1 << rot; | |||
4133 | status = XRRSetScreenConfigAndRate (dpy, sc, root, (SizeID) size, | |||
4134 | (Rotation) (rotation | reflection), | |||
4135 | rate, CurrentTime0L); | |||
4136 | } | |||
4137 | ||||
4138 | if (setit && !dryrun && status == RRSetConfigFailed3) { | |||
4139 | printf ("Failed to change the screen configuration!\n"); | |||
4140 | ret = 1; | |||
4141 | } | |||
4142 | ||||
4143 | if (verbose && setit && !dryrun && size != current_size) { | |||
4144 | if (status == RRSetConfigSuccess0) | |||
4145 | { | |||
4146 | Boolint seen_screen = False0; | |||
4147 | while (!seen_screen) { | |||
4148 | int spo; | |||
4149 | XNextEvent(dpy, (XEvent *) &event); | |||
4150 | ||||
4151 | printf ("Event received, type = %d\n", event.type); | |||
4152 | /* update Xlib's knowledge of the event */ | |||
4153 | XRRUpdateConfiguration (&event); | |||
4154 | if (event.type == ConfigureNotify22) | |||
4155 | printf("Received ConfigureNotify Event!\n"); | |||
4156 | ||||
4157 | switch (event.type - event_base) { | |||
4158 | case RRScreenChangeNotify0: | |||
4159 | sce = (XRRScreenChangeNotifyEvent *) &event; | |||
4160 | ||||
4161 | printf("Got a screen change notify event!\n"); | |||
4162 | printf(" window = %d\n root = %d\n size_index = %d\n rotation %d\n", | |||
4163 | (int) sce->window, (int) sce->root, | |||
4164 | sce->size_index, sce->rotation); | |||
4165 | printf(" timestamp = %ld, config_timestamp = %ld\n", | |||
4166 | sce->timestamp, sce->config_timestamp); | |||
4167 | printf(" Rotation = %x\n", sce->rotation); | |||
4168 | printf(" %d X %d pixels, %d X %d mm\n", | |||
4169 | sce->width, sce->height, sce->mwidth, sce->mheight); | |||
4170 | printf("Display width %d, height %d\n", | |||
4171 | DisplayWidth(dpy, screen)((&((_XPrivDisplay)(dpy))->screens[screen])->width), DisplayHeight(dpy, screen)((&((_XPrivDisplay)(dpy))->screens[screen])->height )); | |||
4172 | printf("Display widthmm %d, heightmm %d\n", | |||
4173 | DisplayWidthMM(dpy, screen)((&((_XPrivDisplay)(dpy))->screens[screen])->mwidth ), DisplayHeightMM(dpy, screen)((&((_XPrivDisplay)(dpy))->screens[screen])->mheight )); | |||
4174 | spo = sce->subpixel_order; | |||
4175 | if ((spo < 0) || (spo > 5)) | |||
4176 | printf ("Unknown subpixel order, value = %d\n", spo); | |||
4177 | else printf ("new Subpixel rendering model is %s\n", order[spo]); | |||
4178 | seen_screen = True1; | |||
4179 | break; | |||
4180 | default: | |||
4181 | if (event.type != ConfigureNotify22) | |||
4182 | printf("unknown event received, type = %d!\n", event.type); | |||
4183 | } | |||
4184 | } | |||
4185 | } | |||
4186 | } | |||
4187 | XRRFreeScreenConfigInfo(sc); | |||
4188 | return(ret); | |||
4189 | } |