Commit 4fc169c0 authored by Tijder's avatar Tijder
Browse files

Init builder commit

parents
This diff is collapsed.
#!/usr/bin/env python3
from os import environ, path
from subprocess import call
prefix = environ.get('MESON_INSTALL_PREFIX', '/usr/local')
datadir = path.join(prefix, 'share')
destdir = environ.get('DESTDIR', '')
# Package managers set this so we don't need to run
if not destdir:
print('Updating icon cache...')
call(['gtk-update-icon-cache', '-qtf', path.join(datadir, 'icons', 'hicolor')])
print('Updating desktop database...')
call(['update-desktop-database', '-q', path.join(datadir, 'applications')])
print('Compiling GSettings schemas...')
call(['glib-compile-schemas', path.join(datadir, 'glib-2.0', 'schemas')])
desktop_file = i18n.merge_file(
input: 'org.gnome.Plex.desktop.in',
output: 'org.gnome.Plex.desktop',
type: 'desktop',
po_dir: '../po',
install: true,
install_dir: join_paths(get_option('datadir'), 'applications')
)
desktop_utils = find_program('desktop-file-validate', required: false)
if desktop_utils.found()
test('Validate desktop file', desktop_utils,
args: [desktop_file]
)
endif
appstream_file = i18n.merge_file(
input: 'org.gnome.Plex.appdata.xml.in',
output: 'org.gnome.Plex.appdata.xml',
po_dir: '../po',
install: true,
install_dir: join_paths(get_option('datadir'), 'appdata')
)
appstream_util = find_program('appstream-util', required: false)
if appstream_util.found()
test('Validate appstream file', appstream_util,
args: ['validate', appstream_file]
)
endif
install_data('org.gnome.Plex.gschema.xml',
install_dir: join_paths(get_option('datadir'), 'glib-2.0/schemas')
)
compile_schemas = find_program('glib-compile-schemas', required: false)
if compile_schemas.found()
test('Validate schema file', compile_schemas,
args: ['--strict', '--dry-run', meson.current_source_dir()]
)
endif
<?xml version="1.0" encoding="UTF-8"?>
<component type="desktop">
<id>org.gnome.Plex.desktop</id>
<metadata_license>CC0-1.0</metadata_license>
<project_license>GPL-3.0-or-later</project_license>
<description>
</description>
</component>
[Desktop Entry]
Name=plex
Exec=plex
Terminal=false
Type=Application
Categories=GTK;
StartupNotify=true
<?xml version="1.0" encoding="UTF-8"?>
<schemalist gettext-domain="plex">
<schema id="org.gnome.Plex" path="/org/gnome/Plex/">
</schema>
</schemalist>
project('plex', version: '0.1.0',
meson_version: '>= 0.40.0',
)
i18n = import('i18n')
subdir('data')
subdir('src')
subdir('po')
meson.add_install_script('build-aux/meson/postinstall.py')
\ No newline at end of file
{
"app-id": "org.gnome.Plex",
"runtime": "org.gnome.Platform",
"runtime-version": "3.28",
"sdk": "org.gnome.Sdk",
"command": "plex",
"finish-args": [
"--share=network",
"--share=ipc",
"--socket=x11",
"--socket=wayland",
"--filesystem=xdg-run/dconf",
"--filesystem=~/.config/dconf:ro",
"--talk-name=ca.desrt.dconf",
"--env=DCONF_USER_CONFIG_DIR=.config/dconf"
],
"build-options": {
"cflags": "-O2 -g",
"cxxflags": "-O2 -g",
"env": {
"V": "1"
}
},
"cleanup": [
"/include",
"/lib/pkgconfig",
"/man",
"/share/doc",
"/share/gtk-doc",
"/share/man",
"/share/pkgconfig",
"*.la",
"*.a"
],
"modules": [
{
"name": "plex",
"buildsystem": "meson",
"config-opts": [ "--libdir=lib" ],
"builddir": true,
"sources": [
{
"type": "git",
"url": "file:///home/gerben/git/plex"
}
]
}
]
}
data/org.gnome.Plex.desktop.in
data/org.gnome.Plex.appdata.xml.in
data/org.gnome.Plex.gschema.xml
src/window.ui
src/main.py
src/window.py
i18n.gettext('plex', preset: 'glib')
#
# Copyright 2015 Dustin Spicuzza <dustin@virtualroadside.com>
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
# USA
from os.path import abspath, join
import inspect
import warnings
from gi.repository import Gio
from gi.repository import GLib
from gi.repository import GObject
from gi.repository import Gtk
__all__ = ['GtkTemplate']
class GtkTemplateWarning(UserWarning):
pass
def _connect_func(builder, obj, signal_name, handler_name,
connect_object, flags, cls):
'''Handles GtkBuilder signal connect events'''
if connect_object is None:
extra = ()
else:
extra = (connect_object,)
# The handler name refers to an attribute on the template instance,
# so ask GtkBuilder for the template instance
template_inst = builder.get_object(cls.__gtype_name__)
if template_inst is None: # This should never happen
errmsg = "Internal error: cannot find template instance! obj: %s; " \
"signal: %s; handler: %s; connect_obj: %s; class: %s" % \
(obj, signal_name, handler_name, connect_object, cls)
warnings.warn(errmsg, GtkTemplateWarning)
return
handler = getattr(template_inst, handler_name)
if flags == GObject.ConnectFlags.AFTER:
obj.connect_after(signal_name, handler, *extra)
else:
obj.connect(signal_name, handler, *extra)
template_inst.__connected_template_signals__.add(handler_name)
def _register_template(cls, template_bytes):
'''Registers the template for the widget and hooks init_template'''
# This implementation won't work if there are nested templates, but
# we can't do that anyways due to PyGObject limitations so it's ok
if not hasattr(cls, 'set_template'):
raise TypeError("Requires PyGObject 3.13.2 or greater")
cls.set_template(template_bytes)
bound_methods = set()
bound_widgets = set()
# Walk the class, find marked callbacks and child attributes
for name in dir(cls):
o = getattr(cls, name, None)
if inspect.ismethod(o):
if hasattr(o, '_gtk_callback'):
bound_methods.add(name)
# Don't need to call this, as connect_func always gets called
#cls.bind_template_callback_full(name, o)
elif isinstance(o, _Child):
cls.bind_template_child_full(name, True, 0)
bound_widgets.add(name)
# Have to setup a special connect function to connect at template init
# because the methods are not bound yet
cls.set_connect_func(_connect_func, cls)
cls.__gtemplate_methods__ = bound_methods
cls.__gtemplate_widgets__ = bound_widgets
base_init_template = cls.init_template
cls.init_template = lambda s: _init_template(s, cls, base_init_template)
def _init_template(self, cls, base_init_template):
'''This would be better as an override for Gtk.Widget'''
# TODO: could disallow using a metaclass.. but this is good enough
# .. if you disagree, feel free to fix it and issue a PR :)
if self.__class__ is not cls:
raise TypeError("Inheritance from classes with @GtkTemplate decorators "
"is not allowed at this time")
connected_signals = set()
self.__connected_template_signals__ = connected_signals
base_init_template(self)
for name in self.__gtemplate_widgets__:
widget = self.get_template_child(cls, name)
self.__dict__[name] = widget
if widget is None:
# Bug: if you bind a template child, and one of them was
# not present, then the whole template is broken (and
# it's not currently possible for us to know which
# one is broken either -- but the stderr should show
# something useful with a Gtk-CRITICAL message)
raise AttributeError("A missing child widget was set using "
"GtkTemplate.Child and the entire "
"template is now broken (widgets: %s)" %
', '.join(self.__gtemplate_widgets__))
for name in self.__gtemplate_methods__.difference(connected_signals):
errmsg = ("Signal '%s' was declared with @GtkTemplate.Callback " +
"but was not present in template") % name
warnings.warn(errmsg, GtkTemplateWarning)
# TODO: Make it easier for IDE to introspect this
class _Child(object):
'''
Assign this to an attribute in your class definition and it will
be replaced with a widget defined in the UI file when init_template
is called
'''
__slots__ = []
@staticmethod
def widgets(count):
'''
Allows declaring multiple widgets with less typing::
button \
label1 \
label2 = GtkTemplate.Child.widgets(3)
'''
return [_Child() for _ in range(count)]
class _GtkTemplate(object):
'''
Use this class decorator to signify that a class is a composite
widget which will receive widgets and connect to signals as
defined in a UI template. You must call init_template to
cause the widgets/signals to be initialized from the template::
@GtkTemplate(ui='foo.ui')
class Foo(Gtk.Box):
def __init__(self):
super(Foo, self).__init__()
self.init_template()
The 'ui' parameter can either be a file path or a GResource resource
path::
@GtkTemplate(ui='/org/example/foo.ui')
class Foo(Gtk.Box):
pass
To connect a signal to a method on your instance, do::
@GtkTemplate.Callback
def on_thing_happened(self, widget):
pass
To create a child attribute that is retrieved from your template,
add this to your class definition::
@GtkTemplate(ui='foo.ui')
class Foo(Gtk.Box):
widget = GtkTemplate.Child()
Note: This is implemented as a class decorator, but if it were
included with PyGI I suspect it might be better to do this
in the GObject metaclass (or similar) so that init_template
can be called automatically instead of forcing the user to do it.
.. note:: Due to limitations in PyGObject, you may not inherit from
python objects that use the GtkTemplate decorator.
'''
__ui_path__ = None
@staticmethod
def Callback(f):
'''
Decorator that designates a method to be attached to a signal from
the template
'''
f._gtk_callback = True
return f
Child = _Child
@staticmethod
def set_ui_path(*path):
'''
If using file paths instead of resources, call this *before*
loading anything that uses GtkTemplate, or it will fail to load
your template file
:param path: one or more path elements, will be joined together
to create the final path
TODO: Alternatively, could wait until first class instantiation
before registering templates? Would need a metaclass...
'''
_GtkTemplate.__ui_path__ = abspath(join(*path))
def __init__(self, ui):
self.ui = ui
def __call__(self, cls):
if not issubclass(cls, Gtk.Widget):
raise TypeError("Can only use @GtkTemplate on Widgets")
# Nested templates don't work
if hasattr(cls, '__gtemplate_methods__'):
raise TypeError("Cannot nest template classes")
# Load the template either from a resource path or a file
# - Prefer the resource path first
try:
template_bytes = Gio.resources_lookup_data(self.ui, Gio.ResourceLookupFlags.NONE)
except GLib.GError:
ui = self.ui
if isinstance(ui, (list, tuple)):
ui = join(ui)
if _GtkTemplate.__ui_path__ is not None:
ui = join(_GtkTemplate.__ui_path__, ui)
with open(ui, 'rb') as fp:
template_bytes = GLib.Bytes.new(fp.read())
_register_template(cls, template_bytes)
return cls
# Future shim support if this makes it into PyGI?
#if hasattr(Gtk, 'GtkTemplate'):
# GtkTemplate = lambda c: c
#else:
GtkTemplate = _GtkTemplate
# main.py
#
# Copyright 2018 Gerben Droogers
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import sys
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, Gio
from .window import PlexWindow
class Application(Gtk.Application):
def __init__(self):
super().__init__(application_id='org.gnome.Plex',
flags=Gio.ApplicationFlags.FLAGS_NONE)
def do_activate(self):
win = self.props.active_window
if not win:
win = PlexWindow(application=self)
win.present()
def main(version):
app = Application()
return app.run(sys.argv)
pkgdatadir = join_paths(get_option('prefix'), get_option('datadir'), meson.project_name())
moduledir = join_paths(pkgdatadir, 'plex')
gnome = import('gnome')
gnome.compile_resources('plex',
'plex.gresource.xml',
gresource_bundle: true,
install: true,
install_dir: pkgdatadir,
)
python3 = import('python3')
conf = configuration_data()
conf.set('PYTHON', python3.find_python().path())
conf.set('VERSION', meson.project_version())
conf.set('localedir', join_paths(get_option('prefix'), get_option('localedir')))
conf.set('pkgdatadir', pkgdatadir)
configure_file(
input: 'plex.in',
output: 'plex',
configuration: conf,
install: true,
install_dir: get_option('bindir')
)
plex_sources = [
'__init__.py',
'gi_composites.py',
'main.py',
'window.py',
]
install_data(plex_sources, install_dir: moduledir)
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
<gresource prefix="/org/gnome/Plex">
<file>window.ui</file>
</gresource>
</gresources>
#!@PYTHON@
# plex.in
#
# Copyright 2018 Gerben Droogers
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os
import sys
import signal
import gettext
VERSION = '@VERSION@'
pkgdatadir = '@pkgdatadir@'
localedir = '@localedir@'
sys.path.insert(1, pkgdatadir)
signal.signal(signal.SIGINT, signal.SIG_DFL)
gettext.install('plex', localedir)
if __name__ == '__main__':
import gi
from gi.repository import Gio
resource = Gio.Resource.load(os.path.join(pkgdatadir, 'plex.gresource'))
resource._register()
from plex import main
sys.exit(main.main(VERSION))
# window.py
#
# Copyright 2018 Gerben Droogers
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from gi.repository import Gtk
from .gi_composites import GtkTemplate
@GtkTemplate(ui='/org/gnome/Plex/window.ui')
class PlexWindow(Gtk.ApplicationWindow):
__gtype_name__ = 'PlexWindow'
label = GtkTemplate.Child()
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.init_template()
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<requires lib="gtk+" version="3.20"/>
<template class="PlexWindow" parent="GtkApplicationWindow">
<property name="default-width">600</property>
<property name="default-height">300</property>
<child type="titlebar">
<object class="GtkHeaderBar" id="header_bar">
<property name="visible">True</property>
<property name="show-close-button">True</property>
<property name="title">Hello, World!</property>
</object>
</child>
<child>
<object class="GtkLabel" id="label">
<property name="label">Hello, World!</property>
<property name="visible">True</property>
<attributes>
<attribute name="weight" value="bold"/>
<attribute name="scale" value="2"/>
</attributes>
</object>
</child>
</template>