dark knight
dark knight

Reputation: 304

QDesktopWidget for an X display

I have an X display say :2 . I want to display my qt widget on given X display. This display is different from the primary display. So in addition to the primary display (which is set by environment variable DISPLAY), I want to access an additional X display.

I know QDekstopWidget has screen function(). This is not what I want. I have a special case when I want to directly access X Display using the display id.

Let me know if there is anyway to do this . Update: Tried this

#include<QApplication>
#include<QWidget>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xresource.h>


int main(int argc, char *argv[])
{
QApplication a(argc, argv);

Display* display = XOpenDisplay(":1");

XSynchronize(display, True);
//XSetErrorHandler(myErrorHandler);

Window x11root = XDefaultRootWindow(display);

int x = 0;
int y = 0;
unsigned int width = 500;
unsigned int height = 500;
unsigned int borderWidth = 0;
long colorBlue = 0xff0000ff;

Window x11w = XCreateSimpleWindow(display, x11root, x, y, 
    width, height, borderWidth, 1 /*magic number*/, colorBlue);
XMapWindow(display, x11w); // must be performed after XReparentWindow, 
                           // otherwise the window is not visible.

QWidget w;
w.resize(200,200);
w.show();

XReparentWindow(display, w.winId(), x11w, 0, 0);

return a.exec();

}

Tried qscreen test as suggested. Its detecting the display but both windows are going on display :3

shiva@RSV-HP-ENVY-15-Notebook-PC:/tmp/korvins-qtbase-6226fcdc3e4ace4636c58778ef53fbf69f46c36e-6226fcdc3e4ace4636c58778ef53fbf69f46c36e/tests/manual/qscreen$ ./qscreen -platform xcb::3::5
qt.core.logging: Loading "/home/shiva/.config/QtProject/qtlogging.ini" ...
qt.qpa.screen: Output VGA-1-0 is not connected
qt.qpa.screen: Output HDMI-1-0 is not connected
qt.qpa.screen: adding QXcbScreen(0x1b82f60, name="eDP-1-0", geometry=1366x768+0+0, availableGeometry=1309x744+57+24, devicePixelRatio=1.0, logicalDpi=QPair(96.0,96.0), physicalSize=344.0x194.0mm, screenNumber=0, virtualSize=1366x768 (1366.0x768.0mm), orientation=Qt::ScreenOrientation(LandscapeOrientation), depth=24, refreshRate=59.0, root=2c1, windowManagerName="Compiz") (Primary: true )
qt.qpa.screen: primary output is "eDP-1-0"
qt.qpa.screen: connecting to additional display: "" "3"
qt.qpa.screen: adding QXcbScreen(0x1bae540, name="TurboVNC", geometry=1024x716+0+0, availableGeometry=1024x664+0+28, devicePixelRatio=1.0, logicalDpi=QPair(96.0,96.0), physicalSize=271.0x189.0mm, screenNumber=0, virtualSize=1024x716 (1024.0x716.0mm), orientation=Qt::ScreenOrientation(LandscapeOrientation), depth=24, refreshRate=60.0, root=6a, windowManagerName="Metacity") (Primary: true )
qt.qpa.screen: primary output is "TurboVNC"
qt.qpa.screen: connecting to additional display: "" "5"
qt.qpa.screen: adding QXcbScreen(0x1bd6ca0, name="TurboVNC", geometry=1024x716+0+0, availableGeometry=1024x664+0+28, devicePixelRatio=1.0, logicalDpi=QPair(96.0,96.0), physicalSize=271.0x189.0mm, screenNumber=0, virtualSize=1024x716 (1024.0x716.0mm), orientation=Qt::ScreenOrientation(LandscapeOrientation), depth=24, refreshRate=60.0, root=6a, windowManagerName="Metacity") (Primary: true ) 
qt.qpa.screen: primary output is "TurboVNC"
Xlib: extension "GLX" missing on display ":5".
Xlib: extension "GLX" missing on display ":5".
Xlib: extension "GLX" missing on display ":5".
Xlib: extension "GLX" missing on display ":5".
Could not initialize OpenGL for RasterGLSurface, reverting to RasterSurface.
Xlib: extension "GLX" missing on display ":5".
Xlib: extension "GLX" missing on display ":5".
Xlib: extension "GLX" missing on display ":5".
Xlib: extension "GLX" missing on display ":5".
Could not initialize OpenGL for RasterGLSurface, reverting to RasterSurface.
Xlib: extension "GLX" missing on display ":5".
Xlib: extension "GLX" missing on display ":5".
Xlib: extension "GLX" missing on display ":5".
Xlib: extension "GLX" missing on display ":5".
Could not initialize OpenGL for RasterGLSurface, reverting to RasterSurface. 

Upvotes: 3

Views: 2903

Answers (3)

Hayk Shahparonyan
Hayk Shahparonyan

Reputation: 23

If I understand your question correctly, than I have a nasty solution. You can set display manually by specifying ./app -display :2 If you can't do it, you can alter your command line options in the main() function. Something like this.

#include <QApplication>
#include <QWidget>
#include <cstdio>
#include <cstring>

int main(int argc, char** argv)
{
    char** args = (char**)malloc((argc + 2) * sizeof(char*));
    for(int i = 0; i < argc; ++i) {
            int l = strlen(argv[i]);
            args[i] = (char*)malloc(l * sizeof(char));
            strcpy(args[i], argv[i]);
    }
    const char* const display = "-display_";
    const char* const display_number = ":2_";
    args[argc] = (char*)malloc(strlen(display) * sizeof(char));
    args[argc + 1] = (char*)malloc(strlen(display_number) * sizeof(char));
    strcpy(args[argc], display);
    strcpy(args[argc + 1], display_number);
    args[argc][strlen(display) - 1] = 0;
    args[argc + 1][strlen(display_number) - 1] = 0;
    for(int i = 0; i < argc + 2; ++i) {
            printf("%s\t%d\n", args[i], strlen(args[i]));
    }
    int aargc = argc + 2;
    QApplication app(aargc, args);
    QWidget w;
    w.show();
    return app.exec();
}

Hope you got the idea. Tried it on my machine, and it worked.

Thanks.

Upvotes: 0

ecloud
ecloud

Reputation: 356

If you look at the QXcbConnection constructor, m_displayName is initialized to the contents of the displayName parameter if it’s not null, or otherwise the DISPLAY env variable, then it calls xcb_connect() with that display, and from then on, that Qt application normally only talks to that display. It does not automatically discover the other displays. The QXcbConnection is created in QXcbIntegration’s constructor, and that in turn is created in QGuiApplication’s init_platform function. QXcbIntegration looks for the -display command line argument too, so that’s the second way of choosing a display (overriding the DISPLAY env variable).

The third way to configure it is provided by the fact that init_platform splits off any colon-separated arguments which are appended to the platform plugin name, which end up as QStringList parameters to the QXcbIntegration constructor. QXcbIntegration takes them two at a time and creates additional QXcbConnection instances for each pair. So, if you start your application with -platform xcb::0.1::0.2, it will connect to displays :0.1 and :0.2 in addition to the default one (which normally comes from the DISPLAY env variable). If you give invalid displays though, it will fail, and say "could not connect to display :0.2" for example.

Now try that with the QScreen manual test (assuming you have displays :0 and :0.1 available):

cd path/to/qtbase/tests/manual/qscreen
qmake
make
./qscreen -platform xcb::0.1

You will get a window on each output of each display, whereas without any arguments you would get a window only on each output of the default display.

You can also set the env variable QPA_PLATFORM instead of giving the -platform argument. And in your main, you could even use qputenv to set the env variable before constructing the QApplication, in case you want to avoid needing to configure the env variable in your shell. If you figure out how to discover the displays, you could build up that argument programmatically.

As you can see in the manual test's main.cpp, QGuiApplication::screens() will give you a QScreen instance for each output on each display that Qt is connected to. You could then use QScreen:name() or other properties to identify the screen you want to use. Multiple outputs on one display are usually arranged side-by-side, so calling setGeometry() to position the window is normally enough to put it onto one screen or another; but in your case you have multiple displays, so then you need to also call QWindow::setScreen() or set the widget's parent to the appropriate QDesktopWidget's screen widget, as you can see in the middle of the screenAdded() function.

Upvotes: 1

dmi
dmi

Reputation: 1479

QX11Info gives the access to the X Display info. Reference: QX11Info::display()

I assume you need to open a second X connection to the second display, and pass it to the newly created widgets.

Here is also some info.

Upvotes: 2

Related Questions