Desktop integration
| Anke (encarsia) | Also available in: Deutsch
Contents
Desktop integration: icon, headerbar, commndline options
(Continuation if the GtkApplication article)
Glade
Icon
To assign an icon to an window just select "General Appearance > Icon File". Problematic here is that Glade only shows image files located in the same folder as the Glade file even if an image from another folder is chosen.
A simple solution is editing the Glade file in a text editor and add the relative path to the icon. This edit is preserved even when changing and saving the file with Glade again:
<object class="GtkApplicationWindow" id="window"> ... <!-- <property name="icon">duckyou.svg</property> --> <property name="icon">../files/duckyou.svg</property> ...
Headerbar
Headerbars were introduced in GNOME 3.10 and unite titlebar and toolbar. Besides title and subtitle there is room for widgets such as buttons or menus and client side window controls.
A headerbar is optional. To make use of it "General > Appearance > Client side window decorations" has to be activated if not set yet. This prepares a reserved container area in the upper window area to add the headerbar widget in. If a headerbar is placed out of this specific area a regular titlebar is generated in addition to the headerbar.
Commandline options
GtkApplication provides functions to define individual commandline options of the applications (Handling command line options in GApplication).
Create Options
Options are added by the add_main_option_entries(entrylist)
function. The entries must be GLib.OptionEntry formatted which requires a bunch of parameters.
def __init__(self): self.app = Gtk.Application.new("org.application.test", Gio.ApplicationFlags(0)) self.app.add_main_option_entries([ self.create_option_entry("--version", description="Show version numbers and exit"), self.create_option_entry("--setlabel", description="Set label widget", arg=GLib.OptionArg.STRING,), self.create_option_entry("--bollocks", description="Additional test option - exit"), ]) def create_option_entry(self, long_name, short_name=None, flags=0, arg=GLib.OptionArg.NONE, arg_data=None, description=None, arg_description=None): option = GLib.OptionEntry() option.long_name = long_name.lstrip('-') option.short_name = 0 if not short_name else ord(short_name.lstrip('-')) option.flags = flags option.arg = arg option.arg_data = arg_data option.description = description option.arg_description = arg_description return option
Short names
An option can have a one character synonym ("a printable ASCII character different from ‘-‘" to be precise), the short name. Lokking at the option --help
this commonly is -h
.
The short_name
variable of OptionEntry ist surprisingly integer. The not very obvious solution here is to pass the character's decimal code, p.e. 97 for "a". An error message will be thrown when trying to pass invalid numbers. Options without a short code get a value of 0.
Connect signal
The "handle-local-options" signal of Gtk.Application handles commandline options. If the signal is connected the signal is emitted before the "startup" signal.
self.app.connect("handle-local-options", self.on_local_option)
Processing options
The option
will be passed as an element of the GLib.VariantDict class which can be searched for by calling contains("option")
:
def on_local_option(self, app, option): if option.contains("option1"): #do something and exit normally return 0 elif option.contains("option2"): #do something different and exit return 0 elif option.contains("option3"): #do more and continue return -1
A string can be extracted by calling end()
which converts GLib.VariantDict to a GLib.Variant element. That GLib.Variant then can be culled by calling keys()
:
var = GLib.VariantDict.end(option) option_string = var[var.keys()[0]]
The handler function demands a return value that corresponds to the exit status:
-1: application execution will be continued
0: execution successful, application will be quit, "startup/activate" will not be emitted
1 or positive value: execution was not successful, application will be quit
Run application with options
The option --help
is always available and lists all defined options of the application and their descriptions.
The options of the example file now can be executed:
$ python script.py --version Python: 3.6.0 GTK+: 3.22.6
or pass a string to the application's Gtk.Label:
$ python script.py --setlabel "I can haz options!"
Listings
Glade
<?xml version="1.0" encoding="UTF-8"?> <!-- Generated with glade 3.20.0 --> <interface> <requires lib="gtk+" version="3.20"/> <object class="GtkMenu" id="menu"> <property name="visible">True</property> <property name="can_focus">False</property> <child> <object class="GtkMenuItem"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="label" translatable="yes">MenuItem 1</property> <property name="use_underline">True</property> </object> </child> <child> <object class="GtkMenuItem"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="label" translatable="yes">MenuItem 2</property> <property name="use_underline">True</property> </object> </child> <child> <object class="GtkMenuItem"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="label" translatable="yes">MenuItem 3</property> <property name="use_underline">True</property> </object> </child> </object> <object class="GtkApplicationWindow" id="window"> <property name="width_request">400</property> <property name="height_request">300</property> <property name="can_focus">False</property> <property name="title" translatable="yes">Titel</property> <property name="icon">../files/duckyou.svg</property> <property name="show_menubar">False</property> <child> <object class="GtkBox"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="orientation">vertical</property> <child> <object class="GtkImage"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="pixbuf">../files/duckyou.svg</property> </object> <packing> <property name="expand">True</property> <property name="fill">True</property> <property name="position">0</property> </packing> </child> <child> <object class="GtkLabel" id="label"> <property name="visible">True</property> <property name="can_focus">False</property> </object> <packing> <property name="expand">False</property> <property name="fill">True</property> <property name="pack_type">end</property> <property name="position">1</property> </packing> </child> <child> <object class="GtkSeparator"> <property name="visible">True</property> <property name="can_focus">False</property> </object> <packing> <property name="expand">False</property> <property name="fill">True</property> <property name="position">2</property> </packing> </child> </object> </child> <child type="titlebar"> <object class="GtkHeaderBar"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="title">Titel</property> <property name="subtitle">Untertitel</property> <property name="show_close_button">True</property> <child> <object class="GtkMenuButton"> <property name="visible">True</property> <property name="can_focus">True</property> <property name="receives_default">True</property> <property name="popup">menu</property> <child> <placeholder/> </child> </object> </child> <child> <object class="GtkButton"> <property name="label">gtk-no</property> <property name="visible">True</property> <property name="can_focus">True</property> <property name="receives_default">True</property> <property name="use_stock">True</property> <property name="always_show_image">True</property> </object> <packing> <property name="pack_type">end</property> <property name="position">2</property> </packing> </child> <child> <object class="GtkButton"> <property name="label">gtk-yes</property> <property name="visible">True</property> <property name="can_focus">True</property> <property name="receives_default">True</property> <property name="use_stock">True</property> <property name="always_show_image">True</property> </object> <packing> <property name="pack_type">end</property> <property name="position">2</property> </packing> </child> </object> </child> </object> </interface>
Python
#!/usr/bin/python # -*- coding: utf-8 -*- import sys import setproctitle import gi gi.require_version("Gtk", "3.0") from gi.repository import Gtk, Gio, GLib class ExampleApp: def __init__(self): setproctitle.setproctitle("Application test") GLib.set_prgname("testapp") self.app = Gtk.Application.new("org.application.test", Gio.ApplicationFlags(0)) self.app.add_main_option_entries([ self.create_option_entry("--version", description="Show version numbers and exit", ), self.create_option_entry("--setlabel", description="Set label widget", arg=GLib.OptionArg.STRING, ), self.create_option_entry("--bollocks", description="Additional test option - exit", ), ]) self.app.connect("handle-local-options", self.on_local_option) self.app.connect("activate", self.on_app_activate) def on_local_option(self, app, option): self.option_string = "" if option.contains("version"): var = GLib.VariantDict.end(option) print("Python: {}".format(sys.version[:5])) print("GTK+: {}.{}.{}".format(Gtk.MAJOR_VERSION, Gtk.MINOR_VERSION, Gtk.MICRO_VERSION, )) return 0 elif option.contains("bollocks"): return 1 elif option.contains("setlabel"): var = GLib.VariantDict.end(option) self.option_string = var[var.keys()[0]] return -1 def create_option_entry(self, long_name, short_name=None, flags=0, arg=GLib.OptionArg.NONE, arg_data=None, description=None, arg_description=None, ): option = GLib.OptionEntry() option.long_name = long_name.lstrip("-") option.short_name = 0 if not short_name else ord(short_name.lstrip("-")) option.flags = flags option.arg = arg option.arg_data = arg_data option.description = description option.arg_description = arg_description return option def on_app_activate(self, app): builder = Gtk.Builder() builder.add_from_file("15_application.glade") self.obj = builder.get_object self.obj("window").set_application(app) self.obj("label").set_text(self.option_string) self.obj("window").show_all() def run(self, argv): self.app.run(argv) app = ExampleApp() app.run(sys.argv)
Comments
Comments powered by Disqus