diff options
author | Kjell Ahlstedt <kjell.ahlstedt@bredband.net> | 2014-05-12 19:56:44 +0200 |
---|---|---|
committer | Kjell Ahlstedt <kjell.ahlstedt@bredband.net> | 2014-05-12 19:56:44 +0200 |
commit | 122282ab161dfd4fdca75406308291c5599fd990 (patch) | |
tree | 34eacea54a59f8740c5deb11e115efbaec80b76d | |
parent | 149cf07c6952a876f2a7946508bc18de7dfcbc30 (diff) | |
download | glibmm-122282ab161dfd4fdca75406308291c5599fd990.tar.gz |
Gio::Application: Add add_main_option_entry() and enum OptionType
* gio/src/application.[hg|ccg]: Add add_main_option_entry() and
enum Application::OptionType. Bug #727822.
-rw-r--r-- | gio/src/application.ccg | 78 | ||||
-rw-r--r-- | gio/src/application.hg | 106 |
2 files changed, 166 insertions, 18 deletions
diff --git a/gio/src/application.ccg b/gio/src/application.ccg index 0ca8245d..a04d9ba5 100644 --- a/gio/src/application.ccg +++ b/gio/src/application.ccg @@ -22,9 +22,38 @@ #include <giomm/actiongroup.h> #include <giomm/init.h> #include <cstring> // std::memset() +#include <vector> -namespace +namespace // anonymous { +//TODO: At the next ABI break, implement the pimpl idiom. Then we need not use +// a GQuark for ExtraApplicationData, which should be renamed to +// struct Gio::Application::Impl. +// These are new data members that can't be added to Gio::Application now, +// because it would break ABI. +struct ExtraApplicationData +{ + std::vector<gchar*> option_entry_strings; + + ~ExtraApplicationData() + { + for (std::vector<gchar*>::iterator iter = option_entry_strings.begin(); + iter != option_entry_strings.end(); ++iter) + { + g_free(*iter); + *iter = 0; + } + } +}; + +GQuark quark_extra_application_data = + g_quark_from_static_string("glibmm__Gio::Application::quark_extra_application_data"); + +void Application_delete_extra_application_data(gpointer data) +{ + ExtraApplicationData* extra_application_data = static_cast<ExtraApplicationData*>(data); + delete extra_application_data; +} static void Application_signal_open_callback(GApplication* self, GFile** files, gint n_files, const gchar* hint, void* data) @@ -99,7 +128,7 @@ static const Glib::SignalProxyInfo Application_signal_open_info = (GCallback) &Application_signal_open_notify_callback }; -} +} // anonymous namespace namespace Gio { @@ -208,16 +237,49 @@ void Application::open(const Glib::RefPtr<Gio::File>& file, const Glib::ustring& open(files, hint); } -/* -void Application::add_main_option_entry(Glib::OptionEntry& entry) +void Application::add_main_option_entry(OptionType arg_type, const Glib::ustring& long_name, + gchar short_name, const Glib::ustring& description, const Glib::ustring& arg_description, int flags) { - //Create a temporary array, just so we can give the correct thing to g_application_add_main_option_entries(): + // Create a temporary array, just so we can give the correct thing to g_application_add_main_option_entries(): GOptionEntry array[2]; - array[0] = *(entry.gobj()); //Copy contents. - std::memset(&array[1], 0, sizeof(GOptionEntry)); + std::memset(array, 0, 2 * sizeof(GOptionEntry)); // null-termination + + // g_application_add_main_option_entries() does not take its own copy + // of the strings. We must keep them alive, and keep pointers to them, + // so we can delete them when the Application instance is deleted. + + // GOptionEntry.long_name must be set, even if it's an empty string. + gchar* lname = g_strdup(long_name.c_str()); + gchar* desc = description.empty() ? 0 : g_strdup(description.c_str()); + gchar* arg_desc = arg_description.empty() ? 0 : g_strdup(arg_description.c_str()); + + ExtraApplicationData* extra_application_data = + static_cast<ExtraApplicationData*>(g_object_get_qdata(gobject_, quark_extra_application_data)); + if (!extra_application_data) + { + extra_application_data = new ExtraApplicationData(); + g_object_set_qdata_full(gobject_, quark_extra_application_data, extra_application_data, + Application_delete_extra_application_data); + } + + extra_application_data->option_entry_strings.push_back(lname); + if (desc) + extra_application_data->option_entry_strings.push_back(desc); + if (arg_desc) + extra_application_data->option_entry_strings.push_back(arg_desc); + + // Fill in array[0]. + array[0].arg = (GOptionArg)arg_type; + array[0].long_name = lname; + array[0].short_name = short_name; + array[0].description = desc; + array[0].arg_description = arg_desc; + array[0].flags = flags; + // We ensure that this is null to ensure that it is not used, + // telling GApplication to put the parsed value in the options VariantDict instead. + array[0].arg_data = 0; g_application_add_main_option_entries(gobj(), array); } -*/ } // namespace Gio diff --git a/gio/src/application.hg b/gio/src/application.hg index ac96e0cb..e926744e 100644 --- a/gio/src/application.hg +++ b/gio/src/application.hg @@ -27,7 +27,7 @@ #include <giomm/applicationcommandline.h> #include <giomm/file.h> #include <glibmm/object.h> -//#include <glibmm/optiongroup.h> +#include <glibmm/optionentry.h> #include <glibmm/variant.h> #include <glibmm/variantdict.h> #include <giomm/dbusconnection.h> @@ -104,6 +104,31 @@ protected: _IGNORE(g_application_new) public: + /** The OptionType enum values determine the expected type of a command line option. + * If an option expects an extra argument, it can be specified in several ways; + * with a short option: "-x arg", with a long option: "--name arg" or combined + * in a single argument: "--name=arg". All option types except OPTION_TYPE_BOOL + * expect an extra argument. OPTION_TYPE_STRING_VECTOR and + * OPTION_TYPE_FILENAME_VECTOR accept more than one extra argument. + * + * The descriptions of the enum values show what type of Glib::Variant<> + * is stored in a Glib::VariantDict. + * + * @ingroup glibmmEnums + */ + enum OptionType + { + OPTION_TYPE_BOOL, ///< bool + OPTION_TYPE_STRING, ///< Glib::ustring + OPTION_TYPE_INT, ///< gint32 + //OPTION_TYPE_CALLBACK, + OPTION_TYPE_FILENAME = OPTION_TYPE_INT+2, ///< std::string + OPTION_TYPE_STRING_VECTOR, ///< std::vector<Glib::ustring> + OPTION_TYPE_FILENAME_VECTOR, ///< std::vector<std::string> + OPTION_TYPE_DOUBLE, ///< double + OPTION_TYPE_INT64 ///< gint64 + }; + /** Creates an application instance. * If no application ID is given then some features (most notably application uniqueness) will be disabled. * @@ -131,16 +156,78 @@ public: _WRAP_METHOD(void set_action_group(const Glib::RefPtr<ActionGroup>& action_group), g_application_set_action_group) - - //TODO: We need to be able to add a group, not just some entries, + //Note: We would like to add a group, not just some entries, //so we can do pre and post parsing. See https://bugzilla.gnome.org/show_bug.cgi?id=727602 - // - //TODO: Custom write the documentation for this method? - //_WRAP_METHOD_DOCS_ONLY(g_application_add_main_option_entries) - //void add_main_option_entry(Glib::OptionEntry& entry); - //_IGNORE(g_application_add_main_option_entries) + //but instead we need to use the VariantDict passed to the handle_local_options signal + //and provided by ApplicationCommandLine::get_options_dict() in on_command_line(). + + /** Adds a main option entry to be handled by the Application. + * + * This function is comparable to Glib::OptionGroup::add_entry() + + * Glib::OptionContext::set_main_group(). + * + * After the commandline arguments are parsed, the + * signal_handle_local_options() signal will be emitted. At this + * point, the application can inspect the parsed values. + * + * Unlike OptionGroup + OptionContext, Application packs the arguments + * into a Glib::VariantDict which is passed to the + * signal_handle_local_options() handler, where it can be + * inspected and modified. If Gio::APPLICATION_HANDLES_COMMAND_LINE is + * set, then the resulting dictionary is sent to the primary instance, + * where Gio::ApplicationCommandLine::get_options_dict() will return it. + * This "packing" is done according to the type of the argument -- + * booleans for normal flags, Glib::ustring's for strings, std::string's for + * filenames, etc. The packing only occurs if the flag is given (ie: we + * do not pack a "false" Variant in the case that a flag is missing). + * + * In general, it is recommended that all commandline arguments are + * parsed locally. The options dictionary should then be used to + * transmit the result of the parsing to the primary instance, where + * Glib::VariantDict::lookup_value() can be used. For local options, it is + * possible to consult (and potentially remove) the option from the options dictionary. + * + * This function is new in GLib 2.40. Before then, the only real choice + * was to send all of the commandline arguments (options and all) to the + * primary instance for handling. Application ignored them completely + * on the local side. Calling this function "opts in" to the new + * behaviour, and in particular, means that unrecognised options will be + * treated as errors. Unrecognised options have never been ignored when + * Gio::APPLICATION_HANDLES_COMMAND_LINE is unset. + * + * If signal_handle_local_options() needs to see the list of + * filenames, then the use of G_OPTION_REMAINING as @a long_name is recommended. + * G_OPTION_REMAINING can be used as a key into + * the options dictionary. If you do use G_OPTION_REMAINING then you + * need to handle these arguments for yourself because once they are + * consumed, they will no longer be visible to the default handling + * (which treats them as filenames to be opened). + * + * @newin{2,42} + * + * @param arg_type A Gio::Application::OptionType. + * @param long_name The long name of an option can be used to specify it + * in a commandline as `--long_name`. Every option must have a + * long name. + * @param short_name If an option has a short name, it can be specified + * `-short_name` in a commandline. @a short_name must be a printable + * ASCII character different from '-', or '\0' if the option has no + * short name. + * @param description The description for the option in `--help` output. + * @param arg_description The placeholder to use for the extra argument parsed + * by the option in `--help` output. + * @param flags Flags from Glib::OptionEntry::Flags. Do not set FLAG_FILENAME. + * Character encoding is chosen with @a arg_type. + */ + void add_main_option_entry(OptionType arg_type, const Glib::ustring& long_name, + gchar short_name = '\0', const Glib::ustring& description = Glib::ustring(), + const Glib::ustring& arg_description = Glib::ustring(), int flags = 0); + _IGNORE(g_application_add_main_option_entries) - //TODO: _WRAP_METHOD(void add_option_group(Glib::OptionGroup& group), g_application_add_option_group) + // _WRAP_METHOD(void add_option_group(Glib::OptionGroup& group), g_application_add_option_group) + // add_option_group() is probably not very useful. If implemented, it must probably + // be custom-implemented. See https://bugzilla.gnome.org/show_bug.cgi?id=727822#c10 + _IGNORE(g_application_add_option_group) _WRAP_METHOD(bool is_registered() const, g_application_get_is_registered) _WRAP_METHOD(bool is_remote() const, g_application_get_is_remote) @@ -274,5 +361,4 @@ private: const Glib::Class& custom_class_init(); }; - } // namespace Gio |