2 * Copyright © 2001 Keith Packard, member of The XFree86 Project, Inc.
3 * Copyright © 2002 Hewlett Packard Company, Inc.
4 * Copyright © 2006 Intel Corporation
6 * Permission to use, copy, modify, distribute, and sell this software and its
7 * documentation for any purpose is hereby granted without fee, provided that
8 * the above copyright notice appear in all copies and that both that copyright
9 * notice and this permission notice appear in supporting documentation, and
10 * that the name of the copyright holders not be used in advertising or
11 * publicity pertaining to distribution of the software without specific,
12 * written prior permission. The copyright holders make no representations
13 * about the suitability of this software for any purpose. It is provided "as
14 * is" without express or implied warranty.
16 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
19 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
20 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
21 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
27 * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
29 * Permission is hereby granted, free of charge, to any person obtaining a
30 * copy of this software and associated documentation files (the "Software"),
31 * to deal in the Software without restriction, including without limitation
32 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
33 * and/or sell copies of the Software, and to permit persons to whom the
34 * Software is furnished to do so, subject to the following conditions:
36 * The above copyright notice and this permission notice (including the next
37 * paragraph) shall be included in all copies or substantial portions of the
40 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
41 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
42 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
43 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
44 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
45 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
46 * DEALINGS IN THE SOFTWARE.
52 #include <X11/Xlibint.h>
53 #include <X11/Xproto.h>
54 #include <X11/extensions/Xrandr.h>
65 static char *program_name
;
66 static Display
*dpy
= NULL
;
67 static Window root
, win
;
69 static Bool nosideview
= False
;
70 static Bool verbose
= False
;
71 static Bool testrun
= False
;
72 static int had_error
= 0;
73 static XErrorHandler prev_handler
;
74 static int cur_keycode
;
75 static struct timeval time_val
;
76 static Rotation init_rotation
;
79 static Bool use_init_pos
= False
;
80 static Bool need_off_deferred
= False
;
85 fprintf(stderr
, "usage: %s [options]\n", program_name
);
86 fprintf(stderr
, " where options are:\n");
87 fprintf(stderr
, " -toggle or -t\n");
88 fprintf(stderr
, " -listen or -l\n");
89 fprintf(stderr
, " -display <display> or -d <display>\n");
90 fprintf(stderr
, " -key <key> or -k <key>\n");
91 fprintf(stderr
, " -mod <modifier> or -m <modifier>\n");
92 fprintf(stderr
, " -help\n");
93 fprintf(stderr
, " -nosideview\n");
94 fprintf(stderr
, " -verbose or -v\n");
95 fprintf(stderr
, " -testrun\n");
101 fatal (const char *format
, ...)
105 va_start (ap
, format
);
106 fprintf (stderr
, "%s exiting: ", program_name
);
107 vfprintf (stderr
, format
, ap
);
115 Display
*const err_display
,
116 XErrorEvent
*const err_event
)
118 had_error
= err_event
-> error_code
;
122 typedef enum _relation
{
123 left_of
, right_of
, above
, below
, same_as
,
126 typedef enum _changes
{
128 changes_crtc
= (1 << 0),
129 changes_mode
= (1 << 1),
130 changes_relation
= (1 << 2),
131 changes_position
= (1 << 3),
134 typedef enum _name_kind
{
136 name_string
= (1 << 0),
138 name_index
= (1 << 2),
148 typedef struct _crtc crtc_t
;
149 typedef struct _output output_t
;
153 XRRCrtcInfo
*crtc_info
;
155 XRRModeInfo
*mode_info
;
164 struct _output
*next
;
169 XRROutputInfo
*output_info
;
173 crtc_t
*current_crtc_info
;
177 XRRModeInfo
*mode_info
;
182 struct _output
*relative_to
;
188 static output_t
*outputs
= NULL
;
189 static output_t
**outputs_tail
= &outputs
;
190 static crtc_t
*crtcs
= NULL
;
191 static int num_crtcs
;
192 static XRRScreenResources
*res
= NULL
;
193 static int fb_width
= 0, fb_height
= 0;
194 static int fb_width_mm
= 0, fb_height_mm
= 0;
195 static float dpi
= 0.0;
196 static Bool dryrun
= False
;
197 static int minWidth
, maxWidth
, minHeight
, maxHeight
;
200 #define MAX_MODIFIERS 10
202 typedef struct _con_output con_output_t
;
206 XRRModeInfo
**smodes
;
211 typedef struct _mod_key_table mod_key_table_t
;
213 struct _mod_key_table
{
218 static con_output_t con_outputs
[MAX_OUTPUT
];
219 static con_output_t dis_con_outputs
[MAX_OUTPUT
];
220 static XRRModeInfo
*start_mode
[MAX_OUTPUT
];
221 static XRRModeInfo
*new_mode
[MAX_OUTPUT
];
222 static int start
= 0;
225 static Bool do_not_switch
= False
;
226 static Bool did_init
= False
;
228 static mod_key_table_t mod_key_table
[MAX_MODIFIERS
] = {
230 {"shift", ShiftMask
},
232 {"control", ControlMask
},
242 mode_height (XRRModeInfo
*mode_info
, Rotation rotation
)
244 switch (rotation
& 0xf) {
247 return mode_info
->height
;
250 return mode_info
->width
;
257 mode_width (XRRModeInfo
*mode_info
, Rotation rotation
)
259 switch (rotation
& 0xf) {
262 return mode_info
->width
;
265 return mode_info
->height
;
271 /* v refresh frequency in Hz */
273 mode_refresh (XRRModeInfo
*mode_info
)
277 if (mode_info
->hTotal
&& mode_info
->vTotal
)
278 rate
= ((float) mode_info
->dotClock
/
279 ((float) mode_info
->hTotal
* (float) mode_info
->vTotal
));
287 init_name (name_t
*name
)
289 name
->kind
= name_none
;
293 set_name_string (name_t
*name
, char *string
)
295 name
->kind
|= name_string
;
296 name
->string
= string
;
300 set_name_xid (name_t
*name
, XID xid
)
302 name
->kind
|= name_xid
;
307 set_name_index (name_t
*name
, int index
)
309 name
->kind
|= name_index
;
314 set_name_all (name_t
*name
, name_t
*old
)
316 if (old
->kind
& name_xid
)
317 name
->xid
= old
->xid
;
318 if (old
->kind
& name_string
)
319 name
->string
= old
->string
;
320 if (old
->kind
& name_index
)
321 name
->index
= old
->index
;
322 name
->kind
|= old
->kind
;
328 output_t
*output
= calloc (1, sizeof (output_t
));
331 fatal ("out of memory");
333 *outputs_tail
= output
;
334 outputs_tail
= &output
->next
;
339 find_output (name_t
*name
)
343 for (output
= outputs
; output
; output
= output
->next
)
345 name_kind_t common
= name
->kind
& output
->output
.kind
;
347 if ((common
& name_xid
) && name
->xid
== output
->output
.xid
)
349 if ((common
& name_string
) && !strcmp (name
->string
, output
->output
.string
))
351 if ((common
& name_index
) && name
->index
== output
->output
.index
)
358 find_output_by_xid (RROutput output
)
362 init_name (&output_name
);
363 set_name_xid (&output_name
, output
);
364 return find_output (&output_name
);
368 find_crtc (name_t
*name
)
373 for (c
= 0; c
< num_crtcs
; c
++)
378 common
= name
->kind
& crtc
->crtc
.kind
;
380 if ((common
& name_xid
) && name
->xid
== crtc
->crtc
.xid
)
382 if ((common
& name_string
) && !strcmp (name
->string
, crtc
->crtc
.string
))
384 if ((common
& name_index
) && name
->index
== crtc
->crtc
.index
)
392 find_crtc_by_xid (RRCrtc crtc
)
396 init_name (&crtc_name
);
397 set_name_xid (&crtc_name
, crtc
);
398 return find_crtc (&crtc_name
);
402 find_mode (name_t
*name
)
405 XRRModeInfo
*best
= NULL
;
407 for (m
= 0; m
< res
->nmode
; m
++)
409 XRRModeInfo
*mode
= &res
->modes
[m
];
410 if ((name
->kind
& name_xid
) && name
->xid
== mode
->id
)
420 find_mode_by_xid (RRMode mode
)
424 init_name (&mode_name
);
425 set_name_xid (&mode_name
, mode
);
426 return find_mode (&mode_name
);
430 set_output_info (output_t
*output
, RROutput xid
, XRROutputInfo
*output_info
)
434 /* sanity check output info */
435 if (output_info
->connection
!= RR_Disconnected
&& !output_info
->nmode
)
436 fatal ("Output %s is not disconnected but has no modes\n",
439 /* set output name and info */
440 if (!(output
->output
.kind
& name_xid
))
441 set_name_xid (&output
->output
, xid
);
442 if (!(output
->output
.kind
& name_string
))
443 set_name_string (&output
->output
, output_info
->name
);
444 output
->output_info
= output_info
;
446 crtc
= find_crtc_by_xid (output
->output_info
->crtc
);
448 if (crtc
&& crtc
->crtc_info
) {
449 output
->x
= crtc
->crtc_info
->x
;
450 output
->y
= crtc
->crtc_info
->y
;
454 output
->rotation
&= ~0xf;
455 if (crtc
&& crtc
->crtc_info
)
456 output
->rotation
|= (crtc
->crtc_info
->rotation
& 0xf);
458 output
->rotation
= RR_Rotate_0
;
467 num_crtcs
= res
->ncrtc
;
470 for (c
= 0; c
< res
->ncrtc
; c
++)
472 if (crtcs
[c
].crtc_info
)
473 XRRFreeCrtcInfo (crtcs
[c
].crtc_info
);
479 crtcs
= calloc (num_crtcs
, sizeof (crtc_t
));
480 if (!crtcs
) fatal ("out of memory");
482 for (c
= 0; c
< res
->ncrtc
; c
++)
484 XRRCrtcInfo
*crtc_info
= XRRGetCrtcInfo (dpy
, res
, res
->crtcs
[c
]);
485 set_name_xid (&crtcs
[c
].crtc
, res
->crtcs
[c
]);
486 set_name_index (&crtcs
[c
].crtc
, c
);
487 if (!crtc_info
) fatal ("could not get crtc 0x%x information", res
->crtcs
[c
]);
488 crtcs
[c
].crtc_info
= crtc_info
;
489 if (crtc_info
->mode
== None
)
491 crtcs
[c
].mode_info
= NULL
;
494 crtcs
[c
].rotation
= RR_Rotate_0
;
500 crtc_add_output (crtc_t
*crtc
, output_t
*output
)
503 crtc
->outputs
= realloc (crtc
->outputs
, (crtc
->noutput
+ 1) * sizeof (output_t
*));
506 crtc
->outputs
= calloc (1, sizeof (output_t
*));
509 crtc
->rotation
= output
->rotation
;
510 crtc
->mode_info
= output
->mode_info
;
512 if (!crtc
->outputs
) fatal ("out of memory");
513 crtc
->outputs
[crtc
->noutput
++] = output
;
522 for (i
= 0; i
< ncon
; i
++) {
523 output
= con_outputs
[i
].output
;
524 if (!output
->mode_info
) continue;
525 if (output
->crtc_info
)
526 crtc_add_output (output
->crtc_info
, output
);
531 reset_crtcs_for_outputs (void)
535 for (output
= outputs
; output
; output
= output
->next
)
537 if ((output
->crtc_info
) && (output
->crtc_info
->outputs
)) {
538 free (output
->crtc_info
->outputs
);
539 output
->crtc_info
= NULL
;
545 crtc_disable (crtc_t
*crtc
)
548 fprintf (stderr
, "crtc %d (0x%lx) : disable\n", crtc
->crtc
.index
, crtc
->crtc
.xid
);
551 return RRSetConfigSuccess
;
553 return XRRSetCrtcConfig (dpy
, res
, crtc
->crtc
.xid
, CurrentTime
,
554 0, 0, None
, RR_Rotate_0
, NULL
, 0);
558 crtc_revert (crtc_t
*crtc
)
560 XRRCrtcInfo
*crtc_info
= crtc
->crtc_info
;
563 fprintf (stderr
, "crtc %d: revert\n", crtc
->crtc
.index
);
566 return RRSetConfigSuccess
;
567 return XRRSetCrtcConfig (dpy
, res
, crtc
->crtc
.xid
, CurrentTime
,
568 crtc_info
->x
, crtc_info
->y
,
569 crtc_info
->mode
, crtc_info
->rotation
,
570 crtc_info
->outputs
, crtc_info
->noutput
);
574 crtc_apply (crtc_t
*crtc
)
576 RROutput
*rr_outputs
;
581 if (!crtc
->mode_info
)
582 return RRSetConfigSuccess
;
584 rr_outputs
= calloc (crtc
->noutput
, sizeof (RROutput
));
587 for (o
= 0; o
< crtc
->noutput
; o
++)
588 rr_outputs
[o
] = crtc
->outputs
[o
]->output
.xid
;
589 mode
= crtc
->mode_info
->id
;
591 fprintf (stderr
, "crtc %d (0x%lx) : %12s %6.1f +%d+%d", crtc
->crtc
.index
,
593 crtc
->mode_info
->name
, mode_refresh (crtc
->mode_info
),
595 for (o
= 0; o
< crtc
->noutput
; o
++)
596 fprintf (stderr
, " \"%s\"", crtc
->outputs
[o
]->output
.string
);
597 fprintf (stderr
, "\n");
600 s
= RRSetConfigSuccess
;
602 s
= XRRSetCrtcConfig (dpy
, res
, crtc
->crtc
.xid
, CurrentTime
,
603 crtc
->x
, crtc
->y
, mode
, crtc
->rotation
,
604 rr_outputs
, crtc
->noutput
);
613 fprintf (stderr
, "screen %d: revert\n", screen
);
617 XRRSetScreenSize (dpy
, root
,
618 DisplayWidth (dpy
, screen
),
619 DisplayHeight (dpy
, screen
),
620 DisplayWidthMM (dpy
, screen
),
621 DisplayHeightMM (dpy
, screen
));
627 /* comment it out because DisplayWidth() does not reflect the
628 change of fb_width and fb_height previously set by
632 if (fb_width == DisplayWidth (dpy, screen) &&
633 fb_height == DisplayHeight (dpy, screen) &&
634 fb_width_mm == DisplayWidthMM (dpy, screen) &&
635 fb_height_mm == DisplayHeightMM (dpy, screen))
642 fprintf (stderr
, "screen %d: %dx%d %dx%d mm %6.2fdpi\n", screen
,
643 fb_width
, fb_height
, fb_width_mm
, fb_height_mm
, dpi
);
646 XRRSetScreenSize (dpy
, root
, fb_width
, fb_height
,
647 fb_width_mm
, fb_height_mm
);
656 /* first disable all crtcs */
657 for (c
= 0; c
< res
->ncrtc
; c
++)
658 crtc_disable (&crtcs
[c
]);
659 /* next reset screen size */
661 /* now restore all crtcs */
662 for (c
= 0; c
< res
->ncrtc
; c
++)
663 crtc_revert (&crtcs
[c
]);
667 * uh-oh, something bad happened in the middle of changing
668 * the configuration. Revert to the previous configuration
672 panic (Status s
, crtc_t
*crtc
)
674 int c
= crtc
->crtc
.index
;
678 case RRSetConfigSuccess
: message
= "succeeded"; break;
679 case BadAlloc
: message
= "out of memory"; break;
680 case RRSetConfigFailed
: message
= "failed"; break;
681 case RRSetConfigInvalidConfigTime
: message
= "invalid config time"; break;
682 case RRSetConfigInvalidTime
: message
= "invalid time"; break;
683 default: message
= "unknown failure"; break;
686 fprintf (stderr
, "%s: Configure crtc %d %s\n", program_name
, c
, message
);
698 * Turn off any crtcs which are to be disabled or which are
699 * larger than the target size
701 for (c
= 0; c
< res
->ncrtc
; c
++)
703 crtc_t
*crtc
= &crtcs
[c
];
704 XRRCrtcInfo
*crtc_info
= crtc
->crtc_info
;
707 * if this crtc is already disabled, skip it
708 * Note server sets crtc_info->mode (before change)
710 if (crtc_info
->mode
== None
)
714 * If this crtc is to be left enabled, make
715 * sure the old size fits then new screen
716 * When crtc->mode_info is null, the crtc is to be
717 * disabled. Note set_crtcs () sets crtc->mode_info for
718 * new mode (to be changed to).
722 XRRModeInfo
*old_mode
= find_mode_by_xid (crtc_info
->mode
);
726 panic (RRSetConfigFailed
, crtc
);
728 /* old position and size information */
731 w
= mode_width (old_mode
, crtc_info
->rotation
);
732 h
= mode_height (old_mode
, crtc_info
->rotation
);
734 /* if it fits, skip it */
735 if (x
+ w
<= fb_width
&& y
+ h
<= fb_height
)
739 if (need_off_deferred
)
740 /* Defer taking off */
743 s
= crtc_disable (crtc
);
744 if (s
!= RRSetConfigSuccess
)
749 * Hold the server grabbed while messing with
750 * the screen so that apps which notice the resize
751 * event and ask for xinerama information from the server
752 * receive up-to-date information
757 * Set the screen size
765 for (c
= 0; c
< res
->ncrtc
; c
++)
767 crtc_t
*crtc
= &crtcs
[c
];
769 s
= crtc_apply (crtc
);
770 if (s
!= RRSetConfigSuccess
)
774 * Release the server grab and let all clients
775 * respond to the updated state
781 * Use current output state to complete the output list
788 for (o
= 0; o
< res
->noutput
; o
++)
790 XRROutputInfo
*output_info
= XRRGetOutputInfo (dpy
, res
, res
->outputs
[o
]);
794 if (!output_info
) fatal ("could not get output 0x%x information", res
->outputs
[o
]);
795 set_name_xid (&output_name
, res
->outputs
[o
]);
796 set_name_index (&output_name
, o
);
797 set_name_string (&output_name
, output_info
->name
);
798 output
= find_output (&output_name
);
801 output
= add_output ();
802 set_name_all (&output
->output
, &output_name
);
805 set_output_info (output
, res
->outputs
[o
], output_info
);
811 * Test whether 'crtc' can be used for 'output'
814 check_crtc_for_output (crtc_t
*crtc
, output_t
*output
)
820 for (i
= 0; i
< ncon
; i
++)
822 other
= con_outputs
[i
].output
;
827 if (other
->mode_info
== NULL
)
830 if (other
->crtc_info
!= crtc
)
833 /* see if the output connected to the crtc can clone to this output */
834 for (l
= 0; l
< output
->output_info
->nclone
; l
++)
835 if (output
->output_info
->clones
[l
] == other
->output
.xid
)
837 /* not on the list, can't clone */
838 if (l
== output
->output_info
->nclone
)
844 for (i
= 0; i
< crtc
->noutput
; i
++)
845 /* Check if the output is to be turned on */
846 if (crtc
->outputs
[i
]->mode_info
) {
847 /* make sure the state matches */
848 if (crtc
->mode_info
!= output
->mode_info
)
850 if (crtc
->x
!= output
->x
)
852 if (crtc
->y
!= output
->y
)
854 if (crtc
->rotation
!= output
->rotation
)
862 find_crtc_for_output (output_t
*output
)
866 for (c
= 0; c
< output
->output_info
->ncrtc
; c
++)
870 crtc
= find_crtc_by_xid (output
->output_info
->crtcs
[c
]);
871 if (!crtc
) fatal ("cannot find crtc 0x%x\n", output
->output_info
->crtcs
[c
]);
873 if (check_crtc_for_output (crtc
, output
))
891 for (i
= 0; i
< ncon
; i
++)
893 output_t
*output
= con_outputs
[i
].output
;
896 if (!(output
->changes
& changes_relation
)) continue;
898 if (output
->mode_info
== NULL
) continue;
900 relation
= output
->relative_to
;
902 if (relation
->mode_info
== NULL
)
906 output
->changes
|= changes_position
;
911 * Make sure the dependent object has been set in place
913 if ((relation
->changes
& changes_relation
) &&
914 !(relation
->changes
& changes_position
))
920 switch (output
->relation
) {
922 output
->y
= relation
->y
;
923 output
->x
= relation
->x
- mode_width (output
->mode_info
, output
->rotation
);
926 output
->y
= relation
->y
;
927 output
->x
= relation
->x
+ mode_width (relation
->mode_info
, relation
->rotation
);
930 output
->x
= relation
->x
;
931 output
->y
= relation
->y
- mode_height (output
->mode_info
, output
->rotation
);
934 output
->x
= relation
->x
;
935 output
->y
= relation
->y
+ mode_height (relation
->mode_info
, relation
->rotation
);
938 output
->x
= relation
->x
;
939 output
->y
= relation
->y
;
941 output
->changes
|= changes_position
;
942 relation
->changes
|= changes_position
;
948 fatal ("loop in relative position specifications\n");
952 * Now normalize positions so the upper left corner of all outputs is at 0,0
956 for (i
= 0; i
< ncon
; i
++)
958 output_t
*output
= con_outputs
[i
].output
;
960 if (output
->mode_info
== NULL
) continue;
962 if (output
->x
< min_x
) min_x
= output
->x
;
963 if (output
->y
< min_y
) min_y
= output
->y
;
967 /* move all outputs */
968 for (i
= 0; i
< ncon
; i
++)
970 output_t
*output
= con_outputs
[i
].output
;
972 if (output
->mode_info
== NULL
) continue;
976 output
->changes
|= changes_position
;
982 set_screen_size (void)
986 fb_width
= fb_height
= 0;
988 for (i
= 0; i
< ncon
; i
++)
990 output_t
*output
= con_outputs
[i
].output
;
991 XRRModeInfo
*mode_info
= output
->mode_info
;
994 if (!mode_info
) continue;
998 w
= mode_width (mode_info
, output
->rotation
);
999 h
= mode_height (mode_info
, output
->rotation
);
1000 if (x
+ w
> fb_width
) fb_width
= x
+ w
;
1001 if (y
+ h
> fb_height
) fb_height
= y
+ h
;
1004 if (fb_width
> maxWidth
|| fb_height
> maxHeight
) {
1006 fprintf (stderr
, "screen cannot be larger than %dx%d (desired size %dx%d)\n",
1007 maxWidth
, maxHeight
, fb_width
, fb_height
);
1011 if (fb_width
< minWidth
) fb_width
= minWidth
;
1012 if (fb_height
< minHeight
) fb_height
= minHeight
;
1018 disable_outputs (output_t
*outputs
)
1022 outputs
->crtc_info
= NULL
;
1023 outputs
= outputs
->next
;
1028 * find the best mapping from output to crtc available
1031 pick_crtcs_score (output_t
*outputs
)
1044 outputs
= outputs
->next
;
1046 * Score with this output disabled
1048 output
->crtc_info
= NULL
;
1049 best_score
= pick_crtcs_score (outputs
);
1050 if (output
->mode_info
== NULL
)
1055 * Now score with this output any valid crtc
1057 for (c
= 0; c
< output
->output_info
->ncrtc
; c
++)
1061 crtc
= find_crtc_by_xid (output
->output_info
->crtcs
[c
]);
1063 fatal ("cannot find crtc 0x%x\n", output
->output_info
->crtcs
[c
]);
1065 /* reset crtc allocation for following outputs */
1066 disable_outputs (outputs
);
1067 if (!check_crtc_for_output (crtc
, output
))
1071 /* slight preference for existing connections */
1072 if (crtc
== output
->current_crtc_info
)
1075 output
->crtc_info
= crtc
;
1076 score
= my_score
+ pick_crtcs_score (outputs
);
1077 if (score
> best_score
)
1083 if (output
->crtc_info
!= best_crtc
)
1084 output
->crtc_info
= best_crtc
;
1086 * Reset other outputs based on this one using the best crtc
1088 (void) pick_crtcs_score (outputs
);
1094 * Pick crtcs for any changing outputs that don't have one
1103 * First try to match up newly enabled outputs with spare crtcs
1105 for (i
= 0; i
< ncon
; i
++)
1107 output
= con_outputs
[i
].output
;
1109 if (output
->mode_info
)
1111 if (output
->crtc_info
) {
1112 if (output
->crtc_info
->crtc_info
->noutput
> 0 &&
1113 (output
->crtc_info
->crtc_info
->noutput
> 1 ||
1114 output
!= find_output_by_xid (output
->crtc_info
->crtc_info
->outputs
[0])))
1117 output
->crtc_info
= find_crtc_for_output (output
);
1118 if (!output
->crtc_info
)
1122 fprintf(stderr
, "picked crtc 0x%lx for output %d (%s)\n",
1123 output
->crtc_info
->crtc
.xid
, i
, output
->output_info
->name
);
1135 * When the simple way fails, see if there is a way
1136 * to swap crtcs around and make things work
1138 for (output
= outputs
; output
; output
= output
->next
)
1139 output
->current_crtc_info
= output
->crtc_info
;
1140 pick_crtcs_score (outputs
);
1141 for (output
= outputs
; output
; output
= output
->next
)
1143 if (output
->mode_info
&& !output
->crtc_info
) {
1145 fprintf (stderr
, "cannot find crtc for output %s\n",
1146 output
->output
.string
);
1155 probe_and_check_output_changes (void) {
1156 XRRScreenResources
*new_res
= NULL
;
1157 int changed
= False
;
1160 new_res
= XRRGetScreenResources (dpy
, root
);
1162 fatal ("could not get screen resources");
1164 if ((new_res
->noutput
!= res
->noutput
) || (new_res
->nmode
!= res
->nmode
) ||
1165 (new_res
->ncrtc
!= res
->ncrtc
))
1168 for (i
= 0; i
< new_res
->noutput
; i
++)
1169 if (new_res
->outputs
[i
] != res
->outputs
[i
]) {
1173 for (i
= 0; i
< new_res
->nmode
; i
++)
1174 if (new_res
->modes
[i
].id
!= res
->modes
[i
].id
) {
1178 for (i
= 0; i
< new_res
->ncrtc
; i
++) {
1179 crtc_t
*crtc
= NULL
; /* old */
1180 XRRCrtcInfo
*crtc_info
= NULL
; /* new */
1182 crtc
= find_crtc_by_xid (res
->crtcs
[i
]);
1183 crtc_info
= XRRGetCrtcInfo (dpy
, new_res
,
1186 if (!crtc
|| !crtc_info
) {
1190 if (!crtc
->mode_info
&& !find_mode_by_xid (crtc_info
->mode
))
1192 if ((crtc_info
->x
!= crtc
->x
) ||
1193 (crtc_info
->y
!= crtc
->y
) ||
1194 (find_mode_by_xid (crtc_info
->mode
) != crtc
->mode_info
) ||
1195 (crtc_info
->rotation
!= crtc
->rotation
)) {
1204 XRRFreeScreenResources(res
);
1208 fprintf(stderr
, "probed: output status changed\n");
1213 fprintf(stderr
, "probed: no output status change\n");
1219 struct timeval cur_time_val
;
1220 long long cur
, prev
;
1222 X_GETTIMEOFDAY(&cur_time_val
);
1223 cur
= (long long) cur_time_val
.tv_sec
* 1000000 + cur_time_val
.tv_usec
;
1224 prev
=(long long) time_val
.tv_sec
* 1000000 + time_val
.tv_usec
;
1225 if (((cur
- prev
) < 0) || ((cur
- prev
) > 5000000))
1232 mode_sort (const void *p1
, void *p2
)
1234 XRRModeInfo
*mi1
= * (XRRModeInfo
**) p1
;
1235 XRRModeInfo
*mi2
= * (XRRModeInfo
**) p2
;
1237 if ((mi1
->width
== mi2
->width
) && (mi1
->height
== mi2
->height
)) {
1238 if (mode_refresh(mi1
) && mode_refresh(mi2
)) {
1239 if (mode_refresh(mi1
) < mode_refresh(mi2
))
1241 if (mode_refresh(mi1
) > mode_refresh(mi2
))
1247 if ((mi1
->width
== mi2
->width
) && (mi1
->height
< mi2
->height
))
1249 if ((mi1
->width
== mi2
->width
) && (mi1
->height
> mi2
->height
))
1251 if (mi1
->width
< mi2
->width
)
1253 if (mi1
->width
> mi2
->width
)
1260 output_sort (const void *p1
, const void *p2
) {
1261 con_output_t co1
= * (con_output_t
*) p1
;
1262 con_output_t co2
= * (con_output_t
*) p2
;
1263 int ncrtc1
= co1
.output
->output_info
->ncrtc
;
1264 int ncrtc2
= co2
.output
->output_info
->ncrtc
;
1265 char *name1
= co1
.output
->output_info
->name
;
1266 char *name2
= co2
.output
->output_info
->name
;
1268 if (ncrtc1
== ncrtc2
)
1269 return (strcmp(name1
, name2
));
1270 if (ncrtc1
< ncrtc2
)
1277 get_common_mode(con_output_t
*c0
, con_output_t
*c1
, int *m0
, int *m1
) {
1279 int i1
= -1, j1
= -1, i2
= -1, j2
= -1;
1281 output_t
*output
= c0
->output
;
1285 if (!c0
||!c1
|| !c0
->smodes
|| !c1
->smodes
)
1288 /* first try to find mode with common same size */
1289 for (i
= 0; i
< c0
->nsmodes
; i
++) {
1290 for (j
= 0; j
< c1
->nsmodes
; j
++)
1291 if ((c0
->smodes
[i
]->width
== c1
->smodes
[j
]->width
) &&
1292 (c0
->smodes
[i
]->height
== c1
->smodes
[j
]->height
)) {
1295 w
= mode_width (c0
->smodes
[i
], output
->rotation
);
1296 h
= mode_height (c0
->smodes
[i
], output
->rotation
);
1297 if ((x
+ w
<= maxWidth
) && (y
+ h
<= maxHeight
)) {
1302 if ((i1
!= -1) && (j1
!= -1))
1306 if ((i1
== -1) && (j1
== -1))
1309 /* then try to find mode with common id for possible cloning */
1310 for (i
= 0; i
< c0
->nsmodes
; i
++) {
1311 for (j
= 0; j
< c1
->nsmodes
; j
++)
1312 if (c0
->smodes
[i
] == c1
->smodes
[j
]) {
1315 w
= mode_width (c0
->smodes
[i
], output
->rotation
);
1316 h
= mode_height (c0
->smodes
[i
], output
->rotation
);
1317 if ((x
+ w
<= maxWidth
) && (y
+ h
<= maxHeight
)) {
1322 if ((i2
!= -1) && (j2
!= -1))
1326 if ((i2
== -1) && (j2
== -1)) {
1330 /* use common id if it is not smaller */
1331 if ((mode_width (c0
->smodes
[i1
], output
->rotation
) >
1332 mode_width (c0
->smodes
[i2
], output
->rotation
)) &&
1333 (mode_height (c0
->smodes
[i1
], output
->rotation
) >
1334 mode_height (c0
->smodes
[i2
], output
->rotation
))) {
1346 static XRRModeInfo
*
1347 get_largest_mode (con_output_t
*c
, XRRModeInfo
*start_mode
) {
1348 int i
, found
= False
;
1349 output_t
*output
= c
->output
;
1351 for (i
= 0; i
< c
->nsmodes
; i
++) {
1352 XRRModeInfo
*mode_info
= c
->smodes
[i
];
1355 if (!found
&& (start_mode
!= mode_info
))
1363 w
= mode_width (mode_info
, output
->rotation
);
1364 h
= mode_height (mode_info
, output
->rotation
);
1365 if ((x
+ w
<= maxWidth
) && (y
+ h
<= maxHeight
))
1371 return c
->smodes
[i
];
1373 fatal("cannot find mode");
1378 valid_mode(con_output_t
*con
, XRRModeInfo
*mode
) {
1381 for (i
= 0; i
< con
->nsmodes
; i
++)
1382 if (con
->smodes
[i
] == mode
)
1394 /* Initialize con_outputs array */
1395 for (i
= 0; i
< MAX_OUTPUT
; i
++) {
1396 con_outputs
[i
].output
= NULL
;
1397 con_outputs
[i
].on
= False
;
1398 start_mode
[i
] = NULL
;
1404 init_rotation
= RR_Rotate_0
;
1410 for (output
= outputs
; output
; output
= output
->next
) {
1411 XRROutputInfo
*output_info
= output
->output_info
;
1413 if (output_info
->connection
== RR_Connected
) {
1414 con_outputs
[ncon
].output
= output
;
1415 con_outputs
[ncon
].nsmodes
= 0;
1416 for (j
= 0; j
< output_info
->nmode
; j
++) {
1417 XRRModeInfo
*rmode
= find_mode_by_xid (output_info
->modes
[j
]);
1419 con_outputs
[ncon
].smodes
=
1420 realloc(con_outputs
[ncon
].smodes
,
1421 (con_outputs
[ncon
].nsmodes
+ 1) * sizeof (XRRModeInfo
*));
1422 con_outputs
[ncon
].smodes
[j
] = rmode
;
1423 con_outputs
[ncon
].nsmodes
++;
1426 /* Sort the modes */
1427 qsort((void *) con_outputs
[ncon
].smodes
,
1428 con_outputs
[ncon
].nsmodes
, sizeof(XRRModeInfo
*),
1429 (int (*) (const void *, const void *)) mode_sort
);
1431 if (output_info
->crtc
) {
1434 con_outputs
[ncon
].on
= True
;
1435 for (j
= 0; j
< output_info
->ncrtc
; j
++) {
1436 if (output_info
->crtcs
[j
] == output_info
->crtc
)
1438 if (j
== output_info
->ncrtc
) {
1440 fatal ("crtc does not match for output\n");
1443 /* set initial mode_info */
1444 crtc
= find_crtc_by_xid (output_info
->crtc
);
1446 con_outputs
[ncon
].output
->mode_info
=
1447 find_mode_by_xid (crtc
->crtc_info
->mode
);
1450 con_outputs
[ncon
].on
= False
;
1452 } else if (output_info
->connection
== RR_Disconnected
) {
1453 dis_con_outputs
[dis_ncon
].output
= output
;
1458 qsort((void **) con_outputs
, ncon
,
1459 sizeof(con_output_t
), (int (*) (const void *, const void *)) output_sort
);
1462 fprintf(stderr
, "Total connected outputs = %d :\n", ncon
);
1463 for (j
= 0; j
< ncon
; j
++) {
1464 fprintf(stderr
, "%d (%s): top mode = %s, rotation = %d, crtcs =", j
,
1465 con_outputs
[j
].output
->output_info
->name
,
1466 con_outputs
[j
].smodes
[0]->name
,
1467 con_outputs
[j
].output
->rotation
);
1468 for (i
= 0; i
< con_outputs
[j
].output
->output_info
->ncrtc
; i
++)
1469 fprintf(stderr
, " 0x%lx", con_outputs
[j
].output
->output_info
->crtcs
[i
]);
1470 fprintf(stderr
, ", using 0x%lx", con_outputs
[j
].output
->output_info
->crtc
);
1471 fprintf(stderr
, "\n");
1473 fprintf(stderr
, "Total disconnected outputs = %d :\n", dis_ncon
);
1474 for (j
= 0; j
< dis_ncon
; j
++) {
1475 fprintf(stderr
, "%d (%s) : number of crtcs %d =", j
,
1476 dis_con_outputs
[j
].output
->output_info
->name
,
1477 dis_con_outputs
[j
].output
->output_info
->ncrtc
);
1478 for (i
= 0; i
< dis_con_outputs
[j
].output
->output_info
->ncrtc
; i
++)
1479 fprintf(stderr
, " 0x%lx", dis_con_outputs
[j
].output
->output_info
->crtcs
[i
]);
1480 fprintf(stderr
, ", using 0x%lx", dis_con_outputs
[j
].output
->output_info
->crtc
);
1481 fprintf(stderr
, "\n");
1485 i
= con_outputs
[2].on
* 4 + con_outputs
[1].on
* 2 + con_outputs
[0].on
;
1487 if ((i
== 1) || (i
== 2) || (i
== 4)) {
1488 use_init_pos
= True
;
1491 /* remember position and mode info in single state */
1492 start_mode
[j
] = con_outputs
[j
].output
->mode_info
;
1493 init_rotation
= con_outputs
[j
].output
->rotation
;
1494 init_x
= con_outputs
[j
].output
->x
;
1495 init_y
= con_outputs
[j
].output
->y
;
1497 use_init_pos
= False
;
1499 if ((ncon
!= 2) || (start
< 3))
1502 if ((ncon
< 1) || (ncon
> 3)) {
1503 if ((ncon
< 1) && verbose
)
1504 fprintf (stderr
, "warn: no connection\n");
1505 else if ((ncon
> 3) && verbose
)
1506 fprintf (stderr
, "warn: too many (more than 3) connections: %d: can't switch\n", ncon
);
1507 do_not_switch
= True
;
1516 grab_key (Display
*dpy
, int keysym
, unsigned int modifier
,
1520 int keycode
= XKeysymToKeycode(dpy
, keysym
);
1522 if (keycode
== NoSymbol
)
1523 fatal ("grab_key: keycode not defined for keysym 0x%x\n", keysym
);
1526 prev_handler
= XSetErrorHandler (cur_handler
);
1532 root
, True
, GrabModeAsync
, GrabModeAsync
);
1536 XSetErrorHandler (prev_handler
);
1538 XGetErrorText (dpy
, had_error
, msg
, sizeof (msg
));
1539 fatal ("XGrabKey: %s\n", msg
);
1543 fprintf(stderr
, "keycode to grab: %d\n", keycode
);
1558 for (i
= 0; i
< ncon
; i
++) {
1559 output_t
*output
= con_outputs
[i
].output
;
1562 output
->relation
= same_as
;
1563 output
->relative_to
= NULL
;
1567 output
->rotation
= init_rotation
;
1576 if (++start
> 5) start
= 1;
1579 if (++start
> 3) start
= 1;
1583 fprintf(stderr
, "current state = %d\n", start
);
1587 if (get_common_mode(&con_outputs
[0], &con_outputs
[1], &m0
, &m1
)) {
1588 new_mode
[0] = con_outputs
[0].smodes
[m0
];
1589 new_mode
[1] = con_outputs
[1].smodes
[m1
];
1591 new_mode
[0] = get_largest_mode (&con_outputs
[0],
1592 con_outputs
[0].smodes
[0]);
1593 new_mode
[1] = get_largest_mode (&con_outputs
[1],
1594 con_outputs
[1].smodes
[0]);
1597 if (start_mode
[start
-1] && valid_mode(&con_outputs
[start
-1],
1598 start_mode
[start
-1]))
1599 new_mode
[start
-1] = start_mode
[start
-1];
1601 if (con_outputs
[start
-1].smodes
[0])
1602 new_mode
[start
-1] =
1603 get_largest_mode (&con_outputs
[start
-1],
1604 con_outputs
[start
-1].smodes
[0]);
1610 if (++start
> 6) start
= 1;
1612 fprintf(stderr
, "current state = %d\n", start
);
1613 if ((start
== 1) || (start
== 2) || (start
== 4)) {
1631 if (start_mode
[i
] && valid_mode(&con_outputs
[i
], start_mode
[i
]))
1632 new_mode
[i
] = start_mode
[i
];
1634 if (con_outputs
[i
].smodes
[0])
1635 new_mode
[i
] = get_largest_mode (&con_outputs
[i
],
1636 con_outputs
[i
].smodes
[0]);
1642 if (get_common_mode(&con_outputs
[i
], &con_outputs
[j
], &m0
, &m1
)) {
1643 new_mode
[i
] = con_outputs
[i
].smodes
[m0
];
1644 new_mode
[j
] = con_outputs
[j
].smodes
[m1
];
1646 new_mode
[i
] = get_largest_mode (&con_outputs
[i
],
1647 con_outputs
[i
].smodes
[0]);
1648 new_mode
[j
] = get_largest_mode (&con_outputs
[j
],
1649 con_outputs
[j
].smodes
[0]);
1655 if (start_mode
[0] && valid_mode(&con_outputs
[0], start_mode
[0]))
1656 new_mode
[0] = start_mode
[0];
1658 if (con_outputs
[0].smodes
[0])
1659 new_mode
[0] = get_largest_mode (&con_outputs
[0],
1660 con_outputs
[0].smodes
[0]);
1665 for (i
= 0; i
< ncon
; i
++) {
1668 output
= con_outputs
[i
].output
;
1670 if ((!output
->mode_info
) || (output
->mode_info
!= new_mode
[i
])) {
1671 output
->mode_info
= new_mode
[i
];
1672 con_outputs
[i
].on
= True
;
1674 fprintf(stderr
, "set output %d (%s) to mode %s rotation %d\n", i
,
1675 con_outputs
[i
].output
->output_info
->name
,
1676 con_outputs
[i
].output
->mode_info
->name
,
1677 con_outputs
[i
].output
->rotation
);
1679 } else if (con_outputs
[i
].on
) {
1680 if (!need_off_deferred
) {
1681 output
->mode_info
= NULL
;
1682 con_outputs
[i
].on
= False
;
1684 fprintf(stderr
, "turn off output %d (%s) \n",
1685 i
, con_outputs
[i
].output
->output_info
->name
);
1691 if ((ncon
== 2) && (start
>= 4)) {
1693 con_outputs
[1].output
->relative_to
= con_outputs
[0].output
;
1694 con_outputs
[1].output
->relation
= right_of
;
1695 con_outputs
[1].output
->changes
= changes_relation
;
1696 con_outputs
[0].output
->changes
= 0;
1698 else if (start
== 5) {
1699 con_outputs
[0].output
->relative_to
= con_outputs
[1].output
;
1700 con_outputs
[0].output
->relation
= right_of
;
1701 con_outputs
[0].output
->changes
= changes_relation
;
1702 con_outputs
[1].output
->changes
= 0;
1708 if (!set_screen_size ())
1712 /* reset crtcs before allocation */
1713 reset_crtcs_for_outputs();
1718 if (!pick_crtcs()) {
1720 fprintf(stderr
, "pick_crtcs failed\n");
1727 if (need_off_deferred
&& (save
!= -1)) {
1728 /* Now, take the deferred output off */
1733 output
= con_outputs
[save
].output
;
1734 output
->mode_info
= NULL
;
1735 con_outputs
[save
].on
= False
;
1737 fprintf(stderr
, "turn off output %d (%s) \n",
1738 save
, con_outputs
[save
].output
->output_info
->name
);
1740 crtc
= output
->crtc_info
;
1741 s
= crtc_disable (crtc
);
1742 if (s
!= RRSetConfigSuccess
)
1761 atom
= XInternAtom (dpy
, "DISPLAYSWITCH_DAEMON", True
);
1763 fprintf(stderr
, "dispswitch daemon not running\n");
1767 win
= XGetSelectionOwner (dpy
, atom
);
1769 fprintf(stderr
, "dispswitch: No owner of dispswitch daemon is found\n");
1773 bzero (&xev
, sizeof (XEvent
));
1774 xev
.xkey
.type
= KeyPress
;
1775 xev
.xkey
.send_event
= True
;
1776 xev
.xkey
.display
= dpy
;
1778 xev
.xkey
.keycode
= 71;
1782 * Send another instance of dispswitch (a daemon) an event to
1785 ret
= XSendEvent(dpy
, win
, False
, KeyPressMask
, &xev
);
1789 fprintf(stderr
, "dispswitch: XSendEvent error\n");
1795 main (int argc
, char **argv
)
1797 char *display_name
= NULL
;
1802 unsigned int modifier
= 0;
1803 Bool key_given
= False
;
1804 Bool mod_given
= False
;
1805 int keysym
= 0, toggle
= False
, listen
= False
;
1809 program_name
= argv
[0];
1811 for (i
= 1; i
< argc
; i
++) {
1812 if (!strcmp ("-display", argv
[i
]) || !strcmp ("-d", argv
[i
])) {
1813 if (++i
>=argc
) usage ();
1814 display_name
= argv
[i
];
1817 if (!strcmp ("-key", argv
[i
]) || !strcmp ("-k", argv
[i
])) {
1818 if (++i
>=argc
) usage ();
1819 if ((keysym
= XStringToKeysym(argv
[i
])) == NoSymbol
) {
1820 fprintf(stderr
, "invalid keysym: -key %s\n", argv
[i
]);
1826 if (!strcmp ("-mod", argv
[i
]) || !strcmp ("-m", argv
[i
])) {
1831 if (++i
>=argc
) usage ();
1832 s
= strdup (argv
[i
]);
1835 fprintf(stderr
, "modifier failed, will use default modifier\n");
1838 while (*s
== ' ') s
++;
1839 p
= s
+ strlen(s
) - 1;
1840 while (*p
== ' ') *p
-- = 0;
1843 if (p
= strchr(s
, '+')) {
1845 while ((p
> s
) && (*(p
-1) == ' ')) p
--;
1850 for (j
= 0; j
< MAX_MODIFIERS
; j
++) {
1851 if (!strcmp(mod_key_table
[j
].modname
, s
)) {
1852 modifier
|= mod_key_table
[j
].mod
;
1856 if (j
== MAX_MODIFIERS
) {
1857 fprintf(stderr
, "invalid modifier: -mod %s\n", q
);
1864 while (*s
== ' ') s
++;
1871 if (!strcmp ("-nosideview", argv
[i
])) {
1875 if (!strcmp ("-verbose", argv
[i
]) || !strcmp ("-v", argv
[i
])) {
1879 if (!strcmp ("-testrun", argv
[i
])) {
1884 if (!strcmp ("-toggle", argv
[i
]) || !strcmp ("-t", argv
[i
])) {
1888 if (!strcmp ("-listen", argv
[i
]) || !strcmp ("-l", argv
[i
])) {
1895 dpy
= XOpenDisplay (display_name
);
1898 fatal ("can't open display %s\n", XDisplayName(display_name
));
1900 screen
= DefaultScreen (dpy
);
1901 root
= RootWindow (dpy
, screen
);
1903 if (!XRRQueryVersion (dpy
, &major
, &minor
))
1904 fatal ("randr extension missing\n");
1906 if ((major
<= 1) && (major
!= 1 || minor
< 2))
1907 fatal ("wrong randr version: %d.%d\n", major
, minor
);
1914 * Create an atom, a trivial window, and make it selection owner.
1915 * Ready to accept a client event request for switch
1917 atom
= XInternAtom(dpy
, "DISPLAYSWITCH_DAEMON", False
);
1920 fprintf(stderr
, "cannot create Atom\n");
1923 if (XGetSelectionOwner (dpy
, atom
)) {
1925 fprintf(stderr
, "dispswitch daemon is already running, quit\n");
1928 win
= XCreateSimpleWindow(dpy
, root
, 0, 0, 10, 10, 0, 10, 0);
1931 fprintf(stderr
, "cannot create window\n");
1934 XSetSelectionOwner(dpy
, atom
, win
, CurrentTime
);
1935 if (XGetSelectionOwner(dpy
, atom
) != win
) {
1937 fprintf(stderr
, "set selection owner failed\n");
1939 XSelectInput(dpy
, win
, KeyPressMask
);
1943 /* set default key and modifier if not given in command */
1945 keysym
= XStringToKeysym ("F5");
1947 modifier
= ShiftMask
;
1950 cur_keycode
= grab_key (dpy
, keysym
, modifier
, root
);
1952 XRRGetScreenSizeRange (dpy
, root
, &minWidth
, &minHeight
,
1953 &maxWidth
, &maxHeight
);
1955 fb_width_mm
= DisplayWidthMM (dpy
, screen
);
1956 fb_height_mm
= DisplayHeightMM (dpy
, screen
);
1957 dpi
= (25.4 * DisplayHeight (dpy
, screen
)) / DisplayHeightMM(dpy
, screen
);
1959 res
= XRRGetScreenResources (dpy
, root
);
1961 fatal ("could not get screen resources\n");
1963 fatal ("too few crtcs: %d\n", res
->ncrtc
);
1967 X_GETTIMEOFDAY(&time_val
);
1971 need_off_deferred
= False
;
1975 fprintf(stderr
, "\n");
1977 XNextEvent(dpy
, &ev
);
1979 if (!listen
&& !testrun
&& (ev
.type
== MappingNotify
) &&
1980 ((ev
.xmapping
.request
== MappingKeyboard
) ||
1981 (ev
.xmapping
.request
== MappingModifier
))) {
1982 /* keyboard/modifier mapping changed */
1984 fprintf(stderr
, "\nkeyboard/modifier mapping changed ...\n");
1986 XUngrabKey(dpy
, cur_keycode
, modifier
, root
);
1987 cur_keycode
= grab_key (dpy
, keysym
, modifier
, root
);
1990 if (testrun
|| (ev
.type
== KeyPress
)) {
1992 fprintf(stderr
, "\na key press event was grabbed ...\n");
1994 do_not_switch
= False
;
1996 if (testrun
|| need_probe()) {
1997 /* Too long since last switch, need to check output changes */
1998 if (probe_and_check_output_changes ()) {
1999 output_t
*output
, *next
;
2003 if (output
->output_info
)
2004 XRRFreeOutputInfo (output
->output_info
);
2005 if (output
->crtc_info
&& output
->crtc_info
->outputs
) {
2006 free(output
->crtc_info
->outputs
);
2007 output
->crtc_info
->outputs
= NULL
;
2009 next
= output
->next
;
2014 outputs_tail
= &outputs
;
2015 for (i
= 0; i
< ncon
; i
++) {
2016 con_outputs
[i
].output
= NULL
;
2017 con_outputs
[i
].on
= False
;
2018 if (con_outputs
[i
].smodes
) {
2019 free(con_outputs
[i
].smodes
);
2020 con_outputs
[i
].smodes
= NULL
;
2022 con_outputs
[i
].nsmodes
= 0;
2026 } else if (ncon
== 1)
2027 do_not_switch
= True
;
2028 } else if (ncon
== 1)
2029 do_not_switch
= True
;
2031 if (!do_not_switch
) {
2032 if ((ncon
== 2) && (start
== 1))
2034 * Workaround for intel based graphics: in switching from
2035 * LVDS to VGA, off on LVDS needs to be deferred.
2037 need_off_deferred
= True
;
2039 if ((ncon
== 2) && (start
== 4)) {
2042 fprintf(stderr
, "too small screen, skipping side view\n");
2048 X_GETTIMEOFDAY(&time_val
);