My initial approach was to request the embedding from Qt side. I had no luck with this, as I couldn't find any equivalent for QX11EmbedWidget::embedInto
in Qt5. After giving up on this, I decided to give XReparentWindow
a try, which was reportedly used with success. However, due to lack of documentation, I wasn't able to reproduce this. My third attempt was to initiate the embedding from server side, which is the Gtk window in my case. I'm glad to report, that it worked :-)
For the Record: How to embed an arbitrary Qt5 Widget into a Gtk window
TL;DR:
- Make sure that you write your Gtk code in a unit which is separate from the Qt part. This is necessary in order to avoid name conflicts between Qt5 and Gtk3.
- Simply use
gtk_socket_add_id
to embed any X11 window into a GtkSocket
.
Also see the documentation for reference, but note that the example given their doesn't even compile, because they forgot the GTK_SOCKET
macro. On the contrary, the following code works.

Details
The QGtkWindow
class provides an interface to the Gtk window.
class QGtkWindow : public QObject
{
public:
QGtkWindow();
virtual ~QGtkWindow();
void setCentralWidget( QWidget* const widget );
void show();
private:
GtkWindowAdapter gtkWindow;
QWidget* const container;
}; // QGtkWindow
The GtkWindowAdapter
class wraps the Gtk calls and isolates them from the Qt part of the application. An object of this class represents the Gtk window.
class GtkWindowAdapter
{
public:
GtkWindowAdapter();
~GtkWindowAdapter();
void show();
void embed( unsigned long clientWinId );
private:
struct Details;
const std::auto_ptr< Details > pimpl;
}; // GtkWindowAdapter
When instantiated, an GtkWindowAdapter
object first initializes Gtk,
static bool gtkInitialized = false;
struct GtkWindowAdapter::Details
{
GtkWidget* widget;
GtkWidget* socket;
void setupUi();
};
GtkWindowAdapter::GtkWindowAdapter()
: pimpl( new Details() )
{
if( !gtkInitialized )
{
int argc = 0;
gtk_init( &argc, NULL );
gtkInitialized = true;
}
pimpl->setupUi();
}
and then setups the Gtk window:
void GtkWindowAdapter::Details::setupUi()
{
widget = gtk_window_new( GTK_WINDOW_TOPLEVEL );
socket = gtk_socket_new();
gtk_widget_show( socket );
gtk_container_add( GTK_CONTAINER ( widget ), socket );
gtk_widget_realize( socket );
}
You might already have noted the embed
method which this class provides. This method initiates the embedding of any X11 window. The show
method turns the encapsulated Gtk window visible.
void GtkWindowAdapter::embed( unsigned long clientWinId )
{
gtk_socket_add_id( GTK_SOCKET( pimpl->socket ), clientWinId );
}
void GtkWindowAdapter::show()
{
gtk_widget_show( pimpl->widget );
}
Now, the implementation of the QGtkWindow
class is fairly simple. When created, it initializes a Gtk window by using the GtkWindowApdater
and puts an empty QWidget
into that window:
QGtkWindow::QGtkWindow()
: container( new QWidget() )
{
container->setLayout( new QVBoxLayout() );
gtkWindow.embed( container->winId() );
container->show();
}
When the user of the QGtkWindow
class decides to put some widget into the window, the setCentralWidget
is the way to go. It simply clears the parent widget, which was embedded into the Gtk window originally, then inserts the user's widget instead:
void QGtkWindow::setCentralWidget( QWidget* const widget )
{
qDeleteAll( pimpl->container->layout()->children() );
pimpl->container->layout()->addWidget( widget );
}
void QGtkWindow::show()
{
pimpl->gtkWindow.show();
}
Hope this might spare somebody many hours.