xlibxorgxrandr

How to find the dpi of a monitor on which a specific window is placed in linux?


I want to change the font size when my application window moves from one monitor to another depending on the underlying dpi of destination monitor.

I played with xrandr, xdpyinfo and xlib. I looked at the source code but I couldn't find a way to associate the monitor on which the window (window id) is placed.

Qt has QDesktopWidget, which provides physicalDpiX/Y but only (so it seems) for the primary monitor.

xrandr.h contains XRROutputInfo which delivers mm_width and mm_height, but how can I make the connection to a window id?

Since this question got some attention, I want so share my research. I haven not found a perfect solution. It looks like it's not possible.

But playing with the following code snip will probably help you. The idea is to calculate the underlying display by comparing the window position. If the position is larger then the first screen's resolution, and must be the 2nd monitor. Pretty straight forward.

#include <X11/Xlib.h>
#include <X11/extensions/Xrandr.h>
#include <stdio.h>
#include <stdlib.h>

// compile: g++ screen_dimension.cpp -lX11 -lXrandr

int main()
{
  int wid = atoi( getenv( "WINDOWID" ) );

  printf("window id: %i\n", wid);

  Display * dpy = XOpenDisplay(NULL);
  int screen  = DefaultScreen(dpy);
  Window root = DefaultRootWindow(dpy);
  
  XRRScreenResources * res = XRRGetScreenResourcesCurrent(dpy, root);
  
  XRROutputInfo * output_info;

  for (int i = 0; i < res->noutput; i++)
  {
      output_info = XRRGetOutputInfo (dpy, res, res->outputs[i]);
 
      if( output_info->connection ) continue; // No connection no crtcs
          printf(" (%lu %lu) mm Name: %s connection: %i ncrtc: %i \n",  output_info->mm_width
            , output_info->mm_height
            , output_info->name
            , output_info->connection
            , output_info->ncrtc
          );
  }
 
   printf("crtcs:\n");
  for( int j = 0; j < output_info->ncrtc; j++ ) {
    XRRCrtcInfo * crtc_info = XRRGetCrtcInfo( dpy, res, res->crtcs[ j ] );
    if( not crtc_info->noutput ) continue;
    printf("%i w: %5i   h: %5i     x: %5i    y: %i\n", j
    , crtc_info->width
    , crtc_info->height
    , crtc_info->x
    , crtc_info->y
    );
  }
}

There are actually 2 functions to query resources about the screens: XRRGetScreenResourcesCurrent and XRRGetScreenResources. The first one returns some cached value, while the latter one asks the server which may introduce polling. The description (search for RRGetScreenResources): https://www.x.org/releases/X11R7.6/doc/randrproto/randrproto.txt

Someone went through the trouble timing it: https://github.com/glfw/glfw/issues/347

XRRGetScreenResourcesCurrent: Tipically from 20 to 100 us. h XRRGetScreenResources: Typically from 13600 to 13700 us.


Solution

  • Ok, since there is no further discussion here and I am convinced my little program (see above) works, I declare it now as: Answered!

    Compile instructions are

    g++ screen_dimension.cpp -lX11 -lXrandr

    (also added as comment above)