/* * Copyright © 2011 Keith Packard * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ #include #include #include #include #include #include #include "config.h" struct output_info { struct output_info *next; RROutput output; XRROutputInfo *info; }; static struct output_info *output_info; static struct output_info * find_output_info (RROutput output) { struct output_info *oi; for (oi = output_info; oi; oi = oi->next) if (oi->output == output) return oi; return NULL; } static void clear_output_info (RROutput output) { struct output_info *oi, **prev; for (prev = &output_info; (oi = *prev); prev = &(oi->next)) if (oi->output == output) { XRRFreeOutputInfo (oi->info); *prev = oi->next; free (oi); break; } } /* * Check to see if the monitor attached to an output * is the same */ static int same_monitor(XRROutputInfo *a, XRROutputInfo *b) { int m; if (a->connection != b->connection) return 0; if (a->nmode != b->nmode) return 0; if (a->npreferred != b->npreferred) return 0; for (m = 0; m < a->nmode; m++) if (a->modes[m] != b->modes[m]) return 0; return 1; } static int check_output (Display *dpy, XRRScreenResources *resources, RROutput output) { XRROutputInfo *info; struct output_info *oi; info = XRRGetOutputInfo (dpy, resources, output); if (!info) { clear_output_info(output); return 0; } oi = find_output_info(output); if (oi) { int same = same_monitor(oi->info, info); XRRFreeOutputInfo(oi->info); oi->info = info; return same; } oi = calloc(1, sizeof (struct output_info)); oi->output = output; oi->info = info; oi->next = output_info; output_info = oi; return 0; } int main (int argc, char **argv) { Display *dpy; int event_base, error_base; int major, minor; XEvent ev; XRRNotifyEvent *nev; const char *config = NULL; const char *resize = NULL; const char *display = NULL; int c, o; int start = 0; XRRScreenResources *resources; static struct option opts[] = { { "config", 1, NULL, 'c' }, { "resize", 1, NULL, 'r' }, { "start", 0, NULL, 's' }, { "auto", 0, NULL, 'a' }, { "display", 1, NULL, 'd' }, { "help", 0, NULL, 'h' }, { "version", 0, NULL, 'v' }, { 0, 0, NULL, 0 } }; while ((c = getopt_long(argc, argv, "c:r:d:hsav", opts, NULL)) != -1) { switch (c) { case 'c': config = optarg; break; case 'r': resize = optarg; break; case 'd': display = optarg; break; case 'a': config = "xrandr --auto"; break; case 's': start = 1; break; case 'v': printf("%s\n", PACKAGE_STRING); exit(0); case 'h': default: fprintf(stderr, "Usage: %s --display --config --resize --auto --start --version\n", argv[0]); exit(1); break; } } dpy = XOpenDisplay(display); if (!dpy) { fprintf(stderr, "XOpenDisplay %s failed\n", XDisplayName(display)); exit(1); } if (!XRRQueryExtension (dpy, &event_base, &error_base) || !XRRQueryVersion (dpy, &major, &minor)) { fprintf (stderr, "RandR extension missing on %s\n", XDisplayName(display)); exit (1); } XRRSelectInput(dpy, RootWindow(dpy, 0), RROutputChangeNotifyMask); XSelectInput(dpy, RootWindow(dpy, 0), StructureNotifyMask); /* Get current configuration */ resources = XRRGetScreenResourcesCurrent(dpy, RootWindow(dpy, 0)); for (o = 0; o < resources->noutput; o++) (void) check_output(dpy, resources, resources->outputs[o]); XRRFreeScreenResources (resources); if (start) { if (config) system(config); if (resize) system(resize); } for (;;) { int configed = 0; int resized = 0; do { XNextEvent(dpy, &ev); switch (ev.type - event_base) { case RRNotify: nev = (XRRNotifyEvent *) &ev; if (nev->subtype == RRNotify_OutputChange) { XRROutputChangeNotifyEvent *noev = (XRROutputChangeNotifyEvent *) nev; resources = XRRGetScreenResources(dpy, RootWindow(dpy, 0)); if (!check_output(dpy, resources, noev->output)) configed = 1; XRRFreeScreenResources (resources); } break; } switch (ev.type) { case ConfigureNotify: resized = 1; break; } usleep(100000); } while (XEventsQueued(dpy, QueuedAfterFlush)); if (configed) { if (config) system(config); else printf ("config\n"); } if (resized) { if (resize) system(resize); else printf ("resize\n"); } } }