Commit d7b066dc authored by Guido Gunther's avatar Guido Gunther

Initial commit

parents
_build
*.swp
*~
\#*#
.\#*
# Handy
The aim of The handy library is to help with developing UI for mobile devices
using GTK+/GNOME.
## License
libhandy is licensed under the GPLv3+.
## Building
We use the meson (and thereby Ninja) build system for libhandy. The quickest
way to get going is to do the following:
meson . _build
ninja -C _build
ninja -C _build install
For build options see [meson_options.txt](./meson_otions.txt). E.g. to enable documentation:
meson . _build -Denable_gtk_doc=true
ninja -C _build/ libhandy-doc
## Usage
There a C example:
_build/examples/example
and one in Python. When running from the built source tree it
needs several environment varibles so use \_build/run to set them:
_build/run examples/example.py
<?xml version="1.0"?>
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
"http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [
<!ENTITY % local.common.attrib "xmlns:xi CDATA #FIXED 'http://www.w3.org/2003/XInclude'">
<!ENTITY % gtkdocentities SYSTEM "xml/gtkdocentities.ent">
%gtkdocentities;
]>
<refentry id="build-howto">
<refmeta>
<refentrytitle>Compiling with &package_string;</refentrytitle>
<manvolnum>3</manvolnum>
</refmeta>
<refnamediv>
<refname>Compiling with &package_string;</refname><refpurpose>Notes on compiling</refpurpose>
</refnamediv>
<refsect2>
<title>Using pkg-config</title>
<para> Like other GNOME libraries,
<application>&package_string;</application> uses
<application>pkg-config</application> to provide compiler options. The
package name is
"<literal>&package_ver_str;</literal>". So in
your <literal>configure</literal> script, you might specify something
like: </para>
<informalexample><programlisting>
PKG_CHECK_MODULES(LIBPLANFAHR, [&package_string;-&package_api_version;])
AC_SUBST(LIBPLANFAHR_CFLAGS)
AC_SUBST(LIBPLANFAHR_LIBS)
</programlisting></informalexample>
<para>
The "<literal>&package_api_version;</literal>" in the package name is the "API version"
(indicating "the version of the <application>&package_string;</application> API
that first appeared in version &package_api_version;") and is essentially just part of
the package name.
</para>
</refsect2>
<refsect2>
<title>Headers</title>
<para>
Code using <application>&package_string;</application> should do:
</para>
<informalexample><programlisting>
#include &lt;&package_string;/&package_ver_str;.h&gt;
</programlisting></informalexample>
<para>
Including individual headers rather than <literal>&package_string;.h</literal> is not
recommended.
</para>
</refsect2>
</refentry>
<?xml version="1.0"?>
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
"http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd"
[
<!ENTITY % local.common.attrib "xmlns:xi CDATA #FIXED 'http://www.w3.org/2003/XInclude'">
<!ENTITY % gtkdocentities SYSTEM "xml/gtkdocentities.ent">
%gtkdocentities;
]>
<book id="index">
<bookinfo>
<title>&package_name; Reference Manual</title>
<releaseinfo>
<para>This document is the API reference for for &package_name; &package_version;.</para>
<para>
Handy is a library to help you write dialers for GTK+/GNOME based mobile phones.
</para>
<para>
If you find any issues in this API reference, please report it
using <ulink type="http" url="&package_bugreport;">at the
bugtracker</ulink>
</para>
</releaseinfo>
<copyright>
<year>2017</year>
<holder>Guido Günther</holder>
</copyright>
</bookinfo>
<chapter id="intro">
<title>Introduction</title>
<xi:include href="build-howto.xml"/>
<xi:include href="visual-index.xml"/>
</chapter>
<chapter id="core-api">
<title>Widgets and Objects</title>
<xi:include href="xml/hdy-dialer.xml"/>
<xi:include href="xml/hdy-dialer-button.xml"/>
</chapter>
<chapter id="helpers">
<title>Helpers</title>
<xi:include href="xml/hdy-version.xml"/>
</chapter>
<chapter id="object-tree">
<title>Object Hierarchy</title>
<xi:include href="xml/tree_index.sgml"/>
</chapter>
<index id="api-index-full">
<title>API Index</title>
<xi:include href="xml/api-index-full.xml"><xi:fallback /></xi:include>
</index>
<index id="deprecated-api-index" role="deprecated">
<title>Index of deprecated API</title>
<xi:include href="xml/api-index-deprecated.xml"><xi:fallback /></xi:include>
</index>
</book>
if get_option('enable_gtk_doc')
subdir('xml')
private_headers = [
'config.h',
]
images = [
'images/dialer.png',
]
content_files = [
'build-howto.xml',
'visual-index.xml',
]
glib_prefix = dependency('glib-2.0').get_pkgconfig_variable('prefix')
glib_docpath = join_paths(glib_prefix, 'share', 'gtk-doc', 'html')
docpath = join_paths(get_option('datadir'), 'gtk-doc', 'html')
gnome.gtkdoc('libhandy',
main_xml: 'handy-docs.xml',
src_dir: [
join_paths(meson.source_root(), 'src'),
join_paths(meson.build_root(), 'src'),
],
dependencies: libhandy_dep,
gobject_typesfile: 'libhandy.types',
scan_args: [
'--rebuild-types',
'--ignore-headers=' + ' '.join(private_headers),
],
fixxref_args: [
'--html-dir=@0@'.format(docpath),
'--extra-dir=@0@'.format(join_paths(glib_docpath, 'glib')),
'--extra-dir=@0@'.format(join_paths(glib_docpath, 'gobject')),
'--extra-dir=@0@'.format(join_paths(glib_docpath, 'gio')),
'--extra-dir=@0@'.format(join_paths(glib_docpath, 'gi')),
'--extra-dir=@0@'.format(join_paths(glib_docpath, 'gtk3')),
],
install_dir: 'libhandy',
content_files: content_files,
html_assets: images,
install: true)
endif
<?xml version="1.0"?>
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
"http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [
<!ENTITY % local.common.attrib "xmlns:xi CDATA #FIXED 'http://www.w3.org/2003/XInclude'">
<!ENTITY % gtkdocentities SYSTEM "xml/gtkdocentities.ent">
%gtkdocentities;
]>
<refentry id="visual-index">
<refmeta>
<refentrytitle>Visual index</refentrytitle>
<manvolnum>3</manvolnum>
</refmeta>
<refnamediv>
<refname>Widgets in &package_string;</refname><refpurpose>Widget overview</refpurpose>
</refnamediv>
<refsect2>
<title>Widgets</title>
<para role="gallery">
<link linkend="HdyDialer">
<inlinegraphic fileref="dialer.png" format="PNG"></inlinegraphic>
</link>
</para>
</refsect2>
</refentry>
<!ENTITY package "@PACKAGE@">
<!ENTITY package_bugreport "@PACKAGE_BUGREPORT@">
<!ENTITY package_name "@PACKAGE_NAME@">
<!ENTITY package_string "@PACKAGE_STRING@">
<!ENTITY package_tarname "@PACKAGE_TARNAME@">
<!ENTITY package_url "@PACKAGE_URL@">
<!ENTITY package_version "@PACKAGE_VERSION@">
<!ENTITY package_api_version "@PACKAGE_API_VERSION@">
<!ENTITY package_ver_str "@PACKAGE_STRING@-@PACKAGE_API_VERSION@">
ent_conf = configuration_data()
ent_conf.set('PACKAGE', 'Handy')
ent_conf.set('PACKAGE_BUGREPORT', 'http://&lt;nobugtrackeryet&gt;')
ent_conf.set('PACKAGE_NAME', 'Handy')
ent_conf.set('PACKAGE_STRING', 'libhandy')
ent_conf.set('PACKAGE_TARNAME', 'libhandy-' + meson.project_version())
ent_conf.set('PACKAGE_URL', 'http://&lt;nohomepageyet&gt;')
ent_conf.set('PACKAGE_VERSION', meson.project_version())
ent_conf.set('PACKAGE_API_VERSION', apiversion)
configure_file(input: 'gtkdocentities.ent.in', output: 'gtkdocentities.ent', configuration: ent_conf)
#include <gtk/gtk.h>
#include <handy.h>
static void
print_number (GtkWidget *widget,
gchar *number,
gpointer data)
{
g_print ("Dial %s\n", number);
}
static void
barf (GtkWidget *widget,
gpointer data)
{
g_print ("wuff: %s\n", hdy_dialer_get_number (HDY_DIALER (widget)));
}
static void
dialed (GtkApplication *app,
gpointer user_data)
{
GtkWidget *window;
GtkWidget *dialer;
window = gtk_application_window_new (app);
dialer = hdy_dialer_new();
gtk_window_set_title (GTK_WINDOW (window), "Dialer Example");
gtk_window_set_default_size (GTK_WINDOW (window), 200, 200);
gtk_container_add (GTK_CONTAINER (window), dialer);
g_signal_connect (dialer, "notify::number", G_CALLBACK (barf), NULL);
g_signal_connect (dialer, "dialed", G_CALLBACK (print_number), NULL);
g_signal_connect_swapped (dialer, "dialed", G_CALLBACK (gtk_widget_destroy), window);
gtk_widget_show_all (window);
}
int
main (int argc,
char **argv)
{
GtkApplication *app;
int status;
app = gtk_application_new ("org.sigxcpu.example", G_APPLICATION_FLAGS_NONE);
g_signal_connect (app, "activate", G_CALLBACK (dialed), NULL);
status = g_application_run (G_APPLICATION (app), argc, argv);
g_object_unref (app);
return status;
}
#!/usr/bin/python3
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
gi.require_version('Handy', '0.0')
from gi.repository import Handy
import sys
def print_number(dialer, number):
print("Dial {}".format(number))
def quit(dialer, number=None):
Gtk.main_quit()
window = Gtk.Window(title="Dialer Example with Python")
dialer = Handy.Dialer()
dialer.connect("dialed", print_number)
dialer.connect("dialed", quit)
window.connect("destroy", quit)
window.add(dialer)
window.show_all()
Gtk.main()
if get_option('enable_examples')
example_sources = [
'example.c',
]
example = executable('example', example_sources,
dependencies: libhandy_dep,
)
endif
project('libhandy', 'c',
version: '0.0.0',
license: 'GPLv3+',
meson_version: '>= 0.40.1',
default_options: [ 'warning_level=1', 'buildtype=debugoptimized', 'c_std=gnu11' ],
)
version_arr = meson.project_version().split('.')
handy_version_major = version_arr[0].to_int()
handy_version_minor = version_arr[1].to_int()
handy_version_micro = version_arr[2].to_int()
apiversion = '0.0'
soversion = 0
if handy_version_minor.is_odd()
handy_interface_age = 0
else
handy_interface_age = handy_version_micro
endif
# maintaining compatibility with libtool versioning
# current = minor * 100 + micro - interface
# revision = interface
current = handy_version_minor * 100 + handy_version_micro - handy_interface_age
revision = handy_interface_age
libversion = '@0@.@1@.@2@'.format(soversion, current, revision)
config_h = configuration_data()
config_h.set_quoted('GETTEXT_PACKAGE', 'libhandy')
config_h.set_quoted('LOCALEDIR', join_paths(get_option('prefix'), get_option('localedir')))
configure_file(
output: 'config.h',
configuration: config_h,
)
add_project_arguments([
'-DHAVE_CONFIG_H',
'-DHANDY_COMPILATION',
'-I' + meson.build_root(),
], language: 'c')
root_inc = include_directories('.')
src_inc = include_directories('src')
cc = meson.get_compiler('c')
global_c_args = []
test_c_args = [
'-Wcast-align',
'-Wdeclaration-after-statement',
['-Werror=format-security', '-Werror=format=2'],
'-Wformat-nonliteral',
'-Wformat-security',
'-Wmissing-include-dirs',
'-Wnested-externs',
'-Wno-missing-field-initializers',
'-Wno-sign-compare',
'-Wno-strict-aliasing',
'-Wno-uninitialized',
'-Wno-unused-parameter',
'-Wpointer-arith',
'-Wredundant-decls',
'-Wshadow',
'-Wswitch-default',
'-Wswitch-enum',
'-Wundef',
]
if get_option('buildtype') != 'plain'
test_c_args += '-fstack-protector-strong'
endif
if get_option('enable_profiling')
test_c_args += '-pg'
endif
foreach arg: test_c_args
if cc.has_multi_arguments(arg)
global_c_args += arg
endif
endforeach
add_project_arguments(
global_c_args,
language: 'c'
)
# Setup various paths that subdirectory meson.build files need
package_subdir = get_option('package_subdir') # When used as subproject
libdir = join_paths(get_option('libdir'), package_subdir)
girdir = join_paths(get_option('datadir'), package_subdir, 'gir-1.0')
typelibdir = join_paths(get_option('libdir'), package_subdir, 'girepository-1.0')
if package_subdir != ''
vapidir = join_paths(get_option('datadir'), package_subdir, 'vapi')
else
vapidir = join_paths(get_option('datadir'), 'vala', 'vapi')
endif
gnome = import('gnome')
subdir('src')
subdir('examples')
subdir('tests')
subdir('doc')
run_data = configuration_data()
run_data.set('ABS_BUILDDIR', meson.current_build_dir())
configure_file(
input: 'run.in',
output: 'run',
configuration: run_data)
summary = [
'',
'------',
'Handy @0@ (@1@)'.format(current, apiversion),
'',
' Tests: @0@'.format(get_option('enable_tests')),
' Examples: @0@'.format(get_option('enable_examples')),
' Documentation: @0@'.format(get_option('enable_gtk_doc')),
'------',
''
]
message('\n'.join(summary))
# Performance and debugging related options
option('enable_profiling', type: 'boolean', value: false)
option('with_introspection', type: 'boolean', value: true)
option('with_vapi', type: 'boolean', value: true)
# Subproject
option('package_subdir', type: 'string',
description: 'Subdirectory to append to all installed files, for use as subproject'
)
option('enable_gtk_doc',
type: 'boolean', value: false,
description: 'Whether to generate the API reference for Handy')
option('enable_tests',
type: 'boolean', value: true,
description: 'Whether to compile unit tests')
option('enable_examples',
type: 'boolean', value: true,
description: 'Whether to compile unit tests')
#!/bin/sh
ABS_BUILDDIR='@ABS_BUILDDIR@'
export GI_TYPELIB_PATH="${ABS_BUILDDIR}/src:$GI_TYPELIB_PATH"
export LD_LIBRARY_PATH="${ABS_BUILDDIR}/src:$LD_LIBRARY_PATH"
export PKG_CONFIG_PATH="${ABS_BUILDDIR}/src:$PKG_CONFIG_PATH"
exec "$@"
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
<gresource prefix="/org/sigxcpu/handy/dialer/ui">
<file>hdy-dialer.ui</file>
</gresource>
<gresource prefix="/org/sigxcpu/handy/icons/scalable/actions">
<file>phone-dial-symbolic.svg</file>
</gresource>
</gresources>
/* handy.h
*
* Copyright (C) 2017 Christian Hergert <chergert@redhat.com>
*
* 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/>.
*/
#ifndef HANDY_H
#define HANDY_H
#include <gtk/gtk.h>
G_BEGIN_DECLS
#if !GTK_CHECK_VERSION(3, 22, 0)
# error "libhandy requires gtk+-3.0 >= 3.22.0"
#endif
#if !GLIB_CHECK_VERSION(2, 50, 0)
# error "libhandy requires glib-2.0 >= 2.50.0"
#endif
#define HANDY_INSIDE
#include "hdy-version.h"
#include "hdy-dialer-button.h"
#include "hdy-dialer.h"
#undef HANDY_INSIDE
G_END_DECLS
#endif /* HANDY_H */
/* hdy-dialer-button.c
*
* Copyright (C) 2017 Guido Günther <agx@sigxcpu.org>
*
* 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/>.
*/
#include <glib/gi18n.h>
#include "hdy-dialer-button.h"
/**
* SECTION:hdy-dialer-button
* @short_description: A button on a #HdyDialer keypad
* @Title: HdyDialerButton
*
* The #HdyDialerButton widget is a single button on an #HdyDialer. It
* can represent a single digit (0-9) plus an arbitrary number of
* letters that are displayed below the number.
*/
enum {
HDY_DIALER_BUTTON_PROP_0 = 0,
HDY_DIALER_BUTTON_PROP_DIGIT = 1,
HDY_DIALER_BUTTON_PROP_LETTERS = 2,
};
typedef struct
{
gint digit;
gchar *letters;
} HdyDialerButtonPrivate;
G_DEFINE_TYPE_WITH_PRIVATE (HdyDialerButton, hdy_dialer_button, GTK_TYPE_BUTTON)
void
format_label(HdyDialerButton *self)
{
HdyDialerButtonPrivate *priv = hdy_dialer_button_get_instance_private(self);
GString *str;
GtkLabel *label;
g_autofree gchar *text;
str = g_string_new(NULL);
if (priv->digit >= 0) {
g_string_sprintf(str, "%d", priv->digit);
if (priv->letters)
g_string_append_c(str, '\n');
}
if (priv->letters)
g_string_append(str, priv->letters);
text = g_string_free (str, FALSE);
gtk_button_set_label (GTK_BUTTON(self), text);
label = GTK_LABEL(gtk_bin_get_child (GTK_BIN (self)));
gtk_label_set_xalign(label, 0.5);
gtk_label_set_yalign(label, 0.5);
gtk_label_set_justify (GTK_LABEL(label), GTK_JUSTIFY_CENTER);
}
static void
hdy_dialer_button_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
HdyDialerButton *self = HDY_DIALER_BUTTON (object);
HdyDialerButtonPrivate *priv = hdy_dialer_button_get_instance_private(self);
switch (property_id) {
case HDY_DIALER_BUTTON_PROP_DIGIT:
priv->digit = g_value_get_int (value);
format_label(self);
break;
case HDY_DIALER_BUTTON_PROP_LETTERS:
g_free (priv->letters);
priv->letters = g_value_dup_string (value);
format_label(self);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
hdy_dialer_button_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
HdyDialerButton *self = HDY_DIALER_BUTTON (object);
HdyDialerButtonPrivate *priv = hdy_dialer_button_get_instance_private(self);
switch (property_id) {
case HDY_DIALER_BUTTON_PROP_DIGIT:
g_value_set_int (value, priv->digit);
break;
case HDY_DIALER_BUTTON_PROP_LETTERS:
g_value_set_string (value, priv->letters);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
hdy_dialer_button_class_init (HdyDialerButtonClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->set_property = hdy_dialer_button_set_property;
object_class->get_property = hdy_dialer_button_get_property;
g_object_class_install_property (object_class,
HDY_DIALER_BUTTON_PROP_DIGIT,
g_param_spec_int ("digit",
"dialer digit",
"dialer digit",
-1,
INT_MAX,
0,
G_PARAM_READWRITE));
g_object_class_install_property (object_class,
HDY_DIALER_BUTTON_PROP_LETTERS,
g_param_spec_string ("letters",
"dialer letters",
"dialer letters",
"",
G_PARAM_READWRITE));
}
/**
* hdy_dialer_button_new:
* @digit: the digit displayed on the #HdyDialerButton
* @letters: (nullable): the letters displayed on the #HdyDialerButton
*
* Create a new #HdyDialerButton which displays @digit and
* @letters. If @digit is a negative no number will be displayed. If
* @letters is %NULL no letters will be displayed.
*
* Returns: the newly created #HdyDialerButton widget
*/
GtkWidget *hdy_dialer_button_new (int digit, const gchar* letters)
{
return g_object_new (HDY_TYPE_DIALER_BUTTON, "digit", digit, "letters", letters, NULL);
}
static void
hdy_dialer_button_init (HdyDialerButton *self)
{
HdyDialerButtonPrivate *priv = hdy_dialer_button_get_instance_private(self);
priv->digit = -1;
priv->letters = NULL;
}
/**
* hdy_dialer_button_get_digit:
* @self: a #HdyDialerButton
*
* Get the #HdyDialerButton's digit.