mhsabbagh / green-recorder

A simple screen recorder for Linux desktop. Supports Wayland & Xorg
GNU General Public License v3.0
616 stars 118 forks source link

App is not relocatable #7

Open popey opened 7 years ago

popey commented 7 years ago

in some places green-recorder has hard wired paths to files. e.g.

indicator = appindicator.Indicator.new("Green Recorder", '/usr/share/pixmaps/green-recorder.png', appindicator.IndicatorCategory.APPLICATION_STATUS)

and:-

builder.add_from_file("/usr/lib/green-recorder/ui.glade")

This assumption breaks the ability for green-recorder to work in some environments. Specifically when containerised or confined, that directory may be somewhere else (relative) on the filesystem, and not at that absolute path.

mhsabbagh commented 7 years ago

You are right. Any suggestion for determining those paths relatively?

popey commented 7 years ago

Sorry, I don't know. Are there not XDG or LD environment variables which could be used? how do other gtk apps do this?

mhsabbagh commented 7 years ago

Unfortunately - as far as I know - no. There doesn't exist such variables to use. So implementing such solution would require some hard coding. Or maybe there's a library which provides such functionality and I don't know about it.

phw commented 7 years ago

Other GTK apps often compile pixmaps, glade UI and CSS files as a gresource. This way you don't have to rely on hard coded paths, but use URIs like "resource:///com/uploadedlobster/peek/css/peek.css" defined inside the resource file. See https://developer.gnome.org/gio/stable/GResource.html

Not quite sure how this works with Python, though. If using C or Vala one can simply compile the resources in, removing the needs for file system paths entirely. On Python you have to still load the compiled gresource file with some code like this:

DATA_DIR = "data/"
resource = Gio.resource_load(DATA_DIR + "green-recorder.gresource")
Gio.Resource._register(self.resource)
builder = Gtk.Builder()
builder.add_from_resource('/some/path/to/resource/window.ui')

Again one typical approach is to set the DATA_DIR path during installation. Or you search for it in known locations.

SafaAlfulaij commented 7 years ago

Since a GNOME app uses a hardcoded path, I don't see it's that bad...

phw commented 7 years ago

That's not a hard coded file system path, that is the path inside the compiled resources ;) It is independent of the install location.

SafaAlfulaij commented 7 years ago

Then there is this: https://git.gnome.org/browse/gnome-music/tree/gnome-music.in#n102 Which leads to: https://git.gnome.org/browse/gnome-music/tree/gnome-music.in#n47 That leads to: https://git.gnome.org/browse/gnome-music/tree/gnome-music.in#n44

Side note: The app needs some restructuring :)

gort818 commented 7 years ago

@phw I do not understand , it is a python application how are there compiled resources?

julianrichen commented 7 years ago

@gort818 The ui, images, and whatever assets you want inside the resources can be either

  1. Compiled into the c code (if your using c)
  2. Compiled into a .gresource file (what most Python people do)
  3. Loaded directly

You create the gresource file by using glib-compile-resources:

glib-compile-resources test.gresource.xml --target=test.gresource

Creates a test.gresource file containing the compiled resources.

Then you can access it with:

resource = Gio.resource_load(os.path.join(PACKAGE_DATA_DIR, 'test.gresource'))
Gio.Resource._register(resource)

and loaded resources from it with:

builder = Gtk.Builder()
builder.add_from_resource('/tld/domain/project/resource.ui')

Where /tld/domain/project is the application id for the project, and is included in the gresource. Normally it follows the standard of a domain + name, example:

gnome.org/music

becomes:

/org/gnome/music

A lot of people on Github do:

github.com/green-project/green-recorder
green-project.github.io/green-recorder

becomes:

/io/github/green-project/green-recorder
gort818 commented 7 years ago

@julianrichen Wow thank you very informative!

julianrichen commented 7 years ago

Also forgot a few things. Gtk can automatically implement parts of your program with resources (page I linked -> Description -> Automatic resources). For example the app-menu and menubar can be loaded automatically by linking a ui file in the gresoures.xml that is either at gtk/menus.ui or has an alias to it. They can also be split into gtk/menus-appmenu.ui or gtk/menus-traditional.ui.

Same can also be done with for Keyboard shortcuts via gtk/help-overlay.ui.

Here is an example that links up Preferences, Keyboard Shortcuts, Help, About and Quit to the app-menu/menubar to the application + adds the help-overlay (GAction is win.show-help-overlay). This only setsup the menus, besides the help-overlay you would need to create the preferences, about, help, quit actions your self. If you wanted to add them of course.

gtk/menus.ui

<?xml version="1.0"?>
<interface>
    <menu id="app-menu">
        <section>
            <item>
                <attribute name="label" translatable="yes">_Preferences</attribute>
                <attribute name="action">app.preferences</attribute>
                <attribute name="accel">&lt;Primary&gt;comma</attribute>
            </item>
        </section>
        <section>
            <item>
                <attribute name="label" translatable="yes">_Keyboard Shortcuts</attribute>
                <attribute name="action">win.show-help-overlay</attribute>
            </item>
            <item>
                <attribute name="label" translatable="yes">_Help</attribute>
                <attribute name="action">app.help</attribute>
                <attribute name="accel">F1</attribute>
            </item>
            <item>
                <attribute name="label" translatable="yes">_About</attribute>
                <attribute name="action">app.about</attribute>
                <attribute name="accel">F2</attribute>
            </item>
            <item>
                <attribute name="label" translatable="yes">_Quit</attribute>
                <attribute name="action">app.quit</attribute>
                <attribute name="accel">&lt;Primary&gt;q</attribute>
            </item>
        </section>
    </menu>
    <menu id="menubar">
        <submenu>
            <attribute name="label">_File</attribute>
            <section>
                <item>
                    <attribute name="label" translatable="yes">_Quit</attribute>
                    <attribute name="action">app.quit</attribute>
                    <attribute name="accel">&lt;Primary&gt;q</attribute>
                </item>
            </section>
        </submenu>
        <submenu>
            <attribute name="label">_Edit</attribute>
            <section>
                <item>
                    <attribute name="label" translatable="yes">_Preferences</attribute>
                    <attribute name="action">app.preferences</attribute>
                    <attribute name="accel">&lt;Primary&gt;comma</attribute>
                </item>
            </section>
        </submenu>
        <submenu>
            <attribute name="label">_Help</attribute>
            <section>
                <item>
                    <attribute name="label" translatable="yes">_Keyboard Shortcuts</attribute>
                    <attribute name="action">win.show-help-overlay</attribute>
                </item>
                <item>
                    <attribute name="label" translatable="yes">_Help</attribute>
                    <attribute name="action">app.help</attribute>
                    <attribute name="accel">F1</attribute>
                </item>
                <item>
                    <attribute name="label" translatable="yes">_About</attribute>
                    <attribute name="action">app.about</attribute>
                    <attribute name="accel">F2</attribute>
                </item>
            </section>
        </submenu>
    </menu>
</interface>

gtk/help-overlay.ui

<?xml version="1.0" encoding="UTF-8"?>
<interface>
    <object class="GtkShortcutsWindow" id="help_overlay">
        <property name="modal">True</property>
        <child>
            <object class="GtkShortcutsSection">
                <property name="visible">True</property>
                <property name="section-name">shortcuts</property>
                <property name="max-height">17</property>
                <child>
                    <object class="GtkShortcutsGroup">
                        <property name="visible">True</property>
                        <property name="title" translatable="yes" context="shortcut window">General</property>
                        <child>
                            <object class="GtkShortcutsShortcut">
                                <property name="visible">True</property>
                                <property name="title" translatable="yes" context="shortcut window">Preferences</property>
                                <property name="accelerator">&lt;Primary&gt;comma</property>
                            </object>
                        </child>
                        <child>
                            <object class="GtkShortcutsShortcut">
                                <property name="visible">True</property>
                                <property name="title" translatable="yes" context="shortcut window">Keyboard Shortcuts</property>
                                <property name="accelerator">&lt;Primary&gt;F1</property>
                                <property name="accelerator">&lt;Primary&gt;&lt;Shift&gt;question</property>
                            </object>
                        </child>
                        <child>
                            <object class="GtkShortcutsShortcut">
                                <property name="visible">True</property>
                                <property name="title" translatable="yes" context="shortcut window">Help</property>
                                <property name="accelerator">F1</property>
                            </object>
                        </child>
                        <child>
                            <object class="GtkShortcutsShortcut">
                                <property name="visible">True</property>
                                <property name="title" translatable="yes" context="shortcut window">About</property>
                                <property name="accelerator">F2</property>
                            </object>
                        </child>
                        <child>
                            <object class="GtkShortcutsShortcut">
                                <property name="visible">True</property>
                                <property name="title" translatable="yes" context="shortcut window">Quit</property>
                                <property name="accelerator">&lt;Primary&gt;Q</property>
                            </object>
                        </child>
                    </object>
                </child>
            </object>
        </child>
    </object>
</interface>

ui/window.ui (your current ui/ui.glade)

xml code...
``

`io.github.green-project.green-recorder.gresource.xml`
```xml
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
    <gresource prefix="/io/github/green-project/green-recorder/">
        <file alias="gtk/menus.ui">gtk/menus.ui</file>
        <file alias="gtk/help-overlay.ui" preprocess="xml-stripblanks" compressed="true">gtk/help-overlay.ui</file>
        <file preprocess="xml-stripblanks" compressed="true">ui/window.ui</file>
    </gresource>
</gresources>

I would refrain from doing to many images as it can make the size of the gresource massive. SVG's are ok since they tend to be small and you only need one for most sizes.

ghost commented 6 years ago

I've made a PR which should fix the issue, the commit in question: https://github.com/foss-project/green-recorder/pull/97/commits/59f08907a4ffeb6a7acf082af90c1037e80f37d1