Using FLTK, I'm writing a desktop application which uses multiple windows. The application manages a list of open windows and shows them in the menu with these lines:
for( int i = 0; i < windows.size(); ++i ) {
menu->add(("&Windows/"+windows[i].name).c_str(), 0, MyMenuCallback);
}
Now I want to set a checkmark in front of the name of the top-most window:
flags = FL_MENU_TOGGLE|FL_MENU_VALUE;
menu->add(("&Windows/"+windows[i].name).c_str(), 0, MyMenuCallback, 0, flags);
I'm stuck at installing an event handler that gets called whenever the top-most window changes. I was hoping Fl::add_handler( &genericEventHandler ); would get called whenever focus changes, but that is not the case. So, my question is: How do I get notified, when the focus of my windows changes?
You should subclass Fl_Window to override its handle method to monitor FL_FOCUS and FL_UNFOCUS events. Here is a sample:
class MyWindow : public Fl_Window {
public:
MyWindow(int X,int Y,int W,int H, const char* title) : Fl_Window (X, Y, W, H, title) {}
int handle(int e) {
switch(e) {
case FL_FOCUS:
std::cout << "Window " << label() << " is focused" << std::endl;
break;
case FL_UNFOCUS:
std::cout << "Window " << label() << " has lost focus" << std::endl;
break;
}
return(Fl_Window::handle(e));
}
};
int main() {
MyWindow win1(100, 100, 200,200, "Window 1");
win1.show();
MyWindow win2(350, 100, 200,200, "Window 2");
win2.show();
return Fl::run();
}
Related
I want to derive from Gtk::Window and want to create a stand alone window from that object. If the user closes that window, how can I achieve that the destructor of my derived object will be called.
I want to close it in the moment the window is destroyed by user. I tried to do it inside the "on_signal_delete" handler, but that results in segfault.
Currently my code did never call the destructor of the stand alone window!
#include <iostream>
#include <string>
#include <gtkmm.h>
class ExampleWindow : public Gtk::Window
{
protected:
//Child widgets:
Gtk::Box m_VBox;
Gtk::Label m_Label1;
std::string mytext;
public:
ExampleWindow(const std::string& text_):
m_VBox{ Gtk::ORIENTATION_VERTICAL }
,m_Label1{ text_ }
,mytext{ text_ }
{
set_title("Example");
set_border_width(10);
set_default_size(400, 200);
add(m_VBox);
m_VBox.pack_start( m_Label1 );
show_all_children();
}
virtual ~ExampleWindow()
{
// Not called for the stand alone win while closing it. How to achieve that?
std::cout << "Destructor called for " << mytext << std::endl;
}
bool on_delete_event( GdkEventAny* ) override
{
std::cout << "sig on delete called" << mytext << std::endl;
// free( this ); // that results in segfault
return true;
}
};
int main(int argc, char *argv[])
{
auto app = Gtk::Application::create(argc, argv, "some.base");
ExampleWindow window{ "First Window" };
// Create the same window as free window ( toplevel )
ExampleWindow* win2 = new ExampleWindow("Stand Alone Win");
win2->show(); // How can I desruct this window, if a user closes it?
//Shows the window and returns when it is closed.
return app->run(window);
}
EDIT: As comming up discussion from comments why it is not possible to not use new I provide this more complicated example to show that my real world application has to create the new windows from a signal handler inside gtk. So there is a need to create the objects on demand.
Full example which can create new windows on demand:
#include <iostream>
#include <string>
#include <gtkmm.h>
class ExampleWindow : public Gtk::Window
{
protected:
//Child widgets:
Gtk::Box m_VBox;
Gtk::Button m_button;
std::string mytext;
public:
ExampleWindow(const std::string& text_):
m_VBox{ Gtk::ORIENTATION_VERTICAL }
,m_button{ text_ }
,mytext{ text_ }
{
set_title("Example");
set_border_width(10);
set_default_size(400, 200);
add(m_VBox);
m_VBox.pack_start( m_button );
m_button.signal_clicked().connect(sigc::mem_fun(this,&ExampleWindow::on_clicked));
show_all_children();
}
void on_clicked()
{
ExampleWindow* win2 = new ExampleWindow("Stand Alone Win");
win2->show(); // How can I desruct this window, if a user closes it?
}
virtual ~ExampleWindow()
{
// Not called for the stand alone win while closing it. How to achieve that?
std::cout << "Destructor called for " << mytext << std::endl;
}
bool on_delete_event( GdkEventAny* ) override
{
std::cout << "sighandler on_delete called" << mytext << std::endl;
//delete this; // results in segfault
return false;
}
};
int main(int argc, char *argv[])
{
auto app = Gtk::Application::create(argc, argv, "some.base");
ExampleWindow window{ "Press to create new win" };
//Shows the window and returns when it is closed.
return app->run(window);
}
The question is still: Where can I hook into the signal handlers to free the dynamically created top level windows.
You dynamically allocate win2 but you never free the memory afterwards.
Call delete on win2 after Gtk::Application::run() returns:
delete win2;
Edit, after a discussion in the comments of this answer
Instead of dynamically allocating your pointer in ExampleWindow::on_clicked(), showing it and then forgetting about it, you should have some sort of a global registry, e.g. an array, of created windows that you can track and destroy when required. Coming up with a design on how to do this is not in scope of the original question so I won't suggest anything more concrete here. You can then even avoid having the dynamic allocation, as it was also suggested below.
I'm having some issues trying to use SDL (version 2.0.3) for handling multiple game controllers in a SDL/OpenGL/C++ program.
I'm updating events using a SDL_PollEvent(&m_events) loop and looking for SDL_JOYBUTTONDOWN (or SDL_JOYBUTTONUP/SDL_JOYAXISMOTION/SDL_HATMOTION) events with switch(m_events.type).
What I want is to use the values of m_events.jbutton.which and m_events.jbutton.button (or the equivalents for axes and hat) to update arrays containing the state of my controllers.
I'm using Windows 7 Pro 64bit and Code::Blocks 13.12 though it's not supposed to change anything.
Here is my (debug) code, I tried to keep just the relevant parts :
main.cpp
#include "SceneOpenGL.h"
int main(int argc, char *argv[])
{
SceneOpenGL scene(/* some args for window size */);
if(!scene.initWindow())
return -1;
scene.mainLoop();
return 0;
}
SceneOpenGL.h
#ifndef SCENEOPENGL_H_INCLUDED
#define SCENEOPENGL_H_INCLUDED
#include <iostream>
#include "Input.h"
#include <SDL2/SDL.h>
class SceneOpenGL
{
public:
SceneOpenGL(/* some args for window size */);
~SceneOpenGL();
bool initWindow();
void mainLoop();
private:
SDL_Window* m_window;
SDL_Event m_event;
Input m_input;
bool m_useJoysticks;
};
#endif
SceneOpenGL.cpp
SceneOpenGL::SceneOpenGL(/* some args for window size */) :
m_window(0), m_input()
{
if(SDL_NumJoysticks())
m_useJoysticks = true;
}
bool SceneOpenGL::initWindow()
{
if(SDL_Init( SDL_INIT_VIDEO | SDL_INIT_JOYSTICK ) == -1)
{
std::cout << "Error while initializing SDL : " << SDL_GetError() << std::endl;
SDL_Quit();
return false;
}
/*
**** Creation of SDL Window and GLContext ****
*/
return true;
}
void SceneOpenGL::mainLoop()
{
if(m_useJoysticks)
{
m_input.openJoysticks();
SDL_JoystickEventState(SDL_ENABLE);
}
while(!m_input.terminate()) // m_input.terminate() sends true when SDL receives SDL_WINDOWEVENT_CLOSE event
{
m_input.updateEvents(); // this is the other loop where I update the joystick, keyboard & mouse state
/* ...
**** moving opengl objects & render ****
*/
}
}
Input.h
#ifndef INPUT_H_INCLUDED
#define INPUT_H_INCLUDED
#include <SDL2/SDL.h>
#include <iostream>
class Input
{
public:
Input();
~Input();
void updateEvents();
bool terminate() const;
void openJoysticks();
private:
SDL_Event m_events;
int m_numJoysticks;
SDL_Joysticks* m_joysticks[4]; // Array containing the first 4 joysicks
bool m_terminate; // used for ending program
};
Input.cpp
#include "Input.h"
Input::Input() :
m_numJoysticks(0), m_terminate(false)
{}
Input::~Input()
{
for(int i(0); i < SDL_NumJoysticks(); i++)
SDL_JoystickClose(m_joysticks[i]); // Closes joysticks before exiting
}
void Input::openJoysticks()
{
m_numJoysticks = SDL_NumJoysticks; // Counts the connected joysticks
if(m_numJoysticks > 4)
m_numJoysticks = 4; // Sets maximum joysticks to 4
for(int i(0); i < m_numJoysticks; i++)
{
m_joysticks[i] = SDL_JoystickOpen(0) // Open existing joysticks
std::cout << "Joystick #" << i << " OK" << std::endl;
}
}
void Input::updateEvents()
{
while(SDL_PollEvent(&m_events))
{
switch(m_events.type)
{
/* ... Keyboard and mouse events, no problem there */
case SDL_JOYBUTTONDOWN:
std::cout << "JOYBUTTONDOWN" << std::endl;
std::cout << "type : " << m_events.jbutton.type << std::endl;
std::cout << "which : " << m_events.jbutton.which << std::endl;
std::cout << "button : " << m_events.jbutton.button << std::endl;
std::cout << "state : " << m_events.jbutton.state << std:: endl << std::endl;
break;
/* ... Same thing for SDL_JOYBUTTONUP, SDL_JOYAXISMOTION, SDL_JOYHATMOTION */
case SDL_WINDOWEVENT:
if(m_events.window.event == SDL_WINDOWEVENT_CLOSE)
m_terminate = true; // end program
break;
default:
break;
}
}
}
bool Input::terminate() const
{
return m_terminate;
}
And so here is the console output when I press A, B, X, Y on my x360 controller (= buttons 0, 1, 2 & 3) :
Joystick #0 OK
JOYBUTTONDOWN
type : 1539
which : 65536
button : §
state : Ý
JOYBUTTONDOWN
type : 1539
which : 1996554496
button :
state :
JOYBUTTONDOWN
type : 1539
which : 1996554752
button :
state :
JOYBUTTONDOWN
type : 1539
which : 1996555008
button :
state :
Process returned 0 (0x0) execution time : 7.437 s
Press any key to continue.
As you can see it doesn't seem really OK. I even sometimes get different values for the same input (like here with the first button pressed), but I noticed that the difference between "which" values is 256 so it's not totally random. And the values are mostly the same if I restart the program or press the same button twice.
Well it seems like "event.jbutton.which" contains the informations of the button index (which is supposed to be a Uint8)
I don't know if I'm doing it wrong or if it's a bug in SDL2.
Your numbers appear to be the bitwise OR of a variety of flag fields, possibly with a value field.
Examining them in hex will make this obvious:
1996554752 = 0x77010200
1996554496 = 0x77010100
1996555008 = 0x77010300
It looks like your "button number" might be in bits 15-8, ie, the values 2, 1, 3
This is almost surely covered in the appropriate documentation
I'm in the process of porting my engine across to Linux support.
I can successfully create a window, and set up an OpenGL context however, the contents of the window are whatever was displayed behind it at the time of creation. NOTE: This is not a transparent window, if I drag the window around it still contains an 'image' of whatever was behind it at the time of creation. (See attached image).
Now I'm not sure where the issue could be, however I'm not looking for a solution to a specific issue in my code, mainly just any insight from other Linux/GLX developers who may have seen a similar issue and might know where I should start looking?
I stripped all the code in my update function right down to just be:
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
glXSwapBuffers(dpy, win);
With no joy. My first thought was that it was garbage, but with just those calls I'd expect to the see the glClearColor().
glGetError() returns no errors anywhere in my application.
Immediately after glXCreateContext() I then call glXMakeCurrent() and calling glGetIntegerv() with GL_MAJOR_VERSION and GL_MINOR_VERSION returns 4 and 2 (4.2) respectively which indicates the GL context has been created successfully.
I tried having a glXMakeCurrent() call immediately before I try my glClear/glXSwapBuffers() but to effect.
Further info!, this is a multithreaded application, however all X11/GLX/OpenGL calls are only made by a single thread. I have also tried calling XInitThreads() from the main application thread, and from the Rendering thread with no luck either.
Code for Creating Window
bool RenderWindow::createWindow(std::string title, unsigned int width, unsigned int height)
{
std::cout << "createWindow() called" << std::endl;
this->m_Width = width;
this->m_Height = height;
this->m_Display = XOpenDisplay(NULL);
if (this->m_Display == NULL)
{
std::cout << "Unable to connect to X Server" << std::endl;
return false;
}
this->m_Root = DefaultRootWindow(this->m_Display);
this->m_Active = true;
XSetErrorHandler(RenderWindow::errorHandler);
return true;
}
Code for initialising OpenGL Context
bool RenderingSubsystem::initialiseContext()
{
if(!this->m_Window)
{
std::cout << "Unable to initialise context because there is no Window" << std::endl;
return false;
}
this->m_Window->createWindow(this->m_Window->GetTitle(), this->m_Window->GetWidth(), this->m_Window->GetHeight());
int att[] = { GLX_RGBA, GLX_DEPTH_SIZE, 24, GLX_DOUBLEBUFFER, None };
this->m_VI = glXChooseVisual(this->m_Window->GetDisplay(), 0, att);
if (this->m_VI == NULL)
{
std::cout << "Unable to initialise context because no suitable VisualInfo could be found" << std::endl;
return false;
}
this->m_CMap = XCreateColormap(this->m_Window->GetDisplay(), this->m_Window->GetHandle(), this->m_VI->visual, AllocNone);
this->m_SWA.colormap = this->m_CMap;
this->m_SWA.event_mask = ExposureMask;
std::cout << "Width: " << this->m_Window->GetWidth() << " Height: " << this->m_Window->GetHeight() << std::endl;
this->m_Wnd = XCreateWindow(this->m_Window->GetDisplay(), this->m_Window->GetHandle(), 0, 0, this->m_Window->GetWidth(), this->m_Window->GetHeight(), 0, this->m_VI->depth, InputOutput, this->m_VI->visual, CWColormap | CWEventMask, &this->m_SWA);
XMapWindow(this->m_Window->GetDisplay(), this->m_Wnd);
XStoreName(this->m_Window->GetDisplay(), this->m_Wnd, this->m_Window->GetTitle().c_str());
this->m_DC = glXCreateContext(this->m_Window->GetDisplay(), this->m_VI, NULL, GL_TRUE);
if(this->m_DC == 0)
{
std::cout << "Unable to create GL Context" << std::endl;
return false;
}
glXMakeCurrent(this->m_Window->GetDisplay(), this->m_Window->GetHandle(), this->m_DC);
int major, minor;
glGetIntegerv( GL_MAJOR_VERSION, &major );
glGetIntegerv( GL_MINOR_VERSION, &minor );
std::cout << "InitialiseContext complete (" << major << "." << minor << ")" << std::endl;
return true;
}
Can someone help to clear up the confusion of how to update a gui window without user input.
In other words, I would like to be able to output text to either or both the console our the gui window.
At present I can call the gui window (Window with a label for example) and output the initial text. However, the process doesn't return to my c++ code until the window closes. I'm trying to figure out how to (or where to have my code) for updating the gui screen before the gui window exits.
This is an example:
#include <gtkmm.h>
#include <iostream>
using namespace std;
int main(int argc, char* argv[])
{
Gtk::Main kit(argc, argv);
Gtk::Window window;
Gtk::TextView textview;
Gtk::Label label;
string mylabeltext = "This is the first line of text in my gui window.\n";
window.set_default_size(600, 360);
window.set_title("Gtkmm Programming - C++");
window.set_position(Gtk::WIN_POS_CENTER);
label.show();
window.add(label);
label.set_text(mylabeltext);
mylabeltext += "About to run some routines...\n";
label.set_text(mylabeltext);
cout << "An initial line has been set to the gui window." << endl;
// The Gui Window is displayed
Gtk::Main::run(window);
// Now my main program has performed some functions and wants to update
// the console and the gui window.
cout << "Continuing after various functions and processing..." << endl;
mylabeltext = "Showing the results of the functions and processing.";
label.set_text(mylabeltext);
return 0;
}
The last line of text is never printed to the console until the gui is exited. The last line of the mylabeltext is never printed to the label window.
What I'm trying to describe is how to keep the gtkmm window active while I run other routines in my c++ code and update the output to both the console and the gui window without closing the gui window to continue the c++ routines.
All the examples that I can find uses a button in the code. I have tested and experimented enough that I can update the gui screen after a button is pressed. However, I don't want to have to rely on the user for screen updates. I hope to be able to run disc scans and other functions and periodically update the screen so that the user can see the progress and know that the program is still working and not dead.
Some of the resources that I have studied in my attempts at understanding this include:
https://developer.gnome.org/
https://developer.gnome.org/gtkmm-tutorial/3.2/gtkmm-tutorial.html
http://en.wikipedia.org/wiki/Gtkmm
Like tp1 said in their comment on your question, a timer is going to be the easiest way to do this.
To set a 1.5 second timeout that will call another function, do this (gtkmm 3):
#include <gtkmm.h>
#include <iostream>
using namespace std;
class MyApp : public Gtk::Window{
public:
Gtk::Label label;
bool on_timeout(); //return true to keep the timeout and false to end it
MyApp();
virtual ~MyApp();
};
MyApp::MyApp(){
string mylabeltext = "This is the first line of text in my gui window.\n";
set_default_size(600, 360);
set_title("Gtkmm Programming - C++");
set_position(Gtk::WIN_POS_CENTER);
add(label);
label.set_text(mylabeltext);
mylabeltext += "About to run some routines...\n";
label.set_text(mylabeltext);
cout << "An initial line has been set to the gui window." << endl;
//create slot for timeout signal
int timeout_value = 1500; //in ms (1.5 sec)
sigc::slot<bool>my_slot = sigc::mem_fun(*this, &MyApp::on_timeout);
//connect slot to signal
Glib::signal_timeout().connect(my_slot, timeout_value);
show_all_children();
}
MyApp::~MyApp(){
}
bool MyApp::on_timeout(){
cout << "Continuing after various functions and processing..." << endl;
string temp = label.get_text();
temp += "Showing the results of the functions and processing.\n";
label.set_text(temp);
return true;
}
int main(int argc, char* argv[])
{
Glib::RefPtr<Gtk::Application> app = Gtk::Application::create(argc, argv, "com.kaze.test");
MyApp myapp;
// The Gui Window is displayed
return app->run(myapp);
}
More info here: https://developer.gnome.org/gtkmm-tutorial/3.3/sec-timeouts.html.en
This is crude, but this is functional for what I was trying to do:
#include <gtkmm.h>
#include <iostream>
using namespace std;
class myLabel: public Gtk::Window
{
public:
myLabel();
virtual ~myLabel();
protected:
Gtk::Label m_label;
string labeltext;
string newtext;
void myprocess1();
};
myLabel::myLabel() :
m_label()
{
void myprocess1();
set_title("Gtkmm Programming - C++");
add(m_label);
m_label.show();
Glib::Thread::create(sigc::mem_fun(*this, &myLabel::myprocess1), true);
}
myLabel::~myLabel()
{
}
void myLabel::myprocess1()
{
labeltext = "About to preform a number of processes.\n";
labeltext += "Each process may take up to three hours.\n";
labeltext += "Please carry your daily chores and wait.\n";
cout << labeltext;
cout.flush();
m_label.set_text(labeltext);
sleep(10); // Back from a three hour function
newtext = "Back from a three hour function\n";
labeltext += newtext;
m_label.set_text(labeltext);
cout << newtext;
cout.flush();
sleep(10); // Back from a three hour function
newtext = "Back from another three hour function\n";
labeltext += newtext;
m_label.set_text(labeltext);
cout << newtext;
cout.flush();
newtext = "Exiting in 1 minute...\n";
labeltext += newtext;
m_label.set_text(labeltext);
cout << newtext;
cout.flush();
sleep(60);
exit(0);
}
int main(int argc, char* argv[])
{
if (Glib::thread_supported())
Glib::thread_init();
else
{
cerr << "Threads aren't supported!" << endl;
exit(1);
}
Gtk::Main kit(argc, argv);
myLabel mylabel;
Gtk::Main::run(mylabel);
return 0;
}
Hope the example can help anyone else that wants to output to the gtkmm gui with updates, similar to updating info to the console.
I tried overriding methods hasHeightToWidth() and heightToWidth() but it didn't work for some reason.
Is there some complete example that I can use?
Upd1:
class MyWidget : public QWidget {
Q_OBJECT
public:
MyWidget() {
QSizePolicy sizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
sizePolicy.setHeightForWidth(true);
setSizePolicy(sizePolicy);
}
bool hasHeightForWidth() const override {
std::cout << __FUNCTION__ << std::endl;
return true;
}
int heightForWidth(int w) const override {
std::cout << __FUNCTION__ << " " << w << std::endl;
return w;
}
QSize sizeHint() const override {
return QSize(100, heightForWidth(100));
}
};
MyWidget instances are inserted in QHBoxLayout.
I use qt5.
Debug std::cout's show that hasHeightForWidth and heightForWidth are called many times