FLTK: XLib error with X window initialization with multiple Fl_Windows - c++

Per design requirements, I am developing a GUI in FLTK that must have a main (parent) window, a child window, and an X Window that is the child of the child window. This is in Ubuntu 16.04.
Running my original project with this setup produces the XLib error BadWindow (invalid Window parameter) (Details: serial 7 error_code 3 request_code 1 minor_code 0).
I have the following test program with only the features relevant to the error that reproduces a similar error:
#include <FL/Fl.H>
#include <FL/Fl_Window.H>
#include <FL/Fl_Button.H>
#include <FL/x.H>
#include <iostream>
class ChildWindow : public Fl_Window {
public:
ChildWindow() : Fl_Window(100, 100, 300, 200, "Child"){
this->end();
this->show();
Display * dis = XOpenDisplay(NULL);
std::cout << "Child XID: " << (void *)fl_xid(this) << '\n';
std::cout << "XWindow XID: " << dis << '\n';
Window win = XCreateSimpleWindow(dis, fl_xid(this),
5, 5, 100, 100, 0, 0, 0);
XMapRaised(dis, win);
XSync(dis, false);
}
};
class ParentWindow : public Fl_Window {
public:
static ChildWindow * child;
ParentWindow() : Fl_Window(100, 100, 400, 300, "Parent"){
Fl_Button * b = new Fl_Button(10, 10, 70, 20, "Make Child");
b->callback(CallbackMakeChild, NULL);
this->add(b);
this->end();
this->show();
std::cout << "Parent XID: " << (void *)fl_xid(this) << '\n';
}
static void CallbackMakeChild(Fl_Widget * w, void * o){
child = new ChildWindow();
child->show();
}
};
ChildWindow * ParentWindow::child = NULL;
with the main function of
int main(){
ParentWindow parent;
Fl::run();
}
When run, the above code should create a window with a button. When the button is pressed, a child window will be created and the X Window will be attempted to be created. Here is the console output:
Parent XID: 0x4400002
Child XID: 0x4400005
XWindow XID: 0xe03140
X_CreateWindow: BadWindow (invalid Window parameter) 0x4400005
X_ConfigureWindow: BadWindow (invalid Window parameter) 0x4600001
X_MapWindow: BadWindow (invalid Window parameter) 0x4600001
The child window and X Window by themselves behave fine:
int main(){
ChildWindow child;
Fl::run();
}
This code (creating two non-hierarchical windows) also fails:
int main(){
ChildWindow child1; // This window works
ChildWindow child2; // This causes similar errors as above
Fl::run();
}
I have also tried various combinations of fl_open_display and Fl_Window::make_current without success.
(All code, being in one file, compiles by running ./fltk-config --compile myprog.cpp)
The pattern here appears that X windows initialize fine for the first FLTK window, but do not for windows created after that. My guess is that it has something to do with how FLTK interfaces/initializes with XLib, but I have not been able to find specifics in the documentation.
Does anyone have an explanation/solution for why X Window initialization only works when using the first-created FLTK window as a parent?

The problem was that XOpenDisplay was being called twice. FLTK opens the display as part of the initialization process, and calling it again with initializing the X window messed up the system.
This was solved by removing the line that said dis = XOpenDisplay(NULL) and replacing references to dis, with the FLTK display located at fl_display.

Related

How to inject an event like button press programmatically in gtkmm C++?

I am very new to C++ gtkmm (Linux) programming. I developing a program where I need a button to be clicked in the callback function of another button on the gui.
I have tried
button.activate()
But it only animates the button click but the callback function is not called. When I click the button manually, the callback function is called.
Please explain how to inject event into the gtkmm C++ coding. Events may include button press, key press etc.
Here is an example that works with Gtkmm 3.24 for a button click:
#include <iostream>
#include <gtkmm.h>
class MainWindow : public Gtk::ApplicationWindow
{
public:
MainWindow();
private:
Gtk::Grid m_layout;
Gtk::Label m_label;
Gtk::Button m_buttonA;
Gtk::Button m_buttonB;
};
MainWindow::MainWindow()
: m_buttonA{"A"}
, m_buttonB{"B"}
{
m_label.set_text("Click a button...");
m_buttonA.signal_clicked().connect(
[this](){
std::cout << "Button A clicked!" << std::endl;
// Emits "clicked" on button B, just like when
// a user clicks it:
m_buttonB.clicked();
m_buttonB.activate_action("clicked");
}
);
m_buttonB.signal_clicked().connect(
[this](){
std::cout << "Button B clicked!" << std::endl;
}
);
m_layout.attach(m_buttonA, 0, 0, 1, 1);
m_layout.attach(m_buttonB, 1, 0, 1, 1);
add(m_layout);
}
int main(int argc, char *argv[])
{
std::cout << "Gtkmm version : " << gtk_get_major_version() << "."
<< gtk_get_minor_version() << "."
<< gtk_get_micro_version() << std::endl;
auto app = Gtk::Application::create(argc, argv, "org.gtkmm.examples.base");
MainWindow window;
window.show_all();
return app->run(window);
}
With Gtkmm 4 however, the clicked() method seems to have been removed from Gtk::Button's interface. By looking at the new interface, there is a activate_action method (inherited from Gtk::Widget) that, maybe, could work. However, I don't have Gtkmm 4 here, so I could not try it.

Window with image GTK C++

I'm trying to open a new window from an existing window by clicking on a button. The new window should display an image. When I click the button, the new window is shown, but the image is not displayed. There are no errors.
I made sure that my image is in the current directory and is readable. What is happening?
Code:
void ExampleWindow::on_button_clicked()
{
std::cout << "The Button was clicked." << std::endl;
Gtk::Window *window = new Gtk::Window();
Gtk::VBox mainLayout;
window->add(mainLayout);
Gtk::Image image("Vampire.png");
mainLayout.pack_start(image);
window->show_all();
}
The problem is that after your handler is called (end of scope), all local variables are destroyed, and that includes image.
Here is code that works:
#include <iostream>
#include <memory>
#include <gtkmm.h>
class ExampleWindow : public Gtk::Window
{
public:
ExampleWindow()
: m_image("Vampire.png")
{
add(m_btn);
m_btn.signal_clicked().connect([this](){OnButtonClicked();});
}
private:
void OnButtonClicked()
{
std::cout << __FUNCTION__ << " enter scope" << std::endl;
m_window = std::make_unique<Gtk::Window>();
m_window->add(m_image);
m_window->show_all();
std::cout << __FUNCTION__ << " leaving scope" << std::endl;
// With your code, image is destroyed here. The window still
// lives because it was newed, but you lost your reference to
// it and so the program will leak memory (i.e. you will be
// unable to call delete on it, unless it is a class member).
}
Gtk::Button m_btn("Show image");
Gtk::Image m_image;
std::unique_ptr<Gtk::Window> m_window;
};
int main(int argc, char *argv[])
{
auto app = Gtk::Application::create(argc, argv, "so.question.q65011763");
ExampleWindow window;
window.show_all();
return app->run(window);
// With this code, the image and the window are both destroyed here.
// Since the window is in a unique_ptr, delete will be automatically
// called on it.
}
Note that I have made all variables class members, so that they outlive the end of scope of the handler. I have also stored the window containing the image inside a smart pointer so that I don't have to call delete myself.

How do you create a gtk window handle from an X11 window handle

I'm trying to open a gtk file dialog window with a GLFW window.
Now since GLFW is a pretty low level API it only exposes the X11 window and display, because it just creates a window without any GUI stuff.
The problem I'm having is that gtk_file_chooser_dialog_new() expects a parent window to be passed on, but since I only have an X11 handle I'm not quite sure how to create a GTK handle from it.
I followed this tutorial which resulted in the following code:
glfwSetKeyCallback(windowHandle1, [](GLFWwindow *window, int keyCode, int scanCode, int action, int mods) {
if (action == GLFW_PRESS)
{
if (keyCode == GLFW_KEY_O && mods == (GLFW_MOD_SHIFT | GLFW_MOD_CONTROL))
{
GtkWidget *dialog;
GtkFileChooserAction fileAction = GTK_FILE_CHOOSER_ACTION_OPEN;
gint res;
// Window x11Window = glfwGetX11Window(window);
// Display *x11Display = glfwGetX11Display();
int argc = 0;
gtk_init(&argc, nullptr); // TODO: don't do this every time
dialog = gtk_file_chooser_dialog_new("Open File",
nullptr, // should be _GtkWindow of the GLFWwindow
fileAction,
_("_Cancel"),
GTK_RESPONSE_CANCEL,
_("_Open"),
GTK_RESPONSE_ACCEPT,
nullptr);
res = gtk_dialog_run(GTK_DIALOG(dialog));
if (res == GTK_RESPONSE_ACCEPT)
{
char *filename;
GtkFileChooser *chooser = GTK_FILE_CHOOSER(dialog);
filename = gtk_file_chooser_get_filename(chooser);
std::cout << filename << std::endl;
g_free(filename);
}
gtk_widget_destroy(dialog);
std::cout << "destroyed file dialog" << std::endl;
}
}
});
This opens an open file dialog, but because I didn't specify a parent window the main window can still be focused, and another problem is that the dialog doesn't close for some reason even though I call gtk_widget_destroy(dialog).
I already took a look at this post, but the only answer seems to be getting the xid of the file dialog window, which is not what I want to do.
This google search result doesn't seem to help either, as it creates a completely new gdk (not gtk) window on the default display.
I've got the same problem and found hackish way to fix this. Null parent is not really problem here, but lack of event dispatching, so I've added:
gtk_widget_destroy(dialog);
while (g_main_context_iteration(nullptr, false));

X11 - XCB: Window information not up-to-date?

I'm using XCB to create my x11 window and, somewhere in the code, I want to move it.
I make a little test to print the window position (0, 0), then move it, and print the position again (200, 100).
Saddly, I have always x:10 and y:10.
Here the code:
// g++ -o test test_xcb.cpp -lX11 -lxcb
#include <xcb/xcb.h>
#include <iostream>
using namespace std;
void print_window_xywh(xcb_connection_t *conn, xcb_drawable_t win)
{
auto geo = xcb_get_geometry_reply(
conn, xcb_get_geometry(conn, win), nullptr);
cout << "Window( " << win << ") - x: " << geo->x
<< " - y: " << geo->y
<< " - w: " << geo->width
<< " - h: " << geo->height << endl;
}
int main(void) {
xcb_connection_t *c;
xcb_screen_t *screen;
xcb_window_t win;
/* Open the connection to the X server */
c = xcb_connect (NULL, NULL);
/* Get the first screen */
screen = xcb_setup_roots_iterator (xcb_get_setup (c)).data;
/* Ask for our window's Id */
win = xcb_generate_id(c);
/* Create the window */
xcb_create_window (c, /* Connection */
XCB_COPY_FROM_PARENT, /* depth (same as root)*/
win, /* window Id */
screen->root, /* parent window */
10, 10, /* x, y */
150, 150, /* width, height */
10, /* border_width */
XCB_WINDOW_CLASS_INPUT_OUTPUT, /* class */
screen->root_visual, /* visual */
0, NULL); /* masks, not used yet */
/* Map the window on the screen */
xcb_map_window (c, win);
/* Make sure commands are sent, so window is shown */
xcb_flush (c);
// Print the position and size of the window
print_window_xywh(c, win);
// Move the window
const static uint32_t values[] = { 200, 100 };
xcb_configure_window(c, win, XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, values);
// Print again, should be 200 for x and 100 for y
print_window_xywh(c, win);
return 0;
}
Did I miss something? Thank you.
The short version: You are ignoring the interaction with the window manager.
The long version:
First, the position that GetGeometry gives you is relative to the parent window. With a reparenting window manager, the WM will add a frame window around your window to draw window decorations to (titlebar, close button, ...). If you want the position of your window on screen, you should use use xcb_translate_coordinates(c, win, screen->root, 0, 0). The reply to this request will give you the position of 0,0 of your window translated to the root window.
However, in your example that will still not work. This is because of how the window manager works. It basically forbids your program from moving its window (XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT). Due to this, when you try to move your window, the X11 server only sends this request as an event to the window manager. The window manager then needs some time to handle this request. Since you are immediately checking the window position again, the request will not yet have been handled.

SDL2 multiple windows focus

I have some problems with windows focus in SDL2.
I got two windows and listen to focus gain and lost events.
When I click on Window 2, the following events trigger:
"Window 1 lost focus"
"Window 2 gained focus."
When I click on Window 1, the following events trigger:
"Window 2 lost focus."
"Window 1 gained focus."
"Window 1 lost focus."
I can clearly tell the window has focus by the glowing effect my operating system draws around it.
Also, other SDL2 functions to get focus information give the same, wrong, answer when tested on Window 1.
I trimmed down the code to an almost-minimal test case:
#include <iostream>
#include <SDL2/SDL.h>
using namespace std;
int main(int argc, char **argv) {
SDL_Init(SDL_INIT_VIDEO);
SDL_Window* w1=SDL_CreateWindow("Window 1",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
250,200,SDL_WINDOW_SHOWN);
SDL_Window* w2=SDL_CreateWindow("Window 2",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
200,250,SDL_WINDOW_SHOWN);
bool quit=false;
while(!quit){
SDL_Event e;
while(!quit && SDL_PollEvent(&e)){
switch(e.type){
case SDL_WINDOWEVENT :
{ // this block just scopes 'targetWindow' and 'title'
SDL_Window* targetWindow=SDL_GetWindowFromID(e.window.windowID);
const char* title=SDL_GetWindowTitle(targetWindow);
switch(e.window.event){
case SDL_WINDOWEVENT_FOCUS_GAINED :
// tell which window gained focus
cout << title << " gained focus!" << endl;
break;
case SDL_WINDOWEVENT_FOCUS_LOST :
// tell which window lost focus
cout << title << " lost focus!" << endl;
break;
}
}
break;
case SDL_QUIT :
quit=true;
break;
}
}
}
SDL_Quit();
return 0;
}
Is this a bug in SDL2 multi-windows support?
Does it depend on the underlying windowing system?
More importantly, is there a way to have correct focus information for multiple windows with SDL2?
I did a little more research on this and find out that the issue I described is a known bug as can be seen here.
There's a patch at the other end of the link but that's already included in the latest version of SDL.
Personally, I solved this by installing version 2.0.3 of the library.