/* 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 #include #include #include #include #include #include #include #include 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 (screen_resources) { if (e->connection == RR_Connected) { XID crtc_avail = None; mode_info = NULL; /* 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]; if (!mode_info) { printf(" %lu: Could not be found in the screen resources!\n", output_info->modes[i]); continue; } 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]); if (!crtc_info) { printf(" %lu: could not be queried!\n", screen_resources->crtcs[i]); continue; } 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 && highest_mode->id == e->mode) { printf (" The highest mode is already selected, nothing to do!\n"); } else if (highest_mode && 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 if (highest_mode) printf (" Found no available CRTC, do not set a new mode!\n"); else printf (" Found no highest mode!!\n"); } else if (e->crtc != None) { printf (" Disable the CRTC %lu\n", e->crtc); do_XRRSetCrtcConfig (screen_resources, e->crtc, None, NULL, 0); } } else printf (" Could not query the screen resources, bailed out!\n"); 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); } } printf("Waiting for hotplug events...\n"); 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; }