Example #1
0
// Restore the saved (original) video mode for the specified monitor
//
void _glfwRestoreVideoModeX11(_GLFWmonitor* monitor)
{
    if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken)
    {
        XRRScreenResources* sr;
        XRRCrtcInfo* ci;

        if (monitor->x11.oldMode == None)
            return;

        sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root);
        ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc);

        XRRSetCrtcConfig(_glfw.x11.display,
                         sr, monitor->x11.crtc,
                         CurrentTime,
                         ci->x, ci->y,
                         monitor->x11.oldMode,
                         ci->rotation,
                         ci->outputs,
                         ci->noutput);

        XRRFreeCrtcInfo(ci);
        XRRFreeScreenResources(sr);

        monitor->x11.oldMode = None;
    }
}
Example #2
0
int
get_screen_geom(Window last_focused, int *x, int *y, int *w, int *h)
{
	int i;
	XWindowAttributes wa;
	XRRScreenResources *resources;
	XRRCrtcInfo *monitor_info;

	XGetWindowAttributes(dpy, last_focused, &wa);
	/* TODO externalize resources */
	resources = XRRGetScreenResourcesCurrent(dpy, last_focused);

	for (i = 0; i < resources->ncrtc; i++) {
		monitor_info = XRRGetCrtcInfo(dpy, resources, resources->crtcs[i]);
		if (wa.x >= monitor_info->x
			&& wa.x <= monitor_info->x + monitor_info->width - 1
			&& wa.y >= monitor_info->y && wa.y <= monitor_info->y + monitor_info->height - 1) {
			*x = monitor_info->x;
			*y = monitor_info->y;
			*w = monitor_info->width;
			*h = monitor_info->height;
			return 1;
		}
	}
	return 0;
}
Example #3
0
XRRConfiguration::XRRConfiguration(Display *_dpy, Window _win)
	: dpy(_dpy)
	, win(_win)
	, screenResources(nullptr), outputInfo(nullptr), crtcInfo(nullptr)
	, fullMode(0)
	, fs_fb_width(0), fs_fb_height(0), fs_fb_width_mm(0), fs_fb_height_mm(0)
	, bValid(true), bIsFullscreen(false)
{
	int XRRMajorVersion, XRRMinorVersion;

	if (!XRRQueryVersion(dpy, &XRRMajorVersion, &XRRMinorVersion) ||
	    (XRRMajorVersion < 1 || (XRRMajorVersion == 1 && XRRMinorVersion < 3)))
	{
		WARN_LOG(VIDEO, "XRRExtension not supported.");
		bValid = false;
		return;
	}

	screenResources = XRRGetScreenResourcesCurrent(dpy, win);

	screen = DefaultScreen(dpy);
	fb_width = DisplayWidth(dpy, screen);
	fb_height = DisplayHeight(dpy, screen);
	fb_width_mm = DisplayWidthMM(dpy, screen);
	fb_height_mm = DisplayHeightMM(dpy, screen);

	INFO_LOG(VIDEO, "XRRExtension-Version %d.%d", XRRMajorVersion, XRRMinorVersion);
	Update();
}
Example #4
0
void
xfce_randr_reload (XfceRandr *randr)
{
    Display   *xdisplay;
    GdkWindow *root_window;

    xfce_randr_cleanup (randr);

    /* get the x display */
    xdisplay = gdk_x11_display_get_xdisplay (randr->priv->display);

    /* get the root window */
    root_window = gdk_get_default_root_window ();

    /* get the screen resource */
#ifdef HAS_RANDR_ONE_POINT_THREE
    /* xfce_randr_reload() is only called after a xrandr notification, which
       means that X is aware of the new hardware already. So, if possible,
       do not reprobe the hardware again. */
    if (randr->priv->has_1_3)
        randr->priv->resources = XRRGetScreenResourcesCurrent (xdisplay, GDK_WINDOW_XID (root_window));
    else
#endif
    randr->priv->resources = XRRGetScreenResources (xdisplay, GDK_WINDOW_XID (root_window));

    /* repopulate */
    xfce_randr_populate (randr, xdisplay, root_window);
}
Example #5
0
void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode)
{
    if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken)
    {
        XRRScreenResources* sr;
        XRRCrtcInfo* ci;

        sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root);
        ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc);

        *mode = vidmodeFromModeInfo(getModeInfo(sr, ci->mode), ci);

        XRRFreeCrtcInfo(ci);
        XRRFreeScreenResources(sr);
    }
    else
    {
        mode->width = DisplayWidth(_glfw.x11.display, _glfw.x11.screen);
        mode->height = DisplayHeight(_glfw.x11.display, _glfw.x11.screen);
        mode->refreshRate = 0;

        _glfwSplitBPP(DefaultDepth(_glfw.x11.display, _glfw.x11.screen),
                      &mode->redBits, &mode->greenBits, &mode->blueBits);
    }
}
Example #6
0
GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* found)
{
    GLFWvidmode* result;

    *found = 0;

    // Build array of available resolutions

    if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken)
    {
        int i, j;
        XRRScreenResources* sr;
        XRRCrtcInfo* ci;
        XRROutputInfo* oi;

        sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root);
        ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc);
        oi = XRRGetOutputInfo(_glfw.x11.display, sr, monitor->x11.output);

        result = calloc(oi->nmode, sizeof(GLFWvidmode));

        for (i = 0;  i < oi->nmode;  i++)
        {
            const XRRModeInfo* mi = getModeInfo(sr, oi->modes[i]);
            if (!modeIsGood(mi))
                continue;

            const GLFWvidmode mode = vidmodeFromModeInfo(mi, ci);

            for (j = 0;  j < *found;  j++)
            {
                if (_glfwCompareVideoModes(result + j, &mode) == 0)
                    break;
            }

            if (j < *found)
            {
                // This is a duplicate, so skip it
                continue;
            }

            result[*found] = mode;
            (*found)++;
        }

        XRRFreeOutputInfo(oi);
        XRRFreeCrtcInfo(ci);
        XRRFreeScreenResources(sr);
    }
    else
    {
        *found = 1;
        result = calloc(1, sizeof(GLFWvidmode));
        _glfwPlatformGetVideoMode(monitor, result);
    }

    return result;
}
Example #7
0
static inline XRRScreenResources *_XRRGetScreenResourcesCurrent(Display *dpy, Window window)
{
	XRRScreenResources *res;

	res = XRRGetScreenResourcesCurrent(dpy, window);
	if (res == NULL)
		res = XRRGetScreenResources(dpy, window);

	return res;
}
Example #8
0
// Set the current video mode for the specified monitor
//
void _glfwSetVideoModeX11(_GLFWmonitor* monitor, const GLFWvidmode* desired)
{
    if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken)
    {
        XRRScreenResources* sr;
        XRRCrtcInfo* ci;
        XRROutputInfo* oi;
        GLFWvidmode current;
        const GLFWvidmode* best;
        RRMode native = None;
        int i;

        best = _glfwChooseVideoMode(monitor, desired);
        _glfwPlatformGetVideoMode(monitor, &current);
        if (_glfwCompareVideoModes(&current, best) == 0)
            return;

        sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root);
        ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc);
        oi = XRRGetOutputInfo(_glfw.x11.display, sr, monitor->x11.output);

        for (i = 0;  i < oi->nmode;  i++)
        {
            const XRRModeInfo* mi = getModeInfo(sr, oi->modes[i]);
            if (!modeIsGood(mi))
                continue;

            const GLFWvidmode mode = vidmodeFromModeInfo(mi, ci);
            if (_glfwCompareVideoModes(best, &mode) == 0)
            {
                native = mi->id;
                break;
            }
        }

        if (native)
        {
            if (monitor->x11.oldMode == None)
                monitor->x11.oldMode = ci->mode;

            XRRSetCrtcConfig(_glfw.x11.display,
                             sr, monitor->x11.crtc,
                             CurrentTime,
                             ci->x, ci->y,
                             native,
                             ci->rotation,
                             ci->outputs,
                             ci->noutput);
        }

        XRRFreeOutputInfo(oi);
        XRRFreeCrtcInfo(ci);
        XRRFreeScreenResources(sr);
    }
}
Example #9
0
/*
 * Class:     jogamp_newt_driver_x11_RandR13
 * Method:    getScreenResources0
 * Signature: (JI)J
 */
JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_x11_RandR13_getScreenResources0
  (JNIEnv *env, jclass clazz, jlong display, jint screen_idx) 
{
    Display *dpy = (Display *) (intptr_t) display;
    Window root = RootWindow(dpy, (int)screen_idx);

    XRRScreenResources *res = XRRGetScreenResourcesCurrent( dpy, root); // 1.3
    // XRRScreenResources *res = XRRGetScreenResources( dpy, root); // 1.2

    return (jlong) (intptr_t) res;
}
Example #10
0
static int
SwitchRes(char inout, int x __UNUSED__, int y __UNUSED__, int w, int h,
	  int *dw, int *dh)
{
   XRRScreenResources *xsr;
   XRRCrtcInfo        *xci;
   RRCrtc              crtc;
   RRMode              ss_mode_new;
   int                 ok = 0;

   Dprintf("%s: inout=%d\n", __func__, inout);

   xsr = XRRGetScreenResourcesCurrent(disp, WinGetXwin(VROOT));
   if (!xsr)
      goto done;
   crtc = xsr->crtcs[0];	/* FIXME - Which crtc? */

   if (inout)
     {
	/* Save current setup */
	xci = XRRGetCrtcInfo(disp, xsr, crtc);
	if (!xci)
	   goto done;
	ss_mode = xci->mode;
	ss_rot = xci->rotation;
	XRRFreeCrtcInfo(xci);

	/* Select zoomed setup */
	ss_mode_new = FindMode(xsr, w, h, dw, dh);

	/* Set zoomed setup */
	SetPanning(xsr, crtc, 1);

	ok = SetMode(xsr, crtc, ss_mode_new, ss_rot);
     }
   else
     {
	/* Revert to original setup */
	ok = SetMode(xsr, crtc, ss_mode, ss_rot);

	SetPanning(xsr, crtc, 0);
     }

 done:
   if (xsr)
      XRRFreeScreenResources(xsr);

   Dprintf("%s: ok=%d\n", __func__, ok);
   return ok;
}
Example #11
0
void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos)
{
    if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken)
    {
        XRRScreenResources* sr;
        XRRCrtcInfo* ci;

        sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root);
        ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc);

        if (xpos)
            *xpos = ci->x;
        if (ypos)
            *ypos = ci->y;

        XRRFreeCrtcInfo(ci);
        XRRFreeScreenResources(sr);
    }
}
Example #12
0
/*
 * Class:     jogamp_newt_driver_x11_RandR13
 * Method:    getScreenResources0
 * Signature: (JI)J
 */
JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_x11_RandR13_getScreenResources0
  (JNIEnv *env, jclass clazz, jlong display, jint screen_idx) 
{
    Display *dpy = (Display *) (intptr_t) display;
    Window root = RootWindow(dpy, (int)screen_idx);

    /* Bug 1183
     * XRRGetScreenResourcesCurrent (or XRRGetScreenResources)
     * _occasionally_ reports empty data
     * unless XRRGetScreenSizeRange has been called once.
     */
    int minWidth, minHeight, maxWidth, maxHeight;
    XRRGetScreenSizeRange ( dpy, root, &minWidth, &minHeight, &maxWidth, &maxHeight);

    XRRScreenResources *res = XRRGetScreenResourcesCurrent( dpy, root); // 1.3
    // XRRScreenResources *res = XRRGetScreenResources( dpy, root); // 1.2

    return (jlong) (intptr_t) res;
}
Example #13
0
File: sct.c Project: cstrahan/notes
int
main(int argc, char **argv)
{
	Display *dpy = XOpenDisplay(NULL);
	int screen = DefaultScreen(dpy);
	Window root = RootWindow(dpy, screen);

	XRRScreenResources *res = XRRGetScreenResourcesCurrent(dpy, root);

	int temp = 6500;
	if (argc > 1)
		temp = atoi(argv[1]);
	if (temp < 1000 || temp > 10000)
		temp = 6500;

	temp -= 1000;
	double ratio = temp % 500 / 500.0;
#define AVG(c) whitepoints[temp / 500].c * (1 - ratio) + whitepoints[temp / 500 + 1].c * ratio
	double gammar = AVG(r);
	double gammag = AVG(g);
	double gammab = AVG(b);

	int num_crtcs = res->ncrtc;
	for (int c = 0; c < res->ncrtc; c++) {
		int crtcxid = res->crtcs[c];
		XRRCrtcInfo *crtc_info = XRRGetCrtcInfo(dpy, res, crtcxid);

		int size = XRRGetCrtcGammaSize(dpy, crtcxid);

		XRRCrtcGamma *crtc_gamma = XRRAllocGamma(size);

		for (int i = 0; i < size; i++) {
			double g = 65535.0 * i / size;
			crtc_gamma->red[i] = g * gammar;
			crtc_gamma->green[i] = g * gammag;
			crtc_gamma->blue[i] = g * gammab;
		}
		XRRSetCrtcGamma(dpy, crtcxid, crtc_gamma);

		XFree(crtc_gamma);
	}
}
void handleDisplayChange(XRRScreenChangeNotifyEvent *evt) {
    int screenWidth, screenHeight;
    if(evt==NULL) {
        screenWidth = lastScreenWidth;
        screenHeight = lastScreenHeight;
    } else {
        screenWidth = evt->width;
        lastScreenWidth = screenWidth;
        screenHeight = evt->height;
        lastScreenHeight = screenHeight;
    }

    if(debugMode) {
        printf("Screen size: %ix%i\n", screenWidth, screenHeight);
    }

    XRRScreenResources *res = XRRGetScreenResourcesCurrent(display, root);

    int d;
    for(d = 0; d < profiles.nDeviceSettings; d++) {
        if(profiles.deviceSettings[d].attachedOutput == NULL && !(profiles.deviceSettings[d].autoOutput)) {

            /* Set calibration of whole screen */

            int id = 0;
            for(id = 0; id<profiles.deviceSettings[d].inputDeviceCount; id++) {
                if(debugMode) {
                    printf("Calibrate Device with ID %i\n", profiles.deviceSettings[d].inputDeviceIDs[id]);
                }
                setCalibration(profiles.deviceSettings[d].inputDeviceIDs[id], profiles.deviceSettings[d].outputMinX, profiles.deviceSettings[d].outputMaxX, profiles.deviceSettings[d].outputMinY, profiles.deviceSettings[d].outputMaxY, profiles.deviceSettings[d].swapAxes, screenWidth, screenHeight, 0, 0, screenWidth, screenHeight, 0);

            }

        } else if(profiles.deviceSettings[d].inputDeviceCount > 0) {
            int o;
            for(o = 0; o < res->noutput; o++) {
                XRROutputInfo *outpInf = XRRGetOutputInfo(display, res, res->outputs[o]);
                if((profiles.deviceSettings[d].autoOutput && (strstr(outpInf->name, "LVDS") || strstr(outpInf->name, "lvds")) )
                        || (profiles.deviceSettings[d].attachedOutput && !strcmp(outpInf->name, profiles.deviceSettings[d].attachedOutput))) {
                    /* This is the attached output */
                    if(outpInf->crtc != 0) {
                        /* The output is active (has a CRTC) */

                        XRRCrtcInfo* crtcInf = XRRGetCrtcInfo(display, res, outpInf->crtc);
                        if(debugMode) {
                            printf("Output %s -- x: %i; y: %i; w: %i; h: %i\n", outpInf->name, crtcInf->x, crtcInf->y, crtcInf->width, crtcInf->height);
                        }

                        /* Set calibration */
                        int id = 0;
                        for(id = 0; id<profiles.deviceSettings[d].inputDeviceCount; id++) {
                            if(debugMode) {
                                printf("Calibrate Device with ID %i\n", profiles.deviceSettings[d].inputDeviceIDs[id]);
                            }

                            setCalibration(profiles.deviceSettings[d].inputDeviceIDs[id], profiles.deviceSettings[d].outputMinX, profiles.deviceSettings[d].outputMaxX, profiles.deviceSettings[d].outputMinY, profiles.deviceSettings[d].outputMaxY, profiles.deviceSettings[d].swapAxes, screenWidth, screenHeight, crtcInf->x, crtcInf->y, crtcInf->width, crtcInf->height, crtcInf->rotation);

                        }

                        XRRFreeCrtcInfo(crtcInf);
                    }
                    /* Output found, so break */
                    break;
                }
                XRRFreeOutputInfo(outpInf);
            }
        }
    }
    XRRFreeScreenResources(res);
}
Example #15
0
File: screen.c Project: guns/subtle
void
subScreenInit(void)
{
  SubScreen *s = NULL;

#ifdef HAVE_X11_EXTENSIONS_XRANDR_H
  /* Check both but prefer xrandr */
  if(subtle->flags & SUB_SUBTLE_XRANDR)
    {
      XRRScreenResources *res = NULL;

      if((res = XRRGetScreenResourcesCurrent(subtle->dpy, ROOT)))
        {
          int i;
          XRRCrtcInfo *crtc = NULL;

          /* Query screens */
          for(i = 0; i < res->ncrtc; i++)
            {
              if((crtc = XRRGetCrtcInfo(subtle->dpy, res, res->crtcs[i])))
                {
                  /* Create new screen if crtc is enabled */
                  if(None != crtc->mode && (s = subScreenNew(crtc->x,
                      crtc->y, crtc->width, crtc->height)))
                    subArrayPush(subtle->screens, (void *)s);

                  XRRFreeCrtcInfo(crtc);
                }
            }

          XRRFreeScreenResources(res);
        }
    }
#endif /* HAVE_X11_EXTENSIONS_XRANDR_H */

#ifdef HAVE_X11_EXTENSIONS_XINERAMA_H
  if(subtle->flags & SUB_SUBTLE_XINERAMA && 0 == subtle->screens->ndata &&
      XineramaIsActive(subtle->dpy))
    {
      int i, n = 0;
      XineramaScreenInfo *info = NULL;

      /* Query screens */
      if((info = XineramaQueryScreens(subtle->dpy, &n)))
        {
          for(i = 0; i < n; i++)
            {
              /* Create new screen */
              if((s = subScreenNew(info[i].x_org, info[i].y_org,
                  info[i].width, info[i].height)))
                subArrayPush(subtle->screens, (void *)s);
            }

          XFree(info);
        }
    }
#endif /* HAVE_X11_EXTENSIONS_XINERAMA_H */

  /* Create default screen */
  if(0 == subtle->screens->ndata)
    {
      /* Create new screen */
      if((s = subScreenNew(0, 0, subtle->width, subtle->height)))
        subArrayPush(subtle->screens, (void *)s);
    }

  printf("Running on %d screen(s)\n", subtle->screens->ndata);

  ScreenPublish();
  subScreenPublish();

  subSharedLogDebugSubtle("init=screen\n");
} /* }}} */
Example #16
0
// Look for and initialize supported X11 extensions
//
static GLFWbool initExtensions(void)
{
    _glfw.x11.vidmode.handle = _glfw_dlopen("libXxf86vm.so.1");
    if (_glfw.x11.vidmode.handle)
    {
        _glfw.x11.vidmode.QueryExtension = (PFN_XF86VidModeQueryExtension)
            _glfw_dlsym(_glfw.x11.vidmode.handle, "XF86VidModeQueryExtension");
        _glfw.x11.vidmode.GetGammaRamp = (PFN_XF86VidModeGetGammaRamp)
            _glfw_dlsym(_glfw.x11.vidmode.handle, "XF86VidModeGetGammaRamp");
        _glfw.x11.vidmode.SetGammaRamp = (PFN_XF86VidModeSetGammaRamp)
            _glfw_dlsym(_glfw.x11.vidmode.handle, "XF86VidModeSetGammaRamp");
        _glfw.x11.vidmode.GetGammaRampSize = (PFN_XF86VidModeGetGammaRampSize)
            _glfw_dlsym(_glfw.x11.vidmode.handle, "XF86VidModeGetGammaRampSize");

        _glfw.x11.vidmode.available =
            XF86VidModeQueryExtension(_glfw.x11.display,
                                      &_glfw.x11.vidmode.eventBase,
                                      &_glfw.x11.vidmode.errorBase);
    }

#if defined(__CYGWIN__)
    _glfw.x11.xi.handle = _glfw_dlopen("libXi-6.so");
#else
    _glfw.x11.xi.handle = _glfw_dlopen("libXi.so.6");
#endif
    if (_glfw.x11.xi.handle)
    {
        _glfw.x11.xi.QueryVersion = (PFN_XIQueryVersion)
            _glfw_dlsym(_glfw.x11.xi.handle, "XIQueryVersion");
        _glfw.x11.xi.SelectEvents = (PFN_XISelectEvents)
            _glfw_dlsym(_glfw.x11.xi.handle, "XISelectEvents");

        if (XQueryExtension(_glfw.x11.display,
                            "XInputExtension",
                            &_glfw.x11.xi.majorOpcode,
                            &_glfw.x11.xi.eventBase,
                            &_glfw.x11.xi.errorBase))
        {
            _glfw.x11.xi.major = 2;
            _glfw.x11.xi.minor = 0;

            if (XIQueryVersion(_glfw.x11.display,
                               &_glfw.x11.xi.major,
                               &_glfw.x11.xi.minor) == Success)
            {
                _glfw.x11.xi.available = GLFW_TRUE;
            }
        }
    }

#if defined(__CYGWIN__)
    _glfw.x11.randr.handle = _glfw_dlopen("libXrandr-2.so");
#else
    _glfw.x11.randr.handle = _glfw_dlopen("libXrandr.so.2");
#endif
    if (_glfw.x11.randr.handle)
    {
        _glfw.x11.randr.AllocGamma = (PFN_XRRAllocGamma)
            _glfw_dlsym(_glfw.x11.randr.handle, "XRRAllocGamma");
        _glfw.x11.randr.FreeGamma = (PFN_XRRFreeGamma)
            _glfw_dlsym(_glfw.x11.randr.handle, "XRRFreeGamma");
        _glfw.x11.randr.FreeCrtcInfo = (PFN_XRRFreeCrtcInfo)
            _glfw_dlsym(_glfw.x11.randr.handle, "XRRFreeCrtcInfo");
        _glfw.x11.randr.FreeGamma = (PFN_XRRFreeGamma)
            _glfw_dlsym(_glfw.x11.randr.handle, "XRRFreeGamma");
        _glfw.x11.randr.FreeOutputInfo = (PFN_XRRFreeOutputInfo)
            _glfw_dlsym(_glfw.x11.randr.handle, "XRRFreeOutputInfo");
        _glfw.x11.randr.FreeScreenResources = (PFN_XRRFreeScreenResources)
            _glfw_dlsym(_glfw.x11.randr.handle, "XRRFreeScreenResources");
        _glfw.x11.randr.GetCrtcGamma = (PFN_XRRGetCrtcGamma)
            _glfw_dlsym(_glfw.x11.randr.handle, "XRRGetCrtcGamma");
        _glfw.x11.randr.GetCrtcGammaSize = (PFN_XRRGetCrtcGammaSize)
            _glfw_dlsym(_glfw.x11.randr.handle, "XRRGetCrtcGammaSize");
        _glfw.x11.randr.GetCrtcInfo = (PFN_XRRGetCrtcInfo)
            _glfw_dlsym(_glfw.x11.randr.handle, "XRRGetCrtcInfo");
        _glfw.x11.randr.GetOutputInfo = (PFN_XRRGetOutputInfo)
            _glfw_dlsym(_glfw.x11.randr.handle, "XRRGetOutputInfo");
        _glfw.x11.randr.GetOutputPrimary = (PFN_XRRGetOutputPrimary)
            _glfw_dlsym(_glfw.x11.randr.handle, "XRRGetOutputPrimary");
        _glfw.x11.randr.GetScreenResourcesCurrent = (PFN_XRRGetScreenResourcesCurrent)
            _glfw_dlsym(_glfw.x11.randr.handle, "XRRGetScreenResourcesCurrent");
        _glfw.x11.randr.QueryExtension = (PFN_XRRQueryExtension)
            _glfw_dlsym(_glfw.x11.randr.handle, "XRRQueryExtension");
        _glfw.x11.randr.QueryVersion = (PFN_XRRQueryVersion)
            _glfw_dlsym(_glfw.x11.randr.handle, "XRRQueryVersion");
        _glfw.x11.randr.SelectInput = (PFN_XRRSelectInput)
            _glfw_dlsym(_glfw.x11.randr.handle, "XRRSelectInput");
        _glfw.x11.randr.SetCrtcConfig = (PFN_XRRSetCrtcConfig)
            _glfw_dlsym(_glfw.x11.randr.handle, "XRRSetCrtcConfig");
        _glfw.x11.randr.SetCrtcGamma = (PFN_XRRSetCrtcGamma)
            _glfw_dlsym(_glfw.x11.randr.handle, "XRRSetCrtcGamma");
        _glfw.x11.randr.UpdateConfiguration = (PFN_XRRUpdateConfiguration)
            _glfw_dlsym(_glfw.x11.randr.handle, "XRRUpdateConfiguration");

        if (XRRQueryExtension(_glfw.x11.display,
                              &_glfw.x11.randr.eventBase,
                              &_glfw.x11.randr.errorBase))
        {
            if (XRRQueryVersion(_glfw.x11.display,
                                &_glfw.x11.randr.major,
                                &_glfw.x11.randr.minor))
            {
                // The GLFW RandR path requires at least version 1.3
                if (_glfw.x11.randr.major > 1 || _glfw.x11.randr.minor >= 3)
                    _glfw.x11.randr.available = GLFW_TRUE;
            }
            else
            {
                _glfwInputError(GLFW_PLATFORM_ERROR,
                                "X11: Failed to query RandR version");
            }
        }
    }

    if (_glfw.x11.randr.available)
    {
        XRRScreenResources* sr = XRRGetScreenResourcesCurrent(_glfw.x11.display,
                                                              _glfw.x11.root);

        if (!sr->ncrtc || !XRRGetCrtcGammaSize(_glfw.x11.display, sr->crtcs[0]))
        {
            // This is likely an older Nvidia driver with broken gamma support
            // Flag it as useless and fall back to xf86vm gamma, if available
            _glfw.x11.randr.gammaBroken = GLFW_TRUE;
        }

        if (!sr->ncrtc)
        {
            // A system without CRTCs is likely a system with broken RandR
            // Disable the RandR monitor path and fall back to core functions
            _glfw.x11.randr.monitorBroken = GLFW_TRUE;
        }

        XRRFreeScreenResources(sr);
    }

    if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken)
    {
        XRRSelectInput(_glfw.x11.display, _glfw.x11.root,
                       RROutputChangeNotifyMask);
    }

#if defined(__CYGWIN__)
    _glfw.x11.xcursor.handle = _glfw_dlopen("libXcursor-1.so");
#else
    _glfw.x11.xcursor.handle = _glfw_dlopen("libXcursor.so.1");
#endif
    if (_glfw.x11.xcursor.handle)
    {
        _glfw.x11.xcursor.ImageCreate = (PFN_XcursorImageCreate)
            _glfw_dlsym(_glfw.x11.xcursor.handle, "XcursorImageCreate");
        _glfw.x11.xcursor.ImageDestroy = (PFN_XcursorImageDestroy)
            _glfw_dlsym(_glfw.x11.xcursor.handle, "XcursorImageDestroy");
        _glfw.x11.xcursor.ImageLoadCursor = (PFN_XcursorImageLoadCursor)
            _glfw_dlsym(_glfw.x11.xcursor.handle, "XcursorImageLoadCursor");
    }

#if defined(__CYGWIN__)
    _glfw.x11.xinerama.handle = _glfw_dlopen("libXinerama-1.so");
#else
    _glfw.x11.xinerama.handle = _glfw_dlopen("libXinerama.so.1");
#endif
    if (_glfw.x11.xinerama.handle)
    {
        _glfw.x11.xinerama.IsActive = (PFN_XineramaIsActive)
            _glfw_dlsym(_glfw.x11.xinerama.handle, "XineramaIsActive");
        _glfw.x11.xinerama.QueryExtension = (PFN_XineramaQueryExtension)
            _glfw_dlsym(_glfw.x11.xinerama.handle, "XineramaQueryExtension");
        _glfw.x11.xinerama.QueryScreens = (PFN_XineramaQueryScreens)
            _glfw_dlsym(_glfw.x11.xinerama.handle, "XineramaQueryScreens");

        if (XineramaQueryExtension(_glfw.x11.display,
                                   &_glfw.x11.xinerama.major,
                                   &_glfw.x11.xinerama.minor))
        {
            if (XineramaIsActive(_glfw.x11.display))
                _glfw.x11.xinerama.available = GLFW_TRUE;
        }
    }

    _glfw.x11.xkb.major = 1;
    _glfw.x11.xkb.minor = 0;
    _glfw.x11.xkb.available =
        XkbQueryExtension(_glfw.x11.display,
                          &_glfw.x11.xkb.majorOpcode,
                          &_glfw.x11.xkb.eventBase,
                          &_glfw.x11.xkb.errorBase,
                          &_glfw.x11.xkb.major,
                          &_glfw.x11.xkb.minor);

    if (_glfw.x11.xkb.available)
    {
        Bool supported;

        if (XkbSetDetectableAutoRepeat(_glfw.x11.display, True, &supported))
        {
            if (supported)
                _glfw.x11.xkb.detectable = GLFW_TRUE;
        }
    }

#if defined(__CYGWIN__)
    _glfw.x11.x11xcb.handle = _glfw_dlopen("libX11-xcb-1.so");
#else
    _glfw.x11.x11xcb.handle = _glfw_dlopen("libX11-xcb.so.1");
#endif
    if (_glfw.x11.x11xcb.handle)
    {
        _glfw.x11.x11xcb.GetXCBConnection = (PFN_XGetXCBConnection)
            _glfw_dlsym(_glfw.x11.x11xcb.handle, "XGetXCBConnection");
    }

#if defined(__CYGWIN__)
    _glfw.x11.xrender.handle = _glfw_dlopen("libXrender-1.so");
#else
    _glfw.x11.xrender.handle = _glfw_dlopen("libXrender.so.1");
#endif
    if (_glfw.x11.xrender.handle)
    {
        _glfw.x11.xrender.QueryExtension = (PFN_XRenderQueryExtension)
            _glfw_dlsym(_glfw.x11.xrender.handle, "XRenderQueryExtension");
        _glfw.x11.xrender.QueryVersion = (PFN_XRenderQueryVersion)
            _glfw_dlsym(_glfw.x11.xrender.handle, "XRenderQueryVersion");
        _glfw.x11.xrender.FindVisualFormat = (PFN_XRenderFindVisualFormat)
            _glfw_dlsym(_glfw.x11.xrender.handle, "XRenderFindVisualFormat");

        if (XRenderQueryExtension(_glfw.x11.display,
                                  &_glfw.x11.xrender.errorBase,
                                  &_glfw.x11.xrender.eventBase))
        {
            if (XRenderQueryVersion(_glfw.x11.display,
                                    &_glfw.x11.xrender.major,
                                    &_glfw.x11.xrender.minor))
            {
                _glfw.x11.xrender.available = GLFW_TRUE;
            }
        }
    }

    // Update the key code LUT
    // FIXME: We should listen to XkbMapNotify events to track changes to
    // the keyboard mapping.
    createKeyTables();

    // Detect whether an EWMH-conformant window manager is running
    detectEWMH();

    // String format atoms
    _glfw.x11.NULL_ = XInternAtom(_glfw.x11.display, "NULL", False);
    _glfw.x11.UTF8_STRING = XInternAtom(_glfw.x11.display, "UTF8_STRING", False);
    _glfw.x11.ATOM_PAIR = XInternAtom(_glfw.x11.display, "ATOM_PAIR", False);

    // Custom selection property atom
    _glfw.x11.GLFW_SELECTION =
        XInternAtom(_glfw.x11.display, "GLFW_SELECTION", False);

    // ICCCM standard clipboard atoms
    _glfw.x11.TARGETS = XInternAtom(_glfw.x11.display, "TARGETS", False);
    _glfw.x11.MULTIPLE = XInternAtom(_glfw.x11.display, "MULTIPLE", False);
    _glfw.x11.PRIMARY = XInternAtom(_glfw.x11.display, "PRIMARY", False);
    _glfw.x11.INCR = XInternAtom(_glfw.x11.display, "INCR", False);
    _glfw.x11.CLIPBOARD = XInternAtom(_glfw.x11.display, "CLIPBOARD", False);

    // Clipboard manager atoms
    _glfw.x11.CLIPBOARD_MANAGER =
        XInternAtom(_glfw.x11.display, "CLIPBOARD_MANAGER", False);
    _glfw.x11.SAVE_TARGETS =
        XInternAtom(_glfw.x11.display, "SAVE_TARGETS", False);

    // Xdnd (drag and drop) atoms
    _glfw.x11.XdndAware = XInternAtom(_glfw.x11.display, "XdndAware", False);
    _glfw.x11.XdndEnter = XInternAtom(_glfw.x11.display, "XdndEnter", False);
    _glfw.x11.XdndPosition = XInternAtom(_glfw.x11.display, "XdndPosition", False);
    _glfw.x11.XdndStatus = XInternAtom(_glfw.x11.display, "XdndStatus", False);
    _glfw.x11.XdndActionCopy = XInternAtom(_glfw.x11.display, "XdndActionCopy", False);
    _glfw.x11.XdndDrop = XInternAtom(_glfw.x11.display, "XdndDrop", False);
    _glfw.x11.XdndFinished = XInternAtom(_glfw.x11.display, "XdndFinished", False);
    _glfw.x11.XdndSelection = XInternAtom(_glfw.x11.display, "XdndSelection", False);
    _glfw.x11.XdndTypeList = XInternAtom(_glfw.x11.display, "XdndTypeList", False);
    _glfw.x11.text_uri_list = XInternAtom(_glfw.x11.display, "text/uri-list", False);

    // ICCCM, EWMH and Motif window property atoms
    // These can be set safely even without WM support
    // The EWMH atoms that require WM support are handled in detectEWMH
    _glfw.x11.WM_PROTOCOLS =
        XInternAtom(_glfw.x11.display, "WM_PROTOCOLS", False);
    _glfw.x11.WM_STATE =
        XInternAtom(_glfw.x11.display, "WM_STATE", False);
    _glfw.x11.WM_DELETE_WINDOW =
        XInternAtom(_glfw.x11.display, "WM_DELETE_WINDOW", False);
    _glfw.x11.NET_WM_ICON =
        XInternAtom(_glfw.x11.display, "_NET_WM_ICON", False);
    _glfw.x11.NET_WM_PING =
        XInternAtom(_glfw.x11.display, "_NET_WM_PING", False);
    _glfw.x11.NET_WM_PID =
        XInternAtom(_glfw.x11.display, "_NET_WM_PID", False);
    _glfw.x11.NET_WM_NAME =
        XInternAtom(_glfw.x11.display, "_NET_WM_NAME", False);
    _glfw.x11.NET_WM_ICON_NAME =
        XInternAtom(_glfw.x11.display, "_NET_WM_ICON_NAME", False);
    _glfw.x11.NET_WM_BYPASS_COMPOSITOR =
        XInternAtom(_glfw.x11.display, "_NET_WM_BYPASS_COMPOSITOR", False);
    _glfw.x11.NET_WM_WINDOW_OPACITY =
        XInternAtom(_glfw.x11.display, "_NET_WM_WINDOW_OPACITY", False);
    _glfw.x11.MOTIF_WM_HINTS =
        XInternAtom(_glfw.x11.display, "_MOTIF_WM_HINTS", False);

    // The compositing manager selection name contains the screen number
    {
        char name[32];
        snprintf(name, sizeof(name), "_NET_WM_CM_S%u", _glfw.x11.screen);
        _glfw.x11.NET_WM_CM_Sx = XInternAtom(_glfw.x11.display, name, False);
    }

    return GLFW_TRUE;
}
Example #17
0
static gboolean
init_randr13 (GdkScreen *screen)
{
#ifdef HAVE_RANDR
  GdkDisplay *display = gdk_screen_get_display (screen);
  GdkX11Display *display_x11 = GDK_X11_DISPLAY (display);
  GdkX11Screen *x11_screen = GDK_X11_SCREEN (screen);
  Display *dpy = GDK_SCREEN_XDISPLAY (screen);
  XRRScreenResources *resources;
  RROutput primary_output;
  RROutput first_output = None;
  int i;
  GArray *monitors;
  gboolean randr12_compat = FALSE;

  if (!display_x11->have_randr13)
      return FALSE;

  resources = XRRGetScreenResourcesCurrent (x11_screen->xdisplay,
				            x11_screen->xroot_window);
  if (!resources)
    return FALSE;

  monitors = g_array_sized_new (FALSE, TRUE, sizeof (GdkX11Monitor),
                                resources->noutput);

  for (i = 0; i < resources->noutput; ++i)
    {
      XRROutputInfo *output =
	XRRGetOutputInfo (dpy, resources, resources->outputs[i]);

      /* Non RandR1.2 X driver have output name "default" */
      randr12_compat |= !g_strcmp0 (output->name, "default");

      if (output->connection == RR_Disconnected)
        {
          XRRFreeOutputInfo (output);
          continue;
        }

      if (output->crtc)
	{
	  GdkX11Monitor monitor;
	  XRRCrtcInfo *crtc = XRRGetCrtcInfo (dpy, resources, output->crtc);

	  monitor.geometry.x = crtc->x;
	  monitor.geometry.y = crtc->y;
	  monitor.geometry.width = crtc->width;
	  monitor.geometry.height = crtc->height;

	  monitor.output = resources->outputs[i];
	  monitor.width_mm = output->mm_width;
	  monitor.height_mm = output->mm_height;
	  monitor.output_name = g_strdup (output->name);
	  /* FIXME: need EDID parser */
	  monitor.manufacturer = NULL;

	  g_array_append_val (monitors, monitor);

          XRRFreeCrtcInfo (crtc);
	}

      XRRFreeOutputInfo (output);
    }

  if (resources->noutput > 0)
    first_output = resources->outputs[0];

  XRRFreeScreenResources (resources);

  /* non RandR 1.2 X driver doesn't return any usable multihead data */
  if (randr12_compat)
    {
      guint n_monitors = monitors->len;

      free_monitors ((GdkX11Monitor *)g_array_free (monitors, FALSE),
		     n_monitors);

      return FALSE;
    }

  g_array_sort (monitors,
                (GCompareFunc) monitor_compare_function);
  x11_screen->n_monitors = monitors->len;
  x11_screen->monitors = (GdkX11Monitor *)g_array_free (monitors, FALSE);

  x11_screen->primary_monitor = 0;

  primary_output = XRRGetOutputPrimary (x11_screen->xdisplay,
                                        x11_screen->xroot_window);

  for (i = 0; i < x11_screen->n_monitors; ++i)
    {
      if (x11_screen->monitors[i].output == primary_output)
	{
	  x11_screen->primary_monitor = i;
	  break;
	}

      /* No RandR1.3+ available or no primary set, fall back to prefer LVDS as primary if present */
      if (primary_output == None &&
          g_ascii_strncasecmp (x11_screen->monitors[i].output_name, "LVDS", 4) == 0)
	{
	  x11_screen->primary_monitor = i;
	  break;
	}

      /* No primary specified and no LVDS found */
      if (x11_screen->monitors[i].output == first_output)
	x11_screen->primary_monitor = i;
    }

  return x11_screen->n_monitors > 0;
#endif

  return FALSE;
}
Example #18
0
static gboolean
panel_multiscreen_get_randr_monitors_for_screen (GdkScreen     *screen,
						 int           *monitors_ret,
						 GdkRectangle **geometries_ret)
{
#ifdef HAVE_RANDR
	Display            *xdisplay;
	Window              xroot;
	XRRScreenResources *resources;
	RROutput            primary;
	GArray             *geometries;
	int                 i;
	gboolean            driver_is_pre_randr_1_2;

	if (!have_randr)
		return FALSE;

	/* GTK+ 2.14.x uses the Xinerama API, instead of RANDR, to get the
	 * monitor geometries. It does this to avoid calling
	 * XRRGetScreenResources(), which is slow as it re-detects all the
	 * monitors --- note that XRRGetScreenResourcesCurrent() had not been
	 * introduced yet.  Using Xinerama in GTK+ has the bad side effect that
	 * gdk_screen_get_monitor_plug_name() will return NULL, as Xinerama
	 * does not provide that information, unlike RANDR.
	 *
	 * Here we need to identify the output names, so that we can put the
	 * built-in LCD in a laptop *before* all other outputs.  This is so
	 * that mate-panel will normally prefer to appear on the "native"
	 * display rather than on an external monitor.
	 *
	 * To get the output names and geometries, we will not use
	 * gdk_screen_get_n_monitors() and friends, but rather we will call
	 * XRR*() directly.
	 *
	 * See https://bugzilla.novell.com/show_bug.cgi?id=479684 for this
	 * particular bug, and and
	 * http://bugzilla.gnome.org/show_bug.cgi?id=562944 for a more
	 * long-term solution.
	 */

	xdisplay = GDK_SCREEN_XDISPLAY (screen);
#if GTK_CHECK_VERSION (3, 0, 0)
	xroot = GDK_WINDOW_XID (gdk_screen_get_root_window (screen));
#else
	xroot = GDK_WINDOW_XWINDOW (gdk_screen_get_root_window (screen));
#endif

#if (RANDR_MAJOR > 1 || (RANDR_MAJOR == 1 && RANDR_MINOR >= 3))
	if (have_randr_1_3) {
		resources = XRRGetScreenResourcesCurrent (xdisplay, xroot);
		if (resources->noutput == 0) {
			/* This might happen if nothing tried to get randr
			 * resources from the server before, so we need an
			 * active probe. See comment #27 in
			 * https://bugzilla.gnome.org/show_bug.cgi?id=597101 */
			XRRFreeScreenResources (resources);
			resources = XRRGetScreenResources (xdisplay, xroot);
		}
	} else
		resources = XRRGetScreenResources (xdisplay, xroot);
#else
	resources = XRRGetScreenResources (xdisplay, xroot);
#endif

	if (!resources)
		return FALSE;

	primary = None;
#if (RANDR_MAJOR > 1 || (RANDR_MAJOR == 1 && RANDR_MINOR >= 3))
	if (have_randr_1_3)
		primary = XRRGetOutputPrimary (xdisplay, xroot);
#endif

	geometries = g_array_sized_new (FALSE, FALSE,
					sizeof (GdkRectangle),
					resources->noutput);

	driver_is_pre_randr_1_2 = FALSE;

	for (i = 0; i < resources->noutput; i++) {
		XRROutputInfo *output;

		output = XRRGetOutputInfo (xdisplay, resources,
					   resources->outputs[i]);

		/* Drivers before RANDR 1.2 return "default" for the output
		 * name */
		if (g_strcmp0 (output->name, "default") == 0)
			driver_is_pre_randr_1_2 = TRUE;

		if (output->connection != RR_Disconnected &&
		    output->crtc != 0) {
			XRRCrtcInfo  *crtc;
			GdkRectangle  rect;

			crtc = XRRGetCrtcInfo (xdisplay, resources,
					       output->crtc);

			rect.x	    = crtc->x;
			rect.y	    = crtc->y;
			rect.width  = crtc->width;
			rect.height = crtc->height;

			XRRFreeCrtcInfo (crtc);

			if (_panel_multiscreen_output_should_be_first (xdisplay,
								       resources->outputs[i],
								       output, primary))
				g_array_prepend_vals (geometries, &rect, 1);
			else
				g_array_append_vals (geometries, &rect, 1);
		}

		XRRFreeOutputInfo (output);
	}

	XRRFreeScreenResources (resources);

	if (driver_is_pre_randr_1_2) {
		/* Drivers before RANDR 1.2 don't provide useful info about
		 * outputs */
		g_array_free (geometries, TRUE);
		return FALSE;
	}

	if (geometries->len == 0) {
		/* This can happen in at least one case:
		 * https://bugzilla.novell.com/show_bug.cgi?id=543876 where all
		 * monitors appear disconnected (possibly because the  screen
		 * is behing a KVM switch) -- see comment #8.
		 * There might be other cases too, so we stay on the safe side.
		 */
		g_array_free (geometries, TRUE);
		return FALSE;
	}

	*monitors_ret = geometries->len;
	*geometries_ret = (GdkRectangle *) g_array_free (geometries, FALSE);

	return TRUE;
#else
	return FALSE;
#endif
}
static void
reload_monitor_infos (CsScreen *screen)
{
    GdkDisplay *gdk_display;
    Display *xdisplay;
    Window xroot;

    gdk_display = gdk_screen_get_display (screen->gdk_screen);
    xdisplay = gdk_x11_display_get_xdisplay (gdk_display);

    xroot = gdk_x11_window_get_xid (gdk_screen_get_root_window (screen->gdk_screen));

    /* Any previous screen->monitor_infos is freed by the caller */

    screen->monitor_infos = NULL;
    screen->n_monitor_infos = 0;

    /* Xinerama doesn't have a concept of primary monitor, however XRandR
     * does. However, the XRandR xinerama compat code always sorts the
     * primary output first, so we rely on that here. We could use the
     * native XRandR calls instead of xinerama, but that would be
     * slightly problematic for _NET_WM_FULLSCREEN_MONITORS support, as
     * that is defined in terms of xinerama monitor indexes.
     * So, since we don't need anything in xrandr except the primary
     * we can keep using xinerama and use the first monitor as the
     * primary.
     */

    screen->primary_monitor_index = PRIMARY_MONITOR;


#ifdef HAVE_XFREE_XINERAMA
    if (screen->n_monitor_infos == 0 &&
        XineramaIsActive (xdisplay))
    {
        XineramaScreenInfo *infos;
        int n_infos;
        int i;

        n_infos = 0;
        infos = XineramaQueryScreens (xdisplay, &n_infos);

        DEBUG ("Found %d Xinerama screens on display %s\n",
               n_infos, gdk_display_get_name (gdk_display));

        if (n_infos > 0)
        {
            screen->monitor_infos = g_new0 (CsMonitorInfo, n_infos);
            screen->n_monitor_infos = n_infos;

            i = 0;
            while (i < n_infos)
            {
                screen->monitor_infos[i].number = infos[i].screen_number;
                screen->monitor_infos[i].rect.x = infos[i].x_org;
                screen->monitor_infos[i].rect.y = infos[i].y_org;
                screen->monitor_infos[i].rect.width = infos[i].width;
                screen->monitor_infos[i].rect.height = infos[i].height;

                DEBUG ("Monitor %d is %d,%d %d x %d\n",
                       screen->monitor_infos[i].number,
                       screen->monitor_infos[i].rect.x,
                       screen->monitor_infos[i].rect.y,
                       screen->monitor_infos[i].rect.width,
                       screen->monitor_infos[i].rect.height);

                ++i;
            }
        }

        cs_XFree (infos);

#ifdef HAVE_RANDR
    {
        XRRScreenResources *resources;

        resources = XRRGetScreenResourcesCurrent (xdisplay, xroot);

        if (resources)
        {
            for (i = 0; i < resources->ncrtc; i++)
            {
                XRRCrtcInfo *crtc;
                CsMonitorInfo *info;

                crtc = XRRGetCrtcInfo (xdisplay, resources, resources->crtcs[i]);
                info = find_monitor_with_rect (screen, crtc->x, crtc->y, (int)crtc->width, (int)crtc->height);

                if (info)
                {
                  info->output = find_main_output_for_crtc (resources, crtc, xdisplay, xroot);
                }

                XRRFreeCrtcInfo (crtc);
            }

            XRRFreeScreenResources (resources);
        }
    }
#endif
    }
    else if (screen->n_monitor_infos > 0)
    {
        DEBUG ("No XFree86 Xinerama extension or XFree86 Xinerama inactive on display %s\n",
               gdk_display_get_name (gdk_display));
    }
#else
    DEBUG ("Muffin compiled without XFree86 Xinerama support\n");
#endif /* HAVE_XFREE_XINERAMA */

#ifdef HAVE_SOLARIS_XINERAMA
    /* This code from GDK, Copyright (C) 2002 Sun Microsystems */
    if (screen->n_monitor_infos == 0 &&
        XineramaGetState (xdisplay,
                          gdk_screen_get_number (screen->gdk_screen)))
    {
        XRectangle monitors[MAXFRAMEBUFFERS];
        unsigned char hints[16];
        int result;
        int n_monitors;
        int i;

        n_monitors = 0;
        result = XineramaGetInfo (xdisplay,
                                  gdk_screen_get_number (screen->gdk_screen),
                                  monitors, hints,
                                  &n_monitors);
        /* Yes I know it should be Success but the current implementation
         * returns the num of monitor
         */
        if (result > 0)
        {
            g_assert (n_monitors > 0);

            screen->monitor_infos = g_new0 (CsMonitorInfo, n_monitors);
            screen->n_monitor_infos = n_monitors;

            i = 0;
            while (i < n_monitors)
            {
                screen->monitor_infos[i].number = i;
                screen->monitor_infos[i].rect.x = monitors[i].x;
                screen->monitor_infos[i].rect.y = monitors[i].y;
                screen->monitor_infos[i].rect.width = monitors[i].width;
                screen->monitor_infos[i].rect.height = monitors[i].height;

                DEBUG ("Monitor %d is %d,%d %d x %d\n",
                       screen->monitor_infos[i].number,
                       screen->monitor_infos[i].rect.x,
                       screen->monitor_infos[i].rect.y,
                       screen->monitor_infos[i].rect.width,
                       screen->monitor_infos[i].rect.height);
                ++i;
            }
        }
    }
    else if (screen->n_monitor_infos == 0)
    {
        DEBUG ("No Solaris Xinerama extension or Solaris Xinerama inactive on display %s\n",
               gdk_display_get_name (gdk_display));
    }
#else
    DEBUG ("Cinnamon Screensaver compiled without Solaris Xinerama support\n");
#endif /* HAVE_SOLARIS_XINERAMA */

    /* If no Xinerama, fill in the single screen info so
     * we can use the field unconditionally
    */
    if (screen->n_monitor_infos == 0)
    {
        DEBUG ("No Xinerama screens, using default screen info\n");

        screen->monitor_infos = g_new0 (CsMonitorInfo, 1);
        screen->n_monitor_infos = 1;

        screen->monitor_infos[0].number = 0;
        screen->monitor_infos[0].rect = screen->rect;
    }

    filter_mirrored_monitors (screen);

    screen->monitor_infos[screen->primary_monitor_index].is_primary = TRUE;

    apply_scale_factor (screen->monitor_infos,
                        screen->n_monitor_infos,
                        gdk_screen_get_monitor_scale_factor (screen->gdk_screen, PRIMARY_MONITOR));

    g_assert (screen->n_monitor_infos > 0);
    g_assert (screen->monitor_infos != NULL);
}
Example #20
0
// Initialize X11 display and look for supported X11 extensions
//
static GLFWbool initExtensions(void)
{
    _glfw.x11.vidmode.handle = dlopen("libXxf86vm.so.1", RTLD_LAZY | RTLD_GLOBAL);
    if (_glfw.x11.vidmode.handle)
    {
        _glfw.x11.vidmode.QueryExtension = (PFN_XF86VidModeQueryExtension)
            dlsym(_glfw.x11.vidmode.handle, "XF86VidModeQueryExtension");
        _glfw.x11.vidmode.GetGammaRamp = (PFN_XF86VidModeGetGammaRamp)
            dlsym(_glfw.x11.vidmode.handle, "XF86VidModeGetGammaRamp");
        _glfw.x11.vidmode.SetGammaRamp = (PFN_XF86VidModeSetGammaRamp)
            dlsym(_glfw.x11.vidmode.handle, "XF86VidModeSetGammaRamp");
        _glfw.x11.vidmode.GetGammaRampSize = (PFN_XF86VidModeGetGammaRampSize)
            dlsym(_glfw.x11.vidmode.handle, "XF86VidModeGetGammaRampSize");

        _glfw.x11.vidmode.available =
            XF86VidModeQueryExtension(_glfw.x11.display,
                                      &_glfw.x11.vidmode.eventBase,
                                      &_glfw.x11.vidmode.errorBase);
    }

    _glfw.x11.xi.handle = dlopen("libXi.so", RTLD_LAZY | RTLD_GLOBAL);
    if (_glfw.x11.xi.handle)
    {
        _glfw.x11.xi.QueryVersion = (PFN_XIQueryVersion)
            dlsym(_glfw.x11.xi.handle, "XIQueryVersion");
        _glfw.x11.xi.SelectEvents = (PFN_XISelectEvents)
            dlsym(_glfw.x11.xi.handle, "XISelectEvents");

        if (XQueryExtension(_glfw.x11.display,
                            "XInputExtension",
                            &_glfw.x11.xi.majorOpcode,
                            &_glfw.x11.xi.eventBase,
                            &_glfw.x11.xi.errorBase))
        {
            _glfw.x11.xi.major = 2;
            _glfw.x11.xi.minor = 0;

            if (XIQueryVersion(_glfw.x11.display,
                               &_glfw.x11.xi.major,
                               &_glfw.x11.xi.minor) == Success)
            {
                _glfw.x11.xi.available = GLFW_TRUE;
            }
        }
    }

    // Check for RandR extension
    if (XRRQueryExtension(_glfw.x11.display,
                          &_glfw.x11.randr.eventBase,
                          &_glfw.x11.randr.errorBase))
    {
        if (XRRQueryVersion(_glfw.x11.display,
                            &_glfw.x11.randr.major,
                            &_glfw.x11.randr.minor))
        {
            // The GLFW RandR path requires at least version 1.3
            if (_glfw.x11.randr.major > 1 || _glfw.x11.randr.minor >= 3)
                _glfw.x11.randr.available = GLFW_TRUE;
        }
        else
        {
            _glfwInputError(GLFW_PLATFORM_ERROR,
                            "X11: Failed to query RandR version");
        }
    }

    if (_glfw.x11.randr.available)
    {
        XRRScreenResources* sr = XRRGetScreenResourcesCurrent(_glfw.x11.display,
                                                              _glfw.x11.root);

        if (!sr->ncrtc || !XRRGetCrtcGammaSize(_glfw.x11.display, sr->crtcs[0]))
        {
            // This is either a headless system or an older Nvidia binary driver
            // with broken gamma support
            // Flag it as useless and fall back to Xf86VidMode gamma, if
            // available
            _glfwInputError(GLFW_PLATFORM_ERROR,
                            "X11: Detected broken RandR gamma ramp support");
            _glfw.x11.randr.gammaBroken = GLFW_TRUE;
        }

        if (!sr->ncrtc || !sr->noutput || !sr->nmode)
        {
            // This is either a headless system or broken Cygwin/X RandR
            // Flag it as useless and fall back to Xlib display functions
            _glfwInputError(GLFW_PLATFORM_ERROR,
                            "X11: Detected broken RandR monitor support");
            _glfw.x11.randr.monitorBroken = GLFW_TRUE;
        }

        XRRFreeScreenResources(sr);

        XRRSelectInput(_glfw.x11.display, _glfw.x11.root,
                       RROutputChangeNotifyMask);
    }

    if (XineramaQueryExtension(_glfw.x11.display,
                               &_glfw.x11.xinerama.major,
                               &_glfw.x11.xinerama.minor))
    {
        if (XineramaIsActive(_glfw.x11.display))
            _glfw.x11.xinerama.available = GLFW_TRUE;
    }

    // Check if Xkb is supported on this display
    _glfw.x11.xkb.major = 1;
    _glfw.x11.xkb.minor = 0;
    _glfw.x11.xkb.available =
        XkbQueryExtension(_glfw.x11.display,
                          &_glfw.x11.xkb.majorOpcode,
                          &_glfw.x11.xkb.eventBase,
                          &_glfw.x11.xkb.errorBase,
                          &_glfw.x11.xkb.major,
                          &_glfw.x11.xkb.minor);

    if (_glfw.x11.xkb.available)
    {
        Bool supported;

        if (XkbSetDetectableAutoRepeat(_glfw.x11.display, True, &supported))
        {
            if (supported)
                _glfw.x11.xkb.detectable = GLFW_TRUE;
        }
    }

    _glfw.x11.x11xcb.handle = dlopen("libX11-xcb.so.1", RTLD_LAZY | RTLD_GLOBAL);
    if (_glfw.x11.x11xcb.handle)
    {
        _glfw.x11.x11xcb.XGetXCBConnection = (PFN_XGetXCBConnection)
            dlsym(_glfw.x11.x11xcb.handle, "XGetXCBConnection");
    }

    // Update the key code LUT
    // FIXME: We should listen to XkbMapNotify events to track changes to
    // the keyboard mapping.
    createKeyTables();

    // Detect whether an EWMH-conformant window manager is running
    detectEWMH();

    // String format atoms
    _glfw.x11.NULL_ = XInternAtom(_glfw.x11.display, "NULL", False);
    _glfw.x11.UTF8_STRING =
        XInternAtom(_glfw.x11.display, "UTF8_STRING", False);
    _glfw.x11.COMPOUND_STRING =
        XInternAtom(_glfw.x11.display, "COMPOUND_STRING", False);
    _glfw.x11.ATOM_PAIR = XInternAtom(_glfw.x11.display, "ATOM_PAIR", False);

    // Custom selection property atom
    _glfw.x11.GLFW_SELECTION =
        XInternAtom(_glfw.x11.display, "GLFW_SELECTION", False);

    // ICCCM standard clipboard atoms
    _glfw.x11.TARGETS = XInternAtom(_glfw.x11.display, "TARGETS", False);
    _glfw.x11.MULTIPLE = XInternAtom(_glfw.x11.display, "MULTIPLE", False);
    _glfw.x11.CLIPBOARD = XInternAtom(_glfw.x11.display, "CLIPBOARD", False);

    // Clipboard manager atoms
    _glfw.x11.CLIPBOARD_MANAGER =
        XInternAtom(_glfw.x11.display, "CLIPBOARD_MANAGER", False);
    _glfw.x11.SAVE_TARGETS =
        XInternAtom(_glfw.x11.display, "SAVE_TARGETS", False);

    // Xdnd (drag and drop) atoms
    _glfw.x11.XdndAware = XInternAtom(_glfw.x11.display, "XdndAware", False);
    _glfw.x11.XdndEnter = XInternAtom(_glfw.x11.display, "XdndEnter", False);
    _glfw.x11.XdndPosition = XInternAtom(_glfw.x11.display, "XdndPosition", False);
    _glfw.x11.XdndStatus = XInternAtom(_glfw.x11.display, "XdndStatus", False);
    _glfw.x11.XdndActionCopy = XInternAtom(_glfw.x11.display, "XdndActionCopy", False);
    _glfw.x11.XdndDrop = XInternAtom(_glfw.x11.display, "XdndDrop", False);
    _glfw.x11.XdndFinished = XInternAtom(_glfw.x11.display, "XdndFinished", False);
    _glfw.x11.XdndSelection = XInternAtom(_glfw.x11.display, "XdndSelection", False);
    _glfw.x11.XdndTypeList = XInternAtom(_glfw.x11.display, "XdndTypeList", False);
    _glfw.x11.text_uri_list = XInternAtom(_glfw.x11.display, "text/uri-list", False);

    // ICCCM, EWMH and Motif window property atoms
    // These can be set safely even without WM support
    // The EWMH atoms that require WM support are handled in detectEWMH
    _glfw.x11.WM_PROTOCOLS =
        XInternAtom(_glfw.x11.display, "WM_PROTOCOLS", False);
    _glfw.x11.WM_STATE =
        XInternAtom(_glfw.x11.display, "WM_STATE", False);
    _glfw.x11.WM_DELETE_WINDOW =
        XInternAtom(_glfw.x11.display, "WM_DELETE_WINDOW", False);
    _glfw.x11.NET_WM_ICON =
        XInternAtom(_glfw.x11.display, "_NET_WM_ICON", False);
    _glfw.x11.NET_WM_PING =
        XInternAtom(_glfw.x11.display, "_NET_WM_PING", False);
    _glfw.x11.NET_WM_PID =
        XInternAtom(_glfw.x11.display, "_NET_WM_PID", False);
    _glfw.x11.NET_WM_NAME =
        XInternAtom(_glfw.x11.display, "_NET_WM_NAME", False);
    _glfw.x11.NET_WM_ICON_NAME =
        XInternAtom(_glfw.x11.display, "_NET_WM_ICON_NAME", False);
    _glfw.x11.NET_WM_BYPASS_COMPOSITOR =
        XInternAtom(_glfw.x11.display, "_NET_WM_BYPASS_COMPOSITOR", False);
    _glfw.x11.MOTIF_WM_HINTS =
        XInternAtom(_glfw.x11.display, "_MOTIF_WM_HINTS", False);

    return GLFW_TRUE;
}
Example #21
0
void get_monitors()
{
	int i, j, nbmonitor;
	if (XineramaIsActive(server.dsp)) {
		XineramaScreenInfo *info = XineramaQueryScreens(server.dsp, &nbmonitor);
		XRRScreenResources *res = XRRGetScreenResourcesCurrent(server.dsp, server.root_win);

		if (res && res->ncrtc >= nbmonitor) {
			// use xrandr to identify monitors (does not work with proprietery nvidia drivers)

			// Workaround for issue https://code.google.com/p/tint2/issues/detail?id=353
			// on some recent configs, XRRGetScreenResourcesCurrent returns a fantom monitor at last position
			{
				int i = res->ncrtc - 1;
				XRRCrtcInfo* crtc_info = XRRGetCrtcInfo(server.dsp, res, res->crtcs[i]);
				if (!(crtc_info->x || crtc_info->y || crtc_info->width || crtc_info->height)) {
					res->ncrtc -= 1;
				}
				XRRFreeCrtcInfo(crtc_info);
			}

			printf("xRandr: Found crtc's: %d\n", res->ncrtc );
			server.monitor = malloc(res->ncrtc * sizeof(Monitor));
			for (i=0; i<res->ncrtc; ++i) {
				XRRCrtcInfo* crtc_info = XRRGetCrtcInfo(server.dsp, res, res->crtcs[i]);
				server.monitor[i].x = crtc_info->x;
				server.monitor[i].y = crtc_info->y;
				server.monitor[i].width = crtc_info->width;
				server.monitor[i].height = crtc_info->height;
				server.monitor[i].names = malloc((crtc_info->noutput+1) * sizeof(char*));
				for (j=0; j<crtc_info->noutput; ++j) {
					XRROutputInfo* output_info = XRRGetOutputInfo(server.dsp, res, crtc_info->outputs[j]);
					printf("xRandr: Linking output %s with crtc %d\n", output_info->name, i);
					server.monitor[i].names[j] = g_strdup(output_info->name);
					XRRFreeOutputInfo(output_info);
				}
				server.monitor[i].names[j] = 0;
				XRRFreeCrtcInfo(crtc_info);
			}
			nbmonitor = res->ncrtc;
		}
		else if (info && nbmonitor > 0) {
			server.monitor = malloc(nbmonitor * sizeof(Monitor));
			for (i=0 ; i < nbmonitor ; i++) {
				server.monitor[i].x = info[i].x_org;
				server.monitor[i].y = info[i].y_org;
				server.monitor[i].width = info[i].width;
				server.monitor[i].height = info[i].height;
				server.monitor[i].names = 0;
			}
		}

		// ordered monitor
		qsort(server.monitor, nbmonitor, sizeof(Monitor), compareMonitorIncluded);

		// remove monitor included into another one
		i = 0;
		while (i < nbmonitor) {
			for (j=0; j < i ; j++) {
				if (compareMonitorIncluded(&server.monitor[i], &server.monitor[j]) > 0) {
					goto next;
				}
			}
			i++;
		}
next:
		for (j=i; j<nbmonitor; ++j)
			if (server.monitor[j].names)
				g_strfreev(server.monitor[j].names);
		server.nb_monitor = i;
		server.monitor = realloc(server.monitor, server.nb_monitor * sizeof(Monitor));
		qsort(server.monitor, server.nb_monitor, sizeof(Monitor), compareMonitorPos);

		if (res)
			XRRFreeScreenResources(res);
		XFree(info);
	}

	if (!server.nb_monitor) {
		server.nb_monitor = 1;
		server.monitor = malloc(sizeof(Monitor));
		server.monitor[0].x = server.monitor[0].y = 0;
		server.monitor[0].width = DisplayWidth (server.dsp, server.screen);
		server.monitor[0].height = DisplayHeight (server.dsp, server.screen);
		server.monitor[0].names = 0;
	}
}
int
main (int argc, char **argv)
{
  Display            *xdpy;
  XRRScreenResources *screen_res = NULL;
  XRROutputInfo      *output     = NULL;
  XRRCrtcInfo        *ci         = NULL;
  RRMode              mode;
  GList              *modes      = NULL;
  GList              *modes_w    = NULL;
  GList              *modes_n    = NULL;
  int                 i, j;
  int                 retval = 1;

  xdpy = XOpenDisplay (g_getenv("DISPLAY"));
  g_assert (xdpy);

  screen_res = XRRGetScreenResourcesCurrent (xdpy, DefaultRootWindow (xdpy));

  output = pick_output (xdpy, screen_res);

  for (i = 0; i < screen_res->nmode; i++)
    {
      int          ratio;
      gboolean     widescreen = FALSE;
      gboolean     valid      = FALSE;
      XRRModeInfo *mi         = &screen_res->modes[i];

      /* Skip modes with a height less than 720 straight away */
      if (mi->width < 720)
        continue;

      /*
       * Check whether this mode is available on our selected output
       */
      for (j = 0; j < output->nmode; ++j)
        {
          if (output->modes[j] == mi->id)
            {
              valid = TRUE;
              break;
            }
        }

      if (!valid)
        continue;

    /*
     * Build a list of all modes that are widescreen.
     *
     * Multiply by ten and truncate into an integer to avoid annoying float
     * comparisons.
     */
    ratio = ((double)mi->width / mi->height) * 10;
    switch (ratio)
      {
      default:
        g_debug ("Unknown ratio for %d x %d", mi->width, mi->height);
      case 13: /* 1.33, or 4:3 */
        widescreen = FALSE;
        break;
      case 16: /* 1.6, or 16:10 */
      case 17: /* 1.777, or 16;9 */
      case 23: /* 2.333, or 21:9 */
        g_debug ("Found widescreen ratio %d", ratio);
        widescreen = TRUE;
        break;
      }

    if (widescreen)
      modes_w = g_list_prepend (modes_w, mi);
    else
      modes_n = g_list_prepend (modes_n, mi);
  }

  if (modes_w)
    modes = modes_w;
  else
    modes = modes_n;

  if (!modes)
    {
      g_warning ("No usable modes detected!\n");
      goto done;
    }

  /* Now sort it so they are sorted in order of distance from 720 */
  modes = g_list_sort (modes, size_sorter);
  mode = ((XRRModeInfo*)(modes->data))->id;

  g_debug ("Chose %d x %d",
           ((XRRModeInfo*)(modes->data))->width,
           ((XRRModeInfo*)(modes->data))->height);

  ci = XRRGetCrtcInfo (xdpy, screen_res, output->crtc);

  if (ci->mode != mode)
    {
      if (Success != XRRSetCrtcConfig (xdpy,
                                       screen_res,
                                       output->crtc,
                                       CurrentTime,
                                       0, 0,
                                       ((XRRModeInfo*)(modes->data))->id,
                                       RR_Rotate_0,
                                       ci->outputs, ci->noutput))
        {
          g_warning ("Failed to apply chosen mode");
        }
      else
        retval = 0;

    }
  else
    {
      retval = 0;
      g_debug ("Already in best mode");
    }

 done:
  if (output)
    XRRFreeOutputInfo (output);

  if (ci)
    XRRFreeCrtcInfo (ci);

  if (screen_res)
    XRRFreeScreenResources (screen_res);

  g_list_free (modes_w);
  g_list_free (modes_n);

  XCloseDisplay (xdpy);

  return retval;
}
Example #23
0
static gboolean
init_randr15 (GdkX11Screen *x11_screen, gboolean *changed)
{
#ifdef HAVE_RANDR15
  GdkDisplay *display = GDK_SCREEN_DISPLAY (x11_screen);
  GdkX11Display *x11_display = GDK_X11_DISPLAY (display);
  XRRScreenResources *resources;
  RROutput primary_output = None;
  RROutput first_output = None;
  int i;
  XRRMonitorInfo *rr_monitors;
  int num_rr_monitors;
  int old_primary;

  if (!x11_display->have_randr15)
    return FALSE;

  resources = XRRGetScreenResourcesCurrent (x11_screen->xdisplay,
                                            x11_screen->xroot_window);
  if (!resources)
    return FALSE;

  rr_monitors = XRRGetMonitors (x11_screen->xdisplay,
                                x11_screen->xroot_window,
                                True,
                                &num_rr_monitors);
  if (!rr_monitors)
    return FALSE;

  for (i = 0; i < x11_display->monitors->len; i++)
    {
      GdkX11Monitor *monitor = x11_display->monitors->pdata[i];
      monitor->add = FALSE;
      monitor->remove = TRUE;
    }

  for (i = 0; i < num_rr_monitors; i++)
    {
      RROutput output = rr_monitors[i].outputs[0];
      XRROutputInfo *output_info;
      GdkX11Monitor *monitor;
      GdkRectangle geometry;
      GdkRectangle newgeo;
      char *name;
      int refresh_rate = 0;

      gdk_x11_display_error_trap_push (display);
      output_info = XRRGetOutputInfo (x11_screen->xdisplay, resources, output);
      if (gdk_x11_display_error_trap_pop (display))
        continue;

      if (output_info == NULL)
        continue;

      if (output_info->connection == RR_Disconnected)
        {
          XRRFreeOutputInfo (output_info);
          continue;
        }

      if (first_output == None)
        first_output = output;

      if (output_info->crtc)
        {
          XRRCrtcInfo *crtc = XRRGetCrtcInfo (x11_screen->xdisplay, resources, output_info->crtc);
          int j;

          for (j = 0; j < resources->nmode; j++)
            {
              XRRModeInfo *xmode = &resources->modes[j];
              if (xmode->id == crtc->mode)
                {
                  if (xmode->hTotal != 0 && xmode->vTotal != 0)
                    refresh_rate = (1000 * xmode->dotClock) / (xmode->hTotal * xmode->vTotal);
                  break;
                }
            }

          XRRFreeCrtcInfo (crtc);
        }

      monitor = find_monitor_by_output (x11_display, output);
      if (monitor)
        monitor->remove = FALSE;
      else
        {
          monitor = g_object_new (GDK_TYPE_X11_MONITOR,
                                  "display", display,
                                  NULL);
          monitor->output = output;
          monitor->add = TRUE;
          g_ptr_array_add (x11_display->monitors, monitor);
        }

      gdk_monitor_get_geometry (GDK_MONITOR (monitor), &geometry);
      name = g_strndup (output_info->name, output_info->nameLen);

      newgeo.x = rr_monitors[i].x / x11_screen->surface_scale;
      newgeo.y = rr_monitors[i].y / x11_screen->surface_scale;
      newgeo.width = rr_monitors[i].width / x11_screen->surface_scale;
      newgeo.height = rr_monitors[i].height / x11_screen->surface_scale;
      if (newgeo.x != geometry.x ||
          newgeo.y != geometry.y ||
          newgeo.width != geometry.width ||
          newgeo.height != geometry.height ||
          rr_monitors[i].mwidth != gdk_monitor_get_width_mm (GDK_MONITOR (monitor)) ||
          rr_monitors[i].mheight != gdk_monitor_get_height_mm (GDK_MONITOR (monitor)) ||
          g_strcmp0 (name, gdk_monitor_get_model (GDK_MONITOR (monitor))))
        *changed = TRUE;

      gdk_monitor_set_position (GDK_MONITOR (monitor), newgeo.x, newgeo.y);
      gdk_monitor_set_size (GDK_MONITOR (monitor), newgeo.width, newgeo.height);
      g_object_notify (G_OBJECT (monitor), "workarea");
      gdk_monitor_set_physical_size (GDK_MONITOR (monitor),
                                     rr_monitors[i].mwidth,
                                     rr_monitors[i].mheight);
      gdk_monitor_set_subpixel_layout (GDK_MONITOR (monitor),
                                       translate_subpixel_order (output_info->subpixel_order));
      gdk_monitor_set_refresh_rate (GDK_MONITOR (monitor), refresh_rate);
      gdk_monitor_set_scale_factor (GDK_MONITOR (monitor), x11_screen->surface_scale);
      gdk_monitor_set_model (GDK_MONITOR (monitor), name);
      g_free (name);

      if (rr_monitors[i].primary)
        primary_output = monitor->output;

      XRRFreeOutputInfo (output_info);
    }

  XRRFreeMonitors (rr_monitors);
  XRRFreeScreenResources (resources);

  for (i = x11_display->monitors->len - 1; i >= 0; i--)
    {
      GdkX11Monitor *monitor = x11_display->monitors->pdata[i];
      if (monitor->add)
        {
          gdk_display_monitor_added (display, GDK_MONITOR (monitor));
          *changed = TRUE;
        }
      else if (monitor->remove)
        {
          g_object_ref (monitor);
          g_ptr_array_remove (x11_display->monitors, monitor);
          gdk_display_monitor_removed (display, GDK_MONITOR (monitor));
          g_object_unref (monitor);
          *changed = TRUE;
        }
    }

  old_primary = x11_display->primary_monitor;
  x11_display->primary_monitor = 0;
  for (i = 0; i < x11_display->monitors->len; ++i)
    {
      GdkX11Monitor *monitor = x11_display->monitors->pdata[i];
      if (monitor->output == primary_output)
        {
          x11_display->primary_monitor = i;
          break;
        }

      /* No RandR1.3+ available or no primary set, fall back to prefer LVDS as primary if present */
      if (primary_output == None &&
          g_ascii_strncasecmp (gdk_monitor_get_model (GDK_MONITOR (monitor)), "LVDS", 4) == 0)
        {
          x11_display->primary_monitor = i;
          break;
        }

      /* No primary specified and no LVDS found */
      if (monitor->output == first_output)
        x11_display->primary_monitor = i;
    }

  if (x11_display->primary_monitor != old_primary)
    *changed = TRUE;

  return x11_display->monitors->len > 0;
#endif

  return FALSE;
}
Example #24
0
static gboolean
fill_out_screen_info (Display *xdisplay,
		      Window xroot,
		      ScreenInfo *info,
		      gboolean needs_reprobe,
		      GError **error)
{
#ifdef HAVE_RANDR
    XRRScreenResources *resources;
    
    g_assert (xdisplay != NULL);
    g_assert (info != NULL);

    /* First update the screen resources */

    if (needs_reprobe)
        resources = XRRGetScreenResources (xdisplay, xroot);
    else
    {
	/* XRRGetScreenResourcesCurrent is less expensive than
	 * XRRGetScreenResources, however it is available only
	 * in RandR 1.3 or higher
	 */
#if (RANDR_MAJOR > 1 || (RANDR_MAJOR == 1 && RANDR_MINOR >= 3))
        /* Runtime check for RandR 1.3 or higher */
        if (info->screen->rr_major_version == 1 && info->screen->rr_minor_version >= 3)
            resources = XRRGetScreenResourcesCurrent (xdisplay, xroot);
        else
            resources = XRRGetScreenResources (xdisplay, xroot);
#else
        resources = XRRGetScreenResources (xdisplay, xroot);
#endif
    }

    if (resources)
    {
	if (!fill_screen_info_from_resources (info, resources, error))
	    return FALSE;
    }
    else
    {
	g_set_error (error, MATE_RR_ERROR, MATE_RR_ERROR_RANDR_ERROR,
		     /* Translators: a CRTC is a CRT Controller (this is X terminology). */
		     _("could not get the screen resources (CRTCs, outputs, modes)"));
	return FALSE;
    }

    /* Then update the screen size range.  We do this after XRRGetScreenResources() so that
     * the X server will already have an updated view of the outputs.
     */

    if (needs_reprobe) {
	gboolean success;

        gdk_error_trap_push ();
	success = XRRGetScreenSizeRange (xdisplay, xroot,
					 &(info->min_width),
					 &(info->min_height),
					 &(info->max_width),
					 &(info->max_height));
	gdk_flush ();
	if (gdk_error_trap_pop ()) {
	    g_set_error (error, MATE_RR_ERROR, MATE_RR_ERROR_UNKNOWN,
			 _("unhandled X error while getting the range of screen sizes"));
	    return FALSE;
	}

	if (!success) {
	    g_set_error (error, MATE_RR_ERROR, MATE_RR_ERROR_RANDR_ERROR,
			 _("could not get the range of screen sizes"));
            return FALSE;
        }
    }
    else
    {
        mate_rr_screen_get_ranges (info->screen, 
					 &(info->min_width),
					 &(info->max_width),
					 &(info->min_height),
					 &(info->max_height));
    }

    info->primary = None;
#if (RANDR_MAJOR > 1 || (RANDR_MAJOR == 1 && RANDR_MINOR >= 3))
    /* Runtime check for RandR 1.3 or higher */
    if (info->screen->rr_major_version == 1 && info->screen->rr_minor_version >= 3) {
        gdk_error_trap_push ();
        info->primary = XRRGetOutputPrimary (xdisplay, xroot);
      #if GTK_CHECK_VERSION (3, 0, 0)
	gdk_error_trap_pop_ignored ();
      #else
	gdk_flush ();
	gdk_error_trap_pop (); /* ignore error */
      #endif
    }
#endif

    return TRUE;
#else
    return FALSE;
#endif /* HAVE_RANDR */
}
Example #25
0
static gboolean
init_randr13 (GdkScreen *screen, gboolean *changed)
{
#ifdef HAVE_RANDR
  GdkDisplay *display = gdk_screen_get_display (screen);
  GdkX11Display *x11_display = GDK_X11_DISPLAY (display);
  GdkX11Screen *x11_screen = GDK_X11_SCREEN (screen);
  XRRScreenResources *resources;
  RROutput primary_output = None;
  RROutput first_output = None;
  int i;
  gboolean randr12_compat = FALSE;
  int old_primary;

  if (!x11_display->have_randr13)
      return FALSE;

  resources = XRRGetScreenResourcesCurrent (x11_screen->xdisplay,
                                            x11_screen->xroot_window);
  if (!resources)
    return FALSE;

  for (i = 0; i < x11_display->monitors->len; i++)
    {
      GdkX11Monitor *monitor = x11_display->monitors->pdata[i];
      monitor->add = FALSE;
      monitor->remove = TRUE;
    }

  for (i = 0; i < resources->noutput; ++i)
    {
      RROutput output = resources->outputs[i];
      XRROutputInfo *output_info =
        XRRGetOutputInfo (x11_screen->xdisplay, resources, output);

      /* Non RandR1.2+ X driver have output name "default" */
      randr12_compat |= !g_strcmp0 (output_info->name, "default");

      if (output_info->connection == RR_Disconnected)
        {
          XRRFreeOutputInfo (output_info);
          continue;
        }

      if (output_info->crtc)
	{
	  GdkX11Monitor *monitor;
	  XRRCrtcInfo *crtc = XRRGetCrtcInfo (x11_screen->xdisplay, resources, output_info->crtc);
          char *name;
          GdkRectangle geometry;
          GdkRectangle newgeo;
          int j;
          int refresh_rate = 0;

          for (j = 0; j < resources->nmode; j++)
            {
              XRRModeInfo *xmode = &resources->modes[j];
              if (xmode->id == crtc->mode)
                {
                  refresh_rate = (1000 * xmode->dotClock) / (xmode->hTotal *xmode->vTotal);
                  break;
                }
            }

          monitor = find_monitor_by_output (x11_display, output);
          if (monitor)
            monitor->remove = FALSE;
          else
            {
              monitor = g_object_new (gdk_x11_monitor_get_type (),
                                      "display", display,
                                      NULL);
              monitor->output = output;
              monitor->add = TRUE;
              g_ptr_array_add (x11_display->monitors, monitor);
            }

          gdk_monitor_get_geometry (GDK_MONITOR (monitor), &geometry);
          name = g_strndup (output_info->name, output_info->nameLen);

          newgeo.x = crtc->x / x11_screen->window_scale;
          newgeo.y = crtc->y / x11_screen->window_scale;
          newgeo.width = crtc->width / x11_screen->window_scale;
          newgeo.height = crtc->height / x11_screen->window_scale;
          if (newgeo.x != geometry.x ||
              newgeo.y != geometry.y ||
              newgeo.width != geometry.width ||
              newgeo.height != geometry.height ||
              output_info->mm_width != gdk_monitor_get_width_mm (GDK_MONITOR (monitor)) ||
              output_info->mm_height != gdk_monitor_get_height_mm (GDK_MONITOR (monitor)) ||
              g_strcmp0 (name, gdk_monitor_get_model (GDK_MONITOR (monitor))) != 0)
            *changed = TRUE;

          gdk_monitor_set_position (GDK_MONITOR (monitor), newgeo.x, newgeo.y);
          gdk_monitor_set_size (GDK_MONITOR (monitor), newgeo.width, newgeo.height);
          g_object_notify (G_OBJECT (monitor), "workarea");
          gdk_monitor_set_physical_size (GDK_MONITOR (monitor),
                                         output_info->mm_width,
                                         output_info->mm_height);
          gdk_monitor_set_subpixel_layout (GDK_MONITOR (monitor),
                                           translate_subpixel_order (output_info->subpixel_order));
          gdk_monitor_set_refresh_rate (GDK_MONITOR (monitor), refresh_rate);
          gdk_monitor_set_scale_factor (GDK_MONITOR (monitor), x11_screen->window_scale);
          gdk_monitor_set_model (GDK_MONITOR (monitor), name);

          g_free (name);

          XRRFreeCrtcInfo (crtc);
	}

      XRRFreeOutputInfo (output_info);
    }

  if (resources->noutput > 0)
    first_output = resources->outputs[0];

  XRRFreeScreenResources (resources);

  if (randr12_compat)
    {
      for (i = 0; i < x11_display->monitors->len; i++)
        {
          GdkX11Monitor *monitor = x11_display->monitors->pdata[i];
          if (monitor->remove)
            gdk_display_monitor_removed (display, GDK_MONITOR (monitor));
        }
      g_ptr_array_remove_range (x11_display->monitors, 0, x11_display->monitors->len);
      return FALSE;
    }

  for (i = x11_display->monitors->len - 1; i >= 0; i--)
    {
      GdkX11Monitor *monitor = x11_display->monitors->pdata[i];
      if (monitor->add)
        {
          gdk_display_monitor_added (display, GDK_MONITOR (monitor));
          *changed = TRUE;
        }
      else if (monitor->remove)
        {
          g_object_ref (monitor);
          g_ptr_array_remove (x11_display->monitors, monitor);
          gdk_display_monitor_removed (display, GDK_MONITOR (monitor));
          g_object_unref (monitor);
          *changed = TRUE;
        }
    }

  old_primary = x11_display->primary_monitor;
  x11_display->primary_monitor = 0;
  primary_output = XRRGetOutputPrimary (x11_screen->xdisplay,
                                        x11_screen->xroot_window);

  for (i = 0; i < x11_display->monitors->len; ++i)
    {
      GdkX11Monitor *monitor = x11_display->monitors->pdata[i];
      if (monitor->output == primary_output)
        {
          x11_display->primary_monitor = i;
          break;
        }

      /* No RandR1.3+ available or no primary set, fall back to prefer LVDS as primary if present */
      if (primary_output == None &&
          g_ascii_strncasecmp (gdk_monitor_get_model (GDK_MONITOR (monitor)), "LVDS", 4) == 0)
        {
          x11_display->primary_monitor = i;
          break;
        }

      /* No primary specified and no LVDS found */
      if (monitor->output == first_output)
        x11_display->primary_monitor = i;
    }

  if (x11_display->primary_monitor != old_primary)
    *changed = TRUE;

  return x11_display->monitors->len > 0;
#endif

  return FALSE;
}
Example #26
0
File: server.c Project: o9000/tint2
void get_monitors()
{
	if (XineramaIsActive(server.display)) {
		int num_monitors;
		XineramaScreenInfo *info = XineramaQueryScreens(server.display, &num_monitors);
		XRRScreenResources *res = XRRGetScreenResourcesCurrent(server.display, server.root_win);
		RROutput primary_output = XRRGetOutputPrimary(server.display, server.root_win);

		if (res && res->ncrtc >= num_monitors) {
			// use xrandr to identify monitors (does not work with proprietery nvidia drivers)

			// Workaround for issue https://gitlab.com/o9000/tint2/issues/353
			// on some recent configs, XRRGetScreenResourcesCurrent returns a fantom monitor at last position
			{
				int i = res->ncrtc - 1;
				XRRCrtcInfo *crtc_info = XRRGetCrtcInfo(server.display, res, res->crtcs[i]);
				if (!(crtc_info->x || crtc_info->y || crtc_info->width || crtc_info->height)) {
					res->ncrtc -= 1;
				}
				XRRFreeCrtcInfo(crtc_info);
			}

			printf("xRandr: Found crtc's: %d\n", res->ncrtc);
			server.monitors = calloc(res->ncrtc, sizeof(Monitor));
			for (int i = 0; i < res->ncrtc; ++i) {
				XRRCrtcInfo *crtc_info = XRRGetCrtcInfo(server.display, res, res->crtcs[i]);
				server.monitors[i].x = crtc_info->x;
				server.monitors[i].y = crtc_info->y;
				server.monitors[i].width = crtc_info->width;
				server.monitors[i].height = crtc_info->height;
				server.monitors[i].names = calloc((crtc_info->noutput + 1), sizeof(gchar *));
				for (int j = 0; j < crtc_info->noutput; ++j) {
					XRROutputInfo *output_info = XRRGetOutputInfo(server.display, res, crtc_info->outputs[j]);
					printf("xRandr: Linking output %s with crtc %d\n", output_info->name, i);
					server.monitors[i].names[j] = g_strdup(output_info->name);
					XRRFreeOutputInfo(output_info);
					server.monitors[i].primary = crtc_info->outputs[j] == primary_output;
				}
				server.monitors[i].names[crtc_info->noutput] = NULL;
				XRRFreeCrtcInfo(crtc_info);
			}
			num_monitors = res->ncrtc;
		} else if (info && num_monitors > 0) {
			server.monitors = calloc(num_monitors, sizeof(Monitor));
			for (int i = 0; i < num_monitors; i++) {
				server.monitors[i].x = info[i].x_org;
				server.monitors[i].y = info[i].y_org;
				server.monitors[i].width = info[i].width;
				server.monitors[i].height = info[i].height;
				server.monitors[i].names = 0;
			}
		}

		// Sort monitors by inclusion
		qsort(server.monitors, num_monitors, sizeof(Monitor), monitor_includes_monitor);

		// Remove monitors included in other ones
		int i = 0;
		while (i < num_monitors) {
			for (int j = 0; j < i; j++) {
				if (monitor_includes_monitor(&server.monitors[i], &server.monitors[j]) > 0) {
					goto next;
				}
			}
			i++;
		}
	next:
		for (int j = i; j < num_monitors; ++j)
			if (server.monitors[j].names)
				g_strfreev(server.monitors[j].names);
		server.num_monitors = i;
		server.monitors = realloc(server.monitors, server.num_monitors * sizeof(Monitor));
		qsort(server.monitors, server.num_monitors, sizeof(Monitor), compare_monitor_pos);

		if (res)
			XRRFreeScreenResources(res);
		XFree(info);
	}

	if (!server.num_monitors) {
		server.num_monitors = 1;
		server.monitors = calloc(1, sizeof(Monitor));
		server.monitors[0].x = server.monitors[0].y = 0;
		server.monitors[0].width = DisplayWidth(server.display, server.screen);
		server.monitors[0].height = DisplayHeight(server.display, server.screen);
		server.monitors[0].names = 0;
	}
}
Example #27
0
int
apply_transform (Display *display,
                 Window root,
                 RRCrtc crtcnum,
                 const char *input_name)
{
    int ret;

    ret = EXIT_SUCCESS;

    if (ret != EXIT_FAILURE) {
        XRRScreenConfiguration *sconf;
        XRRScreenResources *res;
        XRRCrtcInfo *crtc;
        XRRCrtcTransformAttributes *transform;
        Status status;
        double amx[3][3];
        double sina, cosa;
        double hscale, vscale, hoffs, voffs;
        XRRScreenSize *ssize;
        int nsizes;
        Rotation srot;

        res = XRRGetScreenResourcesCurrent (display, root);
        sconf = XRRGetScreenInfo (display, root);
        ssize = XRRConfigSizes(sconf, &nsizes) + XRRConfigCurrentConfiguration (sconf, &srot);
        crtc = XRRGetCrtcInfo (display, res, crtcnum);

        if (verbose) {
            fprintf (stderr, "Screen: (%u, %u) 0x%02x\n", ssize->width, ssize->height, srot);
            fprintf (stderr, "CRTC: (%i, %i) (%u, %u) 0x%02x\n", crtc->x, crtc->y, crtc->width, crtc->height, crtc->rotation);
        }

        switch (srot) {
        case RR_Rotate_0:
        case RR_Rotate_180:
            hscale = (double)crtc->width/(double)ssize->width;
            vscale = (double)crtc->height/(double)ssize->height;
            break;
        case RR_Rotate_90:
        case RR_Rotate_270:
            hscale = (double)crtc->width/(double)ssize->height;
            vscale = (double)crtc->height/(double)ssize->width;
            break;
        default:
            ret = EXIT_FAILURE;
            fprintf (stderr, "The screen rotation/reflection 0x%02x is not supported yet. Sorry.\n", srot);
        }

        switch (crtc->rotation) {
        case RR_Rotate_0:
            sina = 0;
            cosa = 1;
            hoffs = 0;
            voffs = 0;
            break;
        case RR_Rotate_90:
            sina = 1;
            cosa = 0;
            hoffs = 1;
            voffs = 0;
            break;
        case RR_Rotate_180:
            sina = 0;
            cosa = -1;
            hoffs = 1;
            voffs = 1;
            break;
        case RR_Rotate_270:
            sina = -1;
            cosa = 0;
            hoffs = 0;
            voffs = 1;
            break;
        default:
            ret = EXIT_FAILURE;
            fprintf (stderr, "The rotation/reflection 0x%02x is not supported yet. Sorry.\n", crtc->rotation);
        }

        if (ret != EXIT_FAILURE) {
            amx[0][0] = cosa*hscale;
            amx[0][1] = -sina*hscale;
            amx[0][2] = hoffs*hscale + crtc->x/ssize->width;
            amx[1][0] = sina*vscale;
            amx[1][1] = cosa*vscale;
            amx[1][2] = voffs*vscale + crtc->y/ssize->height;
            amx[2][0] = 0;
            amx[2][1] = 0;
            amx[2][2] = 1;

            status = XRRGetCrtcTransform (display, crtcnum, &transform);
            if (!status) {
                fprintf (stderr, "Unable to get the current transformation\n");
                ret = EXIT_FAILURE;
            }
        }

        if (ret != EXIT_FAILURE) {
            static char strmx[3][3][8];
            static const char *args[11];
            double mx[3][3];
            int i, j;

            for (j = 0; j < 3; j++) {
                for (i = 0; i < 3; i++) {
                    XFixed fv = transform->currentTransform.matrix[j][i];
                    mx[j][i] = XFixedToDouble (fv);
                }
            }

            args[0] = input_name;
            args[1] = "Coordinate Transformation Matrix";
            for (j = 0; j < 3; j++) {
                for (i = 0; i < 3; i++) {
                    double v = mx[0][i]*amx[j][0] + mx[1][i]*amx[j][1] + mx[2][i]*amx[j][2];
                    snprintf (strmx[j][i], 8, "%8.6f", v);
                    args[2 + i + j*3] = strmx[j][i];
                }
            }
            if (verbose) {
                fprintf (stderr, "Debug: set-float-prop");
                for (i = 0; i < 11; i++) {
                    fprintf (stderr, " %s", args[i]);
                }
                fprintf (stderr, "\n");
            }
            ret = set_float_prop(display, 11, args, "set-float-prop", ": error calling function, please report a bug.");
            XFree (transform);
        }
        XRRFreeCrtcInfo (crtc);
        XRRFreeScreenResources (res);
        XRRFreeScreenConfigInfo (sconf);
    }

    return ret;
}
Example #28
0
// Poll for changes in the set of connected monitors
//
void _glfwPollMonitorsX11(void)
{
    if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken)
    {
        int i, j, disconnectedCount, screenCount = 0;
        _GLFWmonitor** disconnected = NULL;
        XineramaScreenInfo* screens = NULL;
        XRRScreenResources* sr = XRRGetScreenResourcesCurrent(_glfw.x11.display,
                                                              _glfw.x11.root);
        RROutput primary = XRRGetOutputPrimary(_glfw.x11.display,
                                               _glfw.x11.root);

        if (_glfw.x11.xinerama.available)
            screens = XineramaQueryScreens(_glfw.x11.display, &screenCount);

        disconnectedCount = _glfw.monitorCount;
        if (disconnectedCount)
        {
            disconnected = calloc(_glfw.monitorCount, sizeof(_GLFWmonitor*));
            memcpy(disconnected,
                   _glfw.monitors,
                   _glfw.monitorCount * sizeof(_GLFWmonitor*));
        }

        for (i = 0;  i < sr->noutput;  i++)
        {
            int type, widthMM, heightMM;
            XRROutputInfo* oi;
            XRRCrtcInfo* ci;
            _GLFWmonitor* monitor;

            oi = XRRGetOutputInfo(_glfw.x11.display, sr, sr->outputs[i]);
            if (oi->connection != RR_Connected || oi->crtc == None)
            {
                XRRFreeOutputInfo(oi);
                continue;
            }

            for (j = 0;  j < disconnectedCount;  j++)
            {
                if (disconnected[j] &&
                    disconnected[j]->x11.output == sr->outputs[i])
                {
                    disconnected[j] = NULL;
                    break;
                }
            }

            if (j < disconnectedCount)
            {
                XRRFreeOutputInfo(oi);
                continue;
            }

            ci = XRRGetCrtcInfo(_glfw.x11.display, sr, oi->crtc);
            if (ci->rotation == RR_Rotate_90 || ci->rotation == RR_Rotate_270)
            {
                widthMM  = oi->mm_height;
                heightMM = oi->mm_width;
            }
            else
            {
                widthMM  = oi->mm_width;
                heightMM = oi->mm_height;
            }

            monitor = _glfwAllocMonitor(oi->name, widthMM, heightMM);
            monitor->x11.output = sr->outputs[i];
            monitor->x11.crtc   = oi->crtc;

            for (j = 0;  j < screenCount;  j++)
            {
                if (screens[j].x_org == ci->x &&
                    screens[j].y_org == ci->y &&
                    screens[j].width == ci->width &&
                    screens[j].height == ci->height)
                {
                    monitor->x11.index = j;
                    break;
                }
            }

            if (monitor->x11.output == primary)
                type = _GLFW_INSERT_FIRST;
            else
                type = _GLFW_INSERT_LAST;

            _glfwInputMonitor(monitor, GLFW_CONNECTED, type);

            XRRFreeOutputInfo(oi);
            XRRFreeCrtcInfo(ci);
        }

        XRRFreeScreenResources(sr);

        if (screens)
            XFree(screens);

        for (i = 0;  i < disconnectedCount;  i++)
        {
            if (disconnected[i])
                _glfwInputMonitor(disconnected[i], GLFW_DISCONNECTED, 0);
        }

        free(disconnected);
    }
    else
    {
        const int widthMM = DisplayWidthMM(_glfw.x11.display, _glfw.x11.screen);
        const int heightMM = DisplayHeightMM(_glfw.x11.display, _glfw.x11.screen);

        _glfwInputMonitor(_glfwAllocMonitor("Display", widthMM, heightMM),
                          GLFW_CONNECTED,
                          _GLFW_INSERT_FIRST);
    }
}
Example #29
0
void _glfwPlatformGetMonitorWorkarea(_GLFWmonitor* monitor, int* xpos, int* ypos, int* width, int* height)
{
    int areaX = 0, areaY = 0, areaWidth = 0, areaHeight = 0;

    if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken)
    {
        XRRScreenResources* sr;
        XRRCrtcInfo* ci;

        sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root);
        ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc);

        areaX = ci->x;
        areaY = ci->y;

        const XRRModeInfo* mi = getModeInfo(sr, ci->mode);

        if (ci->rotation == RR_Rotate_90 || ci->rotation == RR_Rotate_270)
        {
            areaWidth  = mi->height;
            areaHeight = mi->width;
        }
        else
        {
            areaWidth  = mi->width;
            areaHeight = mi->height;
        }

        XRRFreeCrtcInfo(ci);
        XRRFreeScreenResources(sr);
    }
    else
    {
        areaWidth  = DisplayWidth(_glfw.x11.display, _glfw.x11.screen);
        areaHeight = DisplayHeight(_glfw.x11.display, _glfw.x11.screen);
    }

    if (_glfw.x11.NET_WORKAREA && _glfw.x11.NET_CURRENT_DESKTOP)
    {
        Atom* extents = NULL;
        Atom* desktop = NULL;
        const unsigned long extentCount =
            _glfwGetWindowPropertyX11(_glfw.x11.root,
                                      _glfw.x11.NET_WORKAREA,
                                      XA_CARDINAL,
                                      (unsigned char**) &extents);

        if (_glfwGetWindowPropertyX11(_glfw.x11.root,
                                      _glfw.x11.NET_CURRENT_DESKTOP,
                                      XA_CARDINAL,
                                      (unsigned char**) &desktop) > 0)
        {
            if (extentCount >= 4 && *desktop < extentCount / 4)
            {
                const int globalX = extents[*desktop * 4 + 0];
                const int globalY = extents[*desktop * 4 + 1];
                const int globalWidth  = extents[*desktop * 4 + 2];
                const int globalHeight = extents[*desktop * 4 + 3];

                if (areaX < globalX)
                {
                    areaWidth -= globalX - areaX;
                    areaX = globalX;
                }

                if (areaY < globalY)
                {
                    areaHeight -= globalY - areaY;
                    areaY = globalY;
                }

                if (areaX + areaWidth > globalX + globalWidth)
                    areaWidth = globalX - areaX + globalWidth;
                if (areaY + areaHeight > globalY + globalHeight)
                    areaHeight = globalY - areaY + globalHeight;
            }
        }

        if (extents)
            XFree(extents);
        if (desktop)
            XFree(desktop);
    }

    if (xpos)
        *xpos = areaX;
    if (ypos)
        *ypos = areaY;
    if (width)
        *width = areaWidth;
    if (height)
        *height = areaHeight;
}