Search code examples
c++gtkfreeglut

Show Gtk::FileChooserDialog without a parent window


I'm writing an application with an OpenGL GUI. On Windows, I'm using GetOpenFilename to allow the user to select a file.

I tried to implement similar functionality for on Linux for Gtk, using Gtk::FileChooserDialog (following this tutorial). I'm trying to keep the function signature the same for Windows and Linux, so I modified the example to look like this:

std::string browseFile( std::string filetypes )
{
    Gtk::Main kit(false);

    Gtk::FileChooserDialog dialog( "Please choose a file",
            Gtk::FILE_CHOOSER_ACTION_OPEN );
//    dialog.set_transient_for( kit.instance() );

    //Add response buttons the the dialog:
    dialog.add_button( Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL );
    dialog.add_button( Gtk::Stock::OPEN, Gtk::RESPONSE_OK );

    //Add filters, so that only certain file types can be selected:
    Glib::RefPtr<Gtk::FileFilter> filter_any = Gtk::FileFilter::create();
    filter_any->set_name( "Any files" );
    filter_any->add_pattern( "*" );
    dialog.add_filter( filter_any );

    //Show the dialog and wait for a user response:
    int result = dialog.run();

    //Handle the response:
    switch( result )
    {
        case( Gtk::RESPONSE_OK ):
        {
            std::cout << "Open clicked." << std::endl;

            //Notice that this is a std::string, not a Glib::ustring.
            std::string filename = dialog.get_filename(  );
            std::cout << "File selected: " <<  filename << std::endl;
            return filename;
        }
        case( Gtk::RESPONSE_CANCEL ): { std::cout << "Cancel clicked." << std::endl; break; }
        default: { std::cout << "Unexpected button clicked." << std::endl; break; }
    }
    return std::string( "" );
}

The main difference is that I eliminated the set_transient_for bit, since my main window isn't managed by Gtk (it's created by freeglut).

Problem: after I choose a file, the dialog just freezes. My application continues running, I can process the selected file, it's just the dialogs that freeze.

How do I kill the dialog box after choosing a file ? I tried dialog.hide(), but it doesn't seem to have any effect. I'm also trying to contain Gtk-specific code to this function, keeping int main() free of platform-specific code.


Solution

  • I decided to create overloaded class for this. The code is below:

        class FileChooser : public Gtk::FileChooserDialog {
    public:
    
        static std::string getFileName() {
            FileChooser dialog("Select file", Gtk::FILE_CHOOSER_ACTION_OPEN);
            kit.run(dialog);
            std::string ret = dialog.chosenFile;
            return ret;
        }
    protected:
        static Gtk::Main kit;
        std::string chosenFile;
    
        FileChooser(const Glib::ustring& title, Gtk::FileChooserAction action = Gtk::FILE_CHOOSER_ACTION_OPEN) :
        Gtk::FileChooserDialog(title, action) {
            chosenFile = std::string("");
            add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
            add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_OK);
            signal_response().connect(sigc::mem_fun(*this,
                    &FileChooser::on_my_response));
        }
    
        void on_my_response(int response_id) {
            chosenFile = get_filename();
            hide();
        }
    };
    Gtk::Main FileChooser::kit(false);
    

    You can use it like this:

    std::cout << "File: " << FileChooser::getFileName() << "\n";