Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ Linux: Get the refresh rate of a monitor

In Windows, winapi provides a function that reports information about a monitor:

DEVMODE dm;
dm.dmSize = sizeof(DEVMODE);

EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dm);

int FPS = dm.dmDisplayFrequency;

What is the equivalent of this on Linux? The Linux man pages direct me to an allegro library function, but not only am I not using allegro, that function is from a very outdated version of said library and reportedly only works on Windows.

like image 388
NmdMystery Avatar asked Jul 22 '13 21:07

NmdMystery


3 Answers

Use XRandr API (man 3 Xrandr). See here for an example:

  • http://www.blitzbasic.com/Community/posts.php?topic=86911

You can also look at the code for xrandr(1).


Edit1: For posterity sake:

Sample code slightly adjusted so its more of a demo:

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <iostream>
#include <unistd.h>
#include <X11/Xlib.h>
#include <X11/extensions/Xrandr.h>

int main()
{
    int num_sizes;
    Rotation current_rotation;

    Display *dpy = XOpenDisplay(NULL);
    Window root = RootWindow(dpy, 0);
    XRRScreenSize *xrrs = XRRSizes(dpy, 0, &num_sizes);
    //
    //     GET CURRENT RESOLUTION AND FREQUENCY
    //
    XRRScreenConfiguration *conf = XRRGetScreenInfo(dpy, root);
    short current_rate = XRRConfigCurrentRate(conf);
    SizeID current_size_id = XRRConfigCurrentConfiguration(conf, &current_rotation);

    int current_width = xrrs[current_size_id].width;
    int current_height = xrrs[current_size_id].height;
    std::cout << "current_rate = " << current_rate << std::endl;
    std::cout << "current_width = " << current_width << std::endl;
    std::cout << "current_height = " << current_height << std::endl;

    XCloseDisplay(dpy);
}

Compile with:

g++ 17797636.cpp -o 17797636 -lX11 -lXrandr

Output:

$ ./17797636 
current_rate = 50
current_width = 1920
current_height = 1080
like image 113
Iwan Aucamp Avatar answered Oct 08 '22 21:10

Iwan Aucamp


A simple example:

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

int main(int argc, char *argv[])
{
  Display *display = XOpenDisplay(NULL);
  Window default_root_window = XDefaultRootWindow(display);

  XRRScreenResources *screen_resources = XRRGetScreenResources(display, default_root_window);

  RRMode active_mode_id = 0;
  for (int i = 0; i < screen_resources->ncrtc; ++i) {
    XRRCrtcInfo *crtc_info = XRRGetCrtcInfo(display, screen_resources, screen_resources->crtcs[i]);
    // If None, then is not displaying the screen contents
    if (crtc_info->mode != None) {
      active_mode_id = crtc_info->mode; 
    }
  }

  double active_rate = 0;
  for (int i = 0; i < screen_resources->nmode; ++i) {
    XRRModeInfo mode_info = screen_resources->modes[i];
    if (mode_info.id == active_mode_id) {
      active_rate = (double)mode_info.dotClock / ((double)mode_info.hTotal * (double)mode_info.vTotal);
    }
  }

  printf("Active rate is: %.1f\n", active_rate);

  return 0;
}
like image 37
Edward Chamberlain Avatar answered Oct 08 '22 19:10

Edward Chamberlain


Iwan's answer did not work for me; xrandr has changed since 2013 I guess? The command-line tool xrandr can read my refresh rate correctly, but its source code is too complex for me to be willing to copy the way it's doing so. Instead I have chosen to clumsily delegate the work to the entire xrandr program. My crappy solution is pasted below.

Note that this solution is likely to be unreliable when multiple display devices are connected, and will probably someday break when xrandr changes again.

(pstream.h is provided by Jonathan Wakely's PStreams library, referenced here: https://stackoverflow.com/a/10702464/1364776

I'm only using it to turn the output of a command into a std::string; obviously there are various other ways to do that so use one of them if you prefer.)

#include <pstream.h>
#include <cctype>
#include <cstdlib>
#include <cmath>

float getRefreshRate()
{
    try
    {
        redi::ipstream queryStream("xrandr");
        std::string chunk;
        while (queryStream >> chunk)
        {
            auto rateEnd = chunk.find("*");
            if (rateEnd != std::string::npos)
            {
                auto rateBeginning = rateEnd;
                while (std::isdigit(chunk[rateBeginning]) || std::ispunct(chunk[rateBeginning]))
                    --rateBeginning;
                ++rateBeginning;

                auto numberString = chunk.substr(rateBeginning, rateEnd - rateBeginning);
                float rate = std::strtof(numberString.data(), nullptr);
                if (rate != 0 && rate != HUGE_VALF)
                    return rate;
            }
        }
    }
    catch (...)
    {
    }

    return 60; // I am not proud of any of this :(
}
like image 1
mjwach Avatar answered Oct 08 '22 19:10

mjwach