(DOC) GTK start-up internals and design of Lumiera's UI-Layer

This commit is contained in:
Fischlurch 2018-08-03 21:53:27 +02:00
parent 7db8bf4c0c
commit 4306e47930
3 changed files with 226 additions and 77 deletions

View file

@ -7,3 +7,72 @@ GTK -- UI toolkit and framework
Within this subsection we collect some random bits of information related to our
use of the GTK windowing toolkit for building Lumiera's user interface.
Concepts
--------
A facility like GTK can be seen to serve various needs. It can be used to simplify
the arduous task of building a graphical user interface, but it can also be seen as
a one-stop solution for just creating a (``damn modern cool'') application, which
all ``reasonable'' people today expect to have a shiny GUI. In fact, we can identify
these two different levels of support, which inevitably create conflicting goals.
- GTK-the-framework shall be easy to use and cover everything I never wanted to know
about user interfaces. Ideally, I just inherit from a base class, implement two or
three abstract methods and fill in my actual working logic.
- GTK-the-toolkit is a collection of prefabricated building blocks, ready to be used
and put into action, by people with a clear conception about what is required for
a productive UI and how to achieve that in detail.
Needless to say that Lumiera's use of GTK falls into the second category. Even more so,
as the GTK UI is just a plug-in, loaded optionally, and not identical with the application
as such. Which often places us into a tricky situation -- obviously GTK-the-framework is
what attracts most attention, both from the users and the developers.
The Gtk::Application
~~~~~~~~~~~~~~~~~~~~
*In short*: we do not use it, we do not want it, we do not need it, it's just obnoxious.
In the _good old days(TM)_ there used to be a singleton class `GTK::Main`. You'd activate
your application by invoking the blocking function `Main::run()`. This design was sweet
and simple, but turned out to be too rigid once people started to expect lots of things
to ``just work''. Consequently, `Gtk::Main` was deprecated by the GTK-developers and
``replaced'' by `Gtk::Application`. Unfortunately, this move reflects a paradigm shift
from _toolkit_ towards an _application building framework._ This framework includes
- a well defined global application lifecycle
- command line parsing with extension points for custom argument handling
- a ready-made framework of _actions_, to be arranged into menus and toolbars
- management of ``the application instance'', with inter process communication
in case the deaf user double clicks the application icon a second time
- the notion of a ``associated document type'' and ``desktop actions''
to be forwarded to the implementing application, which thus needs to
be invocable in service-style.
- registration with the desktop, interconnection with the D-Bus
None of the above is _evil_ in any sense, much is even useful. However, there is a notion
of a working style, underlying the vision for Lumiera: work is considered a long-term
undertaking, organised into a project and carried out in a fixed and controlled environment
over the course of an extended time period. Basically we envision the user to make some
_footage_ available to an _editing workstation_, and then to return to this very setup over
the course of weeks, or months, or years, expecting everything to remain reliably the same,
just as configured initially.
Based on this model, we basically want to shape all application global concerns in a
very specific way -- and almost all the standard solutions offered by GTK-the-framework
tend to get into our way of working. For this reason
- we have our own framework of subsystems
- we build our own approach towards command line handling
- we rely on the notion of a project to define a specific work environment
- we want menus and toolbars to be configurable based on both the project and user preference,
goverened by rules and with persistent interface state
- we deliberately allow for various ways to launch the application, even without UI
- we build our own system to navigate within the UI, spanning several top-level windows and desktops.
Consequently, none of the services offered by `Gtk::Application` is of much use for us. After reading
the source code, we came to the conclusion that it is perfectly valid to sidestep all those aspects
of GTK, and just perform those small number of toolkit initialisation steps -- previously invoked
by `Gtk::Main` -- directly from our application code. Basically Lumiera's `gui::ctrl::UiManager`
replaces `Gtk::Main`, invokes `gtk_init` and enters the blocking event loop by calling `gtk_main`.

View file

@ -2,68 +2,145 @@ GTK start-up
============
:Date: 2018
//Menu: label start-up
_some insights regarding the start-up of GTK and related framework aspects_
A facility like GTK can be seen to serve various needs. It can be used to simplify
the arduous task of building a graphical user interface, but it can also be seen as
a one-stop solution for just creating a (``damn modern cool'') application, which
all ``reasonable'' people today expect to have a shiny GUI. In fact, we can identify
these two different levels of support, which inevitably create conflicting goals.
As outlined on the link:{ldoc}/technical/code/gtk/index.html[overview page], we need to discern between
toolkit aspects, and GTK-the-framework. Moreover, we use GTK though the C++ bindings (`gtkmm`), which also
add a thin layer of software abstractions.
- GTK-the-framework shall be easy to use and cover everything I never wanted to know
about user interfaces. Ideally, I just inherit from a base class, implement two or
three abstract methods and fill in my actual working logic.
- GTK-the-toolkit is a collection of prefabricated building blocks, ready to be used
and put into action, by people with a clear conception about what is required for
a productive UI and how to achieve that in detail.
Initialisation
--------------
So in order to ``use GTK'' ...
Needless to say that Lumiera's use of GTK falls into the second category. Even more so,
as the GTK UI is just a plug-in, loaded optionally, and not identical with the application
as such. Which often places us into a tricky situation -- obviously GTK-the-framework is
what attracts most attention, both from the users and the developers.
- we need to build our application against the appropriate headers of GTK\--, which also implies to
install the corresponding development packages (or a source tree) of the libraries involved.
- when our main application decides to use the GTK-UI, it loads the GUI plug-in -- at this point
the dynamic loader also requires and loads the runtime libraries of GTK, Glib, GDL, Cairo, Pango,
plus the runtime libraries of the C++ wrappers (Gtkmm, Glibmm, Gdlmm)
- at this point, the various layers of software comprising ``the GTK'' will require some very
specific initialisation hooks to be invoked. Especially
The Gtk::Application
--------------------
*In short*: we do not use it, we do not want it, we do not need it, it's just obnoxious.
** GTK itself requires the invocation of `gtk_init()` in order to attach to the windowing system.
This might also parse additional framework specific command lines and react on some environment
variables, init the gettext library and maybe activate interactive UI debugging. But nothing
beyond that
In the _good old days(TM)_ there used to be a singleton class `GTK::Main`. You'd activate
your application by invoking the blocking function `Main::run()`. This design was simple
and sweet, but turned out to be too rigid once people started to expect lots of things
to ``just work''. Consequently, `Gtk::Main` was deprecated by the GTK-developers and
``replaced'' by `Gtk::Application`. Unfortunately, this move reflects a paradigm shift
from _toolkit_ towards an _application building framework._ This framework includes
** the `gtkmm` C\++ wrappers deal with a lot of additional ceremony, required by the plain-C
implementation of the GTK core. Especially, they automatically register any ``object type''
with the GObject-system of Glib. Moreover, some virtual function tables will be populated
and several ``object functions'' and signals need to be wrapped, so client code can invoke
the more convenient C++ equivalents. All of this additional initialisation is effected
by invoking `Gtk::Main::init_gtkmm_internals()` or the (equivalent) static function within
`Gtk::Application`
- command line parsing with extension points for custom argument handling
- a ready-made framework of _actions_, to be arranged into menus and toolbars
- management of ``the application instance'', with inter process communication
in case the deaf user double clicks the application icon a second time
- registration with the desktop, interconnection with the D-Bus
- the notion of a ``associated document type'' and ``desktop actions''
to be forwarded to the implementing application, which thus needs to
be invocable in service-style.
** finally, any features of GTK-the-framework need to be initialised and prepared for use:
None of the above is _evil_ in any sense, much is even useful. However, there is a notion
of a working style, underlying the vision for Lumiera: work is a long-term undertaking,
organised into a project and carried out in a fixed and controlled environment over the
course of an extended time period. Basically we envision the user to make some _footage_
available to a _editing workstation_, and then to return to this very setup over the
course of weeks, or months, or years, expecting everything to remain reliably the same
as configured initially.
*** lifecycle events need to be issued. GTK uses ``signals'' for this purpose
footnote:[not to be confused with the signals on operating system level]
*** registration of document types with the desktop environment
*** the application instance will connect to the D-bus and install the necessary callbacks,
possibly even waiting for an ``activation event''
*** depending on the specific way of _activation_, behaviour and error response of the
application instance need to be controlled in distinct ways -- maybe just rendering
content or even silently terminating altogether after a timeout has passed
Based on this model, we basically want to shape all application global concerns in a
very specific way -- and almost all the standard solutions offered by GTK-the-framework
tend to get into our way of working. For this reason
For reasons outlined link:{ldoc}/technical/code/gtk/index.html#_the_gtk_application[above],
Lumiera does not need nor use a `Gtk::Application`.footnote:[In fact, most of the framework
functionality is actually handled within the base class `Gio::Application`, which corresponds
to the plain-C type `GApplication`.] Thus, we leave out the third stage and deal with all those
application global aspects through means appropriate to our specific purpose.
- we have our own framework of subsystems
- we build our own approach towards command line handling
- we rely on the notion of a project to define a specific work environment
- we want menus and toolbars to be configurable based on both the project and user preference
- we deliberately allow for various ways to launch the application, possibly in multiple instances
- we build our own system to navigate within the UI, spanning several top-level windows and desktops.
- our link:{ldoc}/design/architecture/Subsystems.html[Subsystem runner] boots the UI subsystem
(`gui::GuiFacade`), which in turn loads the UI-plug-in ('target/modules/gtk_gui.lum').
- within this plug-in, the class `gui::GtkLumiera` governs the complete UI lifecycle.
- this class holds a member `gui::ctl::UiManager` -- which is our ``UI main object'' and mimics
the design of the late `Gtk::Main`.
- we inherit from our own `gui::ctrl::ApplicationBase` class, to ensure invocation of all the
initialisation and clean-up functions required by GTK
- we instantiate a class `gui::ctrl::GlobalCtx` to hold and provide all global services used
throughout the UI layer, including population of the menu and global actions
- within the global context, there is also `gui::ctrl::WindowLocator`, to keep track of all
top-level application windows, and to support direct navigation to relevant entities within
the UI, based on _abstracted UI-coordinates_.
- finally, `GtkLumiera` invokes the functions
** `UiManager::createApplicationWindow()` to create the visible interface frame
** `UiManager::performMainLoop()` to activate `gtk_main()` -- the blocking GTK event loop
Consequently, none of the services offered by `Gtk::Application` is of any use for us. After reading
the source code, we came to the conclusion that it is perfectly valid to sidestep all those aspects
of GTK, and just perform those small number of toolkit initialisation steps -- previously invoked
by `Gtk::Main` -- directly from our application code. Basically Lumiera's `gui::ctrl::UiManager`
replaces `Gtk::Main`, invokes `gtk_init` and enters the blocking event loop by calling `gtk_main`.
Running a GTK application
-------------------------
The _event processing_ is what makes an UI application ``live''. However, event processing must
not be confused with graphical presentation. In GTK, it is perfectly valid to create and even
show a widget prior to entering the event loop. Yet it is a very fundamental design decision
within GTK to operate all of the UI concerns *synchronously*, from within a single dedicated
*UI thread*. We consider this a very wise design decision, and expand it to all of Lumiera's
UI concerns, including the UI-Bus; any ``interaction mechanics'' has to happen within this
single thread, and is completely decoupled from all other application functionality like
editing actions and rendering, which happen in separate threads and respond asynchronously
by _dispatching_ their reactions back into the UI event thread.
Due to the shifted scope between the old-style `Gtk::Main` and the corresponding `gtk_main()`
C-function on one side, and the newer, more framework-centric `Gtk::Application`, it might seem
on first sight, that both will perform different tasks. However, a closer look reveals that
during the redesign for GTK-3, the old ``main'' functionality has been _retrofitted_ to rely
on the newer, more generic GIO-Framework. More specifically
- the classical `gtk_main()` without much ado invokes `g_main_loop_run()`, which in turn
immediately starts to ``pull'' the GIO main context by repeatedly invoking `g_main_context_iterate()`
- whereas the `Gtk::Application::run()` invokes `Gio::Application::run()` and from there the new
application-level _main function_ `g_application_run(gobj(), argc, argv)`. Which in turn handles
all the above mentioned framework concerns (e.g. D-Bus registration / activation). Then it
enters `g_main_context_iteration()` which -- similar to `g_main_loop_run()` -- starts ``pulling''
the GIO main context by repeatedly invoking `g_main_context_iterate()`
Thus, once we reach the actual operative state, both paths of activating a GTK application behave
essentially the same.footnote:[This is the state of affairs during the GTK-3 lifetime cycle,
as verified in 8/2018 based on the source code of `GTK 3.22`. Note though that GTK-4 is ``around
the corner'' -- let's see what awesome innovations we have to face then...]
The application activation signal
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
However, the old-style approach seems to lack a feature offered by `Gio::Application`:
the *activation* signal, which is a feature solely present at the ``application-framework'' level
and used internally for the convenience function to ``run an ApplicationWindow object''
(-> `Gtk::Application::run(Gtk::Window&)`). In fact, this happens to be a lifecycle event,
and can be used by connecting a SigC++ slot to the application object's `signal_activation()`.
Outside the realm of GTK-the-framework this feature turns out to be not so useful; especially, the
signal is emitted _shortly before_ entering the event loop, and not from within (as you'd might expect).
A better alternative is to rely on the `Glib::signal_idle()` rsp. `Glib::signal_timeout()`. Both allow
to invoke a slot only once, and both ensure the invocation really happens from within the event loop.
SigC++ trackable
~~~~~~~~~~~~~~~~
Any closure or callback based system of wiring and activation suffers from the inherent danger of invoking
a dangling reference. Within an interactive UI environment, this problem becomes quite acid, since widgets
will be created and destroyed through arbitrary interactions, yet still need to be connected to ``live state''.
When building UI applications with Gtkmm (the C\++ wrapper of GTK), this problem is dealt with by inheriting
all widget classes from the `sigc::trackable` mix-in. This mechanism automatically detaches a signal slot
when the corresponding target widget goes out of scope. However, this solution only works reliably when
all slots are created and connected from within a single thread (the UI event thread!). Moreover, we
can not possibly ``track'' a slot created from a C\++ language lambda or functor -- which sometimes
is even the only option, unless we want to incur a dependency on the SigC++ library. In Lumiera,
we have a strict policy to prohibit any dependency on GTK libraries outside the UI layer.
Shutdown
--------
The GTK main loop terminates after invocation of `gtk_main_quit()` (or in case of serious internal errors).
Typically, this function is somehow bound to a widget interaction, like clicking on the ``close'' button.
In Lumiera, this concern is managed by the `gui::ctrl::WindowLocator`, which keeps track of all top-level
windows and terminates the UI when the last one is closed. Moreover, the UI can deliberately be closed
by sending an event over the `GuiNotification::triggerGuiShutdown(message)' call.
After leaving the main loop, the external façade interfaces are closed. By general architectonic reasoning,
no event can be processed and no signal can be invoked any more -- and thus we're free to destroy all widgets,
services and the backbone of the UI. After that, the UI subsystem signals termination, which causes all other
subsystems to shut down as well.footnote:[We are aware that there is a race between closing the façade and actually
ceasing other subsystem's activities, which might cause those other activities to fail with an exception]

View file

@ -1659,7 +1659,7 @@
</html></richcontent>
<arrowlink COLOR="#851358" DESTINATION="ID_548720270" ENDARROW="Default" ENDINCLINATION="-663;-614;" ID="Arrow_ID_325703166" STARTARROW="None" STARTINCLINATION="1110;608;"/>
<icon BUILTIN="messagebox_warning"/>
<node COLOR="#338800" CREATED="1485118623744" HGAP="23" ID="ID_392996871" MODIFIED="1518487921055" TEXT="#1032 use gtk::Application instead of gtk::Main" VSHIFT="11">
<node COLOR="#338800" CREATED="1485118623744" FOLDED="true" HGAP="23" ID="ID_392996871" MODIFIED="1533325801383" TEXT="#1032 use gtk::Application instead of gtk::Main" VSHIFT="11">
<arrowlink COLOR="#ae1856" DESTINATION="ID_206480879" ENDARROW="Default" ENDINCLINATION="715;0;" ID="Arrow_ID_926482654" STARTARROW="Default" STARTINCLINATION="134;383;"/>
<icon BUILTIN="button_ok"/>
<node CREATED="1485118668802" ID="ID_575152579" MODIFIED="1518487921055" TEXT="WindowManager verwendet gtk::Main"/>
@ -1798,7 +1798,11 @@
<node COLOR="#2f1d56" CREATED="1495218684994" ID="ID_101574501" MODIFIED="1518487921056" TEXT="vorerst defensiv vorgehen">
<font ITALIC="true" NAME="SansSerif" SIZE="12"/>
</node>
<node CREATED="1495218699712" ID="ID_1332523704" MODIFIED="1518487921056" TEXT="den Code aus Gtk::Main in unsere Codebasis &#xfc;bernehmen">
<node COLOR="#338800" CREATED="1533325503372" ID="ID_1815764983" MODIFIED="1533325787563" TEXT="nochmal gr&#xfc;ndlich &#xfc;berpr&#xfc;ft und dokumentiert">
<arrowlink COLOR="#70dcb9" DESTINATION="ID_889790361" ENDARROW="Default" ENDINCLINATION="1308;0;" ID="Arrow_ID_1988524020" STARTARROW="Default" STARTINCLINATION="-2084;0;"/>
<icon BUILTIN="button_ok"/>
</node>
<node COLOR="#338800" CREATED="1495218699712" ID="ID_1332523704" MODIFIED="1533325519569" TEXT="den Code aus Gtk::Main in unsere Codebasis &#xfc;bernehmen">
<icon BUILTIN="button_ok"/>
</node>
<node CREATED="1495218714230" FOLDED="true" ID="ID_1371091843" MODIFIED="1531584014122" TEXT="Vorsicht mit Action / ActionGroup">
@ -15890,8 +15894,8 @@
<font ITALIC="true" NAME="SansSerif" SIZE="12"/>
<icon BUILTIN="messagebox_warning"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1532788645307" ID="ID_254810710" MODIFIED="1532788655288" TEXT="Trigger-Technik kl&#xe4;ren">
<icon BUILTIN="pencil"/>
<node COLOR="#338800" CREATED="1532788645307" ID="ID_254810710" MODIFIED="1533325370427" TEXT="Trigger-Technik kl&#xe4;ren">
<icon BUILTIN="button_ok"/>
<node CREATED="1532788681197" FOLDED="true" HGAP="336" ID="ID_32192034" MODIFIED="1533310206546" TEXT="bei GTK selber abschauen" VSHIFT="-52">
<richcontent TYPE="NOTE"><html>
<head>
@ -16112,9 +16116,9 @@
<icon BUILTIN="yes"/>
</node>
</node>
<node CREATED="1532788727680" HGAP="57" ID="ID_889790361" MODIFIED="1533310405367" TEXT="Gtk::Main auf aktuellem Stand" VSHIFT="8">
<arrowlink COLOR="#f3396a" DESTINATION="ID_1283695968" ENDARROW="Default" ENDINCLINATION="-81;-236;" ID="Arrow_ID_1530325920" STARTARROW="None" STARTINCLINATION="119;-5;"/>
<icon BUILTIN="pencil"/>
<node COLOR="#338800" CREATED="1532788727680" FOLDED="true" HGAP="69" ID="ID_889790361" MODIFIED="1533325857935" TEXT="Gtk::Main auf aktuellem Stand" VSHIFT="12">
<linktarget COLOR="#70dcb9" DESTINATION="ID_889790361" ENDARROW="Default" ENDINCLINATION="1308;0;" ID="Arrow_ID_1988524020" SOURCE="ID_1815764983" STARTARROW="Default" STARTINCLINATION="-2084;0;"/>
<icon BUILTIN="button_ok"/>
<node COLOR="#338800" CREATED="1532788737366" ID="ID_1527913663" MODIFIED="1532788745870" TEXT="aktuellen Code bereitlegen in Eclipse">
<icon BUILTIN="button_ok"/>
</node>
@ -16269,18 +16273,17 @@
<icon BUILTIN="info"/>
</node>
</node>
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1532797168836" ID="ID_1283695968" MODIFIED="1533218227864" TEXT="TODO: diesen Stand dokumentieren">
<linktarget COLOR="#f3396a" DESTINATION="ID_1283695968" ENDARROW="Default" ENDINCLINATION="-81;-236;" ID="Arrow_ID_1530325920" SOURCE="ID_889790361" STARTARROW="None" STARTINCLINATION="119;-5;"/>
<icon BUILTIN="flag-pink"/>
<node COLOR="#338800" CREATED="1532797168836" ID="ID_1283695968" MODIFIED="1533325339452" TEXT="diesen Stand dokumentieren...">
<icon BUILTIN="button_ok"/>
<node CREATED="1532797180066" ID="ID_687615166" MODIFIED="1532797192496" TEXT="siehe Ticket #1032">
<icon BUILTIN="info"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1533218052308" ID="ID_1734927969" MODIFIED="1533218091117" TEXT="neue Kategorie: technical/code base/ GTK">
<icon BUILTIN="yes"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1533218096245" ID="ID_1901487140" MODIFIED="1533218296183" TEXT="dort Seite startup">
<node COLOR="#338800" CREATED="1533218096245" ID="ID_1901487140" MODIFIED="1533325344852" TEXT="dort Seite startup">
<arrowlink COLOR="#dc217a" DESTINATION="ID_539459561" ENDARROW="Default" ENDINCLINATION="33;201;" ID="Arrow_ID_601982135" STARTARROW="None" STARTINCLINATION="-55;-186;"/>
<icon BUILTIN="flag-yellow"/>
<icon BUILTIN="button_ok"/>
<node CREATED="1533218137447" ID="ID_59387223" MODIFIED="1533218142874" TEXT="lose Notizen dorthin"/>
<node CREATED="1533218147981" ID="ID_1385133985" MODIFIED="1533218153417" TEXT="Main vs Application"/>
<node CREATED="1533218154141" ID="ID_511849124" MODIFIED="1533218165327" TEXT="unser Ansatz"/>
@ -16466,12 +16469,12 @@
<icon BUILTIN="yes"/>
</node>
</node>
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1533311818120" ID="ID_413505030" MODIFIED="1533311824592" TEXT="Forschung: wie machbar?">
<icon BUILTIN="flag-pink"/>
<node COLOR="#338800" CREATED="1533311818120" ID="ID_413505030" MODIFIED="1533325891506" TEXT="Forschung: wie machbar?">
<icon BUILTIN="button_ok"/>
<node CREATED="1533311849484" ID="ID_741726269" MODIFIED="1533311856167" TEXT="Problem: gtk_main blockt"/>
<node CREATED="1533311863586" ID="ID_1275401100" MODIFIED="1533311895161" TEXT="jeder Aufruf davor k&#xf6;nnte zum Race f&#xfc;hren"/>
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1533311922114" ID="ID_542781128" MODIFIED="1533311941004" TEXT="gibt es dazu irgendwelche Doku?">
<icon BUILTIN="flag-pink"/>
<node CREATED="1533311922114" ID="ID_542781128" MODIFIED="1533325883642" TEXT="gibt es dazu irgendwelche Doku?">
<icon BUILTIN="button_ok"/>
<node COLOR="#435e98" CREATED="1533311999743" ID="ID_159524494" LINK="https://developer.gnome.org/gtkmm-tutorial/stable/sec-the-constraints.html.de" MODIFIED="1533312023736" TEXT="GTKmm-Tutorial: multithreaded">
<font NAME="SansSerif" SIZE="12"/>
<icon BUILTIN="info"/>
@ -32300,7 +32303,7 @@
<linktarget COLOR="#677ab7" DESTINATION="ID_782313223" ENDARROW="Default" ENDINCLINATION="-1088;-39;" ID="Arrow_ID_234165792" SOURCE="ID_433225506" STARTARROW="None" STARTINCLINATION="-2111;0;"/>
<linktarget COLOR="#677ab7" DESTINATION="ID_782313223" ENDARROW="Default" ENDINCLINATION="-981;-106;" ID="Arrow_ID_1912776282" SOURCE="ID_1636078216" STARTARROW="None" STARTINCLINATION="-2111;0;"/>
<node CREATED="1495221242285" ID="ID_185528211" MODIFIED="1518487921099" TEXT="Applikation">
<node CREATED="1495221272545" ID="ID_624250153" MODIFIED="1518487921099" TEXT="Gtk::Application">
<node CREATED="1495221272545" FOLDED="true" ID="ID_624250153" MODIFIED="1533325443038" TEXT="Gtk::Application">
<node CREATED="1495222327564" ID="ID_175461027" MODIFIED="1518487921099" TEXT="initialisiert Gio::Application"/>
<node CREATED="1495222337235" ID="ID_348472460" MODIFIED="1518487921099" TEXT="setzt ggfs. die Applikations-ID"/>
<node CREATED="1495223436241" ID="ID_1015366549" MODIFIED="1518487921099" TEXT="Application::run">
@ -32341,7 +32344,7 @@
</node>
<node CREATED="1495221537366" ID="ID_381245884" MODIFIED="1518487921099" TEXT="stellt eine dBus-Verbindung bereit"/>
<node CREATED="1495221546252" ID="ID_771692992" MODIFIED="1518487921099" TEXT="erbt von Gio::ActionGroup und ActionMap"/>
<node CREATED="1533307013028" HGAP="32" ID="ID_1511454400" MODIFIED="1533307028207" TEXT="on activation" VSHIFT="16">
<node CREATED="1533307013028" FOLDED="true" HGAP="32" ID="ID_1511454400" MODIFIED="1533325409236" TEXT="on activation" VSHIFT="16">
<node CREATED="1533307054478" ID="ID_1200897297" MODIFIED="1533307059929" TEXT="g_application_activate">
<node CREATED="1533307252691" ID="ID_11609503" MODIFIED="1533307276116" TEXT="gapplication.c (ca line 2220)"/>
<node CREATED="1533307297630" ID="ID_312502406" MODIFIED="1533307298225" TEXT="g_signal_emit (application, g_application_signals[SIGNAL_ACTIVATE], 0)"/>
@ -32461,7 +32464,7 @@
</node>
</node>
</node>
<node CREATED="1495223467588" HGAP="27" ID="ID_666842762" MODIFIED="1533307038494" TEXT="run" VSHIFT="12">
<node CREATED="1495223467588" FOLDED="true" HGAP="27" ID="ID_666842762" MODIFIED="1533325417082" TEXT="run" VSHIFT="12">
<icon BUILTIN="back"/>
<node CREATED="1533306448070" ID="ID_1602611708" MODIFIED="1533307626966" TEXT="g_application_run(gobj(), argc, argv)">
<linktarget COLOR="#a9b4c1" DESTINATION="ID_1602611708" ENDARROW="Default" ENDINCLINATION="262;0;" ID="Arrow_ID_1688106140" SOURCE="ID_1228966939" STARTARROW="None" STARTINCLINATION="-50;95;"/>
@ -32500,7 +32503,7 @@
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1495224595638" ID="ID_1774384379" MODIFIED="1518487921099" TEXT="@deprecated">
<icon BUILTIN="messagebox_warning"/>
</node>
<node CREATED="1495224609188" ID="ID_1615155508" MODIFIED="1533306146656">
<node CREATED="1495224609188" FOLDED="true" ID="ID_1615155508" MODIFIED="1533325432144">
<richcontent TYPE="NODE"><html>
<head>
@ -32517,7 +32520,7 @@
<linktarget COLOR="#a9b4c1" DESTINATION="ID_1615155508" ENDARROW="Default" ENDINCLINATION="-27;-158;" ID="Arrow_ID_152226640" SOURCE="ID_1085605910" STARTARROW="None" STARTINCLINATION="-209;0;"/>
<node CREATED="1495224862227" ID="ID_762530588" MODIFIED="1518487921099" TEXT="init_gtkmm_internals"/>
<node CREATED="1495224890119" ID="ID_137730290" MODIFIED="1518487921099" TEXT="statische funktion"/>
<node CREATED="1532795620784" FOLDED="true" ID="ID_1850885017" MODIFIED="1533306139169" TEXT="gtk_init">
<node CREATED="1532795620784" FOLDED="true" ID="ID_1850885017" MODIFIED="1533319255913" TEXT="gtk_init">
<linktarget COLOR="#87a8bf" DESTINATION="ID_1850885017" ENDARROW="Default" ENDINCLINATION="-195;-45;" ID="Arrow_ID_960670945" SOURCE="ID_377749143" STARTARROW="None" STARTINCLINATION="416;0;"/>
<icon BUILTIN="back"/>
<node CREATED="1532796724776" ID="ID_685469322" MODIFIED="1532796729971" TEXT="bleibt weiterhin bestehen"/>
@ -32593,7 +32596,7 @@
<icon BUILTIN="messagebox_warning"/>
</node>
</node>
<node CREATED="1532795594468" FOLDED="true" ID="ID_681479502" MODIFIED="1533306019466" TEXT="Main::init_gtkmm_internals">
<node CREATED="1532795594468" FOLDED="true" ID="ID_681479502" MODIFIED="1533320812539" TEXT="Main::init_gtkmm_internals">
<richcontent TYPE="NOTE"><html>
<head>
@ -32699,8 +32702,8 @@
</node>
</node>
</node>
<node CREATED="1495224625466" ID="ID_668309036" MODIFIED="1518487921099" TEXT="run">
<node CREATED="1495224647071" ID="ID_660577000" MODIFIED="1518487921099" TEXT="gtk_main">
<node CREATED="1495224625466" ID="ID_668309036" MODIFIED="1533325422859" TEXT="run">
<node CREATED="1495224647071" FOLDED="true" ID="ID_660577000" MODIFIED="1533325424496" TEXT="gtk_main">
<font BOLD="true" NAME="SansSerif" SIZE="12"/>
<node CREATED="1495224649943" ID="ID_1753452940" MODIFIED="1518487921099" TEXT="g_main_loop_run">
<node CREATED="1495224690714" ID="ID_355427981" MODIFIED="1518487921099" TEXT="g_main_context_iterate">