|
|
# PyGObject Development Notes
|
|
|
|
|
|
## Checklist
|
|
|
|
|
|
* Application structure
|
|
|
* Build system
|
|
|
* Forms, resources
|
|
|
* Connecting forms to code (`Gtk.Builder`)
|
|
|
* ...or use Gtk.Template decorators
|
|
|
* Connecting resources to code (`Gio.Resource`)
|
|
|
* How to package forms, icons as resources
|
|
|
* Signals
|
|
|
* Actions
|
|
|
* Shortcuts
|
|
|
* Common desktop integration
|
|
|
* Session management
|
|
|
* App menu
|
|
|
* Settings
|
|
|
* Keyfiles for user data
|
|
|
* Desktop file (https://developer.gnome.org/desktop-entry-spec/)
|
|
|
* Categories from https://specifications.freedesktop.org/menu-spec/latest/
|
|
|
* Appdata file (https://www.freedesktop.org/software/appstream/docs/sect-Metadata-Application.html)
|
|
|
* About menu entry and dialog
|
|
|
* Icon in app list in Phosh
|
|
|
* Internationalization/localization
|
|
|
* Packaging
|
|
|
* Librem 5 App Submission into PureOS
|
|
|
https://lists.puri.sm/private/librem5-team/Week-of-Mon-20180409/000992.html
|
|
|
|
|
|
## Gtk.Application
|
|
|
|
|
|
Subclass and instantiate `Gtk.Application` to control the application's lifecycle.
|
|
|
|
|
|
* https://developer.gnome.org/GtkApplication/
|
|
|
|
|
|
Implement `__init__` to call the base class's `__init__` method, giving the application an ID (see https://wiki.gnome.org/HowDoI/ChooseApplicationID).
|
|
|
|
|
|
Implement `do_activate` to create a `Gtk.ApplicationWindow` instance. Note that we must pass the `application` keyword argument when we create this instance.
|
|
|
|
|
|
According to the [PyGObject API Reference](https://lazka.github.io/pgi-docs/#Gtk-3.0/classes/Application.html#Gtk.Application) the following paths relative to the application's resource base path are relevant:
|
|
|
|
|
|
* gtk/menus.ui
|
|
|
* gtk/menus-appmenu.ui
|
|
|
* gtk/menus-traditional.ui
|
|
|
* gtk/menus-common.ui
|
|
|
|
|
|
These should be picked up automatically, but that may not actually be the case given that this example explicitly loads the .ui file using `Gtk.Builder` to load the menu from the resources and sets it explicitly using `set_app_menu`:
|
|
|
|
|
|
* https://developer.gnome.org/gtk3/stable/ch01s04.html#id-1.2.3.12.8
|
|
|
|
|
|
Similarly in this tutorial:
|
|
|
|
|
|
* https://python-gtk-3-tutorial.readthedocs.io/en/latest/application.html
|
|
|
|
|
|
The resource base path is a path within the resource, prefixed by the application's ID. So, an application with the ID "sm.puri.app" will have a resource base path of "/sm/puri/app".
|
|
|
|
|
|
Application IDs have to follow the D-Bus guidelines which restrict the use of digits following periods and hyphens. So digits should be prefixed if they follow periods and underscores should be used instead of hyphens. For example:
|
|
|
|
|
|
com.example.ex02_hello_app not com.example.02-hello-app
|
|
|
|
|
|
Using an invalid application ID can be a problem, especially when creating a flatpak because something expects to be able to use the D-Bus using the application ID and will silently fail if the ID is invalid.
|
|
|
|
|
|
## Gtk.Builder
|
|
|
|
|
|
Instantiate a `Gtk.Builder` to load user interface descriptions from files.
|
|
|
|
|
|
Use the builder's `add_from_file` method to load the contents of a file.
|
|
|
|
|
|
Access widgets, including windows, using the builder's `get_object` method.
|
|
|
|
|
|
Connect signals to handlers, either using code to manually connect the signals to handlers, use a dictionary to map signals to handlers, or use an instance to host handler methods. The last two of these use the builder's `connect_signals` method.
|
|
|
|
|
|
## Gio.Resource
|
|
|
|
|
|
Resources that are not automatically loaded by classes such as `Gtk.Application` can be loaded by calling `Gio.Resource.load` with the file name of the compiled resource file, then registered with `Gio.resources_register` to make their contents available to the whole application.
|
|
|
|
|
|
Resource files are compiled from XML descriptions using the `glib-compile-resources` tool.
|
|
|
|
|
|
## Actions
|
|
|
|
|
|
Action strings used in `Gio.Menu.append` calls are either application level, with an `app.` prefix, or window level, with a `win.` prefix.
|
|
|
|
|
|
https://lazka.github.io/pgi-docs/#Gio-2.0/classes/Action.html#Gio.Action.parse_detailed_name
|
|
|
|
|
|
## Application Menu
|
|
|
|
|
|
* [Making an application menu](https://developer.gnome.org/ApplicationMenu/)
|
|
|
* [Making an application menu](https://wiki.gnome.org/HowDoI/ApplicationMenu)
|
|
|
|
|
|
## Directory Layout for Applications
|
|
|
|
|
|
Use the following layout for applications that use the Python packaging tools (distutils or setuptools):
|
|
|
|
|
|
* COPYING (or LICENSE or other equivalent license file)
|
|
|
* data
|
|
|
* debian *(if Debian packaging is also included)*
|
|
|
* MANIFEST.in
|
|
|
* po
|
|
|
* src *(can be the package/appliction name instead)*
|
|
|
* README (with optional suffix)
|
|
|
* setup.py
|
|
|
|
|
|
Optional files and directories:
|
|
|
|
|
|
* test (if tests are supplied)
|
|
|
|
|
|
Use the following layout for applications that use Meson:
|
|
|
|
|
|
* COPYING (or LICENSE or other equivalent license file)
|
|
|
* data
|
|
|
* debian *(if Debian packaging is also included)*
|
|
|
* meson.build
|
|
|
* meson-postinstall.py
|
|
|
* po
|
|
|
* src *(can be the package/appliction name instead)*
|
|
|
* README (with optional suffix)
|
|
|
|
|
|
Note that Meson can be passed a `--prefix` option and argument to allow programs to be installed in non-system locations for testing.
|
|
|
|
|
|
## Internationalization, Localization, Translations
|
|
|
|
|
|
Packaged outside the application, not as resources.
|
|
|
|
|
|
Configured using standard gettext calls, or the locale module in Python.
|
|
|
|
|
|
The translation domain needs to be set on `Gtk.Builder` for translation of user interface files (for menus, windows) to work.
|
|
|
|
|
|
The destination of the translations (message catalogs) needs to be known by the application itself. Various build systems usually handle this by writing the installation directory to the main program file via a template.
|
|
|
|
|
|
The use of functions in the `locale` module is described in the Python module documentation: [locale - Internationalization services](https://docs.python.org/3/library/locale.html#access-to-message-catalogs).
|
|
|
|
|
|
## Icons
|
|
|
|
|
|
Use the layout described by the Icon Theme Specification, generating a local directory layout for non-installed examples and setting the `XDG_DATA_DIRS` environment variable.
|
|
|
|
|
|
Maybe just supply SVG files.
|
|
|
|
|
|
Supplying a scalable icon in `icons/hicolor/scalable/apps` works. Not sure if a symbolic icon is also required in `icons/hicolor/symbolic/apps`.
|
|
|
|
|
|
## Styles
|
|
|
|
|
|
Some widget styling properties are deprecated and require the use of CSS instead:
|
|
|
* https://developer.gnome.org/gtk3/unstable/GtkButton.html#gtk-button-set-relief
|
|
|
|
|
|
how to set a specific css class to a widget in gtk3? (c)
|
|
|
* https://stackoverflow.com/questions/37609381/how-to-set-a-specific-css-class-to-a-widget-in-gtk3-c
|
|
|
|
|
|
Custom Style:
|
|
|
* https://wiki.gnome.org/HowDoI/CustomStyle
|
|
|
|
|
|
## Widgets
|
|
|
|
|
|
How do I get the size of a Gtk widget?
|
|
|
* https://askubuntu.com/questions/155077/how-do-i-get-the-size-of-a-gtk-widget
|
|
|
|
|
|
Get number of columns in Gtk.Grid?
|
|
|
* https://stackoverflow.com/questions/49756058/get-number-of-columns-in-gtk-grid
|
|
|
(Hint: You can't. You have to keep track of this yourself.)
|
|
|
|
|
|
Custom Widgets
|
|
|
* https://wiki.gnome.org/HowDoI/CustomWidgets
|
|
|
|
|
|
Window.set_default_geometry:
|
|
|
* https://lazka.github.io/pgi-docs/#Gtk-3.0/classes/Window.html#Gtk.Window.set_default_geometry
|
|
|
|
|
|
Window.set_default_size:
|
|
|
* https://lazka.github.io/pgi-docs/#Gtk-3.0/classes/Window.html#Gtk.Window.set_default_size
|
|
|
|
|
|
## Menus and Popovers
|
|
|
|
|
|
ModelButton is for use inside popovers?
|
|
|
* https://python-gtk-3-tutorial.readthedocs.io/en/latest/popover.html
|
|
|
* https://lazka.github.io/pgi-docs/#Gtk-3.0/classes/PopoverMenu.html
|
|
|
|
|
|
## Settings
|
|
|
|
|
|
* https://www.micahcarrick.com/gsettings-python-gnome-3.html
|
|
|
* https://developer.gnome.org/gtk3/stable/ch01s04.html#id-1.2.3.12.8
|
|
|
|
|
|
## DBus
|
|
|
|
|
|
* https://lazka.github.io/pgi-docs/#Gio-2.0/functions.html#Gio.bus_get_sync
|
|
|
|
|
|
## Composite Widget Templates
|
|
|
|
|
|
* https://source.puri.sm/Librem5/developer.puri.sm/merge_requests/251#note_22580
|
|
|
* http://www.virtualroadside.com/blog/index.php/2015/05/24/gtk3-composite-widget-templates-for-python/
|
|
|
* https://github.com/virtuald/pygi-composite-templates
|
|
|
* https://bugzilla.gnome.org/show_bug.cgi?id=701843
|
|
|
|
|
|
## Glade
|
|
|
|
|
|
* https://wiki.gnome.org/action/show/Apps/Glade/Tutorials
|
|
|
* https://www.gnipsel.com/glade/glade01a.html
|
|
|
|
|
|
## Asynchronous Programming
|
|
|
|
|
|
* https://www.micahcarrick.com/asynchronous-read-in-python-with-gio.html
|
|
|
|
|
|
## Timers
|
|
|
|
|
|
* https://stackoverflow.com/questions/23817161/proper-way-force-refresh-of-window-in-gtk-3-using-pygobject |