Programmatically determining individual screen widths/heights in Linux (w/Xinerama, TwinView, and/or BigDesktop)
Asked Answered
P

4

4

I'm developing a little side-project to display multiple wallpapers on multiple screens under GNOME (something that apparently can't be done by GNOME itself or anything else). I've figured out how to do the main part of it (using the ImageMagick components, for the curious); I'm trying to automate the configuration system.

To do that, I need a way to determine the dimensions of the individual screens are. Can anyone give me a hint where to look for that? I presume the X server itself has the information, but I'm not sure how my program can ask for it.

Paraselene answered 7/5, 2009 at 17:48 Comment(1)
wallpapoz can do what you are developing. wallpapoz.akbarhome.comRepine
P
8

It looks like there's a libXinerama API that can retrieve that information. I haven't found any detailed information on it yet though.

General X.org programming information can be found here (PDF file). Information on the functions provided by libXinerama can be found here (online copy of a manpage, not a lot of information in it).

Here's a small C++ program that I whipped up from those references to retrieve the dimensions and offsets of each of the monitors hooked into Xinerama. It also works for nVidia TwinView; I don't presently have an ATI card to test it on their BigDesktop system, but I suspect it would work on it as well.

#include <cstdlib>
#include <iostream>

#include <X11/extensions/Xinerama.h>

using std::cout;
using std::endl;

int main(int argc, char *argv[]) {
    bool success=false;
    Display *d=XOpenDisplay(NULL);
    if (d) {
        int dummy1, dummy2;
        if (XineramaQueryExtension(d, &dummy1, &dummy2)) {
            if (XineramaIsActive(d)) {
                int heads=0;
                XineramaScreenInfo *p=XineramaQueryScreens(d, &heads);
                if (heads>0) {
                    for (int x=0; x<heads; ++x)
                        cout << "Head " << x+1 << " of " << heads << ": " <<
                            p[x].width << "x" << p[x].height << " at " <<
                            p[x].x_org << "," << p[x].y_org << endl;
                    success=true;
                } else cout << "XineramaQueryScreens says there aren't any" << endl;
                XFree(p);
            } else cout << "Xinerama not active" << endl;
        } else cout << "No Xinerama extension" << endl;
        XCloseDisplay(d);
    } else cout << "Can't open display" << endl;

    return (success ? EXIT_SUCCESS : EXIT_FAILURE);
}
Paraselene answered 7/5, 2009 at 18:51 Comment(0)
K
5

Try something like

GdkScreen *screen;
int num_monitors;
int i;

screen = gdk_screen_get_default ();
num_monitors = gdk_screen_get_n_monitors ();

for (i = 0; i < num_monitors; i++) {
    GdkRectangle rect;

    gdk_screen_get_monitor_geometry (screen, i, &rect);
    printf ("monitor %d: offsets (%d, %d), size (%d, %d)\n",
        i,
        rect.x, rect.y,
        rect.width, rect.height);
}

Internally this uses the libXrandr API. Xinerama is more or less deprecated, but still works; RANDR is the new way to handle multiple monitors in X.

Kibler answered 16/7, 2009 at 16:16 Comment(2)
Thanks, I'll give that a try the next time I have a chance.Paraselene
Hi @HeadGeek and Federico, what if Linux has multiple displays? Will this code sitll get all of the monitors? gdk_screen_get_default gets the default screen of only the default display. Can't other displays exist which have their own monitors?Forgetmenot
B
2

This works for TwinView, I haven't tested the others:

#!/usr/bin/python
# Print some information about the X environment, the monitor setup, currently active window and cursor position
import gtk.gdk

screen = gtk.gdk.screen_get_default()
print "X default screen size: %d x %d" % (screen.get_width(), screen.get_height())
print "xid of root window: %d" % screen.get_root_window().xid

monitors = int(screen.get_n_monitors())
print "== %d monitors ==" % monitors
for m in range(0, monitors):
    print " - geometry of monitor %d: %s" % (m, screen.get_monitor_geometry(m))

window = screen.get_active_window()
win_x, win_y, win_w, win_h, win_bit_depth = window.get_geometry()
print "active window on monitor: %d" % screen.get_monitor_at_point((win_x+(win_w/2)),(win_y+(win_h/2)))
print "window geometry (x,y,w,h): %d, %d, %d, %d" % (win_x,win_y,win_w,win_h)

display = gtk.gdk.display_get_default()
pointer = display.get_pointer()
print "cursor position (x, y): %d, %d" % (pointer[1], pointer[2])
print "cursor on monitor: %d" % screen.get_monitor_at_point(pointer[1],pointer[2])
Burnaby answered 6/7, 2010 at 22:4 Comment(0)
R
1

I always use the "xdpyinfo" command to determine the screen size; run the command, then look at the second or third page of output for where it says something like:

screen #0:
  dimensions:    1280x800 pixels (339x212 millimeters)
  resolution:    96x96 dots per inch
  depths (7):    24, 1, 4, 8, 15, 16, 32
  root window id:    0xac
  depth of root window:    24 planes
  ...

You can either run this command externally and grab the dimensions via text processing, or you could quickly download xdpyinfo's code and copy the C calls that it makes to produce that line of output. Good luck!

Ruthie answered 8/5, 2009 at 1:56 Comment(1)
'Fraid that doesn't do the trick, at least under TwinView. When I try it here, the dimensions of screen #0 are the combined dimensions of both screens.Paraselene

© 2022 - 2024 — McMap. All rights reserved.