diff options
author | Jérémie Courrèges-Anglas <jca@wxcvbn.org> | 2017-02-15 16:25:34 +0100 |
---|---|---|
committer | Jérémie Courrèges-Anglas <jca@wxcvbn.org> | 2017-02-15 16:25:34 +0100 |
commit | 2dbe923ea51cc9a13f4c20091e1bfd86f56f9688 (patch) | |
tree | 3dd7587776ff1679dac0aee80913244d2dd0cad4 /src/xrandr.c | |
parent | c24d1e39ea14666f86c286d72d7f88c9028b3094 (diff) | |
parent | 2bda8bc2933dc3be318fbb7d1e290cd6ff4b1262 (diff) | |
download | ratpoison-2dbe923ea51cc9a13f4c20091e1bfd86f56f9688.zip |
Merge branch 'xrandr'
All the hard work on xrandr done by Mathieu OTHACEHE, thanks!
Diffstat (limited to 'src/xrandr.c')
-rw-r--r-- | src/xrandr.c | 265 |
1 files changed, 265 insertions, 0 deletions
diff --git a/src/xrandr.c b/src/xrandr.c new file mode 100644 index 0000000..de0cde3 --- /dev/null +++ b/src/xrandr.c @@ -0,0 +1,265 @@ +/* functions for grabbing information about xrandr screens + * Copyright (C) 2016 Mathieu OTHACEHE <m.othacehe@gmail.com> + * + * This file is part of ratpoison. + * + * ratpoison is free software; you can redistribute it and/or moify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * ratpoison 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 software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA + */ + +#include "ratpoison.h" + +#include <X11/extensions/Xrandr.h> + +static int xrandr_evbase; + +#define XRANDR_MAJOR 1 +#define XRANDR_MINOR 3 + +void +init_xrandr (void) +{ + int errbase, major, minor; + + if (!XRRQueryExtension (dpy, &xrandr_evbase, &errbase)) { + return; + } + + if (XRRQueryVersion (dpy, &major, &minor) == 0) { + return; + } + + if (major != XRANDR_MAJOR || + (major == XRANDR_MAJOR && minor < XRANDR_MINOR)) { + PRINT_ERROR (("Xrandr version %d.%d is not supported\n", major, minor)); + return; + } + + XRRSelectInput (dpy, RootWindow (dpy, DefaultScreen(dpy)), + RRCrtcChangeNotifyMask | RROutputChangeNotifyMask); + + rp_have_xrandr = 1; +} + +int * +xrandr_query_screen (int *screen_count) +{ + XRRScreenResources *res; + XRROutputInfo *outinfo; + int *output_array; + int count = 0; + int i; + + res = XRRGetScreenResources (dpy, RootWindow (dpy, DefaultScreen (dpy))); + output_array = xmalloc (res->noutput * sizeof(int)); + + for (i = 0; i < res->noutput; i++) { + outinfo = XRRGetOutputInfo (dpy, res, res->outputs[i]); + if (!outinfo->crtc) + continue; + + output_array[count] = res->outputs[i]; + count++; + + XRRFreeOutputInfo (outinfo); + } + + *screen_count = count; + XRRFreeScreenResources (res); + + return output_array; +} + +static rp_screen * +xrandr_screen_output (int rr_output) +{ + rp_screen *cur; + + list_for_each_entry (cur, &rp_screens, node) + { + if (cur->xrandr.output == rr_output) + return cur; + } + + return NULL; +} + +static rp_screen * +xrandr_screen_crtc (int rr_crtc) +{ + rp_screen *cur; + + list_for_each_entry (cur, &rp_screens, node) + { + if (cur->xrandr.crtc == rr_crtc) + return cur; + } + + return NULL; +} + +int +xrandr_is_primary (rp_screen *screen) +{ + return screen->xrandr.primary; +} + +void +xrandr_fill_screen (int rr_output, rp_screen *screen) +{ + XRRScreenResources *res; + XRROutputInfo *outinfo; + XRRCrtcInfo *crtinfo; + RROutput primary; + + res = XRRGetScreenResourcesCurrent (dpy, RootWindow (dpy, DefaultScreen (dpy))); + outinfo = XRRGetOutputInfo (dpy, res, rr_output); + if (!outinfo->crtc) + goto free_res; + + crtinfo = XRRGetCrtcInfo (dpy, res, outinfo->crtc); + if (!crtinfo) + goto free_out; + + primary = XRRGetOutputPrimary (dpy, RootWindow (dpy, DefaultScreen (dpy))); + if (rr_output == primary) + screen->xrandr.primary = 1; + else + screen->xrandr.primary = 0; + + screen->xrandr.name = sbuf_new (0); + sbuf_concat (screen->xrandr.name, outinfo->name); + + screen->xrandr.output = rr_output; + screen->xrandr.crtc = outinfo->crtc; + + screen->left = crtinfo->x; + screen->top = crtinfo->y; + screen->width = crtinfo->width; + screen->height = crtinfo->height; + + XRRFreeCrtcInfo (crtinfo); + free_out: + XRRFreeOutputInfo (outinfo); + free_res: + XRRFreeScreenResources (res); +} + +static void +xrandr_output_change (XRROutputChangeNotifyEvent *ev) +{ + XRRScreenResources *res; + XRROutputInfo *outinfo; + rp_screen *screen; + + res = XRRGetScreenResourcesCurrent (dpy, RootWindow (dpy, DefaultScreen (dpy))); + outinfo = XRRGetOutputInfo (dpy, res, ev->output); + + screen = xrandr_screen_output (ev->output); + + if (!screen && outinfo->crtc) { + screen = screen_add (ev->output); + screen_sort (); + PRINT_DEBUG (("%s: Added screen %s with crtc %lu\n", __func__, + sbuf_get (screen->xrandr.name), + (unsigned long)outinfo->crtc)); + } else if (screen && !outinfo->crtc) { + PRINT_DEBUG (("%s: Removing screen %s\n", __func__, + sbuf_get (screen->xrandr.name))); + screen_del (screen); + } + + XRRFreeOutputInfo (outinfo); + XRRFreeScreenResources (res); +} + +#ifdef DEBUG +static const char * +xrandr_rotation_string (Rotation r) +{ + static char buf[64]; + +#define CASE(c) case c : return #c + switch (r) + { + CASE(RR_Rotate_0); + CASE(RR_Rotate_90); + CASE(RR_Rotate_180); + CASE(RR_Rotate_270); +#undef CASE + default: + snprintf(buf, sizeof buf, "Unknown rotation %hu", (unsigned short)r); + return buf; + } +} +#endif + +static void +xrandr_crtc_change (XRRCrtcChangeNotifyEvent *ev) +{ + rp_screen *screen; + + if (!ev->crtc || !ev->width || !ev->height) + return; + + screen = xrandr_screen_crtc (ev->crtc); + + PRINT_DEBUG (("%s: crtc %s, rotation %s " + "ev->x %d, ev->y %d, ev->width %d, ev->height %d\n", + __func__, screen ? "found" : "not found", + xrandr_rotation_string (ev->rotation), + ev->x, ev->y, ev->width, ev->height)); + + if (!screen) + return; + + if (ev->rotation == RR_Rotate_90 || ev->rotation == RR_Rotate_270) + screen_update (screen, ev->x, ev->y, ev->height, ev->width); + else + screen_update (screen, ev->x, ev->y, ev->width, ev->height); +} + +void +xrandr_notify (XEvent *ev) +{ + XRRNotifyEvent *n_event; + XRROutputChangeNotifyEvent *o_event; + XRRCrtcChangeNotifyEvent *c_event; + + if (ev->type != xrandr_evbase + RRNotify) + return; + + PRINT_DEBUG (("--- Handling RRNotify ---\n")); + + n_event = (XRRNotifyEvent *)ev; + switch (n_event->subtype) { + case RRNotify_OutputChange: + PRINT_DEBUG (("--- XRROutputChangeNotifyEvent ---\n")); + o_event = (XRROutputChangeNotifyEvent *)ev; + xrandr_output_change (o_event); + break; + case RRNotify_CrtcChange: + PRINT_DEBUG (("--- XRRCrtcChangeNotifyEvent ---\n")); + c_event = (XRRCrtcChangeNotifyEvent *)ev; + xrandr_crtc_change (c_event); + break; + case RRNotify_OutputProperty: + PRINT_DEBUG (("--- RRNotify_OutputProperty ---\n")); + break; + default: + PRINT_DEBUG (("--- Unknown subtype %d ---\n", n_event->subtype)); + break; + } +} |