/*
* Copyright © 2001 Keith Packard, member of The XFree86 Project, Inc.
* Copyright © 2002 Hewlett Packard Company, Inc.
* Copyright © 2006 Intel Corporation
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting documentation, and
* that the name of the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THIS SOFTWARE.
*
*/
/*
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include <fcntl.h>
#include <signal.h>
#include <unistd.h>
static char *program_name;
static int screen;
static int had_error = 0;
static int cur_keycode;
static int init_x;
static int init_y;
static void
usage(void)
{
exit(1);
/*NOTREACHED*/
}
static void
{
exit (1);
/*NOTREACHED*/
}
static int
Display *const err_display,
XErrorEvent *const err_event)
{
return (0);
}
typedef enum _relation {
} relation_t;
typedef enum _changes {
changes_none = 0,
} changes_t;
typedef enum _name_kind {
name_none = 0,
} name_kind_t;
typedef struct {
char *string;
int index;
} name_t;
struct _crtc {
int x;
int y;
int noutput;
};
struct _output {
float refresh;
int x, y;
};
static int num_crtcs;
struct _con_output {
int nsmodes;
};
struct _mod_key_table {
char *modname;
unsigned int mod;
};
static int start = 0;
static int ncon;
static int dis_ncon;
{"none", 0},
{"shift", ShiftMask},
{"lock", LockMask},
{"control", ControlMask},
{"mod1", Mod1Mask},
{"mod2", Mod2Mask},
{"mod3", Mod3Mask},
{"mod4", Mod4Mask},
{"mod5", Mod5Mask},
{"any", AnyModifier}
};
static int
{
switch (rotation & 0xf) {
case RR_Rotate_0:
case RR_Rotate_180:
case RR_Rotate_90:
case RR_Rotate_270:
default:
return 0;
}
}
static int
{
switch (rotation & 0xf) {
case RR_Rotate_0:
case RR_Rotate_180:
case RR_Rotate_90:
case RR_Rotate_270:
default:
return 0;
}
}
/* v refresh frequency in Hz */
static float
{
float rate;
else
rate = 0;
return rate;
}
static void
{
}
static void
{
}
static void
{
}
static void
{
}
static void
{
}
static output_t *
add_output (void)
{
if (!output)
fatal ("out of memory");
*outputs_tail = output;
return output;
}
static output_t *
{
{
break;
break;
break;
}
return output;
}
static output_t *
{
init_name (&output_name);
return find_output (&output_name);
}
static crtc_t *
{
int c;
for (c = 0; c < num_crtcs; c++)
{
break;
break;
break;
}
return crtc;
}
static crtc_t *
{
}
static XRRModeInfo *
{
int m;
{
{
break;
}
}
return best;
}
static XRRModeInfo *
{
}
static void
{
/* sanity check output info */
fatal ("Output %s is not disconnected but has no modes\n",
output_info->name);
/* set output name and info */
/* set position */
}
/* set rotation */
else
}
static void
get_crtcs (void)
{
int c;
if (crtcs)
{
{
}
}
{
{
crtcs[c].x = 0;
crtcs[c].y = 0;
}
}
}
static void
{
else
{
}
}
static void
set_crtcs (void)
{
int i;
for (i = 0; i < ncon; i++) {
}
}
static void
reset_crtcs_for_outputs (void)
{
{
}
}
}
static Status
{
if (verbose)
if (dryrun)
return RRSetConfigSuccess;
}
static Status
{
if (verbose)
if (dryrun)
return RRSetConfigSuccess;
}
static Status
{
int o;
Status s;
return RRSetConfigSuccess;
if (!rr_outputs)
return BadAlloc;
if (verbose) {
}
if (dryrun)
s = RRSetConfigSuccess;
else
free (rr_outputs);
return s;
}
static void
screen_revert (void)
{
if (verbose)
if (dryrun)
return;
}
static void
screen_apply (void)
{
/* comment it out because DisplayWidth() does not reflect the
change of fb_width and fb_height previously set by
XRRSetScreenSize()
*/
/*
if (fb_width == DisplayWidth (dpy, screen) &&
fb_height == DisplayHeight (dpy, screen) &&
fb_width_mm == DisplayWidthMM (dpy, screen) &&
fb_height_mm == DisplayHeightMM (dpy, screen))
{
return;
}
*/
if (verbose)
if (dryrun)
return;
}
static void
revert (void)
{
int c;
/* first disable all crtcs */
crtc_disable (&crtcs[c]);
/* next reset screen size */
screen_revert ();
/* now restore all crtcs */
crtc_revert (&crtcs[c]);
}
/*
* uh-oh, something bad happened in the middle of changing
* the configuration. Revert to the previous configuration
* and bail
*/
static void
{
char *message;
switch (s) {
default: message = "unknown failure"; break;
}
revert ();
exit (1);
}
static void
apply (void)
{
Status s;
int c;
/*
* Turn off any crtcs which are to be disabled or which are
* larger than the target size
*/
{
/*
* if this crtc is already disabled, skip it
* Note server sets crtc_info->mode (before change)
*/
continue;
/*
* If this crtc is to be left enabled, make
* sure the old size fits then new screen
* When crtc->mode_info is null, the crtc is to be
* disabled. Note set_crtcs () sets crtc->mode_info for
* new mode (to be changed to).
*/
{
int x, y, w, h;
if (!old_mode)
/* old position and size information */
x = crtc_info->x;
y = crtc_info->y;
/* if it fits, skip it */
continue;
}
if (need_off_deferred)
/* Defer taking off */
continue;
s = crtc_disable (crtc);
if (s != RRSetConfigSuccess)
}
/*
* Hold the server grabbed while messing with
* the screen so that apps which notice the resize
* event and ask for xinerama information from the server
* receive up-to-date information
*/
XGrabServer (dpy);
/*
* Set the screen size
*/
screen_apply ();
/*
* Set crtcs
*/
{
s = crtc_apply (crtc);
if (s != RRSetConfigSuccess)
}
/*
* Release the server grab and let all clients
* respond to the updated state
*/
XUngrabServer (dpy);
}
/*
* Use current output state to complete the output list
*/
static void
get_outputs (void)
{
int o;
{
set_name_index (&output_name, o);
if (!output)
{
output = add_output ();
}
}
}
/*
* Test whether 'crtc' can be used for 'output'
*/
static Bool
{
int i;
int l;
for (i = 0; i < ncon; i++)
{
continue;
continue;
continue;
/* see if the output connected to the crtc can clone to this output */
break;
/* not on the list, can't clone */
return False;
}
{
/* Check if the output is to be turned on */
/* make sure the state matches */
return False;
return False;
return False;
return False;
}
}
return True;
}
static crtc_t *
{
int c;
{
return crtc;
}
return NULL;
}
static void
set_positions (void)
{
int i;
for (;;)
{
keep_going = False;
for (i = 0; i < ncon; i++)
{
{
output->x = 0;
output->y = 0;
continue;
}
/*
* Make sure the dependent object has been set in place
*/
{
keep_going = True;
continue;
}
case left_of:
break;
case right_of:
break;
case above:
break;
case below:
break;
case same_as:
}
}
if (!keep_going)
break;
if (!any_set)
fatal ("loop in relative position specifications\n");
}
/*
* Now normalize positions so the upper left corner of all outputs is at 0,0
*/
min_x = 32768;
min_y = 32768;
for (i = 0; i < ncon; i++)
{
}
{
/* move all outputs */
for (i = 0; i < ncon; i++)
{
}
}
}
static Bool
set_screen_size (void)
{
int i;
for (i = 0; i < ncon; i++)
{
int x, y, w, h;
if (!mode_info) continue;
x = output->x;
y = output->y;
}
if (verbose)
return False;
}
return True;
}
static void
{
while (outputs)
{
}
}
/*
* find the best mapping from output to crtc available
*/
static int
{
int best_score;
int my_score;
int score;
int c;
if (!outputs)
return 0;
/*
* Score with this output disabled
*/
return best_score;
/*
* Now score with this output any valid crtc
*/
{
if (!crtc)
/* reset crtc allocation for following outputs */
continue;
my_score = 1000;
/* slight preference for existing connections */
my_score++;
if (score > best_score)
{
best_score = score;
}
}
/*
* Reset other outputs based on this one using the best crtc
*/
(void) pick_crtcs_score (outputs);
return best_score;
}
/*
* Pick crtcs for any changing outputs that don't have one
*/
static Bool
pick_crtcs (void)
{
int i;
/*
* First try to match up newly enabled outputs with spare crtcs
*/
for (i = 0; i < ncon; i++)
{
{
break;
} else {
break;
else {
if (verbose)
}
}
}
}
/*
* Everyone is happy
*/
if (i == ncon)
return True;
/*
* When the simple way fails, see if there is a way
* to swap crtcs around and make things work
*/
{
if (verbose)
return False;
}
}
return True;
}
static Bool
probe_and_check_output_changes (void) {
int i;
if (!new_res)
fatal ("could not get screen resources");
else {
break;
}
break;
}
break;
}
continue;
break;
}
}
}
if (changed) {
if (res)
if (verbose)
return True;
}
if (verbose)
return False;
}
static Bool
need_probe (void) {
return True;
else
return False;
}
static int
{
return 1;
return -1;
} else
return 0;
}
return 1;
return -1;
return 1;
return -1;
return 0;
}
static int
return -1;
return 1;
}
static Bool
int i, j;
int x, y, w, h;
*m0 = -1;
*m0 = -1;
return False;
/* first try to find mode with common same size */
x = output->x;
y = output->y;
break;
}
}
break;
}
return False;
/* then try to find mode with common id for possible cloning */
x = output->x;
y = output->y;
break;
}
}
break;
}
} else {
/* use common id if it is not smaller */
} else {
}
}
return True;
}
static XRRModeInfo *
for (i = 0; i < c->nsmodes; i++) {
int x, y, w, h;
continue;
else
if (mode_info) {
x = output->x;
y = output->y;
break;
}
}
if (i < c->nsmodes)
return c->smodes[i];
else
fatal("cannot find mode");
}
static Bool
int i;
return True;
return False;
}
static void
do_init (void)
{
int i, j;
/* Initialize con_outputs array */
for (i = 0; i < MAX_OUTPUT; i++) {
start_mode[i] = NULL;
}
ncon = 0;
dis_ncon = 0;
init_x = 0;
init_y = 0;
get_crtcs ();
get_outputs ();
for (j = 0; j < output_info->nmode; j++) {
}
/* Sort the modes */
(int (*) (const void *, const void *)) mode_sort);
if (output_info->crtc) {
for (j = 0; j < output_info->ncrtc; j++) {
break;
if (j == output_info->ncrtc) {
if (verbose)
fatal ("crtc does not match for output\n");
}
}
/* set initial mode_info */
if (crtc)
}
else
ncon ++;
dis_ncon ++;
}
}
sizeof(con_output_t), (int (*) (const void *, const void *)) output_sort);
if (verbose) {
for (j = 0; j < ncon; j++) {
}
for (j = 0; j < dis_ncon; j++) {
}
}
if ((i == 1) || (i == 2) || (i == 4)) {
use_init_pos = True;
j = i >> 1;
/* remember position and mode info in single state */
} else
start = i;
}
return;
}
static int
{
had_error = 0;
if (!testrun) {
}
if (had_error) {
}
if (verbose)
return keycode;
}
static Bool
do_switch (void)
{
int i, j;
int single;
if (ncon <= 0)
return True;
for (i = 0; i < ncon; i++) {
if (use_init_pos) {
} else {
output->x = 0;
output->y = 0;
}
}
if (ncon == 2) {
if (!nosideview) {
}
else {
}
if (verbose)
if (start >= 3) {
} else {
con_outputs[0].smodes[0]);
}
} else {
else {
}
}
}
if (ncon == 3) {
if (verbose)
single = 1;
i = start >> 1;
j = 0;
}
else {
single = 0;
if (start > 4)
j = 2;
else
j = 1;
if (start > 5)
i = 1;
else
i = 0;
}
if (single) {
new_mode[i] = start_mode[i];
else {
if (con_outputs[i].smodes[0])
con_outputs[i].smodes[0]);
}
}
else {
} else {
con_outputs[i].smodes[0]);
con_outputs[j].smodes[0]);
}
}
}
if (ncon == 1) {
new_mode[0] = start_mode[0];
else {
if (con_outputs[0].smodes[0])
con_outputs[0].smodes[0]);
}
}
/* Set mode */
for (i = 0; i < ncon; i++) {
if (new_mode[i]) {
if (verbose)
}
} else if (con_outputs[i].on ) {
if (!need_off_deferred) {
if (verbose)
} else
save = i;
}
}
if (start == 4) {
}
else if (start == 5) {
}
}
if (!set_screen_size ())
return False;
/* reset crtcs before allocation */
if (!did_init)
get_crtcs();
if (!pick_crtcs()) {
if (verbose)
return True;
}
set_crtcs ();
apply();
/* Now, take the deferred output off */
Status s;
if (verbose)
s = crtc_disable (crtc);
if (s != RRSetConfigSuccess)
}
return True;
}
static Bool
do_toggle (void)
{
int ret;
if (!atom) {
return False;
}
if (!win) {
return False;
}
/* Any keycode */
/*
* Send another instance of dispswitch (a daemon) an event to
* request a switch
*/
if (!ret)
return (!ret);
}
int
{
int i;
unsigned int modifier = 0;
program_name = argv[0];
for (i = 1; i < argc; i++) {
display_name = argv[i];
continue;
}
usage();
}
continue;
}
int j;
char *s, *p, *q;
int end = 0;
if (!s) {
if (verbose)
continue;
}
while (*s == ' ') s++;
p = s + strlen(s) - 1;
while (*p == ' ') *p-- = 0;
q = s;
for (; ;) {
if (p = strchr(s, '+')) {
*p = ' ';
while ((p > s) && (*(p-1) == ' ')) p--;
*p = 0;
}
else
end = 1;
for (j = 0; j < MAX_MODIFIERS; j++) {
break;
}
}
if (j == MAX_MODIFIERS) {
usage();
}
if (end)
break;
else {
s = ++p;
while (*s == ' ') s++;
}
}
free (q);
continue;
}
nosideview = True;
continue;
}
continue;
}
continue;
}
continue;
}
continue;
}
usage();
}
fatal ("randr extension missing\n");
if (toggle)
/*
* Create an atom, a trivial window, and make it selection owner.
* Ready to accept a client event request for switch
*/
if (!atom) {
if (verbose)
}
else {
if (verbose)
exit (1);
}
if (!win) {
if (verbose)
}
else {
if (verbose)
} else
}
}
/* set default key and modifier if not given in command */
if (!key_given)
if (!mod_given)
if (!listen)
if (!res)
fatal ("could not get screen resources\n");
do_init();
for(;;)
{
if (testrun) {
usleep(4000000);
} else
if (verbose)
}
if (verbose)
if (testrun || need_probe()) {
/* Too long since last switch, need to check output changes */
if (probe_and_check_output_changes ()) {
while (output) {
if (output->output_info)
}
}
outputs_tail = &outputs;
for (i = 0; i < ncon; i++) {
if (con_outputs[i].smodes) {
}
con_outputs[i].nsmodes = 0;
}
do_init();
} else if (ncon == 1)
} else if (ncon == 1)
if (!do_not_switch) {
/*
* Workaround for intel based graphics: in switching from
* LVDS to VGA, off on LVDS needs to be deferred.
*/
if (!do_switch()) {
start = 5;
if (verbose)
(void) do_switch();
}
}
}
}
}
}