diff options
author | Martin Peres <martin.peres@linux.intel.com> | 2017-01-20 18:08:18 +0200 |
---|---|---|
committer | Martin Peres <martin.peres@linux.intel.com> | 2017-01-20 18:08:18 +0200 |
commit | 1443224f9d2de179514a0bf14194ac3fe3a01499 (patch) | |
tree | 3600ee64d2bd38ad49f263d6dc15548b9d908d89 |
initial commit
-rw-r--r-- | Makefile | 27 | ||||
-rw-r--r-- | auto-randr.c | 382 |
2 files changed, 409 insertions, 0 deletions
diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..0c97d49 --- /dev/null +++ b/Makefile @@ -0,0 +1,27 @@ +CC = gcc +CFLAGS = -c -Wall +LDFLAGS = + +# List of sources: +SOURCES = auto-randr.c +OBJECTS = $(SOURCES:.cpp=.o) + +# Name of executable target: +EXECUTABLE = auto-randr + +CFLAGS += `pkg-config --cflags x11` +LDFLAGS += `pkg-config --libs x11` + +CFLAGS += `pkg-config --cflags xrandr` +LDFLAGS += `pkg-config --libs xrandr` + +all: $(SOURCES) $(EXECUTABLE) + +$(EXECUTABLE): $(OBJECTS) + $(CC) $(OBJECTS) -o $@ $(LDFLAGS) + +.cpp.o: + $(CC) $(CFLAGS) $< -o $@ + +clean: + rm $(OBJECTS) $(EXECUTABLE) diff --git a/auto-randr.c b/auto-randr.c new file mode 100644 index 0000000..ac3a9c1 --- /dev/null +++ b/auto-randr.c @@ -0,0 +1,382 @@ +/* +Copyright (c) 1988 X Consortium + +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, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice 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 X CONSORTIUM 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. + +Except as contained in this notice, the name of the X Consortium shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from the X Consortium. + +*/ + +/* + * Author: Jim Fulton, MIT X Consortium (For the XEV part) + * Martin Peres (Automatic setting of the highest-available resolution) + */ + +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> +#include <X11/Xlocale.h> +#include <X11/Xos.h> +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#include <X11/Xproto.h> +#include <X11/extensions/Xrandr.h> + +const char *Yes = "YES"; +const char *No = "NO"; +const char *Unknown = "unknown"; + +const char *ProgramName; +Display *dpy; +int screen; + +Bool have_rr; +int rr_event_base, rr_error_base; + +static void +prologue (XEvent *eventp, const char *event_name) +{ + XAnyEvent *e = (XAnyEvent *) eventp; + + printf ("\n%s event, serial %ld, synthetic %s, window 0x%lx,\n", + event_name, e->serial, e->send_event ? Yes : No, e->window); +} + +static void +print_SubPixelOrder (SubpixelOrder subpixel_order) +{ + switch (subpixel_order) { + case SubPixelUnknown: printf ("SubPixelUnknown"); return; + case SubPixelHorizontalRGB: printf ("SubPixelHorizontalRGB"); return; + case SubPixelHorizontalBGR: printf ("SubPixelHorizontalBGR"); return; + case SubPixelVerticalRGB: printf ("SubPixelVerticalRGB"); return; + case SubPixelVerticalBGR: printf ("SubPixelVerticalBGR"); return; + case SubPixelNone: printf ("SubPixelNone"); return; + default: printf ("%d", subpixel_order); + } +} + +static void +print_Rotation (Rotation rotation) +{ + if (rotation & RR_Rotate_0) + printf ("RR_Rotate_0"); + else if (rotation & RR_Rotate_90) + printf ("RR_Rotate_90"); + else if (rotation & RR_Rotate_180) + printf ("RR_Rotate_180"); + else if (rotation & RR_Rotate_270) + printf ("RR_Rotate_270"); + else { + printf ("%d", rotation); + return; + } + if (rotation & RR_Reflect_X) + printf (", RR_Reflect_X"); + if (rotation & RR_Reflect_Y) + printf (", RR_Reflect_Y"); +} + +static void +print_Connection (Connection connection) +{ + switch (connection) { + case RR_Connected: printf ("RR_Connected"); return; + case RR_Disconnected: printf ("RR_Disconnected"); return; + case RR_UnknownConnection: printf ("RR_UnknownConnection"); return; + default: printf ("%d", connection); + } +} + +static void +do_RRScreenChangeNotify (XEvent *eventp) +{ + XRRScreenChangeNotifyEvent *e = (XRRScreenChangeNotifyEvent *) eventp; + + XRRUpdateConfiguration (eventp); + printf (" root 0x%lx, timestamp %lu, config_timestamp %lu\n", + e->root, e->timestamp, e->config_timestamp); + printf (" size_index %hu", e->size_index); + printf (", subpixel_order "); + print_SubPixelOrder (e->subpixel_order); + printf ("\n rotation "); + print_Rotation (e->rotation); + printf("\n width %d, height %d, mwidth %d, mheight %d\n", + e->width, e->height, e->mwidth, e->mheight); +} + +static Status +do_XRRSetCrtcConfig (XRRScreenResources *resources, RRCrtc crtc, RRMode mode, + RROutput *outputs, int noutputs) +{ + XGrabServer(dpy); + Status s = XRRSetCrtcConfig(dpy, resources, crtc, CurrentTime, 0, 0, + mode, RR_Rotate_0, outputs, noutputs); + if (s != RRSetConfigSuccess) + printf("XRRSetCrtcConfig failed!"); + XUngrabServer(dpy); + + return s; +} + +static void +do_RRNotify_OutputChange (XEvent *eventp, XRRScreenResources *screen_resources) +{ + XRROutputChangeNotifyEvent *e = (XRROutputChangeNotifyEvent *) eventp; + XRROutputInfo *output_info = NULL; + XRRModeInfo *mode_info = NULL, *highest_mode = NULL; + XRRCrtcInfo *crtc_info = NULL; + int i, j; + + if (screen_resources) { + output_info = XRRGetOutputInfo (dpy, screen_resources, e->output); + for (i = 0; i < screen_resources->nmode; i++) + if (screen_resources->modes[i].id == e->mode) { + mode_info = &screen_resources->modes[i]; break; + } + } + printf (" subtype XRROutputChangeNotifyEvent\n"); + if (output_info) + printf (" output %s, ", output_info->name); + else + printf (" output %lu, ", e->output); + if (e->crtc) + printf("crtc %lu, ", e->crtc); + else + printf("crtc None, "); + if (mode_info) + printf ("mode %s (%dx%d)\n", mode_info->name, mode_info->width, + mode_info->height); + else if (e->mode) + printf ("mode %lu\n", e->mode); + else + printf("mode None\n"); + printf (" rotation "); + print_Rotation (e->rotation); + printf ("\n connection "); + print_Connection (e->connection); + printf (", subpixel_order "); + print_SubPixelOrder (e->subpixel_order); + printf ("\n"); + + if (e->connection == RR_Connected) { + XID crtc_avail = None; + + /* Now list all the available modes */ + printf (" Found the following modes:\n"); + for (i = 0; i < output_info->nmode; i++) { + /* Find the corresponding mode */ + for (j = 0; j < screen_resources->nmode; j++) + if (output_info->modes[i] == screen_resources->modes[j].id) + mode_info = &screen_resources->modes[j]; + + printf(" %lu: %s, dotClk=%lu Hz, flags=%lu%s%s\n", mode_info->id, + mode_info->name, mode_info->dotClock, mode_info->modeFlags, + mode_info->id == e->mode ? "*" : "", + i < output_info->npreferred ? "+" : ""); + + if (highest_mode == NULL || + mode_info->width * mode_info->height > + highest_mode->width * highest_mode->height) + highest_mode = mode_info; + } + if (e->crtc) { + crtc_avail = e->crtc; + } else { + printf (" Search for an available CRTC:\n"); + for (i = 0; i < screen_resources->ncrtc; i++) { + crtc_info = XRRGetCrtcInfo (dpy, screen_resources, + screen_resources->crtcs[i]); + printf(" %lu: %ix%i (mode %lu)\n", screen_resources->crtcs[i], + crtc_info->width, crtc_info->height, crtc_info->mode); + + if (crtc_info->mode == None) + crtc_avail = screen_resources->crtcs[i]; + } + } + + if (highest_mode->id == e->mode) { + printf (" The highest mode is already selected, nothing to do!\n"); + } else if (crtc_avail != None) { + printf (" Setting the mode %lu (%s, dotClk=%lu Hz) on CRTC %lu\n", + highest_mode->id, highest_mode->name, highest_mode->dotClock, + crtc_avail); + + do_XRRSetCrtcConfig (screen_resources, crtc_avail, highest_mode->id, + &e->output, 1); + } else + printf (" Found no available CRTC, do not set a new mode!\n"); + } else if (e->crtc != None) { + printf (" Disable the CRTC %lu\n", e->crtc); + + do_XRRSetCrtcConfig (screen_resources, e->crtc, None, NULL, 0); + } + + XRRFreeOutputInfo (output_info); +} + +static void +do_RRNotify_CrtcChange (XEvent *eventp, XRRScreenResources *screen_resources) +{ + XRRCrtcChangeNotifyEvent *e = (XRRCrtcChangeNotifyEvent *) eventp; + XRRModeInfo *mode_info = NULL; + + if (screen_resources) { + int i; + + for (i = 0; i < screen_resources->nmode; i++) + if (screen_resources->modes[i].id == e->mode) { + mode_info = &screen_resources->modes[i]; break; + } + } + printf (" subtype XRRCrtcChangeNotifyEvent\n"); + if (e->crtc) + printf(" crtc %lu, ", e->crtc); + else + printf(" crtc None, "); + if (mode_info) + printf ("mode %s, ", mode_info->name); + else if (e->mode) + printf ("mode %lu, ", e->mode); + else + printf("mode None, "); + printf ("rotation "); + print_Rotation (e->rotation); + printf ("\n x %d, y %d, width %d, height %d\n", + e->x, e->y, e->width, e->height); +} + +static void +do_RRNotify_OutputProperty (XEvent *eventp, + XRRScreenResources *screen_resources) +{ + XRROutputPropertyNotifyEvent *e = (XRROutputPropertyNotifyEvent *) eventp; + XRROutputInfo *output_info = NULL; + char *property = XGetAtomName (dpy, e->property); + + if (screen_resources) + output_info = XRRGetOutputInfo (dpy, screen_resources, e->output); + printf (" subtype XRROutputPropertyChangeNotifyEvent\n"); + if (output_info) + printf (" output %s, ", output_info->name); + else + printf (" output %lu, ", e->output); + printf ("property %s, timestamp %lu, state ", + property, e->timestamp); + if (e->state == PropertyNewValue) + printf ("NewValue\n"); + else if (e->state == PropertyDelete) + printf ("Delete\n"); + else + printf ("%d\n", e->state); + XRRFreeOutputInfo (output_info); + XFree (property); +} + +static void +do_RRNotify (XEvent *eventp) +{ + XRRNotifyEvent *e = (XRRNotifyEvent *) eventp; + XRRScreenResources *screen_resources; + + XRRUpdateConfiguration (eventp); + screen_resources = XRRGetScreenResources (dpy, e->window); + prologue (eventp, "RRNotify"); + switch (e->subtype) { + case RRNotify_OutputChange: + do_RRNotify_OutputChange (eventp, screen_resources); break; + case RRNotify_CrtcChange: + do_RRNotify_CrtcChange (eventp, screen_resources); break; + case RRNotify_OutputProperty: + do_RRNotify_OutputProperty (eventp, screen_resources); break; + default: + printf (" subtype %d\n", e->subtype); + } + XRRFreeScreenResources (screen_resources); +} + +int +main (int argc, char **argv) +{ + char *displayname = NULL; + Window w; + int done; + + ProgramName = argv[0]; + + dpy = XOpenDisplay (displayname); + if (!dpy) { + fprintf (stderr, "%s: unable to open display '%s'\n", + ProgramName, XDisplayName (displayname)); + exit (1); + } + + screen = DefaultScreen (dpy); + w = RootWindow(dpy, screen); + + have_rr = XRRQueryExtension (dpy, &rr_event_base, &rr_error_base); + if (have_rr) { + int rr_major, rr_minor; + + if (XRRQueryVersion (dpy, &rr_major, &rr_minor)) { + int rr_mask = RROutputChangeNotifyMask | RROutputPropertyNotifyMask; + /* RRScreenChangeNotifyMask | RRCrtcChangeNotifyMask | RROutputChangeNotifyMask | RROutputPropertyNotifyMask; */ + + if (rr_major == 1 && rr_minor <= 1) { + rr_mask &= ~(RRCrtcChangeNotifyMask | + RROutputChangeNotifyMask | + RROutputPropertyNotifyMask); + } + + XRRSelectInput (dpy, w, rr_mask); + } + } + + for (done = 0; !done; ) { + XEvent event; + + XNextEvent (dpy, &event); + + switch (event.type) { + default: + if (have_rr) { + if (event.type == rr_event_base + RRScreenChangeNotify) { + prologue (&event, "RRScreenChangeNotify"); + do_RRScreenChangeNotify (&event); + break; + } + if (event.type == rr_event_base + RRNotify) { + do_RRNotify (&event); + break; + } + } + printf ("Unknown event type %d, exit!\n", event.type); + done = 1; + break; + } + fflush(stdout); + } + + XCloseDisplay (dpy); + return 0; +} |