diff options
127 files changed, 20359 insertions, 124 deletions
diff --git a/.gitignore b/.gitignore deleted file mode 100644 index cbbcb9ca..00000000 --- a/.gitignore +++ /dev/null @@ -1,85 +0,0 @@ -*~ -builddir/ -/*.bak -/*.lo -/*.o -/*.orig -/*.rej -/*.tab.c -/*~ -/.*.sw[nop] -/.deps -/.dirstamp -/.gitignore -/.libs -/AUTHORS -/ABOUT-NLS -/GPATH -/GRTAGS -/GSYMS -/GTAGS -/ID -/INSTALL -/Makefile -/Makefile.in -/TAGS -/_build -/_libs -/aclocal.m4 -/autom4te.cache -/autoscan.log -/compile -/config.cache -/config.guess -/config.h -/config.h.in -/config.log -/config.lt -/config.rpath -/config.status -/config.status.lineno -/config.sub -/configure -/configure.lineno -/configure.scan -/depcomp -/install-sh -/libtool -/ltmain.sh -/m4 -/missing -/mkinstalldirs -/po/*.gmo -/po/*.mo -/po/Makefile -/po/Makefile.in -/po/Makefile.in.in -/po/POTFILES -/po/gnome-music.pot -/po/stamp-it -/so_locations -/stamp-h1 -/tags -/gnome-music/*.pyc -/gnome-music/Makefile -/gnome-music/Makefile.in -/py-compile -*.tar.xz -*.desktop -*.gresource -*.compiled -data/Makefile -data/Makefile.in -*.patch -*.pyc -Makefile -gnome-music -*.valid -/gnomemusic/Makefile.in -/data/AboutDialog.ui -/data/gnome-music.appdata.xml -/help/Makefile.in -/help/**/*.page -/help/**/*.mo -/help/**/*.stamp -/help/**/legal.xml diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml deleted file mode 100644 index a484574a..00000000 --- a/.gitlab-ci.yml +++ /dev/null @@ -1,30 +0,0 @@ -include: 'https://gitlab.gnome.org/GNOME/citemplates/raw/master/flatpak/flatpak_ci_initiative.yml' - -stages: - - check - - build-flatpak - - deploy - -variables: - BUNDLE: "gnome-music-dev.flatpak" - GIT_SUBMODULE_STRATEGY: normal - -flatpak: - extends: .flatpak - stage: build-flatpak - variables: - APP_ID: "org.gnome.Music.Devel" - FLATPAK_MODULE: "gnome-music" - MANIFEST_PATH: "org.gnome.Music.json" - RUNTIME_REPO: "https://nightly.gnome.org/gnome-nightly.flatpakrepo" - -nightly: - extends: .publish_nightly - dependencies: - - flatpak - -flake8: - stage: check - script: - - dnf install -y python3-flake8 - - flake8 --ignore E402,W503 --show-source gnomemusic/ diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index 9b66516e..00000000 --- a/.gitmodules +++ /dev/null @@ -1,9 +0,0 @@ -[submodule "subprojects/libgd"] - path = subprojects/libgd - url = https://gitlab.gnome.org/GNOME/libgd.git -[submodule "subprojects/shared-modules"] - path = subprojects/shared-modules - url = https://github.com/flathub/shared-modules.git -[submodule "subprojects/gfm"] - path = subprojects/gfm - url = https://gitlab.gnome.org/mschraal/gfm.git diff --git a/subprojects/gfm b/subprojects/gfm deleted file mode 160000 -Subproject f53bde10101e025c83868bcbad34f7a248d0526 diff --git a/subprojects/gfm/gtkfilterlistmodel.c b/subprojects/gfm/gtkfilterlistmodel.c new file mode 100644 index 00000000..5cfd4542 --- /dev/null +++ b/subprojects/gfm/gtkfilterlistmodel.c @@ -0,0 +1,711 @@ +/* + * Copyright © 2018 Benjamin Otte + * + * 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, see <http://www.gnu.org/licenses/>. + * + * Authors: Benjamin Otte <otte@gnome.org> + */ + +// #include "config.h" + +#include "gtkfilterlistmodel.h" + +#include "gtkrbtreeprivate.h" +#include "gtkintl.h" +// #include "gtkprivate.h" + +/** + * SECTION:gtkfilterlistmodel + * @title: GtkFilterListModel + * @short_description: A list model that filters its items + * @see_also: #GListModel + * + * #GtkFilterListModel is a list model that filters a given other + * listmodel. + * It hides some elements from the other model according to + * criteria given by a #GtkFilterListModelFilterFunc. + */ + +enum { + PROP_0, + PROP_HAS_FILTER, + PROP_ITEM_TYPE, + PROP_MODEL, + NUM_PROPERTIES +}; + +typedef struct _FilterNode FilterNode; +typedef struct _FilterAugment FilterAugment; + +struct _FilterNode +{ + guint visible : 1; +}; + +struct _FilterAugment +{ + guint n_items; + guint n_visible; +}; + +struct _GtkFilterListModel +{ + GObject parent_instance; + + GType item_type; + GListModel *model; + GtkFilterListModelFilterFunc filter_func; + gpointer user_data; + GDestroyNotify user_destroy; + + GtkRbTree *items; /* NULL if filter_func == NULL */ +}; + +struct _GtkFilterListModelClass +{ + GObjectClass parent_class; +}; + +static GParamSpec *properties[NUM_PROPERTIES] = { NULL, }; + +static FilterNode * +gtk_filter_list_model_get_nth_filtered (GtkRbTree *tree, + guint position, + guint *out_unfiltered) +{ + FilterNode *node, *tmp; + guint unfiltered; + + node = gtk_rb_tree_get_root (tree); + unfiltered = 0; + + while (node) + { + tmp = gtk_rb_tree_node_get_left (node); + if (tmp) + { + FilterAugment *aug = gtk_rb_tree_get_augment (tree, tmp); + if (position < aug->n_visible) + { + node = tmp; + continue; + } + position -= aug->n_visible; + unfiltered += aug->n_items; + } + + if (node->visible) + { + if (position == 0) + break; + position--; + } + + unfiltered++; + + node = gtk_rb_tree_node_get_right (node); + } + + if (out_unfiltered) + *out_unfiltered = unfiltered; + + return node; +} + +static FilterNode * +gtk_filter_list_model_get_nth (GtkRbTree *tree, + guint position, + guint *out_filtered) +{ + FilterNode *node, *tmp; + guint filtered; + + node = gtk_rb_tree_get_root (tree); + filtered = 0; + + while (node) + { + tmp = gtk_rb_tree_node_get_left (node); + if (tmp) + { + FilterAugment *aug = gtk_rb_tree_get_augment (tree, tmp); + if (position < aug->n_items) + { + node = tmp; + continue; + } + position -= aug->n_items; + filtered += aug->n_visible; + } + + if (position == 0) + break; + + position--; + if (node->visible) + filtered++; + + node = gtk_rb_tree_node_get_right (node); + } + + if (out_filtered) + *out_filtered = filtered; + + return node; +} + +static GType +gtk_filter_list_model_get_item_type (GListModel *list) +{ + GtkFilterListModel *self = GTK_FILTER_LIST_MODEL (list); + + return self->item_type; +} + +static guint +gtk_filter_list_model_get_n_items (GListModel *list) +{ + GtkFilterListModel *self = GTK_FILTER_LIST_MODEL (list); + FilterAugment *aug; + FilterNode *node; + + if (self->model == NULL) + return 0; + + if (!self->items) + return g_list_model_get_n_items (self->model); + + node = gtk_rb_tree_get_root (self->items); + if (node == NULL) + return 0; + + aug = gtk_rb_tree_get_augment (self->items, node); + return aug->n_visible; +} + +static gpointer +gtk_filter_list_model_get_item (GListModel *list, + guint position) +{ + GtkFilterListModel *self = GTK_FILTER_LIST_MODEL (list); + guint unfiltered; + + if (self->model == NULL) + return NULL; + + if (self->items) + gtk_filter_list_model_get_nth_filtered (self->items, position, &unfiltered); + else + unfiltered = position; + + return g_list_model_get_item (self->model, unfiltered); +} + +static void +gtk_filter_list_model_model_init (GListModelInterface *iface) +{ + iface->get_item_type = gtk_filter_list_model_get_item_type; + iface->get_n_items = gtk_filter_list_model_get_n_items; + iface->get_item = gtk_filter_list_model_get_item; +} + +G_DEFINE_TYPE_WITH_CODE (GtkFilterListModel, gtk_filter_list_model, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (G_TYPE_LIST_MODEL, gtk_filter_list_model_model_init)) + +static gboolean +gtk_filter_list_model_run_filter (GtkFilterListModel *self, + guint position) +{ + gpointer item; + gboolean visible; + + item = g_list_model_get_item (self->model, position); + visible = self->filter_func (item, self->user_data); + g_object_unref (item); + + return visible; +} + +static guint +gtk_filter_list_model_add_items (GtkFilterListModel *self, + FilterNode *after, + guint position, + guint n_items) +{ + FilterNode *node; + guint i, n_visible; + + n_visible = 0; + + for (i = 0; i < n_items; i++) + { + node = gtk_rb_tree_insert_before (self->items, after); + node->visible = gtk_filter_list_model_run_filter (self, position + i); + if (node->visible) + n_visible++; + } + + return n_visible; +} + +static void +gtk_filter_list_model_items_changed_cb (GListModel *model, + guint position, + guint removed, + guint added, + GtkFilterListModel *self) +{ + FilterNode *node; + guint i, filter_position, filter_removed, filter_added; + + if (self->items == NULL) + { + g_list_model_items_changed (G_LIST_MODEL (self), position, removed, added); + return; + } + + node = gtk_filter_list_model_get_nth (self->items, position, &filter_position); + + filter_removed = 0; + for (i = 0; i < removed; i++) + { + FilterNode *next = gtk_rb_tree_node_get_next (node); + if (node->visible) + filter_removed++; + gtk_rb_tree_remove (self->items, node); + node = next; + } + + filter_added = gtk_filter_list_model_add_items (self, node, position, added); + + if (filter_removed > 0 || filter_added > 0) + g_list_model_items_changed (G_LIST_MODEL (self), filter_position, filter_removed, filter_added); +} + +static void +gtk_filter_list_model_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + GtkFilterListModel *self = GTK_FILTER_LIST_MODEL (object); + + switch (prop_id) + { + case PROP_ITEM_TYPE: + self->item_type = g_value_get_gtype (value); + break; + + case PROP_MODEL: + gtk_filter_list_model_set_model (self, g_value_get_object (value)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gtk_filter_list_model_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GtkFilterListModel *self = GTK_FILTER_LIST_MODEL (object); + + switch (prop_id) + { + case PROP_HAS_FILTER: + g_value_set_boolean (value, self->items != NULL); + break; + + case PROP_ITEM_TYPE: + g_value_set_gtype (value, self->item_type); + break; + + case PROP_MODEL: + g_value_set_object (value, self->model); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gtk_filter_list_model_clear_model (GtkFilterListModel *self) +{ + if (self->model == NULL) + return; + + g_signal_handlers_disconnect_by_func (self->model, gtk_filter_list_model_items_changed_cb, self); + g_clear_object (&self->model); + if (self->items) + gtk_rb_tree_remove_all (self->items); +} + +static void +gtk_filter_list_model_dispose (GObject *object) +{ + GtkFilterListModel *self = GTK_FILTER_LIST_MODEL (object); + + gtk_filter_list_model_clear_model (self); + if (self->user_destroy) + self->user_destroy (self->user_data); + self->filter_func = NULL; + self->user_data = NULL; + self->user_destroy = NULL; + g_clear_pointer (&self->items, gtk_rb_tree_unref); + + G_OBJECT_CLASS (gtk_filter_list_model_parent_class)->dispose (object); +} + +static void +gtk_filter_list_model_class_init (GtkFilterListModelClass *class) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (class); + + gobject_class->set_property = gtk_filter_list_model_set_property; + gobject_class->get_property = gtk_filter_list_model_get_property; + gobject_class->dispose = gtk_filter_list_model_dispose; + + /** + * GtkFilterListModel:has-filter: + * + * If a filter is set for this model + */ + properties[PROP_HAS_FILTER] = + g_param_spec_boolean ("has-filter", + P_("has filter"), + P_("If a filter is set for this model"), + FALSE, + GTK_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY); + + /** + * GtkFilterListModel:item-type: + * + * The #GType for elements of this object + */ + properties[PROP_ITEM_TYPE] = + g_param_spec_gtype ("item-type", + P_("Item type"), + P_("The type of elements of this object"), + G_TYPE_OBJECT, + GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_EXPLICIT_NOTIFY); + + /** + * GtkFilterListModel:model: + * + * The model being filtered + */ + properties[PROP_MODEL] = + g_param_spec_object ("model", + P_("Model"), + P_("The model being filtered"), + G_TYPE_LIST_MODEL, + GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_EXPLICIT_NOTIFY); + + g_object_class_install_properties (gobject_class, NUM_PROPERTIES, properties); +} + +static void +gtk_filter_list_model_init (GtkFilterListModel *self) +{ +} + + +static void +gtk_filter_list_model_augment (GtkRbTree *filter, + gpointer _aug, + gpointer _node, + gpointer left, + gpointer right) +{ + FilterNode *node = _node; + FilterAugment *aug = _aug; + + aug->n_items = 1; + aug->n_visible = node->visible ? 1 : 0; + + if (left) + { + FilterAugment *left_aug = gtk_rb_tree_get_augment (filter, left); + aug->n_items += left_aug->n_items; + aug->n_visible += left_aug->n_visible; + } + if (right) + { + FilterAugment *right_aug = gtk_rb_tree_get_augment (filter, right); + aug->n_items += right_aug->n_items; + aug->n_visible += right_aug->n_visible; + } +} + +/** + * gtk_filter_list_model_new: + * @model: the model to sort + * @filter_func: (allow-none): filter function or %NULL to not filter items + * @user_data: (closure): user data passed to @filter_func + * @user_destroy: destroy notifier for @user_data + * + * Creates a new #GtkFilterListModel that will filter @model using the given + * @filter_func. + * + * Returns: a new #GtkFilterListModel + **/ +GtkFilterListModel * +gtk_filter_list_model_new (GListModel *model, + GtkFilterListModelFilterFunc filter_func, + gpointer user_data, + GDestroyNotify user_destroy) +{ + GtkFilterListModel *result; + + g_return_val_if_fail (G_IS_LIST_MODEL (model), NULL); + + result = g_object_new (GTK_TYPE_FILTER_LIST_MODEL, + "item-type", g_list_model_get_item_type (model), + "model", model, + NULL); + + if (filter_func) + gtk_filter_list_model_set_filter_func (result, filter_func, user_data, user_destroy); + + return result; +} + +/** + * gtk_filter_list_model_new_for_type: + * @item_type: the type of the items that will be returned + * + * Creates a new empty filter list model set up to return items of type @item_type. + * It is up to the application to set a proper filter function and model to ensure + * the item type is matched. + * + * Returns: a new #GtkFilterListModel + **/ +GtkFilterListModel * +gtk_filter_list_model_new_for_type (GType item_type) +{ + g_return_val_if_fail (g_type_is_a (item_type, G_TYPE_OBJECT), NULL); + + return g_object_new (GTK_TYPE_FILTER_LIST_MODEL, + "item-type", item_type, + NULL); +} + +/** + * gtk_filter_list_model_set_filter_func: + * @self: a #GtkFilterListModel + * @filter_func: (allow-none): filter function or %NULL to not filter items + * @user_data: (closure): user data passed to @filter_func + * @user_destroy: destroy notifier for @user_data + * + * Sets the function used to filter items. The function will be called for every + * item and if it returns %TRUE the item is considered visible. + **/ +void +gtk_filter_list_model_set_filter_func (GtkFilterListModel *self, + GtkFilterListModelFilterFunc filter_func, + gpointer user_data, + GDestroyNotify user_destroy) +{ + gboolean was_filtered, will_be_filtered; + + g_return_if_fail (GTK_IS_FILTER_LIST_MODEL (self)); + g_return_if_fail (filter_func != NULL || (user_data == NULL && !user_destroy)); + + was_filtered = self->filter_func != NULL; + will_be_filtered = filter_func != NULL; + + if (!was_filtered && !will_be_filtered) + return; + + if (self->user_destroy) + self->user_destroy (self->user_data); + + self->filter_func = filter_func; + self->user_data = user_data; + self->user_destroy = user_destroy; + + if (!will_be_filtered) + { + g_clear_pointer (&self->items, gtk_rb_tree_unref); + } + else if (!was_filtered) + { + guint i, n_items; + + self->items = gtk_rb_tree_new (FilterNode, + FilterAugment, + gtk_filter_list_model_augment, + NULL, NULL); + if (self->model) + { + n_items = g_list_model_get_n_items (self->model); + for (i = 0; i < n_items; i++) + { + FilterNode *node = gtk_rb_tree_insert_before (self->items, NULL); + node->visible = TRUE; + } + } + } + + gtk_filter_list_model_refilter (self); + + if (was_filtered != will_be_filtered) + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_HAS_FILTER]); +} + +/** + * gtk_filter_list_model_set_model: + * @self: a #GtkFilterListModel + * @model: (allow-none): The model to be filtered + * + * Sets the model to be filtered. + * + * Note that GTK makes no effort to ensure that @model conforms to + * the item type of @self. It assumes that the caller knows what they + * are doing and have set up an appropriate filter function to ensure + * that item types match. + **/ +void +gtk_filter_list_model_set_model (GtkFilterListModel *self, + GListModel *model) +{ + guint removed, added; + + g_return_if_fail (GTK_IS_FILTER_LIST_MODEL (self)); + g_return_if_fail (model == NULL || G_IS_LIST_MODEL (model)); + /* Note: We don't check for matching item type here, we just assume the + * filter func takes care of filtering wrong items. */ + + if (self->model == model) + return; + + removed = g_list_model_get_n_items (G_LIST_MODEL (self)); + gtk_filter_list_model_clear_model (self); + + if (model) + { + self->model = g_object_ref (model); + g_signal_connect (model, "items-changed", G_CALLBACK (gtk_filter_list_model_items_changed_cb), self); + if (self->items) + added = gtk_filter_list_model_add_items (self, NULL, 0, g_list_model_get_n_items (model)); + else + added = g_list_model_get_n_items (model); + } + else + added = 0; + + if (removed > 0 || added > 0) + g_list_model_items_changed (G_LIST_MODEL (self), 0, removed, added); + + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_MODEL]); +} + +/** + * gtk_filter_list_model_get_model: + * @self: a #GtkFilterListModel + * + * Gets the model currently filtered or %NULL if none. + * + * Returns: (nullable) (transfer none): The model that gets filtered + **/ +GListModel * +gtk_filter_list_model_get_model (GtkFilterListModel *self) +{ + g_return_val_if_fail (GTK_IS_FILTER_LIST_MODEL (self), NULL); + + return self->model; +} + +/** + * gtk_filter_list_model_has_filter: + * @self: a #GtkFilterListModel + * + * Checks if a filter function is currently set on @self + * + * Returns: %TRUE if a filter function is set + **/ +gboolean +gtk_filter_list_model_has_filter (GtkFilterListModel *self) +{ + g_return_val_if_fail (GTK_IS_FILTER_LIST_MODEL (self), FALSE); + + return self->filter_func != NULL; +} + +/** + * gtk_filter_list_model_refilter: + * @self: a #GtkFilterListModel + * + * Causes @self to refilter all items in the model. + * + * Calling this function is necessary when data used by the filter + * function has changed. + **/ +void +gtk_filter_list_model_refilter (GtkFilterListModel *self) +{ + FilterNode *node; + guint i, first_change, last_change; + guint n_is_visible, n_was_visible; + gboolean visible; + + g_return_if_fail (GTK_IS_FILTER_LIST_MODEL (self)); + + if (self->items == NULL || self->model == NULL) + return; + + first_change = G_MAXUINT; + last_change = 0; + n_is_visible = 0; + n_was_visible = 0; + for (i = 0, node = gtk_rb_tree_get_first (self->items); + node != NULL; + i++, node = gtk_rb_tree_node_get_next (node)) + { + visible = gtk_filter_list_model_run_filter (self, i); + if (visible == node->visible) + { + if (visible) + { + n_is_visible++; + n_was_visible++; + } + continue; + } + + node->visible = visible; + gtk_rb_tree_node_mark_dirty (node); + first_change = MIN (n_is_visible, first_change); + if (visible) + n_is_visible++; + else + n_was_visible++; + last_change = MAX (n_is_visible, last_change); + } + + if (first_change <= last_change) + { + g_list_model_items_changed (G_LIST_MODEL (self), + first_change, + last_change - first_change + n_was_visible - n_is_visible, + last_change - first_change); + } +} + diff --git a/subprojects/gfm/gtkfilterlistmodel.h b/subprojects/gfm/gtkfilterlistmodel.h new file mode 100644 index 00000000..d16bd2fc --- /dev/null +++ b/subprojects/gfm/gtkfilterlistmodel.h @@ -0,0 +1,81 @@ +/* + * Copyright © 2018 Benjamin Otte + * + * 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, see <http://www.gnu.org/licenses/>. + * + * Authors: Benjamin Otte <otte@gnome.org> + */ + +#ifndef __GTK_FILTER_LIST_MODEL_H__ +#define __GTK_FILTER_LIST_MODEL_H__ + + +/* #if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION) + * #error "Only <gtk/gtk.h> can be included directly." + * #endif + */ + +#include <gio/gio.h> +#include <gtk/gtkwidget.h> + + +G_BEGIN_DECLS + +#define GTK_TYPE_FILTER_LIST_MODEL (gtk_filter_list_model_get_type ()) +#define GTK_PARAM_READABLE G_PARAM_READABLE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB +#define GTK_PARAM_READWRITE G_PARAM_READWRITE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB + +GDK_AVAILABLE_IN_ALL +G_DECLARE_FINAL_TYPE (GtkFilterListModel, gtk_filter_list_model, GTK, FILTER_LIST_MODEL, GObject) + +/** + * GtkFilterListModelFilterFunc: + * @item: (type GObject): The item that may be filtered + * @user_data: user data + * + * User function that is called to determine if the @item of the original model should be visible. + * If it should be visible, this function must return %TRUE. If the model should filter out the + * @item, %FALSE must be returned. + * + * Returns: %TRUE to keep the item around + */ +typedef gboolean (* GtkFilterListModelFilterFunc) (gpointer item, gpointer user_data); + +GDK_AVAILABLE_IN_ALL +GtkFilterListModel * gtk_filter_list_model_new (GListModel *model, + GtkFilterListModelFilterFunc filter_func, + gpointer user_data, + GDestroyNotify user_destroy); +GDK_AVAILABLE_IN_ALL +GtkFilterListModel * gtk_filter_list_model_new_for_type (GType item_type); + +GDK_AVAILABLE_IN_ALL +void gtk_filter_list_model_set_filter_func (GtkFilterListModel *self, + GtkFilterListModelFilterFunc filter_func, + gpointer user_data, + GDestroyNotify user_destroy); +GDK_AVAILABLE_IN_ALL +void gtk_filter_list_model_set_model (GtkFilterListModel *self, + GListModel *model); +GDK_AVAILABLE_IN_ALL +GListModel * gtk_filter_list_model_get_model (GtkFilterListModel *self); +GDK_AVAILABLE_IN_ALL +gboolean gtk_filter_list_model_has_filter (GtkFilterListModel *self); + +GDK_AVAILABLE_IN_ALL +void gtk_filter_list_model_refilter (GtkFilterListModel *self); + +G_END_DECLS + +#endif /* __GTK_FILTER_LIST_MODEL_H__ */ diff --git a/subprojects/gfm/gtkflattenlistmodel.c b/subprojects/gfm/gtkflattenlistmodel.c new file mode 100644 index 00000000..0027f023 --- /dev/null +++ b/subprojects/gfm/gtkflattenlistmodel.c @@ -0,0 +1,541 @@ +/* + * Copyright © 2018 Benjamin Otte + * + * 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, see <http://www.gnu.org/licenses/>. + * + * Authors: Benjamin Otte <otte@gnome.org> + */ + +// #include "config.h" + +#include "gtkflattenlistmodel.h" + +#include "gtkrbtreeprivate.h" +#include "gtkintl.h" +// #include "gtkprivate.h" + +/** + * SECTION:gtkflattenlistmodel + * @title: GtkFlattenListModel + * @short_description: A list model that flattens a list of lists + * @see_also: #GListModel + * + * #GtkFlattenListModel is a list model that takes a list model containing + * list models and flattens it into a single model. + * + * Another term for this is concatenation: #GtkFlattenListModel takes a + * list of lists and concatenates them into a single list. + */ + +enum { + PROP_0, + PROP_ITEM_TYPE, + PROP_MODEL, + NUM_PROPERTIES +}; + +typedef struct _FlattenNode FlattenNode; +typedef struct _FlattenAugment FlattenAugment; + +struct _FlattenNode +{ + GListModel *model; + GtkFlattenListModel *list; +}; + +struct _FlattenAugment +{ + guint n_items; + guint n_models; +}; + +struct _GtkFlattenListModel +{ + GObject parent_instance; + + GType item_type; + GListModel *model; + GtkRbTree *items; /* NULL if model == NULL */ +}; + +struct _GtkFlattenListModelClass +{ + GObjectClass parent_class; +}; + +static GParamSpec *properties[NUM_PROPERTIES] = { NULL, }; + +static FlattenNode * +gtk_flatten_list_model_get_nth (GtkRbTree *tree, + guint position, + guint *model_position) +{ + FlattenNode *node, *tmp; + guint model_n_items; + + node = gtk_rb_tree_get_root (tree); + + while (node) + { + tmp = gtk_rb_tree_node_get_left (node); + if (tmp) + { + FlattenAugment *aug = gtk_rb_tree_get_augment (tree, tmp); + if (position < aug->n_items) + { + node = tmp; + continue; + } + position -= aug->n_items; + } + + model_n_items = g_list_model_get_n_items (node->model); + if (position < model_n_items) + break; + position -= model_n_items; + + node = gtk_rb_tree_node_get_right (node); + } + + if (model_position) + *model_position = node ? position : 0; + + return node; +} + +static FlattenNode * +gtk_flatten_list_model_get_nth_model (GtkRbTree *tree, + guint position, + guint *items_before) +{ + FlattenNode *node, *tmp; + guint before; + + node = gtk_rb_tree_get_root (tree); + before = 0; + + while (node) + { + tmp = gtk_rb_tree_node_get_left (node); + if (tmp) + { + FlattenAugment *aug = gtk_rb_tree_get_augment (tree, tmp); + if (position < aug->n_models) + { + node = tmp; + continue; + } + position -= aug->n_models; + before += aug->n_items; + } + + if (position == 0) + break; + position--; + before += g_list_model_get_n_items (node->model); + + node = gtk_rb_tree_node_get_right (node); + } + + if (items_before) + *items_before = before; + + return node; +} + +static GType +gtk_flatten_list_model_get_item_type (GListModel *list) +{ + GtkFlattenListModel *self = GTK_FLATTEN_LIST_MODEL (list); + + return self->item_type; +} + +static guint +gtk_flatten_list_model_get_n_items (GListModel *list) +{ + GtkFlattenListModel *self = GTK_FLATTEN_LIST_MODEL (list); + FlattenAugment *aug; + FlattenNode *node; + + if (!self->items) + return 0; + + node = gtk_rb_tree_get_root (self->items); + if (node == NULL) + return 0; + + aug = gtk_rb_tree_get_augment (self->items, node); + return aug->n_items; +} + +static gpointer +gtk_flatten_list_model_get_item (GListModel *list, + guint position) +{ + GtkFlattenListModel *self = GTK_FLATTEN_LIST_MODEL (list); + FlattenNode *node; + guint model_pos; + + if (!self->items) + return NULL; + + node = gtk_flatten_list_model_get_nth (self->items, position, &model_pos); + if (node == NULL) + return NULL; + + return g_list_model_get_item (node->model, model_pos); +} + +static void +gtk_flatten_list_model_model_init (GListModelInterface *iface) +{ + iface->get_item_type = gtk_flatten_list_model_get_item_type; + iface->get_n_items = gtk_flatten_list_model_get_n_items; + iface->get_item = gtk_flatten_list_model_get_item; +} + +G_DEFINE_TYPE_WITH_CODE (GtkFlattenListModel, gtk_flatten_list_model, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (G_TYPE_LIST_MODEL, gtk_flatten_list_model_model_init)) + +static void +gtk_flatten_list_model_items_changed_cb (GListModel *model, + guint position, + guint removed, + guint added, + gpointer _node) +{ + FlattenNode *node = _node, *parent, *left; + GtkFlattenListModel *self = node->list; + guint real_position; + + gtk_rb_tree_node_mark_dirty (node); + real_position = position; + + left = gtk_rb_tree_node_get_left (node); + if (left) + { + FlattenAugment *aug = gtk_rb_tree_get_augment (self->items, left); + real_position += aug->n_items; + } + + for (; + (parent = gtk_rb_tree_node_get_parent (node)) != NULL; + node = parent) + { + left = gtk_rb_tree_node_get_left (parent); + if (left != node) + { + if (left) + { + FlattenAugment *aug = gtk_rb_tree_get_augment (self->items, left); + real_position += aug->n_items; + } + real_position += g_list_model_get_n_items (parent->model); + } + } + + g_list_model_items_changed (G_LIST_MODEL (self), real_position, removed, added); +} + +static void +gtk_flatten_list_model_clear_node (gpointer _node) +{ + FlattenNode *node= _node; + + g_signal_handlers_disconnect_by_func (node->model, gtk_flatten_list_model_items_changed_cb, node); + g_object_unref (node->model); +} + +static void +gtk_flatten_list_model_augment (GtkRbTree *flatten, + gpointer _aug, + gpointer _node, + gpointer left, + gpointer right) +{ + FlattenNode *node = _node; + FlattenAugment *aug = _aug; + + aug->n_items = g_list_model_get_n_items (node->model); + aug->n_models = 1; + + if (left) + { + FlattenAugment *left_aug = gtk_rb_tree_get_augment (flatten, left); + aug->n_items += left_aug->n_items; + aug->n_models += left_aug->n_models; + } + if (right) + { + FlattenAugment *right_aug = gtk_rb_tree_get_augment (flatten, right); + aug->n_items += right_aug->n_items; + aug->n_models += right_aug->n_models; + } +} + +static guint +gtk_flatten_list_model_add_items (GtkFlattenListModel *self, + FlattenNode *after, + guint position, + guint n) +{ + FlattenNode *node; + guint added, i; + + added = 0; + for (i = 0; i < n; i++) + { + node = gtk_rb_tree_insert_before (self->items, after); + node->model = g_list_model_get_item (self->model, position + i); + g_warn_if_fail (g_type_is_a (g_list_model_get_item_type (node->model), self->item_type)); + g_signal_connect (node->model, + "items-changed", + G_CALLBACK (gtk_flatten_list_model_items_changed_cb), + node); + node->list = self; + added +=g_list_model_get_n_items (node->model); + } + + return added; +} + +static void +gtk_flatten_list_model_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + GtkFlattenListModel *self = GTK_FLATTEN_LIST_MODEL (object); + + switch (prop_id) + { + case PROP_ITEM_TYPE: + self->item_type = g_value_get_gtype (value); + break; + + case PROP_MODEL: + gtk_flatten_list_model_set_model (self, g_value_get_object (value)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gtk_flatten_list_model_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GtkFlattenListModel *self = GTK_FLATTEN_LIST_MODEL (object); + + switch (prop_id) + { + case PROP_ITEM_TYPE: + g_value_set_gtype (value, self->item_type); + break; + + case PROP_MODEL: + g_value_set_object (value, self->model); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gtk_flatten_list_model_model_items_changed_cb (GListModel *model, + guint position, + guint removed, + guint added, + GtkFlattenListModel *self) +{ + FlattenNode *node; + guint i, real_position, real_removed, real_added; + + node = gtk_flatten_list_model_get_nth_model (self->items, position, &real_position); + + real_removed = 0; + for (i = 0; i < removed; i++) + { + FlattenNode *next = gtk_rb_tree_node_get_next (node); + real_removed += g_list_model_get_n_items (node->model); + gtk_rb_tree_remove (self->items, node); + node = next; + } + + real_added = gtk_flatten_list_model_add_items (self, node, position, added); + + if (real_removed > 0 || real_added > 0) + g_list_model_items_changed (G_LIST_MODEL (self), real_position, real_removed, real_added); +} + +static void +gtk_flatten_list_clear_model (GtkFlattenListModel *self) +{ + if (self->model) + { + g_signal_handlers_disconnect_by_func (self->model, gtk_flatten_list_model_model_items_changed_cb, self); + g_clear_object (&self->model); + g_clear_pointer (&self->items, gtk_rb_tree_unref); + } +} + +static void +gtk_flatten_list_model_dispose (GObject *object) +{ + GtkFlattenListModel *self = GTK_FLATTEN_LIST_MODEL (object); + + gtk_flatten_list_clear_model (self); + + G_OBJECT_CLASS (gtk_flatten_list_model_parent_class)->dispose (object); +} + +static void +gtk_flatten_list_model_class_init (GtkFlattenListModelClass *class) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (class); + + gobject_class->set_property = gtk_flatten_list_model_set_property; + gobject_class->get_property = gtk_flatten_list_model_get_property; + gobject_class->dispose = gtk_flatten_list_model_dispose; + + /** + * GtkFlattenListModel:item-type: + * + * The #GTpe for elements of this object + */ + properties[PROP_ITEM_TYPE] = + g_param_spec_gtype ("item-type", + P_("Item type"), + P_("The type of elements of this object"), + G_TYPE_OBJECT, + GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_EXPLICIT_NOTIFY); + + /** + * GtkFlattenListModel:model: + * + * The model being flattened + */ + properties[PROP_MODEL] = + g_param_spec_object ("model", + P_("Model"), + P_("The model being flattened"), + G_TYPE_LIST_MODEL, + GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY); + + g_object_class_install_properties (gobject_class, NUM_PROPERTIES, properties); +} + +static void +gtk_flatten_list_model_init (GtkFlattenListModel *self) +{ +} + +/** + * gtk_flatten_list_model_new: + * @item_type: The type of items in the to-be-flattened models + * @model: (nullable) (transfer none): the item to be flattened + * + * Creates a new #GtkFlattenListModel that flattens @list. The + * models returned by @model must conform to the given @item_type, + * either by having an identical type or a subtype. + * + * Returns: a new #GtkFlattenListModel + **/ +GtkFlattenListModel * +gtk_flatten_list_model_new (GType item_type, + GListModel *model) +{ + GtkFlattenListModel *result; + + g_return_val_if_fail (g_type_is_a (item_type, G_TYPE_OBJECT), NULL); + g_return_val_if_fail (model == NULL || G_IS_LIST_MODEL (model), NULL); + + result = g_object_new (GTK_TYPE_FLATTEN_LIST_MODEL, + "item-type", item_type, + "model", model, + NULL); + + return result; +} + +/** + * gtk_flatten_list_model_set_model: + * @self: a #GtkFlattenListModel + * @model: (nullable) (transfer none): the new model or %NULL + * + * Sets a new model to be flattened. The model must contain items of + * #GtkListModel that conform to the item type of @self. + **/ +void +gtk_flatten_list_model_set_model (GtkFlattenListModel *self, + GListModel *model) +{ + guint removed, added = 0; + + g_return_if_fail (GTK_IS_FLATTEN_LIST_MODEL (self)); + g_return_if_fail (model == NULL || G_IS_LIST_MODEL (model)); + if (model) + { + g_return_if_fail (g_type_is_a (g_list_model_get_item_type (model), G_TYPE_LIST_MODEL)); + } + + if (self->model == model) + return; + + removed = g_list_model_get_n_items (G_LIST_MODEL (self)); + gtk_flatten_list_clear_model (self); + + self->model = model; + + if (model) + { + g_object_ref (model); + g_signal_connect (model, "items-changed", G_CALLBACK (gtk_flatten_list_model_model_items_changed_cb), self); + self->items = gtk_rb_tree_new (FlattenNode, + FlattenAugment, + gtk_flatten_list_model_augment, + gtk_flatten_list_model_clear_node, + NULL); + + added = gtk_flatten_list_model_add_items (self, NULL, 0, g_list_model_get_n_items (model)); + } + + if (removed > 0 || added > 0) + g_list_model_items_changed (G_LIST_MODEL (self), 0, removed, added); + + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_MODEL]); +} + +/** + * gtk_flatten_list_model_get_model: + * @self: a #GtkFlattenListModel + * + * Gets the model set via gtk_flatten_list_model_set_model(). + * + * Returns: (nullable) (transfer none): The model flattened by @self + **/ +GListModel * +gtk_flatten_list_model_get_model (GtkFlattenListModel *self) +{ + g_return_val_if_fail (GTK_IS_FLATTEN_LIST_MODEL (self), NULL); + + return self->model; +} diff --git a/subprojects/gfm/gtkflattenlistmodel.h b/subprojects/gfm/gtkflattenlistmodel.h new file mode 100644 index 00000000..dec783f4 --- /dev/null +++ b/subprojects/gfm/gtkflattenlistmodel.h @@ -0,0 +1,52 @@ +/* + * Copyright © 2018 Benjamin Otte + * + * 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, see <http://www.gnu.org/licenses/>. + * + * Authors: Benjamin Otte <otte@gnome.org> + */ + +#ifndef __GTK_FLATTEN_LIST_MODEL_H__ +#define __GTK_FLATTEN_LIST_MODEL_H__ + + +/* #if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION) + * #error "Only <gtk/gtk.h> can be included directly." + * #endif + */ + +#include <gdk/gdk.h> + + +G_BEGIN_DECLS + +#define GTK_TYPE_FLATTEN_LIST_MODEL (gtk_flatten_list_model_get_type ()) +#define GTK_PARAM_READWRITE G_PARAM_READWRITE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB + +GDK_AVAILABLE_IN_ALL +G_DECLARE_FINAL_TYPE (GtkFlattenListModel, gtk_flatten_list_model, GTK, FLATTEN_LIST_MODEL, GObject) + +GDK_AVAILABLE_IN_ALL +GtkFlattenListModel * gtk_flatten_list_model_new (GType item_type, + GListModel *model); + +GDK_AVAILABLE_IN_ALL +void gtk_flatten_list_model_set_model (GtkFlattenListModel *self, + GListModel *model); +GDK_AVAILABLE_IN_ALL +GListModel * gtk_flatten_list_model_get_model (GtkFlattenListModel *self); + +G_END_DECLS + +#endif /* __GTK_FLATTEN_LIST_MODEL_H__ */ diff --git a/subprojects/gfm/gtkintl.h b/subprojects/gfm/gtkintl.h new file mode 100644 index 00000000..caeb68eb --- /dev/null +++ b/subprojects/gfm/gtkintl.h @@ -0,0 +1,15 @@ +#ifndef __GTKINTL_H__ +#define __GTKINTL_H__ + +#include <glib/gi18n-lib.h> + +#ifdef ENABLE_NLS +#define P_(String) g_dgettext(GETTEXT_PACKAGE "-properties",String) +#else +#define P_(String) (String) +#endif + +/* not really I18N-related, but also a string marker macro */ +#define I_(string) g_intern_static_string (string) + +#endif diff --git a/subprojects/gfm/gtkrbtree.c b/subprojects/gfm/gtkrbtree.c new file mode 100644 index 00000000..8d706467 --- /dev/null +++ b/subprojects/gfm/gtkrbtree.c @@ -0,0 +1,800 @@ +/* gtkrbtree.c + * Copyright (C) 2000 Red Hat, Inc., Jonathan Blandford <jrb@redhat.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + */ + +// #include "config.h" + +#include "gtkrbtreeprivate.h" + +// #include "gtkdebug.h" + +/* Define the following to print adds and removals to stdout. + * The format of the printout will be suitable for addition as a new test to + * testsuite/gtk/rbtree-crash.c + * by just grepping the printouts from the relevant rbtree. + * + * This is meant to be a trivial way to add rbtree tests to the testsuite. + */ +#undef DUMP_MODIFICATION + +typedef struct _GtkRbNode GtkRbNode; + +struct _GtkRbTree +{ + guint ref_count; + + gsize element_size; + gsize augment_size; + GtkRbTreeAugmentFunc augment_func; + GDestroyNotify clear_func; + GDestroyNotify clear_augment_func; + + GtkRbNode *root; +}; + +struct _GtkRbNode +{ + guint red :1; + guint dirty :1; + + GtkRbNode *left; + GtkRbNode *right; + /* The difference between tree and parent here is that we OR the tree with 1 and because + * pointers are always multiples of 4, we can know if we've stored a parent or the tree here */ + union { + gpointer parent_or_tree; + GtkRbNode *parent; + GtkRbTree *tree; + }; +}; + +#define NODE_FROM_POINTER(ptr) ((GtkRbNode *) ((ptr) ? (((guchar *) (ptr)) - sizeof (GtkRbNode)) : NULL)) +#define NODE_TO_POINTER(node) ((gpointer) ((node) ? (((guchar *) (node)) + sizeof (GtkRbNode)) : NULL)) +#define NODE_TO_AUG_POINTER(tree, node) ((gpointer) ((node) ? (((guchar *) (node)) + sizeof (GtkRbNode) + (tree)->element_size) : NULL)) + +static inline gboolean +is_root (GtkRbNode *node) +{ + return GPOINTER_TO_SIZE (node->parent_or_tree) & 1 ? TRUE : FALSE; +} + +static inline GtkRbNode * +parent (GtkRbNode *node) +{ + if (is_root (node)) + return NULL; + else + return node->parent; +} + +static GtkRbTree * +tree (GtkRbNode *node) +{ + while (!is_root (node)) + node = parent (node); + + return GSIZE_TO_POINTER (GPOINTER_TO_SIZE (node->tree) & ~1); +} + +static void +set_parent (GtkRbTree *tree, + GtkRbNode *node, + GtkRbNode *new_parent) +{ + + if (new_parent != NULL) + { + node->parent = new_parent; + } + else + { + node->tree = GSIZE_TO_POINTER (GPOINTER_TO_SIZE (tree) | 1); + tree->root = node; + } +} + +static inline gsize +gtk_rb_node_get_size (GtkRbTree *tree) +{ + return sizeof (GtkRbNode) + tree->element_size + tree->augment_size; +} + +static GtkRbNode * +gtk_rb_node_new (GtkRbTree *tree) +{ + GtkRbNode *result; + + result = g_slice_alloc0 (gtk_rb_node_get_size (tree)); + + result->red = TRUE; + result->dirty = TRUE; + + return result; +} + +static void +gtk_rb_node_free (GtkRbTree *tree, + GtkRbNode *node) +{ + if (tree->clear_func) + tree->clear_func (NODE_TO_POINTER (node)); + if (tree->clear_augment_func) + tree->clear_augment_func (NODE_TO_AUG_POINTER (tree, node)); + + g_slice_free1 (gtk_rb_node_get_size (tree), node); +} + +static void +gtk_rb_node_free_deep (GtkRbTree *tree, + GtkRbNode *node) +{ + GtkRbNode *right = node->right; + + if (node->left) + gtk_rb_node_free_deep (tree, node->left); + + gtk_rb_node_free (tree, node); + + if (right) + gtk_rb_node_free_deep (tree, right); +} + +static void +gtk_rb_node_mark_dirty (GtkRbNode *node, + gboolean mark_parent) +{ + if (node->dirty) + return; + + node->dirty = TRUE; + + if (mark_parent && parent (node)) + gtk_rb_node_mark_dirty (parent (node), TRUE); +} + +static void +gtk_rb_node_clean (GtkRbTree *tree, + GtkRbNode *node) +{ + if (!node->dirty) + return; + + node->dirty = FALSE; + if (tree->augment_func) + tree->augment_func (tree, + NODE_TO_AUG_POINTER (tree, node), + NODE_TO_POINTER (node), + NODE_TO_POINTER (node->left), + NODE_TO_POINTER (node->right)); +} + +static GtkRbNode * +gtk_rb_node_get_first (GtkRbNode *node) +{ + while (node->left) + node = node->left; + + return node; +} + +static GtkRbNode * +gtk_rb_node_get_last (GtkRbNode *node) +{ + while (node->right) + node = node->right; + + return node; +} + +static GtkRbNode * +gtk_rb_node_get_previous (GtkRbNode *node) +{ + GtkRbNode *p; + + if (node->left) + return gtk_rb_node_get_last (node->left); + + for (p = parent (node); p != NULL; p = parent (node)) + { + if (p->right == node) + return p; + + node = p; + } + + return NULL; +} + +static GtkRbNode * +gtk_rb_node_get_next (GtkRbNode *node) +{ + GtkRbNode *p; + + if (node->right) + return gtk_rb_node_get_first (node->right); + + for (p = parent (node); p != NULL; p = parent (node)) + { + if (p->left == node) + return p; + + node = p; + } + + return NULL; +} + +#ifdef DUMP_MODIFICATION +static guint +position (GtkRbTree *tree, + GtkRbNode *node) +{ + GtkRbNode *n; + guint i; + + i = 0; + for (n = gtk_rb_node_get_first (tree->root); + n != node; + n = gtk_rb_node_get_next (n)) + i++; + + return i; +} +#endif + +static void +gtk_rb_node_rotate_left (GtkRbTree *tree, + GtkRbNode *node) +{ + GtkRbNode *right, *p; + + right = node->right; + p = parent (node); + + node->right = right->left; + if (right->left) + set_parent (tree, right->left, node); + + set_parent (tree, right, p); + if (p) + { + if (node == p->left) + p->left = right; + else + p->right = right; + } + + right->left = node; + set_parent (tree, node, right); + + gtk_rb_node_mark_dirty (node, FALSE); + gtk_rb_node_mark_dirty (right, FALSE); +} + +static void +gtk_rb_node_rotate_right (GtkRbTree *tree, + GtkRbNode *node) +{ + GtkRbNode *left, *p; + + left = node->left; + p = parent (node); + + node->left = left->right; + if (left->right) + set_parent (tree, left->right, node); + + set_parent (tree, left, p); + if (p) + { + if (node == p->right) + p->right = left; + else + p->left = left; + } + + /* link node and left */ + left->right = node; + set_parent (tree, node, left); + + gtk_rb_node_mark_dirty (node, FALSE); + gtk_rb_node_mark_dirty (left, FALSE); +} + +static gboolean +is_red (GtkRbNode *node_or_null) +{ + if (node_or_null == NULL) + return FALSE; + else + return node_or_null->red; +} + +static inline gboolean +is_black (GtkRbNode *node_or_null) +{ + return !is_red (node_or_null); +} + +static void +set_black (GtkRbNode *node_or_null) +{ + if (node_or_null == NULL) + return; + + node_or_null->red = FALSE; +} + +static void +set_red (GtkRbNode *node_or_null) +{ + if (node_or_null == NULL) + return; + + node_or_null->red = TRUE; +} + +static void +gtk_rb_tree_insert_fixup (GtkRbTree *tree, + GtkRbNode *node) +{ + GtkRbNode *p; + + /* check Red-Black properties */ + for (p = parent (node); + p && is_red (p); + p = parent (node)) + { + GtkRbNode *pp = parent (p); + + /* we have a violation */ + g_assert (pp); + + if (p == pp->left) + { + GtkRbNode *uncle = pp->right; + + if (is_red (uncle)) + { + /* uncle is red */ + set_black (p); + set_black (uncle); + set_red (pp); + node = pp; + } + else + { + /* uncle is black */ + if (node == p->right) + { + /* make node a left child */ + node = p; + gtk_rb_node_rotate_left (tree, node); + p = parent (node); + pp = parent (p); + } + /* recolor and rotate */ + set_black (p); + set_red (pp); + gtk_rb_node_rotate_right (tree, pp); + } + } + else + { + /* mirror image of above code */ + GtkRbNode *uncle = pp->left; + + if (is_red (uncle)) + { + /* uncle is red */ + set_black (p); + set_black (uncle); + set_red (pp); + node = pp; + } + else + { + /* uncle is black */ + if (node == p->left) + { + node = p; + gtk_rb_node_rotate_right (tree, node); + p = parent (node); + pp = parent (p); + } + set_black (p); + set_red (pp); + gtk_rb_node_rotate_left (tree, pp); + } + } + } + + set_black (tree->root); +} + +static void +gtk_rb_tree_remove_node_fixup (GtkRbTree *tree, + GtkRbNode *node, + GtkRbNode *p) +{ + while (node != tree->root && is_black (node)) + { + if (node == p->left) + { + GtkRbNode *w = p->right; + + if (is_red (w)) + { + set_black (w); + set_red (p); + gtk_rb_node_rotate_left (tree, p); + w = p->right; + } + if (is_black (w->left) && is_black (w->right)) + { + set_red (w); + node = p; + } + else + { + if (is_black (w->right)) + { + set_black (w->left); + set_red (w); + gtk_rb_node_rotate_right (tree, w); + w = p->right; + } + w->red = p->red; + set_black (p); + set_black (w->right); + gtk_rb_node_rotate_left (tree, p); + node = tree->root; + } + } + else + { + GtkRbNode *w = p->left; + if (is_red (w)) + { + set_black (w); + set_red (p); + gtk_rb_node_rotate_right (tree, p); + w = p->left; + } + if (is_black (w->right) && is_black (w->left)) + { + set_red (w); + node = p; + } + else + { + if (is_black (w->left)) + { + set_black (w->right); + set_red (w); + gtk_rb_node_rotate_left (tree, w); + w = p->left; + } + w->red = p->red; + set_black (p); + set_black (w->left); + gtk_rb_node_rotate_right (tree, p); + node = tree->root; + } + } + + p = parent (node); + } + + set_black (node); +} + +GtkRbTree * +gtk_rb_tree_new_for_size (gsize element_size, + gsize augment_size, + GtkRbTreeAugmentFunc augment_func, + GDestroyNotify clear_func, + GDestroyNotify clear_augment_func) +{ + GtkRbTree *tree; + + tree = g_slice_new0 (GtkRbTree); + tree->ref_count = 1; + + tree->element_size = element_size; + tree->augment_size = augment_size; + tree->augment_func = augment_func; + tree->clear_func = clear_func; + tree->clear_augment_func = clear_augment_func; + + return tree; +} + +GtkRbTree * +gtk_rb_tree_ref (GtkRbTree *tree) +{ + tree->ref_count++; + + return tree; +} + +void +gtk_rb_tree_unref (GtkRbTree *tree) +{ + tree->ref_count--; + if (tree->ref_count > 0) + return; + + if (tree->root) + gtk_rb_node_free_deep (tree, tree->root); + + g_slice_free (GtkRbTree, tree); +} + +gpointer +gtk_rb_tree_get_first (GtkRbTree *tree) +{ + if (tree->root == NULL) + return NULL; + + return NODE_TO_POINTER (gtk_rb_node_get_first (tree->root)); +} + +gpointer +gtk_rb_tree_get_last (GtkRbTree *tree) +{ + if (tree->root == NULL) + return NULL; + + return NODE_TO_POINTER (gtk_rb_node_get_last (tree->root)); +} + +gpointer +gtk_rb_tree_node_get_previous (gpointer node) +{ + return NODE_TO_POINTER (gtk_rb_node_get_previous (NODE_FROM_POINTER (node))); +} + +gpointer +gtk_rb_tree_node_get_next (gpointer node) +{ + return NODE_TO_POINTER (gtk_rb_node_get_next (NODE_FROM_POINTER (node))); +} + +gpointer +gtk_rb_tree_get_root (GtkRbTree *tree) +{ + return NODE_TO_POINTER (tree->root); +} + +gpointer +gtk_rb_tree_node_get_parent (gpointer node) +{ + return NODE_TO_POINTER (parent (NODE_FROM_POINTER (node))); +} + +gpointer +gtk_rb_tree_node_get_left (gpointer node) +{ + return NODE_TO_POINTER (NODE_FROM_POINTER (node)->left); +} + +gpointer +gtk_rb_tree_node_get_right (gpointer node) +{ + return NODE_TO_POINTER (NODE_FROM_POINTER (node)->right); +} + +gpointer +gtk_rb_tree_get_augment (GtkRbTree *tree, + gpointer node) +{ + GtkRbNode *rbnode = NODE_FROM_POINTER (node); + + gtk_rb_node_clean (tree, rbnode); + + return NODE_TO_AUG_POINTER (tree, rbnode); +} + +GtkRbTree * +gtk_rb_tree_node_get_tree (gpointer node) +{ + return tree (NODE_FROM_POINTER (node)); +} + +void +gtk_rb_tree_node_mark_dirty (gpointer node) +{ + gtk_rb_node_mark_dirty (NODE_FROM_POINTER (node), TRUE); +} + +gpointer +gtk_rb_tree_insert_before (GtkRbTree *tree, + gpointer node) +{ + GtkRbNode *result; + + + if (tree->root == NULL) + { +#ifdef DUMP_MODIFICATION + g_print ("add (tree, 0); /* 0x%p */\n", tree); +#endif /* DUMP_MODIFICATION */ + + g_assert (node == NULL); + + result = gtk_rb_node_new (tree); + tree->root = result; + } + else if (node == NULL) + { + return gtk_rb_tree_insert_after (tree, gtk_rb_tree_get_last (tree)); + } + else + { + GtkRbNode *current = NODE_FROM_POINTER (node); + +#ifdef DUMP_MODIFICATION + g_print ("add (tree, %u); /* 0x%p */\n", position (tree, current), tree); +#endif /* DUMP_MODIFICATION */ + + /* setup new node */ + result = gtk_rb_node_new (tree); + + if (current->left) + { + current = gtk_rb_node_get_last (current->left); + current->right = result; + } + else + { + current->left = result; + } + set_parent (tree, result, current); + gtk_rb_node_mark_dirty (current, TRUE); + } + + gtk_rb_tree_insert_fixup (tree, result); + + return NODE_TO_POINTER (result); +} + +gpointer +gtk_rb_tree_insert_after (GtkRbTree *tree, + gpointer node) +{ + GtkRbNode *current, *result; + + if (node == NULL) + return gtk_rb_tree_insert_before (tree, gtk_rb_tree_get_first (tree)); + + current = NODE_FROM_POINTER (node); + +#ifdef DUMP_MODIFICATION + g_print ("add (tree, %u); /* 0x%p */\n", position (tree, current) + 1, tree); +#endif /* DUMP_MODIFICATION */ + + /* setup new node */ + result = gtk_rb_node_new (tree); + + if (current->right) + { + current = gtk_rb_node_get_first (current->right); + current->left = result; + } + else + { + current->right = result; + } + set_parent (tree, result, current); + gtk_rb_node_mark_dirty (current, TRUE); + + gtk_rb_tree_insert_fixup (tree, result); + + return NODE_TO_POINTER (result); +} + +void +gtk_rb_tree_remove (GtkRbTree *tree, + gpointer node) +{ + GtkRbNode *x, *y, *p, *real_node; + + real_node = NODE_FROM_POINTER (node); + +#ifdef DUMP_MODIFICATION + g_print ("delete (tree, %u); /* 0x%p */\n", position (tree, real_node), tree); +#endif /* DUMP_MODIFICATION */ + + y = real_node; + if (y->left && y->right) + { + y = y->right; + + while (y->left) + y = y->left; + } + + /* x is y's only child, or nil */ + if (y->left) + x = y->left; + else + x = y->right; + + /* remove y from the parent chain */ + p = parent (y); + if (x != NULL) + set_parent (tree, x, p); + if (p) + { + if (y == p->left) + p->left = x; + else + p->right = x; + gtk_rb_node_mark_dirty (p, TRUE); + } + else + { + if (x == NULL) + tree->root = NULL; + } + + /* We need to clean up the validity of the tree. + */ + if (is_black (y)) + gtk_rb_tree_remove_node_fixup (tree, x, p); + + if (y != real_node) + { + /* Move the node over */ + if (is_red (real_node) != is_red (y)) + y->red = !y->red; + + y->left = real_node->left; + if (y->left) + set_parent (tree, y->left, y); + y->right = real_node->right; + if (y->right) + set_parent (tree, y->right, y); + p = parent (real_node); + set_parent (tree, y, p); + if (p) + { + if (p->left == real_node) + p->left = y; + else + p->right = y; + gtk_rb_node_mark_dirty (p, TRUE); + } + gtk_rb_node_mark_dirty (y, TRUE); + } + + gtk_rb_node_free (tree, real_node); +} + +void +gtk_rb_tree_remove_all (GtkRbTree *tree) +{ +#ifdef DUMP_MODIFICATION + g_print ("delete_all (tree); /* 0x%p */\n", tree); +#endif /* DUMP_MODIFICATION */ + + if (tree->root) + gtk_rb_node_free_deep (tree, tree->root); + + tree->root = NULL; +} + diff --git a/subprojects/gfm/gtkrbtreeprivate.h b/subprojects/gfm/gtkrbtreeprivate.h new file mode 100644 index 00000000..45aba5cc --- /dev/null +++ b/subprojects/gfm/gtkrbtreeprivate.h @@ -0,0 +1,75 @@ +/* gtkrbtree.h + * Copyright (C) 2000 Red Hat, Inc., Jonathan Blandford <jrb@redhat.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + */ + +/* A Red-Black Tree implementation used specifically by GtkTreeView. + */ +#ifndef __GTK_RB_TREE_H__ +#define __GTK_RB_TREE_H__ + +#include <glib.h> + + +G_BEGIN_DECLS + + +typedef struct _GtkRbTree GtkRbTree; + +typedef void (* GtkRbTreeAugmentFunc) (GtkRbTree *tree, + gpointer node_augment, + gpointer node, + gpointer left, + gpointer right); + +GtkRbTree * gtk_rb_tree_new_for_size (gsize element_size, + gsize augment_size, + GtkRbTreeAugmentFunc augment_func, + GDestroyNotify clear_func, + GDestroyNotify clear_augment_func); +#define gtk_rb_tree_new(type, augment_type, augment_func, clear_func, clear_augment_func) \ + gtk_rb_tree_new_for_size (sizeof (type), sizeof (augment_type), (augment_func), (clear_func), (clear_augment_func)) + +GtkRbTree * gtk_rb_tree_ref (GtkRbTree *tree); +void gtk_rb_tree_unref (GtkRbTree *tree); + +gpointer gtk_rb_tree_get_root (GtkRbTree *tree); +gpointer gtk_rb_tree_get_first (GtkRbTree *tree); +gpointer gtk_rb_tree_get_last (GtkRbTree *tree); + +gpointer gtk_rb_tree_node_get_previous (gpointer node); +gpointer gtk_rb_tree_node_get_next (gpointer node); +gpointer gtk_rb_tree_node_get_parent (gpointer node); +gpointer gtk_rb_tree_node_get_left (gpointer node); +gpointer gtk_rb_tree_node_get_right (gpointer node); +GtkRbTree * gtk_rb_tree_node_get_tree (gpointer node); +void gtk_rb_tree_node_mark_dirty (gpointer node); + +gpointer gtk_rb_tree_get_augment (GtkRbTree *tree, + gpointer node); + +gpointer gtk_rb_tree_insert_before (GtkRbTree *tree, + gpointer node); +gpointer gtk_rb_tree_insert_after (GtkRbTree *tree, + gpointer node); +void gtk_rb_tree_remove (GtkRbTree *tree, + gpointer node); +void gtk_rb_tree_remove_all (GtkRbTree *tree); + + +G_END_DECLS + + +#endif /* __GTK_RB_TREE_H__ */ diff --git a/subprojects/gfm/gtkslicelistmodel.c b/subprojects/gfm/gtkslicelistmodel.c new file mode 100644 index 00000000..55ea970b --- /dev/null +++ b/subprojects/gfm/gtkslicelistmodel.c @@ -0,0 +1,527 @@ +/* + * Copyright © 2018 Benjamin Otte + * + * 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, see <http://www.gnu.org/licenses/>. + * + * Authors: Benjamin Otte <otte@gnome.org> + */ + +// #include "config.h" + +#include "gtkslicelistmodel.h" + +#include "gtkintl.h" +// #include "gtkprivate.h" + +/** + * SECTION:gtkslicelistmodel + * @title: GtkSliceListModel + * @short_description: A list model that presents a slice out of a larger list + * @see_also: #GListModel + * + * #GtkSliceListModel is a list model that takes a list model and presents a slice of + * that model. + * + * This is useful when implementing paging by setting the size to the number of elements + * per page and updating the offset whenever a different page is opened. + */ + +#define DEFAULT_SIZE 10 + +enum { + PROP_0, + PROP_ITEM_TYPE, + PROP_MODEL, + PROP_OFFSET, + PROP_SIZE, + NUM_PROPERTIES +}; + +struct _GtkSliceListModel +{ + GObject parent_instance; + + GType item_type; + GListModel *model; + guint offset; + guint size; + + guint n_items; +}; + +struct _GtkSliceListModelClass +{ + GObjectClass parent_class; +}; + +static GParamSpec *properties[NUM_PROPERTIES] = { NULL, }; + +static GType +gtk_slice_list_model_get_item_type (GListModel *list) +{ + GtkSliceListModel *self = GTK_SLICE_LIST_MODEL (list); + + return self->item_type; +} + +static guint +gtk_slice_list_model_get_n_items (GListModel *list) +{ + GtkSliceListModel *self = GTK_SLICE_LIST_MODEL (list); + guint n_items; + + if (self->model == NULL) + return 0; + + /* XXX: This can be done without calling g_list_model_get_n_items() on the parent model + * by checking if model.get_item(offset + size) != NULL */ + n_items = g_list_model_get_n_items (self->model); + if (n_items <= self->offset) + return 0; + + n_items -= self->offset; + return MIN (n_items, self->size); +} + +static gpointer +gtk_slice_list_model_get_item (GListModel *list, + guint position) +{ + GtkSliceListModel *self = GTK_SLICE_LIST_MODEL (list); + + if (self->model == NULL) + return NULL; + + if (position >= self->size) + return NULL; + + return g_list_model_get_item (self->model, position + self->offset); +} + +static void +gtk_slice_list_model_model_init (GListModelInterface *iface) +{ + iface->get_item_type = gtk_slice_list_model_get_item_type; + iface->get_n_items = gtk_slice_list_model_get_n_items; + iface->get_item = gtk_slice_list_model_get_item; +} + +G_DEFINE_TYPE_WITH_CODE (GtkSliceListModel, gtk_slice_list_model, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (G_TYPE_LIST_MODEL, gtk_slice_list_model_model_init)) + +static void +gtk_slice_list_model_items_changed_cb (GListModel *model, + guint position, + guint removed, + guint added, + GtkSliceListModel *self) +{ + if (position >= self->offset + self->size) + return; + + if (position < self->offset) + { + guint skip = MIN (removed, added); + skip = MIN (skip, position - self->offset); + + position += skip; + removed -= skip; + added -= skip; + } + + if (removed == added) + { + guint changed = removed; + + if (changed == 0) + return; + + g_assert (position >= self->offset); + position -= self->offset; + changed = MIN (changed, self->size) - position; + + g_list_model_items_changed (G_LIST_MODEL (self), position, changed, changed); + } + else + { + guint n_after, n_before; + guint skip; + + if (position > self->offset) + skip = position - self->offset; + else + skip = 0; + + n_after = g_list_model_get_n_items (self->model); + n_before = n_after - added + removed; + n_after = CLAMP (n_after, self->offset, self->offset + self->size) - self->offset; + n_before = CLAMP (n_before, self->offset, self->offset + self->size) - self->offset; + + g_list_model_items_changed (G_LIST_MODEL (self), skip, n_before - skip, n_after - skip); + } +} + +static void +gtk_slice_list_model_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + GtkSliceListModel *self = GTK_SLICE_LIST_MODEL (object); + + switch (prop_id) + { + case PROP_ITEM_TYPE: + self->item_type = g_value_get_gtype (value); + break; + + case PROP_MODEL: + gtk_slice_list_model_set_model (self, g_value_get_object (value)); + break; + + case PROP_OFFSET: + gtk_slice_list_model_set_offset (self, g_value_get_uint (value)); + break; + + case PROP_SIZE: + gtk_slice_list_model_set_size (self, g_value_get_uint (value)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gtk_slice_list_model_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GtkSliceListModel *self = GTK_SLICE_LIST_MODEL (object); + + switch (prop_id) + { + case PROP_ITEM_TYPE: + g_value_set_gtype (value, self->item_type); + break; + + case PROP_MODEL: + g_value_set_object (value, self->model); + break; + + case PROP_OFFSET: + g_value_set_uint (value, self->offset); + break; + + case PROP_SIZE: + g_value_set_uint (value, self->size); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gtk_slice_list_model_clear_model (GtkSliceListModel *self) +{ + if (self->model == NULL) + return; + + g_signal_handlers_disconnect_by_func (self->model, gtk_slice_list_model_items_changed_cb, self); + g_clear_object (&self->model); +} + +static void +gtk_slice_list_model_dispose (GObject *object) +{ + GtkSliceListModel *self = GTK_SLICE_LIST_MODEL (object); + + gtk_slice_list_model_clear_model (self); + + G_OBJECT_CLASS (gtk_slice_list_model_parent_class)->dispose (object); +}; + +static void +gtk_slice_list_model_class_init (GtkSliceListModelClass *class) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (class); + + gobject_class->set_property = gtk_slice_list_model_set_property; + gobject_class->get_property = gtk_slice_list_model_get_property; + gobject_class->dispose = gtk_slice_list_model_dispose; + + /** + * GtkSliceListModel:item-type: + * + * The #GType for elements of this object + */ + properties[PROP_ITEM_TYPE] = + g_param_spec_gtype ("item-type", + P_("Item type"), + P_("The type of elements of this object"), + G_TYPE_OBJECT, + GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_EXPLICIT_NOTIFY); + + /** + * GtkSliceListModel:model: + * + * Child model to take slice from + */ + properties[PROP_MODEL] = + g_param_spec_object ("model", + P_("Model"), + P_("Child model to take slice from"), + G_TYPE_LIST_MODEL, + GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY); + + /** + * GtkSliceListModel:offset: + * + * Offset of slice + */ + properties[PROP_OFFSET] = + g_param_spec_uint ("offset", + P_("Offset"), + P_("Offset of slice"), + 0, G_MAXUINT, 0, + GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY); + + /** + * GtkSliceListModel:size: + * + * Maximum size of slice + */ + properties[PROP_SIZE] = + g_param_spec_uint ("size", + P_("Size"), + P_("Maximum size of slice"), + 0, G_MAXUINT, DEFAULT_SIZE, + GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY); + + g_object_class_install_properties (gobject_class, NUM_PROPERTIES, properties); +} + +static void +gtk_slice_list_model_init (GtkSliceListModel *self) +{ + self->size = DEFAULT_SIZE; +} + +/** + * gtk_slice_list_model_new: + * @model: (transfer none): The model to use + * @offset: the offset of the slice + * @size: maximum size of the slice + * + * Creates a new slice model that presents the slice from @offset to + * @offset + @size our of the given @model. + * + * Returns: A new #GtkSliceListModel + **/ +GtkSliceListModel * +gtk_slice_list_model_new (GListModel *model, + guint offset, + guint size) +{ + g_return_val_if_fail (G_IS_LIST_MODEL (model), NULL); + + return g_object_new (GTK_TYPE_SLICE_LIST_MODEL, + "item-type", g_list_model_get_item_type (model), + "model", model, + "offset", offset, + "size", size, + NULL); +} + +/** + * gtk_slice_list_model_new_for_type: + * @item_type: the type of items + * + * Creates a new empty #GtkSliceListModel for the given @item_type that + * can be set up later. + * + * Returns: a new empty #GtkSliceListModel + **/ +GtkSliceListModel * +gtk_slice_list_model_new_for_type (GType item_type) +{ + g_return_val_if_fail (g_type_is_a (item_type, G_TYPE_OBJECT), NULL); + + return g_object_new (GTK_TYPE_SLICE_LIST_MODEL, + "item-type", item_type, + NULL); +} + +/** + * gtk_slice_list_model_set_model: + * @self: a #GtkSliceListModel + * @model: (allow-none): The model to be sliced + * + * Sets the model to show a slice of. The model's item type must conform + * to @self's item type. + * + **/ +void +gtk_slice_list_model_set_model (GtkSliceListModel *self, + GListModel *model) +{ + guint removed, added; + + g_return_if_fail (GTK_IS_SLICE_LIST_MODEL (self)); + g_return_if_fail (model == NULL || G_IS_LIST_MODEL (model)); + + if (self->model == model) + return; + + removed = g_list_model_get_n_items (G_LIST_MODEL (self)); + gtk_slice_list_model_clear_model (self); + + if (model) + { + self->model = g_object_ref (model); + g_signal_connect (model, "items-changed", G_CALLBACK (gtk_slice_list_model_items_changed_cb), self); + added = g_list_model_get_n_items (G_LIST_MODEL (self)); + } + else + { + added = 0; + } + + if (removed > 0 || added > 0) + g_list_model_items_changed (G_LIST_MODEL (self), 0, removed, added); + + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_MODEL]); +} + +/** + * gtk_slice_list_model_get_model: + * @self: a #GtkSliceListModel + * + * Gets the model that is curently being used or %NULL if none. + * + * Returns: (nullable) (transfer none): The model in use + **/ +GListModel * +gtk_slice_list_model_get_model (GtkSliceListModel *self) +{ + g_return_val_if_fail (GTK_IS_SLICE_LIST_MODEL (self), NULL); + + return self->model; +} + +/** + * gtk_slice_list_model_set_offset: + * @self: a #GtkSliceListModel + * @offset: the new offset to use + * + * Sets the offset into the original model for this slice. + * + * If the offset is too large for the sliced model, + * @self will end up empty. + **/ +void +gtk_slice_list_model_set_offset (GtkSliceListModel *self, + guint offset) +{ + guint before, after; + + g_return_if_fail (GTK_IS_SLICE_LIST_MODEL (self)); + + if (self->offset == offset) + return; + + before = g_list_model_get_n_items (G_LIST_MODEL (self)); + + self->offset = offset; + + after = g_list_model_get_n_items (G_LIST_MODEL (self)); + + if (before > 0 || after > 0) + g_list_model_items_changed (G_LIST_MODEL (self), 0, before, after); + + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_OFFSET]); +} + +/** + * gtk_slice_list_model_get_offset: + * @self: a #GtkSliceListModel + * + * Gets the offset set via gtk_slice_list_model_set_offset() + * + * Returns: The offset + **/ +guint +gtk_slice_list_model_get_offset (GtkSliceListModel *self) +{ + g_return_val_if_fail (GTK_IS_SLICE_LIST_MODEL (self), 0); + + return self->offset; +} + +/** + * gtk_slice_list_model_set_size: + * @self: a #GtkSliceListModel + * @size: the maximum size + * + * Sets the maximum size. @self will never have more items + * than @size. + * + * It can however have fewer items if the offset is too large or + * the model sliced from doesn't have enough items. + */ +void +gtk_slice_list_model_set_size (GtkSliceListModel *self, + guint size) +{ + guint before, after; + + g_return_if_fail (GTK_IS_SLICE_LIST_MODEL (self)); + + if (self->size == size) + return; + + before = g_list_model_get_n_items (G_LIST_MODEL (self)); + + self->size = size; + + after = g_list_model_get_n_items (G_LIST_MODEL (self)); + + if (before > after) + g_list_model_items_changed (G_LIST_MODEL (self), after, before - after, 0); + else if (before < after) + g_list_model_items_changed (G_LIST_MODEL (self), before, 0, after - before); + /* else nothing */ + + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SIZE]); +} + +/** + * gtk_slice_list_model_get_size: + * @self: a #GtkSliceListModel + * + * Gets the size set via gtk_slice_list_model_set_size(). + * + * Returns: The size + **/ +guint +gtk_slice_list_model_get_size (GtkSliceListModel *self) +{ + g_return_val_if_fail (GTK_IS_SLICE_LIST_MODEL (self), DEFAULT_SIZE); + + return self->size; +} diff --git a/subprojects/gfm/gtkslicelistmodel.h b/subprojects/gfm/gtkslicelistmodel.h new file mode 100644 index 00000000..25543f18 --- /dev/null +++ b/subprojects/gfm/gtkslicelistmodel.h @@ -0,0 +1,66 @@ +/* + * Copyright © 2018 Benjamin Otte + * + * 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, see <http://www.gnu.org/licenses/>. + * + * Authors: Benjamin Otte <otte@gnome.org> + */ + +#ifndef __GTK_SLICE_LIST_MODEL_H__ +#define __GTK_SLICE_LIST_MODEL_H__ + + +/* #if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION) + * #error "Only <gtk/gtk.h> can be included directly." + * #endif + */ + +#include <gio/gio.h> +#include <gtk/gtkwidget.h> + + +G_BEGIN_DECLS + +#define GTK_TYPE_SLICE_LIST_MODEL (gtk_slice_list_model_get_type ()) +#define GTK_PARAM_READWRITE G_PARAM_READWRITE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB + +GDK_AVAILABLE_IN_ALL +G_DECLARE_FINAL_TYPE (GtkSliceListModel, gtk_slice_list_model, GTK, SLICE_LIST_MODEL, GObject) + +GDK_AVAILABLE_IN_ALL +GtkSliceListModel * gtk_slice_list_model_new (GListModel *model, + guint offset, + guint size); +GDK_AVAILABLE_IN_ALL +GtkSliceListModel * gtk_slice_list_model_new_for_type (GType item_type); + +GDK_AVAILABLE_IN_ALL +void gtk_slice_list_model_set_model (GtkSliceListModel *self, + GListModel *model); +GDK_AVAILABLE_IN_ALL +GListModel * gtk_slice_list_model_get_model (GtkSliceListModel *self); +GDK_AVAILABLE_IN_ALL +void gtk_slice_list_model_set_offset (GtkSliceListModel *self, + guint offset); +GDK_AVAILABLE_IN_ALL +guint gtk_slice_list_model_get_offset (GtkSliceListModel *self); +GDK_AVAILABLE_IN_ALL +void gtk_slice_list_model_set_size (GtkSliceListModel *self, + guint size); +GDK_AVAILABLE_IN_ALL +guint gtk_slice_list_model_get_size (GtkSliceListModel *self); + +G_END_DECLS + +#endif /* __GTK_SLICE_LIST_MODEL_H__ */ diff --git a/subprojects/gfm/gtksortlistmodel.c b/subprojects/gfm/gtksortlistmodel.c new file mode 100644 index 00000000..a702feb6 --- /dev/null +++ b/subprojects/gfm/gtksortlistmodel.c @@ -0,0 +1,563 @@ +/* + * Copyright © 2018 Benjamin Otte + * + * 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, see <http://www.gnu.org/licenses/>. + * + * Authors: Benjamin Otte <otte@gnome.org> + */ + +// #include "config.h" + +#include "gtksortlistmodel.h" + +#include "gtkintl.h" +// #include "gtkprivate.h" + +/** + * SECTION:gtksortlistmodel + * @title: GtkSortListModel + * @short_description: A list model that sorts its items + * @see_also: #GListModel + * + * #GtkSortListModel is a list model that takes a list model and + * sorts its elements according to a compare function. + * + * #GtkSortListModel is a generic model and because of that it + * cannot take advantage of any external knowledge when sorting. + * If you run into performance issues with #GtkSortListModel, it + * is strongly recommended that you write your own sorting list + * model. + */ + +enum { + PROP_0, + PROP_HAS_SORT, + PROP_ITEM_TYPE, + PROP_MODEL, + NUM_PROPERTIES +}; + +struct _GtkSortListModel +{ + GObject parent_instance; + + GType item_type; + GListModel *model; + GCompareDataFunc sort_func; + gpointer user_data; + GDestroyNotify user_destroy; + + GSequence *sorted; /* NULL if sort_func == NULL */ + GSequence *unsorted; /* NULL if sort_func == NULL */ +}; + +struct _GtkSortListModelClass +{ + GObjectClass parent_class; +}; + +static GParamSpec *properties[NUM_PROPERTIES] = { NULL, }; + +static GType +gtk_sort_list_model_get_item_type (GListModel *list) +{ + GtkSortListModel *self = GTK_SORT_LIST_MODEL (list); + + return self->item_type; +} + +static guint +gtk_sort_list_model_get_n_items (GListModel *list) +{ + GtkSortListModel *self = GTK_SORT_LIST_MODEL (list); + + if (self->model == NULL) + return 0; + + if (self->sorted) + return g_sequence_get_length (self->sorted); + + return g_list_model_get_n_items (self->model); +} + +static gpointer +gtk_sort_list_model_get_item (GListModel *list, + guint position) +{ + GtkSortListModel *self = GTK_SORT_LIST_MODEL (list); + GSequenceIter *iter; + + if (self->model == NULL) + return NULL; + + if (self->unsorted == NULL) + return g_list_model_get_item (self->model, position); + + iter = g_sequence_get_iter_at_pos (self->sorted, position); + if (g_sequence_iter_is_end (iter)) + return NULL; + + return g_object_ref (g_sequence_get (iter)); +} + +static void +gtk_sort_list_model_model_init (GListModelInterface *iface) +{ + iface->get_item_type = gtk_sort_list_model_get_item_type; + iface->get_n_items = gtk_sort_list_model_get_n_items; + iface->get_item = gtk_sort_list_model_get_item; +} + +G_DEFINE_TYPE_WITH_CODE (GtkSortListModel, gtk_sort_list_model, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (G_TYPE_LIST_MODEL, gtk_sort_list_model_model_init)) + +static void +gtk_sort_list_model_remove_items (GtkSortListModel *self, + guint position, + guint n_items, + guint *unmodified_start, + guint *unmodified_end) +{ + GSequenceIter *unsorted_iter; + guint i, pos, start, end, length_before; + + start = end = length_before = g_sequence_get_length (self->sorted); + unsorted_iter = g_sequence_get_iter_at_pos (self->unsorted, position); + + for (i = 0; i < n_items ; i++) + { + GSequenceIter *sorted_iter; + GSequenceIter *next; + + next = g_sequence_iter_next (unsorted_iter); + + sorted_iter = g_sequence_get (unsorted_iter); + pos = g_sequence_iter_get_position (sorted_iter); + start = MIN (start, pos); + end = MIN (end, length_before - i - 1 - pos); + + g_sequence_remove (sorted_iter); + g_sequence_remove (unsorted_iter); + + unsorted_iter = next; + } + + *unmodified_start = start; + *unmodified_end = end; +} + +static void +gtk_sort_list_model_add_items (GtkSortListModel *self, + guint position, + guint n_items, + guint *unmodified_start, + guint *unmodified_end) +{ + GSequenceIter *unsorted_iter, *sorted_iter; + guint i, pos, start, end, length_before; + + unsorted_iter = g_sequence_get_iter_at_pos (self->unsorted, position); + start = end = length_before = g_sequence_get_length (self->sorted); + + for (i = 0; i < n_items; i++) + { + gpointer item = g_list_model_get_item (self->model, position + i); + sorted_iter = g_sequence_insert_sorted (self->sorted, item, self->sort_func, self->user_data); + g_sequence_insert_before (unsorted_iter, sorted_iter); + if (unmodified_start != NULL || unmodified_end != NULL) + { + pos = g_sequence_iter_get_position (sorted_iter); + start = MIN (start, pos); + end = MIN (end, length_before + i - pos); + } + } + + if (unmodified_start) + *unmodified_start = start; + if (unmodified_end) + *unmodified_end = end; +} + +static void +gtk_sort_list_model_items_changed_cb (GListModel *model, + guint position, + guint removed, + guint added, + GtkSortListModel *self) +{ + guint n_items, start, end, start2, end2; + + if (removed == 0 && added == 0) + return; + + if (self->sorted == NULL) + { + g_list_model_items_changed (G_LIST_MODEL (self), position, removed, added); + return; + } + + gtk_sort_list_model_remove_items (self, position, removed, &start, &end); + gtk_sort_list_model_add_items (self, position, added, &start2, &end2); + start = MIN (start, start2); + end = MIN (end, end2); + + n_items = g_sequence_get_length (self->sorted) - start - end; + g_list_model_items_changed (G_LIST_MODEL (self), start, n_items - added + removed, n_items); +} + +static void +gtk_sort_list_model_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + GtkSortListModel *self = GTK_SORT_LIST_MODEL (object); + + switch (prop_id) + { + case PROP_ITEM_TYPE: + self->item_type = g_value_get_gtype (value); + break; + + case PROP_MODEL: + gtk_sort_list_model_set_model (self, g_value_get_object (value)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gtk_sort_list_model_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GtkSortListModel *self = GTK_SORT_LIST_MODEL (object); + + switch (prop_id) + { + case PROP_HAS_SORT: + g_value_set_boolean (value, self->sort_func != NULL); + break; + + case PROP_ITEM_TYPE: + g_value_set_gtype (value, self->item_type); + break; + + case PROP_MODEL: + g_value_set_object (value, self->model); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gtk_sort_list_model_clear_model (GtkSortListModel *self) +{ + if (self->model == NULL) + return; + + g_signal_handlers_disconnect_by_func (self->model, gtk_sort_list_model_items_changed_cb, self); + g_clear_object (&self->model); + g_clear_pointer (&self->sorted, g_sequence_free); + g_clear_pointer (&self->unsorted, g_sequence_free); +} + +static void +gtk_sort_list_model_dispose (GObject *object) +{ + GtkSortListModel *self = GTK_SORT_LIST_MODEL (object); + + gtk_sort_list_model_clear_model (self); + if (self->user_destroy) + self->user_destroy (self->user_data); + self->sort_func = NULL; + self->user_data = NULL; + self->user_destroy = NULL; + + G_OBJECT_CLASS (gtk_sort_list_model_parent_class)->dispose (object); +}; + +static void +gtk_sort_list_model_class_init (GtkSortListModelClass *class) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (class); + + gobject_class->set_property = gtk_sort_list_model_set_property; + gobject_class->get_property = gtk_sort_list_model_get_property; + gobject_class->dispose = gtk_sort_list_model_dispose; + + /** + * GtkSortListModel:has-sort: + * + * If a sort function is set for this model + */ + properties[PROP_HAS_SORT] = + g_param_spec_boolean ("has-sort", + P_("has sort"), + P_("If a sort function is set for this model"), + FALSE, + GTK_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY); + + /** + * GtkSortListModel:item-type: + * + * The #GType for items of this model + */ + properties[PROP_ITEM_TYPE] = + g_param_spec_gtype ("item-type", + P_("Item type"), + P_("The type of items of this list"), + G_TYPE_OBJECT, + GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_EXPLICIT_NOTIFY); + + /** + * GtkSortListModel:model: + * + * The model being sorted + */ + properties[PROP_MODEL] = + g_param_spec_object ("model", + P_("Model"), + P_("The model being sorted"), + G_TYPE_LIST_MODEL, + GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_EXPLICIT_NOTIFY); + + g_object_class_install_properties (gobject_class, NUM_PROPERTIES, properties); +} + +static void +gtk_sort_list_model_init (GtkSortListModel *self) +{ +} + + +/** + * gtk_sort_list_model_new: + * @model: the model to sort + * @sort_func: (allow-none): sort function or %NULL to not sort items + * @user_data: user data passed to @sort_func + * @user_destroy: destroy notifier for @user_data + * + * Creates a new sort list model that uses the @sort_func to sort @model. + * + * Returns: a new #GtkSortListModel + **/ +GtkSortListModel * +gtk_sort_list_model_new (GListModel *model, + GCompareDataFunc sort_func, + gpointer user_data, + GDestroyNotify user_destroy) +{ + GtkSortListModel *result; + + g_return_val_if_fail (G_IS_LIST_MODEL (model), NULL); + + result = g_object_new (GTK_TYPE_SORT_LIST_MODEL, + "item-type", g_list_model_get_item_type (model), + "model", model, + NULL); + + if (sort_func) + gtk_sort_list_model_set_sort_func (result, sort_func, user_data, user_destroy); + + return result; +} + +/** + * gtk_sort_list_model_new_for_type: + * @item_type: the type of the items that will be returned + * + * Creates a new empty sort list model set up to return items of type @item_type. + * It is up to the application to set a proper sort function and model to ensure + * the item type is matched. + * + * Returns: a new #GtkSortListModel + **/ +GtkSortListModel * +gtk_sort_list_model_new_for_type (GType item_type) +{ + g_return_val_if_fail (g_type_is_a (item_type, G_TYPE_OBJECT), NULL); + + return g_object_new (GTK_TYPE_SORT_LIST_MODEL, + "item-type", item_type, + NULL); +} + +static void +gtk_sort_list_model_create_sequences (GtkSortListModel *self) +{ + if (!self->sort_func || self->model == NULL) + return; + + self->sorted = g_sequence_new (g_object_unref); + self->unsorted = g_sequence_new (NULL); + + gtk_sort_list_model_add_items (self, 0, g_list_model_get_n_items (self->model), NULL, NULL); +} + +/** + * gtk_sort_list_model_set_sort_func: + * @self: a #GtkSortListModel + * @sort_func: (allow-none): sort function or %NULL to not sort items + * @user_data: user data passed to @sort_func + * @user_destroy: destroy notifier for @user_data + * + * Sets the function used to sort items. The function will be called for every + * item and must return an integer less than, equal to, or greater than zero if + * for two items from the model if the first item is considered to be respectively + * less than, equal to, or greater than the second. + **/ +void +gtk_sort_list_model_set_sort_func (GtkSortListModel *self, + GCompareDataFunc sort_func, + gpointer user_data, + GDestroyNotify user_destroy) +{ + guint n_items; + + g_return_if_fail (GTK_IS_SORT_LIST_MODEL (self)); + g_return_if_fail (sort_func != NULL || (user_data == NULL && !user_destroy)); + + if (!sort_func && !self->sort_func) + return; + + if (self->user_destroy) + self->user_destroy (self->user_data); + + g_clear_pointer (&self->unsorted, g_sequence_free); + g_clear_pointer (&self->sorted, g_sequence_free); + self->sort_func = sort_func; + self->user_data = user_data; + self->user_destroy = user_destroy; + + gtk_sort_list_model_create_sequences (self); + + n_items = g_list_model_get_n_items (G_LIST_MODEL (self)); + if (n_items > 1) + g_list_model_items_changed (G_LIST_MODEL (self), 0, n_items, n_items); + + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_HAS_SORT]); +} + +/** + * gtk_sort_list_model_set_model: + * @self: a #GtkSortListModel + * @model: (allow-none): The model to be sorted + * + * Sets the model to be sorted. The @model's item type must conform to + * the item type of @self. + **/ +void +gtk_sort_list_model_set_model (GtkSortListModel *self, + GListModel *model) +{ + guint removed, added; + + g_return_if_fail (GTK_IS_SORT_LIST_MODEL (self)); + g_return_if_fail (model == NULL || G_IS_LIST_MODEL (model)); + if (model) + { + g_return_if_fail (g_type_is_a (self->item_type, g_list_model_get_item_type (model))); + } + + if (self->model == model) + return; + + removed = g_list_model_get_n_items (G_LIST_MODEL (self)); + gtk_sort_list_model_clear_model (self); + + if (model) + { + self->model = g_object_ref (model); + g_signal_connect (model, "items-changed", G_CALLBACK (gtk_sort_list_model_items_changed_cb), self); + added = g_list_model_get_n_items (model); + + gtk_sort_list_model_create_sequences (self); + } + else + added = 0; + + if (removed > 0 || added > 0) + g_list_model_items_changed (G_LIST_MODEL (self), 0, removed, added); + + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_MODEL]); +} + +/** + * gtk_sort_list_model_get_model: + * @self: a #GtkSortListModel + * + * Gets the model currently sorted or %NULL if none. + * + * Returns: (nullable) (transfer none): The model that gets sorted + **/ +GListModel * +gtk_sort_list_model_get_model (GtkSortListModel *self) +{ + g_return_val_if_fail (GTK_IS_SORT_LIST_MODEL (self), NULL); + + return self->model; +} + +/** + * gtk_sort_list_model_has_sort: + * @self: a #GtkSortListModel + * + * Checks if a sort function is currently set on @self + * + * Returns: %TRUE if a sort function is set + **/ +gboolean +gtk_sort_list_model_has_sort (GtkSortListModel *self) +{ + g_return_val_if_fail (GTK_IS_SORT_LIST_MODEL (self), FALSE); + + return self->sort_func != NULL; +} + +/** + * gtk_sort_list_model_resort: + * @self: a #GtkSortListModel + * + * Causes @self to resort all items in the model. + * + * Calling this function is necessary when data used by the sort + * function has changed. + **/ +void +gtk_sort_list_model_resort (GtkSortListModel *self) +{ + guint n_items; + + g_return_if_fail (GTK_IS_SORT_LIST_MODEL (self)); + + if (self->sorted == NULL) + return; + + n_items = g_list_model_get_n_items (self->model); + if (n_items <= 1) + return; + + g_sequence_sort (self->sorted, self->sort_func, self->user_data); + + g_list_model_items_changed (G_LIST_MODEL (self), 0, n_items, n_items); +} + diff --git a/subprojects/gfm/gtksortlistmodel.h b/subprojects/gfm/gtksortlistmodel.h new file mode 100644 index 00000000..460491b2 --- /dev/null +++ b/subprojects/gfm/gtksortlistmodel.h @@ -0,0 +1,68 @@ +/* + * Copyright © 2018 Benjamin Otte + * + * 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, see <http://www.gnu.org/licenses/>. + * + * Authors: Benjamin Otte <otte@gnome.org> + */ + +#ifndef __GTK_SORT_LIST_MODEL_H__ +#define __GTK_SORT_LIST_MODEL_H__ + + +/*#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)*/ +/*#error "Only <gtk/gtk.h> can be included directly."*/ +/*#endif*/ + +#include <gio/gio.h> +#include <gtk/gtkwidget.h> + + +G_BEGIN_DECLS + +#define GTK_TYPE_SORT_LIST_MODEL (gtk_sort_list_model_get_type ()) +#define GTK_PARAM_READABLE G_PARAM_READABLE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB +#define GTK_PARAM_WRITABLE G_PARAM_WRITABLE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB +#define GTK_PARAM_READWRITE G_PARAM_READWRITE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB + +GDK_AVAILABLE_IN_ALL +G_DECLARE_FINAL_TYPE (GtkSortListModel, gtk_sort_list_model, GTK, SORT_LIST_MODEL, GObject) + +GDK_AVAILABLE_IN_ALL +GtkSortListModel * gtk_sort_list_model_new (GListModel *model, + GCompareDataFunc sort_func, + gpointer user_data, + GDestroyNotify user_destroy); +GDK_AVAILABLE_IN_ALL +GtkSortListModel * gtk_sort_list_model_new_for_type (GType item_type); + +GDK_AVAILABLE_IN_ALL +void gtk_sort_list_model_set_sort_func (GtkSortListModel *self, + GCompareDataFunc sort_func, + gpointer user_data, + GDestroyNotify user_destroy); +GDK_AVAILABLE_IN_ALL +gboolean gtk_sort_list_model_has_sort (GtkSortListModel *self); +GDK_AVAILABLE_IN_ALL +void gtk_sort_list_model_set_model (GtkSortListModel *self, + GListModel *model); +GDK_AVAILABLE_IN_ALL +GListModel * gtk_sort_list_model_get_model (GtkSortListModel *self); + +GDK_AVAILABLE_IN_ALL +void gtk_sort_list_model_resort (GtkSortListModel *self); + +G_END_DECLS + +#endif /* __GTK_SORT_LIST_MODEL_H__ */ diff --git a/subprojects/gfm/meson.build b/subprojects/gfm/meson.build new file mode 100644 index 00000000..ab93f9cf --- /dev/null +++ b/subprojects/gfm/meson.build @@ -0,0 +1,85 @@ +project('gfm', 'c', + meson_version: '>= 0.38.0', +) + +c_args = [] +gnome = import('gnome') + +if not meson.is_subproject() + message('WARNING: This project is only intended to be used as a subproject!') +endif + +api_version = '0.1' + +gfm_sources = [ + 'gtkfilterlistmodel.c', + 'gtkflattenlistmodel.c', + 'gtkslicelistmodel.c', + 'gtksortlistmodel.c', + 'gtkrbtree.c', +] + +gfm_headers = [ + 'gtkfilterlistmodel.h', + 'gtkflattenlistmodel.h', + 'gtkslicelistmodel.h', + 'gtksortlistmodel.h', + 'gtkrbtreeprivate.h', + 'gtkintl.h', +] + +gfm_introspection_headers = [ + 'gtkfilterlistmodel.h', + 'gtkflattenlistmodel.h', + 'gtkslicelistmodel.h', + 'gtksortlistmodel.h', +] + +pkglibdir = get_option('pkglibdir') +pkgdatadir = get_option('pkgdatadir') +pkggirdir = join_paths(pkgdatadir, 'gir-1.0') +pkgtypelibdir = join_paths(pkglibdir, 'girepository-1.0') + +gfm_header_subdir = '.' +gfm_header_dir = join_paths(get_option('includedir'), gfm_header_subdir) + +cc = meson.get_compiler('c') + +gfm_deps = [ + dependency('gio-2.0', version: '>= 2.50'), + dependency('gtk+-3.0'), +] + +gfm_lib = shared_library('gfm-' + api_version, + gfm_sources, + dependencies: gfm_deps, + c_args: ['-DGETTEXT_PACKAGE', '-DGTK_COMPILATION '], + install: true, + install_dir: pkglibdir +) + +gfm_gir = gnome.generate_gir(gfm_lib, + sources: gfm_sources + gfm_introspection_headers, + nsversion: api_version, + namespace: 'Gfm', + symbol_prefix: 'gtk', + extra_args: ['-DGETTEXT_PACKAGE', '-DGTK_COMPILATION '], + identifier_prefix: 'Gtk', + link_with: gfm_lib, + includes: ['Gio-2.0', 'Gtk-3.0'], + install: true, + install_dir_gir: pkggirdir, + install_dir_typelib: pkgtypelibdir, +) + +pkg = import('pkgconfig') + +pkg.generate( + description: 'A shared library backporting a few GTK4 listmodels to GTK3', + libraries: gfm_lib, + name: 'gfm', + filebase: 'gfm-' + api_version, + version: meson.project_version(), + requires: 'glib-2.0', + install_dir: join_paths(pkglibdir, 'pkgconfig') +) diff --git a/subprojects/gfm/meson_options.txt b/subprojects/gfm/meson_options.txt new file mode 100644 index 00000000..7abaf8b9 --- /dev/null +++ b/subprojects/gfm/meson_options.txt @@ -0,0 +1,6 @@ +option('pkglibdir', type: 'string', value: '', + description: 'The private directory the shared library/typelib will be installed into.' +) +option('pkgdatadir', type: 'string', value: '', + description: 'The private directory the gir file will be installed into.' +) diff --git a/subprojects/libgd b/subprojects/libgd deleted file mode 160000 -Subproject c7c7ff4e05d3fe82854219091cf116cce6b19de diff --git a/subprojects/libgd/Makefile.am b/subprojects/libgd/Makefile.am new file mode 100644 index 00000000..5a071446 --- /dev/null +++ b/subprojects/libgd/Makefile.am @@ -0,0 +1,230 @@ +AUTOMAKE_OPTIONS=subdir-objects +NULL = +CLEANFILES = +MAINTAINERCLEANFILES = +EXTRA_DIST = +noinst_DATA = + +AM_CPPFLAGS = \ + -I$(top_srcdir) \ + -DPREFIX=\"$(prefix)\" \ + -DLIBDIR=\"$(libdir)\" \ + -DG_LOG_DOMAIN=\"libgd\" \ + -DG_DISABLE_DEPRECATED \ + $(LIBGD_CFLAGS) \ + $(NULL) + +noinst_PROGRAMS = + +if LIBGD_STATIC +noinst_LTLIBRARIES = libgd.la +else +pkglib_LTLIBRARIES = libgd.la +endif + +libgd_la_LIBADD = $(LIBGD_LIBS) $(LIBM) +libgd_la_LDFLAGS = -avoid-version +libgd_la_SOURCES = libgd/gd.h +nodist_libgd_la_SOURCES = + +catalog_sources = \ + libgd/gd-types-catalog.c \ + libgd/gd-types-catalog.h \ + $(NULL) + +nodist_libgd_la_SOURCES += $(catalog_sources) +EXTRA_DIST += $(catalog_sources) + +if LIBGD_GTK_HACKS +gtk_hacks_sources = \ + libgd/gd-icon-utils.c \ + libgd/gd-icon-utils.h \ + $(NULL) + +nodist_libgd_la_SOURCES += $(gtk_hacks_sources) +EXTRA_DIST += $(gtk_hacks_sources) +endif + +if LIBGD__BOX_COMMON +box_common_sources = \ + libgd/gd-main-box-child.c \ + libgd/gd-main-box-child.h \ + libgd/gd-main-box-generic.c \ + libgd/gd-main-box-generic.h \ + libgd/gd-main-box-item.c \ + libgd/gd-main-box-item.h \ + $(NULL) + +nodist_libgd_la_SOURCES += $(box_common_sources) +EXTRA_DIST += $(box_common_sources) +endif + +if LIBGD_MAIN_ICON_BOX +main_icon_box_sources = \ + libgd/gd-main-icon-box.c \ + libgd/gd-main-icon-box.h \ + libgd/gd-main-icon-box-child.c \ + libgd/gd-main-icon-box-child.h \ + libgd/gd-main-icon-box-icon.c \ + libgd/gd-main-icon-box-icon.h \ + $(NULL) + +nodist_libgd_la_SOURCES += $(main_icon_box_sources) +EXTRA_DIST += $(main_icon_box_sources) +endif + +if LIBGD_MAIN_BOX +main_box_sources = \ + libgd/gd-main-box.c \ + libgd/gd-main-box.h \ + $(NULL) + +nodist_libgd_la_SOURCES += $(main_box_sources) +EXTRA_DIST += $(main_box_sources) +endif + +if LIBGD__VIEW_COMMON +view_common_sources = \ + libgd/gd-main-view-generic.c \ + libgd/gd-main-view-generic.h \ + libgd/gd-styled-text-renderer.c \ + libgd/gd-styled-text-renderer.h \ + libgd/gd-two-lines-renderer.c \ + libgd/gd-two-lines-renderer.h \ + $(NULL) + +nodist_libgd_la_SOURCES += $(view_common_sources) +EXTRA_DIST += $(view_common_sources) +endif + +if LIBGD_MAIN_ICON_VIEW +main_icon_view_sources = \ + libgd/gd-main-icon-view.c \ + libgd/gd-main-icon-view.h \ + libgd/gd-toggle-pixbuf-renderer.c \ + libgd/gd-toggle-pixbuf-renderer.h \ + $(NULL) + +nodist_libgd_la_SOURCES += $(main_icon_view_sources) +EXTRA_DIST += $(main_icon_view_sources) +endif + +if LIBGD_MAIN_LIST_VIEW +main_list_view_sources = \ + libgd/gd-main-list-view.c \ + libgd/gd-main-list-view.h \ + $(NULL) + +nodist_libgd_la_SOURCES += $(main_list_view_sources) +EXTRA_DIST += $(main_list_view_sources) +endif + +if LIBGD_MAIN_VIEW +main_view_sources = \ + libgd/gd-main-view.c \ + libgd/gd-main-view.h \ + $(NULL) + +nodist_libgd_la_SOURCES += $(main_view_sources) +EXTRA_DIST += $(main_view_sources) +endif + +if LIBGD_MARGIN_CONTAINER +margin_container_sources = \ + libgd/gd-margin-container.c \ + libgd/gd-margin-container.h \ + $(NULL) + +nodist_libgd_la_SOURCES += $(margin_container_sources) +EXTRA_DIST += $(margin_container_sources) +endif + +if LIBGD_NOTIFICATION +notification_sources = \ + libgd/gd-notification.c \ + libgd/gd-notification.h \ + $(NULL) + +nodist_libgd_la_SOURCES += $(notification_sources) +EXTRA_DIST += $(notification_sources) +endif + +if LIBGD_TAGGED_ENTRY +tagged_entry_sources = \ + libgd/gd-tagged-entry.c \ + libgd/gd-tagged-entry.h \ + $(NULL) + +nodist_libgd_la_SOURCES += $(tagged_entry_sources) +EXTRA_DIST += $(tagged_entry_sources) + +noinst_PROGRAMS += \ + test-tagged-entry \ + test-tagged-entry-2 \ + $(null) + +test_tagged_entry_SOURCES = \ + test-tagged-entry.c \ + $(NULL) +test_tagged_entry_LDADD = \ + $(LIBGD_LIBS) \ + libgd.la \ + $(NULL) + +test_tagged_entry_2_SOURCES = \ + test-tagged-entry-2.c \ + $(NULL) +test_tagged_entry_2_LDADD = \ + $(LIBGD_LIBS) \ + libgd.la \ + $(NULL) +endif + +if LIBGD_GIR +include $(INTROSPECTION_MAKEFILE) +INTROSPECTION_GIRS = Gd-1.0.gir + +Gd-1.0.gir: libgd.la Makefile +Gd_1_0_gir_NAMESPACE = Gd +Gd_1_0_gir_VERSION = 1.0 +Gd_1_0_gir_LIBS = libgd.la +Gd_1_0_gir_CFLAGS = $(AM_CPPFLAGS) +Gd_1_0_gir_SCANNERFLAGS = \ + --warn-all \ + --symbol-prefix=gd \ + --identifier-prefix=Gd \ + --c-include="libgd/gd.h" \ + $(NULL) +Gd_1_0_gir_INCLUDES = $(LIBGD_GIR_INCLUDES) +Gd_1_0_gir_FILES = $(nodist_libgd_la_SOURCES) + +if LIBGD_STATIC +noinst_DATA += Gd-1.0.gir +CLEANFILES += Gd-1.0.gir +else +girdir= $(pkgdatadir)/gir-1.0 +typelibdir= $(pkglibdir)/girepository-1.0 + +gir_DATA = $(INTROSPECTION_GIRS) +typelib_DATA = $(gir_DATA:.gir=.typelib) + +CLEANFILES += $(gir_DATA) $(typelib_DATA) +endif +endif + +if LIBGD_VAPI +VAPIS = gd-1.0.vapi + +gd-1.0.vapi: Gd-1.0.gir + $(AM_V_GEN)$(VAPIGEN) \ + --library gd-1.0 \ + --pkg gtk+-3.0 \ + $< +#This 'touch' is a workaround for vapigen not touching the dest file if +#its content hasn't changed, which causes the rule to generate the .vapi +#file to always trigger + @touch $@ + +noinst_DATA += $(VAPIS) +CLEANFILES += $(VAPIS) +endif diff --git a/subprojects/libgd/README b/subprojects/libgd/README new file mode 100644 index 00000000..fb8c88d2 --- /dev/null +++ b/subprojects/libgd/README @@ -0,0 +1,123 @@ +===== +libgd +===== + +Introduction +============ + +libgd is a library used by various GNOME 3 styled applications. +However, it is not a typical library, since it doesn't guarantee +API/ABI stability, nor does it has official releases tarballs. Only +the files actually used by your project will be shipped with its +tarball. Only the necessary dependencies will be checked during +configure time and used at runtime. + +Each application can configure libgd depending on its needs and will +be able to either link dynamically (privately) or statically link with +a specific development version. + +GObject Introspection based bindings generation such as Javascript or +Vala are also supported. + +More Background +--------------- + +libgd originates from the GNOME Documents project (written by Cosimo +Cecchi), which was one of the first application to follow the novel +GNOME 3 application design. + +Since other applications have similar needs, it makes sense to try to +reuse and improve the existing work. However, the design being not +frozen, and the code being not yet matured enough and proven, it is +not possible for the developers to guarantee API and propose the +addition to the respective projects (Gtk+, or GLib for example) right +now. Sharing the code allows to experiment, discuss and test together +before proposing it upstream. + +Traditionally, this problem is solved by copying often outdated +snippets of code around (due to no API/ABI guarantee), often not +centralized (libegg). + +In the past, there used to be some common aging GNOME application +libraries above Gtk+ which have been slowly deprecated in favour of +Gtk+ (gnomeui and friends). + +All approaches have pros and cons. A configurable git submodule +has the following advantages: + +- no direct code copying necessary because API/ABI breakage (history + is preserved etc..) +- code is shared and maintained in a common project +- you can stick to a particular upstream version, or branch off your + own version easily if needed (hopefully you find your way back upstream) +- update the submodule version when your project is ready +- the libgd options should help you to configure a library to suit + your needs, taking care of some of autofoo stuff for you + +Usage +===== + +In order to use libgd, an application using autotools needs to: + +1. from the top-level project directory, add the submodule: + - git submodule add git://git.gnome.org/libgd + +2. in autogen.sh, it is recommended to add before autoreconf call: + - git submodule update --init --recursive + +3. in top-level Makefile.am: + - add -I libgd to ACLOCAL_AMFLAGS + - add libgd to SUBDIRS, before the project src directory + +4. in project configure.ac: + - add LIBGD_INIT([list-of-options]) after your project + dependencies checks + - add libgd/Makefile to AC_CONFIG_FILES + +5. from your program Makefile.am, you may now for example: + - link with $(top_builddir)/libgd/libgd.la, and include + <libgd/gd.h> (adjust your AM_CPPFLAGS as necessary) + +You may be interested to look at the commit switching GNOME Boxes from +private libgd usage to the libgd submodule: + +http://git.gnome.org/browse/gnome-boxes/commit/?id=395652458d8b311a25ecb27cc42287602a122b1f + +Note for example that the submodule url is "../libgd", which is a +better alternative for projects hosted on git.gnome.org. It will allow +the submodule update to reuse the address and the credentials given to +the toplevel project. + +LIBGD_INIT options +================== + +- gtk-hacks + +- main-icon-view + +- margin-container + +- notification + +- static + +- tagged-entry + +- vapi + +- gir + +How to modify or add an API? +============================ + + +TODO +==== + +- add translation support +- add some form of build test +- document: options, modification process +- eventually add documentation generation +- some licensing check +- more modularity (not all in libgd.m4/Makefile.am) +- CSS styling and data: shared only with gnome-themes-standard? diff --git a/subprojects/libgd/libgd.doap b/subprojects/libgd/libgd.doap new file mode 100644 index 00000000..6fd9c8ba --- /dev/null +++ b/subprojects/libgd/libgd.doap @@ -0,0 +1,35 @@ +<Project xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#" + xmlns:foaf="http://xmlns.com/foaf/0.1/" + xmlns:gnome="http://api.gnome.org/doap-extensions#" + xmlns="http://usefulinc.com/ns/doap#"> + + <name xml:lang="en">libgd</name> + <shortdesc xml:lang="en">A common GNOME 3 applications submodule</shortdesc> + <description>No long description yet</description> + +<!-- + <homepage rdf:resource="http://live.gnome.org/Libgd" /> +--> + <bug-database rdf:resource="https://gitlab.gnome.org/GNOME/libgd/issues/" /> + +<!-- + <category rdf:resource="http://api.gnome.org/doap-extensions#platform" /> +--> + + <maintainer> + <foaf:Person> + <foaf:name>Cosimo Cecchi</foaf:name> + <foaf:mbox rdf:resource="mailto:cosimoc@gnome.org" /> + <gnome:userid>cosimoc</gnome:userid> + </foaf:Person> + </maintainer> + <maintainer> + <foaf:Person> + <foaf:name>Marc-André Lureau</foaf:name> + <foaf:mbox rdf:resource="mailto:malureau@gnome.org" /> + <gnome:userid>malureau</gnome:userid> + </foaf:Person> + </maintainer> + +</Project> diff --git a/subprojects/libgd/libgd.m4 b/subprojects/libgd/libgd.m4 new file mode 100644 index 00000000..b71e3440 --- /dev/null +++ b/subprojects/libgd/libgd.m4 @@ -0,0 +1,140 @@ +dnl The option stuff below is based on the similar code from Automake + +# _LIBGD_MANGLE_OPTION(NAME) +# ------------------------- +# Convert NAME to a valid m4 identifier, by replacing invalid characters +# with underscores, and prepend the _LIBGD_OPTION_ suffix to it. +AC_DEFUN([_LIBGD_MANGLE_OPTION], +[[_LIBGD_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) + +# _LIBGD_SET_OPTION(NAME) +# ---------------------- +# Set option NAME. If NAME begins with a digit, treat it as a requested +# Guile version number, and define _LIBGD_GUILE_VERSION to that number. +# Otherwise, define the option using _LIBGD_MANGLE_OPTION. +AC_DEFUN([_LIBGD_SET_OPTION], +[m4_define(_LIBGD_MANGLE_OPTION([$1]), 1)]) + +# _LIBGD_SET_OPTIONS(OPTIONS) +# ---------------------------------- +# OPTIONS is a space-separated list of libgd options. +AC_DEFUN([_LIBGD_SET_OPTIONS], +[m4_foreach_w([_LIBGD_Option], [$1], [_LIBGD_SET_OPTION(_LIBGD_Option)])]) + +# _LIBGD_IF_OPTION_SET(NAME,IF-SET,IF-NOT-SET) +# ------------------------------------------- +# Check if option NAME is set. +AC_DEFUN([_LIBGD_IF_OPTION_SET], +[m4_ifset(_LIBGD_MANGLE_OPTION([$1]),[$2],[$3])]) + +dnl LIBGD_INIT([OPTIONS], [DIR]) +dnl ---------------------------- +dnl OPTIONS A whitespace-seperated list of options. +dnl DIR libgd submodule directory (defaults to 'libgd') +AC_DEFUN([LIBGD_INIT], [ + _LIBGD_SET_OPTIONS([$1]) + AC_SUBST([LIBGD_MODULE_DIR],[m4_if([$2],,[libgd],[$2])]) + + AC_REQUIRE([LT_INIT]) + AC_REQUIRE([AC_CHECK_LIBM]) + AC_SUBST(LIBM) + LIBGD_MODULES="gtk+-3.0 >= 3.7.10" + LIBGD_GIR_INCLUDES="Gtk-3.0" + LIBGD_SOURCES="" + + AM_CONDITIONAL([LIBGD_STATIC],[_LIBGD_IF_OPTION_SET([static],[true],[false])]) + + # main-box: + AM_CONDITIONAL([LIBGD_MAIN_BOX],[_LIBGD_IF_OPTION_SET([main-box],[true],[false])]) + _LIBGD_IF_OPTION_SET([main-box],[ + _LIBGD_SET_OPTION([main-icon-box]) + AC_DEFINE([LIBGD_MAIN_BOX], [1], [Description]) + ]) + + # main-icon-box: + AM_CONDITIONAL([LIBGD_MAIN_ICON_BOX],[_LIBGD_IF_OPTION_SET([main-icon-box],[true],[false])]) + _LIBGD_IF_OPTION_SET([main-icon-box],[ + _LIBGD_SET_OPTION([_box-common]) + _LIBGD_SET_OPTION([gtk-hacks]) + AC_DEFINE([LIBGD_MAIN_ICON_BOX], [1], [Description]) + ]) + + # main-view: + AM_CONDITIONAL([LIBGD_MAIN_VIEW],[_LIBGD_IF_OPTION_SET([main-view],[true],[false])]) + _LIBGD_IF_OPTION_SET([main-view],[ + _LIBGD_SET_OPTION([main-icon-view]) + _LIBGD_SET_OPTION([main-list-view]) + _LIBGD_SET_OPTION([gtk-hacks]) + AC_DEFINE([LIBGD_MAIN_VIEW], [1], [Description]) + ]) + + # main-icon-view: + AM_CONDITIONAL([LIBGD_MAIN_ICON_VIEW],[_LIBGD_IF_OPTION_SET([main-icon-view],[true],[false])]) + _LIBGD_IF_OPTION_SET([main-icon-view],[ + _LIBGD_SET_OPTION([_view-common]) + AC_DEFINE([LIBGD_MAIN_ICON_VIEW], [1], [Description]) + ]) + + # main-list-view: + AM_CONDITIONAL([LIBGD_MAIN_LIST_VIEW],[_LIBGD_IF_OPTION_SET([main-list-view],[true],[false])]) + _LIBGD_IF_OPTION_SET([main-list-view],[ + _LIBGD_SET_OPTION([_view-common]) + AC_DEFINE([LIBGD_MAIN_LIST_VIEW], [1], [Description]) + ]) + + # margin-container: + AM_CONDITIONAL([LIBGD_MARGIN_CONTAINER],[_LIBGD_IF_OPTION_SET([margin-container],[true],[false])]) + _LIBGD_IF_OPTION_SET([margin-container],[ + AC_DEFINE([LIBGD_MARGIN_CONTAINER], [1], [Description]) + ]) + + # notification: + AM_CONDITIONAL([LIBGD_NOTIFICATION],[_LIBGD_IF_OPTION_SET([notification],[true],[false])]) + _LIBGD_IF_OPTION_SET([notification],[ + AC_DEFINE([LIBGD_NOTIFICATION], [1], [Description]) + ]) + + # tagged-entry: Gtk+ widget + AM_CONDITIONAL([LIBGD_TAGGED_ENTRY],[_LIBGD_IF_OPTION_SET([tagged-entry],[true],[false])]) + _LIBGD_IF_OPTION_SET([tagged-entry],[ + AC_DEFINE([LIBGD_TAGGED_ENTRY], [1], [Description]) + ]) + + # vapi: vala bindings support + AM_CONDITIONAL([LIBGD_VAPI],[ _LIBGD_IF_OPTION_SET([vapi],[true],[false])]) + _LIBGD_IF_OPTION_SET([vapi],[ + _LIBGD_SET_OPTION([gir]) + dnl check for vapigen + AC_PATH_PROG(VAPIGEN, vapigen, no) + AS_IF([test x$VAPIGEN = "xno"], + [AC_MSG_ERROR([Cannot find the "vapigen compiler in your PATH])]) + ]) + + # gir: gobject introspection support + AM_CONDITIONAL([LIBGD_GIR],[ _LIBGD_IF_OPTION_SET([gir],[true],[false])]) + _LIBGD_IF_OPTION_SET([gir],[ + GOBJECT_INTROSPECTION_REQUIRE([0.9.6]) + ]) + + # gtk-hacks: collection of Gtk+ hacks and workarounds + AM_CONDITIONAL([LIBGD_GTK_HACKS],[_LIBGD_IF_OPTION_SET([gtk-hacks],[true],[false])]) + _LIBGD_IF_OPTION_SET([gtk-hacks],[ + AC_DEFINE([LIBGD_GTK_HACKS], [1], [Description]) + ]) + + # _box-common: + AM_CONDITIONAL([LIBGD__BOX_COMMON],[_LIBGD_IF_OPTION_SET([_box-common],[true],[false])]) + _LIBGD_IF_OPTION_SET([_box-common],[ + AC_DEFINE([LIBGD__BOX_COMMON], [1], [Description]) + ]) + + # _view-common: + AM_CONDITIONAL([LIBGD__VIEW_COMMON],[_LIBGD_IF_OPTION_SET([_view-common],[true],[false])]) + _LIBGD_IF_OPTION_SET([_view-common],[ + AC_DEFINE([LIBGD__VIEW_COMMON], [1], [Description]) + ]) + + PKG_CHECK_MODULES(LIBGD, [ $LIBGD_MODULES ]) + AC_SUBST(LIBGD_GIR_INCLUDES) + AC_SUBST(LIBGD_SOURCES) +]) diff --git a/subprojects/libgd/libgd/gd-icon-utils.c b/subprojects/libgd/libgd/gd-icon-utils.c new file mode 100644 index 00000000..6c9dd401 --- /dev/null +++ b/subprojects/libgd/libgd/gd-icon-utils.c @@ -0,0 +1,394 @@ +/* + * Copyright (c) 2011, 2012, 2015, 2016 Red Hat, Inc. + * + * Gnome Documents 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 2 of the License, or (at your + * option) any later version. + * + * Gnome Documents 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 Gnome Documents; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Author: Cosimo Cecchi <cosimoc@redhat.com> + * + */ + +#include "gd-icon-utils.h" + +#include <gdk-pixbuf/gdk-pixbuf.h> +#include <string.h> +#include <math.h> + +#define _BG_MIN_SIZE 20 +#define _EMBLEM_MIN_SIZE 8 + +/** + * gd_copy_image_surface: + * @surface: + * + * Returns: (transfer full): + */ +cairo_surface_t * +gd_copy_image_surface (cairo_surface_t *surface) +{ + cairo_surface_t *copy = NULL; + cairo_t *cr; + gdouble scale_x; + gdouble scale_y; + + copy = cairo_surface_create_similar_image (surface, CAIRO_FORMAT_ARGB32, + cairo_image_surface_get_width (surface), + cairo_image_surface_get_height (surface)); + cairo_surface_get_device_scale (surface, &scale_x, &scale_y); + cairo_surface_set_device_scale (copy, scale_x, scale_y); + + cr = cairo_create (copy); + cairo_set_source_surface (cr, surface, 0, 0); + cairo_paint (cr); + cairo_destroy (cr); + + return copy; +} + +/** + * gd_create_surface_with_counter: + * @widget: + * @base: + * @number: + * + * Returns: (transfer full): + */ +cairo_surface_t * +gd_create_surface_with_counter (GtkWidget *widget, cairo_surface_t *base, gint number) +{ + GtkStyleContext *context; + cairo_t *cr, *emblem_cr; + cairo_surface_t *emblem_surface; + cairo_surface_t *surface; + gint height; + gint height_scaled; + gint width; + gint width_scaled; + gint layout_width, layout_height; + gint emblem_size; + gint emblem_size_scaled; + gdouble scale; + gdouble scale_x; + gdouble scale_y; + gchar *str; + PangoLayout *layout; + PangoAttrList *attr_list; + PangoAttribute *attr; + PangoFontDescription *desc; + GdkRGBA color; + + context = gtk_widget_get_style_context (GTK_WIDGET (widget)); + gtk_style_context_save (context); + gtk_style_context_add_class (context, "documents-counter"); + + width_scaled = cairo_image_surface_get_width (base); + height_scaled = cairo_image_surface_get_height (base); + cairo_surface_get_device_scale (base, &scale_x, &scale_y); + + width = width_scaled / (gint) floor (scale_x), + height = height_scaled / (gint) floor (scale_y); + + surface = cairo_surface_create_similar_image (base, CAIRO_FORMAT_ARGB32, + width_scaled, height_scaled); + cairo_surface_set_device_scale (surface, scale_x, scale_y); + + cr = cairo_create (surface); + cairo_set_source_surface (cr, base, 0, 0); + cairo_paint (cr); + + emblem_size_scaled = MIN (width_scaled / 2, height_scaled / 2); + emblem_size = MIN (width / 2, height / 2); + + emblem_surface = cairo_surface_create_similar_image (base, CAIRO_FORMAT_ARGB32, + emblem_size_scaled, emblem_size_scaled); + cairo_surface_set_device_scale (emblem_surface, scale_x, scale_y); + + emblem_cr = cairo_create (emblem_surface); + gtk_render_background (context, emblem_cr, + 0, 0, emblem_size, emblem_size); + + if (number > 99) + number = 99; + if (number < -99) + number = -99; + + str = g_strdup_printf ("%d", number); + layout = gtk_widget_create_pango_layout (GTK_WIDGET (widget), str); + g_free (str); + + pango_layout_get_pixel_size (layout, &layout_width, &layout_height); + + /* scale the layout to be 0.5 of the size still available for drawing */ + scale = (emblem_size * 0.50) / (MAX (layout_width, layout_height)); + attr_list = pango_attr_list_new (); + + attr = pango_attr_scale_new (scale); + pango_attr_list_insert (attr_list, attr); + pango_layout_set_attributes (layout, attr_list); + + gtk_style_context_get (context, GTK_STATE_FLAG_NORMAL, "font", &desc, NULL); + pango_layout_set_font_description (layout, desc); + pango_font_description_free (desc); + + gtk_style_context_get_color (context, 0, &color); + gdk_cairo_set_source_rgba (emblem_cr, &color); + + /* update these values */ + pango_layout_get_pixel_size (layout, &layout_width, &layout_height); + + cairo_move_to (emblem_cr, + emblem_size / 2 - layout_width / 2, + emblem_size / 2 - layout_height / 2); + + pango_cairo_show_layout (emblem_cr, layout); + + g_object_unref (layout); + pango_attr_list_unref (attr_list); + cairo_destroy (emblem_cr); + + cairo_set_source_surface (cr, emblem_surface, + width - emblem_size, height - emblem_size); + cairo_paint (cr); + cairo_destroy (cr); + + cairo_surface_destroy (emblem_surface); + gtk_style_context_restore (context); + + return surface; +} + +/** + * gd_create_symbolic_icon_for_scale: + * @name: + * @base_size: + * @scale: + * + * Returns: (transfer full): + */ +GIcon * +gd_create_symbolic_icon_for_scale (const gchar *name, + gint base_size, + gint scale) +{ + gchar *symbolic_name; + GIcon *icon, *retval = NULL; + cairo_surface_t *icon_surface; + cairo_surface_t *surface; + cairo_t *cr; + GtkStyleContext *style; + GtkWidgetPath *path; + GdkPixbuf *pixbuf; + GtkIconTheme *theme; + GtkIconInfo *info; + gint bg_size; + gint emblem_size; + gint total_size; + gint total_size_scaled; + + total_size = base_size / 2; + total_size_scaled = total_size * scale; + + bg_size = MAX (total_size / 2, _BG_MIN_SIZE); + emblem_size = MAX (bg_size - 8, _EMBLEM_MIN_SIZE); + + surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, total_size_scaled, total_size_scaled); + cairo_surface_set_device_scale (surface, (gdouble) scale, (gdouble) scale); + cr = cairo_create (surface); + + style = gtk_style_context_new (); + + path = gtk_widget_path_new (); + gtk_widget_path_append_type (path, GTK_TYPE_ICON_VIEW); + gtk_style_context_set_path (style, path); + gtk_widget_path_unref (path); + + gtk_style_context_add_class (style, "documents-icon-bg"); + + gtk_render_background (style, cr, (total_size - bg_size) / 2, (total_size - bg_size) / 2, bg_size, bg_size); + + symbolic_name = g_strconcat (name, "-symbolic", NULL); + icon = g_themed_icon_new_with_default_fallbacks (symbolic_name); + g_free (symbolic_name); + + theme = gtk_icon_theme_get_default(); + info = gtk_icon_theme_lookup_by_gicon_for_scale (theme, icon, emblem_size, scale, + GTK_ICON_LOOKUP_FORCE_SIZE); + g_object_unref (icon); + + if (info == NULL) + goto out; + + pixbuf = gtk_icon_info_load_symbolic_for_context (info, style, NULL, NULL); + g_object_unref (info); + + if (pixbuf == NULL) + goto out; + + icon_surface = gdk_cairo_surface_create_from_pixbuf (pixbuf, scale, NULL); + g_object_unref (pixbuf); + + gtk_render_icon_surface (style, cr, icon_surface, (total_size - emblem_size) / 2, (total_size - emblem_size) / 2); + cairo_surface_destroy (icon_surface); + + retval = G_ICON (gdk_pixbuf_get_from_surface (surface, 0, 0, total_size_scaled, total_size_scaled)); + + out: + g_object_unref (style); + cairo_surface_destroy (surface); + cairo_destroy (cr); + + return retval; +} + +/** + * gd_create_symbolic_icon: + * @name: + * @base_size: + * + * Returns: (transfer full): + */ +GIcon * +gd_create_symbolic_icon (const gchar *name, + gint base_size) +{ + return gd_create_symbolic_icon_for_scale (name, base_size, 1); +} + +/** + * gd_embed_surface_in_frame: + * @source_image: + * @frame_image_url: + * @slice_width: + * @border_width: + * + * Returns: (transfer full): + */ +cairo_surface_t * +gd_embed_surface_in_frame (cairo_surface_t *source_image, + const gchar *frame_image_url, + GtkBorder *slice_width, + GtkBorder *border_width) +{ + cairo_surface_t *surface; + cairo_t *cr; + int source_width, source_height; + gchar *css_str; + GtkCssProvider *provider; + GtkStyleContext *context; + GError *error = NULL; + GtkWidgetPath *path; + gdouble scale_x, scale_y; + + cairo_surface_get_device_scale (source_image, &scale_x, &scale_y); + + source_width = cairo_image_surface_get_width (source_image) / (gint) floor (scale_x), + source_height = cairo_image_surface_get_height (source_image) / (gint) floor (scale_y); + + css_str = g_strdup_printf (".embedded-image { border-image: url(\"%s\") %d %d %d %d / %dpx %dpx %dpx %dpx }", + frame_image_url, + slice_width->top, slice_width->right, slice_width->bottom, slice_width->left, + border_width->top, border_width->right, border_width->bottom, border_width->left); + provider = gtk_css_provider_new (); + gtk_css_provider_load_from_data (provider, css_str, -1, &error); + + if (error != NULL) + { + g_warning ("Unable to create the thumbnail frame image: %s", error->message); + g_error_free (error); + g_free (css_str); + + return g_object_ref (source_image); + } + + surface = cairo_surface_create_similar (source_image, + CAIRO_CONTENT_COLOR_ALPHA, + source_width, source_height); + cr = cairo_create (surface); + + context = gtk_style_context_new (); + path = gtk_widget_path_new (); + gtk_widget_path_append_type (path, GTK_TYPE_ICON_VIEW); + + gtk_style_context_set_path (context, path); + gtk_style_context_add_provider (context, + GTK_STYLE_PROVIDER (provider), + GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); + + cairo_save (cr); + cairo_rectangle (cr, + border_width->left, + border_width->top, + source_width - border_width->left - border_width->right, + source_height - border_width->top - border_width->bottom); + cairo_clip (cr); + gtk_render_icon_surface (context, cr, + source_image, + 0, 0); + cairo_restore (cr); + + gtk_style_context_save (context); + gtk_style_context_add_class (context, "embedded-image"); + + gtk_render_frame (context, cr, + 0, 0, + source_width, source_height); + + gtk_style_context_restore (context); + cairo_destroy (cr); + + gtk_widget_path_unref (path); + g_object_unref (provider); + g_object_unref (context); + g_free (css_str); + + return surface; +} + +/** + * gd_embed_image_in_frame: + * @source_image: + * @frame_image_url: + * @slice_width: + * @border_width: + * + * Returns: (transfer full): + */ +GdkPixbuf * +gd_embed_image_in_frame (GdkPixbuf *source_image, + const gchar *frame_image_url, + GtkBorder *slice_width, + GtkBorder *border_width) +{ + cairo_surface_t *surface, *embedded_surface; + GdkPixbuf *retval; + + surface = gdk_cairo_surface_create_from_pixbuf (source_image, + 0, NULL); + + /* Force the device scale to 1.0, since pixbufs are always in unscaled + * dimensions. + */ + cairo_surface_set_device_scale (surface, 1.0, 1.0); + embedded_surface = gd_embed_surface_in_frame (surface, frame_image_url, + slice_width, border_width); + retval = gdk_pixbuf_get_from_surface (embedded_surface, + 0, 0, + cairo_image_surface_get_width (embedded_surface), + cairo_image_surface_get_height (embedded_surface)); + + cairo_surface_destroy (embedded_surface); + cairo_surface_destroy (surface); + + return retval; +} diff --git a/subprojects/libgd/libgd/gd-icon-utils.h b/subprojects/libgd/libgd/gd-icon-utils.h new file mode 100644 index 00000000..12f4f068 --- /dev/null +++ b/subprojects/libgd/libgd/gd-icon-utils.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2011, 2012, 2015, 2016 Red Hat, Inc. + * + * Gnome Documents 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 2 of the License, or (at your + * option) any later version. + * + * Gnome Documents 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 Gnome Documents; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Author: Cosimo Cecchi <cosimoc@redhat.com> + * + */ + +#ifndef __GD_CREATE_SYMBOLIC_ICON_H__ +#define __GD_CREATE_SYMBOLIC_ICON_H__ + +#include <cairo.h> +#include <gtk/gtk.h> + +cairo_surface_t *gd_copy_image_surface (cairo_surface_t *surface); + +cairo_surface_t *gd_create_surface_with_counter (GtkWidget *widget, + cairo_surface_t *base, + gint number); + +GIcon *gd_create_symbolic_icon (const gchar *name, + gint base_size); +GIcon *gd_create_symbolic_icon_for_scale (const gchar *name, + gint base_size, + gint scale); + +GdkPixbuf *gd_embed_image_in_frame (GdkPixbuf *source_image, + const gchar *frame_image_url, + GtkBorder *slice_width, + GtkBorder *border_width); +cairo_surface_t *gd_embed_surface_in_frame (cairo_surface_t *source_image, + const gchar *frame_image_url, + GtkBorder *slice_width, + GtkBorder *border_width); + +#endif /* __GD_CREATE_SYMBOLIC_ICON_H__ */ diff --git a/subprojects/libgd/libgd/gd-main-box-child.c b/subprojects/libgd/libgd/gd-main-box-child.c new file mode 100644 index 00000000..9a1118d2 --- /dev/null +++ b/subprojects/libgd/libgd/gd-main-box-child.c @@ -0,0 +1,186 @@ +/* + * Copyright (c) 2016, 2017 Red Hat, Inc. + * + * This program 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 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 Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Author: Debarshi Ray <debarshir@gnome.org> + * + */ + +#include "gd-main-box-child.h" + +G_DEFINE_INTERFACE (GdMainBoxChild, gd_main_box_child, GTK_TYPE_WIDGET) + +static void +gd_main_box_child_default_init (GdMainBoxChildInterface *iface) +{ + GParamSpec *pspec; + + /** + * GdMainBoxChild:item: + * + * A #GdMainBoxItem that is rendered by the #GdMainBoxChild widget. + */ + pspec = g_param_spec_object ("item", + "Item", + "An item that is rendered by the widget", + GD_TYPE_MAIN_BOX_ITEM, + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_EXPLICIT_NOTIFY | + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS); + g_object_interface_install_property (iface, pspec); + + /** + * GdMainBoxChild:selection-mode: + * + * Whether the #GdMainBoxChild widget is in selection mode. + */ + pspec = g_param_spec_boolean ("selection-mode", + "Selection mode", + "Whether the child is in selection mode", + FALSE, + G_PARAM_CONSTRUCT | + G_PARAM_EXPLICIT_NOTIFY | + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS); + g_object_interface_install_property (iface, pspec); + + /** + * GdMainBoxChild:show-primary-text: + * + * Whether the #GdMainBoxChild widget is going to show the + * primary-text of its item. + */ + pspec = g_param_spec_boolean ("show-primary-text", + "Show Primary Text", + "Whether the item's primary-text is going to be shown", + FALSE, + G_PARAM_EXPLICIT_NOTIFY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + g_object_interface_install_property (iface, pspec); + + /** + * GdMainBoxChild:show-secondary-text: + * + * Whether the #GdMainBoxChild widget is going to show the + * secondary-text of its item. + */ + pspec = g_param_spec_boolean ("show-secondary-text", + "Show Secondary Text", + "Whether the item's secondary-text is going to be shown", + FALSE, + G_PARAM_EXPLICIT_NOTIFY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + g_object_interface_install_property (iface, pspec); +} + +/** + * gd_main_box_child_get_item: + * @self: + * + * Returns: (transfer none): The #GdMainBoxItem + */ +GdMainBoxItem * +gd_main_box_child_get_item (GdMainBoxChild *self) +{ + GdMainBoxChildInterface *iface; + + g_return_val_if_fail (GD_IS_MAIN_BOX_CHILD (self), NULL); + + iface = GD_MAIN_BOX_CHILD_GET_IFACE (self); + + return (* iface->get_item) (self); +} + +/** + * gd_main_box_child_get_index: + * @self: + * + * Returns: (transfer none): The index + */ +gint +gd_main_box_child_get_index (GdMainBoxChild *self) +{ + GdMainBoxChildInterface *iface; + + g_return_val_if_fail (GD_IS_MAIN_BOX_CHILD (self), -1); + + iface = GD_MAIN_BOX_CHILD_GET_IFACE (self); + + return (* iface->get_index) (self); +} + +/** + * gd_main_box_child_get_selected: + * @self: + * + * Returns: (transfer none): Whether @self is selected + */ +gboolean +gd_main_box_child_get_selected (GdMainBoxChild *self) +{ + GdMainBoxChildInterface *iface; + + g_return_val_if_fail (GD_IS_MAIN_BOX_CHILD (self), FALSE); + + iface = GD_MAIN_BOX_CHILD_GET_IFACE (self); + + return (* iface->get_selected) (self); +} + +/** + * gd_main_box_child_get_selection_mode: + * @self: + * + * Returns: (transfer none): Whether @self is in selection mode + */ +gboolean +gd_main_box_child_get_selection_mode (GdMainBoxChild *self) +{ + gboolean selection_mode; + + g_return_val_if_fail (GD_IS_MAIN_BOX_CHILD (self), FALSE); + + g_object_get (self, "selection-mode", &selection_mode, NULL); + return selection_mode; +} + +/** + * gd_main_box_child_set_selected: + * @self: + * @selected: + */ +void +gd_main_box_child_set_selected (GdMainBoxChild *self, gboolean selected) +{ + GdMainBoxChildInterface *iface; + + g_return_if_fail (GD_IS_MAIN_BOX_CHILD (self)); + + iface = GD_MAIN_BOX_CHILD_GET_IFACE (self); + + return (* iface->set_selected) (self, selected); +} + +/** + * gd_main_box_child_set_selection_mode: + * @self: + * @selection_mode: + */ +void +gd_main_box_child_set_selection_mode (GdMainBoxChild *self, gboolean selection_mode) +{ + g_return_if_fail (GD_IS_MAIN_BOX_CHILD (self)); + g_object_set (self, "selection-mode", selection_mode, NULL); +} diff --git a/subprojects/libgd/libgd/gd-main-box-child.h b/subprojects/libgd/libgd/gd-main-box-child.h new file mode 100644 index 00000000..b2600a61 --- /dev/null +++ b/subprojects/libgd/libgd/gd-main-box-child.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2016 Red Hat, Inc. + * + * This program 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 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 Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Author: Debarshi Ray <debarshir@gnome.org> + * + */ + +#ifndef __GD_MAIN_BOX_CHILD_H__ +#define __GD_MAIN_BOX_CHILD_H__ + +#include <gtk/gtk.h> + +#include "gd-main-box-item.h" + +G_BEGIN_DECLS + +#define GD_TYPE_MAIN_BOX_CHILD gd_main_box_child_get_type() +G_DECLARE_INTERFACE (GdMainBoxChild, gd_main_box_child, GD, MAIN_BOX_CHILD, GtkWidget) + +struct _GdMainBoxChildInterface +{ + GTypeInterface base_iface; + + /* vtable */ + gint (* get_index) (GdMainBoxChild *self); + GdMainBoxItem * (* get_item) (GdMainBoxChild *self); + gboolean (* get_selected) (GdMainBoxChild *self); + void (* set_selected) (GdMainBoxChild *self, gboolean selected); +}; + +gint gd_main_box_child_get_index (GdMainBoxChild *self); +GdMainBoxItem * gd_main_box_child_get_item (GdMainBoxChild *self); +gboolean gd_main_box_child_get_selected (GdMainBoxChild *self); +gboolean gd_main_box_child_get_selection_mode (GdMainBoxChild *self); +void gd_main_box_child_set_selected (GdMainBoxChild *self, gboolean selected); +void gd_main_box_child_set_selection_mode (GdMainBoxChild *self, gboolean selection_mode); + +G_END_DECLS + +#endif /* __GD_MAIN_BOX_CHILD_H__ */ diff --git a/subprojects/libgd/libgd/gd-main-box-generic.c b/subprojects/libgd/libgd/gd-main-box-generic.c new file mode 100644 index 00000000..0d187643 --- /dev/null +++ b/subprojects/libgd/libgd/gd-main-box-generic.c @@ -0,0 +1,491 @@ +/* + * Copyright (c) 2016, 2017 Red Hat, Inc. + * + * This program 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 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 Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Author: Debarshi Ray <debarshir@gnome.org> + * + */ + +#include "gd-main-box-generic.h" +#include "gd-main-box-item.h" + +enum +{ + ITEM_ACTIVATED, + SELECTION_CHANGED, + SELECTION_MODE_REQUEST, + NUM_SIGNALS +}; + +static guint signals[NUM_SIGNALS] = { 0, }; + +G_DEFINE_INTERFACE (GdMainBoxGeneric, gd_main_box_generic, GTK_TYPE_WIDGET) + +static void +gd_main_box_generic_mark_range_as_selected (GdMainBoxGeneric *self, gint first_element, gint last_element) +{ + gint i; + + if (first_element > last_element) + { + gint tmp; + + tmp = first_element; + first_element = last_element; + last_element = tmp; + } + + for (i = first_element; i <= last_element; i++) + { + GdMainBoxChild *child; + + child = gd_main_box_generic_get_child_at_index (self, i); + gd_main_box_generic_select_child (self, child); + } +} + +static void +gd_main_box_generic_select_range (GdMainBoxGeneric *self, GdMainBoxChild *child) +{ + GListModel *model; + const gchar *last_selected_id; + gint index; + gint other_index = -1; + guint n_items; + + model = gd_main_box_generic_get_model (self); + n_items = g_list_model_get_n_items (model); + + last_selected_id = gd_main_box_generic_get_last_selected_id (self); + index = gd_main_box_child_get_index (child); + + if (last_selected_id != NULL) + { + guint i; + + for (i = 0; i < n_items; i++) + { + GdMainBoxItem *item; + const gchar *id; + + item = GD_MAIN_BOX_ITEM (g_list_model_get_object (model, i)); + id = gd_main_box_item_get_id (item); + + if (g_strcmp0 (id, last_selected_id) == 0) + { + other_index = (gint) i; + g_object_unref (item); + break; + } + + g_object_unref (item); + } + } + + if (other_index == -1) + { + gint i; + + for (i = index - 1; i >= 0; i--) + { + GdMainBoxChild *other; + + other = gd_main_box_generic_get_child_at_index (self, i); + if (gd_main_box_child_get_selected (other)) + { + other_index = i; + break; + } + } + } + + if (other_index == -1) + { + gint i; + + for (i = index + 1; i < (gint) n_items; i++) + { + GdMainBoxChild *other; + + other = gd_main_box_generic_get_child_at_index (self, i); + if (gd_main_box_child_get_selected (other)) + { + other_index = i; + break; + } + } + } + + if (other_index == -1) + gd_main_box_generic_select_child (self, child); + else + gd_main_box_generic_mark_range_as_selected (self, index, other_index); +} + +static void +gd_main_box_generic_default_init (GdMainBoxGenericInterface *iface) +{ + GParamSpec *pspec; + + /** + * GdMainBoxGeneric:last-selected-id: + * + * A unique ID to identify the #GdMainBoxItem object that was most + * recently selected. + */ + pspec = g_param_spec_string ("last-selected-id", + "ID", + "A unique ID to identify the most recently selected item", + NULL, + G_PARAM_EXPLICIT_NOTIFY | G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + g_object_interface_install_property (iface, pspec); + + /** + * GdMainBoxGeneric:model: + * + * A #GListModel that is rendered by the #GdMainBoxGeneric widget. + */ + pspec = g_param_spec_object ("model", + "Model", + "A model that is rendered by the widget", + G_TYPE_LIST_MODEL, + G_PARAM_EXPLICIT_NOTIFY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + g_object_interface_install_property (iface, pspec); + + /** + * GdMainBoxGeneric:gd-selection-mode: + * + * Whether the #GdMainBoxGeneric widget is in selection mode. + */ + pspec = g_param_spec_boolean ("gd-selection-mode", + "Selection Mode", + "Whether the widget is in selection mode", + FALSE, + G_PARAM_EXPLICIT_NOTIFY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + g_object_interface_install_property (iface, pspec); + + /** + * GdMainBoxGeneric:show-primary-text: + * + * Whether the #GdMainBoxGeneric widget is going to show the + * primary-text of each #GdMainBoxItem. + */ + pspec = g_param_spec_boolean ("show-primary-text", + "Show Primary Text", + "Whether each GdMainBoxItem's primary-text is going to be shown", + FALSE, + G_PARAM_EXPLICIT_NOTIFY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + g_object_interface_install_property (iface, pspec); + + /** + * GdMainBoxGeneric:show-secondary-text: + * + * Whether the #GdMainBoxGeneric widget is going to show the + * secondary-text of each #GdMainBoxItem. + */ + pspec = g_param_spec_boolean ("show-secondary-text", + "Show Secondary Text", + "Whether each GdMainBoxItem's secondary-text is going to be shown", + FALSE, + G_PARAM_EXPLICIT_NOTIFY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + g_object_interface_install_property (iface, pspec); + + signals[ITEM_ACTIVATED] = g_signal_new ("item-activated", + GD_TYPE_MAIN_BOX_GENERIC, + G_SIGNAL_RUN_LAST, + 0, + NULL, + NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, + 1, + GD_TYPE_MAIN_BOX_CHILD); + + signals[SELECTION_CHANGED] = g_signal_new ("selection-changed", + GD_TYPE_MAIN_BOX_GENERIC, + G_SIGNAL_RUN_LAST, + 0, + NULL, + NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, + 0); + + signals[SELECTION_MODE_REQUEST] = g_signal_new ("selection-mode-request", + GD_TYPE_MAIN_BOX_GENERIC, + G_SIGNAL_RUN_LAST, + 0, + NULL, + NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, + 0); +} + +/** + * gd_main_box_generic_get_child_at_index: + * @self: + * @index: + * + * Returns: (transfer none): The child at @index. + */ +GdMainBoxChild * +gd_main_box_generic_get_child_at_index (GdMainBoxGeneric *self, gint index) +{ + GdMainBoxGenericInterface *iface; + + g_return_val_if_fail (GD_IS_MAIN_BOX_GENERIC (self), NULL); + + iface = GD_MAIN_BOX_GENERIC_GET_IFACE (self); + + return (* iface->get_child_at_index) (self, index); +} + +/** + * gd_main_box_generic_get_last_selected_id: + * @self: + * + * Returns: (transfer none): The ID of the most recently selected #GdMainBoxItem. + */ +const gchar * +gd_main_box_generic_get_last_selected_id (GdMainBoxGeneric *self) +{ + GdMainBoxGenericInterface *iface; + + g_return_val_if_fail (GD_IS_MAIN_BOX_GENERIC (self), NULL); + + iface = GD_MAIN_BOX_GENERIC_GET_IFACE (self); + + return (* iface->get_last_selected_id) (self); +} + +/** + * gd_main_box_generic_get_model: + * @self: + * + * Returns: (transfer none): The associated model + */ +GListModel * +gd_main_box_generic_get_model (GdMainBoxGeneric *self) +{ + GdMainBoxGenericInterface *iface; + + g_return_val_if_fail (GD_IS_MAIN_BOX_GENERIC (self), NULL); + + iface = GD_MAIN_BOX_GENERIC_GET_IFACE (self); + + return (* iface->get_model) (self); +} + +/** + * gd_main_box_generic_get_selected_children: + * @self: + * + * Returns: (element-type GdMainBoxChild) (transfer container): The + * selected children + */ +GList * +gd_main_box_generic_get_selected_children (GdMainBoxGeneric *self) +{ + GdMainBoxGenericInterface *iface; + + g_return_val_if_fail (GD_IS_MAIN_BOX_GENERIC (self), NULL); + + iface = GD_MAIN_BOX_GENERIC_GET_IFACE (self); + + return (* iface->get_selected_children) (self); +} + +/** + * gd_main_box_generic_get_selection_mode: + * @self: + * + * Returns: (transfer none): Whether @self is in selection mode + */ +gboolean +gd_main_box_generic_get_selection_mode (GdMainBoxGeneric *self) +{ + gboolean selection_mode; + + g_return_val_if_fail (GD_IS_MAIN_BOX_GENERIC (self), FALSE); + + g_object_get (self, "gd-selection-mode", &selection_mode, NULL); + return selection_mode; +} + +/** + * gd_main_box_generic_get_show_primary_text: + * @self: + * + * Returns: (transfer none): Whether @self is going to show the + * primary-text of each #GdMainBoxItem + */ +gboolean +gd_main_box_generic_get_show_primary_text (GdMainBoxGeneric *self) +{ + gboolean show_primary_text; + + g_return_val_if_fail (GD_IS_MAIN_BOX_GENERIC (self), FALSE); + + g_object_get (self, "show-primary-text", &show_primary_text, NULL); + return show_primary_text; +} + +/** + * gd_main_box_generic_get_show_secondary_text: + * @self: + * + * Returns: (transfer none): Whether @self is going to show the + * secondary-text of each #GdMainBoxItem + */ +gboolean +gd_main_box_generic_get_show_secondary_text (GdMainBoxGeneric *self) +{ + gboolean show_secondary_text; + + g_return_val_if_fail (GD_IS_MAIN_BOX_GENERIC (self), FALSE); + + g_object_get (self, "show-secondary-text", &show_secondary_text, NULL); + return show_secondary_text; +} + +void +gd_main_box_generic_select_all (GdMainBoxGeneric *self) +{ + GdMainBoxGenericInterface *iface; + + g_return_if_fail (GD_IS_MAIN_BOX_GENERIC (self)); + + iface = GD_MAIN_BOX_GENERIC_GET_IFACE (self); + + (* iface->select_all) (self); +} + +void +gd_main_box_generic_select_child (GdMainBoxGeneric *self, GdMainBoxChild *child) +{ + GdMainBoxGenericInterface *iface; + + g_return_if_fail (GD_IS_MAIN_BOX_GENERIC (self)); + g_return_if_fail (GD_IS_MAIN_BOX_CHILD (child)); + + iface = GD_MAIN_BOX_GENERIC_GET_IFACE (self); + + (* iface->select_child) (self, child); +} + +/** + * gd_main_box_generic_set_model: + * @self: + * @model: (allow-none): + * + */ +void +gd_main_box_generic_set_model (GdMainBoxGeneric *self, GListModel *model) +{ + g_return_if_fail (GD_IS_MAIN_BOX_GENERIC (self)); + g_return_if_fail (model == NULL || G_IS_LIST_MODEL (model)); + + g_object_set (self, "model", model, NULL); +} + +/** + * gd_main_box_generic_set_selection_mode: + * @self: + * @selection_mode: + * + */ +void +gd_main_box_generic_set_selection_mode (GdMainBoxGeneric *self, gboolean selection_mode) +{ + g_return_if_fail (GD_IS_MAIN_BOX_GENERIC (self)); + g_object_set (self, "gd-selection-mode", selection_mode, NULL); +} + +/** + * gd_main_box_generic_set_show_primary_text: + * @self: + * @show_primary_text: + * + */ +void +gd_main_box_generic_set_show_primary_text (GdMainBoxGeneric *self, gboolean show_primary_text) +{ + g_return_if_fail (GD_IS_MAIN_BOX_GENERIC (self)); + g_object_set (self, "show-primary-text", show_primary_text, NULL); +} + +/** + * gd_main_box_generic_set_show_secondary_text: + * @self: + * @show_secondary_text: + * + */ +void +gd_main_box_generic_set_show_secondary_text (GdMainBoxGeneric *self, gboolean show_secondary_text) +{ + g_return_if_fail (GD_IS_MAIN_BOX_GENERIC (self)); + g_object_set (self, "show-secondary-text", show_secondary_text, NULL); +} + +void +gd_main_box_generic_unselect_all (GdMainBoxGeneric *self) +{ + GdMainBoxGenericInterface *iface; + + g_return_if_fail (GD_IS_MAIN_BOX_GENERIC (self)); + + iface = GD_MAIN_BOX_GENERIC_GET_IFACE (self); + + (* iface->unselect_all) (self); +} + +void +gd_main_box_generic_unselect_child (GdMainBoxGeneric *self, GdMainBoxChild *child) +{ + GdMainBoxGenericInterface *iface; + + g_return_if_fail (GD_IS_MAIN_BOX_GENERIC (self)); + g_return_if_fail (GD_IS_MAIN_BOX_CHILD (child)); + + iface = GD_MAIN_BOX_GENERIC_GET_IFACE (self); + + (* iface->unselect_child) (self, child); +} + +void +gd_main_box_generic_toggle_selection_for_child (GdMainBoxGeneric *self, + GdMainBoxChild *child, + gboolean select_range) +{ + GListModel *model; + + model = gd_main_box_generic_get_model (self); + if (model == NULL) + return; + + if (gd_main_box_child_get_selected (child)) + { + gd_main_box_generic_unselect_child (self, child); + } + else + { + if (select_range) + gd_main_box_generic_select_range (self, child); + else + gd_main_box_generic_select_child (self, child); + } +} diff --git a/subprojects/libgd/libgd/gd-main-box-generic.h b/subprojects/libgd/libgd/gd-main-box-generic.h new file mode 100644 index 00000000..2c9c805a --- /dev/null +++ b/subprojects/libgd/libgd/gd-main-box-generic.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2016, 2017 Red Hat, Inc. + * + * This program 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 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 Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Author: Debarshi Ray <debarshir@gnome.org> + * + */ + +#ifndef __GD_MAIN_BOX_GENERIC_H__ +#define __GD_MAIN_BOX_GENERIC_H__ + +#include <gio/gio.h> +#include <gtk/gtk.h> + +#include "gd-main-box-child.h" + +G_BEGIN_DECLS + +#define GD_TYPE_MAIN_BOX_GENERIC gd_main_box_generic_get_type() +G_DECLARE_INTERFACE (GdMainBoxGeneric, gd_main_box_generic, GD, MAIN_BOX_GENERIC, GtkWidget) + +struct _GdMainBoxGenericInterface +{ + GTypeInterface base_iface; + + /* vtable */ + GdMainBoxChild * (* get_child_at_index) (GdMainBoxGeneric *self, gint index); + const gchar * (* get_last_selected_id) (GdMainBoxGeneric *self); + GListModel * (* get_model) (GdMainBoxGeneric *self); + GList * (* get_selected_children) (GdMainBoxGeneric *self); + void (* select_all) (GdMainBoxGeneric *self); + void (* select_child) (GdMainBoxGeneric *self, GdMainBoxChild *child); + void (* unselect_all) (GdMainBoxGeneric *self); + void (* unselect_child) (GdMainBoxGeneric *self, GdMainBoxChild *child); +}; + +GdMainBoxChild * gd_main_box_generic_get_child_at_index (GdMainBoxGeneric *self, gint index); +const gchar * gd_main_box_generic_get_last_selected_id (GdMainBoxGeneric *self); +GListModel * gd_main_box_generic_get_model (GdMainBoxGeneric *self); +GList * gd_main_box_generic_get_selected_children (GdMainBoxGeneric *self); +gboolean gd_main_box_generic_get_selection_mode (GdMainBoxGeneric *self); +gboolean gd_main_box_generic_get_show_primary_text (GdMainBoxGeneric *self); +gboolean gd_main_box_generic_get_show_secondary_text (GdMainBoxGeneric *self); +void gd_main_box_generic_select_all (GdMainBoxGeneric *self); +void gd_main_box_generic_select_child (GdMainBoxGeneric *self, GdMainBoxChild *child); +void gd_main_box_generic_set_model (GdMainBoxGeneric *self, GListModel *model); +void gd_main_box_generic_set_selection_mode (GdMainBoxGeneric *self, gboolean selection_mode); +void gd_main_box_generic_set_show_primary_text (GdMainBoxGeneric *self, gboolean show_primary_text); +void gd_main_box_generic_set_show_secondary_text (GdMainBoxGeneric *self, + gboolean show_secondary_text); +void gd_main_box_generic_unselect_all (GdMainBoxGeneric *self); +void gd_main_box_generic_unselect_child (GdMainBoxGeneric *self, GdMainBoxChild *child); + +void gd_main_box_generic_toggle_selection_for_child (GdMainBoxGeneric *self, + GdMainBoxChild *child, + gboolean select_range); + +G_END_DECLS + +#endif /* __GD_MAIN_BOX_GENERIC_H__ */ diff --git a/subprojects/libgd/libgd/gd-main-box-item.c b/subprojects/libgd/libgd/gd-main-box-item.c new file mode 100644 index 00000000..042b0e43 --- /dev/null +++ b/subprojects/libgd/libgd/gd-main-box-item.c @@ -0,0 +1,242 @@ +/* + * Copyright (c) 2016 Red Hat, Inc. + * + * This program 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 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 Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Author: Debarshi Ray <debarshir@gnome.org> + * + */ + +#include <cairo-gobject.h> + +#include "gd-main-box-item.h" + +G_DEFINE_INTERFACE (GdMainBoxItem, gd_main_box_item, G_TYPE_OBJECT) + +static void +gd_main_box_item_default_init (GdMainBoxItemInterface *iface) +{ + GParamSpec *pspec; + + /** + * GdMainBoxItem:id: + * + * A unique ID to identify the #GdMainBoxItem object. + */ + pspec = g_param_spec_string ("id", + "ID", + "A unique ID to identify the item", + NULL, + G_PARAM_EXPLICIT_NOTIFY | G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + g_object_interface_install_property (iface, pspec); + + /** + * GdMainBoxItem:uri: + * + * A URI corresponding to the #GdMainBoxItem object. + */ + pspec = g_param_spec_string ("uri", + "URI", + "A URI corresponding to the item", + NULL, + G_PARAM_EXPLICIT_NOTIFY | G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + g_object_interface_install_property (iface, pspec); + + /** + * GdMainBoxItem:primary-text: + * + * Some text to describe the #GdMainBoxItem object. + */ + pspec = g_param_spec_string ("primary-text", + "Primary Text", + "Some text to describe the item", + NULL, + G_PARAM_EXPLICIT_NOTIFY | G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + g_object_interface_install_property (iface, pspec); + + /** + * GdMainBoxItem:secondary-text: + * + * Some additional text to describe the #GdMainBoxItem object. + */ + pspec = g_param_spec_string ("secondary-text", + "Secondary Text", + "Some additional text to describe the item", + NULL, + G_PARAM_EXPLICIT_NOTIFY | G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + g_object_interface_install_property (iface, pspec); + + /** + * GdMainBoxItem:icon: + * + * An icon to visually identify the #GdMainBoxItem object. + */ + pspec = g_param_spec_boxed ("icon", + "Icon", + "An icon to visually identify the item", + CAIRO_GOBJECT_TYPE_SURFACE, + G_PARAM_EXPLICIT_NOTIFY | G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + g_object_interface_install_property (iface, pspec); + + /** + * GdMainBoxItem:mtime: + * + * The time when the #GdMainBoxItem object was last modified. + */ + pspec = g_param_spec_int64 ("mtime", + "Modification time", + "The time when the item was last modified", + -1, + G_MAXINT64, + -1, + G_PARAM_EXPLICIT_NOTIFY | G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + g_object_interface_install_property (iface, pspec); + + /** + * GdMainBoxItem:pulse: + * + * Whether to show a progress indicator. + */ + pspec = g_param_spec_boolean ("pulse", + "Pulse", + "Whether to show a progress indicator", + FALSE, + G_PARAM_EXPLICIT_NOTIFY | G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + g_object_interface_install_property (iface, pspec); +} + +/** + * gd_main_box_item_get_id: + * @self: + * + * Returns: (transfer none): The ID + */ +const gchar * +gd_main_box_item_get_id (GdMainBoxItem *self) +{ + GdMainBoxItemInterface *iface; + + g_return_val_if_fail (GD_IS_MAIN_BOX_ITEM (self), NULL); + + iface = GD_MAIN_BOX_ITEM_GET_IFACE (self); + + return (* iface->get_id) (self); +} + +/** + * gd_main_box_item_get_uri: + * @self: + * + * Returns: (transfer none): The URI + */ +const gchar * +gd_main_box_item_get_uri (GdMainBoxItem *self) +{ + GdMainBoxItemInterface *iface; + + g_return_val_if_fail (GD_IS_MAIN_BOX_ITEM (self), NULL); + + iface = GD_MAIN_BOX_ITEM_GET_IFACE (self); + + return (* iface->get_uri) (self); +} + +/** + * gd_main_box_item_get_primary_text: + * @self: + * + * Returns: (transfer none): The primary text + */ +const gchar * +gd_main_box_item_get_primary_text (GdMainBoxItem *self) +{ + GdMainBoxItemInterface *iface; + + g_return_val_if_fail (GD_IS_MAIN_BOX_ITEM (self), NULL); + + iface = GD_MAIN_BOX_ITEM_GET_IFACE (self); + + return (* iface->get_primary_text) (self); +} + +/** + * gd_main_box_item_get_secondary_text: + * @self: + * + * Returns: (transfer none): The secondary text + */ +const gchar * +gd_main_box_item_get_secondary_text (GdMainBoxItem *self) +{ + GdMainBoxItemInterface *iface; + + g_return_val_if_fail (GD_IS_MAIN_BOX_ITEM (self), NULL); + + iface = GD_MAIN_BOX_ITEM_GET_IFACE (self); + + return (* iface->get_secondary_text) (self); +} + +/** + * gd_main_box_item_get_icon: + * @self: + * + * Returns: (transfer none): The icon + */ +cairo_surface_t * +gd_main_box_item_get_icon (GdMainBoxItem *self) +{ + GdMainBoxItemInterface *iface; + + g_return_val_if_fail (GD_IS_MAIN_BOX_ITEM (self), NULL); + + iface = GD_MAIN_BOX_ITEM_GET_IFACE (self); + + return (* iface->get_icon) (self); +} + +/** + * gd_main_box_item_get_mtime: + * @self: + * + * Returns: (transfer none): The modification time + */ +gint64 +gd_main_box_item_get_mtime (GdMainBoxItem *self) +{ + gint64 mtime; + + g_return_val_if_fail (GD_IS_MAIN_BOX_ITEM (self), -1); + + g_object_get (self, "mtime", &mtime, NULL); + return mtime; +} + +/** + * gd_main_box_item_get_pulse: + * @self: + * + * Returns: (transfer none): Whether to show a progress indicator + */ +gboolean +gd_main_box_item_get_pulse (GdMainBoxItem *self) +{ + gboolean pulse; + + g_return_val_if_fail (GD_IS_MAIN_BOX_ITEM (self), FALSE); + + g_object_get (self, "pulse", &pulse, NULL); + return pulse; +} diff --git a/subprojects/libgd/libgd/gd-main-box-item.h b/subprojects/libgd/libgd/gd-main-box-item.h new file mode 100644 index 00000000..e37cb072 --- /dev/null +++ b/subprojects/libgd/libgd/gd-main-box-item.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2016 Red Hat, Inc. + * + * This program 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 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 Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Author: Debarshi Ray <debarshir@gnome.org> + * + */ + +#ifndef __GD_MAIN_BOX_ITEM_H__ +#define __GD_MAIN_BOX_ITEM_H__ + +#include <cairo.h> +#include <glib-object.h> + +G_BEGIN_DECLS + +#define GD_TYPE_MAIN_BOX_ITEM gd_main_box_item_get_type() +G_DECLARE_INTERFACE (GdMainBoxItem, gd_main_box_item, GD, MAIN_BOX_ITEM, GObject) + +struct _GdMainBoxItemInterface +{ + GTypeInterface base_iface; + + /* vtable */ + const gchar * (* get_id) (GdMainBoxItem *self); + const gchar * (* get_uri) (GdMainBoxItem *self); + const gchar * (* get_primary_text) (GdMainBoxItem *self); + const gchar * (* get_secondary_text) (GdMainBoxItem *self); + cairo_surface_t * (* get_icon) (GdMainBoxItem *self); +}; + +const gchar * gd_main_box_item_get_id (GdMainBoxItem *self); +const gchar * gd_main_box_item_get_uri (GdMainBoxItem *self); +const gchar * gd_main_box_item_get_primary_text (GdMainBoxItem *self); +const gchar * gd_main_box_item_get_secondary_text (GdMainBoxItem *self); +cairo_surface_t * gd_main_box_item_get_icon (GdMainBoxItem *self); +gint64 gd_main_box_item_get_mtime (GdMainBoxItem *self); +gboolean gd_main_box_item_get_pulse (GdMainBoxItem *self); + +G_END_DECLS + +#endif /* __GD_MAIN_BOX_ITEM_H__ */ diff --git a/subprojects/libgd/libgd/gd-main-box.c b/subprojects/libgd/libgd/gd-main-box.c new file mode 100644 index 00000000..be87b1df --- /dev/null +++ b/subprojects/libgd/libgd/gd-main-box.c @@ -0,0 +1,548 @@ +/* + * Copyright (c) 2016, 2017 Red Hat, Inc. + * + * This program 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 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 Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Author: Debarshi Ray <debarshir@gnome.org> + * + */ + +#include "gd-main-box.h" +#include "gd-main-box-child.h" +#include "gd-main-box-generic.h" +#include "gd-main-icon-box.h" + +#define MAIN_BOX_TYPE_INITIAL -1 + +typedef struct _GdMainBoxPrivate GdMainBoxPrivate; + +struct _GdMainBoxPrivate +{ + GListModel *model; + GdMainBoxType current_type; + GtkWidget *current_box; + GtkWidget *frame; + gboolean selection_mode; + gboolean show_primary_text; + gboolean show_secondary_text; +}; + +enum +{ + PROP_BOX_TYPE = 1, + PROP_SELECTION_MODE, + PROP_SHOW_PRIMARY_TEXT, + PROP_SHOW_SECONDARY_TEXT, + PROP_MODEL, + NUM_PROPERTIES +}; + +enum +{ + ITEM_ACTIVATED, + SELECTION_CHANGED, + SELECTION_MODE_REQUEST, + NUM_SIGNALS +}; + +static GParamSpec *properties[NUM_PROPERTIES] = { NULL, }; +static guint signals[NUM_SIGNALS] = { 0, }; + +G_DEFINE_TYPE_WITH_PRIVATE (GdMainBox, gd_main_box, GTK_TYPE_BIN) + +static void +gd_main_box_activate_item_for_child (GdMainBox *self, GdMainBoxChild *child) +{ + GdMainBoxPrivate *priv; + GdMainBoxItem *item; + + priv = gd_main_box_get_instance_private (self); + + if (priv->model == NULL) + return; + + item = gd_main_box_child_get_item (child); + if (item == NULL) + return; + + g_signal_emit (self, signals[ITEM_ACTIVATED], 0, item); +} + +static void +gd_main_box_apply_selection_mode (GdMainBox *self) +{ + GdMainBoxPrivate *priv; + + priv = gd_main_box_get_instance_private (self); + + gd_main_box_generic_set_selection_mode (GD_MAIN_BOX_GENERIC (priv->current_box), priv->selection_mode); + + if (!priv->selection_mode) + { + if (priv->model != NULL) + gd_main_box_unselect_all (self); + } +} + +static void +gd_main_box_item_activated_cb (GdMainBox *self, GdMainBoxChild *child) +{ + GdMainBoxPrivate *priv; + + priv = gd_main_box_get_instance_private (self); + + if (!priv->selection_mode) + gd_main_box_activate_item_for_child (self, child); +} + +static void +gd_main_box_selection_changed_cb (GdMainBox *self) +{ + g_signal_emit (self, signals[SELECTION_CHANGED], 0); +} + +static void +gd_main_box_selection_mode_request_cb (GdMainBox *self) +{ + g_signal_emit (self, signals[SELECTION_MODE_REQUEST], 0); +} + +static void +gd_main_box_rebuild (GdMainBox *self) +{ + GdMainBoxPrivate *priv; + + priv = gd_main_box_get_instance_private (self); + + if (priv->current_box != NULL) + gtk_widget_destroy (priv->current_box); + + switch (priv->current_type) + { + case GD_MAIN_BOX_ICON: + priv->current_box = gd_main_icon_box_new (); + break; + + case GD_MAIN_BOX_LIST: + default: + g_assert_not_reached (); + break; + } + + gtk_widget_set_hexpand (priv->current_box, TRUE); + gtk_widget_set_valign (priv->current_box, GTK_ALIGN_START); + g_object_bind_property (self, "show-primary-text", + priv->current_box, "show-primary-text", + G_BINDING_SYNC_CREATE); + g_object_bind_property (self, "show-secondary-text", + priv->current_box, "show-secondary-text", + G_BINDING_SYNC_CREATE); + gtk_container_add (GTK_CONTAINER (priv->frame), priv->current_box); + + g_signal_connect_swapped (priv->current_box, + "item-activated", + G_CALLBACK (gd_main_box_item_activated_cb), + self); + g_signal_connect_swapped (priv->current_box, + "selection-changed", + G_CALLBACK (gd_main_box_selection_changed_cb), + self); + g_signal_connect_swapped (priv->current_box, + "selection-mode-request", + G_CALLBACK (gd_main_box_selection_mode_request_cb), + self); + + gd_main_box_generic_set_model (GD_MAIN_BOX_GENERIC (priv->current_box), priv->model); + gd_main_box_apply_selection_mode (self); + + gtk_widget_show_all (GTK_WIDGET (self)); +} + +static void +gd_main_box_dispose (GObject *obj) +{ + GdMainBox *self = GD_MAIN_BOX (obj); + GdMainBoxPrivate *priv; + + priv = gd_main_box_get_instance_private (self); + + g_clear_object (&priv->model); + + G_OBJECT_CLASS (gd_main_box_parent_class)->dispose (obj); +} + +static void +gd_main_box_init (GdMainBox *self) +{ + GdMainBoxPrivate *priv; + GtkStyleContext *context; + + priv = gd_main_box_get_instance_private (self); + + priv->frame = gtk_frame_new (NULL); + context = gtk_widget_get_style_context (priv->frame); + gtk_style_context_add_class (context, "content-view"); + gtk_container_add (GTK_CONTAINER (self), priv->frame); + + /* so that we get constructed with the right view even at startup */ + priv->current_type = MAIN_BOX_TYPE_INITIAL; +} + +static void +gd_main_box_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) +{ + GdMainBox *self = GD_MAIN_BOX (object); + + switch (property_id) + { + case PROP_BOX_TYPE: + g_value_set_int (value, gd_main_box_get_box_type (self)); + break; + case PROP_SELECTION_MODE: + g_value_set_boolean (value, gd_main_box_get_selection_mode (self)); + break; + case PROP_SHOW_PRIMARY_TEXT: + g_value_set_boolean (value, gd_main_box_get_show_primary_text (self)); + break; + case PROP_SHOW_SECONDARY_TEXT: + g_value_set_boolean (value, gd_main_box_get_show_secondary_text (self)); + break; + case PROP_MODEL: + g_value_set_object (value, gd_main_box_get_model (self)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gd_main_box_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) +{ + GdMainBox *self = GD_MAIN_BOX (object); + + switch (property_id) + { + case PROP_BOX_TYPE: + gd_main_box_set_box_type (self, g_value_get_int (value)); + break; + case PROP_SELECTION_MODE: + gd_main_box_set_selection_mode (self, g_value_get_boolean (value)); + break; + case PROP_SHOW_PRIMARY_TEXT: + gd_main_box_set_show_primary_text (self, g_value_get_boolean (value)); + break; + case PROP_SHOW_SECONDARY_TEXT: + gd_main_box_set_show_secondary_text (self, g_value_get_boolean (value)); + break; + case PROP_MODEL: + gd_main_box_set_model (self, g_value_get_object (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gd_main_box_class_init (GdMainBoxClass *klass) +{ + GObjectClass *oclass = G_OBJECT_CLASS (klass); + + oclass->get_property = gd_main_box_get_property; + oclass->set_property = gd_main_box_set_property; + oclass->dispose = gd_main_box_dispose; + + properties[PROP_BOX_TYPE] = g_param_spec_int ("box-type", + "Box type", + "Box type", + GD_MAIN_BOX_ICON, + GD_MAIN_BOX_LIST, + GD_MAIN_BOX_ICON, + G_PARAM_EXPLICIT_NOTIFY | + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT | + G_PARAM_STATIC_STRINGS); + + properties[PROP_MODEL] = g_param_spec_object ("model", + "Model", + "The GListModel", + G_TYPE_LIST_MODEL, + G_PARAM_EXPLICIT_NOTIFY | + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT | + G_PARAM_STATIC_STRINGS); + + properties[PROP_SELECTION_MODE] = g_param_spec_boolean ("selection-mode", + "Selection mode", + "Whether the view is in selection mode", + FALSE, + G_PARAM_EXPLICIT_NOTIFY | + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT | + G_PARAM_STATIC_STRINGS); + + properties[PROP_SHOW_PRIMARY_TEXT] = g_param_spec_boolean ("show-primary-text", + "Show primary text", + "Whether each GdMainBoxItem's primary-text is going " + "to be shown", + FALSE, + G_PARAM_EXPLICIT_NOTIFY | + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT | + G_PARAM_STATIC_STRINGS); + + properties[PROP_SHOW_SECONDARY_TEXT] = g_param_spec_boolean ("show-secondary-text", + "Show secondary text", + "Whether each GdMainBoxItem's secondary-text is " + "going to be shown", + FALSE, + G_PARAM_EXPLICIT_NOTIFY | + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT | + G_PARAM_STATIC_STRINGS); + + signals[ITEM_ACTIVATED] = g_signal_new ("item-activated", + GD_TYPE_MAIN_BOX, + G_SIGNAL_RUN_LAST, + 0, + NULL, + NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, + 1, + GD_TYPE_MAIN_BOX_ITEM); + + signals[SELECTION_CHANGED] = g_signal_new ("selection-changed", + GD_TYPE_MAIN_BOX, + G_SIGNAL_RUN_LAST, + 0, + NULL, + NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, + 0); + + signals[SELECTION_MODE_REQUEST] = g_signal_new ("selection-mode-request", + GD_TYPE_MAIN_BOX, + G_SIGNAL_RUN_LAST, + 0, + NULL, + NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, + 0); + + g_object_class_install_properties (oclass, NUM_PROPERTIES, properties); +} + +GtkWidget * +gd_main_box_new (GdMainBoxType type) +{ + return g_object_new (GD_TYPE_MAIN_BOX, "box-type", type, NULL); +} + +GdMainBoxType +gd_main_box_get_box_type (GdMainBox *self) +{ + GdMainBoxPrivate *priv; + + priv = gd_main_box_get_instance_private (self); + return priv->current_type; +} + +void +gd_main_box_set_box_type (GdMainBox *self, GdMainBoxType type) +{ + GdMainBoxPrivate *priv; + + priv = gd_main_box_get_instance_private (self); + + if (type == priv->current_type) + return; + + priv->current_type = type; + gd_main_box_rebuild (self); + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_BOX_TYPE]); +} + +gboolean +gd_main_box_get_selection_mode (GdMainBox *self) +{ + GdMainBoxPrivate *priv; + + priv = gd_main_box_get_instance_private (self); + return priv->selection_mode; +} + +gboolean +gd_main_box_get_show_primary_text (GdMainBox *self) +{ + GdMainBoxPrivate *priv; + + priv = gd_main_box_get_instance_private (self); + return priv->show_primary_text; +} + +gboolean +gd_main_box_get_show_secondary_text (GdMainBox *self) +{ + GdMainBoxPrivate *priv; + + priv = gd_main_box_get_instance_private (self); + return priv->show_secondary_text; +} + +void +gd_main_box_set_selection_mode (GdMainBox *self, gboolean selection_mode) +{ + GdMainBoxPrivate *priv; + + priv = gd_main_box_get_instance_private (self); + + if (selection_mode == priv->selection_mode) + return; + + priv->selection_mode = selection_mode; + gd_main_box_apply_selection_mode (self); + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SELECTION_MODE]); +} + +void +gd_main_box_set_show_primary_text (GdMainBox *self, gboolean show_primary_text) +{ + GdMainBoxPrivate *priv; + + priv = gd_main_box_get_instance_private (self); + + if (show_primary_text == priv->show_primary_text) + return; + + priv->show_primary_text = show_primary_text; + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SHOW_PRIMARY_TEXT]); +} + +void +gd_main_box_set_show_secondary_text (GdMainBox *self, gboolean show_secondary_text) +{ + GdMainBoxPrivate *priv; + + priv = gd_main_box_get_instance_private (self); + + if (show_secondary_text == priv->show_secondary_text) + return; + + priv->show_secondary_text = show_secondary_text; + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SHOW_SECONDARY_TEXT]); +} + +/** + * gd_main_box_get_model: + * @self: + * + * Returns: (transfer none): + */ +GListModel * +gd_main_box_get_model (GdMainBox *self) +{ + GdMainBoxPrivate *priv; + + priv = gd_main_box_get_instance_private (self); + return priv->model; +} + +/** + * gd_main_box_set_model: + * @self: + * @model: (allow-none): + * + */ +void +gd_main_box_set_model (GdMainBox *self, GListModel *model) +{ + GdMainBoxPrivate *priv; + + priv = gd_main_box_get_instance_private (self); + + if (!g_set_object (&priv->model, model)) + return; + + gd_main_box_generic_set_model (GD_MAIN_BOX_GENERIC (priv->current_box), priv->model); + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_MODEL]); +} + +/** + * gd_main_box_get_generic_box: + * @self: + * + * Returns: (transfer none): + */ +GtkWidget * +gd_main_box_get_generic_box (GdMainBox *self) +{ + GdMainBoxPrivate *priv; + + priv = gd_main_box_get_instance_private (self); + return priv->current_box; +} + +/** + * gd_main_box_get_selection: + * @self: + * + * Returns: (element-type GdMainBoxItem) (transfer full): + */ +GList * +gd_main_box_get_selection (GdMainBox *self) +{ + GdMainBoxPrivate *priv; + GList *l; + GList *selected_children; + GList *selection = NULL; + + priv = gd_main_box_get_instance_private (self); + + selected_children = gd_main_box_generic_get_selected_children (GD_MAIN_BOX_GENERIC (priv->current_box)); + for (l = selected_children; l != NULL; l = l->next) + { + GdMainBoxChild *child = GD_MAIN_BOX_CHILD (l->data); + GdMainBoxItem *item; + + item = gd_main_box_child_get_item (child); + selection = g_list_prepend (selection, g_object_ref (item)); + } + + selection = g_list_reverse (selection); + g_list_free (selected_children); + return selection; +} + +void +gd_main_box_select_all (GdMainBox *self) +{ + GdMainBoxPrivate *priv; + + priv = gd_main_box_get_instance_private (self); + gd_main_box_generic_select_all (GD_MAIN_BOX_GENERIC (priv->current_box)); +} + +void +gd_main_box_unselect_all (GdMainBox *self) +{ + GdMainBoxPrivate *priv; + + priv = gd_main_box_get_instance_private (self); + gd_main_box_generic_unselect_all (GD_MAIN_BOX_GENERIC (priv->current_box)); +} diff --git a/subprojects/libgd/libgd/gd-main-box.h b/subprojects/libgd/libgd/gd-main-box.h new file mode 100644 index 00000000..1ff80387 --- /dev/null +++ b/subprojects/libgd/libgd/gd-main-box.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2016, 2017 Red Hat, Inc. + * + * This program 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 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 Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Author: Debarshi Ray <debarshir@gnome.org> + * + */ + +#ifndef __GD_MAIN_BOX_H__ +#define __GD_MAIN_BOX_H__ + +#include <gio/gio.h> +#include <gtk/gtk.h> + +G_BEGIN_DECLS + +#define GD_TYPE_MAIN_BOX gd_main_box_get_type() +G_DECLARE_DERIVABLE_TYPE (GdMainBox, gd_main_box, GD, MAIN_BOX, GtkBin) + +typedef enum +{ + GD_MAIN_BOX_ICON, + GD_MAIN_BOX_LIST +} GdMainBoxType; + +struct _GdMainBoxClass +{ + GtkBinClass parent_class; +}; + +GtkWidget * gd_main_box_new (GdMainBoxType type); +GdMainBoxType gd_main_box_get_box_type (GdMainBox *self); +GListModel * gd_main_box_get_model (GdMainBox *self); +GList * gd_main_box_get_selection (GdMainBox *self); +gboolean gd_main_box_get_selection_mode (GdMainBox *self); +gboolean gd_main_box_get_show_primary_text (GdMainBox *self); +gboolean gd_main_box_get_show_secondary_text (GdMainBox *self); +void gd_main_box_select_all (GdMainBox *self); +void gd_main_box_set_box_type (GdMainBox *self, GdMainBoxType type); +void gd_main_box_set_model (GdMainBox *self, GListModel *model); +void gd_main_box_set_selection_mode (GdMainBox *self, gboolean selection_mode); +void gd_main_box_set_show_primary_text (GdMainBox *self, gboolean show_primary_text); +void gd_main_box_set_show_secondary_text (GdMainBox *self, gboolean show_secondary_text); +void gd_main_box_unselect_all (GdMainBox *self); + +G_END_DECLS + +#endif /* __GD_MAIN_BOX_H__ */ diff --git a/subprojects/libgd/libgd/gd-main-icon-box-child.c b/subprojects/libgd/libgd/gd-main-icon-box-child.c new file mode 100644 index 00000000..3e246946 --- /dev/null +++ b/subprojects/libgd/libgd/gd-main-icon-box-child.c @@ -0,0 +1,439 @@ +/* + * Copyright (c) 2016, 2017 Red Hat, Inc. + * + * This program 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 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 Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Author: Debarshi Ray <debarshir@gnome.org> + * + */ + +#include "gd-main-box-child.h" +#include "gd-main-icon-box-child.h" +#include "gd-main-icon-box-icon.h" + +#include <gio/gio.h> +#include <glib.h> + +typedef struct _GdMainIconBoxChildPrivate GdMainIconBoxChildPrivate; + +struct _GdMainIconBoxChildPrivate +{ + GdMainBoxItem *item; + GtkWidget *check_button; + gboolean selection_mode; + gboolean show_primary_text; + gboolean show_secondary_text; +}; + +enum +{ + PROP_ITEM = 1, + PROP_SELECTION_MODE, + PROP_SHOW_PRIMARY_TEXT, + PROP_SHOW_SECONDARY_TEXT, + NUM_PROPERTIES +}; + +static void gd_main_box_child_interface_init (GdMainBoxChildInterface *iface); +G_DEFINE_TYPE_WITH_CODE (GdMainIconBoxChild, gd_main_icon_box_child, GTK_TYPE_FLOW_BOX_CHILD, + G_ADD_PRIVATE (GdMainIconBoxChild) + G_IMPLEMENT_INTERFACE (GD_TYPE_MAIN_BOX_CHILD, gd_main_box_child_interface_init)) + +static gboolean +gd_main_icon_box_child_bind_text_to_visible (GBinding *binding, + const GValue *from_value, + GValue *to_value, + gpointer user_data) +{ + gboolean to_visible; + const gchar *from_text; + + from_text = g_value_get_string (from_value); + to_visible = from_text != NULL && from_text[0] != '\0' ? TRUE : FALSE; + g_value_set_boolean (to_value, to_visible); + return TRUE; +} + +static void +gd_main_icon_box_check_button_toggled (GdMainIconBoxChild *self) +{ + GdMainIconBoxChildPrivate *priv; + GtkWidget *parent; + + priv = gd_main_icon_box_child_get_instance_private (self); + + parent = gtk_widget_get_parent (GTK_WIDGET (self)); + if (!GTK_IS_FLOW_BOX (parent)) + return; + + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->check_button))) + gtk_flow_box_select_child (GTK_FLOW_BOX (parent), GTK_FLOW_BOX_CHILD (self)); + else + gtk_flow_box_unselect_child (GTK_FLOW_BOX (parent), GTK_FLOW_BOX_CHILD (self)); +} + +static void +gd_main_icon_box_child_update_layout (GdMainIconBoxChild *self) +{ + GdMainIconBoxChildPrivate *priv; + GtkWidget *grid; + GtkWidget *icon; + GtkWidget *overlay; + + priv = gd_main_icon_box_child_get_instance_private (self); + + gtk_container_foreach (GTK_CONTAINER (self), (GtkCallback) gtk_widget_destroy, NULL); + + grid = gtk_grid_new (); + gtk_widget_set_valign (grid, GTK_ALIGN_CENTER); + gtk_orientable_set_orientation (GTK_ORIENTABLE (grid), GTK_ORIENTATION_VERTICAL); + gtk_container_add (GTK_CONTAINER (self), grid); + + overlay = gtk_overlay_new (); + gtk_container_add (GTK_CONTAINER (grid), overlay); + + icon = gd_main_icon_box_icon_new (priv->item); + gtk_widget_set_hexpand (icon, TRUE); + gtk_container_add (GTK_CONTAINER (overlay), icon); + + if (gd_main_box_item_get_pulse (priv->item)) + { + GtkWidget *spinner; + + spinner = gtk_spinner_new (); + gtk_widget_set_halign (spinner, GTK_ALIGN_CENTER); + gtk_widget_set_size_request (spinner, 32, 32); + gtk_widget_set_valign (spinner, GTK_ALIGN_CENTER); + gtk_spinner_start (GTK_SPINNER (spinner)); + gtk_overlay_add_overlay (GTK_OVERLAY (overlay), spinner); + } + + priv->check_button = gtk_check_button_new (); + gtk_widget_set_can_focus (priv->check_button, FALSE); + gtk_widget_set_halign (priv->check_button, GTK_ALIGN_END); + gtk_widget_set_valign (priv->check_button, GTK_ALIGN_END); + gtk_widget_set_no_show_all (priv->check_button, TRUE); + g_object_bind_property (self, "selection-mode", priv->check_button, "visible", G_BINDING_SYNC_CREATE); + gtk_overlay_add_overlay (GTK_OVERLAY (overlay), priv->check_button); + g_signal_connect_swapped (priv->check_button, + "toggled", + G_CALLBACK (gd_main_icon_box_check_button_toggled), + self); + + if (priv->show_primary_text) + { + GtkWidget *primary_label; + + primary_label = gtk_label_new (NULL); + gtk_widget_set_no_show_all (primary_label, TRUE); + gtk_label_set_ellipsize (GTK_LABEL (primary_label), PANGO_ELLIPSIZE_MIDDLE); + g_object_bind_property (priv->item, "primary-text", primary_label, "label", G_BINDING_SYNC_CREATE); + g_object_bind_property_full (priv->item, + "primary-text", + primary_label, + "visible", + G_BINDING_SYNC_CREATE, + gd_main_icon_box_child_bind_text_to_visible, + NULL, + NULL, + NULL); + gtk_container_add (GTK_CONTAINER (grid), primary_label); + } + + if (priv->show_secondary_text) + { + GtkStyleContext *context; + GtkWidget *secondary_label; + + secondary_label = gtk_label_new (NULL); + gtk_widget_set_no_show_all (secondary_label, TRUE); + gtk_label_set_ellipsize (GTK_LABEL (secondary_label), PANGO_ELLIPSIZE_END); + context = gtk_widget_get_style_context (secondary_label); + gtk_style_context_add_class (context, "dim-label"); + g_object_bind_property (priv->item, "secondary-text", secondary_label, "label", G_BINDING_SYNC_CREATE); + g_object_bind_property_full (priv->item, + "secondary-text", + secondary_label, + "visible", + G_BINDING_SYNC_CREATE, + gd_main_icon_box_child_bind_text_to_visible, + NULL, + NULL, + NULL); + gtk_container_add (GTK_CONTAINER (grid), secondary_label); + } + + gtk_widget_show_all (grid); +} + +static void +gd_main_icon_box_child_notify_pulse (GdMainIconBoxChild *self) +{ + gd_main_icon_box_child_update_layout (self); +} + +static GdMainBoxItem * +gd_main_icon_box_child_get_item (GdMainBoxChild *child) +{ + GdMainIconBoxChild *self = GD_MAIN_ICON_BOX_CHILD (child); + GdMainIconBoxChildPrivate *priv; + + priv = gd_main_icon_box_child_get_instance_private (self); + return priv->item; +} + +static gint +gd_main_icon_box_child_get_index (GdMainBoxChild *child) +{ + GdMainIconBoxChild *self = GD_MAIN_ICON_BOX_CHILD (child); + gint index; + + index = gtk_flow_box_child_get_index (GTK_FLOW_BOX_CHILD (self)); + return index; +} + +static gboolean +gd_main_icon_box_child_get_selected (GdMainBoxChild *child) +{ + GdMainIconBoxChild *self = GD_MAIN_ICON_BOX_CHILD (child); + gboolean selected; + + selected = gtk_flow_box_child_is_selected (GTK_FLOW_BOX_CHILD (self)); + return selected; +} + +static gboolean +gd_main_icon_box_child_get_selection_mode (GdMainIconBoxChild *self) +{ + GdMainIconBoxChildPrivate *priv; + + priv = gd_main_icon_box_child_get_instance_private (self); + return priv->selection_mode; +} + +static gboolean +gd_main_icon_box_child_get_show_primary_text (GdMainIconBoxChild *self) +{ + GdMainIconBoxChildPrivate *priv; + + priv = gd_main_icon_box_child_get_instance_private (self); + return priv->show_primary_text; +} + +static gboolean +gd_main_icon_box_child_get_show_secondary_text (GdMainIconBoxChild *self) +{ + GdMainIconBoxChildPrivate *priv; + + priv = gd_main_icon_box_child_get_instance_private (self); + return priv->show_secondary_text; +} + +static void +gd_main_icon_box_child_set_item (GdMainIconBoxChild *self, GdMainBoxItem *item) +{ + GdMainIconBoxChildPrivate *priv; + + priv = gd_main_icon_box_child_get_instance_private (self); + + if (priv->item != NULL) + g_signal_handlers_disconnect_by_func (priv->item, gd_main_icon_box_child_notify_pulse, self); + + if (!g_set_object (&priv->item, item)) + return; + + if (priv->item != NULL) + { + g_signal_connect_object (priv->item, + "notify::pulse", + G_CALLBACK (gd_main_icon_box_child_notify_pulse), + self, + G_CONNECT_SWAPPED); + } + + g_object_notify (G_OBJECT (self), "item"); + gtk_widget_queue_draw (GTK_WIDGET (self)); +} + +static void +gd_main_icon_box_child_set_selected (GdMainBoxChild *child, gboolean selected) +{ + GdMainIconBoxChild *self = GD_MAIN_ICON_BOX_CHILD (child); + GdMainIconBoxChildPrivate *priv; + + priv = gd_main_icon_box_child_get_instance_private (self); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->check_button), selected); +} + +static void +gd_main_icon_box_child_set_selection_mode (GdMainIconBoxChild *self, gboolean selection_mode) +{ + GdMainIconBoxChildPrivate *priv; + + priv = gd_main_icon_box_child_get_instance_private (self); + + if (priv->selection_mode == selection_mode) + return; + + priv->selection_mode = selection_mode; + g_object_notify (G_OBJECT (self), "selection-mode"); + gtk_widget_queue_draw (GTK_WIDGET (self)); +} + +static void +gd_main_icon_box_child_set_show_primary_text (GdMainIconBoxChild *self, gboolean show_primary_text) +{ + GdMainIconBoxChildPrivate *priv; + + priv = gd_main_icon_box_child_get_instance_private (self); + + if (priv->show_primary_text == show_primary_text) + return; + + priv->show_primary_text = show_primary_text; + gd_main_icon_box_child_update_layout (self); + g_object_notify (G_OBJECT (self), "show-primary-text"); +} + +static void +gd_main_icon_box_child_set_show_secondary_text (GdMainIconBoxChild *self, gboolean show_secondary_text) +{ + GdMainIconBoxChildPrivate *priv; + + priv = gd_main_icon_box_child_get_instance_private (self); + + if (priv->show_secondary_text == show_secondary_text) + return; + + priv->show_secondary_text = show_secondary_text; + gd_main_icon_box_child_update_layout (self); + g_object_notify (G_OBJECT (self), "show-secondary-text"); +} + +static void +gd_main_icon_box_child_constructed (GObject *obj) +{ + GdMainIconBoxChild *self = GD_MAIN_ICON_BOX_CHILD (obj); + + G_OBJECT_CLASS (gd_main_icon_box_child_parent_class)->constructed (obj); + + gd_main_icon_box_child_update_layout (self); +} + +static void +gd_main_icon_box_child_dispose (GObject *obj) +{ + GdMainIconBoxChild *self = GD_MAIN_ICON_BOX_CHILD (obj); + GdMainIconBoxChildPrivate *priv; + + priv = gd_main_icon_box_child_get_instance_private (self); + + g_clear_object (&priv->item); + + G_OBJECT_CLASS (gd_main_icon_box_child_parent_class)->dispose (obj); +} + +static void +gd_main_icon_box_child_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) +{ + GdMainIconBoxChild *self = GD_MAIN_ICON_BOX_CHILD (object); + + switch (property_id) + { + case PROP_ITEM: + g_value_set_object (value, gd_main_icon_box_child_get_item (GD_MAIN_BOX_CHILD (self))); + break; + case PROP_SELECTION_MODE: + g_value_set_boolean (value, gd_main_icon_box_child_get_selection_mode (self)); + break; + case PROP_SHOW_PRIMARY_TEXT: + g_value_set_boolean (value, gd_main_icon_box_child_get_show_primary_text (self)); + break; + case PROP_SHOW_SECONDARY_TEXT: + g_value_set_boolean (value, gd_main_icon_box_child_get_show_secondary_text (self)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gd_main_icon_box_child_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) +{ + GdMainIconBoxChild *self = GD_MAIN_ICON_BOX_CHILD (object); + + switch (property_id) + { + case PROP_ITEM: + gd_main_icon_box_child_set_item (self, g_value_get_object (value)); + break; + case PROP_SELECTION_MODE: + gd_main_icon_box_child_set_selection_mode (self, g_value_get_boolean (value)); + break; + case PROP_SHOW_PRIMARY_TEXT: + gd_main_icon_box_child_set_show_primary_text (self, g_value_get_boolean (value)); + break; + case PROP_SHOW_SECONDARY_TEXT: + gd_main_icon_box_child_set_show_secondary_text (self, g_value_get_boolean (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gd_main_icon_box_child_init (GdMainIconBoxChild *self) +{ + GtkStyleContext *context; + + context = gtk_widget_get_style_context (GTK_WIDGET (self)); + gtk_style_context_add_class (context, "tile"); +} + +static void +gd_main_icon_box_child_class_init (GdMainIconBoxChildClass *klass) +{ + GObjectClass *oclass = G_OBJECT_CLASS (klass); + + oclass->constructed = gd_main_icon_box_child_constructed; + oclass->dispose = gd_main_icon_box_child_dispose; + oclass->get_property = gd_main_icon_box_child_get_property; + oclass->set_property = gd_main_icon_box_child_set_property; + + g_object_class_override_property (oclass, PROP_ITEM, "item"); + g_object_class_override_property (oclass, PROP_SELECTION_MODE, "selection-mode"); + g_object_class_override_property (oclass, PROP_SHOW_PRIMARY_TEXT, "show-primary-text"); + g_object_class_override_property (oclass, PROP_SHOW_SECONDARY_TEXT, "show-secondary-text"); +} + +static void +gd_main_box_child_interface_init (GdMainBoxChildInterface *iface) +{ + iface->get_index = gd_main_icon_box_child_get_index; + iface->get_item = gd_main_icon_box_child_get_item; + iface->get_selected = gd_main_icon_box_child_get_selected; + iface->set_selected = gd_main_icon_box_child_set_selected; +} + +GtkWidget * +gd_main_icon_box_child_new (GdMainBoxItem *item, gboolean selection_mode) +{ + return g_object_new (GD_TYPE_MAIN_ICON_BOX_CHILD, + "item", item, + "selection-mode", selection_mode, + NULL); +} diff --git a/subprojects/libgd/libgd/gd-main-icon-box-child.h b/subprojects/libgd/libgd/gd-main-icon-box-child.h new file mode 100644 index 00000000..40eb2716 --- /dev/null +++ b/subprojects/libgd/libgd/gd-main-icon-box-child.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2016 Red Hat, Inc. + * + * This program 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 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 Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Author: Debarshi Ray <debarshir@gnome.org> + * + */ + +#ifndef __GD_MAIN_ICON_BOX_CHILD_H__ +#define __GD_MAIN_ICON_BOX_CHILD_H__ + +#include <gtk/gtk.h> + +#include "gd-main-box-item.h" + +G_BEGIN_DECLS + +#define GD_TYPE_MAIN_ICON_BOX_CHILD gd_main_icon_box_child_get_type() +G_DECLARE_DERIVABLE_TYPE (GdMainIconBoxChild, gd_main_icon_box_child, GD, MAIN_ICON_BOX_CHILD, GtkFlowBoxChild) + +struct _GdMainIconBoxChildClass +{ + GtkFlowBoxChildClass parent_class; +}; + +GtkWidget * gd_main_icon_box_child_new (GdMainBoxItem *item, gboolean selection_mode); + +G_END_DECLS + +#endif /* __GD_MAIN_ICON_BOX_CHILD_H__ */ diff --git a/subprojects/libgd/libgd/gd-main-icon-box-icon.c b/subprojects/libgd/libgd/gd-main-icon-box-icon.c new file mode 100644 index 00000000..54fa139f --- /dev/null +++ b/subprojects/libgd/libgd/gd-main-icon-box-icon.c @@ -0,0 +1,366 @@ +/* + * Copyright (c) 2017 Red Hat, Inc. + * + * This program 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 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 Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Author: Debarshi Ray <debarshir@gnome.org> + * + */ + +#include "gd-main-icon-box-icon.h" + +#include <cairo.h> +#include <glib.h> + +struct _GdMainIconBoxIcon +{ + GtkDrawingArea parent_instance; + GdMainBoxItem *item; + cairo_surface_t *surface_zoomed; + gdouble x; + gdouble y; +}; + +enum +{ + PROP_ITEM = 1, + NUM_PROPERTIES +}; + +static GParamSpec *properties[NUM_PROPERTIES] = { NULL, }; + +G_DEFINE_TYPE (GdMainIconBoxIcon, gd_main_icon_box_icon, GTK_TYPE_DRAWING_AREA) + +static cairo_surface_t * +gd_zoom_image_surface (cairo_surface_t *surface, gint width_zoomed, gint height_zoomed) +{ + cairo_t *cr; + cairo_format_t format; + cairo_pattern_t *pattern; + cairo_surface_t *zoomed = NULL; + cairo_surface_type_t surface_type; + gdouble scale_x; + gdouble scale_y; + gdouble zoom_x; + gdouble zoom_y; + gint height; + gint width; + + g_return_val_if_fail (surface != NULL, NULL); + + surface_type = cairo_surface_get_type (surface); + g_return_val_if_fail (surface_type == CAIRO_SURFACE_TYPE_IMAGE, NULL); + + format = cairo_image_surface_get_format (surface); + zoomed = cairo_surface_create_similar_image (surface, format, width_zoomed, height_zoomed); + cairo_surface_get_device_scale (surface, &scale_x, &scale_y); + cairo_surface_set_device_scale (zoomed, scale_x, scale_y); + + cr = cairo_create (zoomed); + + pattern = cairo_get_source (cr); + cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REFLECT); + cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); + + height = cairo_image_surface_get_height (surface); + width = cairo_image_surface_get_width (surface); + zoom_x = (double) width_zoomed / (gdouble) width; + zoom_y = (double) height_zoomed / (gdouble) height; + cairo_scale (cr, zoom_x, zoom_y); + cairo_set_source_surface (cr, surface, 0, 0); + + cairo_paint (cr); + cairo_destroy (cr); + + return zoomed; +} + +static void +gd_main_icon_box_icon_get_preferred_size (GdMainIconBoxIcon *self, gint *minimum, gint *natural) +{ + cairo_surface_t *surface; + cairo_surface_type_t surface_type; + gint height_scaled; + gint width_scaled; + gint scale_factor; + gint size = 0; + gint size_scaled; + + surface = gd_main_box_item_get_icon (self->item); + if (surface == NULL) + goto out; + + surface_type = cairo_surface_get_type (surface); + g_return_if_fail (surface_type == CAIRO_SURFACE_TYPE_IMAGE); + + scale_factor = gtk_widget_get_scale_factor (GTK_WIDGET (self)); + height_scaled = cairo_image_surface_get_height (surface); + width_scaled = cairo_image_surface_get_width (surface); + + size_scaled = MAX (height_scaled, width_scaled); + size = size_scaled / scale_factor; + + out: + if (minimum != NULL) + *minimum = size; + + if (natural != NULL) + *natural = size; +} + +static void +gd_main_icon_box_icon_notify_icon (GdMainIconBoxIcon *self) +{ + g_clear_pointer (&self->surface_zoomed, cairo_surface_destroy); + gtk_widget_queue_resize (GTK_WIDGET (self)); +} + +static gboolean +gd_main_icon_box_icon_draw (GtkWidget *widget, cairo_t *cr) +{ + GdMainIconBoxIcon *self = GD_MAIN_ICON_BOX_ICON (widget); + + if (self->surface_zoomed == NULL) + goto out; + + cairo_save (cr); + cairo_set_source_surface (cr, self->surface_zoomed, self->x, self->y); + cairo_paint (cr); + cairo_restore (cr); + + out: + return GDK_EVENT_PROPAGATE; +} + +static void +gd_main_icon_box_icon_get_preferred_height (GtkWidget *widget, gint *minimum, gint *natural) +{ + GdMainIconBoxIcon *self = GD_MAIN_ICON_BOX_ICON (widget); + gd_main_icon_box_icon_get_preferred_size (self, minimum, natural); +} + +static void +gd_main_icon_box_icon_get_preferred_width (GtkWidget *widget, gint *minimum, gint *natural) +{ + GdMainIconBoxIcon *self = GD_MAIN_ICON_BOX_ICON (widget); + gd_main_icon_box_icon_get_preferred_size (self, minimum, natural); +} + +static void +gd_main_icon_box_icon_size_allocate (GtkWidget *widget, GtkAllocation *allocation) +{ + GdMainIconBoxIcon *self = GD_MAIN_ICON_BOX_ICON (widget); + cairo_surface_t *surface; + cairo_surface_type_t surface_type; + gdouble zoom; + gint allocation_height_scaled; + gint allocation_width_scaled; + gint height_scaled; + gint height_zoomed_scaled; + gint scale_factor; + gint width_scaled; + gint width_zoomed_scaled; + + GTK_WIDGET_CLASS (gd_main_icon_box_icon_parent_class)->size_allocate (widget, allocation); + + surface = gd_main_box_item_get_icon (self->item); + if (surface == NULL) + { + g_return_if_fail (self->surface_zoomed == NULL); + return; + } + + surface_type = cairo_surface_get_type (surface); + g_return_if_fail (surface_type == CAIRO_SURFACE_TYPE_IMAGE); + + scale_factor = gtk_widget_get_scale_factor (GTK_WIDGET (self)); + + allocation_height_scaled = allocation->height * scale_factor; + allocation_width_scaled = allocation->width * scale_factor; + + if (self->surface_zoomed != NULL) + { + height_zoomed_scaled = cairo_image_surface_get_height (self->surface_zoomed); + width_zoomed_scaled = cairo_image_surface_get_width (self->surface_zoomed); + if (height_zoomed_scaled == allocation_height_scaled && width_zoomed_scaled == allocation_width_scaled) + return; + } + + height_scaled = cairo_image_surface_get_height (surface); + width_scaled = cairo_image_surface_get_width (surface); + + if (height_scaled > width_scaled && allocation_height_scaled > height_scaled) + { + zoom = (gdouble) allocation_height_scaled / (gdouble) height_scaled; + height_zoomed_scaled = allocation_height_scaled; + width_zoomed_scaled = (gint) (zoom * (gdouble) width_scaled + 0.5); + + if (allocation_width_scaled < width_zoomed_scaled) + { + zoom = (gdouble) allocation_width_scaled / (gdouble) width_zoomed_scaled; + height_zoomed_scaled = (gint) (zoom * (gdouble) height_zoomed_scaled + 0.5); + width_zoomed_scaled = allocation_width_scaled; + } + } + else if (height_scaled <= width_scaled && allocation_width_scaled > width_scaled) + { + zoom = (gdouble) allocation_width_scaled / (gdouble) width_scaled; + height_zoomed_scaled = (gint) (zoom * (gdouble) height_scaled + 0.5); + width_zoomed_scaled = allocation_width_scaled; + + if (allocation_height_scaled < height_zoomed_scaled) + { + zoom = (gdouble) allocation_height_scaled / (gdouble) height_zoomed_scaled; + height_zoomed_scaled = allocation_height_scaled; + width_zoomed_scaled = (gint) (zoom * (gdouble) width_zoomed_scaled + 0.5); + } + } + else + { + height_zoomed_scaled = height_scaled; + width_zoomed_scaled = width_scaled; + } + + g_clear_pointer (&self->surface_zoomed, cairo_surface_destroy); + self->surface_zoomed = gd_zoom_image_surface (surface, width_zoomed_scaled, height_zoomed_scaled); + + self->x = (gdouble) (allocation_width_scaled - width_zoomed_scaled) / (2.0 * (gdouble) scale_factor); + self->y = (gdouble) (allocation_height_scaled - height_zoomed_scaled) / (2.0 * (gdouble) scale_factor); +} + +static void +gd_main_icon_box_icon_dispose (GObject *obj) +{ + GdMainIconBoxIcon *self = GD_MAIN_ICON_BOX_ICON (obj); + + g_clear_object (&self->item); + + G_OBJECT_CLASS (gd_main_icon_box_icon_parent_class)->dispose (obj); +} + +static void +gd_main_icon_box_icon_finalize (GObject *obj) +{ + GdMainIconBoxIcon *self = GD_MAIN_ICON_BOX_ICON (obj); + + g_clear_pointer (&self->surface_zoomed, cairo_surface_destroy); + + G_OBJECT_CLASS (gd_main_icon_box_icon_parent_class)->finalize (obj); +} + +static void +gd_main_icon_box_icon_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) +{ + GdMainIconBoxIcon *self = GD_MAIN_ICON_BOX_ICON (object); + + switch (property_id) + { + case PROP_ITEM: + g_value_set_object (value, gd_main_icon_box_icon_get_item (self)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gd_main_icon_box_icon_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) +{ + GdMainIconBoxIcon *self = GD_MAIN_ICON_BOX_ICON (object); + + switch (property_id) + { + case PROP_ITEM: + gd_main_icon_box_icon_set_item (self, g_value_get_object (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gd_main_icon_box_icon_init (GdMainIconBoxIcon *self) +{ +} + +static void +gd_main_icon_box_icon_class_init (GdMainIconBoxIconClass *klass) +{ + GObjectClass *oclass = G_OBJECT_CLASS (klass); + GtkWidgetClass *wclass = GTK_WIDGET_CLASS (klass); + + oclass->dispose = gd_main_icon_box_icon_dispose; + oclass->finalize = gd_main_icon_box_icon_finalize; + oclass->get_property = gd_main_icon_box_icon_get_property; + oclass->set_property = gd_main_icon_box_icon_set_property; + wclass->draw = gd_main_icon_box_icon_draw; + wclass->get_preferred_height = gd_main_icon_box_icon_get_preferred_height; + wclass->get_preferred_width = gd_main_icon_box_icon_get_preferred_width; + wclass->size_allocate = gd_main_icon_box_icon_size_allocate; + + properties[PROP_ITEM] = g_param_spec_object ("item", + "Item", + "An item that is rendered by the widget", + GD_TYPE_MAIN_BOX_ITEM, + G_PARAM_EXPLICIT_NOTIFY | + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties (oclass, NUM_PROPERTIES, properties); +} + +GtkWidget * +gd_main_icon_box_icon_new (GdMainBoxItem *item) +{ + g_return_val_if_fail (item == NULL || GD_IS_MAIN_BOX_ITEM (item), NULL); + return g_object_new (GD_TYPE_MAIN_ICON_BOX_ICON, "item", item, NULL); +} + +GdMainBoxItem * +gd_main_icon_box_icon_get_item (GdMainIconBoxIcon *self) +{ + g_return_val_if_fail (GD_IS_MAIN_ICON_BOX_ICON (self), NULL); + return self->item; +} + +void +gd_main_icon_box_icon_set_item (GdMainIconBoxIcon *self, GdMainBoxItem *item) +{ + g_return_if_fail (GD_IS_MAIN_ICON_BOX_ICON (self)); + g_return_if_fail (item == NULL || GD_IS_MAIN_BOX_ITEM (item)); + + if (self->item == item) + return; + + if (self->item != NULL) + g_signal_handlers_disconnect_by_func (self->item, gd_main_icon_box_icon_notify_icon, self); + + g_clear_pointer (&self->surface_zoomed, cairo_surface_destroy); + g_set_object (&self->item, item); + + if (self->item != NULL) + { + g_signal_connect_object (self->item, + "notify::icon", + G_CALLBACK (gd_main_icon_box_icon_notify_icon), + self, + G_CONNECT_SWAPPED); + } + + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_ITEM]); + gtk_widget_queue_resize (GTK_WIDGET (self)); +} diff --git a/subprojects/libgd/libgd/gd-main-icon-box-icon.h b/subprojects/libgd/libgd/gd-main-icon-box-icon.h new file mode 100644 index 00000000..7189e0e8 --- /dev/null +++ b/subprojects/libgd/libgd/gd-main-icon-box-icon.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2017 Red Hat, Inc. + * + * This program 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 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 Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Author: Debarshi Ray <debarshir@gnome.org> + * + */ + +#ifndef __GD_MAIN_ICON_BOX_ICON_H__ +#define __GD_MAIN_ICON_BOX_ICON_H__ + +#include <gtk/gtk.h> + +#include "gd-main-box-item.h" + +G_BEGIN_DECLS + +#define GD_TYPE_MAIN_ICON_BOX_ICON gd_main_icon_box_icon_get_type() +G_DECLARE_FINAL_TYPE (GdMainIconBoxIcon, gd_main_icon_box_icon, GD, MAIN_ICON_BOX_ICON, GtkDrawingArea) + +GtkWidget * gd_main_icon_box_icon_new (GdMainBoxItem *item); +GdMainBoxItem * gd_main_icon_box_icon_get_item (GdMainIconBoxIcon *self); +void gd_main_icon_box_icon_set_item (GdMainIconBoxIcon *self, GdMainBoxItem *item); + +G_END_DECLS + +#endif /* __GD_MAIN_ICON_BOX_ICON_H__ */ diff --git a/subprojects/libgd/libgd/gd-main-icon-box.c b/subprojects/libgd/libgd/gd-main-icon-box.c new file mode 100644 index 00000000..1d6cdf43 --- /dev/null +++ b/subprojects/libgd/libgd/gd-main-icon-box.c @@ -0,0 +1,1042 @@ +/* + * Copyright (c) 2016, 2017 Red Hat, Inc. + * + * This program 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 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 Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Author: Debarshi Ray <debarshir@gnome.org> + * + */ + +#include <math.h> + +#include <cairo.h> +#include <gio/gio.h> + +#include "gd-icon-utils.h" +#include "gd-main-icon-box.h" +#include "gd-main-icon-box-child.h" +#include "gd-main-box-child.h" +#include "gd-main-box-generic.h" +#include "gd-main-box-item.h" + +#define MAIN_ICON_BOX_DND_ICON_OFFSET 20 + +typedef struct _GdMainIconBoxPrivate GdMainIconBoxPrivate; + +struct _GdMainIconBoxPrivate +{ + GListModel *model; + gboolean dnd_started; + gboolean key_pressed; + gboolean key_shift_pressed; + gboolean left_button_released; + gboolean left_button_shift_released; + gboolean selection_changed; + gboolean selection_mode; + gboolean show_primary_text; + gboolean show_secondary_text; + gchar *last_selected_id; + gdouble dnd_start_x; + gdouble dnd_start_y; + gint dnd_button; +}; + +enum +{ + PROP_LAST_SELECTED_ID = 1, + PROP_MODEL, + PROP_SELECTION_MODE, + PROP_SHOW_PRIMARY_TEXT, + PROP_SHOW_SECONDARY_TEXT, + NUM_PROPERTIES +}; + +static void gd_main_box_generic_interface_init (GdMainBoxGenericInterface *iface); +G_DEFINE_TYPE_WITH_CODE (GdMainIconBox, gd_main_icon_box, GTK_TYPE_FLOW_BOX, + G_ADD_PRIVATE (GdMainIconBox) + G_IMPLEMENT_INTERFACE (GD_TYPE_MAIN_BOX_GENERIC, gd_main_box_generic_interface_init)) + +GtkWidget * +gd_main_icon_box_create_widget_func (gpointer item, gpointer user_data) +{ + GdMainIconBox *self = GD_MAIN_ICON_BOX (user_data); + GdMainIconBoxPrivate *priv; + GtkWidget *child; + + g_return_val_if_fail (GD_IS_MAIN_BOX_ITEM (item), NULL); + + priv = gd_main_icon_box_get_instance_private (self); + + child = gd_main_icon_box_child_new (GD_MAIN_BOX_ITEM (item), priv->selection_mode); + g_object_bind_property (self, "show-primary-text", child, "show-primary-text", G_BINDING_SYNC_CREATE); + g_object_bind_property (self, "show-secondary-text", child, "show-secondary-text", G_BINDING_SYNC_CREATE); + gtk_widget_show_all (child); + + return child; +} + +static void +gd_main_icon_box_update_last_selected_id (GdMainIconBox *self, GdMainBoxChild *child) +{ + GdMainIconBoxPrivate *priv; + GdMainBoxItem *item; + const gchar *id = NULL; + + priv = gd_main_icon_box_get_instance_private (self); + + if (child != NULL) + { + item = gd_main_box_child_get_item (child); + id = gd_main_box_item_get_id (item); + } + + if (g_strcmp0 (priv->last_selected_id, id) != 0) + { + g_free (priv->last_selected_id); + priv->last_selected_id = g_strdup (id); + g_object_notify (G_OBJECT (self), "last-selected-id"); + } +} + +static GdMainBoxChild * +gd_main_icon_box_get_child_at_index (GdMainBoxGeneric *generic, gint index) +{ + GdMainIconBox *self = GD_MAIN_ICON_BOX (generic); + GtkFlowBoxChild *child; + + child = gtk_flow_box_get_child_at_index (GTK_FLOW_BOX (self), index); + return GD_MAIN_BOX_CHILD (child); +} + +static const gchar * +gd_main_icon_box_get_last_selected_id (GdMainBoxGeneric *generic) +{ + GdMainIconBox *self = GD_MAIN_ICON_BOX (generic); + GdMainIconBoxPrivate *priv; + + priv = gd_main_icon_box_get_instance_private (self); + return priv->last_selected_id; +} + +static GListModel * +gd_main_icon_box_get_model (GdMainBoxGeneric *generic) +{ + GdMainIconBox *self = GD_MAIN_ICON_BOX (generic); + GdMainIconBoxPrivate *priv; + + priv = gd_main_icon_box_get_instance_private (self); + return priv->model; +} + +static GList * +gd_main_icon_box_get_selected_children (GdMainBoxGeneric *generic) +{ + GdMainIconBox *self = GD_MAIN_ICON_BOX (generic); + GList *selected_children; + + selected_children = gtk_flow_box_get_selected_children (GTK_FLOW_BOX (self)); + return selected_children; +} + +static gboolean +gd_main_icon_box_get_selection_mode (GdMainIconBox *self) +{ + GdMainIconBoxPrivate *priv; + + priv = gd_main_icon_box_get_instance_private (self); + return priv->selection_mode; +} + +static gboolean +gd_main_icon_box_get_show_primary_text (GdMainIconBox *self) +{ + GdMainIconBoxPrivate *priv; + + priv = gd_main_icon_box_get_instance_private (self); + return priv->show_primary_text; +} + +static gboolean +gd_main_icon_box_get_show_secondary_text (GdMainIconBox *self) +{ + GdMainIconBoxPrivate *priv; + + priv = gd_main_icon_box_get_instance_private (self); + return priv->show_secondary_text; +} + +static void +gd_main_icon_box_select_all_generic (GdMainBoxGeneric *generic) +{ + GdMainIconBox *self = GD_MAIN_ICON_BOX (generic); + g_signal_emit_by_name (self, "select-all"); +} + +static void +gd_main_icon_box_select_child (GdMainBoxGeneric *generic, GdMainBoxChild *child) +{ + GdMainIconBox *self = GD_MAIN_ICON_BOX (generic); + gtk_flow_box_select_child (GTK_FLOW_BOX (self), GTK_FLOW_BOX_CHILD (child)); +} + +static void +gd_main_icon_box_set_model (GdMainIconBox *self, GListModel *model) +{ + GdMainIconBoxPrivate *priv; + + priv = gd_main_icon_box_get_instance_private (self); + + if (!g_set_object (&priv->model, model)) + return; + + gtk_flow_box_bind_model (GTK_FLOW_BOX (self), + priv->model, + gd_main_icon_box_create_widget_func, + self, + NULL); + + g_object_notify (G_OBJECT (self), "model"); +} + +static void +gd_main_icon_box_set_selection_mode (GdMainIconBox *self, gboolean selection_mode) +{ + GdMainIconBoxPrivate *priv; + GList *children; + GList *l; + + priv = gd_main_icon_box_get_instance_private (self); + + if (priv->selection_mode == selection_mode) + return; + + gd_main_icon_box_update_last_selected_id (self, NULL); + + priv->selection_mode = selection_mode; + if (priv->selection_mode) + gtk_flow_box_set_selection_mode (GTK_FLOW_BOX (self), GTK_SELECTION_MULTIPLE); + else + gtk_flow_box_set_selection_mode (GTK_FLOW_BOX (self), GTK_SELECTION_NONE); + + children = gtk_container_get_children (GTK_CONTAINER (self)); + for (l = children; l != NULL; l = l->next) + { + GdMainBoxChild *child = GD_MAIN_BOX_CHILD (l->data); + gd_main_box_child_set_selection_mode (child, priv->selection_mode); + } + + g_object_notify (G_OBJECT (self), "last-selected-id"); + g_object_notify (G_OBJECT (self), "selection-mode"); + + g_list_free (children); +} + +static void +gd_main_icon_box_set_show_primary_text (GdMainIconBox *self, gboolean show_primary_text) +{ + GdMainIconBoxPrivate *priv; + + priv = gd_main_icon_box_get_instance_private (self); + + if (priv->show_primary_text == show_primary_text) + return; + + priv->show_primary_text = show_primary_text; + g_object_notify (G_OBJECT (self), "show-primary-text"); +} + +static void +gd_main_icon_box_set_show_secondary_text (GdMainIconBox *self, gboolean show_secondary_text) +{ + GdMainIconBoxPrivate *priv; + + priv = gd_main_icon_box_get_instance_private (self); + + if (priv->show_secondary_text == show_secondary_text) + return; + + priv->show_secondary_text = show_secondary_text; + g_object_notify (G_OBJECT (self), "show-secondary-text"); +} + +static void +gd_main_icon_box_unselect_all_generic (GdMainBoxGeneric *generic) +{ + GdMainIconBox *self = GD_MAIN_ICON_BOX (generic); + g_signal_emit_by_name (self, "unselect-all"); +} + +static void +gd_main_icon_box_unselect_child (GdMainBoxGeneric *generic, GdMainBoxChild *child) +{ + GdMainIconBox *self = GD_MAIN_ICON_BOX (generic); + gtk_flow_box_unselect_child (GTK_FLOW_BOX (self), GTK_FLOW_BOX_CHILD (child)); +} + +static void +gd_main_icon_box_activate_cursor_child (GtkFlowBox *flow_box) +{ + GdMainIconBox *self = GD_MAIN_ICON_BOX (flow_box); + GdMainIconBoxPrivate *priv; + GdkEvent *event = NULL; + gboolean initiating = FALSE; + + priv = gd_main_icon_box_get_instance_private (self); + + /* Use GtkFlowBox::activate-cursor-child instead of + * GtkWidget::key-press-event to catch key presses because it is + * easier to filter out non-activation keys. + */ + + event = gtk_get_current_event (); + if (event == NULL) + goto out; + + if (event->type != GDK_KEY_PRESS) + goto out; + + if (!priv->selection_mode && (event->key.state & GDK_CONTROL_MASK) != 0) + { + g_signal_emit_by_name (self, "selection-mode-request"); + initiating = TRUE; + } + + if (priv->selection_mode) + { + if (!initiating && (event->key.state & GDK_SHIFT_MASK) != 0) + priv->key_shift_pressed = TRUE; + + priv->key_pressed = TRUE; + } + + out: + GTK_FLOW_BOX_CLASS (gd_main_icon_box_parent_class)->activate_cursor_child (flow_box); + g_clear_pointer (&event, gdk_event_free); +} + +static gboolean +gd_main_icon_box_button_press_event (GtkWidget *widget, GdkEventButton *event) +{ + GdMainIconBox *self = GD_MAIN_ICON_BOX (widget); + GdMainIconBoxPrivate *priv; + GtkFlowBoxChild *child; + gboolean res; + + priv = gd_main_icon_box_get_instance_private (self); + + if (event->type != GDK_BUTTON_PRESS) + { + res = GDK_EVENT_STOP; + goto out; + } + + if (event->button != GDK_BUTTON_PRIMARY) + goto default_behavior; + + child = gtk_flow_box_get_child_at_pos (GTK_FLOW_BOX (self), (gint) event->x, (gint) event->y); + if (child == NULL) + goto default_behavior; + + if (priv->selection_mode && !gtk_flow_box_child_is_selected (child)) + goto default_behavior; + + priv->dnd_button = (gint) event->button; + priv->dnd_start_x = event->x; + priv->dnd_start_y = event->y; + + default_behavior: + res = GTK_WIDGET_CLASS (gd_main_icon_box_parent_class)->button_press_event (widget, event); + + out: + return res; +} + +static gboolean +gd_main_icon_box_button_release_event (GtkWidget *widget, GdkEventButton *event) +{ + GdMainIconBox *self = GD_MAIN_ICON_BOX (widget); + GdMainIconBoxPrivate *priv; + GtkFlowBoxChild *child = NULL; + gboolean initiating = FALSE; + gboolean res; + + priv = gd_main_icon_box_get_instance_private (self); + + priv->dnd_button = -1; + priv->dnd_start_x = -1.0; + priv->dnd_start_y = -1.0; + priv->dnd_started = FALSE; + + if (event->type != GDK_BUTTON_RELEASE) + { + res = GDK_EVENT_STOP; + goto out; + } + + if (!priv->selection_mode && + ((event->button == GDK_BUTTON_PRIMARY && (event->state & GDK_CONTROL_MASK) != 0) || + event->button == GDK_BUTTON_SECONDARY)) + { + g_signal_emit_by_name (self, "selection-mode-request"); + initiating = TRUE; + } + + if (priv->selection_mode) + { + if (event->button == GDK_BUTTON_PRIMARY) + { + /* GtkFlowBox doesn't do range selection. It will simply + * select a single child for shift + left-click. We need to + * detect it so that we can handle it later. + * + * However, range selection is only possible if we were + * already in the selection mode. Therefore, skip it if we + * have just requested the selection mode. + */ + if (!initiating && (event->state & GDK_SHIFT_MASK) != 0) + priv->left_button_shift_released = TRUE; + + priv->left_button_released = TRUE; + } + else if (event->button == GDK_BUTTON_SECONDARY) + { + /* GtkFlowBox completely ignores the right mouse + * button. + */ + + child = gtk_flow_box_get_child_at_pos (GTK_FLOW_BOX (self), (gint) event->x, (gint) event->y); + if (child != NULL) + { + gd_main_box_generic_toggle_selection_for_child (GD_MAIN_BOX_GENERIC (self), + GD_MAIN_BOX_CHILD (child), + (!initiating && + (event->state & GDK_SHIFT_MASK) != 0)); + } + } + } + + /* This is for right-clicks and rubberband selection. + * + * Rubberband selection is unlike other modes of selection because + * GtkFlowBox::selected-children-changed is emitted before the mouse + * button is released. + */ + if (priv->selection_changed) + { + g_signal_emit_by_name (self, "selection-changed"); + gd_main_icon_box_update_last_selected_id (self, GD_MAIN_BOX_CHILD (child)); + priv->selection_changed = FALSE; + } + + res = GTK_WIDGET_CLASS (gd_main_icon_box_parent_class)->button_release_event (widget, event); + + out: + return res; +} + +static void +gd_main_icon_box_child_activated (GtkFlowBox *flow_box, GtkFlowBoxChild *child) +{ + GdMainIconBox *self = GD_MAIN_ICON_BOX (flow_box); + GdMainIconBoxPrivate *priv; + GdkEvent *event = NULL; + + g_return_if_fail (GD_IS_MAIN_BOX_CHILD (child)); + + priv = gd_main_icon_box_get_instance_private (self); + + /* GtkFlowBox might emit child-activated in the middle of a + * DnD. See https://bugzilla.gnome.org/show_bug.cgi?id=776306 + */ + if (priv->dnd_started) + goto out; + + if (!priv->selection_mode) + { + g_signal_emit_by_name (self, "item-activated", GD_MAIN_BOX_CHILD (child)); + goto out; + } + + event = gtk_get_current_event (); + if (event == NULL) + goto out; + + if (priv->left_button_released && !priv->selection_changed) + { + /* If a selected child is left-clicked, GtkFlowBox will activate + * it without unselecting it. + */ + gd_main_box_generic_toggle_selection_for_child (GD_MAIN_BOX_GENERIC (self), + GD_MAIN_BOX_CHILD (child), + FALSE); /* One cannot unselect a range. */ + priv->left_button_released = FALSE; + g_signal_emit_by_name (self, "selection-changed"); + } + else if (priv->key_pressed && !priv->selection_changed) + { + /* If a selected child is activated by a keybinding, GtkFlowBox + * will not unselect it. + */ + gd_main_box_generic_toggle_selection_for_child (GD_MAIN_BOX_GENERIC (self), GD_MAIN_BOX_CHILD (child), FALSE); + priv->key_pressed = FALSE; + g_signal_emit_by_name (self, "selection-changed"); + } + else if (priv->left_button_shift_released || priv->key_shift_pressed) + { + /* GtkFlowBox doesn't do range selection and simply selects a + * single child. We handle it by unselecting the child and then + * selecting the range. + */ + gd_main_box_generic_toggle_selection_for_child (GD_MAIN_BOX_GENERIC (self), GD_MAIN_BOX_CHILD (child), FALSE); + priv->left_button_shift_released = FALSE; + priv->key_shift_pressed = FALSE; + gd_main_box_generic_toggle_selection_for_child (GD_MAIN_BOX_GENERIC (self), GD_MAIN_BOX_CHILD (child), TRUE); + g_signal_emit_by_name (self, "selection-changed"); + } + else if (priv->selection_changed) + { + /* This is for non-shift left-clicks and keyboard activation of + * unselected children. + */ + g_signal_emit_by_name (self, "selection-changed"); + } + + g_signal_emit_by_name (self, "item-activated", GD_MAIN_BOX_CHILD (child)); + + if (priv->selection_changed) + { + gd_main_icon_box_update_last_selected_id (self, GD_MAIN_BOX_CHILD (child)); + priv->selection_changed = FALSE; + } + + out: + g_clear_pointer (&event, gdk_event_free); +} + +static void +gd_main_icon_box_drag_begin (GtkWidget *widget, GdkDragContext *context) +{ + GdMainIconBox *self = GD_MAIN_ICON_BOX (widget); + GdMainIconBoxPrivate *priv; + GdMainBoxItem *item; + GtkFlowBoxChild *child; + cairo_surface_t *drag_icon = NULL; + cairo_surface_t *icon; + + priv = gd_main_icon_box_get_instance_private (self); + + if (priv->dnd_start_x < 0.0 || priv->dnd_start_y < 0.0) + goto out; + + child = gtk_flow_box_get_child_at_pos (GTK_FLOW_BOX (self), + (gint) priv->dnd_start_x, + (gint) priv->dnd_start_y); + if (child == NULL) + goto out; + + item = gd_main_box_child_get_item (GD_MAIN_BOX_CHILD (child)); + icon = gd_main_box_item_get_icon (item); + if (icon == NULL) + goto out; + + if (priv->selection_mode) + { + GList *selected_children; + guint length; + + selected_children = gtk_flow_box_get_selected_children (GTK_FLOW_BOX (self)); + length = g_list_length (selected_children); + if (length > 1) + drag_icon = gd_create_surface_with_counter (GTK_WIDGET (self), icon, length); + + g_list_free (selected_children); + } + + if (drag_icon == NULL) + drag_icon = gd_copy_image_surface (icon); + + cairo_surface_set_device_offset (drag_icon, -MAIN_ICON_BOX_DND_ICON_OFFSET, -MAIN_ICON_BOX_DND_ICON_OFFSET); + gtk_drag_set_icon_surface (context, drag_icon); + + out: + g_clear_pointer (&drag_icon, cairo_surface_destroy); +} + +static void +gd_main_icon_box_add_child_uri_to_array (GdMainBoxChild *child, GPtrArray *uri_array) +{ + GdMainBoxItem *item; + const gchar *uri; + + item = gd_main_box_child_get_item (child); + uri = gd_main_box_item_get_uri (item); + g_ptr_array_add (uri_array, g_strdup (uri)); +} + +static void +gd_main_icon_box_drag_data_get (GtkWidget *widget, + GdkDragContext *context, + GtkSelectionData *data, + guint info, + guint time) +{ + GdMainIconBox *self = GD_MAIN_ICON_BOX (widget); + GdMainIconBoxPrivate *priv; + GPtrArray *uri_array = NULL; + + priv = gd_main_icon_box_get_instance_private (self); + + if (info != 0) + goto out; + + if (priv->dnd_start_x < 0.0 || priv->dnd_start_y < 0.0) + goto out; + + uri_array = g_ptr_array_new_with_free_func (g_free); + + if (priv->selection_mode) + { + GList *l; + GList *selected_children; + + selected_children = gtk_flow_box_get_selected_children (GTK_FLOW_BOX (self)); + for (l = selected_children; l != NULL; l = l->next) + { + GdMainBoxChild *child = GD_MAIN_BOX_CHILD (l->data); + gd_main_icon_box_add_child_uri_to_array (child, uri_array); + } + + g_list_free (selected_children); + } + else + { + GtkFlowBoxChild *child; + + child = gtk_flow_box_get_child_at_pos (GTK_FLOW_BOX (self), + (gint) priv->dnd_start_x, + (gint) priv->dnd_start_y); + + if (child != NULL) + gd_main_icon_box_add_child_uri_to_array (GD_MAIN_BOX_CHILD (child), uri_array); + } + + g_ptr_array_add (uri_array, NULL); + gtk_selection_data_set_uris (data, (gchar **) uri_array->pdata); + + out: + g_clear_pointer (&uri_array, g_ptr_array_unref); +} + +static gboolean +gd_main_icon_box_focus (GtkWidget *widget, GtkDirectionType direction) +{ + GdMainIconBox *self = GD_MAIN_ICON_BOX (widget); + GdMainIconBoxPrivate *priv; + GdkEvent *event = NULL; + GdkEvent *fake_event = NULL; + gboolean res; + + priv = gd_main_icon_box_get_instance_private (self); + + if (!priv->selection_mode) + { + res = GTK_WIDGET_CLASS (gd_main_icon_box_parent_class)->focus (widget, direction); + goto out; + } + + event = gtk_get_current_event (); + if (event->type != GDK_KEY_PRESS && event->type != GDK_KEY_RELEASE) + { + res = GTK_WIDGET_CLASS (gd_main_icon_box_parent_class)->focus (widget, direction); + goto out; + } + + if ((event->key.state & GDK_CONTROL_MASK) != 0) + { + res = GTK_WIDGET_CLASS (gd_main_icon_box_parent_class)->focus (widget, direction); + goto out; + } + + fake_event = gdk_event_copy (event); + fake_event->key.state |= GDK_CONTROL_MASK; + + gtk_main_do_event (fake_event); + res = GDK_EVENT_STOP; + + out: + g_clear_pointer (&fake_event, gdk_event_free); + g_clear_pointer (&event, gdk_event_free); + return res; +} + +static gboolean +gd_main_icon_box_motion_notify_event (GtkWidget *widget, GdkEventMotion *event) +{ + GdMainIconBox *self = GD_MAIN_ICON_BOX (widget); + GdMainIconBoxPrivate *priv; + GtkTargetList *targets; + gboolean res; + gint button; + + priv = gd_main_icon_box_get_instance_private (self); + + if (priv->dnd_button < 0) + goto out; + + if (!gtk_drag_check_threshold (GTK_WIDGET (self), + (gint) priv->dnd_start_x, + (gint) priv->dnd_start_y, + (gint) event->x, + (gint) event->y)) + goto out; + + button = priv->dnd_button; + priv->dnd_button = -1; + priv->dnd_started = TRUE; + + targets = gtk_drag_source_get_target_list (GTK_WIDGET (self)); + + gtk_drag_begin_with_coordinates (GTK_WIDGET (self), + targets, + GDK_ACTION_COPY, + button, + (GdkEvent *) event, + (gint) priv->dnd_start_x, + (gint) priv->dnd_start_y); + + out: + res = GTK_WIDGET_CLASS (gd_main_icon_box_parent_class)->motion_notify_event (widget, event); + return res; +} + +static gboolean +gd_main_icon_box_move_cursor (GtkFlowBox *flow_box, GtkMovementStep step, gint count) +{ + GdMainIconBox *self = GD_MAIN_ICON_BOX (flow_box); + GdMainIconBoxPrivate *priv; + GdkEvent *event = NULL; + GdkEvent *fake_event = NULL; + gboolean res; + + priv = gd_main_icon_box_get_instance_private (self); + + if (!priv->selection_mode) + { + res = GTK_FLOW_BOX_CLASS (gd_main_icon_box_parent_class)->move_cursor (flow_box, step, count); + goto out; + } + + event = gtk_get_current_event (); + if (event->type != GDK_KEY_PRESS && event->type != GDK_KEY_RELEASE) + { + res = GTK_FLOW_BOX_CLASS (gd_main_icon_box_parent_class)->move_cursor (flow_box, step, count); + goto out; + } + + if ((event->key.state & GDK_CONTROL_MASK) != 0 && (event->key.state & GDK_SHIFT_MASK) == 0) + { + res = GTK_FLOW_BOX_CLASS (gd_main_icon_box_parent_class)->move_cursor (flow_box, step, count); + goto out; + } + + fake_event = gdk_event_copy (event); + fake_event->key.state |= GDK_CONTROL_MASK; + fake_event->key.state &= ~GDK_SHIFT_MASK; + + gtk_main_do_event (fake_event); + res = GDK_EVENT_STOP; + + out: + g_clear_pointer (&fake_event, gdk_event_free); + g_clear_pointer (&event, gdk_event_free); + return res; +} + +static void +gd_main_icon_box_remove (GtkContainer *container, GtkWidget *widget) +{ + GdMainIconBox *self = GD_MAIN_ICON_BOX (container); + GdMainIconBoxPrivate *priv; + + priv = gd_main_icon_box_get_instance_private (self); + + GTK_CONTAINER_CLASS (gd_main_icon_box_parent_class)->remove (container, widget); + + if (priv->selection_changed) + { + g_signal_emit_by_name (self, "selection-changed"); + priv->selection_changed = FALSE; + } +} + +static void +gd_main_icon_box_select_all_flow_box (GtkFlowBox *flow_box) +{ + GdMainIconBox *self = GD_MAIN_ICON_BOX (flow_box); + GdMainIconBoxPrivate *priv; + + priv = gd_main_icon_box_get_instance_private (self); + + GTK_FLOW_BOX_CLASS (gd_main_icon_box_parent_class)->select_all (flow_box); + + if (priv->selection_changed) + { + g_signal_emit_by_name (self, "selection-changed"); + priv->selection_changed = FALSE; + } +} + +static void +gd_main_icon_box_selected_children_changed (GtkFlowBox *flow_box) +{ + GdMainIconBox *self = GD_MAIN_ICON_BOX (flow_box); + GdMainIconBoxPrivate *priv; + + priv = gd_main_icon_box_get_instance_private (self); + + GTK_FLOW_BOX_CLASS (gd_main_icon_box_parent_class)->selected_children_changed (flow_box); + + priv->selection_changed = TRUE; + + /* When a range selection is attempted, we override GtkFlowBox's + * default behaviour by changing the selection ourselves. Therefore, + * there is no need to update the check buttons until the final + * selection is available. + */ + if (!priv->key_shift_pressed && !priv->left_button_shift_released) + { + GList *children; + GList *l; + + children = gtk_container_get_children (GTK_CONTAINER (self)); + for (l = children; l != NULL; l = l->next) + { + GtkFlowBoxChild *child = GTK_FLOW_BOX_CHILD (l->data); + gboolean selected; + + /* Work around the fact that GtkFlowBoxChild:selected is not + * a property. + */ + selected = gtk_flow_box_child_is_selected (child); + gd_main_box_child_set_selected (GD_MAIN_BOX_CHILD (child), selected); + } + + g_list_free (children); + } +} + +static void +gd_main_icon_box_unselect_all_flow_box (GtkFlowBox *flow_box) +{ + GdMainIconBox *self = GD_MAIN_ICON_BOX (flow_box); + GdMainIconBoxPrivate *priv; + + priv = gd_main_icon_box_get_instance_private (self); + + GTK_FLOW_BOX_CLASS (gd_main_icon_box_parent_class)->unselect_all (flow_box); + + if (priv->selection_changed) + { + g_signal_emit_by_name (self, "selection-changed"); + priv->selection_changed = FALSE; + } +} + +static void +gd_main_icon_box_dispose (GObject *obj) +{ + GdMainIconBox *self = GD_MAIN_ICON_BOX (obj); + GdMainIconBoxPrivate *priv; + + priv = gd_main_icon_box_get_instance_private (self); + + g_clear_object (&priv->model); + + G_OBJECT_CLASS (gd_main_icon_box_parent_class)->dispose (obj); +} + +static void +gd_main_icon_box_finalize (GObject *obj) +{ + GdMainIconBox *self = GD_MAIN_ICON_BOX (obj); + GdMainIconBoxPrivate *priv; + + priv = gd_main_icon_box_get_instance_private (self); + + g_free (priv->last_selected_id); + + G_OBJECT_CLASS (gd_main_icon_box_parent_class)->finalize (obj); +} + +static void +gd_main_icon_box_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) +{ + GdMainIconBox *self = GD_MAIN_ICON_BOX (object); + + switch (property_id) + { + case PROP_LAST_SELECTED_ID: + g_value_set_string (value, gd_main_icon_box_get_last_selected_id (GD_MAIN_BOX_GENERIC (self))); + break; + case PROP_MODEL: + g_value_set_object (value, gd_main_icon_box_get_model (GD_MAIN_BOX_GENERIC (self))); + break; + case PROP_SELECTION_MODE: + g_value_set_boolean (value, gd_main_icon_box_get_selection_mode (self)); + break; + case PROP_SHOW_PRIMARY_TEXT: + g_value_set_boolean (value, gd_main_icon_box_get_show_primary_text (self)); + break; + case PROP_SHOW_SECONDARY_TEXT: + g_value_set_boolean (value, gd_main_icon_box_get_show_secondary_text (self)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gd_main_icon_box_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) +{ + GdMainIconBox *self = GD_MAIN_ICON_BOX (object); + + switch (property_id) + { + case PROP_MODEL: + gd_main_icon_box_set_model (self, g_value_get_object (value)); + break; + case PROP_SELECTION_MODE: + gd_main_icon_box_set_selection_mode (self, g_value_get_boolean (value)); + break; + case PROP_SHOW_PRIMARY_TEXT: + gd_main_icon_box_set_show_primary_text (self, g_value_get_boolean (value)); + break; + case PROP_SHOW_SECONDARY_TEXT: + gd_main_icon_box_set_show_secondary_text (self, g_value_get_boolean (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gd_main_icon_box_init (GdMainIconBox *self) +{ + GdMainIconBoxPrivate *priv; + const GtkTargetEntry targets[] = { { (gchar *) "text/uri-list", GTK_TARGET_OTHER_APP, 0 } }; + + priv = gd_main_icon_box_get_instance_private (self); + + gtk_widget_set_can_focus (GTK_WIDGET (self), TRUE); + gtk_flow_box_set_homogeneous (GTK_FLOW_BOX (self), TRUE); + gtk_flow_box_set_min_children_per_line (GTK_FLOW_BOX (self), 3); + gtk_flow_box_set_selection_mode (GTK_FLOW_BOX (self), GTK_SELECTION_NONE); + + /* We need to ensure that rubberband selection and DnD don't step + * on each others toes. We set start_button_mask to 0 to retain + * control over when to begin a drag. + */ + gtk_drag_source_set (GTK_WIDGET (self), 0, targets, G_N_ELEMENTS (targets), GDK_ACTION_COPY); + + priv->dnd_button = -1; + priv->dnd_start_x = -1.0; + priv->dnd_start_y = -1.0; +} + +static void +gd_main_icon_box_class_init (GdMainIconBoxClass *klass) +{ + GObjectClass *oclass = G_OBJECT_CLASS (klass); + GtkContainerClass *cclass = GTK_CONTAINER_CLASS (klass); + GtkFlowBoxClass *fbclass = GTK_FLOW_BOX_CLASS (klass); + GtkWidgetClass *wclass = GTK_WIDGET_CLASS (klass); + GtkBindingSet *binding_set; + GdkModifierType activate_modifiers[] = { 0, /* Otherwise it will go to GtkFlowBoxChild::activate. */ + GDK_SHIFT_MASK, + GDK_CONTROL_MASK, + GDK_SHIFT_MASK | GDK_CONTROL_MASK }; + guint i; + + binding_set = gtk_binding_set_by_class (klass); + + oclass->dispose = gd_main_icon_box_dispose; + oclass->finalize = gd_main_icon_box_finalize; + oclass->get_property = gd_main_icon_box_get_property; + oclass->set_property = gd_main_icon_box_set_property; + wclass->button_press_event = gd_main_icon_box_button_press_event; + wclass->button_release_event = gd_main_icon_box_button_release_event; + wclass->drag_begin = gd_main_icon_box_drag_begin; + wclass->drag_data_get = gd_main_icon_box_drag_data_get; + wclass->focus = gd_main_icon_box_focus; + wclass->motion_notify_event = gd_main_icon_box_motion_notify_event; + cclass->remove = gd_main_icon_box_remove; + fbclass->activate_cursor_child = gd_main_icon_box_activate_cursor_child; + fbclass->child_activated = gd_main_icon_box_child_activated; + fbclass->move_cursor = gd_main_icon_box_move_cursor; + fbclass->select_all = gd_main_icon_box_select_all_flow_box; + fbclass->selected_children_changed = gd_main_icon_box_selected_children_changed; + fbclass->unselect_all = gd_main_icon_box_unselect_all_flow_box; + + g_object_class_override_property (oclass, PROP_LAST_SELECTED_ID, "last-selected-id"); + g_object_class_override_property (oclass, PROP_MODEL, "model"); + g_object_class_override_property (oclass, PROP_SELECTION_MODE, "gd-selection-mode"); + g_object_class_override_property (oclass, PROP_SHOW_PRIMARY_TEXT, "show-primary-text"); + g_object_class_override_property (oclass, PROP_SHOW_SECONDARY_TEXT, "show-secondary-text"); + + for (i = 0; i < G_N_ELEMENTS (activate_modifiers); i++) + { + gtk_binding_entry_add_signal (binding_set, + GDK_KEY_space, activate_modifiers[i], + "activate-cursor-child", + 0); + gtk_binding_entry_add_signal (binding_set, + GDK_KEY_KP_Space, activate_modifiers[i], + "activate-cursor-child", + 0); + gtk_binding_entry_add_signal (binding_set, + GDK_KEY_Return, activate_modifiers[i], + "activate-cursor-child", + 0); + gtk_binding_entry_add_signal (binding_set, + GDK_KEY_ISO_Enter, activate_modifiers[i], + "activate-cursor-child", + 0); + gtk_binding_entry_add_signal (binding_set, + GDK_KEY_KP_Enter, activate_modifiers[i], + "activate-cursor-child", + 0); + } +} + +static void +gd_main_box_generic_interface_init (GdMainBoxGenericInterface *iface) +{ + iface->get_child_at_index = gd_main_icon_box_get_child_at_index; + iface->get_last_selected_id = gd_main_icon_box_get_last_selected_id; + iface->get_model = gd_main_icon_box_get_model; + iface->get_selected_children = gd_main_icon_box_get_selected_children; + iface->select_all = gd_main_icon_box_select_all_generic; + iface->select_child = gd_main_icon_box_select_child; + iface->unselect_all = gd_main_icon_box_unselect_all_generic; + iface->unselect_child = gd_main_icon_box_unselect_child; +} + +GtkWidget * +gd_main_icon_box_new (void) +{ + return g_object_new (GD_TYPE_MAIN_ICON_BOX, NULL); +} diff --git a/subprojects/libgd/libgd/gd-main-icon-box.h b/subprojects/libgd/libgd/gd-main-icon-box.h new file mode 100644 index 00000000..5dc60fe9 --- /dev/null +++ b/subprojects/libgd/libgd/gd-main-icon-box.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2016 Red Hat, Inc. + * + * This program 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 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 Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Author: Debarshi Ray <debarshir@gnome.org> + * + */ + +#ifndef __GD_MAIN_ICON_BOX_H__ +#define __GD_MAIN_ICON_BOX_H__ + +#include <gtk/gtk.h> + +G_BEGIN_DECLS + +#define GD_TYPE_MAIN_ICON_BOX gd_main_icon_box_get_type() +G_DECLARE_DERIVABLE_TYPE (GdMainIconBox, gd_main_icon_box, GD, MAIN_ICON_BOX, GtkFlowBox) + +struct _GdMainIconBoxClass +{ + GtkFlowBoxClass parent_class; + + /* signals */ + gboolean (* move_cursor) (GdMainIconBox *self, GtkMovementStep step, gint count); +}; + +GtkWidget * gd_main_icon_box_new (void); + +G_END_DECLS + +#endif /* __GD_MAIN_ICON_BOX_H__ */ diff --git a/subprojects/libgd/libgd/gd-main-icon-view.c b/subprojects/libgd/libgd/gd-main-icon-view.c new file mode 100644 index 00000000..95bdb558 --- /dev/null +++ b/subprojects/libgd/libgd/gd-main-icon-view.c @@ -0,0 +1,440 @@ +/* + * Copyright (c) 2011 Red Hat, Inc. + * + * This program 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 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 Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Author: Cosimo Cecchi <cosimoc@redhat.com> + * + */ + +#include "gd-main-icon-view.h" +#include "gd-main-view-generic.h" +#include "gd-toggle-pixbuf-renderer.h" +#include "gd-two-lines-renderer.h" + +#include <math.h> +#include <glib/gi18n.h> +#include <cairo-gobject.h> + +#define VIEW_ITEM_WIDTH 140 +#define VIEW_ITEM_WRAP_WIDTH 128 +#define VIEW_COLUMN_SPACING 20 +#define VIEW_MARGIN 16 + +typedef struct _GdMainIconViewPrivate GdMainIconViewPrivate; + +struct _GdMainIconViewPrivate { + GtkCellRenderer *pixbuf_cell; + GtkCellRenderer *text_cell; + gboolean selection_mode; +}; + +static void gd_main_view_generic_iface_init (GdMainViewGenericIface *iface); +G_DEFINE_TYPE_WITH_CODE (GdMainIconView, gd_main_icon_view, GTK_TYPE_ICON_VIEW, + G_ADD_PRIVATE (GdMainIconView) + G_IMPLEMENT_INTERFACE (GD_TYPE_MAIN_VIEW_GENERIC, + gd_main_view_generic_iface_init)) + +static GtkTreePath* +get_source_row (GdkDragContext *context) +{ + GtkTreeRowReference *ref; + + ref = g_object_get_data (G_OBJECT (context), "gtk-icon-view-source-row"); + + if (ref) + return gtk_tree_row_reference_get_path (ref); + else + return NULL; +} + +static void +set_attributes_from_model (GdMainIconView *self) +{ + GdMainIconViewPrivate *priv; + GtkTreeModel *model = gtk_icon_view_get_model (GTK_ICON_VIEW (self)); + GtkCellLayout *layout = GTK_CELL_LAYOUT (self); + GType icon_gtype; + + priv = gd_main_icon_view_get_instance_private (self); + + if (!model) + return; + + gtk_cell_layout_clear_attributes (layout, priv->pixbuf_cell); + gtk_cell_layout_clear_attributes (layout, priv->text_cell); + + gtk_cell_layout_add_attribute (layout, priv->pixbuf_cell, + "active", GD_MAIN_COLUMN_SELECTED); + gtk_cell_layout_add_attribute (layout, priv->pixbuf_cell, + "pulse", GD_MAIN_COLUMN_PULSE); + + icon_gtype = gtk_tree_model_get_column_type (model, GD_MAIN_COLUMN_ICON); + if (icon_gtype == GDK_TYPE_PIXBUF) + gtk_cell_layout_add_attribute (layout, priv->pixbuf_cell, + "pixbuf", GD_MAIN_COLUMN_ICON); + else if (icon_gtype == CAIRO_GOBJECT_TYPE_SURFACE) + gtk_cell_layout_add_attribute (layout, priv->pixbuf_cell, + "surface", GD_MAIN_COLUMN_ICON); + else + g_assert_not_reached (); + + gtk_cell_layout_add_attribute (layout, priv->text_cell, + "text", GD_MAIN_COLUMN_PRIMARY_TEXT); + gtk_cell_layout_add_attribute (layout, priv->text_cell, + "line-two", GD_MAIN_COLUMN_SECONDARY_TEXT); +} + +static void +gd_main_icon_view_drag_data_get (GtkWidget *widget, + GdkDragContext *drag_context, + GtkSelectionData *data, + guint info, + guint time) +{ + GdMainIconView *self = GD_MAIN_ICON_VIEW (widget); + GdMainIconViewPrivate *priv; + GtkTreeModel *model = gtk_icon_view_get_model (GTK_ICON_VIEW (self)); + + priv = gd_main_icon_view_get_instance_private (self); + + if (info != 0) + return; + + _gd_main_view_generic_dnd_common (model, priv->selection_mode, + get_source_row (drag_context), data); + + GTK_WIDGET_CLASS (gd_main_icon_view_parent_class)->drag_data_get (widget, drag_context, + data, info, time); +} + +static void +gd_main_icon_view_constructed (GObject *obj) +{ + GdMainIconView *self = GD_MAIN_ICON_VIEW (obj); + GdMainIconViewPrivate *priv; + GtkCellRenderer *cell; + const GtkTargetEntry targets[] = { + { (char *) "text/uri-list", GTK_TARGET_OTHER_APP, 0 } + }; + + priv = gd_main_icon_view_get_instance_private (self); + + G_OBJECT_CLASS (gd_main_icon_view_parent_class)->constructed (obj); + + gtk_widget_set_hexpand (GTK_WIDGET (self), TRUE); + gtk_widget_set_vexpand (GTK_WIDGET (self), TRUE); + gtk_icon_view_set_selection_mode (GTK_ICON_VIEW (self), GTK_SELECTION_NONE); + + g_object_set (self, + "column-spacing", VIEW_COLUMN_SPACING, + "margin", VIEW_MARGIN, + NULL); + + priv->pixbuf_cell = cell = gd_toggle_pixbuf_renderer_new (); + g_object_set (cell, + "xalign", 0.5, + "yalign", 0.5, + NULL); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (self), cell, FALSE); + + priv->text_cell = cell = gd_two_lines_renderer_new (); + g_object_set (cell, + "xalign", 0.5, + "yalign", 0.0, + "alignment", PANGO_ALIGN_CENTER, + "wrap-mode", PANGO_WRAP_WORD_CHAR, + "wrap-width", VIEW_ITEM_WRAP_WIDTH, + "text-lines", 3, + NULL); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (self), cell, FALSE); + + set_attributes_from_model (self); + + gtk_icon_view_enable_model_drag_source (GTK_ICON_VIEW (self), + GDK_BUTTON1_MASK, + targets, 1, + GDK_ACTION_COPY); +} + +static void +path_from_line_rects (cairo_t *cr, + GdkRectangle *lines, + int n_lines) +{ + int start_line, end_line; + GdkRectangle *r; + int i; + + /* Join rows vertically by extending to the middle */ + for (i = 0; i < n_lines - 1; i++) + { + GdkRectangle *r1 = &lines[i]; + GdkRectangle *r2 = &lines[i+1]; + int gap = r2->y - (r1->y + r1->height); + int old_y; + + r1->height += gap / 2; + old_y = r2->y; + r2->y = r1->y + r1->height; + r2->height += old_y - r2->y; + } + + cairo_new_path (cr); + start_line = 0; + + do + { + for (i = start_line; i < n_lines; i++) + { + r = &lines[i]; + if (i == start_line) + cairo_move_to (cr, r->x + r->width, r->y); + else + cairo_line_to (cr, r->x + r->width, r->y); + cairo_line_to (cr, r->x + r->width, r->y + r->height); + + if (i < n_lines - 1 && + (r->x + r->width < lines[i+1].x || + r->x > lines[i+1].x + lines[i+1].width)) + { + i++; + break; + } + } + end_line = i; + for (i = end_line - 1; i >= start_line; i--) + { + r = &lines[i]; + cairo_line_to (cr, r->x, r->y + r->height); + cairo_line_to (cr, r->x, r->y); + } + cairo_close_path (cr); + start_line = end_line; + } + while (end_line < n_lines); +} + +static gboolean +gd_main_icon_view_draw (GtkWidget *widget, + cairo_t *cr) +{ + GdMainIconView *self = GD_MAIN_ICON_VIEW (widget); + GtkAllocation allocation; + GtkStyleContext *context; + GdkRectangle line_rect; + GdkRectangle rect; + GtkTreePath *path; + GArray *lines; + GtkTreePath *rubberband_start, *rubberband_end; + + GTK_WIDGET_CLASS (gd_main_icon_view_parent_class)->draw (widget, cr); + + _gd_main_view_generic_get_rubberband_range (GD_MAIN_VIEW_GENERIC (self), + &rubberband_start, &rubberband_end); + + if (rubberband_start) + { + cairo_save (cr); + + context = gtk_widget_get_style_context (widget); + + gtk_style_context_save (context); + gtk_style_context_add_class (context, GTK_STYLE_CLASS_RUBBERBAND); + + path = gtk_tree_path_copy (rubberband_start); + + line_rect.width = 0; + lines = g_array_new (FALSE, FALSE, sizeof (GdkRectangle)); + + while (gtk_tree_path_compare (path, rubberband_end) <= 0) + { + if (gtk_icon_view_get_cell_rect (GTK_ICON_VIEW (widget), + path, + NULL, &rect)) + { + if (line_rect.width == 0) + line_rect = rect; + else + { + if (rect.y == line_rect.y) + gdk_rectangle_union (&rect, &line_rect, &line_rect); + else + { + g_array_append_val (lines, line_rect); + line_rect = rect; + } + } + } + gtk_tree_path_next (path); + } + + if (line_rect.width != 0) + g_array_append_val (lines, line_rect); + + if (lines->len > 0) + { + GtkStateFlags state; + cairo_path_t *path; + GtkBorder border; + GdkRGBA border_color; + + path_from_line_rects (cr, (GdkRectangle *)lines->data, lines->len); + + /* For some reason we need to copy and reapply the path, or it gets + eaten by gtk_render_background() */ + path = cairo_copy_path (cr); + + cairo_save (cr); + cairo_clip (cr); + gtk_widget_get_allocation (widget, &allocation); + gtk_render_background (context, cr, + 0, 0, + allocation.width, allocation.height); + cairo_restore (cr); + + cairo_append_path (cr, path); + cairo_path_destroy (path); + + state = gtk_widget_get_state_flags (widget); + + G_GNUC_BEGIN_IGNORE_DEPRECATIONS; + gtk_style_context_get_border_color (context, + state, + &border_color); + G_GNUC_END_IGNORE_DEPRECATIONS; + + gtk_style_context_get_border (context, state, + &border); + + cairo_set_line_width (cr, border.left); + gdk_cairo_set_source_rgba (cr, &border_color); + cairo_stroke (cr); + } + g_array_free (lines, TRUE); + + gtk_tree_path_free (path); + + gtk_style_context_restore (context); + cairo_restore (cr); + } + + return FALSE; +} + +static void +gd_main_icon_view_class_init (GdMainIconViewClass *klass) +{ + GObjectClass *oclass = G_OBJECT_CLASS (klass); + GtkWidgetClass *wclass = GTK_WIDGET_CLASS (klass); + GtkBindingSet *binding_set; + GdkModifierType activate_modifiers[] = { GDK_SHIFT_MASK, GDK_CONTROL_MASK, GDK_SHIFT_MASK | GDK_CONTROL_MASK }; + guint i; + + binding_set = gtk_binding_set_by_class (klass); + + oclass->constructed = gd_main_icon_view_constructed; + wclass->drag_data_get = gd_main_icon_view_drag_data_get; + wclass->draw = gd_main_icon_view_draw; + + gtk_widget_class_install_style_property (wclass, + g_param_spec_int ("check-icon-size", + "Check icon size", + "Check icon size", + -1, G_MAXINT, 40, + G_PARAM_READWRITE)); + + for (i = 0; i < G_N_ELEMENTS (activate_modifiers); i++) + { + gtk_binding_entry_add_signal (binding_set, GDK_KEY_space, activate_modifiers[i], + "activate-cursor-item", 0); + gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Space, activate_modifiers[i], + "activate-cursor-item", 0); + gtk_binding_entry_add_signal (binding_set, GDK_KEY_Return, activate_modifiers[i], + "activate-cursor-item", 0); + gtk_binding_entry_add_signal (binding_set, GDK_KEY_ISO_Enter, activate_modifiers[i], + "activate-cursor-item", 0); + gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Enter, activate_modifiers[i], + "activate-cursor-item", 0); + } +} + +static void +gd_main_icon_view_init (GdMainIconView *self) +{ + g_signal_connect (self, "notify::model", + G_CALLBACK (set_attributes_from_model), NULL); +} + +static GtkTreePath * +gd_main_icon_view_get_path_at_pos (GdMainViewGeneric *mv, + gint x, + gint y) +{ + return gtk_icon_view_get_path_at_pos (GTK_ICON_VIEW (mv), x, y); +} + +static void +gd_main_icon_view_set_selection_mode (GdMainViewGeneric *mv, + gboolean selection_mode) +{ + GdMainIconView *self = GD_MAIN_ICON_VIEW (mv); + GdMainIconViewPrivate *priv; + + priv = gd_main_icon_view_get_instance_private (self); + + priv->selection_mode = selection_mode; + + g_object_set (priv->pixbuf_cell, + "toggle-visible", selection_mode, + NULL); + gtk_widget_queue_draw (GTK_WIDGET (self)); +} + +static void +gd_main_icon_view_scroll_to_path (GdMainViewGeneric *mv, + GtkTreePath *path) +{ + gtk_icon_view_scroll_to_path (GTK_ICON_VIEW (mv), path, TRUE, 0.5, 0.5); +} + +static void +gd_main_icon_view_set_model (GdMainViewGeneric *mv, + GtkTreeModel *model) +{ + gtk_icon_view_set_model (GTK_ICON_VIEW (mv), model); +} + +static GtkTreeModel * +gd_main_icon_view_get_model (GdMainViewGeneric *mv) +{ + return gtk_icon_view_get_model (GTK_ICON_VIEW (mv)); +} + +static void +gd_main_view_generic_iface_init (GdMainViewGenericIface *iface) +{ + iface->set_model = gd_main_icon_view_set_model; + iface->get_model = gd_main_icon_view_get_model; + iface->get_path_at_pos = gd_main_icon_view_get_path_at_pos; + iface->scroll_to_path = gd_main_icon_view_scroll_to_path; + iface->set_selection_mode = gd_main_icon_view_set_selection_mode; +} + +GtkWidget * +gd_main_icon_view_new (void) +{ + return g_object_new (GD_TYPE_MAIN_ICON_VIEW, NULL); +} diff --git a/subprojects/libgd/libgd/gd-main-icon-view.h b/subprojects/libgd/libgd/gd-main-icon-view.h new file mode 100644 index 00000000..c93e279f --- /dev/null +++ b/subprojects/libgd/libgd/gd-main-icon-view.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2011 Red Hat, Inc. + * + * This program 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 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 Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Author: Cosimo Cecchi <cosimoc@redhat.com> + * + */ + +#ifndef __GD_MAIN_ICON_VIEW_H__ +#define __GD_MAIN_ICON_VIEW_H__ + +#include <glib-object.h> +#include <gtk/gtk.h> + +G_BEGIN_DECLS + +#define GD_TYPE_MAIN_ICON_VIEW gd_main_icon_view_get_type() +G_DECLARE_DERIVABLE_TYPE (GdMainIconView, gd_main_icon_view, GD, MAIN_ICON_VIEW, GtkIconView) + +struct _GdMainIconViewClass +{ + GtkIconViewClass parent_class; +}; + +GtkWidget * gd_main_icon_view_new (void); + +G_END_DECLS + +#endif /* __GD_MAIN_ICON_VIEW_H__ */ diff --git a/subprojects/libgd/libgd/gd-main-list-view.c b/subprojects/libgd/libgd/gd-main-list-view.c new file mode 100644 index 00000000..ae985a14 --- /dev/null +++ b/subprojects/libgd/libgd/gd-main-list-view.c @@ -0,0 +1,345 @@ +/* + * Copyright (c) 2011 Red Hat, Inc. + * + * This program 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 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 Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Author: Cosimo Cecchi <cosimoc@redhat.com> + * + */ + +#include "gd-main-list-view.h" +#include "gd-main-view-generic.h" +#include "gd-two-lines-renderer.h" + +#include <cairo-gobject.h> +#include <glib/gi18n.h> + +struct _GdMainListViewPrivate { + GtkTreeViewColumn *tree_col; + GtkCellRenderer *pixbuf_cell; + GtkCellRenderer *selection_cell; + GtkCellRenderer *text_cell; + + gboolean selection_mode; +}; + +static void gd_main_view_generic_iface_init (GdMainViewGenericIface *iface); +G_DEFINE_TYPE_WITH_CODE (GdMainListView, gd_main_list_view, GTK_TYPE_TREE_VIEW, + G_ADD_PRIVATE (GdMainListView) + G_IMPLEMENT_INTERFACE (GD_TYPE_MAIN_VIEW_GENERIC, + gd_main_view_generic_iface_init)) + +static gboolean gd_main_list_view_draw (GtkWidget *widget, + cairo_t *cr); + +static GtkTreePath* +get_source_row (GdkDragContext *context) +{ + GtkTreeRowReference *ref = + g_object_get_data (G_OBJECT (context), "gtk-tree-view-source-row"); + + if (ref) + return gtk_tree_row_reference_get_path (ref); + else + return NULL; +} + +static void +set_attributes_from_model (GdMainListView *self) +{ + GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (self)); + GType icon_gtype; + + if (!model) + return; + + gtk_tree_view_column_clear_attributes (self->priv->tree_col, self->priv->pixbuf_cell); + gtk_tree_view_column_clear_attributes (self->priv->tree_col, self->priv->selection_cell); + gtk_tree_view_column_clear_attributes (self->priv->tree_col, self->priv->text_cell); + + + gtk_tree_view_column_add_attribute (self->priv->tree_col, self->priv->selection_cell, + "active", GD_MAIN_COLUMN_SELECTED); + + icon_gtype = gtk_tree_model_get_column_type (model, GD_MAIN_COLUMN_ICON); + if (icon_gtype == GDK_TYPE_PIXBUF) + gtk_tree_view_column_add_attribute (self->priv->tree_col, self->priv->pixbuf_cell, + "pixbuf", GD_MAIN_COLUMN_ICON); + else if (icon_gtype == CAIRO_GOBJECT_TYPE_SURFACE) + gtk_tree_view_column_add_attribute (self->priv->tree_col, self->priv->pixbuf_cell, + "surface", GD_MAIN_COLUMN_ICON); + else + g_assert_not_reached (); + + gtk_tree_view_column_add_attribute (self->priv->tree_col, self->priv->text_cell, + "text", GD_MAIN_COLUMN_PRIMARY_TEXT); + gtk_tree_view_column_add_attribute (self->priv->tree_col, self->priv->text_cell, + "line-two", GD_MAIN_COLUMN_SECONDARY_TEXT); +} + +static void +gd_main_list_view_drag_data_get (GtkWidget *widget, + GdkDragContext *drag_context, + GtkSelectionData *data, + guint info, + guint time) +{ + GdMainListView *self = GD_MAIN_LIST_VIEW (widget); + GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (self)); + + if (info != 0) + return; + + _gd_main_view_generic_dnd_common (model, + self->priv->selection_mode, + get_source_row (drag_context), data); + + GTK_WIDGET_CLASS (gd_main_list_view_parent_class)->drag_data_get (widget, drag_context, + data, info, time); +} + +static void +gd_main_list_view_constructed (GObject *obj) +{ + GdMainListView *self = GD_MAIN_LIST_VIEW (obj); + GtkCellRenderer *cell; + GtkTreeSelection *selection; + const GtkTargetEntry targets[] = { + { "text/uri-list", GTK_TARGET_OTHER_APP, 0 } + }; + + G_OBJECT_CLASS (gd_main_list_view_parent_class)->constructed (obj); + + gtk_widget_set_hexpand (GTK_WIDGET (self), TRUE); + gtk_widget_set_vexpand (GTK_WIDGET (self), TRUE); + + g_object_set (self, + "headers-visible", FALSE, + "enable-search", FALSE, + NULL); + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (self)); + gtk_tree_selection_set_mode (selection, GTK_SELECTION_NONE); + + self->priv->tree_col = gtk_tree_view_column_new (); + gtk_tree_view_append_column (GTK_TREE_VIEW (self), self->priv->tree_col); + + self->priv->selection_cell = cell = gtk_cell_renderer_toggle_new (); + g_object_set (cell, + "visible", FALSE, + "xpad", 12, + "xalign", 1.0, + NULL); + gtk_tree_view_column_pack_start (self->priv->tree_col, cell, FALSE); + + self->priv->pixbuf_cell = cell = gtk_cell_renderer_pixbuf_new (); + g_object_set (cell, + "xalign", 0.5, + "yalign", 0.5, + "xpad", 12, + "ypad", 2, + NULL); + gtk_tree_view_column_pack_start (self->priv->tree_col, cell, FALSE); + + self->priv->text_cell = cell = gd_two_lines_renderer_new (); + g_object_set (cell, + "xalign", 0.0, + "wrap-mode", PANGO_WRAP_WORD_CHAR, + "xpad", 12, + "text-lines", 2, + NULL); + gtk_tree_view_column_pack_start (self->priv->tree_col, cell, TRUE); + + set_attributes_from_model (self); + + gtk_tree_view_enable_model_drag_source (GTK_TREE_VIEW (self), + GDK_BUTTON1_MASK, + targets, 1, + GDK_ACTION_COPY); +} + +static void +gd_main_list_view_class_init (GdMainListViewClass *klass) +{ + GObjectClass *oclass = G_OBJECT_CLASS (klass); + GtkWidgetClass *wclass = GTK_WIDGET_CLASS (klass); + GtkBindingSet *binding_set; + GdkModifierType activate_modifiers[] = { GDK_SHIFT_MASK, GDK_CONTROL_MASK, GDK_SHIFT_MASK | GDK_CONTROL_MASK }; + guint i; + + binding_set = gtk_binding_set_by_class (klass); + + oclass->constructed = gd_main_list_view_constructed; + wclass->drag_data_get = gd_main_list_view_drag_data_get; + wclass->draw = gd_main_list_view_draw; + + for (i = 0; i < G_N_ELEMENTS (activate_modifiers); i++) + { + gtk_binding_entry_add_signal (binding_set, GDK_KEY_space, activate_modifiers[i], + "select-cursor-row", 1, + G_TYPE_BOOLEAN, TRUE); + gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Space, activate_modifiers[i], + "select-cursor-row", 1, + G_TYPE_BOOLEAN, TRUE); + gtk_binding_entry_add_signal (binding_set, GDK_KEY_Return, activate_modifiers[i], + "select-cursor-row", 1, + G_TYPE_BOOLEAN, TRUE); + gtk_binding_entry_add_signal (binding_set, GDK_KEY_ISO_Enter, activate_modifiers[i], + "select-cursor-row", 1, + G_TYPE_BOOLEAN, TRUE); + gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Enter, activate_modifiers[i], + "select-cursor-row", 1, + G_TYPE_BOOLEAN, TRUE); + } + +} + +static void +gd_main_list_view_init (GdMainListView *self) +{ + self->priv = gd_main_list_view_get_instance_private (self); + + g_signal_connect (self, "notify::model", + G_CALLBACK (set_attributes_from_model), NULL); +} + +static GtkTreePath * +gd_main_list_view_get_path_at_pos (GdMainViewGeneric *mv, + gint x, + gint y) +{ + GtkTreePath *path = NULL; + + gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (mv), x, y, &path, + NULL, NULL, NULL); + + return path; +} + +static void +gd_main_list_view_set_selection_mode (GdMainViewGeneric *mv, + gboolean selection_mode) +{ + GdMainListView *self = GD_MAIN_LIST_VIEW (mv); + + self->priv->selection_mode = selection_mode; + + g_object_set (self->priv->selection_cell, + "visible", selection_mode, + NULL); + gtk_tree_view_column_queue_resize (self->priv->tree_col); +} + +static gboolean +gd_main_list_view_draw (GtkWidget *widget, + cairo_t *cr) +{ + GdMainListView *self = GD_MAIN_LIST_VIEW (widget); + GtkStyleContext *context; + GdkRectangle lines_rect; + GdkRectangle rect; + GtkTreePath *path; + GtkTreePath *rubberband_start, *rubberband_end; + + GTK_WIDGET_CLASS (gd_main_list_view_parent_class)->draw (widget, cr); + + _gd_main_view_generic_get_rubberband_range (GD_MAIN_VIEW_GENERIC (self), + &rubberband_start, &rubberband_end); + + if (rubberband_start) + { + context = gtk_widget_get_style_context (widget); + + gtk_style_context_save (context); + gtk_style_context_add_class (context, GTK_STYLE_CLASS_RUBBERBAND); + + path = gtk_tree_path_copy (rubberband_start); + + lines_rect.width = 0; + + while (gtk_tree_path_compare (path, rubberband_end) <= 0) + { + gtk_tree_view_get_cell_area (GTK_TREE_VIEW (self), + path, self->priv->tree_col, &rect); + if (lines_rect.width == 0) + lines_rect = rect; + else + gdk_rectangle_union (&rect, &lines_rect, &lines_rect); + + gtk_tree_path_next (path); + } + gtk_tree_path_free (path); + + gtk_render_background (context, cr, + lines_rect.x, lines_rect.y, + lines_rect.width, lines_rect.height); + gtk_render_frame (context, cr, + lines_rect.x, lines_rect.y, + lines_rect.width, lines_rect.height); + + + gtk_style_context_restore (context); + } + + return FALSE; +} + +static void +gd_main_list_view_scroll_to_path (GdMainViewGeneric *mv, + GtkTreePath *path) +{ + gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (mv), path, NULL, TRUE, 0.5, 0.5); +} + +static void +gd_main_list_view_set_model (GdMainViewGeneric *mv, + GtkTreeModel *model) +{ + gtk_tree_view_set_model (GTK_TREE_VIEW (mv), model); +} + +static GtkTreeModel * +gd_main_list_view_get_model (GdMainViewGeneric *mv) +{ + return gtk_tree_view_get_model (GTK_TREE_VIEW (mv)); +} + +static void +gd_main_view_generic_iface_init (GdMainViewGenericIface *iface) +{ + iface->set_model = gd_main_list_view_set_model; + iface->get_model = gd_main_list_view_get_model; + iface->get_path_at_pos = gd_main_list_view_get_path_at_pos; + iface->scroll_to_path = gd_main_list_view_scroll_to_path; + iface->set_selection_mode = gd_main_list_view_set_selection_mode; +} + +void +gd_main_list_view_add_renderer (GdMainListView *self, + GtkCellRenderer *renderer, + GtkTreeCellDataFunc func, + gpointer user_data, + GDestroyNotify destroy) +{ + gtk_tree_view_column_pack_start (self->priv->tree_col, renderer, FALSE); + gtk_tree_view_column_set_cell_data_func (self->priv->tree_col, renderer, + func, user_data, destroy); +} + +GtkWidget * +gd_main_list_view_new (void) +{ + return g_object_new (GD_TYPE_MAIN_LIST_VIEW, NULL); +} diff --git a/subprojects/libgd/libgd/gd-main-list-view.h b/subprojects/libgd/libgd/gd-main-list-view.h new file mode 100644 index 00000000..317e9c4b --- /dev/null +++ b/subprojects/libgd/libgd/gd-main-list-view.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2011 Red Hat, Inc. + * + * This program 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 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 Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Author: Cosimo Cecchi <cosimoc@redhat.com> + * + */ + +#ifndef __GD_MAIN_LIST_VIEW_H__ +#define __GD_MAIN_LIST_VIEW_H__ + +#include <glib-object.h> +#include <gtk/gtk.h> + +G_BEGIN_DECLS + +#define GD_TYPE_MAIN_LIST_VIEW gd_main_list_view_get_type() + +#define GD_MAIN_LIST_VIEW(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), \ + GD_TYPE_MAIN_LIST_VIEW, GdMainListView)) + +#define GD_MAIN_LIST_VIEW_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), \ + GD_TYPE_MAIN_LIST_VIEW, GdMainListViewClass)) + +#define GD_IS_MAIN_LIST_VIEW(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \ + GD_TYPE_MAIN_LIST_VIEW)) + +#define GD_IS_MAIN_LIST_VIEW_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), \ + GD_TYPE_MAIN_LIST_VIEW)) + +#define GD_MAIN_LIST_VIEW_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), \ + GD_TYPE_MAIN_LIST_VIEW, GdMainListViewClass)) + +typedef struct _GdMainListView GdMainListView; +typedef struct _GdMainListViewClass GdMainListViewClass; +typedef struct _GdMainListViewPrivate GdMainListViewPrivate; + +struct _GdMainListView +{ + GtkTreeView parent; + + GdMainListViewPrivate *priv; +}; + +struct _GdMainListViewClass +{ + GtkTreeViewClass parent_class; +}; + +GType gd_main_list_view_get_type (void) G_GNUC_CONST; + +GtkWidget * gd_main_list_view_new (void); + +void gd_main_list_view_add_renderer (GdMainListView *self, + GtkCellRenderer *renderer, + GtkTreeCellDataFunc func, + gpointer user_data, + GDestroyNotify destroy); + +G_END_DECLS + +#endif /* __GD_MAIN_LIST_VIEW_H__ */ diff --git a/subprojects/libgd/libgd/gd-main-view-generic.c b/subprojects/libgd/libgd/gd-main-view-generic.c new file mode 100644 index 00000000..51347e05 --- /dev/null +++ b/subprojects/libgd/libgd/gd-main-view-generic.c @@ -0,0 +1,330 @@ +/* + * Copyright (c) 2011 Red Hat, Inc. + * + * This program 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 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 Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Author: Cosimo Cecchi <cosimoc@redhat.com> + * + */ + +#include "gd-main-view-generic.h" + +enum { + VIEW_SELECTION_CHANGED, + NUM_SIGNALS +}; + +static guint signals[NUM_SIGNALS] = { 0, }; + +typedef GdMainViewGenericIface GdMainViewGenericInterface; +G_DEFINE_INTERFACE (GdMainViewGeneric, gd_main_view_generic, GTK_TYPE_WIDGET) + +static void +gd_main_view_generic_default_init (GdMainViewGenericInterface *iface) +{ + signals[VIEW_SELECTION_CHANGED] = + g_signal_new ("view-selection-changed", + GD_TYPE_MAIN_VIEW_GENERIC, + G_SIGNAL_RUN_LAST, + 0, NULL, NULL, NULL, + G_TYPE_NONE, 0); +} + +/** + * gd_main_view_generic_set_model: + * @self: + * @model: (allow-none): + * + */ +void +gd_main_view_generic_set_model (GdMainViewGeneric *self, + GtkTreeModel *model) +{ + GdMainViewGenericInterface *iface; + + iface = GD_MAIN_VIEW_GENERIC_GET_IFACE (self); + + (* iface->set_model) (self, model); +} + +GtkTreePath * +gd_main_view_generic_get_path_at_pos (GdMainViewGeneric *self, + gint x, + gint y) +{ + GdMainViewGenericInterface *iface; + + iface = GD_MAIN_VIEW_GENERIC_GET_IFACE (self); + + return (* iface->get_path_at_pos) (self, x, y); +} + +void +gd_main_view_generic_set_selection_mode (GdMainViewGeneric *self, + gboolean selection_mode) +{ + GdMainViewGenericInterface *iface; + + iface = GD_MAIN_VIEW_GENERIC_GET_IFACE (self); + + (* iface->set_selection_mode) (self, selection_mode); +} + + +typedef struct { + GtkTreePath *rubberband_start; + GtkTreePath *rubberband_end; +} RubberbandInfo; + +static void +rubber_band_info_destroy (RubberbandInfo *info) +{ + g_clear_pointer (&info->rubberband_start, + gtk_tree_path_free); + g_clear_pointer (&info->rubberband_end, + gtk_tree_path_free); + g_slice_free (RubberbandInfo, info); +} + +static RubberbandInfo* +get_rubber_band_info (GdMainViewGeneric *self) +{ + RubberbandInfo *info; + + info = g_object_get_data (G_OBJECT (self), "gd-main-view-generic-rubber-band"); + if (info == NULL) + { + info = g_slice_new0 (RubberbandInfo); + g_object_set_data_full (G_OBJECT (self), "gd-main-view-generic-rubber-band", + info, (GDestroyNotify)rubber_band_info_destroy); + } + + return info; +} + +void +gd_main_view_generic_set_rubberband_range (GdMainViewGeneric *self, + GtkTreePath *start, + GtkTreePath *end) +{ + RubberbandInfo *info; + + info = get_rubber_band_info (self); + + if (start == NULL || end == NULL) + { + g_clear_pointer (&info->rubberband_start, + gtk_tree_path_free); + g_clear_pointer (&info->rubberband_end, + gtk_tree_path_free); + } + else + { + if (gtk_tree_path_compare (start, end) < 0) + { + info->rubberband_start = gtk_tree_path_copy (start); + info->rubberband_end = gtk_tree_path_copy (end); + } + else + { + info->rubberband_start = gtk_tree_path_copy (end); + info->rubberband_end = gtk_tree_path_copy (start); + } + } + + gtk_widget_queue_draw (GTK_WIDGET (self)); +} + +void +_gd_main_view_generic_get_rubberband_range (GdMainViewGeneric *self, + GtkTreePath **start, + GtkTreePath **end) +{ + RubberbandInfo *info; + + info = get_rubber_band_info (self); + + *start = info->rubberband_start; + *end = info->rubberband_end; +} + +void +gd_main_view_generic_scroll_to_path (GdMainViewGeneric *self, + GtkTreePath *path) +{ + GdMainViewGenericInterface *iface; + + iface = GD_MAIN_VIEW_GENERIC_GET_IFACE (self); + + (* iface->scroll_to_path) (self, path); +} + +/** + * gd_main_view_generic_get_model: + * + * Returns: (transfer none): The associated model + */ +GtkTreeModel * +gd_main_view_generic_get_model (GdMainViewGeneric *self) +{ + GdMainViewGenericInterface *iface; + + iface = GD_MAIN_VIEW_GENERIC_GET_IFACE (self); + + return (* iface->get_model) (self); +} + +static gboolean +build_selection_uris_foreach (GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + gpointer user_data) +{ + GPtrArray *ptr_array = user_data; + gchar *uri; + gboolean is_selected; + + gtk_tree_model_get (model, iter, + GD_MAIN_COLUMN_URI, &uri, + GD_MAIN_COLUMN_SELECTED, &is_selected, + -1); + + if (is_selected) + g_ptr_array_add (ptr_array, uri); + else + g_free (uri); + + return FALSE; +} + +static gchar ** +model_get_selection_uris (GtkTreeModel *model) +{ + GPtrArray *ptr_array = g_ptr_array_new (); + + gtk_tree_model_foreach (model, + build_selection_uris_foreach, + ptr_array); + + g_ptr_array_add (ptr_array, NULL); + return (gchar **) g_ptr_array_free (ptr_array, FALSE); +} + +static gboolean +set_selection_foreach (GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + gpointer user_data) +{ + gboolean selection = GPOINTER_TO_INT (user_data); + GtkTreeModel *actual_model; + GtkTreeIter real_iter; + + if (GTK_IS_TREE_MODEL_FILTER (model)) + { + actual_model = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (model)); + gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (model), + &real_iter, iter); + } + else if (GTK_IS_TREE_MODEL_SORT (model)) + { + actual_model = gtk_tree_model_sort_get_model (GTK_TREE_MODEL_SORT (model)); + gtk_tree_model_sort_convert_iter_to_child_iter (GTK_TREE_MODEL_SORT (model), + &real_iter, iter); + } + else + { + actual_model = model; + real_iter = *iter; + } + + if (GTK_IS_LIST_STORE (actual_model)) + { + gtk_list_store_set (GTK_LIST_STORE (actual_model), &real_iter, + GD_MAIN_COLUMN_SELECTED, selection, + -1); + } + else + { + gtk_tree_store_set (GTK_TREE_STORE (actual_model), &real_iter, + GD_MAIN_COLUMN_SELECTED, selection, + -1); + } + + return FALSE; +} + +static void +set_all_selection (GdMainViewGeneric *self, + GtkTreeModel *model, + gboolean selection) +{ + gtk_tree_model_foreach (model, + set_selection_foreach, + GINT_TO_POINTER (selection)); + g_signal_emit (self, signals[VIEW_SELECTION_CHANGED], 0); +} + +void +gd_main_view_generic_select_all (GdMainViewGeneric *self) +{ + GtkTreeModel *model = gd_main_view_generic_get_model (self); + + set_all_selection (self, model, TRUE); +} + +void +gd_main_view_generic_unselect_all (GdMainViewGeneric *self) +{ + GtkTreeModel *model = gd_main_view_generic_get_model (self); + + set_all_selection (self, model, FALSE); +} + +void +_gd_main_view_generic_dnd_common (GtkTreeModel *model, + gboolean selection_mode, + GtkTreePath *path, + GtkSelectionData *data) +{ + gchar **uris; + + if (selection_mode) + { + uris = model_get_selection_uris (model); + } + else + { + GtkTreeIter iter; + gboolean res; + gchar *uri = NULL; + + if (path != NULL) + { + res = gtk_tree_model_get_iter (model, &iter, path); + if (res) + gtk_tree_model_get (model, &iter, + GD_MAIN_COLUMN_URI, &uri, + -1); + } + + uris = g_new0 (gchar *, 2); + uris[0] = uri; + uris[1] = NULL; + } + + gtk_selection_data_set_uris (data, uris); + g_strfreev (uris); +} diff --git a/subprojects/libgd/libgd/gd-main-view-generic.h b/subprojects/libgd/libgd/gd-main-view-generic.h new file mode 100644 index 00000000..dd53e0ee --- /dev/null +++ b/subprojects/libgd/libgd/gd-main-view-generic.h @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2011 Red Hat, Inc. + * + * This program 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 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 Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Author: Cosimo Cecchi <cosimoc@redhat.com> + * + */ + +#ifndef __GD_MAIN_VIEW_GENERIC_H__ +#define __GD_MAIN_VIEW_GENERIC_H__ + +#include <glib-object.h> + +#include <gtk/gtk.h> + +G_BEGIN_DECLS + +typedef enum { + GD_MAIN_COLUMN_ID, + GD_MAIN_COLUMN_URI, + GD_MAIN_COLUMN_PRIMARY_TEXT, + GD_MAIN_COLUMN_SECONDARY_TEXT, + GD_MAIN_COLUMN_ICON, + GD_MAIN_COLUMN_MTIME, + GD_MAIN_COLUMN_SELECTED, + GD_MAIN_COLUMN_PULSE, + + GD_MAIN_COLUMN_LAST +} GdMainColumns; + +#define GD_TYPE_MAIN_VIEW_GENERIC gd_main_view_generic_get_type() + +#define GD_MAIN_VIEW_GENERIC(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), \ + GD_TYPE_MAIN_VIEW_GENERIC, GdMainViewGeneric)) + +#define GD_MAIN_VIEW_GENERIC_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), \ + GD_TYPE_MAIN_VIEW_GENERIC, GdMainViewGenericIface)) + +#define GD_IS_MAIN_VIEW_GENERIC(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \ + GD_TYPE_MAIN_VIEW_GENERIC)) + +#define GD_IS_MAIN_VIEW_GENERIC_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), \ + GD_TYPE_MAIN_VIEW_GENERIC)) + +#define GD_MAIN_VIEW_GENERIC_GET_IFACE(obj) \ + (G_TYPE_INSTANCE_GET_INTERFACE ((obj), \ + GD_TYPE_MAIN_VIEW_GENERIC, GdMainViewGenericIface)) + +typedef struct _GdMainViewGeneric GdMainViewGeneric; +typedef struct _GdMainViewGenericIface GdMainViewGenericIface; + +struct _GdMainViewGenericIface +{ + GTypeInterface base_iface; + + /* vtable */ + void (* set_model) (GdMainViewGeneric *self, + GtkTreeModel *model); + GtkTreeModel * (* get_model) (GdMainViewGeneric *self); + + GtkTreePath * (* get_path_at_pos) (GdMainViewGeneric *self, + gint x, + gint y); + void (* scroll_to_path) (GdMainViewGeneric *self, + GtkTreePath *path); + void (* set_selection_mode) (GdMainViewGeneric *self, + gboolean selection_mode); +}; + +GType gd_main_view_generic_get_type (void) G_GNUC_CONST; + +void gd_main_view_generic_set_model (GdMainViewGeneric *self, + GtkTreeModel *model); +GtkTreeModel * gd_main_view_generic_get_model (GdMainViewGeneric *self); + +void gd_main_view_generic_scroll_to_path (GdMainViewGeneric *self, + GtkTreePath *path); +void gd_main_view_generic_set_selection_mode (GdMainViewGeneric *self, + gboolean selection_mode); +GtkTreePath * gd_main_view_generic_get_path_at_pos (GdMainViewGeneric *self, + gint x, + gint y); +void gd_main_view_generic_select_all (GdMainViewGeneric *self); +void gd_main_view_generic_unselect_all (GdMainViewGeneric *self); +void gd_main_view_generic_set_rubberband_range (GdMainViewGeneric *self, + GtkTreePath *start, + GtkTreePath *end); + +/* private */ +void _gd_main_view_generic_dnd_common (GtkTreeModel *model, + gboolean selection_mode, + GtkTreePath *path, + GtkSelectionData *data); +void _gd_main_view_generic_get_rubberband_range (GdMainViewGeneric *self, + GtkTreePath **start, + GtkTreePath **end); + +G_END_DECLS + +#endif /* __GD_MAIN_VIEW_GENERIC_H__ */ diff --git a/subprojects/libgd/libgd/gd-main-view.c b/subprojects/libgd/libgd/gd-main-view.c new file mode 100644 index 00000000..008162b6 --- /dev/null +++ b/subprojects/libgd/libgd/gd-main-view.c @@ -0,0 +1,1160 @@ +/* + * Copyright (c) 2011 Red Hat, Inc. + * + * This program 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 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 Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Author: Cosimo Cecchi <cosimoc@redhat.com> + * + */ + +#include "gd-main-view.h" + +#include "gd-icon-utils.h" +#include "gd-main-view-generic.h" +#include "gd-main-icon-view.h" +#include "gd-main-list-view.h" + +#include <math.h> +#include <cairo-gobject.h> + +#define MAIN_VIEW_TYPE_INITIAL -1 +#define MAIN_VIEW_DND_ICON_OFFSET 20 +#define MAIN_VIEW_RUBBERBAND_SELECT_TRIGGER_LENGTH 32 + +typedef struct _GdMainViewPrivate GdMainViewPrivate; + +struct _GdMainViewPrivate { + GdMainViewType current_type; + gboolean selection_mode; + + GtkWidget *current_view; + GtkTreeModel *model; + + gboolean track_motion; + gboolean rubberband_select; + GtkTreePath *rubberband_select_first_path; + GtkTreePath *rubberband_select_last_path; + int button_down_x; + int button_down_y; + + gchar *button_press_item_path; + + gchar *last_selected_id; +}; + +enum { + PROP_VIEW_TYPE = 1, + PROP_SELECTION_MODE, + PROP_MODEL, + NUM_PROPERTIES +}; + +enum { + ITEM_ACTIVATED = 1, + SELECTION_MODE_REQUEST, + VIEW_SELECTION_CHANGED, + NUM_SIGNALS +}; + +static GParamSpec *properties[NUM_PROPERTIES] = { NULL, }; +static guint signals[NUM_SIGNALS] = { 0, }; + +G_DEFINE_TYPE_WITH_PRIVATE (GdMainView, gd_main_view, GTK_TYPE_SCROLLED_WINDOW) + +static void +gd_main_view_dispose (GObject *obj) +{ + GdMainView *self = GD_MAIN_VIEW (obj); + GdMainViewPrivate *priv; + + priv = gd_main_view_get_instance_private (self); + + g_clear_object (&priv->model); + + G_OBJECT_CLASS (gd_main_view_parent_class)->dispose (obj); +} + +static void +gd_main_view_finalize (GObject *obj) +{ + GdMainView *self = GD_MAIN_VIEW (obj); + GdMainViewPrivate *priv; + + priv = gd_main_view_get_instance_private (self); + + g_free (priv->button_press_item_path); + g_free (priv->last_selected_id); + + if (priv->rubberband_select_first_path) + gtk_tree_path_free (priv->rubberband_select_first_path); + + if (priv->rubberband_select_last_path) + gtk_tree_path_free (priv->rubberband_select_last_path); + + G_OBJECT_CLASS (gd_main_view_parent_class)->finalize (obj); +} + +static void +gd_main_view_init (GdMainView *self) +{ + GdMainViewPrivate *priv; + GtkStyleContext *context; + + priv = gd_main_view_get_instance_private (self); + + /* so that we get constructed with the right view even at startup */ + priv->current_type = MAIN_VIEW_TYPE_INITIAL; + + gtk_widget_set_hexpand (GTK_WIDGET (self), TRUE); + gtk_widget_set_vexpand (GTK_WIDGET (self), TRUE); + gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (self), GTK_SHADOW_IN); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (self), + GTK_POLICY_NEVER, + GTK_POLICY_AUTOMATIC); + + context = gtk_widget_get_style_context (GTK_WIDGET (self)); + gtk_style_context_add_class (context, "documents-scrolledwin"); +} + +static void +gd_main_view_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + GdMainView *self = GD_MAIN_VIEW (object); + + switch (property_id) + { + case PROP_VIEW_TYPE: + g_value_set_int (value, gd_main_view_get_view_type (self)); + break; + case PROP_SELECTION_MODE: + g_value_set_boolean (value, gd_main_view_get_selection_mode (self)); + break; + case PROP_MODEL: + g_value_set_object (value, gd_main_view_get_model (self)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gd_main_view_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + GdMainView *self = GD_MAIN_VIEW (object); + + switch (property_id) + { + case PROP_VIEW_TYPE: + gd_main_view_set_view_type (self, g_value_get_int (value)); + break; + case PROP_SELECTION_MODE: + gd_main_view_set_selection_mode (self, g_value_get_boolean (value)); + break; + case PROP_MODEL: + gd_main_view_set_model (self, g_value_get_object (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gd_main_view_class_init (GdMainViewClass *klass) +{ + GObjectClass *oclass = G_OBJECT_CLASS (klass); + + oclass->get_property = gd_main_view_get_property; + oclass->set_property = gd_main_view_set_property; + oclass->dispose = gd_main_view_dispose; + oclass->finalize = gd_main_view_finalize; + + properties[PROP_VIEW_TYPE] = + g_param_spec_int ("view-type", + "View type", + "View type", + GD_MAIN_VIEW_ICON, + GD_MAIN_VIEW_LIST, + GD_MAIN_VIEW_ICON, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT | + G_PARAM_STATIC_STRINGS); + + properties[PROP_SELECTION_MODE] = + g_param_spec_boolean ("selection-mode", + "Selection mode", + "Whether the view is in selection mode", + FALSE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT | + G_PARAM_STATIC_STRINGS); + + properties[PROP_MODEL] = + g_param_spec_object ("model", + "Model", + "The GtkTreeModel", + GTK_TYPE_TREE_MODEL, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT | + G_PARAM_STATIC_STRINGS); + + signals[ITEM_ACTIVATED] = + g_signal_new ("item-activated", + GD_TYPE_MAIN_VIEW, + G_SIGNAL_RUN_LAST, + 0, NULL, NULL, NULL, + G_TYPE_NONE, 2, + G_TYPE_STRING, + GTK_TYPE_TREE_PATH); + + signals[SELECTION_MODE_REQUEST] = + g_signal_new ("selection-mode-request", + GD_TYPE_MAIN_VIEW, + G_SIGNAL_RUN_LAST, + 0, NULL, NULL, NULL, + G_TYPE_NONE, 0); + + signals[VIEW_SELECTION_CHANGED] = + g_signal_new ("view-selection-changed", + GD_TYPE_MAIN_VIEW, + G_SIGNAL_RUN_LAST, + 0, NULL, NULL, NULL, + G_TYPE_NONE, 0); + + g_object_class_install_properties (oclass, NUM_PROPERTIES, properties); +} + +static GdMainViewGeneric * +get_generic (GdMainView *self) +{ + GdMainViewPrivate *priv; + + priv = gd_main_view_get_instance_private (self); + + if (priv->current_view != NULL) + return GD_MAIN_VIEW_GENERIC (priv->current_view); + + return NULL; +} + +static void +do_select_row (GdMainView *self, + GtkTreeIter *iter, + gboolean value) +{ + GdMainViewPrivate *priv; + GtkTreeModel *model; + GtkTreeIter my_iter; + GtkTreePath *path; + + priv = gd_main_view_get_instance_private (self); + + model = priv->model; + my_iter = *iter; + + while (GTK_IS_TREE_MODEL_FILTER (model) || + GTK_IS_TREE_MODEL_SORT (model)) + { + GtkTreeIter child_iter; + + if (GTK_IS_TREE_MODEL_FILTER (model)) + { + GtkTreeModelFilter *filter; + + filter = GTK_TREE_MODEL_FILTER (model); + gtk_tree_model_filter_convert_iter_to_child_iter (filter, &child_iter, &my_iter); + model = gtk_tree_model_filter_get_model (filter); + } + else + { + GtkTreeModelSort *sort; + + sort = GTK_TREE_MODEL_SORT (model); + gtk_tree_model_sort_convert_iter_to_child_iter (sort, &child_iter, &my_iter); + model = gtk_tree_model_sort_get_model (sort); + } + + my_iter = child_iter; + } + + if (GTK_IS_LIST_STORE (model)) + { + gtk_list_store_set (GTK_LIST_STORE (model), &my_iter, + GD_MAIN_COLUMN_SELECTED, value, + -1); + } + else + { + gtk_tree_store_set (GTK_TREE_STORE (model), &my_iter, + GD_MAIN_COLUMN_SELECTED, value, + -1); + } + + /* And tell the view model that something changed */ + path = gtk_tree_model_get_path (priv->model, iter); + if (path) + { + gtk_tree_model_row_changed (priv->model, path, iter); + gtk_tree_path_free (path); + } +} + +static void +selection_mode_do_select_range (GdMainView *self, + GtkTreeIter *first_element, + GtkTreeIter *last_element) +{ + GdMainViewPrivate *priv; + GtkTreeIter iter; + GtkTreePath *path, *last_path; + gboolean equal; + + priv = gd_main_view_get_instance_private (self); + + path = gtk_tree_model_get_path (priv->model, first_element); + last_path = gtk_tree_model_get_path (priv->model, last_element); + if (gtk_tree_path_compare (path, last_path) > 0) + { + gtk_tree_path_free (last_path); + last_path = path; + iter = *last_element; + } + else + { + gtk_tree_path_free (path); + iter = *first_element; + } + + do + { + do_select_row (self, &iter, TRUE); + + path = gtk_tree_model_get_path (priv->model, &iter); + equal = (gtk_tree_path_compare (path, last_path) == 0); + gtk_tree_path_free (path); + + if (equal) + break; + } + while (gtk_tree_model_iter_next (priv->model, &iter)); + + gtk_tree_path_free (last_path); +} + +static void +selection_mode_select_range (GdMainView *self, + GtkTreeIter *iter) +{ + GdMainViewPrivate *priv; + GtkTreeIter other; + gboolean found = FALSE; + gboolean selected; + char *id; + + priv = gd_main_view_get_instance_private (self); + + if (priv->last_selected_id != NULL && + gtk_tree_model_get_iter_first (priv->model, &other)) + { + do + { + gtk_tree_model_get (priv->model, &other, + GD_MAIN_COLUMN_ID, &id, + -1); + if (g_strcmp0 (id, priv->last_selected_id) == 0) + { + g_free (id); + found = TRUE; + break; + } + g_free (id); + } + while (gtk_tree_model_iter_next (priv->model, &other)); + } + + if (!found) + { + other = *iter; + while (gtk_tree_model_iter_previous (priv->model, &other)) + { + gtk_tree_model_get (priv->model, &other, + GD_MAIN_COLUMN_SELECTED, &selected, + -1); + + if (selected) + { + found = TRUE; + break; + } + } + } + + if (!found) + { + other = *iter; + while (gtk_tree_model_iter_next (priv->model, &other)) + { + gtk_tree_model_get (priv->model, &other, + GD_MAIN_COLUMN_SELECTED, &selected, + -1); + if (selected) + { + found = TRUE; + break; + } + } + } + + if (found) + selection_mode_do_select_range (self, iter, &other); + else + { + /* no other selected element found, just select the iter */ + do_select_row (self, iter, TRUE); + } + + g_signal_emit (self, signals[VIEW_SELECTION_CHANGED], 0); +} + +static gboolean +toggle_selection_for_path (GdMainView *self, + GtkTreePath *path, + gboolean select_range) +{ + GdMainViewPrivate *priv; + gboolean selected; + GtkTreeIter iter; + char *id; + + priv = gd_main_view_get_instance_private (self); + + if (priv->model == NULL) + return FALSE; + + if (!gtk_tree_model_get_iter (priv->model, &iter, path)) + return FALSE; + + gtk_tree_model_get (priv->model, &iter, + GD_MAIN_COLUMN_SELECTED, &selected, + -1); + + if (selected) + { + do_select_row (self, &iter, FALSE); + } + else if (!selected) + { + if (select_range) + selection_mode_select_range (self, &iter); + else + { + gtk_tree_model_get (priv->model, &iter, + GD_MAIN_COLUMN_ID, &id, + -1); + g_free (priv->last_selected_id); + priv->last_selected_id = id; + + do_select_row (self, &iter, TRUE); + } + } + + g_signal_emit (self, signals[VIEW_SELECTION_CHANGED], 0); + + return FALSE; +} + +static gboolean +activate_item_for_path (GdMainView *self, + GtkTreePath *path) +{ + GdMainViewPrivate *priv; + GtkTreeIter iter; + gchar *id; + + priv = gd_main_view_get_instance_private (self); + + if (priv->model == NULL) + return FALSE; + + if (!gtk_tree_model_get_iter (priv->model, &iter, path)) + return FALSE; + + gtk_tree_model_get (priv->model, &iter, + GD_MAIN_COLUMN_ID, &id, + -1); + + g_signal_emit (self, signals[ITEM_ACTIVATED], 0, id, path); + g_free (id); + + return FALSE; +} + +static gboolean +on_button_release_selection_mode (GdMainView *self, + GdkEventButton *event, + GtkTreePath *path) +{ + return toggle_selection_for_path (self, path, ((event->state & GDK_SHIFT_MASK) != 0)); +} + +static gboolean +on_button_release_view_mode (GdMainView *self, + GdkEventButton *event, + GtkTreePath *path) +{ + return activate_item_for_path (self, path); +} + +static gboolean +event_triggers_selection_mode (GdkEventButton *event) +{ + return + (event->button == 3) || + ((event->button == 1) && (event->state & GDK_CONTROL_MASK)); +} + +static gboolean +on_button_release_event (GtkWidget *view, + GdkEventButton *event, + gpointer user_data) +{ + GdMainView *self = user_data; + GdMainViewPrivate *priv; + GdMainViewGeneric *generic = get_generic (self); + GtkTreePath *path, *start_path, *end_path, *tmp_path; + GtkTreeIter iter; + gchar *button_release_item_path; + gboolean selection_mode; + gboolean res, same_item = FALSE; + gboolean is_selected; + + priv = gd_main_view_get_instance_private (self); + + /* eat double/triple click events */ + if (event->type != GDK_BUTTON_RELEASE) + return TRUE; + + path = gd_main_view_generic_get_path_at_pos (generic, event->x, event->y); + + if (path != NULL) + { + button_release_item_path = gtk_tree_path_to_string (path); + if (g_strcmp0 (priv->button_press_item_path, button_release_item_path) == 0) + same_item = TRUE; + + g_free (button_release_item_path); + } + + g_free (priv->button_press_item_path); + priv->button_press_item_path = NULL; + + priv->track_motion = FALSE; + if (priv->rubberband_select) + { + priv->rubberband_select = FALSE; + gd_main_view_generic_set_rubberband_range (get_generic (self), NULL, NULL); + if (priv->rubberband_select_last_path) + { + if (!priv->selection_mode) + g_signal_emit (self, signals[SELECTION_MODE_REQUEST], 0); + if (!priv->selection_mode) + { + res = FALSE; + goto out; + } + + start_path = gtk_tree_path_copy (priv->rubberband_select_first_path); + end_path = gtk_tree_path_copy (priv->rubberband_select_last_path); + if (gtk_tree_path_compare (start_path, end_path) > 0) + { + tmp_path = start_path; + start_path = end_path; + end_path = tmp_path; + } + + while (gtk_tree_path_compare (start_path, end_path) <= 0) + { + if (gtk_tree_model_get_iter (priv->model, + &iter, start_path)) + { + gtk_tree_model_get (priv->model, &iter, + GD_MAIN_COLUMN_SELECTED, &is_selected, + -1); + do_select_row (self, &iter, !is_selected); + } + + gtk_tree_path_next (start_path); + } + + g_signal_emit (self, signals[VIEW_SELECTION_CHANGED], 0); + + gtk_tree_path_free (start_path); + gtk_tree_path_free (end_path); + } + + g_clear_pointer (&priv->rubberband_select_first_path, + gtk_tree_path_free); + g_clear_pointer (&priv->rubberband_select_last_path, + gtk_tree_path_free); + + res = TRUE; + goto out; + } + + if (!same_item) + { + res = FALSE; + goto out; + } + + selection_mode = priv->selection_mode; + + if (!selection_mode) + { + if (event_triggers_selection_mode (event)) + { + g_signal_emit (self, signals[SELECTION_MODE_REQUEST], 0); + if (!priv->selection_mode) + { + res = FALSE; + goto out; + } + selection_mode = priv->selection_mode; + } + } + + if (selection_mode) + res = on_button_release_selection_mode (self, event, path); + else + res = on_button_release_view_mode (self, event, path); + + out: + gtk_tree_path_free (path); + return res; +} + +static gboolean +on_button_press_event (GtkWidget *view, + GdkEventButton *event, + gpointer user_data) +{ + GdMainView *self = user_data; + GdMainViewPrivate *priv; + GdMainViewGeneric *generic = get_generic (self); + GtkTreePath *path; + GList *selection, *l; + GtkTreePath *sel_path; + gboolean found = FALSE; + gboolean force_selection; + + priv = gd_main_view_get_instance_private (self); + + path = gd_main_view_generic_get_path_at_pos (generic, event->x, event->y); + + if (path != NULL) + priv->button_press_item_path = gtk_tree_path_to_string (path); + + force_selection = event_triggers_selection_mode (event); + if (!priv->selection_mode && !force_selection) + { + gtk_tree_path_free (path); + return FALSE; + } + + if (path && !force_selection) + { + selection = gd_main_view_get_selection (self); + + for (l = selection; l != NULL; l = l->next) + { + sel_path = l->data; + if (gtk_tree_path_compare (path, sel_path) == 0) + { + found = TRUE; + break; + } + } + + if (selection != NULL) + g_list_free_full (selection, (GDestroyNotify) gtk_tree_path_free); + } + + /* if we did not find the item in the selection, block + * drag and drop, while in selection mode + */ + if (!found) + { + priv->track_motion = TRUE; + priv->rubberband_select = FALSE; + priv->rubberband_select_first_path = NULL; + priv->rubberband_select_last_path = NULL; + priv->button_down_x = event->x; + priv->button_down_y = event->y; + return TRUE; + } + else + return FALSE; +} + +static gboolean +on_motion_event (GtkWidget *widget, + GdkEventMotion *event, + gpointer user_data) +{ + GdMainView *self = user_data; + GdMainViewPrivate *priv; + GtkTreePath *path; + + priv = gd_main_view_get_instance_private (self); + + if (priv->track_motion) + { + if (!priv->rubberband_select && + (event->x - priv->button_down_x) * (event->x - priv->button_down_x) + + (event->y - priv->button_down_y) * (event->y - priv->button_down_y) > + MAIN_VIEW_RUBBERBAND_SELECT_TRIGGER_LENGTH * MAIN_VIEW_RUBBERBAND_SELECT_TRIGGER_LENGTH) + { + priv->rubberband_select = TRUE; + if (priv->button_press_item_path) + { + priv->rubberband_select_first_path = + gtk_tree_path_new_from_string (priv->button_press_item_path); + } + } + + if (priv->rubberband_select) + { + path = gd_main_view_generic_get_path_at_pos (get_generic (self), event->x, event->y); + if (path != NULL) + { + if (priv->rubberband_select_first_path == NULL) + priv->rubberband_select_first_path = gtk_tree_path_copy (path); + + if (priv->rubberband_select_last_path == NULL || + gtk_tree_path_compare (priv->rubberband_select_last_path, path) != 0) + { + if (priv->rubberband_select_last_path) + gtk_tree_path_free (priv->rubberband_select_last_path); + priv->rubberband_select_last_path = path; + + gd_main_view_generic_set_rubberband_range (get_generic (self), + priv->rubberband_select_first_path, + priv->rubberband_select_last_path); + } + else + gtk_tree_path_free (path); + } + } + } + return FALSE; +} + +static void +on_drag_begin (GdMainViewGeneric *generic, + GdkDragContext *drag_context, + gpointer user_data) +{ + GdMainView *self = user_data; + GdMainViewPrivate *priv; + + priv = gd_main_view_get_instance_private (self); + + if (priv->button_press_item_path != NULL) + { + gboolean res; + GtkTreeIter iter; + gpointer data; + cairo_surface_t *surface = NULL; + GtkTreePath *path; + GType column_gtype; + + path = gtk_tree_path_new_from_string (priv->button_press_item_path); + res = gtk_tree_model_get_iter (priv->model, + &iter, path); + if (res) + gtk_tree_model_get (priv->model, &iter, + GD_MAIN_COLUMN_ICON, &data, + -1); + + column_gtype = gtk_tree_model_get_column_type (priv->model, + GD_MAIN_COLUMN_ICON); + + if (column_gtype == CAIRO_GOBJECT_TYPE_SURFACE) + { + surface = gd_copy_image_surface (data); + cairo_surface_destroy (data); + } + else if (column_gtype == GDK_TYPE_PIXBUF) + { + surface = gdk_cairo_surface_create_from_pixbuf (data, 1, NULL); + g_object_unref (data); + } + else + g_assert_not_reached (); + + if (priv->selection_mode && + surface != NULL) + { + GList *selection; + cairo_surface_t *counter; + + selection = gd_main_view_get_selection (self); + + if (g_list_length (selection) > 1) + { + counter = gd_create_surface_with_counter (GTK_WIDGET (self), surface, g_list_length (selection)); + cairo_surface_destroy (surface); + surface = counter; + } + + if (selection != NULL) + g_list_free_full (selection, (GDestroyNotify) gtk_tree_path_free); + } + + if (surface != NULL) + { + cairo_surface_set_device_offset (surface, + -MAIN_VIEW_DND_ICON_OFFSET, + -MAIN_VIEW_DND_ICON_OFFSET); + gtk_drag_set_icon_surface (drag_context, surface); + cairo_surface_destroy (surface); + } + + gtk_tree_path_free (path); + } +} + +static void +on_view_path_activated (GdMainView *self, + GtkTreePath *path) +{ + GdMainViewPrivate *priv; + GdkModifierType state; + + priv = gd_main_view_get_instance_private (self); + + gtk_get_current_event_state (&state); + + if (priv->selection_mode || (state & GDK_CONTROL_MASK) != 0) + { + if (!priv->selection_mode) + g_signal_emit (self, signals[SELECTION_MODE_REQUEST], 0); + toggle_selection_for_path (self, path, ((state & GDK_SHIFT_MASK) != 0)); + } + else + activate_item_for_path (self, path); +} + +static void +on_list_view_row_activated (GtkTreeView *tree_view, + GtkTreePath *path, + GtkTreeViewColumn *column, + gpointer user_data) +{ + GdMainView *self = user_data; + on_view_path_activated (self, path); +} + +static void +on_icon_view_item_activated (GtkIconView *icon_view, + GtkTreePath *path, + gpointer user_data) +{ + GdMainView *self = user_data; + on_view_path_activated (self, path); +} + +static void +on_view_selection_changed (GtkWidget *view, + gpointer user_data) +{ + GdMainView *self = user_data; + + g_signal_emit (self, signals[VIEW_SELECTION_CHANGED], 0); +} + +static void +on_row_deleted_cb (GtkTreeModel *model, + GtkTreePath *path, + gpointer user_data) +{ + GdMainView *self = user_data; + + g_signal_emit (self, signals[VIEW_SELECTION_CHANGED], 0); +} + +static void +gd_main_view_apply_model (GdMainView *self) +{ + GdMainViewPrivate *priv; + GdMainViewGeneric *generic = get_generic (self); + + priv = gd_main_view_get_instance_private (self); + gd_main_view_generic_set_model (generic, priv->model); +} + +static void +gd_main_view_apply_selection_mode (GdMainView *self) +{ + GdMainViewPrivate *priv; + GdMainViewGeneric *generic = get_generic (self); + + priv = gd_main_view_get_instance_private (self); + + gd_main_view_generic_set_selection_mode (generic, priv->selection_mode); + + if (!priv->selection_mode) + { + g_clear_pointer (&priv->last_selected_id, g_free); + if (priv->model != NULL) + gd_main_view_unselect_all (self); + } +} + +static void +gd_main_view_rebuild (GdMainView *self) +{ + GdMainViewPrivate *priv; + GtkStyleContext *context; + + priv = gd_main_view_get_instance_private (self); + + if (priv->current_view != NULL) + gtk_widget_destroy (priv->current_view); + + if (priv->current_type == GD_MAIN_VIEW_ICON) + { + priv->current_view = gd_main_icon_view_new (); + g_signal_connect (priv->current_view, "item-activated", + G_CALLBACK (on_icon_view_item_activated), self); + } + else + { + priv->current_view = gd_main_list_view_new (); + g_signal_connect (priv->current_view, "row-activated", + G_CALLBACK (on_list_view_row_activated), self); + } + + context = gtk_widget_get_style_context (priv->current_view); + gtk_style_context_add_class (context, "content-view"); + + gtk_container_add (GTK_CONTAINER (self), priv->current_view); + + g_signal_connect (priv->current_view, "button-press-event", + G_CALLBACK (on_button_press_event), self); + g_signal_connect (priv->current_view, "button-release-event", + G_CALLBACK (on_button_release_event), self); + g_signal_connect (priv->current_view, "motion-notify-event", + G_CALLBACK (on_motion_event), self); + g_signal_connect_after (priv->current_view, "drag-begin", + G_CALLBACK (on_drag_begin), self); + g_signal_connect (priv->current_view, "view-selection-changed", + G_CALLBACK (on_view_selection_changed), self); + + gd_main_view_apply_model (self); + gd_main_view_apply_selection_mode (self); + + gtk_widget_show_all (GTK_WIDGET (self)); +} + +GdMainView * +gd_main_view_new (GdMainViewType type) +{ + return g_object_new (GD_TYPE_MAIN_VIEW, + "view-type", type, + NULL); +} + +void +gd_main_view_set_view_type (GdMainView *self, + GdMainViewType type) +{ + GdMainViewPrivate *priv; + + priv = gd_main_view_get_instance_private (self); + + if (type != priv->current_type) + { + priv->current_type = type; + gd_main_view_rebuild (self); + + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_VIEW_TYPE]); + } +} + +GdMainViewType +gd_main_view_get_view_type (GdMainView *self) +{ + GdMainViewPrivate *priv; + + priv = gd_main_view_get_instance_private (self); + return priv->current_type; +} + +void +gd_main_view_set_selection_mode (GdMainView *self, + gboolean selection_mode) +{ + GdMainViewPrivate *priv; + + priv = gd_main_view_get_instance_private (self); + + if (selection_mode != priv->selection_mode) + { + priv->selection_mode = selection_mode; + gd_main_view_apply_selection_mode (self); + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SELECTION_MODE]); + } +} + +gboolean +gd_main_view_get_selection_mode (GdMainView *self) +{ + GdMainViewPrivate *priv; + + priv = gd_main_view_get_instance_private (self); + return priv->selection_mode; +} + +/** + * gd_main_view_set_model: + * @self: + * @model: (allow-none): + * + */ +void +gd_main_view_set_model (GdMainView *self, + GtkTreeModel *model) +{ + GdMainViewPrivate *priv; + + priv = gd_main_view_get_instance_private (self); + + if (model != priv->model) + { + if (priv->model) + g_signal_handlers_disconnect_by_func (priv->model, + on_row_deleted_cb, self); + + g_clear_object (&priv->model); + + if (model) + { + priv->model = g_object_ref (model); + g_signal_connect (priv->model, "row-deleted", + G_CALLBACK (on_row_deleted_cb), self); + } + else + { + priv->model = NULL; + } + + gd_main_view_apply_model (self); + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_MODEL]); + } +} + +/** + * gd_main_view_get_model: + * @self: + * + * Returns: (transfer none): + */ +GtkTreeModel * +gd_main_view_get_model (GdMainView *self) +{ + GdMainViewPrivate *priv; + + priv = gd_main_view_get_instance_private (self); + return priv->model; +} + +/** + * gd_main_view_get_generic_view: + * @self: + * + * Returns: (transfer none): + */ +GtkWidget * +gd_main_view_get_generic_view (GdMainView *self) +{ + GdMainViewPrivate *priv; + + priv = gd_main_view_get_instance_private (self); + return priv->current_view; +} + +static gboolean +build_selection_list_foreach (GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + gpointer user_data) +{ + GList **sel = user_data; + gboolean is_selected; + + gtk_tree_model_get (model, iter, + GD_MAIN_COLUMN_SELECTED, &is_selected, + -1); + + if (is_selected) + *sel = g_list_prepend (*sel, gtk_tree_path_copy (path)); + + return FALSE; +} + +/** + * gd_main_view_get_selection: + * @self: + * + * Returns: (element-type GtkTreePath) (transfer full): + */ +GList * +gd_main_view_get_selection (GdMainView *self) +{ + GdMainViewPrivate *priv; + GList *retval = NULL; + + priv = gd_main_view_get_instance_private (self); + + gtk_tree_model_foreach (priv->model, + build_selection_list_foreach, + &retval); + + return g_list_reverse (retval); +} + +void +gd_main_view_select_all (GdMainView *self) +{ + GdMainViewGeneric *generic = get_generic (self); + + gd_main_view_generic_select_all (generic); +} + +void +gd_main_view_unselect_all (GdMainView *self) +{ + GdMainViewGeneric *generic = get_generic (self); + + gd_main_view_generic_unselect_all (generic); +} diff --git a/subprojects/libgd/libgd/gd-main-view.h b/subprojects/libgd/libgd/gd-main-view.h new file mode 100644 index 00000000..4f8afe79 --- /dev/null +++ b/subprojects/libgd/libgd/gd-main-view.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2011 Red Hat, Inc. + * + * This program 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 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 Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Author: Cosimo Cecchi <cosimoc@redhat.com> + * + */ + +#ifndef __GD_MAIN_VIEW_H__ +#define __GD_MAIN_VIEW_H__ + +#include <glib-object.h> + +#include <gtk/gtk.h> + +G_BEGIN_DECLS + +#define GD_TYPE_MAIN_VIEW gd_main_view_get_type() +G_DECLARE_DERIVABLE_TYPE (GdMainView, gd_main_view, GD, MAIN_VIEW, GtkScrolledWindow) + +typedef enum { + GD_MAIN_VIEW_ICON, + GD_MAIN_VIEW_LIST +} GdMainViewType; + +struct _GdMainViewClass { + GtkScrolledWindowClass parent_class; +}; + +GdMainView * gd_main_view_new (GdMainViewType type); +void gd_main_view_set_view_type (GdMainView *self, + GdMainViewType type); +GdMainViewType gd_main_view_get_view_type (GdMainView *self); + +void gd_main_view_set_selection_mode (GdMainView *self, + gboolean selection_mode); +gboolean gd_main_view_get_selection_mode (GdMainView *self); + +GList * gd_main_view_get_selection (GdMainView *self); + +void gd_main_view_select_all (GdMainView *self); +void gd_main_view_unselect_all (GdMainView *self); + +GtkTreeModel * gd_main_view_get_model (GdMainView *self); +void gd_main_view_set_model (GdMainView *self, + GtkTreeModel *model); + +GtkWidget * gd_main_view_get_generic_view (GdMainView *self); + +G_END_DECLS + +#endif /* __GD_MAIN_VIEW_H__ */ diff --git a/subprojects/libgd/libgd/gd-margin-container.c b/subprojects/libgd/libgd/gd-margin-container.c new file mode 100644 index 00000000..20f2046e --- /dev/null +++ b/subprojects/libgd/libgd/gd-margin-container.c @@ -0,0 +1,377 @@ +/* + * Copyright (c) 2011 Red Hat, Inc. + * + * This program 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 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 Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Author: Cosimo Cecchi <cosimoc@redhat.com> + * + */ + +#include "config.h" + +#include "gd-margin-container.h" + +G_DEFINE_TYPE_WITH_CODE (GdMarginContainer, gd_margin_container, GTK_TYPE_BIN, + G_ADD_PRIVATE (GdMarginContainer) + G_IMPLEMENT_INTERFACE (GTK_TYPE_ORIENTABLE, + NULL)) + +struct _GdMarginContainerPrivate { + gint min_margin; + gint max_margin; + + GtkOrientation orientation; +}; + +enum { + PROP_MIN_MARGIN = 1, + PROP_MAX_MARGIN, + PROP_ORIENTATION, + NUM_PROPERTIES +}; + +static void +gd_margin_container_queue_redraw (GdMarginContainer *self) +{ + GtkWidget *child; + + /* Make sure that the widget and children are redrawn with the new setting: */ + child = gtk_bin_get_child (GTK_BIN (self)); + if (child) + gtk_widget_queue_resize (child); + + gtk_widget_queue_draw (GTK_WIDGET (self)); +} + +static void +gd_margin_container_set_orientation (GdMarginContainer *self, + GtkOrientation orientation) +{ + if (self->priv->orientation != orientation) + { + self->priv->orientation = orientation; + g_object_notify (G_OBJECT (self), "orientation"); + + gd_margin_container_queue_redraw (self); + } +} + +static void +gd_margin_container_set_min_margin (GdMarginContainer *self, + gint min_margin) +{ + if (self->priv->min_margin != min_margin) + { + self->priv->min_margin = min_margin; + g_object_notify (G_OBJECT (self), "min-margin"); + + gd_margin_container_queue_redraw (self); + } +} + +static void +gd_margin_container_set_max_margin (GdMarginContainer *self, + gint max_margin) +{ + if (self->priv->max_margin != max_margin) + { + self->priv->max_margin = max_margin; + g_object_notify (G_OBJECT (self), "max-margin"); + + gd_margin_container_queue_redraw (self); + } +} + +static void +gd_margin_container_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + GdMarginContainer *self = GD_MARGIN_CONTAINER (object); + + switch (property_id) + { + case PROP_MIN_MARGIN: + gd_margin_container_set_min_margin (self, g_value_get_int (value)); + break; + case PROP_MAX_MARGIN: + gd_margin_container_set_max_margin (self, g_value_get_int (value)); + break; + case PROP_ORIENTATION: + gd_margin_container_set_orientation (self, g_value_get_enum (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gd_margin_container_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + GdMarginContainer *self = GD_MARGIN_CONTAINER (object); + + switch (property_id) + { + case PROP_MIN_MARGIN: + g_value_set_int (value, self->priv->min_margin); + break; + case PROP_MAX_MARGIN: + g_value_set_int (value, self->priv->max_margin); + break; + case PROP_ORIENTATION: + g_value_set_enum (value, self->priv->orientation); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gd_margin_container_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GdMarginContainer *self = GD_MARGIN_CONTAINER (widget); + GtkWidget *child; + GtkAllocation child_allocation; + gint avail_width, avail_height; + + child = gtk_bin_get_child (GTK_BIN (widget)); + gtk_widget_set_allocation (widget, allocation); + + if (child && gtk_widget_get_visible (child)) + { + gint child_nat_width; + gint child_nat_height; + gint child_width, child_height; + gint offset; + + /* available */ + avail_width = allocation->width; + avail_height = allocation->height; + + if (self->priv->orientation == GTK_ORIENTATION_HORIZONTAL) + avail_width = MAX (1, avail_width - 2 * self->priv->min_margin); + else + avail_height = MAX (1, avail_height - 2 * self->priv->min_margin); + + if (gtk_widget_get_request_mode (child) == GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH) + { + gtk_widget_get_preferred_width (child, NULL, &child_nat_width); + child_width = MIN (avail_width, child_nat_width); + + gtk_widget_get_preferred_height_for_width (child, child_width, NULL, &child_nat_height); + child_height = MIN (avail_height, child_nat_height); + + offset = MIN ((gint) ((avail_height - child_height) / 2), self->priv->max_margin); + + if (offset > 0) + child_allocation.height = avail_height - (offset * 2); + else + child_allocation.height = avail_height; + + child_allocation.width = MIN (avail_width, child_nat_width); + } + else + { + gtk_widget_get_preferred_height (child, NULL, &child_nat_height); + child_height = MIN (avail_height, child_nat_height); + + gtk_widget_get_preferred_width_for_height (child, child_height, NULL, &child_nat_width); + child_width = MIN (avail_width, child_nat_width); + + offset = MIN ((gint) ((avail_width - child_width) / 2), self->priv->max_margin); + + if (offset > 0) + child_allocation.width = avail_width - (offset * 2); + else + child_allocation.width = avail_width; + + child_allocation.height = MIN (avail_height, child_nat_height); + } + + child_allocation.x = offset + allocation->x; + child_allocation.y = (avail_height - child_allocation.height) + allocation->y; + + if (self->priv->orientation == GTK_ORIENTATION_HORIZONTAL) + child_allocation.x += self->priv->min_margin; + else + child_allocation.y += self->priv->min_margin; + + gtk_widget_size_allocate (child, &child_allocation); + } +} + +static void +gd_margin_container_get_preferred_size (GtkWidget *widget, + GtkOrientation orientation, + gint for_size, + gint *minimum_size, + gint *natural_size) +{ + GdMarginContainer *self = GD_MARGIN_CONTAINER (widget); + guint natural, minimum; + GtkWidget *child; + + if (orientation == self->priv->orientation) + { + minimum = self->priv->min_margin * 2; + natural = self->priv->max_margin * 2; + } + else + { + minimum = 0; + natural = 0; + } + + if ((child = gtk_bin_get_child (GTK_BIN (widget))) && gtk_widget_get_visible (child)) + { + gint child_min, child_nat; + + if (orientation == GTK_ORIENTATION_HORIZONTAL) + { + if (for_size < 0) + gtk_widget_get_preferred_width (child, &child_min, &child_nat); + else + { + gint min_height; + + gtk_widget_get_preferred_height (child, &min_height, NULL); + for_size -= 2 * self->priv->min_margin; + + gtk_widget_get_preferred_width_for_height (child, for_size, &child_min, &child_nat); + } + } + else + { + if (for_size < 0) + gtk_widget_get_preferred_height (child, &child_min, &child_nat); + else + { + gint min_width; + + gtk_widget_get_preferred_width (child, &min_width, NULL); + for_size -= 2 * self->priv->min_margin; + + gtk_widget_get_preferred_height_for_width (child, for_size, &child_min, &child_nat); + } + } + + natural += child_nat; + + if (orientation != self->priv->orientation) + minimum += child_min; + } + + if (minimum_size != NULL) + *minimum_size = minimum; + if (natural_size != NULL) + *natural_size = natural; +} + +static void +gd_margin_container_get_preferred_width (GtkWidget *widget, + gint *minimum_size, + gint *natural_size) +{ + gd_margin_container_get_preferred_size (widget, GTK_ORIENTATION_HORIZONTAL, + -1, minimum_size, natural_size); +} + +static void +gd_margin_container_get_preferred_height (GtkWidget *widget, + gint *minimum_size, + gint *natural_size) +{ + gd_margin_container_get_preferred_size (widget, GTK_ORIENTATION_VERTICAL, + -1, minimum_size, natural_size); +} + +static void +gd_margin_container_get_preferred_width_for_height (GtkWidget *widget, + gint for_size, + gint *minimum_size, + gint *natural_size) +{ + gd_margin_container_get_preferred_size (widget, GTK_ORIENTATION_HORIZONTAL, + for_size, minimum_size, natural_size); +} + +static void +gd_margin_container_get_preferred_height_for_width (GtkWidget *widget, + gint for_size, + gint *minimum_size, + gint *natural_size) +{ + gd_margin_container_get_preferred_size (widget, GTK_ORIENTATION_VERTICAL, + for_size, minimum_size, natural_size); +} + +static void +gd_margin_container_init (GdMarginContainer *self) +{ + self->priv = gd_margin_container_get_instance_private (self); + + self->priv->orientation = GTK_ORIENTATION_HORIZONTAL; + + gtk_widget_set_has_window (GTK_WIDGET (self), FALSE); + gtk_widget_set_redraw_on_allocate (GTK_WIDGET (self), FALSE); +} + +static void +gd_margin_container_class_init (GdMarginContainerClass *klass) +{ + GObjectClass *oclass = G_OBJECT_CLASS (klass); + GtkWidgetClass *wclass = GTK_WIDGET_CLASS (klass); + + oclass->get_property = gd_margin_container_get_property; + oclass->set_property = gd_margin_container_set_property; + + wclass->size_allocate = gd_margin_container_size_allocate; + wclass->get_preferred_width = gd_margin_container_get_preferred_width; + wclass->get_preferred_height = gd_margin_container_get_preferred_height; + wclass->get_preferred_width_for_height = gd_margin_container_get_preferred_width_for_height; + wclass->get_preferred_height_for_width = gd_margin_container_get_preferred_height_for_width; + + gtk_container_class_handle_border_width (GTK_CONTAINER_CLASS (klass)); + + g_object_class_install_property (oclass, PROP_MIN_MARGIN, + g_param_spec_int ("min-margin", + "Min margin", + "Minimum margin around the child", + 0, G_MAXINT, 6, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); + g_object_class_install_property (oclass, PROP_MAX_MARGIN, + g_param_spec_int ("max-margin", + "Max margin", + "Maximum margin around the child", + 0, G_MAXINT, 6, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); + g_object_class_override_property (oclass, PROP_ORIENTATION, + "orientation"); +} + +GdMarginContainer * +gd_margin_container_new (void) +{ + return g_object_new (GD_TYPE_MARGIN_CONTAINER, NULL); +} diff --git a/subprojects/libgd/libgd/gd-margin-container.h b/subprojects/libgd/libgd/gd-margin-container.h new file mode 100644 index 00000000..3937ea75 --- /dev/null +++ b/subprojects/libgd/libgd/gd-margin-container.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2011 Red Hat, Inc. + * + * This program 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 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 Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Author: Cosimo Cecchi <cosimoc@redhat.com> + * + */ + +#ifndef _GD_MARGIN_CONTAINER_H +#define _GD_MARGIN_CONTAINER_H + +#include <glib-object.h> + +#include <gtk/gtk.h> + +G_BEGIN_DECLS + +#define GD_TYPE_MARGIN_CONTAINER gd_margin_container_get_type() + +#define GD_MARGIN_CONTAINER(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), \ + GD_TYPE_MARGIN_CONTAINER, GdMarginContainer)) + +#define GD_MARGIN_CONTAINER_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), \ + GD_TYPE_MARGIN_CONTAINER, GdMarginContainerClass)) + +#define GD_IS_MARGIN_CONTAINER(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \ + GD_TYPE_MARGIN_CONTAINER)) + +#define GD_IS_MARGIN_CONTAINER_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), \ + GD_TYPE_MARGIN_CONTAINER)) + +#define GD_MARGIN_CONTAINER_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), \ + GD_TYPE_MARGIN_CONTAINER, GdMarginContainerClass)) + +typedef struct _GdMarginContainer GdMarginContainer; +typedef struct _GdMarginContainerClass GdMarginContainerClass; +typedef struct _GdMarginContainerPrivate GdMarginContainerPrivate; + +struct _GdMarginContainer +{ + GtkBin parent; + + GdMarginContainerPrivate *priv; +}; + +struct _GdMarginContainerClass +{ + GtkBinClass parent_class; +}; + +GType gd_margin_container_get_type (void) G_GNUC_CONST; + +GdMarginContainer *gd_margin_container_new (void); + +G_END_DECLS + +#endif /* _GD_MARGIN_CONTAINER_H */ diff --git a/subprojects/libgd/libgd/gd-notification.c b/subprojects/libgd/libgd/gd-notification.c new file mode 100644 index 00000000..ba006faa --- /dev/null +++ b/subprojects/libgd/libgd/gd-notification.c @@ -0,0 +1,870 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * gd-notification + * Based on gtk-notification from gnome-contacts: + * http://git.gnome.org/browse/gnome-contacts/tree/src/gtk-notification.c?id=3.3.91 + * + * Copyright (C) Erick Pérez Castellanos 2011 <erick.red@gmail.com> + * Copyright (C) 2012 Red Hat, Inc. + * + * This program 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 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>."; + */ + +#include "gd-notification.h" + +/** + * SECTION:gdnotification + * @short_description: Report notification messages to the user + * @include: gtk/gtk.h + * @see_also: #GtkStatusbar, #GtkMessageDialog, #GtkInfoBar + * + * #GdNotification is a widget made for showing notifications to + * the user, allowing them to close the notification or wait for it + * to time out. + * + * #GdNotification provides one signal (#GdNotification::dismissed), for when the notification + * times out or is closed. + * + */ + +#define GTK_PARAM_READWRITE G_PARAM_READWRITE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB +#define SHADOW_OFFSET_X 2 +#define SHADOW_OFFSET_Y 3 +#define ANIMATION_TIME 200 /* msec */ +#define ANIMATION_STEP 40 /* msec */ + +enum { + PROP_0, + PROP_TIMEOUT, + PROP_SHOW_CLOSE_BUTTON +}; + +struct _GdNotificationPrivate { + GtkWidget *close_button; + gboolean show_close_button; + + GdkWindow *bin_window; + + int animate_y; /* from 0 to allocation.height */ + gboolean waiting_for_viewable; + gboolean revealed; + gboolean dismissed; + gboolean sent_dismissed; + guint animate_timeout; + + gint timeout; + guint timeout_source_id; +}; + +enum { + DISMISSED, + LAST_SIGNAL +}; + +static guint notification_signals[LAST_SIGNAL] = { 0 }; + +static gboolean gd_notification_draw (GtkWidget *widget, + cairo_t *cr); +static void gd_notification_get_preferred_width (GtkWidget *widget, + gint *minimum_size, + gint *natural_size); +static void gd_notification_get_preferred_height_for_width (GtkWidget *widget, + gint width, + gint *minimum_height, + gint *natural_height); +static void gd_notification_get_preferred_height (GtkWidget *widget, + gint *minimum_size, + gint *natural_size); +static void gd_notification_get_preferred_width_for_height (GtkWidget *widget, + gint height, + gint *minimum_width, + gint *natural_width); +static void gd_notification_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); +static gboolean gd_notification_timeout_cb (gpointer user_data); +static void gd_notification_show (GtkWidget *widget); +static void gd_notification_add (GtkContainer *container, + GtkWidget *child); + +/* signals handlers */ +static void gd_notification_close_button_clicked_cb (GtkWidget *widget, + gpointer user_data); + +G_DEFINE_TYPE_WITH_PRIVATE (GdNotification, gd_notification, GTK_TYPE_BIN) + +static void +gd_notification_init (GdNotification *notification) +{ + GtkWidget *close_button_image; + GtkStyleContext *context; + GdNotificationPrivate *priv; + + context = gtk_widget_get_style_context (GTK_WIDGET (notification)); + gtk_style_context_add_class (context, GTK_STYLE_CLASS_FRAME); + gtk_style_context_add_class (context, "app-notification"); + + gtk_widget_set_halign (GTK_WIDGET (notification), GTK_ALIGN_CENTER); + gtk_widget_set_valign (GTK_WIDGET (notification), GTK_ALIGN_START); + + gtk_widget_set_has_window (GTK_WIDGET (notification), TRUE); + + priv = notification->priv = gd_notification_get_instance_private (notification); + + priv->animate_y = 0; + priv->close_button = gtk_button_new (); + gtk_widget_set_parent (priv->close_button, GTK_WIDGET (notification)); + gtk_widget_show (priv->close_button); + g_object_set (priv->close_button, + "relief", GTK_RELIEF_NONE, + "focus-on-click", FALSE, + NULL); + g_signal_connect (priv->close_button, + "clicked", + G_CALLBACK (gd_notification_close_button_clicked_cb), + notification); + close_button_image = gtk_image_new_from_icon_name ("window-close-symbolic", GTK_ICON_SIZE_BUTTON); + gtk_button_set_image (GTK_BUTTON (notification->priv->close_button), close_button_image); + + priv->timeout_source_id = 0; +} + +static void +gd_notification_finalize (GObject *object) +{ + GdNotification *notification; + GdNotificationPrivate *priv; + + g_return_if_fail (GTK_IS_NOTIFICATION (object)); + + notification = GD_NOTIFICATION (object); + priv = notification->priv; + + if (priv->animate_timeout != 0) + g_source_remove (priv->animate_timeout); + + if (priv->timeout_source_id != 0) + g_source_remove (priv->timeout_source_id); + + G_OBJECT_CLASS (gd_notification_parent_class)->finalize (object); +} + +static void +gd_notification_destroy (GtkWidget *widget) +{ + GdNotification *notification = GD_NOTIFICATION (widget); + GdNotificationPrivate *priv = notification->priv; + + if (!priv->sent_dismissed) + { + g_signal_emit (notification, notification_signals[DISMISSED], 0); + priv->sent_dismissed = TRUE; + } + + if (priv->close_button) + { + gtk_widget_unparent (priv->close_button); + priv->close_button = NULL; + } + + GTK_WIDGET_CLASS (gd_notification_parent_class)->destroy (widget); +} + +static void +gd_notification_realize (GtkWidget *widget) +{ + GdNotification *notification = GD_NOTIFICATION (widget); + GdNotificationPrivate *priv = notification->priv; + GtkBin *bin = GTK_BIN (widget); + GtkAllocation allocation; + GtkWidget *child; + GdkWindow *window; + GdkWindowAttr attributes; + gint attributes_mask; + + gtk_widget_set_realized (widget, TRUE); + + gtk_widget_get_allocation (widget, &allocation); + + attributes.x = allocation.x; + attributes.y = allocation.y; + attributes.width = allocation.width; + attributes.height = allocation.height; + attributes.window_type = GDK_WINDOW_CHILD; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.visual = gtk_widget_get_visual (widget); + + attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK; + + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL; + + window = gdk_window_new (gtk_widget_get_parent_window (widget), + &attributes, attributes_mask); + gtk_widget_set_window (widget, window); + gtk_widget_register_window (widget, window); + + attributes.x = 0; + attributes.y = attributes.height + priv->animate_y; + attributes.event_mask = gtk_widget_get_events (widget) | + GDK_EXPOSURE_MASK | + GDK_VISIBILITY_NOTIFY_MASK | + GDK_ENTER_NOTIFY_MASK | + GDK_LEAVE_NOTIFY_MASK; + + priv->bin_window = gdk_window_new (window, &attributes, attributes_mask); + gtk_widget_register_window (widget, priv->bin_window); + + child = gtk_bin_get_child (bin); + if (child) + gtk_widget_set_parent_window (child, priv->bin_window); + gtk_widget_set_parent_window (priv->close_button, priv->bin_window); + + gdk_window_show (priv->bin_window); +} + +static void +gd_notification_unrealize (GtkWidget *widget) +{ + GdNotification *notification = GD_NOTIFICATION (widget); + GdNotificationPrivate *priv = notification->priv; + + gtk_widget_unregister_window (widget, priv->bin_window); + gdk_window_destroy (priv->bin_window); + priv->bin_window = NULL; + + GTK_WIDGET_CLASS (gd_notification_parent_class)->unrealize (widget); +} + +static int +animation_target (GdNotification *notification) +{ + GdNotificationPrivate *priv = notification->priv; + GtkAllocation allocation; + + if (priv->revealed) { + gtk_widget_get_allocation (GTK_WIDGET (notification), &allocation); + return allocation.height; + } else { + return 0; + } +} + +static gboolean +animation_timeout_cb (gpointer user_data) +{ + GdNotification *notification = GD_NOTIFICATION (user_data); + GdNotificationPrivate *priv = notification->priv; + GtkAllocation allocation; + int target, delta; + + target = animation_target (notification); + + if (priv->animate_y != target) { + gtk_widget_get_allocation (GTK_WIDGET (notification), &allocation); + + delta = allocation.height * ANIMATION_STEP / ANIMATION_TIME; + + if (priv->revealed) + priv->animate_y += delta; + else + priv->animate_y -= delta; + + priv->animate_y = CLAMP (priv->animate_y, 0, allocation.height); + + if (priv->bin_window != NULL) + gdk_window_move (priv->bin_window, + 0, + -allocation.height + priv->animate_y); + return G_SOURCE_CONTINUE; + } + + if (priv->dismissed && priv->animate_y == 0) + gtk_widget_destroy (GTK_WIDGET (notification)); + + priv->animate_timeout = 0; + return G_SOURCE_REMOVE; +} + +static void +start_animation (GdNotification *notification) +{ + GdNotificationPrivate *priv = notification->priv; + int target; + + if (priv->animate_timeout != 0) + return; /* Already running */ + + target = animation_target (notification); + if (priv->animate_y != target) + notification->priv->animate_timeout = + gdk_threads_add_timeout (ANIMATION_STEP, + animation_timeout_cb, + notification); +} + +static void +gd_notification_show (GtkWidget *widget) +{ + GdNotification *notification = GD_NOTIFICATION (widget); + GdNotificationPrivate *priv = notification->priv; + + GTK_WIDGET_CLASS (gd_notification_parent_class)->show (widget); + priv->revealed = TRUE; + priv->waiting_for_viewable = TRUE; +} + +static void +gd_notification_hide (GtkWidget *widget) +{ + GdNotification *notification = GD_NOTIFICATION (widget); + GdNotificationPrivate *priv = notification->priv; + + GTK_WIDGET_CLASS (gd_notification_parent_class)->hide (widget); + priv->revealed = FALSE; + priv->waiting_for_viewable = FALSE; +} + +static void +gd_notification_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) +{ + GdNotification *notification = GD_NOTIFICATION (object); + + g_return_if_fail (GTK_IS_NOTIFICATION (object)); + + switch (prop_id) { + case PROP_TIMEOUT: + gd_notification_set_timeout (notification, + g_value_get_int (value)); + break; + case PROP_SHOW_CLOSE_BUTTON: + gd_notification_set_show_close_button (notification, + g_value_get_boolean (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gd_notification_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) +{ + g_return_if_fail (GTK_IS_NOTIFICATION (object)); + GdNotification *notification = GD_NOTIFICATION (object); + + switch (prop_id) { + case PROP_TIMEOUT: + g_value_set_int (value, notification->priv->timeout); + break; + case PROP_SHOW_CLOSE_BUTTON: + g_value_set_boolean (value, + notification->priv->show_close_button); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gd_notification_forall (GtkContainer *container, + gboolean include_internals, + GtkCallback callback, + gpointer callback_data) +{ + GtkBin *bin = GTK_BIN (container); + GdNotification *notification = GD_NOTIFICATION (container); + GdNotificationPrivate *priv = notification->priv; + GtkWidget *child; + + child = gtk_bin_get_child (bin); + if (child) + (* callback) (child, callback_data); + + if (include_internals) + (* callback) (priv->close_button, callback_data); +} + +static void +unqueue_autohide (GdNotification *notification) +{ + GdNotificationPrivate *priv = notification->priv; + + if (priv->timeout_source_id) + { + g_source_remove (priv->timeout_source_id); + priv->timeout_source_id = 0; + } +} + +static void +queue_autohide (GdNotification *notification) +{ + GdNotificationPrivate *priv = notification->priv; + + if (priv->timeout_source_id == 0 && + priv->timeout != -1) + priv->timeout_source_id = + gdk_threads_add_timeout (priv->timeout * 1000, + gd_notification_timeout_cb, + notification); +} + +static gboolean +gd_notification_visibility_notify_event (GtkWidget *widget, + GdkEventVisibility *event) +{ + GdNotification *notification = GD_NOTIFICATION (widget); + GdNotificationPrivate *priv = notification->priv; + + if (!gtk_widget_get_visible (widget)) + return FALSE; + + if (priv->waiting_for_viewable) + { + start_animation (notification); + priv->waiting_for_viewable = FALSE; + } + + queue_autohide (notification); + + return FALSE; +} + +static gboolean +gd_notification_enter_notify (GtkWidget *widget, + GdkEventCrossing *event) +{ + GdNotification *notification = GD_NOTIFICATION (widget); + GdNotificationPrivate *priv = notification->priv; + + if ((event->window == priv->bin_window) && + (event->detail != GDK_NOTIFY_INFERIOR)) + { + unqueue_autohide (notification); + } + + return FALSE; +} + +static gboolean +gd_notification_leave_notify (GtkWidget *widget, + GdkEventCrossing *event) +{ + GdNotification *notification = GD_NOTIFICATION (widget); + GdNotificationPrivate *priv = notification->priv; + + if ((event->window == priv->bin_window) && + (event->detail != GDK_NOTIFY_INFERIOR)) + { + queue_autohide (notification); + } + + return FALSE; +} + +static void +gd_notification_class_init (GdNotificationClass *klass) +{ + GObjectClass* object_class = G_OBJECT_CLASS (klass); + GtkWidgetClass* widget_class = GTK_WIDGET_CLASS(klass); + GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass); + + object_class->finalize = gd_notification_finalize; + object_class->set_property = gd_notification_set_property; + object_class->get_property = gd_notification_get_property; + + widget_class->show = gd_notification_show; + widget_class->hide = gd_notification_hide; + widget_class->destroy = gd_notification_destroy; + widget_class->get_preferred_width = gd_notification_get_preferred_width; + widget_class->get_preferred_height_for_width = gd_notification_get_preferred_height_for_width; + widget_class->get_preferred_height = gd_notification_get_preferred_height; + widget_class->get_preferred_width_for_height = gd_notification_get_preferred_width_for_height; + widget_class->size_allocate = gd_notification_size_allocate; + widget_class->draw = gd_notification_draw; + widget_class->realize = gd_notification_realize; + widget_class->unrealize = gd_notification_unrealize; + widget_class->visibility_notify_event = gd_notification_visibility_notify_event; + widget_class->enter_notify_event = gd_notification_enter_notify; + widget_class->leave_notify_event = gd_notification_leave_notify; + + container_class->add = gd_notification_add; + container_class->forall = gd_notification_forall; + gtk_container_class_handle_border_width (container_class); + + + /** + * GdNotification:timeout: + * + * The time it takes to hide the widget, in seconds. + * + * Since: 0.1 + */ + g_object_class_install_property (object_class, + PROP_TIMEOUT, + g_param_spec_int("timeout", "timeout", + "The time it takes to hide the widget, in seconds", + -1, G_MAXINT, -1, + GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT)); + g_object_class_install_property (object_class, + PROP_SHOW_CLOSE_BUTTON, + g_param_spec_boolean("show-close-button", "show-close-button", + "Whether to show a stock close button that dismisses the notification", + TRUE, + GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT)); + + notification_signals[DISMISSED] = g_signal_new ("dismissed", + G_OBJECT_CLASS_TYPE (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GdNotificationClass, dismissed), + NULL, + NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, + 0); +} + +static void +get_padding_and_border (GdNotification *notification, + GtkBorder *border) +{ + GtkStyleContext *context; + GtkStateFlags state; + GtkBorder tmp; + + context = gtk_widget_get_style_context (GTK_WIDGET (notification)); + state = gtk_widget_get_state_flags (GTK_WIDGET (notification)); + + gtk_style_context_get_padding (context, state, border); + + gtk_style_context_get_border (context, state, &tmp); + border->top += tmp.top; + border->right += tmp.right; + border->bottom += tmp.bottom; + border->left += tmp.left; +} + +static gboolean +gd_notification_draw (GtkWidget *widget, cairo_t *cr) +{ + GdNotification *notification = GD_NOTIFICATION (widget); + GdNotificationPrivate *priv = notification->priv; + GtkStyleContext *context; + + if (gtk_cairo_should_draw_window (cr, priv->bin_window)) + { + context = gtk_widget_get_style_context (widget); + + gtk_render_background (context, cr, + 0, 0, + gtk_widget_get_allocated_width (widget), + gtk_widget_get_allocated_height (widget)); + gtk_render_frame (context,cr, + 0, 0, + gtk_widget_get_allocated_width (widget), + gtk_widget_get_allocated_height (widget)); + + + if (GTK_WIDGET_CLASS (gd_notification_parent_class)->draw) + GTK_WIDGET_CLASS (gd_notification_parent_class)->draw(widget, cr); + } + + return FALSE; +} + +static void +gd_notification_add (GtkContainer *container, + GtkWidget *child) +{ + GtkBin *bin = GTK_BIN (container); + GdNotification *notification = GD_NOTIFICATION (bin); + GdNotificationPrivate *priv = notification->priv; + + g_return_if_fail (gtk_bin_get_child (bin) == NULL); + + gtk_widget_set_parent_window (child, priv->bin_window); + + GTK_CONTAINER_CLASS (gd_notification_parent_class)->add (container, child); +} + + +static void +gd_notification_get_preferred_width (GtkWidget *widget, gint *minimum_size, gint *natural_size) +{ + GdNotification *notification = GD_NOTIFICATION (widget); + GdNotificationPrivate *priv = notification->priv; + GtkBin *bin = GTK_BIN (widget); + gint child_min, child_nat; + GtkWidget *child; + GtkBorder padding; + gint minimum, natural; + + get_padding_and_border (notification, &padding); + + minimum = 0; + natural = 0; + + child = gtk_bin_get_child (bin); + if (child && gtk_widget_get_visible (child)) + { + gtk_widget_get_preferred_width (child, + &child_min, &child_nat); + minimum += child_min; + natural += child_nat; + } + + if (priv->show_close_button) + { + gtk_widget_get_preferred_width (priv->close_button, + &child_min, &child_nat); + minimum += child_min; + natural += child_nat; + } + + minimum += padding.left + padding.right + 2 * SHADOW_OFFSET_X; + natural += padding.left + padding.right + 2 * SHADOW_OFFSET_X; + + if (minimum_size) + *minimum_size = minimum; + + if (natural_size) + *natural_size = natural; +} + +static void +gd_notification_get_preferred_width_for_height (GtkWidget *widget, + gint height, + gint *minimum_width, + gint *natural_width) +{ + GdNotification *notification = GD_NOTIFICATION (widget); + GdNotificationPrivate *priv = notification->priv; + GtkBin *bin = GTK_BIN (widget); + gint child_min, child_nat, child_height; + GtkWidget *child; + GtkBorder padding; + gint minimum, natural; + + get_padding_and_border (notification, &padding); + + minimum = 0; + natural = 0; + + child_height = height - SHADOW_OFFSET_Y - padding.top - padding.bottom; + + child = gtk_bin_get_child (bin); + if (child && gtk_widget_get_visible (child)) + { + gtk_widget_get_preferred_width_for_height (child, child_height, + &child_min, &child_nat); + minimum += child_min; + natural += child_nat; + } + + if (priv->show_close_button) + { + gtk_widget_get_preferred_width_for_height (priv->close_button, child_height, + &child_min, &child_nat); + minimum += child_min; + natural += child_nat; + } + + minimum += padding.left + padding.right + 2 * SHADOW_OFFSET_X; + natural += padding.left + padding.right + 2 * SHADOW_OFFSET_X; + + if (minimum_width) + *minimum_width = minimum; + + if (natural_width) + *natural_width = natural; +} + +static void +gd_notification_get_preferred_height_for_width (GtkWidget *widget, + gint width, + gint *minimum_height, + gint *natural_height) +{ + GdNotification *notification = GD_NOTIFICATION (widget); + GdNotificationPrivate *priv = notification->priv; + GtkBin *bin = GTK_BIN (widget); + gint child_min, child_nat, child_width, button_width = 0; + GtkWidget *child; + GtkBorder padding; + gint minimum = 0, natural = 0; + + get_padding_and_border (notification, &padding); + + if (priv->show_close_button) + { + gtk_widget_get_preferred_height (priv->close_button, + &minimum, &natural); + gtk_widget_get_preferred_width (priv->close_button, + NULL, &button_width); + } + + child = gtk_bin_get_child (bin); + if (child && gtk_widget_get_visible (child)) + { + child_width = width - button_width - + 2 * SHADOW_OFFSET_X - padding.left - padding.right; + + gtk_widget_get_preferred_height_for_width (child, child_width, + &child_min, &child_nat); + minimum = MAX (minimum, child_min); + natural = MAX (natural, child_nat); + } + + minimum += padding.top + padding.bottom + SHADOW_OFFSET_Y; + natural += padding.top + padding.bottom + SHADOW_OFFSET_Y; + + if (minimum_height) + *minimum_height = minimum; + + if (natural_height) + *natural_height = natural; +} + +static void +gd_notification_get_preferred_height (GtkWidget *widget, + gint *minimum_height, + gint *natural_height) +{ + gint width; + + gd_notification_get_preferred_width (widget, &width, NULL); + gd_notification_get_preferred_height_for_width (widget, width, + minimum_height, natural_height); +} + +static void +gd_notification_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GdNotification *notification = GD_NOTIFICATION (widget); + GdNotificationPrivate *priv = notification->priv; + GtkBin *bin = GTK_BIN (widget); + GtkAllocation child_allocation; + GtkBorder padding; + GtkRequisition button_req; + GtkWidget *child; + + gtk_widget_set_allocation (widget, allocation); + + /* If somehow the notification changes while not hidden + and we're not animating, immediately follow the resize */ + if (priv->animate_y > 0 && + !priv->animate_timeout) + priv->animate_y = allocation->height; + + get_padding_and_border (notification, &padding); + + if (gtk_widget_get_realized (widget)) + { + gdk_window_move_resize (gtk_widget_get_window (widget), + allocation->x, + allocation->y, + allocation->width, + allocation->height); + gdk_window_move_resize (priv->bin_window, + 0, + -allocation->height + priv->animate_y, + allocation->width, + allocation->height); + } + + child_allocation.x = SHADOW_OFFSET_X + padding.left; + child_allocation.y = padding.top; + + if (priv->show_close_button) + gtk_widget_get_preferred_size (priv->close_button, &button_req, NULL); + else + button_req.width = button_req.height = 0; + + child_allocation.height = MAX (1, allocation->height - SHADOW_OFFSET_Y - padding.top - padding.bottom); + child_allocation.width = MAX (1, (allocation->width - button_req.width - + 2 * SHADOW_OFFSET_X - padding.left - padding.right)); + + child = gtk_bin_get_child (bin); + if (child && gtk_widget_get_visible (child)) + gtk_widget_size_allocate (child, &child_allocation); + + if (priv->show_close_button) + { + child_allocation.x += child_allocation.width; + child_allocation.width = button_req.width; + child_allocation.y += (child_allocation.height - button_req.height) / 2; + child_allocation.height = button_req.height; + + gtk_widget_size_allocate (priv->close_button, &child_allocation); + } +} + +static gboolean +gd_notification_timeout_cb (gpointer user_data) +{ + GdNotification *notification = GD_NOTIFICATION (user_data); + + gd_notification_dismiss (notification); + + return G_SOURCE_REMOVE; +} + +void +gd_notification_set_timeout (GdNotification *notification, + gint timeout_sec) +{ + GdNotificationPrivate *priv = notification->priv; + + priv->timeout = timeout_sec; + g_object_notify (G_OBJECT (notification), "timeout"); +} + +void +gd_notification_set_show_close_button (GdNotification *notification, + gboolean show_close_button) +{ + GdNotificationPrivate *priv = notification->priv; + + priv->show_close_button = show_close_button; + + gtk_widget_set_visible (priv->close_button, show_close_button); + gtk_widget_queue_resize (GTK_WIDGET (notification)); +} + +void +gd_notification_dismiss (GdNotification *notification) +{ + GdNotificationPrivate *priv = notification->priv; + + unqueue_autohide (notification); + + priv->dismissed = TRUE; + priv->revealed = FALSE; + start_animation (notification); +} + +static void +gd_notification_close_button_clicked_cb (GtkWidget *widget, gpointer user_data) +{ + GdNotification *notification = GD_NOTIFICATION(user_data); + + gd_notification_dismiss (notification); +} + +GtkWidget * +gd_notification_new (void) +{ + return g_object_new (GD_TYPE_NOTIFICATION, NULL); +} diff --git a/subprojects/libgd/libgd/gd-notification.h b/subprojects/libgd/libgd/gd-notification.h new file mode 100644 index 00000000..8efa191a --- /dev/null +++ b/subprojects/libgd/libgd/gd-notification.h @@ -0,0 +1,67 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * gd-notification + * Based on gtk-notification from gnome-contacts: + * http://git.gnome.org/browse/gnome-contacts/tree/src/gtk-notification.c?id=3.3.91 + * + * Copyright (C) Erick Pérez Castellanos 2011 <erick.red@gmail.com> + * Copyright (C) 2012 Red Hat, Inc. + * + * This program 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 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>."; + */ + +#ifndef _GD_NOTIFICATION_H_ +#define _GD_NOTIFICATION_H_ + +#include <gtk/gtk.h> + +G_BEGIN_DECLS + +#define GD_TYPE_NOTIFICATION (gd_notification_get_type ()) +#define GD_NOTIFICATION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GD_TYPE_NOTIFICATION, GdNotification)) +#define GD_NOTIFICATION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GD_TYPE_NOTIFICATION, GdNotificationClass)) +#define GTK_IS_NOTIFICATION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GD_TYPE_NOTIFICATION)) +#define GTK_IS_NOTIFICATION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GD_TYPE_NOTIFICATION)) +#define GD_NOTIFICATION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GD_TYPE_NOTIFICATION, GdNotificationClass)) + +typedef struct _GdNotificationPrivate GdNotificationPrivate; +typedef struct _GdNotificationClass GdNotificationClass; +typedef struct _GdNotification GdNotification; + +struct _GdNotificationClass { + GtkBinClass parent_class; + + /* Signals */ + void (*dismissed) (GdNotification *self); +}; + +struct _GdNotification { + GtkBin parent_instance; + + /*< private > */ + GdNotificationPrivate *priv; +}; + +GType gd_notification_get_type (void) G_GNUC_CONST; + +GtkWidget *gd_notification_new (void); +void gd_notification_set_timeout (GdNotification *notification, + gint timeout_sec); +void gd_notification_dismiss (GdNotification *notification); +void gd_notification_set_show_close_button (GdNotification *notification, + gboolean show_close_button); + +G_END_DECLS + +#endif /* _GD_NOTIFICATION_H_ */ diff --git a/subprojects/libgd/libgd/gd-styled-text-renderer.c b/subprojects/libgd/libgd/gd-styled-text-renderer.c new file mode 100644 index 00000000..bdf72d2a --- /dev/null +++ b/subprojects/libgd/libgd/gd-styled-text-renderer.c @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2011 Red Hat, Inc. + * + * This program 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 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 Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Author: Cosimo Cecchi <cosimoc@redhat.com> + * + */ + +#include "gd-styled-text-renderer.h" + +typedef struct _GdStyledTextRendererPrivate GdStyledTextRendererPrivate; + +struct _GdStyledTextRendererPrivate { + GList *style_classes; +}; + +G_DEFINE_TYPE_WITH_PRIVATE (GdStyledTextRenderer, gd_styled_text_renderer, GTK_TYPE_CELL_RENDERER_TEXT) + +static void +gd_styled_text_renderer_render (GtkCellRenderer *cell, + cairo_t *cr, + GtkWidget *widget, + const GdkRectangle *background_area, + const GdkRectangle *cell_area, + GtkCellRendererState flags) +{ + GdStyledTextRenderer *self = GD_STYLED_TEXT_RENDERER (cell); + GdStyledTextRendererPrivate *priv; + GtkStyleContext *context; + const gchar *style_class; + GList *l; + + priv = gd_styled_text_renderer_get_instance_private (self); + + context = gtk_widget_get_style_context (widget); + gtk_style_context_save (context); + + for (l = priv->style_classes; l != NULL; l = l->next) + { + style_class = l->data; + gtk_style_context_add_class (context, style_class); + } + + GTK_CELL_RENDERER_CLASS (gd_styled_text_renderer_parent_class)->render + (cell, cr, widget, + background_area, cell_area, flags); + + gtk_style_context_restore (context); +} + +static void +gd_styled_text_renderer_finalize (GObject *obj) +{ + GdStyledTextRenderer *self = GD_STYLED_TEXT_RENDERER (obj); + GdStyledTextRendererPrivate *priv; + + priv = gd_styled_text_renderer_get_instance_private (self); + + if (priv->style_classes != NULL) + { + g_list_free_full (priv->style_classes, g_free); + priv->style_classes = NULL; + } + + G_OBJECT_CLASS (gd_styled_text_renderer_parent_class)->finalize (obj); +} + +static void +gd_styled_text_renderer_class_init (GdStyledTextRendererClass *klass) +{ + GtkCellRendererClass *crclass = GTK_CELL_RENDERER_CLASS (klass); + GObjectClass *oclass = G_OBJECT_CLASS (klass); + + oclass->finalize = gd_styled_text_renderer_finalize; + crclass->render = gd_styled_text_renderer_render; +} + +static void +gd_styled_text_renderer_init (GdStyledTextRenderer *self) +{ +} + +GtkCellRenderer * +gd_styled_text_renderer_new (void) +{ + return g_object_new (GD_TYPE_STYLED_TEXT_RENDERER, + NULL); +} + +void +gd_styled_text_renderer_add_class (GdStyledTextRenderer *self, + const gchar *class) +{ + GdStyledTextRendererPrivate *priv; + + priv = gd_styled_text_renderer_get_instance_private (self); + + if (g_list_find_custom (priv->style_classes, class, (GCompareFunc) g_strcmp0)) + return; + + priv->style_classes = g_list_append (priv->style_classes, g_strdup (class)); +} + +void +gd_styled_text_renderer_remove_class (GdStyledTextRenderer *self, + const gchar *class) +{ + GdStyledTextRendererPrivate *priv; + GList *class_element; + + priv = gd_styled_text_renderer_get_instance_private (self); + + class_element = g_list_find_custom (priv->style_classes, class, (GCompareFunc) g_strcmp0); + + if (class_element == NULL) + return; + + priv->style_classes = g_list_remove_link (priv->style_classes, class_element); + g_free (class_element->data); + g_list_free_1 (class_element); +} diff --git a/subprojects/libgd/libgd/gd-styled-text-renderer.h b/subprojects/libgd/libgd/gd-styled-text-renderer.h new file mode 100644 index 00000000..42f606b0 --- /dev/null +++ b/subprojects/libgd/libgd/gd-styled-text-renderer.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2011 Red Hat, Inc. + * + * This program 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 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 Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Author: Cosimo Cecchi <cosimoc@redhat.com> + * + */ + +#ifndef _GD_STYLED_TEXT_RENDERER_H +#define _GD_STYLED_TEXT_RENDERER_H + +#include <glib-object.h> + +#include <gtk/gtk.h> + +G_BEGIN_DECLS + +#define GD_TYPE_STYLED_TEXT_RENDERER gd_styled_text_renderer_get_type() +G_DECLARE_DERIVABLE_TYPE (GdStyledTextRenderer, + gd_styled_text_renderer, + GD, + STYLED_TEXT_RENDERER, + GtkCellRendererText) + +struct _GdStyledTextRendererClass +{ + GtkCellRendererTextClass parent_class; +}; + +GtkCellRenderer *gd_styled_text_renderer_new (void); +void gd_styled_text_renderer_add_class (GdStyledTextRenderer *self, + const gchar *class); +void gd_styled_text_renderer_remove_class (GdStyledTextRenderer *self, + const gchar *class); + +G_END_DECLS + +#endif /* _GD_STYLED_TEXT_RENDERER_H */ diff --git a/subprojects/libgd/libgd/gd-tagged-entry.c b/subprojects/libgd/libgd/gd-tagged-entry.c new file mode 100644 index 00000000..5db139e8 --- /dev/null +++ b/subprojects/libgd/libgd/gd-tagged-entry.c @@ -0,0 +1,1240 @@ +/* + * Copyright (c) 2011 Red Hat, Inc. + * Copyright (c) 2013 Ignacio Casal Quinteiro + * + * This program 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 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 Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Author: Cosimo Cecchi <cosimoc@redhat.com> + * + */ + +#include "gd-tagged-entry.h" + +#include <math.h> + +#define BUTTON_INTERNAL_SPACING 6 + +struct _GdTaggedEntryTagPrivate { + GdTaggedEntry *entry; + GdkWindow *window; + PangoLayout *layout; + + gchar *label; + gchar *style; + gboolean has_close_button; + + cairo_surface_t *close_surface; + GtkStateFlags last_button_state; +}; + +struct _GdTaggedEntryPrivate { + GList *tags; + + GdTaggedEntryTag *in_child; + gboolean in_child_button; + gboolean in_child_active; + gboolean in_child_button_active; + gboolean button_visible; +}; + +enum { + SIGNAL_TAG_CLICKED, + SIGNAL_TAG_BUTTON_CLICKED, + LAST_SIGNAL +}; + +enum { + PROP_0, + PROP_TAG_BUTTON_VISIBLE, + NUM_PROPERTIES +}; + +enum { + PROP_TAG_0, + PROP_TAG_LABEL, + PROP_TAG_HAS_CLOSE_BUTTON, + PROP_TAG_STYLE, + NUM_TAG_PROPERTIES +}; + +G_DEFINE_TYPE_WITH_PRIVATE (GdTaggedEntry, gd_tagged_entry, GTK_TYPE_SEARCH_ENTRY) +G_DEFINE_TYPE_WITH_PRIVATE (GdTaggedEntryTag, gd_tagged_entry_tag, G_TYPE_OBJECT) + +static guint signals[LAST_SIGNAL] = { 0, }; +static GParamSpec *properties[NUM_PROPERTIES] = { NULL, }; +static GParamSpec *tag_properties[NUM_TAG_PROPERTIES] = { NULL, }; + +static void gd_tagged_entry_get_text_area_size (GtkEntry *entry, + gint *x, + gint *y, + gint *width, + gint *height); +static gint gd_tagged_entry_tag_get_width (GdTaggedEntryTag *tag, + GdTaggedEntry *entry); +static GtkStyleContext * gd_tagged_entry_tag_get_context (GdTaggedEntryTag *tag, + GdTaggedEntry *entry); + +static void +gd_tagged_entry_tag_get_margin (GdTaggedEntryTag *tag, + GdTaggedEntry *entry, + GtkBorder *margin) +{ + GtkStyleContext *context; + + context = gd_tagged_entry_tag_get_context (tag, entry); + gtk_style_context_set_state (context, GTK_STATE_FLAG_NORMAL); + gtk_style_context_get_margin (context, + gtk_style_context_get_state (context), + margin); + gtk_style_context_restore (context); +} + +static void +gd_tagged_entry_tag_ensure_close_surface (GdTaggedEntryTag *tag, + GtkStyleContext *context) +{ + GtkIconInfo *info; + GdkPixbuf *pixbuf; + gint icon_size; + gint scale_factor; + + if (tag->priv->close_surface != NULL) + return; + + gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, + &icon_size, NULL); + scale_factor = gtk_widget_get_scale_factor (GTK_WIDGET (tag->priv->entry)); + + info = gtk_icon_theme_lookup_icon_for_scale (gtk_icon_theme_get_default (), + "window-close-symbolic", + icon_size, scale_factor, + GTK_ICON_LOOKUP_GENERIC_FALLBACK); + + /* FIXME: we need a fallback icon in case the icon is not found */ + pixbuf = gtk_icon_info_load_symbolic_for_context (info, context, NULL, NULL); + tag->priv->close_surface = gdk_cairo_surface_create_from_pixbuf (pixbuf, scale_factor, tag->priv->window); + + g_object_unref (info); + g_object_unref (pixbuf); +} + +static gint +gd_tagged_entry_tag_panel_get_height (GdTaggedEntryTag *tag, + GdTaggedEntry *entry) +{ + GtkWidget *widget = GTK_WIDGET (entry); + gint height, req_height; + GtkRequisition requisition; + GtkAllocation allocation; + GtkBorder margin; + + gtk_widget_get_allocation (widget, &allocation); + gtk_widget_get_preferred_size (widget, &requisition, NULL); + gd_tagged_entry_tag_get_margin (tag, entry, &margin); + + /* the tag panel height is the whole entry height, minus the tag margins */ + req_height = requisition.height - gtk_widget_get_margin_top (widget) - gtk_widget_get_margin_bottom (widget); + height = MIN (req_height, allocation.height) - margin.top - margin.bottom; + + return height; +} + +static void +gd_tagged_entry_tag_panel_get_position (GdTaggedEntry *self, + gint *x_out, + gint *y_out) +{ + GtkWidget *widget = GTK_WIDGET (self); + gint text_x, text_y, text_width, text_height, req_height; + GtkAllocation allocation; + GtkRequisition requisition; + + gtk_widget_get_allocation (widget, &allocation); + gtk_widget_get_preferred_size (widget, &requisition, NULL); + req_height = requisition.height - gtk_widget_get_margin_top (widget) - gtk_widget_get_margin_bottom (widget); + + gd_tagged_entry_get_text_area_size (GTK_ENTRY (self), &text_x, &text_y, &text_width, &text_height); + + /* allocate the panel immediately after the text area */ + if (x_out) + *x_out = allocation.x + text_x + text_width; + if (y_out) + *y_out = allocation.y + (gint) floor ((allocation.height - req_height) / 2); +} + +static gint +gd_tagged_entry_tag_panel_get_width (GdTaggedEntry *self) +{ + GdTaggedEntryTag *tag; + gint width; + GList *l; + + width = 0; + + for (l = self->priv->tags; l != NULL; l = l->next) + { + tag = l->data; + width += gd_tagged_entry_tag_get_width (tag, self); + } + + return width; +} + +static void +gd_tagged_entry_tag_ensure_layout (GdTaggedEntryTag *tag, + GdTaggedEntry *entry) +{ + if (tag->priv->layout != NULL) + return; + + tag->priv->layout = pango_layout_new (gtk_widget_get_pango_context (GTK_WIDGET (entry))); + pango_layout_set_text (tag->priv->layout, tag->priv->label, -1); +} + +static GtkStateFlags +gd_tagged_entry_tag_get_state (GdTaggedEntryTag *tag, + GdTaggedEntry *entry) +{ + GtkStateFlags state = GTK_STATE_FLAG_NORMAL; + + if (entry->priv->in_child == tag) + state |= GTK_STATE_FLAG_PRELIGHT; + + if (entry->priv->in_child_active) + state |= GTK_STATE_FLAG_ACTIVE; + + return state; +} + +static GtkStateFlags +gd_tagged_entry_tag_get_button_state (GdTaggedEntryTag *tag, + GdTaggedEntry *entry) +{ + GtkStateFlags state = GTK_STATE_FLAG_NORMAL; + + if (entry->priv->in_child == tag) + { + if (entry->priv->in_child_button_active) + state |= GTK_STATE_FLAG_ACTIVE; + + else if (entry->priv->in_child_button) + state |= GTK_STATE_FLAG_PRELIGHT; + } + + return state; +} + +static GtkStyleContext * +gd_tagged_entry_tag_get_context (GdTaggedEntryTag *tag, + GdTaggedEntry *entry) +{ + GtkWidget *widget = GTK_WIDGET (entry); + GtkStyleContext *retval; + GList *l, *list; + + retval = gtk_widget_get_style_context (widget); + gtk_style_context_save (retval); + + list = gtk_style_context_list_classes (retval); + for (l = list; l; l = l->next) + gtk_style_context_remove_class (retval, l->data); + g_list_free (list); + gtk_style_context_add_class (retval, tag->priv->style); + + return retval; +} + +static gint +gd_tagged_entry_tag_get_width (GdTaggedEntryTag *tag, + GdTaggedEntry *entry) +{ + GtkBorder button_padding, button_border, button_margin; + GtkStyleContext *context; + GtkStateFlags state; + gint layout_width; + gint button_width; + gint scale_factor; + + gd_tagged_entry_tag_ensure_layout (tag, entry); + pango_layout_get_pixel_size (tag->priv->layout, &layout_width, NULL); + + context = gd_tagged_entry_tag_get_context (tag, entry); + state = gd_tagged_entry_tag_get_state (tag, entry); + + gtk_style_context_set_state (context, state); + gtk_style_context_get_padding (context, + gtk_style_context_get_state (context), + &button_padding); + gtk_style_context_get_border (context, + gtk_style_context_get_state (context), + &button_border); + gtk_style_context_get_margin (context, + gtk_style_context_get_state (context), + &button_margin); + + gd_tagged_entry_tag_ensure_close_surface (tag, context); + + gtk_style_context_restore (context); + + button_width = 0; + if (entry->priv->button_visible && tag->priv->has_close_button) + { + scale_factor = gtk_widget_get_scale_factor (GTK_WIDGET (entry)); + button_width = cairo_image_surface_get_width (tag->priv->close_surface) / scale_factor + + BUTTON_INTERNAL_SPACING; + } + + return layout_width + button_padding.left + button_padding.right + + button_border.left + button_border.right + + button_margin.left + button_margin.right + + button_width; +} + +static void +gd_tagged_entry_tag_get_size (GdTaggedEntryTag *tag, + GdTaggedEntry *entry, + gint *width_out, + gint *height_out) +{ + gint width, panel_height; + + width = gd_tagged_entry_tag_get_width (tag, entry); + panel_height = gd_tagged_entry_tag_panel_get_height (tag, entry); + + if (width_out) + *width_out = width; + if (height_out) + *height_out = panel_height; +} + +static void +gd_tagged_entry_tag_get_relative_allocations (GdTaggedEntryTag *tag, + GdTaggedEntry *entry, + GtkStyleContext *context, + GtkAllocation *background_allocation_out, + GtkAllocation *layout_allocation_out, + GtkAllocation *button_allocation_out) +{ + GtkAllocation background_allocation, layout_allocation, button_allocation; + gint width, height, x, y, pix_width, pix_height; + gint layout_width, layout_height; + gint scale_factor; + GtkBorder padding, border; + GtkStateFlags state; + + width = gdk_window_get_width (tag->priv->window); + height = gdk_window_get_height (tag->priv->window); + scale_factor = gdk_window_get_scale_factor (tag->priv->window); + + state = gd_tagged_entry_tag_get_state (tag, entry); + gtk_style_context_save (context); + gtk_style_context_set_state (context, state); + gtk_style_context_get_margin (context, + gtk_style_context_get_state (context), + &padding); + gtk_style_context_restore (context); + + width -= padding.left + padding.right; + height -= padding.top + padding.bottom; + x = padding.left; + y = padding.top; + + background_allocation.x = x; + background_allocation.y = y; + background_allocation.width = width; + background_allocation.height = height; + + layout_allocation = button_allocation = background_allocation; + + gtk_style_context_save (context); + gtk_style_context_set_state (context, state); + gtk_style_context_get_padding (context, + gtk_style_context_get_state (context), + &padding); + gtk_style_context_get_border (context, + gtk_style_context_get_state (context), + &border); + gtk_style_context_restore (context); + + gd_tagged_entry_tag_ensure_layout (tag, entry); + pango_layout_get_pixel_size (tag->priv->layout, &layout_width, &layout_height); + + layout_allocation.x += border.left + padding.left; + layout_allocation.y += (layout_allocation.height - layout_height) / 2; + + if (entry->priv->button_visible && tag->priv->has_close_button) + { + pix_width = cairo_image_surface_get_width (tag->priv->close_surface) / scale_factor; + pix_height = cairo_image_surface_get_height (tag->priv->close_surface) / scale_factor; + } + else + { + pix_width = 0; + pix_height = 0; + } + + button_allocation.x += width - pix_width - border.right - padding.right; + button_allocation.y += (height - pix_height) / 2; + button_allocation.width = pix_width; + button_allocation.height = pix_height; + + if (background_allocation_out) + *background_allocation_out = background_allocation; + if (layout_allocation_out) + *layout_allocation_out = layout_allocation; + if (button_allocation_out) + *button_allocation_out = button_allocation; +} + +static gboolean +gd_tagged_entry_tag_event_is_button (GdTaggedEntryTag *tag, + GdTaggedEntry *entry, + gdouble event_x, + gdouble event_y) +{ + GtkAllocation button_allocation; + GtkStyleContext *context; + + if (!entry->priv->button_visible || !tag->priv->has_close_button) + return FALSE; + + context = gd_tagged_entry_tag_get_context (tag, entry); + gd_tagged_entry_tag_get_relative_allocations (tag, entry, context, NULL, NULL, &button_allocation); + + gtk_style_context_restore (context); + + /* see if the event falls into the button allocation */ + if ((event_x >= button_allocation.x && + event_x <= button_allocation.x + button_allocation.width) && + (event_y >= button_allocation.y && + event_y <= button_allocation.y + button_allocation.height)) + return TRUE; + + return FALSE; +} + +gboolean +gd_tagged_entry_tag_get_area (GdTaggedEntryTag *tag, + cairo_rectangle_int_t *rect) +{ + GtkStyleContext *context; + GtkAllocation background_allocation; + int window_x, window_y; + GtkAllocation alloc; + + g_return_val_if_fail (GD_IS_TAGGED_ENTRY_TAG (tag), FALSE); + g_return_val_if_fail (rect != NULL, FALSE); + + gdk_window_get_position (tag->priv->window, &window_x, &window_y); + gtk_widget_get_allocation (GTK_WIDGET (tag->priv->entry), &alloc); + context = gd_tagged_entry_tag_get_context (tag, tag->priv->entry); + gd_tagged_entry_tag_get_relative_allocations (tag, tag->priv->entry, context, + &background_allocation, + NULL, NULL); + gtk_style_context_restore (context); + + rect->x = window_x - alloc.x + background_allocation.x; + rect->y = window_y - alloc.y + background_allocation.y; + rect->width = background_allocation.width; + rect->height = background_allocation.height; + + return TRUE; +} + +static void +gd_tagged_entry_tag_draw (GdTaggedEntryTag *tag, + cairo_t *cr, + GdTaggedEntry *entry) +{ + GtkStyleContext *context; + GtkStateFlags state; + GtkAllocation background_allocation, layout_allocation, button_allocation; + + context = gd_tagged_entry_tag_get_context (tag, entry); + gd_tagged_entry_tag_get_relative_allocations (tag, entry, context, + &background_allocation, + &layout_allocation, + &button_allocation); + + cairo_save (cr); + gtk_cairo_transform_to_window (cr, GTK_WIDGET (entry), tag->priv->window); + + gtk_style_context_save (context); + + state = gd_tagged_entry_tag_get_state (tag, entry); + gtk_style_context_set_state (context, state); + gtk_render_background (context, cr, + background_allocation.x, background_allocation.y, + background_allocation.width, background_allocation.height); + gtk_render_frame (context, cr, + background_allocation.x, background_allocation.y, + background_allocation.width, background_allocation.height); + + gtk_render_layout (context, cr, + layout_allocation.x, layout_allocation.y, + tag->priv->layout); + + gtk_style_context_restore (context); + + if (!entry->priv->button_visible || !tag->priv->has_close_button) + goto done; + + gtk_style_context_add_class (context, GTK_STYLE_CLASS_BUTTON); + state = gd_tagged_entry_tag_get_button_state (tag, entry); + gtk_style_context_set_state (context, state); + + /* if the state changed since last time we draw the pixbuf, + * clear and redraw it. + */ + if (state != tag->priv->last_button_state) + { + g_clear_pointer (&tag->priv->close_surface, cairo_surface_destroy); + gd_tagged_entry_tag_ensure_close_surface (tag, context); + + tag->priv->last_button_state = state; + } + + gtk_render_background (context, cr, + button_allocation.x, button_allocation.y, + button_allocation.width, button_allocation.height); + gtk_render_frame (context, cr, + button_allocation.x, button_allocation.y, + button_allocation.width, button_allocation.height); + + gtk_render_icon_surface (context, cr, + tag->priv->close_surface, + button_allocation.x, button_allocation.y); + +done: + gtk_style_context_restore (context); + + cairo_restore (cr); +} + +static void +gd_tagged_entry_tag_unrealize (GdTaggedEntryTag *tag) +{ + if (tag->priv->window == NULL) + return; + + gdk_window_set_user_data (tag->priv->window, NULL); + gdk_window_destroy (tag->priv->window); + tag->priv->window = NULL; +} + +static void +gd_tagged_entry_tag_realize (GdTaggedEntryTag *tag, + GdTaggedEntry *entry) +{ + GtkWidget *widget = GTK_WIDGET (entry); + GdkWindowAttr attributes; + gint attributes_mask; + gint tag_width, tag_height; + + if (tag->priv->window != NULL) + return; + + attributes.window_type = GDK_WINDOW_CHILD; + attributes.wclass = GDK_INPUT_ONLY; + attributes.event_mask = gtk_widget_get_events (widget); + attributes.event_mask |= GDK_BUTTON_PRESS_MASK + | GDK_BUTTON_RELEASE_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_ENTER_NOTIFY_MASK + | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK; + + gd_tagged_entry_tag_get_size (tag, entry, &tag_width, &tag_height); + attributes.x = 0; + attributes.y = 0; + attributes.width = tag_width; + attributes.height = tag_height; + + attributes_mask = GDK_WA_X | GDK_WA_Y; + + tag->priv->window = gdk_window_new (gtk_widget_get_window (widget), + &attributes, attributes_mask); + gdk_window_set_user_data (tag->priv->window, widget); +} + +static gboolean +gd_tagged_entry_draw (GtkWidget *widget, + cairo_t *cr) +{ + GdTaggedEntry *self = GD_TAGGED_ENTRY (widget); + GdTaggedEntryTag *tag; + GList *l; + + GTK_WIDGET_CLASS (gd_tagged_entry_parent_class)->draw (widget, cr); + + for (l = self->priv->tags; l != NULL; l = l->next) + { + tag = l->data; + gd_tagged_entry_tag_draw (tag, cr, self); + } + + return FALSE; +} + +static void +gd_tagged_entry_map (GtkWidget *widget) +{ + GdTaggedEntry *self = GD_TAGGED_ENTRY (widget); + GdTaggedEntryTag *tag; + GList *l; + + if (gtk_widget_get_realized (widget) && !gtk_widget_get_mapped (widget)) + { + GTK_WIDGET_CLASS (gd_tagged_entry_parent_class)->map (widget); + + for (l = self->priv->tags; l != NULL; l = l->next) + { + tag = l->data; + gdk_window_show (tag->priv->window); + } + } +} + +static void +gd_tagged_entry_unmap (GtkWidget *widget) +{ + GdTaggedEntry *self = GD_TAGGED_ENTRY (widget); + GdTaggedEntryTag *tag; + GList *l; + + if (gtk_widget_get_mapped (widget)) + { + for (l = self->priv->tags; l != NULL; l = l->next) + { + tag = l->data; + gdk_window_hide (tag->priv->window); + } + + GTK_WIDGET_CLASS (gd_tagged_entry_parent_class)->unmap (widget); + } +} + +static void +gd_tagged_entry_realize (GtkWidget *widget) +{ + GdTaggedEntry *self = GD_TAGGED_ENTRY (widget); + GdTaggedEntryTag *tag; + GList *l; + + GTK_WIDGET_CLASS (gd_tagged_entry_parent_class)->realize (widget); + + for (l = self->priv->tags; l != NULL; l = l->next) + { + tag = l->data; + gd_tagged_entry_tag_realize (tag, self); + } +} + +static void +gd_tagged_entry_unrealize (GtkWidget *widget) +{ + GdTaggedEntry *self = GD_TAGGED_ENTRY (widget); + GdTaggedEntryTag *tag; + GList *l; + + GTK_WIDGET_CLASS (gd_tagged_entry_parent_class)->unrealize (widget); + + for (l = self->priv->tags; l != NULL; l = l->next) + { + tag = l->data; + gd_tagged_entry_tag_unrealize (tag); + } +} + +static void +gd_tagged_entry_get_text_area_size (GtkEntry *entry, + gint *x, + gint *y, + gint *width, + gint *height) +{ + GdTaggedEntry *self = GD_TAGGED_ENTRY (entry); + gint tag_panel_width; + + GTK_ENTRY_CLASS (gd_tagged_entry_parent_class)->get_text_area_size (entry, x, y, width, height); + + tag_panel_width = gd_tagged_entry_tag_panel_get_width (self); + + if (width) + *width -= tag_panel_width; +} + +static void +gd_tagged_entry_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GdTaggedEntry *self = GD_TAGGED_ENTRY (widget); + gint x, y, width, height; + GdTaggedEntryTag *tag; + GList *l; + + gtk_widget_set_allocation (widget, allocation); + GTK_WIDGET_CLASS (gd_tagged_entry_parent_class)->size_allocate (widget, allocation); + + if (gtk_widget_get_realized (widget)) + { + gd_tagged_entry_tag_panel_get_position (self, &x, &y); + + for (l = self->priv->tags; l != NULL; l = l->next) + { + GtkBorder margin; + + tag = l->data; + gd_tagged_entry_tag_get_size (tag, self, &width, &height); + gd_tagged_entry_tag_get_margin (tag, self, &margin); + gdk_window_move_resize (tag->priv->window, x, y + margin.top, width, height); + + x += width; + } + + gtk_widget_queue_draw (widget); + } +} + +static void +gd_tagged_entry_get_preferred_width (GtkWidget *widget, + gint *minimum, + gint *natural) +{ + GdTaggedEntry *self = GD_TAGGED_ENTRY (widget); + gint tag_panel_width; + + GTK_WIDGET_CLASS (gd_tagged_entry_parent_class)->get_preferred_width (widget, minimum, natural); + + tag_panel_width = gd_tagged_entry_tag_panel_get_width (self); + + if (minimum) + *minimum += tag_panel_width; + if (natural) + *natural += tag_panel_width; +} + +static void +gd_tagged_entry_finalize (GObject *obj) +{ + GdTaggedEntry *self = GD_TAGGED_ENTRY (obj); + + if (self->priv->tags != NULL) + { + g_list_free_full (self->priv->tags, g_object_unref); + self->priv->tags = NULL; + } + + G_OBJECT_CLASS (gd_tagged_entry_parent_class)->finalize (obj); +} + +static GdTaggedEntryTag * +gd_tagged_entry_find_tag_by_window (GdTaggedEntry *self, + GdkWindow *window) +{ + GdTaggedEntryTag *tag = NULL, *elem; + GList *l; + + for (l = self->priv->tags; l != NULL; l = l->next) + { + elem = l->data; + if (elem->priv->window == window) + { + tag = elem; + break; + } + } + + return tag; +} + +static gint +gd_tagged_entry_enter_notify (GtkWidget *widget, + GdkEventCrossing *event) +{ + GdTaggedEntry *self = GD_TAGGED_ENTRY (widget); + GdTaggedEntryTag *tag; + + tag = gd_tagged_entry_find_tag_by_window (self, event->window); + + if (tag != NULL) + { + self->priv->in_child = tag; + gtk_widget_queue_draw (widget); + } + + return GTK_WIDGET_CLASS (gd_tagged_entry_parent_class)->enter_notify_event (widget, event); +} + +static gint +gd_tagged_entry_leave_notify (GtkWidget *widget, + GdkEventCrossing *event) +{ + GdTaggedEntry *self = GD_TAGGED_ENTRY (widget); + + if (self->priv->in_child != NULL) + { + self->priv->in_child = NULL; + gtk_widget_queue_draw (widget); + } + + return GTK_WIDGET_CLASS (gd_tagged_entry_parent_class)->leave_notify_event (widget, event); +} + +static gint +gd_tagged_entry_motion_notify (GtkWidget *widget, + GdkEventMotion *event) +{ + GdTaggedEntry *self = GD_TAGGED_ENTRY (widget); + GdTaggedEntryTag *tag; + + tag = gd_tagged_entry_find_tag_by_window (self, event->window); + + if (tag != NULL) + { + gdk_event_request_motions (event); + + self->priv->in_child = tag; + self->priv->in_child_button = gd_tagged_entry_tag_event_is_button (tag, self, event->x, event->y); + gtk_widget_queue_draw (widget); + + return FALSE; + } + + return GTK_WIDGET_CLASS (gd_tagged_entry_parent_class)->motion_notify_event (widget, event); +} + +static gboolean +gd_tagged_entry_button_release_event (GtkWidget *widget, + GdkEventButton *event) +{ + GdTaggedEntry *self = GD_TAGGED_ENTRY (widget); + GdTaggedEntryTag *tag; + + tag = gd_tagged_entry_find_tag_by_window (self, event->window); + + if (tag != NULL) + { + self->priv->in_child_active = FALSE; + + if (gd_tagged_entry_tag_event_is_button (tag, self, event->x, event->y)) + { + self->priv->in_child_button_active = FALSE; + g_signal_emit (self, signals[SIGNAL_TAG_BUTTON_CLICKED], 0, tag); + } + else + { + g_signal_emit (self, signals[SIGNAL_TAG_CLICKED], 0, tag); + } + + gtk_widget_queue_draw (widget); + + return TRUE; + } + + return GTK_WIDGET_CLASS (gd_tagged_entry_parent_class)->button_release_event (widget, event); +} + +static gboolean +gd_tagged_entry_button_press_event (GtkWidget *widget, + GdkEventButton *event) +{ + GdTaggedEntry *self = GD_TAGGED_ENTRY (widget); + GdTaggedEntryTag *tag; + + tag = gd_tagged_entry_find_tag_by_window (self, event->window); + + if (tag != NULL) + { + if (gd_tagged_entry_tag_event_is_button (tag, self, event->x, event->y)) + self->priv->in_child_button_active = TRUE; + else + self->priv->in_child_active = TRUE; + + gtk_widget_queue_draw (widget); + + return TRUE; + } + + return GTK_WIDGET_CLASS (gd_tagged_entry_parent_class)->button_press_event (widget, event); +} + +static void +gd_tagged_entry_init (GdTaggedEntry *self) +{ + self->priv = gd_tagged_entry_get_instance_private (self); + self->priv->button_visible = TRUE; +} + +static void +gd_tagged_entry_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + GdTaggedEntry *self = GD_TAGGED_ENTRY (object); + + switch (property_id) + { + case PROP_TAG_BUTTON_VISIBLE: + g_value_set_boolean (value, gd_tagged_entry_get_tag_button_visible (self)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +gd_tagged_entry_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + GdTaggedEntry *self = GD_TAGGED_ENTRY (object); + + switch (property_id) + { + case PROP_TAG_BUTTON_VISIBLE: + gd_tagged_entry_set_tag_button_visible (self, g_value_get_boolean (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +gd_tagged_entry_class_init (GdTaggedEntryClass *klass) +{ + GtkWidgetClass *wclass = GTK_WIDGET_CLASS (klass); + GtkEntryClass *eclass = GTK_ENTRY_CLASS (klass); + GObjectClass *oclass = G_OBJECT_CLASS (klass); + + oclass->finalize = gd_tagged_entry_finalize; + oclass->set_property = gd_tagged_entry_set_property; + oclass->get_property = gd_tagged_entry_get_property; + + wclass->realize = gd_tagged_entry_realize; + wclass->unrealize = gd_tagged_entry_unrealize; + wclass->map = gd_tagged_entry_map; + wclass->unmap = gd_tagged_entry_unmap; + wclass->size_allocate = gd_tagged_entry_size_allocate; + wclass->get_preferred_width = gd_tagged_entry_get_preferred_width; + wclass->draw = gd_tagged_entry_draw; + wclass->enter_notify_event = gd_tagged_entry_enter_notify; + wclass->leave_notify_event = gd_tagged_entry_leave_notify; + wclass->motion_notify_event = gd_tagged_entry_motion_notify; + wclass->button_press_event = gd_tagged_entry_button_press_event; + wclass->button_release_event = gd_tagged_entry_button_release_event; + + eclass->get_text_area_size = gd_tagged_entry_get_text_area_size; + + signals[SIGNAL_TAG_CLICKED] = + g_signal_new ("tag-clicked", + GD_TYPE_TAGGED_ENTRY, + G_SIGNAL_RUN_FIRST | G_SIGNAL_DETAILED, + 0, NULL, NULL, NULL, + G_TYPE_NONE, + 1, GD_TYPE_TAGGED_ENTRY_TAG); + signals[SIGNAL_TAG_BUTTON_CLICKED] = + g_signal_new ("tag-button-clicked", + GD_TYPE_TAGGED_ENTRY, + G_SIGNAL_RUN_FIRST | G_SIGNAL_DETAILED, + 0, NULL, NULL, NULL, + G_TYPE_NONE, + 1, GD_TYPE_TAGGED_ENTRY_TAG); + + properties[PROP_TAG_BUTTON_VISIBLE] = + g_param_spec_boolean ("tag-close-visible", "Tag close icon visibility", + "Whether the close button should be shown in tags.", TRUE, + G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties (oclass, NUM_PROPERTIES, properties); +} + +static void +gd_tagged_entry_tag_init (GdTaggedEntryTag *self) +{ + GdTaggedEntryTagPrivate *priv; + + self->priv = gd_tagged_entry_tag_get_instance_private (self); + priv = self->priv; + + priv->last_button_state = GTK_STATE_FLAG_NORMAL; +} + +static void +gd_tagged_entry_tag_finalize (GObject *obj) +{ + GdTaggedEntryTag *tag = GD_TAGGED_ENTRY_TAG (obj); + GdTaggedEntryTagPrivate *priv = tag->priv; + + if (priv->window != NULL) + gd_tagged_entry_tag_unrealize (tag); + + g_clear_object (&priv->layout); + g_clear_pointer (&priv->close_surface, cairo_surface_destroy); + g_free (priv->label); + g_free (priv->style); + + G_OBJECT_CLASS (gd_tagged_entry_tag_parent_class)->finalize (obj); +} + +static void +gd_tagged_entry_tag_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + GdTaggedEntryTag *self = GD_TAGGED_ENTRY_TAG (object); + + switch (property_id) + { + case PROP_TAG_LABEL: + g_value_set_string (value, gd_tagged_entry_tag_get_label (self)); + break; + case PROP_TAG_HAS_CLOSE_BUTTON: + g_value_set_boolean (value, gd_tagged_entry_tag_get_has_close_button (self)); + break; + case PROP_TAG_STYLE: + g_value_set_string (value, gd_tagged_entry_tag_get_style (self)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +gd_tagged_entry_tag_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + GdTaggedEntryTag *self = GD_TAGGED_ENTRY_TAG (object); + + switch (property_id) + { + case PROP_TAG_LABEL: + gd_tagged_entry_tag_set_label (self, g_value_get_string (value)); + break; + case PROP_TAG_HAS_CLOSE_BUTTON: + gd_tagged_entry_tag_set_has_close_button (self, g_value_get_boolean (value)); + break; + case PROP_TAG_STYLE: + gd_tagged_entry_tag_set_style (self, g_value_get_string (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +gd_tagged_entry_tag_class_init (GdTaggedEntryTagClass *klass) +{ + GObjectClass *oclass = G_OBJECT_CLASS (klass); + + oclass->finalize = gd_tagged_entry_tag_finalize; + oclass->set_property = gd_tagged_entry_tag_set_property; + oclass->get_property = gd_tagged_entry_tag_get_property; + + tag_properties[PROP_TAG_LABEL] = + g_param_spec_string ("label", "Label", + "Text to show on the tag.", NULL, + G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + tag_properties[PROP_TAG_HAS_CLOSE_BUTTON] = + g_param_spec_boolean ("has-close-button", "Tag has a close button", + "Whether the tag has a close button.", TRUE, + G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + tag_properties[PROP_TAG_STYLE] = + g_param_spec_string ("style", "Style", + "Style of the tag.", "entry-tag", + G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties (oclass, NUM_TAG_PROPERTIES, tag_properties); +} + +GdTaggedEntry * +gd_tagged_entry_new (void) +{ + return g_object_new (GD_TYPE_TAGGED_ENTRY, NULL); +} + +gboolean +gd_tagged_entry_insert_tag (GdTaggedEntry *self, + GdTaggedEntryTag *tag, + gint position) +{ + if (g_list_find (self->priv->tags, tag) != NULL) + return FALSE; + + tag->priv->entry = self; + + self->priv->tags = g_list_insert (self->priv->tags, g_object_ref (tag), position); + + if (gtk_widget_get_realized (GTK_WIDGET (self))) + gd_tagged_entry_tag_realize (tag, self); + + if (gtk_widget_get_mapped (GTK_WIDGET (self))) + gdk_window_show_unraised (tag->priv->window); + + gtk_widget_queue_resize (GTK_WIDGET (self)); + + return TRUE; +} + +gboolean +gd_tagged_entry_add_tag (GdTaggedEntry *self, + GdTaggedEntryTag *tag) +{ + return gd_tagged_entry_insert_tag (self, tag, -1); +} + +gboolean +gd_tagged_entry_remove_tag (GdTaggedEntry *self, + GdTaggedEntryTag *tag) +{ + if (!g_list_find (self->priv->tags, tag)) + return FALSE; + + gd_tagged_entry_tag_unrealize (tag); + + self->priv->tags = g_list_remove (self->priv->tags, tag); + g_object_unref (tag); + + gtk_widget_queue_resize (GTK_WIDGET (self)); + + return TRUE; +} + +GdTaggedEntryTag * +gd_tagged_entry_tag_new (const gchar *label) +{ + return g_object_new (GD_TYPE_TAGGED_ENTRY_TAG, "label", label, NULL); +} + +void +gd_tagged_entry_tag_set_label (GdTaggedEntryTag *tag, + const gchar *label) +{ + GdTaggedEntryTagPrivate *priv; + + g_return_if_fail (GD_IS_TAGGED_ENTRY_TAG (tag)); + + priv = tag->priv; + + if (g_strcmp0 (priv->label, label) != 0) + { + GtkWidget *entry; + + g_free (priv->label); + priv->label = g_strdup (label); + g_clear_object (&priv->layout); + + entry = GTK_WIDGET (tag->priv->entry); + if (entry) + gtk_widget_queue_resize (entry); + } +} + +const gchar * +gd_tagged_entry_tag_get_label (GdTaggedEntryTag *tag) +{ + g_return_val_if_fail (GD_IS_TAGGED_ENTRY_TAG (tag), NULL); + + return tag->priv->label; +} + +void +gd_tagged_entry_tag_set_has_close_button (GdTaggedEntryTag *tag, + gboolean has_close_button) +{ + GdTaggedEntryTagPrivate *priv; + + g_return_if_fail (GD_IS_TAGGED_ENTRY_TAG (tag)); + + priv = tag->priv; + + has_close_button = has_close_button != FALSE; + if (priv->has_close_button != has_close_button) + { + GtkWidget *entry; + + priv->has_close_button = has_close_button; + g_clear_object (&priv->layout); + + entry = GTK_WIDGET (priv->entry); + if (entry) + gtk_widget_queue_resize (entry); + } +} + +gboolean +gd_tagged_entry_tag_get_has_close_button (GdTaggedEntryTag *tag) +{ + g_return_val_if_fail (GD_IS_TAGGED_ENTRY_TAG (tag), FALSE); + + return tag->priv->has_close_button; +} + +void +gd_tagged_entry_tag_set_style (GdTaggedEntryTag *tag, + const gchar *style) +{ + GdTaggedEntryTagPrivate *priv; + + g_return_if_fail (GD_IS_TAGGED_ENTRY_TAG (tag)); + + priv = tag->priv; + + if (g_strcmp0 (priv->style, style) != 0) + { + GtkWidget *entry; + + g_free (priv->style); + priv->style = g_strdup (style); + g_clear_object (&priv->layout); + + entry = GTK_WIDGET (tag->priv->entry); + if (entry) + gtk_widget_queue_resize (entry); + } +} + +const gchar * +gd_tagged_entry_tag_get_style (GdTaggedEntryTag *tag) +{ + g_return_val_if_fail (GD_IS_TAGGED_ENTRY_TAG (tag), NULL); + + return tag->priv->style; +} + +void +gd_tagged_entry_set_tag_button_visible (GdTaggedEntry *self, + gboolean visible) +{ + g_return_if_fail (GD_IS_TAGGED_ENTRY (self)); + + if (self->priv->button_visible == visible) + return; + + self->priv->button_visible = visible; + gtk_widget_queue_resize (GTK_WIDGET (self)); + + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_TAG_BUTTON_VISIBLE]); +} + +gboolean +gd_tagged_entry_get_tag_button_visible (GdTaggedEntry *self) +{ + g_return_val_if_fail (GD_IS_TAGGED_ENTRY (self), FALSE); + + return self->priv->button_visible; +} diff --git a/subprojects/libgd/libgd/gd-tagged-entry.h b/subprojects/libgd/libgd/gd-tagged-entry.h new file mode 100644 index 00000000..ba9f6731 --- /dev/null +++ b/subprojects/libgd/libgd/gd-tagged-entry.h @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2011 Red Hat, Inc. + * Copyright (c) 2013 Ignacio Casal Quinteiro + * + * This program 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 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 Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Author: Cosimo Cecchi <cosimoc@redhat.com> + * + */ + +#ifndef __GD_TAGGED_ENTRY_H__ +#define __GD_TAGGED_ENTRY_H__ + +#include <glib-object.h> + +#include <gtk/gtk.h> + +G_BEGIN_DECLS + +#define GD_TYPE_TAGGED_ENTRY gd_tagged_entry_get_type() +#define GD_TAGGED_ENTRY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GD_TYPE_TAGGED_ENTRY, GdTaggedEntry)) +#define GD_TAGGED_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GD_TYPE_TAGGED_ENTRY, GdTaggedEntryClass)) +#define GD_IS_TAGGED_ENTRY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GD_TYPE_TAGGED_ENTRY)) +#define GD_IS_TAGGED_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GD_TYPE_TAGGED_ENTRY)) +#define GD_TAGGED_ENTRY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GD_TYPE_TAGGED_ENTRY, GdTaggedEntryClass)) + +typedef struct _GdTaggedEntry GdTaggedEntry; +typedef struct _GdTaggedEntryClass GdTaggedEntryClass; +typedef struct _GdTaggedEntryPrivate GdTaggedEntryPrivate; + +typedef struct _GdTaggedEntryTag GdTaggedEntryTag; +typedef struct _GdTaggedEntryTagClass GdTaggedEntryTagClass; +typedef struct _GdTaggedEntryTagPrivate GdTaggedEntryTagPrivate; + +struct _GdTaggedEntry +{ + GtkSearchEntry parent; + + GdTaggedEntryPrivate *priv; +}; + +struct _GdTaggedEntryClass +{ + GtkSearchEntryClass parent_class; +}; + +#define GD_TYPE_TAGGED_ENTRY_TAG gd_tagged_entry_tag_get_type() +#define GD_TAGGED_ENTRY_TAG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GD_TYPE_TAGGED_ENTRY_TAG, GdTaggedEntryTag)) +#define GD_TAGGED_ENTRY_TAG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GD_TYPE_TAGGED_ENTRY_TAG, GdTaggedEntryTagClass)) +#define GD_IS_TAGGED_ENTRY_TAG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GD_TYPE_TAGGED_ENTRY_TAG)) +#define GD_IS_TAGGED_ENTRY_TAG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GD_TYPE_TAGGED_ENTRY_TAG)) +#define GD_TAGGED_ENTRY_TAG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GD_TYPE_TAGGED_ENTRY_TAG, GdTaggedEntryTagClass)) + +struct _GdTaggedEntryTag +{ + GObject parent; + + GdTaggedEntryTagPrivate *priv; +}; + +struct _GdTaggedEntryTagClass +{ + GObjectClass parent_class; +}; + +GType gd_tagged_entry_get_type (void) G_GNUC_CONST; + +GdTaggedEntry *gd_tagged_entry_new (void); + +void gd_tagged_entry_set_tag_button_visible (GdTaggedEntry *self, + gboolean visible); +gboolean gd_tagged_entry_get_tag_button_visible (GdTaggedEntry *self); + +gboolean gd_tagged_entry_insert_tag (GdTaggedEntry *self, + GdTaggedEntryTag *tag, + gint position); + +gboolean gd_tagged_entry_add_tag (GdTaggedEntry *self, + GdTaggedEntryTag *tag); + +gboolean gd_tagged_entry_remove_tag (GdTaggedEntry *self, + GdTaggedEntryTag *tag); + +GType gd_tagged_entry_tag_get_type (void) G_GNUC_CONST; + +GdTaggedEntryTag *gd_tagged_entry_tag_new (const gchar *label); + +void gd_tagged_entry_tag_set_label (GdTaggedEntryTag *tag, + const gchar *label); +const gchar *gd_tagged_entry_tag_get_label (GdTaggedEntryTag *tag); + +void gd_tagged_entry_tag_set_has_close_button (GdTaggedEntryTag *tag, + gboolean has_close_button); +gboolean gd_tagged_entry_tag_get_has_close_button (GdTaggedEntryTag *tag); + +void gd_tagged_entry_tag_set_style (GdTaggedEntryTag *tag, + const gchar *style); +const gchar *gd_tagged_entry_tag_get_style (GdTaggedEntryTag *tag); + +gboolean gd_tagged_entry_tag_get_area (GdTaggedEntryTag *tag, + cairo_rectangle_int_t *rect); + +G_END_DECLS + +#endif /* __GD_TAGGED_ENTRY_H__ */ diff --git a/subprojects/libgd/libgd/gd-toggle-pixbuf-renderer.c b/subprojects/libgd/libgd/gd-toggle-pixbuf-renderer.c new file mode 100644 index 00000000..069050b5 --- /dev/null +++ b/subprojects/libgd/libgd/gd-toggle-pixbuf-renderer.c @@ -0,0 +1,280 @@ +/* + * Copyright (c) 2011 Red Hat, Inc. + * + * This program 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 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 Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Author: Cosimo Cecchi <cosimoc@redhat.com> + * + */ + +#include "gd-toggle-pixbuf-renderer.h" + +enum { + PROP_ACTIVE = 1, + PROP_TOGGLE_VISIBLE, + PROP_PULSE, + NUM_PROPERTIES +}; + +static GParamSpec *properties[NUM_PROPERTIES] = { NULL, }; + +typedef struct _GdTogglePixbufRendererPrivate GdTogglePixbufRendererPrivate; + +struct _GdTogglePixbufRendererPrivate { + gboolean active; + gboolean toggle_visible; + + guint pulse; +}; + +G_DEFINE_TYPE_WITH_PRIVATE (GdTogglePixbufRenderer, gd_toggle_pixbuf_renderer, GTK_TYPE_CELL_RENDERER_PIXBUF) + +static void +render_check (GdTogglePixbufRenderer *self, + cairo_t *cr, + GtkWidget *widget, + const GdkRectangle *cell_area, + gint icon_size, + gint xpad, + gint ypad) +{ + GdTogglePixbufRendererPrivate *priv; + GtkStyleContext *context; + gint check_x, check_y, x_offset; + GtkTextDirection direction; + + priv = gd_toggle_pixbuf_renderer_get_instance_private (self); + context = gtk_widget_get_style_context (widget); + + if (!priv->toggle_visible) + return; + + direction = gtk_widget_get_direction (widget); + if (direction == GTK_TEXT_DIR_RTL) + x_offset = xpad; + else + x_offset = cell_area->width - icon_size - xpad; + + check_x = cell_area->x + x_offset; + check_y = cell_area->y + cell_area->height - icon_size - ypad; + + gtk_style_context_save (context); + gtk_style_context_add_class (context, GTK_STYLE_CLASS_CHECK); + + if (priv->active) + gtk_style_context_set_state (context, gtk_widget_get_state_flags (widget) | GTK_STATE_FLAG_CHECKED); + + gtk_render_background (context, cr, + check_x, check_y, + icon_size, icon_size); + gtk_render_frame (context, cr, + check_x, check_y, + icon_size, icon_size); + gtk_render_check (context, cr, + check_x, check_y, + icon_size, icon_size); + gtk_style_context_restore (context); +} + +static void +render_activity (GdTogglePixbufRenderer *self, + cairo_t *cr, + GtkWidget *widget, + const GdkRectangle *cell_area, + gint icon_size, + gint xpad, + gint ypad) +{ + GdTogglePixbufRendererPrivate *priv; + gint x, y, width, height; + + priv = gd_toggle_pixbuf_renderer_get_instance_private (self); + + if (priv->pulse == 0) + return; + + width = cell_area->width / 4; + height = cell_area->height / 4; + + x = cell_area->x + (cell_area->width / 2) - (width / 2) - xpad; + y = cell_area->y + (cell_area->height / 2) - (height / 2) - ypad; + + G_GNUC_BEGIN_IGNORE_DEPRECATIONS; + gtk_paint_spinner (gtk_widget_get_style (widget), + cr, + GTK_STATE_FLAG_ACTIVE, + widget, + NULL, + (guint) priv->pulse - 1, + x, y, + width, height); + G_GNUC_END_IGNORE_DEPRECATIONS; +} + +static void +gd_toggle_pixbuf_renderer_render (GtkCellRenderer *cell, + cairo_t *cr, + GtkWidget *widget, + const GdkRectangle *background_area, + const GdkRectangle *cell_area, + GtkCellRendererState flags) +{ + gint icon_size = -1; + GdTogglePixbufRenderer *self = GD_TOGGLE_PIXBUF_RENDERER (cell); + gint xpad, ypad; + + GTK_CELL_RENDERER_CLASS (gd_toggle_pixbuf_renderer_parent_class)->render + (cell, cr, widget, + background_area, cell_area, flags); + + gtk_cell_renderer_get_padding (cell, &xpad, &ypad); + gtk_widget_style_get (widget, + "check-icon-size", &icon_size, + NULL); + + if (icon_size == -1) + icon_size = 40; + + render_activity (self, cr, widget, cell_area, icon_size, xpad, ypad); + render_check (self, cr, widget, cell_area, icon_size, xpad, ypad); +} + +static void +gd_toggle_pixbuf_renderer_get_size (GtkCellRenderer *cell, + GtkWidget *widget, + const GdkRectangle *cell_area, + gint *x_offset, + gint *y_offset, + gint *width, + gint *height) +{ + gint icon_size; + + gtk_widget_style_get (widget, + "check-icon-size", &icon_size, + NULL); + + GTK_CELL_RENDERER_CLASS (gd_toggle_pixbuf_renderer_parent_class)->get_size + (cell, widget, cell_area, + x_offset, y_offset, width, height); + + *width += icon_size / 4; +} + +static void +gd_toggle_pixbuf_renderer_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + GdTogglePixbufRenderer *self = GD_TOGGLE_PIXBUF_RENDERER (object); + GdTogglePixbufRendererPrivate *priv; + + priv = gd_toggle_pixbuf_renderer_get_instance_private (self); + + switch (property_id) + { + case PROP_ACTIVE: + g_value_set_boolean (value, priv->active); + break; + case PROP_TOGGLE_VISIBLE: + g_value_set_boolean (value, priv->toggle_visible); + break; + case PROP_PULSE: + g_value_set_uint (value, priv->pulse); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gd_toggle_pixbuf_renderer_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + GdTogglePixbufRenderer *self = GD_TOGGLE_PIXBUF_RENDERER (object); + GdTogglePixbufRendererPrivate *priv; + + priv = gd_toggle_pixbuf_renderer_get_instance_private (self); + + switch (property_id) + { + case PROP_ACTIVE: + priv->active = g_value_get_boolean (value); + break; + case PROP_TOGGLE_VISIBLE: + priv->toggle_visible = g_value_get_boolean (value); + break; + case PROP_PULSE: + priv->pulse = g_value_get_uint (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gd_toggle_pixbuf_renderer_class_init (GdTogglePixbufRendererClass *klass) +{ + GObjectClass *oclass = G_OBJECT_CLASS (klass); + GtkCellRendererClass *crclass = GTK_CELL_RENDERER_CLASS (klass); + + crclass->render = gd_toggle_pixbuf_renderer_render; + crclass->get_size = gd_toggle_pixbuf_renderer_get_size; + oclass->get_property = gd_toggle_pixbuf_renderer_get_property; + oclass->set_property = gd_toggle_pixbuf_renderer_set_property; + + properties[PROP_ACTIVE] = + g_param_spec_boolean ("active", + "Active", + "Whether the cell renderer is active", + FALSE, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS); + properties[PROP_TOGGLE_VISIBLE] = + g_param_spec_boolean ("toggle-visible", + "Toggle visible", + "Whether to draw the toggle indicator", + FALSE, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS); + properties[PROP_PULSE] = + g_param_spec_uint ("pulse", + "Pulse", + "Set to any value other than 0 to display a " + "spinner on top of the pixbuf.", + 0, + G_MAXUINT, + 0, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties (oclass, NUM_PROPERTIES, properties); +} + +static void +gd_toggle_pixbuf_renderer_init (GdTogglePixbufRenderer *self) +{ +} + +GtkCellRenderer * +gd_toggle_pixbuf_renderer_new (void) +{ + return g_object_new (GD_TYPE_TOGGLE_PIXBUF_RENDERER, NULL); +} diff --git a/subprojects/libgd/libgd/gd-toggle-pixbuf-renderer.h b/subprojects/libgd/libgd/gd-toggle-pixbuf-renderer.h new file mode 100644 index 00000000..93f4429c --- /dev/null +++ b/subprojects/libgd/libgd/gd-toggle-pixbuf-renderer.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2011 Red Hat, Inc. + * + * This program 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 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 Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Author: Cosimo Cecchi <cosimoc@redhat.com> + * + */ + +#ifndef _GD_TOGGLE_PIXBUF_RENDERER_H +#define _GD_TOGGLE_PIXBUF_RENDERER_H + +#include <glib-object.h> + +#include <gtk/gtk.h> + +G_BEGIN_DECLS + +#define GD_TYPE_TOGGLE_PIXBUF_RENDERER gd_toggle_pixbuf_renderer_get_type() +G_DECLARE_DERIVABLE_TYPE (GdTogglePixbufRenderer, + gd_toggle_pixbuf_renderer, + GD, + TOGGLE_PIXBUF_RENDERER, + GtkCellRendererPixbuf) + +struct _GdTogglePixbufRendererClass +{ + GtkCellRendererPixbufClass parent_class; +}; + +GtkCellRenderer *gd_toggle_pixbuf_renderer_new (void); + +G_END_DECLS + +#endif /* _GD_TOGGLE_PIXBUF_RENDERER_H */ diff --git a/subprojects/libgd/libgd/gd-two-lines-renderer.c b/subprojects/libgd/libgd/gd-two-lines-renderer.c new file mode 100644 index 00000000..f5e1ce53 --- /dev/null +++ b/subprojects/libgd/libgd/gd-two-lines-renderer.c @@ -0,0 +1,632 @@ +/* + * Copyright (c) 2011 Red Hat, Inc. + * + * This program 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 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 Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Author: Cosimo Cecchi <cosimoc@redhat.com> + * + */ + +#include "gd-two-lines-renderer.h" +#include <string.h> + +#define SUBTITLE_DIM_PERCENTAGE 0.55 +#define SUBTITLE_SIZE_PERCENTAGE 0.82 + +typedef struct _GdTwoLinesRendererPrivate GdTwoLinesRendererPrivate; + +struct _GdTwoLinesRendererPrivate { + gchar *line_two; + gint text_lines; +}; + +enum { + PROP_TEXT_LINES = 1, + PROP_LINE_TWO, + NUM_PROPERTIES +}; + +static GParamSpec *properties[NUM_PROPERTIES] = { NULL, }; + +G_DEFINE_TYPE_WITH_PRIVATE (GdTwoLinesRenderer, gd_two_lines_renderer, GTK_TYPE_CELL_RENDERER_TEXT) + +static PangoLayout * +create_layout_with_attrs (GtkWidget *widget, + const GdkRectangle *cell_area, + GdTwoLinesRenderer *self, + PangoEllipsizeMode ellipsize) +{ + PangoLayout *layout; + gint wrap_width, xpad; + PangoWrapMode wrap_mode; + PangoAlignment alignment; + + g_object_get (self, + "wrap-width", &wrap_width, + "wrap-mode", &wrap_mode, + "alignment", &alignment, + "xpad", &xpad, + NULL); + + layout = pango_layout_new (gtk_widget_get_pango_context (widget)); + + pango_layout_set_ellipsize (layout, ellipsize); + pango_layout_set_alignment (layout, alignment); + + if (wrap_width != -1) + { + pango_layout_set_width (layout, wrap_width * PANGO_SCALE); + pango_layout_set_wrap (layout, wrap_mode); + } + else + { + if (cell_area != NULL) + pango_layout_set_width (layout, (cell_area->width - 2 * xpad) * PANGO_SCALE); + else + pango_layout_set_width (layout, -1); + + pango_layout_set_wrap (layout, PANGO_WRAP_CHAR); + } + + return layout; +} + +static void +apply_subtitle_style_to_layout (GtkStyleContext *context, + PangoLayout *layout, + GtkStateFlags flags) +{ + PangoFontDescription *desc; + PangoAttrList *layout_attr; + PangoAttribute *attr_alpha; + + gtk_style_context_save (context); + gtk_style_context_set_state (context, flags); + gtk_style_context_get (context, gtk_style_context_get_state (context), + "font", &desc, + NULL); + gtk_style_context_restore (context); + + /* Set the font size */ + pango_font_description_set_size (desc, pango_font_description_get_size (desc) * SUBTITLE_SIZE_PERCENTAGE); + pango_layout_set_font_description (layout, desc); + pango_font_description_free (desc); + + /* Set the font alpha */ + layout_attr = pango_attr_list_new (); + attr_alpha = pango_attr_foreground_alpha_new (SUBTITLE_DIM_PERCENTAGE * 65535); + pango_attr_list_insert (layout_attr, attr_alpha); + + pango_layout_set_attributes (layout, layout_attr); + pango_attr_list_unref (layout_attr); +} + +static void +gd_two_lines_renderer_prepare_layouts (GdTwoLinesRenderer *self, + const GdkRectangle *cell_area, + GtkWidget *widget, + PangoLayout **layout_one, + PangoLayout **layout_two) +{ + GdTwoLinesRendererPrivate *priv; + PangoLayout *line_one; + PangoLayout *line_two = NULL; + gchar *text = NULL; + + priv = gd_two_lines_renderer_get_instance_private (self); + + g_object_get (self, + "text", &text, + NULL); + + line_one = create_layout_with_attrs (widget, cell_area, + self, PANGO_ELLIPSIZE_MIDDLE); + + if (priv->line_two == NULL || + g_strcmp0 (priv->line_two, "") == 0) + { + pango_layout_set_height (line_one, - (priv->text_lines)); + + if (text != NULL) + pango_layout_set_text (line_one, text, -1); + } + else + { + GtkStyleContext *context; + + line_two = create_layout_with_attrs (widget, cell_area, + self, PANGO_ELLIPSIZE_END); + + context = gtk_widget_get_style_context (widget); + gtk_style_context_save (context); + apply_subtitle_style_to_layout (context, line_two, GTK_STATE_FLAG_NORMAL); + gtk_style_context_restore (context); + + pango_layout_set_height (line_one, - (priv->text_lines - 1)); + pango_layout_set_height (line_two, -1); + pango_layout_set_text (line_two, priv->line_two, -1); + + if (text != NULL) + pango_layout_set_text (line_one, text, -1); + } + + if (layout_one) + *layout_one = line_one; + if (layout_two) + *layout_two = line_two; + + g_free (text); +} + +static void +gd_two_lines_renderer_get_size (GtkCellRenderer *cell, + GtkWidget *widget, + PangoLayout *layout_1, + PangoLayout *layout_2, + gint *width, + gint *height, + const GdkRectangle *cell_area, + gint *x_offset_1, + gint *x_offset_2, + gint *y_offset) +{ + GdTwoLinesRenderer *self = GD_TWO_LINES_RENDERER (cell); + gint xpad, ypad; + PangoLayout *layout_one, *layout_two; + GdkRectangle layout_one_rect, layout_two_rect, layout_union; + + if (layout_1 == NULL) + { + gd_two_lines_renderer_prepare_layouts (self, cell_area, widget, &layout_one, &layout_two); + } + else + { + layout_one = g_object_ref (layout_1); + + if (layout_2 != NULL) + layout_two = g_object_ref (layout_2); + else + layout_two = NULL; + } + + gtk_cell_renderer_get_padding (cell, &xpad, &ypad); + pango_layout_get_pixel_extents (layout_one, NULL, (PangoRectangle *) &layout_one_rect); + + if (layout_two != NULL) + { + pango_layout_get_pixel_extents (layout_two, NULL, (PangoRectangle *) &layout_two_rect); + + layout_union.width = MAX (layout_one_rect.width, layout_two_rect.width); + layout_union.height = layout_one_rect.height + layout_two_rect.height; + } + else + { + layout_union = layout_one_rect; + } + + if (cell_area) + { + gfloat xalign, yalign; + + gtk_cell_renderer_get_alignment (cell, &xalign, &yalign); + + layout_union.width = MIN (layout_union.width, cell_area->width - 2 * xpad); + layout_union.height = MIN (layout_union.height, cell_area->height - 2 * ypad); + + if (x_offset_1) + { + if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL) + *x_offset_1 = (1.0 - xalign) * (cell_area->width - (layout_one_rect.width + (2 * xpad))); + else + *x_offset_1 = xalign * (cell_area->width - (layout_one_rect.width + (2 * xpad))); + + *x_offset_1 = MAX (*x_offset_1, 0); + } + if (x_offset_2) + { + if (layout_two != NULL) + { + if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL) + *x_offset_2 = (1.0 - xalign) * (cell_area->width - (layout_two_rect.width + (2 * xpad))); + else + *x_offset_2 = xalign * (cell_area->width - (layout_two_rect.width + (2 * xpad))); + + *x_offset_2 = MAX (*x_offset_2, 0); + } + else + { + *x_offset_2 = 0; + } + } + + if (y_offset) + { + *y_offset = yalign * (cell_area->height - (layout_union.height + (2 * ypad))); + *y_offset = MAX (*y_offset, 0); + } + } + else + { + if (x_offset_1) *x_offset_1 = 0; + if (x_offset_2) *x_offset_2 = 0; + if (y_offset) *y_offset = 0; + } + + g_clear_object (&layout_one); + g_clear_object (&layout_two); + + if (height) + *height = ypad * 2 + layout_union.height; + + if (width) + *width = xpad * 2 + layout_union.width; +} + +static void +gd_two_lines_renderer_render (GtkCellRenderer *cell, + cairo_t *cr, + GtkWidget *widget, + const GdkRectangle *background_area, + const GdkRectangle *cell_area, + GtkCellRendererState flags) +{ + GdTwoLinesRenderer *self = GD_TWO_LINES_RENDERER (cell); + GtkStyleContext *context; + gint line_one_height; + GtkStateFlags state; + GdkRectangle area, render_area = *cell_area; + gint xpad, ypad, x_offset_1, x_offset_2, y_offset; + PangoLayout *layout_one, *layout_two; + PangoRectangle layout_rect; + + /* fetch common information */ + context = gtk_widget_get_style_context (widget); + gd_two_lines_renderer_prepare_layouts (self, cell_area, widget, &layout_one, &layout_two); + gd_two_lines_renderer_get_size (cell, widget, + layout_one, layout_two, + NULL, NULL, + cell_area, + &x_offset_1, &x_offset_2, &y_offset); + gtk_cell_renderer_get_padding (cell, &xpad, &ypad); + + area = *cell_area; + area.x += xpad; + area.y += ypad; + + /* now render the first layout */ + pango_layout_get_pixel_extents (layout_one, NULL, &layout_rect); + + render_area = area; + render_area.x += x_offset_1 - layout_rect.x; + render_area.y += y_offset; + + gtk_render_layout (context, cr, + render_area.x, + render_area.y, + layout_one); + + /* render the second layout */ + if (layout_two != NULL) + { + pango_layout_get_pixel_size (layout_one, + NULL, &line_one_height); + + gtk_style_context_save (context); + + apply_subtitle_style_to_layout (context, layout_two, flags); + + state = gtk_cell_renderer_get_state (cell, widget, flags); + gtk_style_context_set_state (context, state); + + pango_layout_get_pixel_extents (layout_two, NULL, &layout_rect); + + render_area = area; + render_area.x += x_offset_2 - layout_rect.x; + render_area.y += y_offset + line_one_height; + + gtk_render_layout (context, cr, + render_area.x, + render_area.y, + layout_two); + + gtk_style_context_restore (context); + } + + g_clear_object (&layout_one); + g_clear_object (&layout_two); +} + +static void +gd_two_lines_renderer_get_preferred_width (GtkCellRenderer *cell, + GtkWidget *widget, + gint *minimum_size, + gint *natural_size) +{ + PangoContext *context; + PangoFontMetrics *metrics; + PangoFontDescription *font_desc; + GtkStyleContext *style_context; + gint nat_width, min_width; + gint xpad, char_width, wrap_width, text_width; + gint width_chars, ellipsize_chars; + + g_object_get (cell, + "xpad", &xpad, + "width-chars", &width_chars, + "wrap-width", &wrap_width, + NULL); + style_context = gtk_widget_get_style_context (widget); + gtk_cell_renderer_get_padding (cell, &xpad, NULL); + + gd_two_lines_renderer_get_size (cell, widget, + NULL, NULL, + &text_width, NULL, + NULL, + NULL, NULL, NULL); + + /* Fetch the average size of a character */ + context = gtk_widget_get_pango_context (widget); + gtk_style_context_save (style_context); + gtk_style_context_set_state (style_context, 0); + gtk_style_context_get (style_context, gtk_style_context_get_state (style_context), + "font", &font_desc, NULL); + gtk_style_context_restore (style_context); + metrics = pango_context_get_metrics (context, font_desc, + pango_context_get_language (context)); + + char_width = pango_font_metrics_get_approximate_char_width (metrics); + + pango_font_metrics_unref (metrics); + pango_font_description_free (font_desc); + + /* enforce minimum width for ellipsized labels at ~3 chars */ + ellipsize_chars = 3; + + /* If no width-chars set, minimum for wrapping text will be the wrap-width */ + if (wrap_width > -1) + min_width = xpad * 2 + MIN (text_width, wrap_width); + else + min_width = xpad * 2 + + MIN (text_width, + (PANGO_PIXELS (char_width) * MAX (width_chars, ellipsize_chars))); + + if (width_chars > 0) + nat_width = xpad * 2 + + MAX ((PANGO_PIXELS (char_width) * width_chars), text_width); + else + nat_width = xpad * 2 + text_width; + + nat_width = MAX (nat_width, min_width); + + if (minimum_size) + *minimum_size = min_width; + + if (natural_size) + *natural_size = nat_width; +} + +static void +gd_two_lines_renderer_get_preferred_height_for_width (GtkCellRenderer *cell, + GtkWidget *widget, + gint width, + gint *minimum_size, + gint *natural_size) +{ + GdTwoLinesRenderer *self = GD_TWO_LINES_RENDERER (cell); + PangoLayout *layout_one, *layout_two; + gint text_height, wrap_width; + gint xpad, ypad; + + gtk_cell_renderer_get_padding (cell, &xpad, &ypad); + g_object_get (cell, "wrap-width", &wrap_width, NULL); + gd_two_lines_renderer_prepare_layouts (self, NULL, widget, &layout_one, &layout_two); + + if (wrap_width != -1) + wrap_width = MIN (width - 2 * xpad, wrap_width); + else + wrap_width = width - 2 * xpad; + + pango_layout_set_width (layout_one, wrap_width); + if (layout_two != NULL) + pango_layout_set_width (layout_two, wrap_width); + + gd_two_lines_renderer_get_size (cell, widget, + layout_one, layout_two, + NULL, &text_height, + NULL, + NULL, NULL, NULL); + + text_height += 2 * ypad; + + if (minimum_size != NULL) + *minimum_size = text_height; + + if (natural_size != NULL) + *natural_size = text_height; + + g_clear_object (&layout_one); + g_clear_object (&layout_two); +} + +static void +gd_two_lines_renderer_get_preferred_height (GtkCellRenderer *cell, + GtkWidget *widget, + gint *minimum_size, + gint *natural_size) +{ + gint min_width; + + gtk_cell_renderer_get_preferred_width (cell, widget, &min_width, NULL); + gd_two_lines_renderer_get_preferred_height_for_width (cell, widget, min_width, + minimum_size, natural_size); +} + +static void +gd_two_lines_renderer_get_aligned_area (GtkCellRenderer *cell, + GtkWidget *widget, + GtkCellRendererState flags, + const GdkRectangle *cell_area, + GdkRectangle *aligned_area) +{ + gint x_offset, x_offset_1, x_offset_2, y_offset; + + /* fetch common information */ + gd_two_lines_renderer_get_size (cell, widget, + NULL, NULL, + &aligned_area->width, &aligned_area->height, + cell_area, + &x_offset_1, &x_offset_2, &y_offset); + + x_offset = MIN (x_offset_1, x_offset_2); + + aligned_area->x = cell_area->x + x_offset; + aligned_area->y = cell_area->y + y_offset; +} + +static void +gd_two_lines_renderer_set_line_two (GdTwoLinesRenderer *self, + const gchar *line_two) +{ + GdTwoLinesRendererPrivate *priv; + + priv = gd_two_lines_renderer_get_instance_private (self); + + if (g_strcmp0 (priv->line_two, line_two) == 0) + return; + + g_free (priv->line_two); + priv->line_two = g_strdup (line_two); + + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_LINE_TWO]); +} + +static void +gd_two_lines_renderer_set_text_lines (GdTwoLinesRenderer *self, + gint text_lines) +{ + GdTwoLinesRendererPrivate *priv; + + priv = gd_two_lines_renderer_get_instance_private (self); + + if (priv->text_lines == text_lines) + return; + + priv->text_lines = text_lines; + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_TEXT_LINES]); +} + +static void +gd_two_lines_renderer_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + GdTwoLinesRenderer *self = GD_TWO_LINES_RENDERER (object); + + switch (property_id) + { + case PROP_TEXT_LINES: + gd_two_lines_renderer_set_text_lines (self, g_value_get_int (value)); + break; + case PROP_LINE_TWO: + gd_two_lines_renderer_set_line_two (self, g_value_get_string (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gd_two_lines_renderer_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + GdTwoLinesRenderer *self = GD_TWO_LINES_RENDERER (object); + GdTwoLinesRendererPrivate *priv; + + priv = gd_two_lines_renderer_get_instance_private (self); + + switch (property_id) + { + case PROP_TEXT_LINES: + g_value_set_int (value, priv->text_lines); + break; + case PROP_LINE_TWO: + g_value_set_string (value, priv->line_two); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gd_two_lines_renderer_finalize (GObject *object) +{ + GdTwoLinesRenderer *self = GD_TWO_LINES_RENDERER (object); + GdTwoLinesRendererPrivate *priv; + + priv = gd_two_lines_renderer_get_instance_private (self); + + g_free (priv->line_two); + + G_OBJECT_CLASS (gd_two_lines_renderer_parent_class)->finalize (object); +} + +static void +gd_two_lines_renderer_class_init (GdTwoLinesRendererClass *klass) +{ + GtkCellRendererClass *cclass = GTK_CELL_RENDERER_CLASS (klass); + GObjectClass *oclass = G_OBJECT_CLASS (klass); + + cclass->render = gd_two_lines_renderer_render; + cclass->get_preferred_width = gd_two_lines_renderer_get_preferred_width; + cclass->get_preferred_height = gd_two_lines_renderer_get_preferred_height; + cclass->get_preferred_height_for_width = gd_two_lines_renderer_get_preferred_height_for_width; + cclass->get_aligned_area = gd_two_lines_renderer_get_aligned_area; + + oclass->set_property = gd_two_lines_renderer_set_property; + oclass->get_property = gd_two_lines_renderer_get_property; + oclass->finalize = gd_two_lines_renderer_finalize; + + properties[PROP_TEXT_LINES] = + g_param_spec_int ("text-lines", + "Lines of text", + "The total number of lines to be displayed", + 2, G_MAXINT, 2, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + + properties[PROP_LINE_TWO] = + g_param_spec_string ("line-two", + "Second line", + "Second line", + NULL, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties (oclass, NUM_PROPERTIES, properties); +} + +static void +gd_two_lines_renderer_init (GdTwoLinesRenderer *self) +{ +} + +GtkCellRenderer * +gd_two_lines_renderer_new (void) +{ + return g_object_new (GD_TYPE_TWO_LINES_RENDERER, NULL); +} diff --git a/subprojects/libgd/libgd/gd-two-lines-renderer.h b/subprojects/libgd/libgd/gd-two-lines-renderer.h new file mode 100644 index 00000000..113191b6 --- /dev/null +++ b/subprojects/libgd/libgd/gd-two-lines-renderer.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2011 Red Hat, Inc. + * + * This program 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 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 Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Author: Cosimo Cecchi <cosimoc@redhat.com> + * + */ + +#ifndef _GD_TWO_LINES_RENDERER_H +#define _GD_TWO_LINES_RENDERER_H + +#include <glib-object.h> + +#include <gtk/gtk.h> + +G_BEGIN_DECLS + +#define GD_TYPE_TWO_LINES_RENDERER gd_two_lines_renderer_get_type() +G_DECLARE_DERIVABLE_TYPE (GdTwoLinesRenderer, gd_two_lines_renderer, GD, TWO_LINES_RENDERER, GtkCellRendererText) + +struct _GdTwoLinesRendererClass +{ + GtkCellRendererTextClass parent_class; +}; + +GtkCellRenderer *gd_two_lines_renderer_new (void); + +G_END_DECLS + +#endif /* _GD_TWO_LINES_RENDERER_H */ diff --git a/subprojects/libgd/libgd/gd-types-catalog.c b/subprojects/libgd/libgd/gd-types-catalog.c new file mode 100644 index 00000000..75f7d577 --- /dev/null +++ b/subprojects/libgd/libgd/gd-types-catalog.c @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2012 Red Hat, Inc. + * + * This program 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 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 Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "gd-types-catalog.h" + +#ifdef LIBGD__BOX_COMMON +# include "gd-main-box-child.h" +# include "gd-main-box-generic.h" +# include "gd-main-box-item.h" +#endif + +#ifdef LIBGD_MAIN_ICON_BOX +# include "gd-main-icon-box.h" +# include "gd-main-icon-box-child.h" +#endif + +#ifdef LIBGD_MAIN_BOX +# include "gd-main-box.h" +#endif + +#ifdef LIBGD__VIEW_COMMON +# include "gd-main-view-generic.h" +# include "gd-styled-text-renderer.h" +# include "gd-two-lines-renderer.h" +#endif + +#ifdef LIBGD_MAIN_ICON_VIEW +# include "gd-main-icon-view.h" +# include "gd-toggle-pixbuf-renderer.h" +#endif + +#ifdef LIBGD_MAIN_LIST_VIEW +# include "gd-main-list-view.h" +#endif + +#ifdef LIBGD_MAIN_VIEW +# include "gd-main-view.h" +#endif + +#ifdef LIBGD_MARGIN_CONTAINER +# include "gd-margin-container.h" +#endif + +#ifdef LIBGD_TAGGED_ENTRY +# include "gd-tagged-entry.h" +#endif + +#ifdef LIBGD_NOTIFICATION +# include "gd-notification.h" +#endif + +/** + * gd_ensure_types: + * + * This functions must be called during initialization + * to make sure the widget types are available to GtkBuilder. + */ +void +gd_ensure_types (void) +{ +#ifdef LIBGD__BOX_COMMON + g_type_ensure (GD_TYPE_MAIN_BOX_CHILD); + g_type_ensure (GD_TYPE_MAIN_BOX_GENERIC); + g_type_ensure (GD_TYPE_MAIN_BOX_ITEM); +#endif + +#ifdef LIBGD_MAIN_ICON_BOX + g_type_ensure (GD_TYPE_MAIN_ICON_BOX); + g_type_ensure (GD_TYPE_MAIN_ICON_BOX_CHILD); +#endif + +#ifdef LIBGD_MAIN_BOX + g_type_ensure (GD_TYPE_MAIN_BOX); +#endif + +#ifdef LIBGD__VIEW_COMMON + g_type_ensure (GD_TYPE_MAIN_VIEW_GENERIC); + g_type_ensure (GD_TYPE_STYLED_TEXT_RENDERER); + g_type_ensure (GD_TYPE_TWO_LINES_RENDERER); +#endif + +#ifdef LIBGD_MAIN_ICON_VIEW + g_type_ensure (GD_TYPE_MAIN_ICON_VIEW); + g_type_ensure (GD_TYPE_TOGGLE_PIXBUF_RENDERER); +#endif + +#ifdef LIBGD_MAIN_LIST_VIEW + g_type_ensure (GD_TYPE_MAIN_LIST_VIEW); +#endif + +#ifdef LIBGD_MAIN_VIEW + g_type_ensure (GD_TYPE_MAIN_VIEW); +#endif + +#ifdef LIBGD_MARGIN_CONTAINER + g_type_ensure (GD_TYPE_MARGIN_CONTAINER); +#endif + +#ifdef LIBGD_TAGGED_ENTRY + g_type_ensure (GD_TYPE_TAGGED_ENTRY); +#endif + +#ifdef LIBGD_NOTIFICATION + g_type_ensure (GD_TYPE_NOTIFICATION); +#endif +} + diff --git a/subprojects/libgd/libgd/gd-types-catalog.h b/subprojects/libgd/libgd/gd-types-catalog.h new file mode 100644 index 00000000..fc99416b --- /dev/null +++ b/subprojects/libgd/libgd/gd-types-catalog.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2012 Red Hat, Inc. + * + * This program 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 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 Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef __GD_TYPES_CATALOG_H__ +#define __GD_TYPES_CATALOG_H__ + +#include <glib-object.h> + +G_BEGIN_DECLS + +void gd_ensure_types (void); + +G_END_DECLS + +#endif /* __GD_TYPES_CATALOG_H__ */ diff --git a/subprojects/libgd/libgd/gd.h b/subprojects/libgd/libgd/gd.h new file mode 100644 index 00000000..69685c97 --- /dev/null +++ b/subprojects/libgd/libgd/gd.h @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2012 Red Hat, Inc. + * + * This program 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 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 Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef __GD_H__ +#define __GD_H__ + +#include <glib-object.h> + +G_BEGIN_DECLS + +#include <libgd/gd-types-catalog.h> + +#ifdef LIBGD_GTK_HACKS +# include <libgd/gd-icon-utils.h> +#endif + +#ifdef LIBGD__BOX_COMMON +# include <libgd/gd-main-box-child.h> +# include <libgd/gd-main-box-generic.h> +# include <libgd/gd-main-box-item.h> +#endif + +#ifdef LIBGD_MAIN_ICON_BOX +# include <libgd/gd-main-icon-box.h> +# include <libgd/gd-main-icon-box-child.h> +#endif + +#ifdef LIBGD_MAIN_BOX +# include <libgd/gd-main-box.h> +#endif + +#ifdef LIBGD__VIEW_COMMON +# include <libgd/gd-main-view-generic.h> +# include <libgd/gd-styled-text-renderer.h> +# include <libgd/gd-two-lines-renderer.h> +#endif + +#ifdef LIBGD_MAIN_ICON_VIEW +# include <libgd/gd-main-icon-view.h> +# include <libgd/gd-toggle-pixbuf-renderer.h> +#endif + +#ifdef LIBGD_MAIN_LIST_VIEW +# include <libgd/gd-main-list-view.h> +#endif + +#ifdef LIBGD_MAIN_VIEW +# include <libgd/gd-main-view.h> +#endif + +#ifdef LIBGD_MARGIN_CONTAINER +# include <libgd/gd-margin-container.h> +#endif + +#ifdef LIBGD_TAGGED_ENTRY +# include <libgd/gd-tagged-entry.h> +#endif + +#ifdef LIBGD_NOTIFICATION +# include <libgd/gd-notification.h> +#endif + +G_END_DECLS + +#endif /* __GD_H__ */ diff --git a/subprojects/libgd/libgd/meson.build b/subprojects/libgd/libgd/meson.build new file mode 100644 index 00000000..6ba7871f --- /dev/null +++ b/subprojects/libgd/libgd/meson.build @@ -0,0 +1,204 @@ +gnome = import('gnome') + +sources = [ + 'gd.h', + 'gd-types-catalog.c' +] +built_sources = [] +c_args = [] +private_c_args = [ + '-DG_LOG_DOMAIN="libgd"', + '-DG_DISABLE_DEPRECATED', +] + +if (get_option('with-gtk-hacks') or + get_option('with-main-box') or + get_option('with-main-icon-box') or + get_option('with-main-view')) + sources += [ + 'gd-icon-utils.c', + 'gd-icon-utils.h', + ] + c_args += '-DLIBGD_GTK_HACKS=1' +endif + +if (get_option('with-main-box') or + get_option('with-main-icon-box')) + sources += [ + 'gd-main-box-child.c', + 'gd-main-box-child.h', + 'gd-main-box-generic.c', + 'gd-main-box-generic.h', + 'gd-main-box-item.c', + 'gd-main-box-item.h' + ] + c_args += '-DLIBGD__BOX_COMMON=1' + + if (get_option('with-main-box') or + get_option('with-main-icon-box')) + sources += [ + 'gd-main-icon-box.c', + 'gd-main-icon-box.h', + 'gd-main-icon-box-child.c', + 'gd-main-icon-box-child.h', + 'gd-main-icon-box-icon.c', + 'gd-main-icon-box-icon.h', + 'gd-icon-utils.c', + 'gd-icon-utils.h', + ] + c_args += '-DLIBGD_MAIN_ICON_BOX=1' + endif + + if get_option('with-main-box') + sources += [ + 'gd-main-box.c', + 'gd-main-box.h', + ] + c_args += '-DLIBGD_MAIN_BOX=1' + endif +endif + +if (get_option('with-main-icon-view') or + get_option('with-main-list-view') or + get_option('with-main-view')) + sources += [ + 'gd-main-view-generic.c', + 'gd-main-view-generic.h', + 'gd-styled-text-renderer.c', + 'gd-styled-text-renderer.h', + 'gd-two-lines-renderer.c', + 'gd-two-lines-renderer.h', + ] + c_args += '-DLIBGD__VIEW_COMMON=1' + + if (get_option('with-main-icon-view') or + get_option('with-main-view')) + sources += [ + 'gd-main-icon-view.c', + 'gd-main-icon-view.h', + 'gd-toggle-pixbuf-renderer.c', + 'gd-toggle-pixbuf-renderer.h' + ] + c_args += '-DLIBGD_MAIN_ICON_VIEW=1' + endif + + if (get_option('with-main-list-view') or + get_option('with-main-view')) + sources += [ + 'gd-main-list-view.c', + 'gd-main-list-view.h', + ] + c_args += '-DLIBGD_MAIN_LIST_VIEW=1' + endif + + if get_option('with-main-view') + sources += [ + 'gd-main-view.c', + 'gd-main-view.h', + ] + c_args += '-DLIBGD_MAIN_VIEW=1' + endif +endif + +if get_option('with-margin-container') + sources += [ + 'gd-margin-container.c', + 'gd-margin-container.h', + ] + c_args += '-DLIBGD_MARGIN_CONTAINER=1' +endif + +if get_option('with-tagged-entry') + sources += [ + 'gd-tagged-entry.c', + 'gd-tagged-entry.h', + ] + c_args += '-DLIBGD_TAGGED_ENTRY=1' +endif + +if get_option('with-notification') + sources += [ + 'gd-notification.c', + 'gd-notification.h', + ] + c_args += '-DLIBGD_NOTIFICATION=1' +endif + +if sources.length() == 2 + error('You must include a feature to be built!') +endif + +# --------- Building ----------- + +static = get_option('static') +install_introspection = get_option('with-introspection') +with_vapi = get_option('with-vapi') + +if static + libgd_lib = static_library('gd', sources, + dependencies: [libgtk, libm], + include_directories: libgd_include, + c_args: c_args + private_c_args + ) +endif + +# Currently in Meson building gir requires a shared library +if not static or (install_introspection or with_vapi) + if not static and pkglibdir == '' + error('Installing shared library but pkglibdir is unset!') + endif + + libgd_shared_lib = shared_library('gd', sources, + dependencies: [libgtk, libm], + include_directories: libgd_include, + c_args: c_args + private_c_args, + install: not static, + install_dir: pkglibdir + ) + + if not static + libgd_lib = libgd_shared_lib + endif +endif + +if install_introspection or with_vapi + if install_introspection + if pkgdatadir == '' + error('Installing introspection but pkgdatadir is unset!') + elif pkglibdir == '' + error('Installing introspection but pkglibdir is unset!') + endif + endif + + libgd_gir = gnome.generate_gir(libgd_shared_lib, + sources : sources, + nsversion : '1.0', + namespace : 'Gd', + symbol_prefix : 'gd', + identifier_prefix : 'Gd', + includes : 'Gtk-3.0', + include_directories: libgd_include, + install: install_introspection, + install_dir_gir: join_paths(pkgdatadir, 'gir-1.0'), + install_dir_typelib: join_paths(pkglibdir, 'girepository-1.0'), + extra_args: [ + '--c-include=libgd/gd.h', + ] + ) + built_sources += libgd_gir + + if get_option('with-vapi') + libgd_vapi_dep = gnome.generate_vapi('gd-1.0', + sources: libgd_gir[0], + packages: ['gtk+-3.0'] + ) + endif +endif + +libgd_dep = declare_dependency( + link_with: libgd_lib, + include_directories: libgd_include, + dependencies: libgtk, + compile_args: c_args, + sources: built_sources +) diff --git a/subprojects/libgd/meson.build b/subprojects/libgd/meson.build new file mode 100644 index 00000000..6d1242c0 --- /dev/null +++ b/subprojects/libgd/meson.build @@ -0,0 +1,24 @@ +project('libgd', 'c', + meson_version: '>= 0.38.0', + default_options: ['static=true'], +) + +if not meson.is_subproject() + message('WARNING: This project is only intended to be used as a subproject!') +endif + +pkglibdir = get_option('pkglibdir') +pkgdatadir = get_option('pkgdatadir') + +libgtk = dependency('gtk+-3.0', version: '>= 3.7.10') +cc = meson.get_compiler('c') +libm = cc.find_library('m', required: false) +libgd_include = include_directories('.') + +subdir('libgd') + +if get_option('with-tagged-entry') + foreach t : ['test-tagged-entry', 'test-tagged-entry-2'] + executable(t, t + '.c', dependencies : libgd_dep) + endforeach +endif diff --git a/subprojects/libgd/meson_options.txt b/subprojects/libgd/meson_options.txt new file mode 100644 index 00000000..fcab3a07 --- /dev/null +++ b/subprojects/libgd/meson_options.txt @@ -0,0 +1,25 @@ +option('pkglibdir', type: 'string', value: '', + description: 'The private directory the shared library/typelib will be installed into.' +) +option('pkgdatadir', type: 'string', value: '', + description: 'The private directory the gir file will be installed into.' +) +option('static', type: 'boolean', value: false, + description: 'Build as a static library' +) +option('with-introspection', type: 'boolean', value: false, + description: 'Build gobject-introspection support' +) +option('with-vapi', type: 'boolean', value: false, + description: 'Build vapi file' +) +# Widget options +option('with-gtk-hacks', type: 'boolean', value: false) +option('with-main-view', type: 'boolean', value: false) +option('with-main-icon-view', type: 'boolean', value: false) +option('with-main-list-view', type: 'boolean', value: false) +option('with-margin-container', type: 'boolean', value: false) +option('with-tagged-entry', type: 'boolean', value: false) +option('with-notification', type: 'boolean', value: false) +option('with-main-box', type: 'boolean', value: false) +option('with-main-icon-box', type: 'boolean', value: false)
\ No newline at end of file diff --git a/subprojects/libgd/meson_readme.md b/subprojects/libgd/meson_readme.md new file mode 100644 index 00000000..c3e7f26e --- /dev/null +++ b/subprojects/libgd/meson_readme.md @@ -0,0 +1,88 @@ +See README for general information. Read below for usage with Meson. + +Usage +===== + +libgd is intended to be used as a submodule from other projects. This requires passing default_options to the subproject +which was added in Meson 0.38.0. To see a full list of options you can run `mesonconf $your_build_dir`. If building a +non-static library `pkglibdir` must be set to a private location to install to which you will also want to pass (an absolute path) +with the `install_rpath` keyword to any executables. For introspection files you also must set `pkgdatadir`. + +So given a Meson project using git you would run this to do initial setup: + +``` +mkdir subprojects +git submodule add https://git.gnome.org/browse/libgd subprojects/libgd +``` + +Then from within your `meson.build` file: + +Static Library +-------------- + +```meson +libgd = subproject('libgd', + default_options: [ + 'with-tagged-entry=true' + ] +) +# Pass as dependency to another target +libgd_dep = libgd.get_variable('libgd_dep') +``` + +```c +#include "libgd/gd.h" + +int main(int argc, char **argv) +{ + gd_ensure_types(); /* As a test */ + return 0; +} +``` + +Introspection +------------- + +```meson +pkglibdir = join_paths(get_option('libdir'), meson.project_name()) +pkgdatadir = join_paths(get_option('datadir'), meson.project_name()) +libgd = subproject('libgd', + default_options: [ + 'pkglibdir=' + pkglibdir, + 'pkgdatadir=' + pkgdatadir, + 'with-tagged-entry=true', + 'with-introspection=true', + 'static=false', + ] +) +``` + +```python +import os +import gi +gi.require_version('GIRepository', '2.0') +from gi.repository import GIRepository +pkglibdir = '/usr/lib/foo' # This would be defined at build time +pkggirdir = os.path.join(pkglibdir, 'girepository-1.0') +GIRepository.Repository.prepend_search_path(pkggirdir) +GIRepository.Repository.prepend_library_path(pkglibdir) +gi.require_version('Gd', '1.0') +``` + +Vala +---- + +```meson +pkglibdir = join_paths(get_option('libdir'), meson.project_name()) +libgd = subproject('libgd', + default_options: [ + 'pkglibdir=' + pkglibdir, + 'with-tagged-entry=true', + 'with-vapi=true' + ] +) +# Pass as dependency to a Vala target +libgd_vapi_dep = libgd.get_variable('libgd_vapi_dep') +``` + +<!-- TODO: Make a Vala example --> diff --git a/subprojects/libgd/test-tagged-entry-2.c b/subprojects/libgd/test-tagged-entry-2.c new file mode 100644 index 00000000..465ab83d --- /dev/null +++ b/subprojects/libgd/test-tagged-entry-2.c @@ -0,0 +1,131 @@ +#include <gtk/gtk.h> +#include <libgd/gd-tagged-entry.h> + +static GdTaggedEntryTag *toggle_tag; + +static void +on_tag_clicked (GdTaggedEntry *entry, + GdTaggedEntryTag *tag, + gpointer useless) +{ + g_print ("tag clicked: %s\n", gd_tagged_entry_tag_get_label (tag)); +} + +static void +on_tag_button_clicked (GdTaggedEntry *entry, + GdTaggedEntryTag *tag, + gpointer useless) +{ + g_print ("tag button clicked: %s\n", gd_tagged_entry_tag_get_label (tag)); +} + +static void +on_toggle_visible (GtkButton *button, + GtkWidget *entry) +{ + gboolean active; + + active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)); + + g_print ("%s tagged entry\n", active ? "show" : "hide"); + gtk_widget_set_visible (entry, active); +} + +static void +on_toggle_tag (GtkButton *button, + GdTaggedEntry *entry) +{ + gboolean active; + + active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)); + + if (active) + { + g_print ("adding tag 'Toggle Tag'\n"); + gd_tagged_entry_insert_tag (entry, toggle_tag, 0); + } + else + { + g_print ("removing tag 'Toggle Tag'\n"); + gd_tagged_entry_remove_tag (entry, toggle_tag); + } +} + +gint +main (gint argc, + gchar ** argv) +{ + GtkWidget *box; + GtkWidget *entry; + GtkWidget *search_bar; + GtkWidget *search_container; + GtkWidget *toggle_tag_button; + GtkWidget *toggle_visible_button; + GtkWidget *revealer; + GtkWidget *window; + GdTaggedEntryTag *tag; + + gtk_init (&argc, &argv); + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_widget_set_size_request (window, 640, 600); + + box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); + gtk_container_add (GTK_CONTAINER (window), box); + + revealer = gtk_revealer_new (); + gtk_revealer_set_reveal_child (GTK_REVEALER (revealer), TRUE); + gtk_container_add (GTK_CONTAINER (box), revealer); + + search_bar = gtk_search_bar_new (); + gtk_search_bar_set_search_mode (GTK_SEARCH_BAR (search_bar), TRUE); + gtk_container_add (GTK_CONTAINER (revealer), search_bar); + + search_container = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); + gtk_widget_set_halign (search_container, GTK_ALIGN_CENTER); + gtk_container_add (GTK_CONTAINER (search_bar), search_container); + + entry = GTK_WIDGET (gd_tagged_entry_new ()); + gtk_widget_set_size_request (entry, 500, -1); + g_signal_connect (entry, "tag-clicked", + G_CALLBACK (on_tag_clicked), NULL); + g_signal_connect (entry, "tag-button-clicked", + G_CALLBACK (on_tag_button_clicked), NULL); + gtk_container_add (GTK_CONTAINER (search_container), entry); + + tag = gd_tagged_entry_tag_new ("Blah1"); + gd_tagged_entry_add_tag (GD_TAGGED_ENTRY (entry), tag); + g_object_unref (tag); + + tag = gd_tagged_entry_tag_new ("Blah2"); + gd_tagged_entry_tag_set_has_close_button (tag, FALSE); + gd_tagged_entry_insert_tag (GD_TAGGED_ENTRY (entry), tag, -1); + g_object_unref (tag); + + tag = gd_tagged_entry_tag_new ("Blah3"); + gd_tagged_entry_tag_set_has_close_button (tag, FALSE); + gd_tagged_entry_insert_tag (GD_TAGGED_ENTRY (entry), tag, 0); + g_object_unref (tag); + + toggle_visible_button = gtk_toggle_button_new_with_label ("Visible"); + gtk_widget_set_vexpand (toggle_visible_button, TRUE); + gtk_widget_set_valign (toggle_visible_button, GTK_ALIGN_END); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle_visible_button), TRUE); + g_signal_connect (toggle_visible_button, "toggled", + G_CALLBACK (on_toggle_visible), entry); + gtk_container_add (GTK_CONTAINER (box), toggle_visible_button); + + toggle_tag = gd_tagged_entry_tag_new ("Toggle Tag"); + + toggle_tag_button = gtk_toggle_button_new_with_label ("Toggle Tag"); + g_signal_connect (toggle_tag_button, "toggled", + G_CALLBACK (on_toggle_tag), entry); + gtk_container_add (GTK_CONTAINER (box), toggle_tag_button); + + gtk_widget_show_all (window); + gtk_main (); + + gtk_widget_destroy (window); + + return 0; +} diff --git a/subprojects/libgd/test-tagged-entry.c b/subprojects/libgd/test-tagged-entry.c new file mode 100644 index 00000000..0f583d9b --- /dev/null +++ b/subprojects/libgd/test-tagged-entry.c @@ -0,0 +1,111 @@ +#include <gtk/gtk.h> +#include <libgd/gd-tagged-entry.h> + +static GdTaggedEntryTag *toggle_tag; + +static void +on_tag_clicked (GdTaggedEntry *entry, + GdTaggedEntryTag *tag, + gpointer useless) +{ + g_print ("tag clicked: %s\n", gd_tagged_entry_tag_get_label (tag)); +} + +static void +on_tag_button_clicked (GdTaggedEntry *entry, + GdTaggedEntryTag *tag, + gpointer useless) +{ + g_print ("tag button clicked: %s\n", gd_tagged_entry_tag_get_label (tag)); +} + +static void +on_toggle_visible (GtkButton *button, + GtkWidget *entry) +{ + gboolean active; + + active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)); + + g_print ("%s tagged entry\n", active ? "show" : "hide"); + gtk_widget_set_visible (entry, active); +} + +static void +on_toggle_tag (GtkButton *button, + GdTaggedEntry *entry) +{ + gboolean active; + + active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)); + + if (active) + { + g_print ("adding tag 'Toggle Tag'\n"); + gd_tagged_entry_insert_tag (entry, toggle_tag, 0); + } + else + { + g_print ("removing tag 'Toggle Tag'\n"); + gd_tagged_entry_remove_tag (entry, toggle_tag); + } +} + +gint +main (gint argc, + gchar ** argv) +{ + GtkWidget *window, *box, *entry, *toggle_visible_button, *toggle_tag_button; + GdTaggedEntryTag *tag; + + gtk_init (&argc, &argv); + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_widget_set_size_request (window, 300, 0); + + box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); + gtk_container_add (GTK_CONTAINER (window), box); + + entry = GTK_WIDGET (gd_tagged_entry_new ()); + g_signal_connect(entry, "tag-clicked", + G_CALLBACK (on_tag_clicked), NULL); + g_signal_connect(entry, "tag-button-clicked", + G_CALLBACK (on_tag_button_clicked), NULL); + gtk_container_add (GTK_CONTAINER (box), entry); + + tag = gd_tagged_entry_tag_new ("Blah1"); + gd_tagged_entry_add_tag (GD_TAGGED_ENTRY (entry), tag); + g_object_unref (tag); + + tag = gd_tagged_entry_tag_new ("Blah2"); + gd_tagged_entry_tag_set_has_close_button (tag, FALSE); + gd_tagged_entry_insert_tag (GD_TAGGED_ENTRY (entry), tag, -1); + g_object_unref (tag); + + tag = gd_tagged_entry_tag_new ("Blah3"); + gd_tagged_entry_tag_set_has_close_button (tag, FALSE); + gd_tagged_entry_insert_tag (GD_TAGGED_ENTRY (entry), tag, 0); + g_object_unref (tag); + + toggle_visible_button = gtk_toggle_button_new_with_label ("Visible"); + gtk_widget_set_vexpand (toggle_visible_button, TRUE); + gtk_widget_set_valign (toggle_visible_button, GTK_ALIGN_END); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle_visible_button), TRUE); + g_signal_connect (toggle_visible_button, "toggled", + G_CALLBACK (on_toggle_visible), entry); + gtk_container_add (GTK_CONTAINER (box), toggle_visible_button); + + toggle_tag = gd_tagged_entry_tag_new ("Toggle Tag"); + + toggle_tag_button = gtk_toggle_button_new_with_label ("Toggle Tag"); + g_signal_connect (toggle_tag_button, "toggled", + G_CALLBACK (on_toggle_tag), entry); + gtk_container_add (GTK_CONTAINER (box), toggle_tag_button); + + gtk_widget_show_all (window); + gtk_main (); + + gtk_widget_destroy (window); + + return 0; +} diff --git a/subprojects/shared-modules b/subprojects/shared-modules deleted file mode 160000 -Subproject 722c257817b83e4cce12bc7b8361ced75e09c90 diff --git a/subprojects/shared-modules/CODEOWNERS b/subprojects/shared-modules/CODEOWNERS new file mode 100644 index 00000000..d8841d17 --- /dev/null +++ b/subprojects/shared-modules/CODEOWNERS @@ -0,0 +1,11 @@ +# Fallback on Flathub admins for unowned shared modules +* @flathub/reviewers + +/dbus-glib/ @TingPing +/gtk2/ @TingPing +/gudev/ @Erick555 +/intltool/ @TingPing +/libappindicator/ @TingPing +/libsecret/ @Lctrs +/openjpeg/ @bochecha +/python2.7/ @bilelmoussaoui diff --git a/subprojects/shared-modules/README.md b/subprojects/shared-modules/README.md new file mode 100644 index 00000000..5a0ec035 --- /dev/null +++ b/subprojects/shared-modules/README.md @@ -0,0 +1,29 @@ +This repository contains commonly shared modules and is intended to be used as a git submodule. + +To use shared modules for packaging an application, add the submodule: + +``` +git submodule add https://github.com/flathub/shared-modules.git +``` + +Then modules from this repository can be specified in a manifest JSON file like this: + +```json +"modules": [ + "shared-modules/SDL/SDL-1.2.15.json", + { + "name": "foo" + } +] +``` + +To update the submodule: + +``` +git submodule update --remote --merge +``` + + +[See the description in the Flathub wiki](https://github.com/flathub/flathub/wiki/App-Requirements#shared-modules) for more information. + +Please do not request adding modules unless they have many users in the Flathub repository. diff --git a/subprojects/shared-modules/SDL/SDL-1.2.15.json b/subprojects/shared-modules/SDL/SDL-1.2.15.json new file mode 100644 index 00000000..4d00288b --- /dev/null +++ b/subprojects/shared-modules/SDL/SDL-1.2.15.json @@ -0,0 +1,40 @@ +{ + "name": "SDL1", + "rm-configure": true, + "config-opts": ["--disable-static"], + "cleanup": [ + "/bin", + "/share/man", + "/share/aclocal", + "/include", + "/lib/pkgconfig", + "/lib/*.la", + "/lib/*.a" + ], + "sources": [ + { + "type": "archive", + "url": "https://www.libsdl.org/release/SDL-1.2.15.tar.gz", + "sha256": "d6d316a793e5e348155f0dd93b979798933fb98aa1edebcc108829d6474aad00" + }, + { + "type": "patch", + "path": "sdl-libx11-build.patch" + }, + { + "type": "patch", + "path": "sdl-check-for-SDL_VIDEO_X11_BACKINGSTORE.patch" + }, + { + "type": "script", + "dest-filename": "autogen.sh", + "commands": [ + "sed -i -e 's/.*AM_PATH_ESD.*//' configure.in", + "cp -p /usr/share/automake-*/config.{sub,guess} build-scripts", + "aclocal", + "libtoolize", + "autoconf" + ] + } + ] +} diff --git a/subprojects/shared-modules/SDL/SDL_Pango-0.1.2-API-adds.patch b/subprojects/shared-modules/SDL/SDL_Pango-0.1.2-API-adds.patch new file mode 100644 index 00000000..6b1f2d05 --- /dev/null +++ b/subprojects/shared-modules/SDL/SDL_Pango-0.1.2-API-adds.patch @@ -0,0 +1,118 @@ +diff -Naupr SDL_Pango-0.1.2.orig/src/SDL_Pango.c SDL_Pango-0.1.2/src/SDL_Pango.c +--- SDL_Pango-0.1.2.orig/src/SDL_Pango.c 2004-12-10 10:06:33.000000000 +0100 ++++ SDL_Pango-0.1.2/src/SDL_Pango.c 2006-09-29 17:42:09.000000000 +0200 +@@ -723,13 +723,8 @@ SDLPango_CopyFTBitmapToSurface(
+ SDL_UnlockSurface(surface);
+ }
+
+-/*!
+- Create a context which contains Pango objects.
+-
+- @return A pointer to the context as a SDLPango_Context*.
+-*/
+ SDLPango_Context*
+-SDLPango_CreateContext()
++SDLPango_CreateContext_GivenFontDesc(const char* font_desc)
+ {
+ SDLPango_Context *context = g_malloc(sizeof(SDLPango_Context));
+ G_CONST_RETURN char *charset;
+@@ -743,8 +738,7 @@ SDLPango_CreateContext()
+ pango_context_set_language (context->context, pango_language_from_string (charset));
+ pango_context_set_base_dir (context->context, PANGO_DIRECTION_LTR);
+
+- context->font_desc = pango_font_description_from_string(
+- MAKE_FONT_NAME (DEFAULT_FONT_FAMILY, DEFAULT_FONT_SIZE));
++ context->font_desc = pango_font_description_from_string(font_desc);
+
+ context->layout = pango_layout_new (context->context);
+
+@@ -762,6 +756,17 @@ SDLPango_CreateContext()
+ }
+
+ /*!
++ Create a context which contains Pango objects.
++
++ @return A pointer to the context as a SDLPango_Context*.
++*/
++SDLPango_Context*
++SDLPango_CreateContext()
++{
++ SDLPango_CreateContext_GivenFontDesc(MAKE_FONT_NAME(DEFAULT_FONT_FAMILY, DEFAULT_FONT_SIZE));
++}
++
++/*!
+ Free a context.
+
+ @param *context [i/o] Context to be free
+@@ -1053,6 +1058,20 @@ SDLPango_SetMarkup(
+ pango_layout_set_font_description (context->layout, context->font_desc);
+ }
+
++void
++SDLPango_SetText_GivenAlignment(
++ SDLPango_Context *context,
++ const char *text,
++ int length,
++ SDLPango_Alignment alignment)
++{
++ pango_layout_set_attributes(context->layout, NULL);
++ pango_layout_set_text (context->layout, text, length);
++ pango_layout_set_auto_dir (context->layout, TRUE);
++ pango_layout_set_alignment (context->layout, alignment);
++ pango_layout_set_font_description (context->layout, context->font_desc);
++}
++
+ /*!
+ Set plain text to context.
+ Text must be utf-8.
+@@ -1067,11 +1086,7 @@ SDLPango_SetText(
+ const char *text,
+ int length)
+ {
+- pango_layout_set_attributes(context->layout, NULL);
+- pango_layout_set_text (context->layout, text, length);
+- pango_layout_set_auto_dir (context->layout, TRUE);
+- pango_layout_set_alignment (context->layout, PANGO_ALIGN_LEFT);
+- pango_layout_set_font_description (context->layout, context->font_desc);
++ SDLPango_SetText_GivenAlignment(context, text, length, SDLPANGO_ALIGN_LEFT);
+ }
+
+ /*!
+diff -Naupr SDL_Pango-0.1.2.orig/src/SDL_Pango.h SDL_Pango-0.1.2/src/SDL_Pango.h +--- SDL_Pango-0.1.2.orig/src/SDL_Pango.h 2004-12-10 10:06:33.000000000 +0100 ++++ SDL_Pango-0.1.2/src/SDL_Pango.h 2006-09-29 17:42:09.000000000 +0200 +@@ -109,12 +109,20 @@ typedef enum {
+ SDLPANGO_DIRECTION_NEUTRAL /*! Neutral */
+ } SDLPango_Direction;
+
+-
++/*!
++ Specifies alignment of text. See Pango reference for detail
++*/
++typedef enum {
++ SDLPANGO_ALIGN_LEFT,
++ SDLPANGO_ALIGN_CENTER,
++ SDLPANGO_ALIGN_RIGHT
++} SDLPango_Alignment;
+
+ extern DECLSPEC int SDLCALL SDLPango_Init();
+
+ extern DECLSPEC int SDLCALL SDLPango_WasInit();
+
++extern DECLSPEC SDLPango_Context* SDLCALL SDLPango_CreateContext_GivenFontDesc(const char* font_desc);
+ extern DECLSPEC SDLPango_Context* SDLCALL SDLPango_CreateContext();
+
+ extern DECLSPEC void SDLCALL SDLPango_FreeContext(
+@@ -157,6 +165,12 @@ extern DECLSPEC void SDLCALL SDLPango_Se + const char *markup,
+ int length);
+
++extern DECLSPEC void SDLCALL SDLPango_SetText_GivenAlignment(
++ SDLPango_Context *context,
++ const char *text,
++ int length,
++ SDLPango_Alignment alignment);
++
+ extern DECLSPEC void SDLCALL SDLPango_SetText(
+ SDLPango_Context *context,
+ const char *markup,
diff --git a/subprojects/shared-modules/SDL/SDL_image-1.2.12.json b/subprojects/shared-modules/SDL/SDL_image-1.2.12.json new file mode 100644 index 00000000..5e1692b6 --- /dev/null +++ b/subprojects/shared-modules/SDL/SDL_image-1.2.12.json @@ -0,0 +1,19 @@ +{ + "name": "SDL_image", + "config-opts": ["--disable-static"], + "rm-configure": true, + "sources": [ + { + "type": "archive", + "url": "https://www.libsdl.org/projects/SDL_image/release/SDL_image-1.2.12.tar.gz", + "sha256": "0b90722984561004de84847744d566809dbb9daf732a9e503b91a1b5a84e5699" + }, + { + "type": "script", + "dest-filename": "autogen.sh", + "commands": [ + "AUTOMAKE=\"automake --foreign\" autoreconf -vfi" + ] + } + ] +} diff --git a/subprojects/shared-modules/SDL/SDL_mixer-1.2.12.json b/subprojects/shared-modules/SDL/SDL_mixer-1.2.12.json new file mode 100644 index 00000000..ba5a6276 --- /dev/null +++ b/subprojects/shared-modules/SDL/SDL_mixer-1.2.12.json @@ -0,0 +1,22 @@ +{ + "name": "SDL_mixer", + "config-opts": ["--disable-static"], + "rm-configure": true, + "sources": [ + { + "type": "archive", + "url": "https://www.libsdl.org/projects/SDL_mixer/release/SDL_mixer-1.2.12.tar.gz", + "sha256": "1644308279a975799049e4826af2cfc787cad2abb11aa14562e402521f86992a" + }, + { + "type": "script", + "dest-filename": "autogen.sh", + "commands": [ + "rm acinclude/libtool.m4", + "rm acinclude/lt*", + "AUTOMAKE=\"automake --foreign\" autoreconf -vfi -I acinclude", + "cp -p /usr/share/automake-*/config.{sub,guess} build-scripts" + ] + } + ] +} diff --git a/subprojects/shared-modules/SDL/SDL_net-1.2.8.json b/subprojects/shared-modules/SDL/SDL_net-1.2.8.json new file mode 100644 index 00000000..9d3e896c --- /dev/null +++ b/subprojects/shared-modules/SDL/SDL_net-1.2.8.json @@ -0,0 +1,19 @@ +{ + "name": "SDL_net", + "config-opts": ["--disable-static"], + "rm-configure": true, + "sources": [ + { + "type": "archive", + "url": "https://www.libsdl.org/projects/SDL_net/release/SDL_net-1.2.8.tar.gz", + "sha256": "5f4a7a8bb884f793c278ac3f3713be41980c5eedccecff0260411347714facb4" + }, + { + "type": "script", + "dest-filename": "autogen.sh", + "commands": [ + "AUTOMAKE=\"automake --foreign\" autoreconf -vfi" + ] + } + ] +} diff --git a/subprojects/shared-modules/SDL/SDL_pango-0.1.2.json b/subprojects/shared-modules/SDL/SDL_pango-0.1.2.json new file mode 100644 index 00000000..fdbef4d1 --- /dev/null +++ b/subprojects/shared-modules/SDL/SDL_pango-0.1.2.json @@ -0,0 +1,23 @@ +{ + "name": "SDL_pango", + "config-opts": ["--disable-static"], + "rm-configure": true, + "sources": [ + { + "type": "archive", + "url": "https://downloads.sourceforge.net/project/sdlpango/SDL_Pango/0.1.2/SDL_Pango-0.1.2.tar.gz", + "sha256": "7f75d3b97acf707c696ea126424906204ebfa07660162de925173cdd0257eba4" + }, + { + "type": "patch", + "path": "SDL_Pango-0.1.2-API-adds.patch" + }, + { + "type": "script", + "dest-filename": "autogen.sh", + "commands": [ + "autoreconf -vfi" + ] + } + ] +} diff --git a/subprojects/shared-modules/SDL/SDL_ttf-2.0.11.json b/subprojects/shared-modules/SDL/SDL_ttf-2.0.11.json new file mode 100644 index 00000000..5e928e46 --- /dev/null +++ b/subprojects/shared-modules/SDL/SDL_ttf-2.0.11.json @@ -0,0 +1,19 @@ +{ + "name": "SDL_ttf", + "config-opts": ["--disable-static"], + "rm-configure": true, + "sources": [ + { + "type": "archive", + "url": "https://www.libsdl.org/projects/SDL_ttf/release/SDL_ttf-2.0.11.tar.gz", + "sha256": "724cd895ecf4da319a3ef164892b72078bd92632a5d812111261cde248ebcdb7" + }, + { + "type": "script", + "dest-filename": "autogen.sh", + "commands": [ + "AUTOMAKE=\"automake --foreign\" autoreconf -vfi" + ] + } + ] +} diff --git a/subprojects/shared-modules/SDL/sdl-check-for-SDL_VIDEO_X11_BACKINGSTORE.patch b/subprojects/shared-modules/SDL/sdl-check-for-SDL_VIDEO_X11_BACKINGSTORE.patch new file mode 100644 index 00000000..c29811d7 --- /dev/null +++ b/subprojects/shared-modules/SDL/sdl-check-for-SDL_VIDEO_X11_BACKINGSTORE.patch @@ -0,0 +1,24 @@ +Description: Do not harness backing store by default + xorg-server 1.15 enables backing store if composite extension is enabled + (default settings). Harnessing backing store through compositor leads to + tearing effect. + This patch reverts default harnessing backing store to conditional use if + SDL_VIDEO_X11_BACKINGSTORE environment variable exists. +Origin: https://bugs.launchpad.net/ubuntu/+source/libsdl1.2/+bug/1280665/comments/1 +Bug: https://bugzilla.libsdl.org/show_bug.cgi?id=2383 +Bug-Debian: https://bugs.debian.org/747168 + +--- a/src/video/x11/SDL_x11video.c ++++ b/src/video/x11/SDL_x11video.c +@@ -1088,10 +1088,8 @@ + } + } + +-#if 0 /* This is an experiment - are the graphics faster now? - nope. */ + if ( SDL_getenv("SDL_VIDEO_X11_BACKINGSTORE") ) +-#endif +- /* Cache the window in the server, when possible */ ++ /* Cache the window in the server when possible, on request */ + { + Screen *xscreen; + XSetWindowAttributes a; diff --git a/subprojects/shared-modules/SDL/sdl-libx11-build.patch b/subprojects/shared-modules/SDL/sdl-libx11-build.patch new file mode 100644 index 00000000..5bb14d4b --- /dev/null +++ b/subprojects/shared-modules/SDL/sdl-libx11-build.patch @@ -0,0 +1,59 @@ + +# HG changeset patch +# User Azamat H. Hackimov <azamat.hackimov@gmail.com> +# Date 1370184533 -21600 +# Node ID 91ad7b43317a6387e115ecdf63a49137f47e42c8 +# Parent f7fd5c3951b9ed922fdf696f7182e71b58a13268 +Fix compilation with libX11 >= 1.5.99.902. + +These changes fixes bug #1769 for SDL 1.2 +(http://bugzilla.libsdl.org/show_bug.cgi?id=1769). + +diff -r f7fd5c3951b9 -r 91ad7b43317a configure.in +--- a/configure.in Wed Apr 17 00:56:53 2013 -0700 ++++ b/configure.in Sun Jun 02 20:48:53 2013 +0600 +@@ -1169,6 +1169,17 @@ + if test x$definitely_enable_video_x11_xrandr = xyes; then + AC_DEFINE(SDL_VIDEO_DRIVER_X11_XRANDR) + fi ++ AC_MSG_CHECKING(for const parameter to _XData32) ++ have_const_param_xdata32=no ++ AC_TRY_COMPILE([ ++ #include <X11/Xlibint.h> ++ extern int _XData32(Display *dpy,register _Xconst long *data,unsigned len); ++ ],[ ++ ],[ ++ have_const_param_xdata32=yes ++ AC_DEFINE(SDL_VIDEO_DRIVER_X11_CONST_PARAM_XDATA32) ++ ]) ++ AC_MSG_RESULT($have_const_param_xdata32) + fi + fi + } +diff -r f7fd5c3951b9 -r 91ad7b43317a include/SDL_config.h.in +--- a/include/SDL_config.h.in Wed Apr 17 00:56:53 2013 -0700 ++++ b/include/SDL_config.h.in Sun Jun 02 20:48:53 2013 +0600 +@@ -283,6 +283,7 @@ + #undef SDL_VIDEO_DRIVER_WINDIB + #undef SDL_VIDEO_DRIVER_WSCONS + #undef SDL_VIDEO_DRIVER_X11 ++#undef SDL_VIDEO_DRIVER_X11_CONST_PARAM_XDATA32 + #undef SDL_VIDEO_DRIVER_X11_DGAMOUSE + #undef SDL_VIDEO_DRIVER_X11_DYNAMIC + #undef SDL_VIDEO_DRIVER_X11_DYNAMIC_XEXT +diff -r f7fd5c3951b9 -r 91ad7b43317a src/video/x11/SDL_x11sym.h +--- a/src/video/x11/SDL_x11sym.h Wed Apr 17 00:56:53 2013 -0700 ++++ b/src/video/x11/SDL_x11sym.h Sun Jun 02 20:48:53 2013 +0600 +@@ -165,7 +165,11 @@ + */ + #ifdef LONG64 + SDL_X11_MODULE(IO_32BIT) ++#if SDL_VIDEO_DRIVER_X11_CONST_PARAM_XDATA32 ++SDL_X11_SYM(int,_XData32,(Display *dpy,register _Xconst long *data,unsigned len),(dpy,data,len),return) ++#else + SDL_X11_SYM(int,_XData32,(Display *dpy,register long *data,unsigned len),(dpy,data,len),return) ++#endif + SDL_X11_SYM(void,_XRead32,(Display *dpy,register long *data,long len),(dpy,data,len),) + #endif + + diff --git a/subprojects/shared-modules/cld2/CMakeLists.txt b/subprojects/shared-modules/cld2/CMakeLists.txt new file mode 100644 index 00000000..d25f857f --- /dev/null +++ b/subprojects/shared-modules/cld2/CMakeLists.txt @@ -0,0 +1,155 @@ +cmake_minimum_required(VERSION 2.8) +project (cld2) +enable_language(CXX) + +set (VERSION "0.0.197") +set (common_SOURCE_FILES + internal/cldutil.cc + internal/cldutil_shared.cc + internal/compact_lang_det.cc + internal/compact_lang_det_hint_code.cc + internal/compact_lang_det_impl.cc + internal/debug.cc + internal/fixunicodevalue.cc + internal/generated_entities.cc + internal/generated_language.cc + internal/generated_ulscript.cc + internal/getonescriptspan.cc + internal/lang_script.cc + internal/offsetmap.cc + internal/scoreonescriptspan.cc + internal/tote.cc + internal/utf8statetable.cc + ) + +set (cld2_SOURCE_FILES + internal/generated_distinct_bi_0.cc + internal/cld_generated_cjk_uni_prop_80.cc + internal/cld2_generated_cjk_compatible.cc + internal/cld_generated_cjk_delta_bi_4.cc + internal/cld2_generated_quadchrome_2.cc + internal/cld2_generated_deltaoctachrome.cc + internal/cld2_generated_distinctoctachrome.cc + internal/cld_generated_score_quad_octa_2.cc + ) + +set (cld2_full_SOURCE_FILES + internal/generated_distinct_bi_0.cc + internal/cld_generated_cjk_uni_prop_80.cc + internal/cld2_generated_cjk_compatible.cc + internal/cld_generated_cjk_delta_bi_32.cc + internal/cld2_generated_quad0122.cc + internal/cld2_generated_deltaocta0122.cc + internal/cld2_generated_distinctocta0122.cc + internal/cld_generated_score_quad_octa_0122.cc + ) + +set (cld2_dynamic_SOURCE_FILES + internal/cld2_dynamic_data.cc + internal/cld2_dynamic_data_loader.cc + ) + +add_library(cld2 SHARED ${common_SOURCE_FILES} ${cld2_SOURCE_FILES}) +set_target_properties(cld2 PROPERTIES + ENABLE_EXPORTS On + OUTPUT_NAME cld2 + VERSION ${VERSION} + SOVERSION 0 + ) +add_library(cld2_full SHARED ${cld2_full_SOURCE_FILES}) +set_target_properties(cld2_full PROPERTIES + ENABLE_EXPORTS On + OUTPUT_NAME cld2_full + VERSION ${VERSION} + SOVERSION 0 + ) + +add_library(cld2_dynamic SHARED ${cld2_dynamic_SOURCE_FILES}) +set_target_properties(cld2_dynamic PROPERTIES + ENABLE_EXPORTS On + OUTPUT_NAME cld2_dynamic + VERSION ${VERSION} + SOVERSION 0 + COMPILE_FLAGS "-DCLD2_DYNAMIC_MODE" + ) +install(TARGETS cld2 DESTINATION lib/${CMAKE_LIBRARY_ARCHITECTURE}) +install(TARGETS cld2_full DESTINATION lib/${CMAKE_LIBRARY_ARCHITECTURE}) +install(TARGETS cld2_dynamic DESTINATION lib/${CMAKE_LIBRARY_ARCHITECTURE}) + +set (cld2_internal_HEADERS + internal/cld2_dynamic_compat.h + internal/cld2_dynamic_data_extractor.h + internal/cld2_dynamic_data.h + internal/cld2_dynamic_data_loader.h + internal/cld2tablesummary.h + internal/cldutil.h + internal/cldutil_offline.h + internal/cldutil_shared.h + internal/compact_lang_det_hint_code.h + internal/compact_lang_det_impl.h + internal/debug.h + internal/fixunicodevalue.h + internal/generated_language.h + internal/generated_ulscript.h + internal/getonescriptspan.h + internal/integral_types.h + internal/lang_script.h + internal/langspan.h + internal/offsetmap.h + internal/port.h + internal/scoreonescriptspan.h + internal/stringpiece.h + internal/tote.h + internal/unittest_data.h + internal/utf8acceptinterchange.h + internal/utf8prop_lettermarkscriptnum.h + internal/utf8repl_lettermarklower.h + internal/utf8scannot_lettermarkspecial.h + internal/utf8statetable.h + ) + +install(FILES ${cld2_internal_HEADERS} DESTINATION include/cld2/internal) +set (cld2_public_HEADERS + public/compact_lang_det.h + public/encodings.h + ) +install(FILES ${cld2_public_HEADERS} DESTINATION include/cld2/public) + +set (full_SOURCE_FILES + internal/cld_generated_cjk_uni_prop_80.cc + internal/cld2_generated_cjk_compatible.cc + internal/cld_generated_cjk_delta_bi_32.cc + internal/generated_distinct_bi_0.cc + internal/cld2_generated_quad0122.cc + internal/cld2_generated_deltaocta0122.cc + internal/cld2_generated_distinctocta0122.cc + internal/cld_generated_score_quad_octa_0122.cc + ) + +add_executable(compact_lang_det_test_full ${full_SOURCE_FILES} internal/compact_lang_det_test.cc) +add_executable(cld2_unittest_full ${full_SOURCE_FILES} internal/cld2_unittest_full.cc) +add_executable(cld2_unittest_full_avoid ${full_SOURCE_FILES} internal/cld2_unittest_full.cc) +set_target_properties(cld2_unittest_full_avoid PROPERTIES COMPILE_FLAGS "-Davoid_utf8_string_constants") + +add_executable(cld2_dynamic_data_tool internal/cld2_dynamic_data_extractor.cc internal/cld2_dynamic_data_tool.cc) +add_executable(compact_lang_det_dynamic_test_chrome ${common_SOURCE_FILES} internal/cld2_dynamic_data_extractor.cc internal/compact_lang_det_test.cc) +add_executable(cld2_dynamic_unittest ${common_SOURCE_FILES} internal/cld2_unittest.cc) +set_target_properties(compact_lang_det_dynamic_test_chrome PROPERTIES COMPILE_FLAGS "-DCLD2_DYNAMIC_MODE") +set_target_properties(cld2_dynamic_unittest PROPERTIES COMPILE_FLAGS "-DCLD2_DYNAMIC_MODE") + +add_executable(compact_lang_det_test_chrome_2 internal/compact_lang_det_test.cc) +add_executable(compact_lang_det_test_chrome_16 internal/compact_lang_det_test.cc) +add_executable(cld2_unittest_chrome_2 internal/cld2_unittest.cc) +add_executable(cld2_unittest_avoid_chrome_2 internal/cld2_unittest.cc) +set_target_properties(cld2_unittest_avoid_chrome_2 PROPERTIES COMPILE_FLAGS "-Davoid_utf8_string_constants") + +target_link_libraries(compact_lang_det_test_full cld2) +target_link_libraries(cld2_unittest_full cld2) +target_link_libraries(cld2_unittest_full_avoid cld2) +target_link_libraries(cld2_dynamic_data_tool cld2 cld2_dynamic) +target_link_libraries(compact_lang_det_dynamic_test_chrome cld2_dynamic) +target_link_libraries(cld2_dynamic_unittest cld2_dynamic) +target_link_libraries(compact_lang_det_test_chrome_2 cld2) +target_link_libraries(compact_lang_det_test_chrome_16 cld2) +target_link_libraries(cld2_unittest_chrome_2 cld2) +target_link_libraries(cld2_unittest_avoid_chrome_2 cld2) diff --git a/subprojects/shared-modules/cld2/cld2.json b/subprojects/shared-modules/cld2/cld2.json new file mode 100644 index 00000000..8487e31e --- /dev/null +++ b/subprojects/shared-modules/cld2/cld2.json @@ -0,0 +1,24 @@ +{ + "name": "cld2", + "buildsystem": "simple", + "build-options": { + "cxxflags": "-std=c++98" + }, + "build-commands": [ + "cp CMakeLists.txt ./cld2", + "cd cld2 && mkdir build && cd build && cmake .. -DCMAKE_INSTALL_PREFIX=/app -DCMAKE_BUILD_TYPE=Release", + "cd cld2/build && make && make install" + ], + "sources":[ + { + "type": "git", + "url": "https://github.com/CLD2Owners/cld2.git", + "commit": "84b58a5d7690ebf05a91406f371ce00c3daf31c0", + "dest": "cld2" + }, + { + "type": "file", + "path": "CMakeLists.txt" + } + ] +} diff --git a/subprojects/shared-modules/dbus-glib/dbus-glib-0.110.json b/subprojects/shared-modules/dbus-glib/dbus-glib-0.110.json new file mode 100644 index 00000000..73ffd084 --- /dev/null +++ b/subprojects/shared-modules/dbus-glib/dbus-glib-0.110.json @@ -0,0 +1,23 @@ +{ + "name": "dbus-glib", + "cleanup": [ + "*.la", + "/bin", + "/etc", + "/include", + "/libexec", + "/share/gtk-doc", + "/share/man" + ], + "config-opts": [ + "--disable-static", + "--disable-gtk-doc" + ], + "sources": [ + { + "type": "archive", + "url": "https://dbus.freedesktop.org/releases/dbus-glib/dbus-glib-0.110.tar.gz", + "sha256": "7ce4760cf66c69148f6bd6c92feaabb8812dee30846b24cd0f7395c436d7e825" + } + ] +} diff --git a/subprojects/shared-modules/glew/glew.json b/subprojects/shared-modules/glew/glew.json new file mode 100644 index 00000000..6ec15bf7 --- /dev/null +++ b/subprojects/shared-modules/glew/glew.json @@ -0,0 +1,26 @@ +{ + "name": "glew", + "no-autogen": true, + "make-args": [ + "GLEW_PREFIX=/app", + "GLEW_DEST=/app", + "LIBDIR=/app/lib" + ], + "make-install-args": [ + "GLEW_PREFIX=/app", + "GLEW_DEST=/app", + "LIBDIR=/app/lib" + ], + "sources": [ + { + "type": "archive", + "url": "https://downloads.sourceforge.net/project/glew/glew/2.1.0/glew-2.1.0.tgz", + "sha256": "04de91e7e6763039bc11940095cd9c7f880baba82196a7765f727ac05a993c95" + } + ], + "cleanup": [ + "/include", + "/lib/pkgconfig", + "/lib/*.a" + ] +} diff --git a/subprojects/shared-modules/glu/glu-9.json b/subprojects/shared-modules/glu/glu-9.json new file mode 100644 index 00000000..d14e2219 --- /dev/null +++ b/subprojects/shared-modules/glu/glu-9.json @@ -0,0 +1,12 @@ +{ + "name": "glu", + "config-opts": ["--disable-static"], + "sources": [ + { + "type": "archive", + "url": "https://mesa.freedesktop.org/archive/glu/glu-9.0.1.tar.xz", + "sha256": "fb5a4c2dd6ba6d1c21ab7c05129b0769544e1d68e1e3b0ffecb18e73c93055bc" + } + ], + "cleanup": [ "/include", "/lib/*.a", "/lib/*.la", "/lib/pkgconfig" ] +} diff --git a/subprojects/shared-modules/gtk2/gtk2-use-adwaita-theme.patch b/subprojects/shared-modules/gtk2/gtk2-use-adwaita-theme.patch new file mode 100644 index 00000000..916b3491 --- /dev/null +++ b/subprojects/shared-modules/gtk2/gtk2-use-adwaita-theme.patch @@ -0,0 +1,80 @@ +diff --git a/gdk/x11/gdkevents-x11.c b/gdk/x11/gdkevents-x11.c +index 186a8f5cb2..f5c39b5afe 100644 +--- a/gdk/x11/gdkevents-x11.c ++++ b/gdk/x11/gdkevents-x11.c +@@ -3000,6 +3000,50 @@ check_transform (const gchar *xsettings_name, + return TRUE; + } + ++static gchar * ++gtk_rc_get_theme_dir (void) ++{ ++ const gchar *var; ++ gchar *path; ++ ++ var = g_getenv ("GTK_DATA_PREFIX"); ++ ++ if (var) ++ path = g_build_filename (var, "share", "themes", NULL); ++ else ++ path = g_build_filename ("/usr", "share", "themes", NULL); ++ ++ return path; ++} ++ ++static gboolean ++theme_name_valid (XSettingsSetting *setting) ++{ ++ gboolean res = FALSE; ++ ++ if (setting->type == XSETTINGS_TYPE_STRING) ++ { ++ char *theme_name = setting->data.v_string; ++ gchar *theme_dir = gtk_rc_get_theme_dir (); ++ gchar *path = g_build_filename (theme_dir, theme_name, "gtk-2.0", "gtkrc", NULL); ++ ++ if (g_file_test (path, G_FILE_TEST_EXISTS)) ++ res = TRUE; ++ else if (g_str_has_suffix (theme_name, "-Dark") || ++ g_str_has_suffix (theme_name, "-dark")) ++ { ++ setting->data.v_string = g_strdup ("Adwaita-dark"); ++ g_free (theme_name); ++ res = TRUE; ++ } ++ ++ g_free (theme_dir); ++ g_free (path); ++ } ++ ++ return res; ++} ++ + /** + * gdk_screen_get_setting: + * @screen: the #GdkScreen where the setting is located +@@ -3050,6 +3094,11 @@ gdk_screen_get_setting (GdkScreen *screen, + if (result != XSETTINGS_SUCCESS) + goto out; + ++ if (strcmp (name, "gtk-theme-name") == 0 && ++ (setting->type != XSETTINGS_TYPE_STRING || ++ !theme_name_valid (setting))) ++ goto out; ++ + switch (setting->type) + { + case XSETTINGS_TYPE_INT: +diff --git a/gtk/gtksettings.c b/gtk/gtksettings.c +index 3fbbf00548..5c0a4b33d2 100644 +--- a/gtk/gtksettings.c ++++ b/gtk/gtksettings.c +@@ -312,7 +312,7 @@ gtk_settings_class_init (GtkSettingsClass *class) + #ifdef G_OS_WIN32 + "MS-Windows", + #else +- "Raleigh", ++ "Adwaita", + #endif + GTK_PARAM_READWRITE), + NULL); diff --git a/subprojects/shared-modules/gtk2/gtk2.json b/subprojects/shared-modules/gtk2/gtk2.json new file mode 100644 index 00000000..cb39de7d --- /dev/null +++ b/subprojects/shared-modules/gtk2/gtk2.json @@ -0,0 +1,109 @@ +{ + "name": "gnome-themes-extra", + "rm-configure": true, + "config-opts": [ + "--disable-dependency-tracking", + "--disable-gtk3-engine" + ], + "cleanup": [ + "/share/themes/Adwaita/gtk-3.0", + "/share/themes/Adwaita-dark/gtk-3.0", + "/share/themes/HighContrast/gtk-3.0", + "*.la" + ], + "sources": [ + { + "type": "archive", + "url": "https://download.gnome.org/sources/gnome-themes-extra/3.28/gnome-themes-extra-3.28.tar.xz", + "sha256": "7c4ba0bff001f06d8983cfc105adaac42df1d1267a2591798a780bac557a5819" + }, + { + "type": "shell", + "//": "We want to avoid generating icons as its 99% of the build time and gnome runtime has it", + "commands": [ + "sed -i 's/icons//' themes/HighContrast/Makefile.am" + ] + }, + { + "type": "script", + "commands": [ + "autoreconf -fsi" + ] + } + ], + "modules": [ + "../intltool/intltool-0.51.json", + { + "name": "gtk2", + "cleanup": [ + "/bin", + "/share/gtk-2.0", + "/share/aclocal", + "/share/gtk-doc", + "/lib/pkgconfig", + "/lib/gtk-2.0/include", + "/include", + "*.la" + ], + "x-cpe": { + "product": "gtk+" + }, + "config-opts": [ + "--disable-dependency-tracking", + "--disable-gtk-doc-html", + "--disable-introspection", + "--with-xinput=xfree" + ], + "sources": [ + { + "type": "archive", + "url": "https://download.gnome.org/sources/gtk+/2.24/gtk+-2.24.32.tar.xz", + "sha256": "b6c8a93ddda5eabe3bfee1eb39636c9a03d2a56c7b62828b359bf197943c582e" + }, + { + "type": "patch", + "path": "gtk2-use-adwaita-theme.patch" + } + ] + }, + { + "name": "ibus-gtk2", + "no-make-install": true, + "config-opts": [ + "--disable-xim", + "--disable-dconf", + "--disable-gconf", + "--disable-memconf", + "--disable-schemas-compile", + "--disable-schemas-install", + "--disable-gtk3", + "--disable-setup", + "--disable-ui", + "--disable-engine", + "--disable-python-library", + "--disable-libnotify", + "--disable-emoji-dict", + "--disable-appindicator", + "--disable-glibtest", + "--disable-tests", + "--disable-unicode-dict", + "--disable-introspection", + "--disable-python2" + ], + "ensure-writable": [ + "/lib/gtk-2.0/2.10.0/immodules.cache" + ], + "post-install": [ + "install -m644 --target-directory=${FLATPAK_DEST}/lib/gtk-2.0/2.10.0/immodules client/gtk2/.libs/im-ibus.so", + "gtk-query-immodules-2.0 > ${FLATPAK_DEST}/lib/gtk-2.0/2.10.0/immodules.cache" + ], + "sources": [ + { + "type": "archive", + "url": "https://github.com/ibus/ibus/releases/download/1.5.21/ibus-1.5.21.tar.gz", + "sha256": "adc1e5e620d6a89a49306f022b50561f2c05218dec13d0c9b136dc8b6568a2b9" + } + ] + } + ] +} diff --git a/subprojects/shared-modules/gudev/gudev.json b/subprojects/shared-modules/gudev/gudev.json new file mode 100644 index 00000000..c86a3f91 --- /dev/null +++ b/subprojects/shared-modules/gudev/gudev.json @@ -0,0 +1,27 @@ +{ + "name": "gudev", + "config-opts": [ "--disable-umockdev"], + "cleanup": [ + "/include", + "/etc", + "/libexec", + "/sbin", + "/lib/pkgconfig", + "/lib/systemd", + "/man", + "/share/aclocal", + "/share/doc", + "/share/gtk-doc", + "/share/man", + "/share/pkgconfig", + "*.la", + "*.a" + ], + "sources": [ + { + "type": "archive", + "url": "https://download.gnome.org/sources/libgudev/233/libgudev-233.tar.xz", + "sha256": "587c4970eb23f4e2deee2cb1fb7838c94a78c578f41ce12cac0a3f4a80dabb03" + } + ] +} diff --git a/subprojects/shared-modules/intltool/intltool-0.51.json b/subprojects/shared-modules/intltool/intltool-0.51.json new file mode 100644 index 00000000..3a092241 --- /dev/null +++ b/subprojects/shared-modules/intltool/intltool-0.51.json @@ -0,0 +1,11 @@ +{ + "name": "intltool", + "cleanup": [ "*" ], + "sources": [ + { + "type": "archive", + "url": "https://launchpad.net/intltool/trunk/0.51.0/+download/intltool-0.51.0.tar.gz", + "sha256": "67c74d94196b153b774ab9f89b2fa6c6ba79352407037c8c14d5aeb334e959cd" + } + ] +} diff --git a/subprojects/shared-modules/lame/lame-3.99.5.json b/subprojects/shared-modules/lame/lame-3.99.5.json new file mode 100644 index 00000000..3b431dca --- /dev/null +++ b/subprojects/shared-modules/lame/lame-3.99.5.json @@ -0,0 +1,37 @@ +{ + "name": "lame", + "rm-configure": true, + "config-opts": ["--disable-static"], + "sources": [ + { + "type": "archive", + "url": "https://downloads.sourceforge.net/lame/lame-3.99.5.tar.gz", + "sha256": "24346b4158e4af3bd9f2e194bb23eb473c75fb7377011523353196b19b9a23ff" + }, + { + "type": "patch", + "path": "lame-msse.patch" + }, + { + "type": "patch", + "path": "lame-gtk1-ac-directives.patch" + }, + { + "type": "patch", + "path": "lame-ansi2knr2devnull.patch" + }, + { + "type": "patch", + "path": "lame-tinfo.patch", + "strip-components": 0 + }, + { + "type": "script", + "dest-filename": "autogen.sh", + "commands": [ + "autoreconf -vfi" + ] + } + ], + "cleanup": ["/bin", "/include", "/share/doc", "/share/man", "*.la"] +} diff --git a/subprojects/shared-modules/lame/lame-ansi2knr2devnull.patch b/subprojects/shared-modules/lame/lame-ansi2knr2devnull.patch new file mode 100644 index 00000000..c427345e --- /dev/null +++ b/subprojects/shared-modules/lame/lame-ansi2knr2devnull.patch @@ -0,0 +1,43 @@ +Description: Patch out remaining ansi2knr. +Author: Dimitri John Ledkov <xnox@ubuntu.com> +Bug-Debian: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=755111 +--- a/configure.in ++++ b/configure.in +@@ -78,7 +78,6 @@ + fi + + dnl more automake stuff +-AM_C_PROTOTYPES + + AC_CHECK_HEADER(dmalloc.h) + if test "${ac_cv_header_dmalloc_h}" = "yes"; then +--- a/doc/man/Makefile.am ++++ b/doc/man/Makefile.am +@@ -1,6 +1,6 @@ + ## $Id: Makefile.am,v 1.1 2000/10/22 11:39:44 aleidinger Exp $ + +-AUTOMAKE_OPTIONS = foreign ansi2knr ++AUTOMAKE_OPTIONS = foreign + + man_MANS = lame.1 + EXTRA_DIST = ${man_MANS} +--- a/libmp3lame/i386/Makefile.am ++++ b/libmp3lame/i386/Makefile.am +@@ -1,6 +1,6 @@ + ## $Id: Makefile.am,v 1.26 2011/04/04 09:42:34 aleidinger Exp $ + +-AUTOMAKE_OPTIONS = foreign $(top_srcdir)/ansi2knr ++AUTOMAKE_OPTIONS = foreign + + DEFS = @DEFS@ @CONFIG_DEFS@ + +--- a/doc/html/Makefile.am ++++ b/doc/html/Makefile.am +@@ -1,6 +1,6 @@ + ## $Id: Makefile.am,v 1.7 2010/09/30 20:58:40 jaz001 Exp $ + +-AUTOMAKE_OPTIONS = foreign ansi2knr ++AUTOMAKE_OPTIONS = foreign + + docdir = $(datadir)/doc + pkgdocdir = $(docdir)/$(PACKAGE) diff --git a/subprojects/shared-modules/lame/lame-gtk1-ac-directives.patch b/subprojects/shared-modules/lame/lame-gtk1-ac-directives.patch new file mode 100644 index 00000000..7e0d3fe4 --- /dev/null +++ b/subprojects/shared-modules/lame/lame-gtk1-ac-directives.patch @@ -0,0 +1,205 @@ +Description: Include GTK-1 autoconf directives in build system. +Origin: http://anonscm.debian.org/gitweb/?p=pkg-multimedia/lame.git;a=tree;f=debian/patches +Forwarded: yes +Applied-Upstream: http://lame.cvs.sf.net/viewvc/lame/lame/acinclude.m4?revision=1.6 + +--- a/acinclude.m4 ++++ b/acinclude.m4 +@@ -85,4 +85,197 @@ + [AC_MSG_WARN(can't check for IEEE854 compliant 80 bit floats)] + )])]) # alex_IEEE854_FLOAT80 + ++# Configure paths for GTK+ ++# Owen Taylor 97-11-3 + ++dnl AM_PATH_GTK([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND [, MODULES]]]]) ++dnl Test for GTK, and define GTK_CFLAGS and GTK_LIBS ++dnl ++AC_DEFUN([AM_PATH_GTK], ++[dnl ++dnl Get the cflags and libraries from the gtk-config script ++dnl ++AC_ARG_WITH(gtk-prefix,[ --with-gtk-prefix=PFX Prefix where GTK is installed (optional)], ++ gtk_config_prefix="$withval", gtk_config_prefix="") ++AC_ARG_WITH(gtk-exec-prefix,[ --with-gtk-exec-prefix=PFX Exec prefix where GTK is installed (optional)], ++ gtk_config_exec_prefix="$withval", gtk_config_exec_prefix="") ++AC_ARG_ENABLE(gtktest, [ --disable-gtktest Do not try to compile and run a test GTK program], ++ , enable_gtktest=yes) ++ ++ for module in . $4 ++ do ++ case "$module" in ++ gthread) ++ gtk_config_args="$gtk_config_args gthread" ++ ;; ++ esac ++ done ++ ++ if test x$gtk_config_exec_prefix != x ; then ++ gtk_config_args="$gtk_config_args --exec-prefix=$gtk_config_exec_prefix" ++ if test x${GTK_CONFIG+set} != xset ; then ++ GTK_CONFIG=$gtk_config_exec_prefix/bin/gtk-config ++ fi ++ fi ++ if test x$gtk_config_prefix != x ; then ++ gtk_config_args="$gtk_config_args --prefix=$gtk_config_prefix" ++ if test x${GTK_CONFIG+set} != xset ; then ++ GTK_CONFIG=$gtk_config_prefix/bin/gtk-config ++ fi ++ fi ++ ++ AC_PATH_PROG(GTK_CONFIG, gtk-config, no) ++ min_gtk_version=ifelse([$1], ,0.99.7,$1) ++ AC_MSG_CHECKING(for GTK - version >= $min_gtk_version) ++ no_gtk="" ++ if test "$GTK_CONFIG" = "no" ; then ++ no_gtk=yes ++ else ++ GTK_CFLAGS=`$GTK_CONFIG $gtk_config_args --cflags` ++ GTK_LIBS=`$GTK_CONFIG $gtk_config_args --libs` ++ gtk_config_major_version=`$GTK_CONFIG $gtk_config_args --version | \ ++ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'` ++ gtk_config_minor_version=`$GTK_CONFIG $gtk_config_args --version | \ ++ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'` ++ gtk_config_micro_version=`$GTK_CONFIG $gtk_config_args --version | \ ++ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'` ++ if test "x$enable_gtktest" = "xyes" ; then ++ ac_save_CFLAGS="$CFLAGS" ++ ac_save_LIBS="$LIBS" ++ CFLAGS="$CFLAGS $GTK_CFLAGS" ++ LIBS="$GTK_LIBS $LIBS" ++dnl ++dnl Now check if the installed GTK is sufficiently new. (Also sanity ++dnl checks the results of gtk-config to some extent ++dnl ++ rm -f conf.gtktest ++ AC_TRY_RUN([ ++#include <gtk/gtk.h> ++#include <stdio.h> ++#include <stdlib.h> ++ ++int ++main () ++{ ++ int major, minor, micro; ++ char *tmp_version; ++ ++ system ("touch conf.gtktest"); ++ ++ /* HP/UX 9 (%@#!) writes to sscanf strings */ ++ tmp_version = g_strdup("$min_gtk_version"); ++ if (sscanf(tmp_version, "%d.%d.%d", &major, &minor, µ) != 3) { ++ printf("%s, bad version string\n", "$min_gtk_version"); ++ exit(1); ++ } ++ ++ if ((gtk_major_version != $gtk_config_major_version) || ++ (gtk_minor_version != $gtk_config_minor_version) || ++ (gtk_micro_version != $gtk_config_micro_version)) ++ { ++ printf("\n*** 'gtk-config --version' returned %d.%d.%d, but GTK+ (%d.%d.%d)\n", ++ $gtk_config_major_version, $gtk_config_minor_version, $gtk_config_micro_version, ++ gtk_major_version, gtk_minor_version, gtk_micro_version); ++ printf ("*** was found! If gtk-config was correct, then it is best\n"); ++ printf ("*** to remove the old version of GTK+. You may also be able to fix the error\n"); ++ printf("*** by modifying your LD_LIBRARY_PATH enviroment variable, or by editing\n"); ++ printf("*** /etc/ld.so.conf. Make sure you have run ldconfig if that is\n"); ++ printf("*** required on your system.\n"); ++ printf("*** If gtk-config was wrong, set the environment variable GTK_CONFIG\n"); ++ printf("*** to point to the correct copy of gtk-config, and remove the file config.cache\n"); ++ printf("*** before re-running configure\n"); ++ } ++#if defined (GTK_MAJOR_VERSION) && defined (GTK_MINOR_VERSION) && defined (GTK_MICRO_VERSION) ++ else if ((gtk_major_version != GTK_MAJOR_VERSION) || ++ (gtk_minor_version != GTK_MINOR_VERSION) || ++ (gtk_micro_version != GTK_MICRO_VERSION)) ++ { ++ printf("*** GTK+ header files (version %d.%d.%d) do not match\n", ++ GTK_MAJOR_VERSION, GTK_MINOR_VERSION, GTK_MICRO_VERSION); ++ printf("*** library (version %d.%d.%d)\n", ++ gtk_major_version, gtk_minor_version, gtk_micro_version); ++ } ++#endif /* defined (GTK_MAJOR_VERSION) ... */ ++ else ++ { ++ if ((gtk_major_version > major) || ++ ((gtk_major_version == major) && (gtk_minor_version > minor)) || ++ ((gtk_major_version == major) && (gtk_minor_version == minor) && (gtk_micro_version >= micro))) ++ { ++ return 0; ++ } ++ else ++ { ++ printf("\n*** An old version of GTK+ (%d.%d.%d) was found.\n", ++ gtk_major_version, gtk_minor_version, gtk_micro_version); ++ printf("*** You need a version of GTK+ newer than %d.%d.%d. The latest version of\n", ++ major, minor, micro); ++ printf("*** GTK+ is always available from ftp://ftp.gtk.org.\n"); ++ printf("***\n"); ++ printf("*** If you have already installed a sufficiently new version, this error\n"); ++ printf("*** probably means that the wrong copy of the gtk-config shell script is\n"); ++ printf("*** being found. The easiest way to fix this is to remove the old version\n"); ++ printf("*** of GTK+, but you can also set the GTK_CONFIG environment to point to the\n"); ++ printf("*** correct copy of gtk-config. (In this case, you will have to\n"); ++ printf("*** modify your LD_LIBRARY_PATH enviroment variable, or edit /etc/ld.so.conf\n"); ++ printf("*** so that the correct libraries are found at run-time))\n"); ++ } ++ } ++ return 1; ++} ++],, no_gtk=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"]) ++ CFLAGS="$ac_save_CFLAGS" ++ LIBS="$ac_save_LIBS" ++ fi ++ fi ++ if test "x$no_gtk" = x ; then ++ AC_MSG_RESULT(yes) ++ ifelse([$2], , :, [$2]) ++ else ++ AC_MSG_RESULT(no) ++ if test "$GTK_CONFIG" = "no" ; then ++ echo "*** The gtk-config script installed by GTK could not be found" ++ echo "*** If GTK was installed in PREFIX, make sure PREFIX/bin is in" ++ echo "*** your path, or set the GTK_CONFIG environment variable to the" ++ echo "*** full path to gtk-config." ++ else ++ if test -f conf.gtktest ; then ++ : ++ else ++ echo "*** Could not run GTK test program, checking why..." ++ CFLAGS="$CFLAGS $GTK_CFLAGS" ++ LIBS="$LIBS $GTK_LIBS" ++ AC_TRY_LINK([ ++#include <gtk/gtk.h> ++#include <stdio.h> ++], [ return ((gtk_major_version) || (gtk_minor_version) || (gtk_micro_version)); ], ++ [ echo "*** The test program compiled, but did not run. This usually means" ++ echo "*** that the run-time linker is not finding GTK or finding the wrong" ++ echo "*** version of GTK. If it is not finding GTK, you'll need to set your" ++ echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point" ++ echo "*** to the installed location Also, make sure you have run ldconfig if that" ++ echo "*** is required on your system" ++ echo "***" ++ echo "*** If you have an old version installed, it is best to remove it, although" ++ echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH" ++ echo "***" ++ echo "*** If you have a RedHat 5.0 system, you should remove the GTK package that" ++ echo "*** came with the system with the command" ++ echo "***" ++ echo "*** rpm --erase --nodeps gtk gtk-devel" ], ++ [ echo "*** The test program failed to compile or link. See the file config.log for the" ++ echo "*** exact error that occured. This usually means GTK was incorrectly installed" ++ echo "*** or that you have moved GTK since it was installed. In the latter case, you" ++ echo "*** may want to edit the gtk-config script: $GTK_CONFIG" ]) ++ CFLAGS="$ac_save_CFLAGS" ++ LIBS="$ac_save_LIBS" ++ fi ++ fi ++ GTK_CFLAGS="" ++ GTK_LIBS="" ++ ifelse([$3], , :, [$3]) ++ fi ++ AC_SUBST(GTK_CFLAGS) ++ AC_SUBST(GTK_LIBS) ++ rm -f conf.gtktest ++]) diff --git a/subprojects/shared-modules/lame/lame-msse.patch b/subprojects/shared-modules/lame/lame-msse.patch new file mode 100644 index 00000000..4b71a2ed --- /dev/null +++ b/subprojects/shared-modules/lame/lame-msse.patch @@ -0,0 +1,17 @@ +Description: Build xmm_quantize_sub.c with -msse +Author: Sebastian Ramacher <sramacher@debian.org> +Bug: http://sourceforge.net/p/lame/bugs/443/ +Bug-Debian: https://bugs.debian.org/760047 +Forwarded: http://sourceforge.net/p/lame/bugs/443/ +Last-Update: 2014-08-31 + +--- lame-3.99.5+repack1.orig/libmp3lame/vector/Makefile.am ++++ lame-3.99.5+repack1/libmp3lame/vector/Makefile.am +@@ -20,6 +20,7 @@ xmm_sources = xmm_quantize_sub.c + + if WITH_XMM + liblamevectorroutines_la_SOURCES = $(xmm_sources) ++liblamevectorroutines_la_CFLAGS = -msse + endif + + noinst_HEADERS = lame_intrin.h diff --git a/subprojects/shared-modules/lame/lame-tinfo.patch b/subprojects/shared-modules/lame/lame-tinfo.patch new file mode 100644 index 00000000..cb570e78 --- /dev/null +++ b/subprojects/shared-modules/lame/lame-tinfo.patch @@ -0,0 +1,23 @@ +initscr is not used anywhere in lame sourcetree, check for used tgetent instead +check for separate tinfo library optionally built out from libncurses source tree, +like used in debian and gentoo +- ssuominen@g.o + +http://bugs.gentoo.org/454322 + +--- configure.in ++++ configure.in +@@ -372,9 +372,10 @@ + + AC_CHECK_HEADERS(termcap.h) + AC_CHECK_HEADERS(ncurses/termcap.h) +-AC_CHECK_LIB(termcap, initscr, HAVE_TERMCAP="termcap") +-AC_CHECK_LIB(curses, initscr, HAVE_TERMCAP="curses") +-AC_CHECK_LIB(ncurses, initscr, HAVE_TERMCAP="ncurses") ++AC_CHECK_LIB(termcap, tgetent, HAVE_TERMCAP="termcap") ++AC_CHECK_LIB(curses, tgetent, HAVE_TERMCAP="curses") ++AC_CHECK_LIB(ncurses, tgetent, HAVE_TERMCAP="ncurses") ++AC_CHECK_LIB(tinfo, tgetent, HAVE_TERMCAP="tinfo") + + AM_ICONV + diff --git a/subprojects/shared-modules/libappindicator/Makefile b/subprojects/shared-modules/libappindicator/Makefile new file mode 100644 index 00000000..58192455 --- /dev/null +++ b/subprojects/shared-modules/libappindicator/Makefile @@ -0,0 +1,10 @@ +all: libappindicator-gtk3-introspection-12.10.json libappindicator-gtk3-12.10.json libappindicator-gtk2-12.10.json + +libappindicator-gtk3-introspection-12.10.json: libappindicator.json.in + sed -e 's/@GTK_VER@/3/g' -e 's/@INTROSPECTION@/yes/g' $< > $@ + +libappindicator-gtk3-12.10.json: libappindicator.json.in + sed -e 's/@GTK_VER@/3/g' -e 's/@INTROSPECTION@/no/g' $< > $@ + +libappindicator-gtk2-12.10.json: libappindicator.json.in + sed -e 's/@GTK_VER@/2/g' -e 's/@INTROSPECTION@/no/g' $< > $@
\ No newline at end of file diff --git a/subprojects/shared-modules/libappindicator/libappindicator-ftbfs.patch b/subprojects/shared-modules/libappindicator/libappindicator-ftbfs.patch new file mode 100644 index 00000000..93d31af6 --- /dev/null +++ b/subprojects/shared-modules/libappindicator/libappindicator-ftbfs.patch @@ -0,0 +1,20 @@ +From: Olivier Tilloy <olivier.tilloy@canonical.com> +Date: Tue 2018-03-20 12:47:56 +0000 +Subject: [PATCH] libappindicator FTBFS on bionic + +Fix build failures on bionic, +and update Vcs-* fields in debian/control. (LP: #1757121) + +Approved by: Marco Trevisan (Treviño) +--- +--- libappindicator-12.10.0/src/app-indicator.c 2017-02-15 14:10:41 +0000 ++++ libappindicator-12.10.0/src/app-indicator.c 2018-03-20 12:38:59 +0000 +@@ -2196,7 +2196,7 @@ app_indicator_set_secondary_activate_tar + + g_return_if_fail (GTK_IS_WIDGET (menuitem)); + +- priv->sec_activate_target = g_object_ref(G_OBJECT(menuitem)); ++ priv->sec_activate_target = g_object_ref(menuitem); + priv->sec_activate_enabled = widget_is_menu_child(self, menuitem); + g_signal_connect(menuitem, "parent-set", G_CALLBACK(sec_activate_target_parent_changed), self); + } diff --git a/subprojects/shared-modules/libappindicator/libappindicator-gtk2-12.10.json b/subprojects/shared-modules/libappindicator/libappindicator-gtk2-12.10.json new file mode 100644 index 00000000..b65cfa3f --- /dev/null +++ b/subprojects/shared-modules/libappindicator/libappindicator-gtk2-12.10.json @@ -0,0 +1,121 @@ +{ + "name": "libappindicator", + "build-options": { + "cflags": "-Wno-error" + }, + "rm-configure": true, + "config-opts": [ + "--disable-static", + "--disable-gtk-doc", + "--disable-tests", + "--disable-mono-tests", + "--enable-introspection=no", + "--with-gtk=2" + ], + "cleanup": [ + "/include", + "/lib/pkgconfig", + "/lib/*.la", + "/share/gtk-doc", + "/share/gir-1.0" + ], + "sources": [ + { + "type": "archive", + "url": "https://launchpad.net/libappindicator/12.10/12.10.0/+download/libappindicator-12.10.0.tar.gz", + "sha256": "d5907c1f98084acf28fd19593cb70672caa0ca1cf82d747ba6f4830d4cc3b49f" + }, + { + "type": "patch", + "path": "libappindicator-ftbfs.patch" + }, + { + "type": "patch", + "path": "libappindicator-no-python.patch" + }, + { + "type": "script", + "commands": ["autoreconf -sfi"], + "dest-filename": "autogen.sh" + } + ], + "modules": [ + "../intltool/intltool-0.51.json", + "../dbus-glib/dbus-glib-0.110.json", + { + "name": "libdbusmenu", + "build-options": { + "cflags": "-Wno-error", + "env": { + "HAVE_VALGRIND_FALSE": "#", + "HAVE_VALGRIND_TRUE": "" + } + }, + "cleanup": [ + "/include", + "/libexec", + "/lib/pkgconfig", + "/lib/*.la", + "/share/doc", + "/share/libdbusmenu", + "/share/gtk-doc", + "/share/gir-1.0" + ], + "config-opts": [ + "--disable-static", + "--disable-gtk-doc", + "--enable-introspection=no", + "--disable-vala", + "--disable-dumper", + "--disable-tests", + "--with-gtk=2" + ], + "sources": [ + { + "type": "archive", + "url": "https://launchpad.net/libdbusmenu/16.04/16.04.0/+download/libdbusmenu-16.04.0.tar.gz", + "sha256": "b9cc4a2acd74509435892823607d966d424bd9ad5d0b00938f27240a1bfa878a" + } + ] + }, + { + "name": "libindicator", + "build-options": { + "cflags": "-Wno-error" + }, + "cleanup": [ + "/include", + "/libexec", + "/lib/pkgconfig", + "/lib/*.la", + "/share/libindicator", + "/share/gtk-doc", + "/share/gir-1.0" + ], + "config-opts": [ + "--disable-static", + "--disable-tests", + "--with-gtk=2" + ], + "sources": [ + { + "type": "archive", + "url": "https://launchpad.net/libindicator/12.10/12.10.1/+download/libindicator-12.10.1.tar.gz", + "sha256": "b2d2e44c10313d5c9cd60db455d520f80b36dc39562df079a3f29495e8f9447f" + }, + { + "type": "shell", + "commands": [ + "# FTBFS fix", + "sed -e '/LIBINDICATOR_LIBS/ s/\\$LIBM/ $LIBM/' -i configure.ac" + ] + }, + { + "type": "script", + "commands": ["autoreconf -sfi"], + "dest-filename": "autogen.sh" + } + ] + } + ] +} diff --git a/subprojects/shared-modules/libappindicator/libappindicator-gtk3-12.10.json b/subprojects/shared-modules/libappindicator/libappindicator-gtk3-12.10.json new file mode 100644 index 00000000..46e6f438 --- /dev/null +++ b/subprojects/shared-modules/libappindicator/libappindicator-gtk3-12.10.json @@ -0,0 +1,121 @@ +{ + "name": "libappindicator", + "build-options": { + "cflags": "-Wno-error" + }, + "rm-configure": true, + "config-opts": [ + "--disable-static", + "--disable-gtk-doc", + "--disable-tests", + "--disable-mono-tests", + "--enable-introspection=no", + "--with-gtk=3" + ], + "cleanup": [ + "/include", + "/lib/pkgconfig", + "/lib/*.la", + "/share/gtk-doc", + "/share/gir-1.0" + ], + "sources": [ + { + "type": "archive", + "url": "https://launchpad.net/libappindicator/12.10/12.10.0/+download/libappindicator-12.10.0.tar.gz", + "sha256": "d5907c1f98084acf28fd19593cb70672caa0ca1cf82d747ba6f4830d4cc3b49f" + }, + { + "type": "patch", + "path": "libappindicator-ftbfs.patch" + }, + { + "type": "patch", + "path": "libappindicator-no-python.patch" + }, + { + "type": "script", + "commands": ["autoreconf -sfi"], + "dest-filename": "autogen.sh" + } + ], + "modules": [ + "../intltool/intltool-0.51.json", + "../dbus-glib/dbus-glib-0.110.json", + { + "name": "libdbusmenu", + "build-options": { + "cflags": "-Wno-error", + "env": { + "HAVE_VALGRIND_FALSE": "#", + "HAVE_VALGRIND_TRUE": "" + } + }, + "cleanup": [ + "/include", + "/libexec", + "/lib/pkgconfig", + "/lib/*.la", + "/share/doc", + "/share/libdbusmenu", + "/share/gtk-doc", + "/share/gir-1.0" + ], + "config-opts": [ + "--disable-static", + "--disable-gtk-doc", + "--enable-introspection=no", + "--disable-vala", + "--disable-dumper", + "--disable-tests", + "--with-gtk=3" + ], + "sources": [ + { + "type": "archive", + "url": "https://launchpad.net/libdbusmenu/16.04/16.04.0/+download/libdbusmenu-16.04.0.tar.gz", + "sha256": "b9cc4a2acd74509435892823607d966d424bd9ad5d0b00938f27240a1bfa878a" + } + ] + }, + { + "name": "libindicator", + "build-options": { + "cflags": "-Wno-error" + }, + "cleanup": [ + "/include", + "/libexec", + "/lib/pkgconfig", + "/lib/*.la", + "/share/libindicator", + "/share/gtk-doc", + "/share/gir-1.0" + ], + "config-opts": [ + "--disable-static", + "--disable-tests", + "--with-gtk=3" + ], + "sources": [ + { + "type": "archive", + "url": "https://launchpad.net/libindicator/12.10/12.10.1/+download/libindicator-12.10.1.tar.gz", + "sha256": "b2d2e44c10313d5c9cd60db455d520f80b36dc39562df079a3f29495e8f9447f" + }, + { + "type": "shell", + "commands": [ + "# FTBFS fix", + "sed -e '/LIBINDICATOR_LIBS/ s/\\$LIBM/ $LIBM/' -i configure.ac" + ] + }, + { + "type": "script", + "commands": ["autoreconf -sfi"], + "dest-filename": "autogen.sh" + } + ] + } + ] +} diff --git a/subprojects/shared-modules/libappindicator/libappindicator-gtk3-introspection-12.10.json b/subprojects/shared-modules/libappindicator/libappindicator-gtk3-introspection-12.10.json new file mode 100644 index 00000000..5df82527 --- /dev/null +++ b/subprojects/shared-modules/libappindicator/libappindicator-gtk3-introspection-12.10.json @@ -0,0 +1,121 @@ +{ + "name": "libappindicator", + "build-options": { + "cflags": "-Wno-error" + }, + "rm-configure": true, + "config-opts": [ + "--disable-static", + "--disable-gtk-doc", + "--disable-tests", + "--disable-mono-tests", + "--enable-introspection=yes", + "--with-gtk=3" + ], + "cleanup": [ + "/include", + "/lib/pkgconfig", + "/lib/*.la", + "/share/gtk-doc", + "/share/gir-1.0" + ], + "sources": [ + { + "type": "archive", + "url": "https://launchpad.net/libappindicator/12.10/12.10.0/+download/libappindicator-12.10.0.tar.gz", + "sha256": "d5907c1f98084acf28fd19593cb70672caa0ca1cf82d747ba6f4830d4cc3b49f" + }, + { + "type": "patch", + "path": "libappindicator-ftbfs.patch" + }, + { + "type": "patch", + "path": "libappindicator-no-python.patch" + }, + { + "type": "script", + "commands": ["autoreconf -sfi"], + "dest-filename": "autogen.sh" + } + ], + "modules": [ + "../intltool/intltool-0.51.json", + "../dbus-glib/dbus-glib-0.110.json", + { + "name": "libdbusmenu", + "build-options": { + "cflags": "-Wno-error", + "env": { + "HAVE_VALGRIND_FALSE": "#", + "HAVE_VALGRIND_TRUE": "" + } + }, + "cleanup": [ + "/include", + "/libexec", + "/lib/pkgconfig", + "/lib/*.la", + "/share/doc", + "/share/libdbusmenu", + "/share/gtk-doc", + "/share/gir-1.0" + ], + "config-opts": [ + "--disable-static", + "--disable-gtk-doc", + "--enable-introspection=yes", + "--disable-vala", + "--disable-dumper", + "--disable-tests", + "--with-gtk=3" + ], + "sources": [ + { + "type": "archive", + "url": "https://launchpad.net/libdbusmenu/16.04/16.04.0/+download/libdbusmenu-16.04.0.tar.gz", + "sha256": "b9cc4a2acd74509435892823607d966d424bd9ad5d0b00938f27240a1bfa878a" + } + ] + }, + { + "name": "libindicator", + "build-options": { + "cflags": "-Wno-error" + }, + "cleanup": [ + "/include", + "/libexec", + "/lib/pkgconfig", + "/lib/*.la", + "/share/libindicator", + "/share/gtk-doc", + "/share/gir-1.0" + ], + "config-opts": [ + "--disable-static", + "--disable-tests", + "--with-gtk=3" + ], + "sources": [ + { + "type": "archive", + "url": "https://launchpad.net/libindicator/12.10/12.10.1/+download/libindicator-12.10.1.tar.gz", + "sha256": "b2d2e44c10313d5c9cd60db455d520f80b36dc39562df079a3f29495e8f9447f" + }, + { + "type": "shell", + "commands": [ + "# FTBFS fix", + "sed -e '/LIBINDICATOR_LIBS/ s/\\$LIBM/ $LIBM/' -i configure.ac" + ] + }, + { + "type": "script", + "commands": ["autoreconf -sfi"], + "dest-filename": "autogen.sh" + } + ] + } + ] +} diff --git a/subprojects/shared-modules/libappindicator/libappindicator-no-python.patch b/subprojects/shared-modules/libappindicator/libappindicator-no-python.patch new file mode 100644 index 00000000..587cddec --- /dev/null +++ b/subprojects/shared-modules/libappindicator/libappindicator-no-python.patch @@ -0,0 +1,888 @@ +diff --git a/bindings/Makefile.am b/bindings/Makefile.am +index d1f6d73..dccca6c 100644 +--- a/bindings/Makefile.am ++++ b/bindings/Makefile.am +@@ -3,7 +3,6 @@ SUBDIRS = \ + vala + else + SUBDIRS = \ +- python \ + vala + endif + +diff --git a/bindings/python/Makefile.am b/bindings/python/Makefile.am +deleted file mode 100644 +index fe95c02..0000000 +--- a/bindings/python/Makefile.am ++++ /dev/null +@@ -1,39 +0,0 @@ +-defsdir = $(datadir)/pygtk/2.0/defs +-defs_DATA = appindicator.defs +- +-#CFLAGS = -Wall -Werror +-INCLUDES = \ +- -I$(top_srcdir)/src \ +- -DG_LOG_DOMAIN=\"appindicator-python\" \ +- -DDATADIR=\"$(datadir)\" \ +- -DLIBDIR=\"$(libdir)\" \ +- $(APPINDICATOR_PYTHON_CFLAGS) \ +- $(PYTHON_INCLUDES) +- +-pkgpythondir = $(pyexecdir) +-pkgpyexecdir = $(pyexecdir) +- +-pkgappindicatordir = $(pkgpythondir)/appindicator +-pkgappindicator_PYTHON = __init__.py +- +-appindicatordir = $(pkgpyexecdir)/appindicator +-appindicator_LTLIBRARIES = _appindicator.la +- +-_appindicator_la_LDFLAGS = -module -avoid-version -export-symbols-regex init_appindicator +-_appindicator_la_LIBADD = $(APPINDICATOR_PYTHON_LIBS) -L$(top_builddir)/src/.libs -lappindicator +-_appindicator_la_SOURCES = appindicatormodule.c +-nodist__appindicator_la_SOURCES = appindicator.c +- +-CLEANFILES = appindicator.c +-EXTRA_DIST = appindicator.override.in appindicator-arg-types.py $(defs_DATA) +-appindicator.c: $(defs_DATA) appindicator.override +- +-%.c: %.defs +- ($(PYGTK_CODEGEN) \ +- --register $(PYGTK_DEFSDIR)/gtk-types.defs \ +- --register $(PYGTK_DEFSDIR)/gdk-types.defs \ +- --load-types $(srcdir)/appindicator-arg-types.py \ +- --override $*.override \ +- --prefix py$* $(srcdir)/$*.defs) > gen-$*.c \ +- && cp gen-$*.c $*.c \ +- && rm -f gen-$*.c +diff --git a/bindings/python/__init__.py b/bindings/python/__init__.py +deleted file mode 100644 +index 20e2140..0000000 +--- a/bindings/python/__init__.py ++++ /dev/null +@@ -1,27 +0,0 @@ +-# Python bindings for libappindicator. +-# +-# Copyright 2009 Canonical Ltd. +-# +-# Authors: +-# Eitan Isaacson <eitan@ascender.com> +-# Neil Jagdish Patel <neil.patel@canonical.com> +-# +-# This program is free software: you can redistribute it and/or modify it +-# under the terms of either or both of the following licenses: +-# +-# 1) the GNU Lesser General Public License version 3, as published by the +-# Free Software Foundation; and/or +-# 2) the GNU Lesser General Public License version 2.1, as published by +-# the Free Software Foundation. +-# +-# This program is distributed in the hope that it will be useful, but +-# WITHOUT ANY WARRANTY; without even the implied warranties of +-# MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR +-# PURPOSE. See the applicable version of the GNU Lesser General Public +-# License for more details. +-# +-# You should have received a copy of both the GNU Lesser General Public +-# License version 3 and version 2.1 along with this program. If not, see +-# <http://www.gnu.org/licenses/> +- +-from _appindicator import * +diff --git a/bindings/python/appindicator-arg-types.py b/bindings/python/appindicator-arg-types.py +deleted file mode 100644 +index 9d74aa0..0000000 +--- a/bindings/python/appindicator-arg-types.py ++++ /dev/null +@@ -1,27 +0,0 @@ +-# Python bindings for libappindicator. +-# +-# Copyright 2009 Canonical Ltd. +-# +-# Authors: +-# Eitan Isaacson <eitan@ascender.com> +-# +-# This program is free software: you can redistribute it and/or modify it +-# under the terms of either or both of the following licenses: +-# +-# 1) the GNU Lesser General Public License version 3, as published by the +-# Free Software Foundation; and/or +-# 2) the GNU Lesser General Public License version 2.1, as published by +-# the Free Software Foundation. +-# +-# This program is distributed in the hope that it will be useful, but +-# WITHOUT ANY WARRANTY; without even the implied warranties of +-# MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR +-# PURPOSE. See the applicable version of the GNU Lesser General Public +-# License for more details. +-# +-# You should have received a copy of both the GNU Lesser General Public +-# License version 3 and version 2.1 along with this program. If not, see +-# <http://www.gnu.org/licenses/> +- +-import argtypes +- +diff --git a/bindings/python/appindicator.defs b/bindings/python/appindicator.defs +deleted file mode 100644 +index 4fcc2d5..0000000 +--- a/bindings/python/appindicator.defs ++++ /dev/null +@@ -1,200 +0,0 @@ +-;; -*- scheme -*- +-; object definitions ... +-(define-object Indicator +- (in-module "App") +- (parent "GObject") +- (c-name "AppIndicator") +- (gtype-id "APP_TYPE_INDICATOR") +-) +- +-;; Enumerations and flags ... +- +-(define-enum IndicatorCategory +- (in-module "App") +- (c-name "AppIndicatorCategory") +- (gtype-id "APP_INDICATOR_TYPE_INDICATOR_CATEGORY") +- (values +- '("ApplicationStatus" "APP_INDICATOR_CATEGORY_APPLICATION_STATUS") +- '("Communications" "APP_INDICATOR_CATEGORY_COMMUNICATIONS") +- '("SystemServices" "APP_INDICATOR_CATEGORY_SYSTEM_SERVICES") +- '("Hardware" "APP_INDICATOR_CATEGORY_HARDWARE") +- '("Other" "APP_INDICATOR_CATEGORY_OTHER") +- ) +-) +- +-(define-enum IndicatorStatus +- (in-module "App") +- (c-name "AppIndicatorStatus") +- (gtype-id "APP_INDICATOR_TYPE_INDICATOR_STATUS") +- (values +- '("Passive" "APP_INDICATOR_STATUS_PASSIVE") +- '("Active" "APP_INDICATOR_STATUS_ACTIVE") +- '("NeedsAttention" "APP_INDICATOR_STATUS_ATTENTION") +- ) +-) +- +-;; From app-indicator.h +- +-(define-function app_indicator_get_type +- (c-name "app_indicator_get_type") +- (return-type "GType") +-) +- +-(define-function app_indicator_new_with_path +- (c-name "app_indicator_new_with_path") +- (is-constructor-of "AppIndicator") +- (return-type "AppIndicator*") +- (parameters +- '("const-gchar*" "id") +- '("const-gchar*" "icon_name") +- '("AppIndicatorCategory" "category") +- '("const-gchar*" "icon_theme_path" (null-ok) (default "NULL")) +- ) +-) +- +-(define-method set_status +- (of-object "AppIndicator") +- (c-name "app_indicator_set_status") +- (return-type "none") +- (parameters +- '("AppIndicatorStatus" "status") +- ) +-) +- +-(define-method set_attention_icon +- (of-object "AppIndicator") +- (c-name "app_indicator_set_attention_icon_full") +- (return-type "none") +- (parameters +- '("const-gchar*" "icon_name") +- '("const-gchar*" "icon_desc" (null-ok) (default "NULL")) +- ) +-) +- +-(define-method set_menu +- (of-object "AppIndicator") +- (c-name "app_indicator_set_menu") +- (return-type "none") +- (parameters +- '("GtkMenu*" "menu") +- ) +-) +- +-(define-method set_icon +- (of-object "AppIndicator") +- (c-name "app_indicator_set_icon_full") +- (return-type "none") +- (parameters +- '("const-gchar*" "icon_name") +- '("const-gchar*" "icon_desc" (null-ok) (default "NULL")) +- ) +-) +- +-(define-method set_label +- (of-object "AppIndicator") +- (c-name "app_indicator_set_label") +- (return-type "none") +- (parameters +- '("const-gchar*" "label" (null-ok)) +- '("const-gchar*" "guide" (null-ok) (default "NULL")) +- ) +-) +- +-(define-method set_ordering_index +- (of-object "AppIndicator") +- (c-name "app_indicator_set_ordering_index") +- (parameters +- '("guint32" "ordering_index") +- ) +-) +- +-(define-method set_icon_theme_path +- (of-object "AppIndicator") +- (c-name "app_indicator_set_icon_theme_path") +- (return-type "none") +- (parameters +- '("const-gchar*" "icon_theme_path" (null-ok)) +- ) +-) +- +-(define-method get_id +- (of-object "AppIndicator") +- (c-name "app_indicator_get_id") +- (return-type "const-gchar*") +-) +- +-(define-method get_category +- (of-object "AppIndicator") +- (c-name "app_indicator_get_category") +- (return-type "AppIndicatorCategory") +-) +- +-(define-method get_status +- (of-object "AppIndicator") +- (c-name "app_indicator_get_status") +- (return-type "AppIndicatorStatus") +-) +- +-(define-method get_icon +- (of-object "AppIndicator") +- (c-name "app_indicator_get_icon") +- (return-type "const-gchar*") +-) +- +-(define-method get_icon_desc +- (of-object "AppIndicator") +- (c-name "app_indicator_get_icon_desc") +- (return-type "const-gchar*") +-) +- +-(define-method get_icon_theme_path +- (of-object "AppIndicator") +- (c-name "app_indicator_get_icon_theme_path") +- (return-type "const-gchar*") +-) +- +-(define-method get_attention_icon +- (of-object "AppIndicator") +- (c-name "app_indicator_get_attention_icon") +- (return-type "const-gchar*") +-) +- +-(define-method get_attention_icon_desc +- (of-object "AppIndicator") +- (c-name "app_indicator_get_attention_icon_desc") +- (return-type "const-gchar*") +-) +- +-(define-method get_menu +- (of-object "AppIndicator") +- (c-name "app_indicator_get_menu") +- (return-type "GtkMenu*") +-) +- +-(define-method get_label +- (of-object "AppIndicator") +- (c-name "app_indicator_get_label") +- (return-type "const-gchar*") +-) +- +-(define-method get_label_guide +- (of-object "AppIndicator") +- (c-name "app_indicator_get_label_guide") +- (return-type "const-gchar*") +-) +- +-(define-method get_ordering_index +- (of-object "AppIndicator") +- (c-name "app_indicator_get_ordering_index") +- (return-type "guint32") +-) +- +-(define-method build_menu_from_desktop +- (of-object "AppIndicator") +- (c-name "app_indicator_build_menu_from_desktop") +- (return-type "none") +- (parameters +- '("const-gchar*" "desktop_file") +- '("const-gchar*" "desktop_profile") +- ) +-) +diff --git a/bindings/python/appindicator.override.in b/bindings/python/appindicator.override.in +deleted file mode 100644 +index 84d3159..0000000 +--- a/bindings/python/appindicator.override.in ++++ /dev/null +@@ -1,65 +0,0 @@ +-/* +-Python bindings for libappindicator. +- +-Copyright 2009 Canonical Ltd. +- +-Authors: +- Eitan Isaacson <eitan@ascender.com> (original) +- Neil Jagdish Patel <neil.patel@canonical.com> +- +-This program is free software: you can redistribute it and/or modify it +-under the terms of either or both of the following licenses: +- +-1) the GNU Lesser General Public License version 3, as published by the +-Free Software Foundation; and/or +-2) the GNU Lesser General Public License version 2.1, as published by +-the Free Software Foundation. +- +-This program is distributed in the hope that it will be useful, but +-WITHOUT ANY WARRANTY; without even the implied warranties of +-MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR +-PURPOSE. See the applicable version of the GNU Lesser General Public +-License for more details. +- +-You should have received a copy of both the GNU Lesser General Public +-License version 3 and version 2.1 along with this program. If not, see +-<http://www.gnu.org/licenses/> +-*/ +-%% +-headers +-#include <Python.h> +-#include "@top_srcdir@/src/app-indicator.h" +-#include "@top_builddir@/src/app-indicator-enum-types.h" +-#include <glib.h> +-#include "pygobject.h" +-#include "pyglib.h" +-#include <pygtk/pygtk.h> +- +-typedef PyObject* (*to_pyobject_func) (gpointer data); +- +-#define APP_TYPE_INDICATOR APP_INDICATOR_TYPE +- +-void +-_appindicator_add_constants(PyObject *module, const gchar *strip_prefix) +-{ +-#ifdef VERSION +- PyModule_AddStringConstant(module, "__version__", VERSION); +-#endif +- pyg_enum_add(module, +- "IndicatorCategory", +- strip_prefix, +- APP_INDICATOR_TYPE_INDICATOR_CATEGORY); +- +- pyg_enum_add(module, +- "IndicatorStatus", +- strip_prefix, +- APP_INDICATOR_TYPE_INDICATOR_STATUS); +- +- if (PyErr_Occurred()) +- PyErr_Print(); +-} +-%% +-modulename appindicator +-%% +-import gobject.GObject as PyGObject_Type +-import gtk.Menu as PyGtkMenu_Type +diff --git a/bindings/python/appindicatormodule.c b/bindings/python/appindicatormodule.c +deleted file mode 100644 +index b66639c..0000000 +--- a/bindings/python/appindicatormodule.c ++++ /dev/null +@@ -1,49 +0,0 @@ +-/* +-Python bindings for libappindicator. +- +-Copyright 2009 Canonical Ltd. +- +-Authors: +- Eitan Isaacson <eitan@ascender.com> +- Neil Jagdish Patel <neil.patel@canonical.com> +- +-This program is free software: you can redistribute it and/or modify it +-under the terms of either or both of the following licenses: +- +-1) the GNU Lesser General Public License version 3, as published by the +-Free Software Foundation; and/or +-2) the GNU Lesser General Public License version 2.1, as published by +-the Free Software Foundation. +- +-This program is distributed in the hope that it will be useful, but +-WITHOUT ANY WARRANTY; without even the implied warranties of +-MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR +-PURPOSE. See the applicable version of the GNU Lesser General Public +-License for more details. +- +-You should have received a copy of both the GNU Lesser General Public +-License version 3 and version 2.1 along with this program. If not, see +-<http://www.gnu.org/licenses/> +-*/ +-#include <pygobject.h> +- +-void pyappindicator_register_classes (PyObject *d); +-extern PyMethodDef pyappindicator_functions[]; +- +-DL_EXPORT(void) +-init_appindicator(void) +-{ +- PyObject *m, *d; +- +- init_pygobject (); +- +- m = Py_InitModule ("_appindicator", pyappindicator_functions); +- d = PyModule_GetDict (m); +- +- pyappindicator_register_classes (d); +- +- _appindicator_add_constants (m, "APP_INDICATOR_"); +- if (PyErr_Occurred ()) { +- Py_FatalError ("can't initialise module appindicator"); +- } +-} +diff --git a/configure b/configure +index 5174b3f..8ff732c 100755 +--- a/configure ++++ b/configure +@@ -13703,363 +13703,6 @@ else + fi + + +-########################### +-# Python +-########################### +- +-PYGTK_REQUIRED=2.14.0 +-PYGOBJECT_REQUIRED=0.22 +- +- +- +- +- +- if test -n "$PYTHON"; then +- # If the user set $PYTHON, use it and don't search something else. +- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $PYTHON version >= 2.3.5" >&5 +-$as_echo_n "checking whether $PYTHON version >= 2.3.5... " >&6; } +- prog="import sys, string +-# split strings by '.' and convert to numeric. Append some zeros +-# because we need at least 4 digits for the hex conversion. +-minver = map(int, string.split('2.3.5', '.')) + [0, 0, 0] +-minverhex = 0 +-for i in xrange(0, 4): minverhex = (minverhex << 8) + minver[i] +-sys.exit(sys.hexversion < minverhex)" +- if { echo "$as_me:$LINENO: $PYTHON -c "$prog"" >&5 +- ($PYTHON -c "$prog") >&5 2>&5 +- ac_status=$? +- echo "$as_me:$LINENO: \$? = $ac_status" >&5 +- (exit $ac_status); }; then : +- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +-$as_echo "yes" >&6; } +-else +- as_fn_error $? "too old" "$LINENO" 5 +-fi +- am_display_PYTHON=$PYTHON +- else +- # Otherwise, try each interpreter until we find one that satisfies +- # VERSION. +- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a Python interpreter with version >= 2.3.5" >&5 +-$as_echo_n "checking for a Python interpreter with version >= 2.3.5... " >&6; } +-if ${am_cv_pathless_PYTHON+:} false; then : +- $as_echo_n "(cached) " >&6 +-else +- +- for am_cv_pathless_PYTHON in python python2 python2.4 python2.3 python2.2 python2.1 python2.0 python1.6 python1.5 none; do +- test "$am_cv_pathless_PYTHON" = none && break +- prog="import sys, string +-# split strings by '.' and convert to numeric. Append some zeros +-# because we need at least 4 digits for the hex conversion. +-minver = map(int, string.split('2.3.5', '.')) + [0, 0, 0] +-minverhex = 0 +-for i in xrange(0, 4): minverhex = (minverhex << 8) + minver[i] +-sys.exit(sys.hexversion < minverhex)" +- if { echo "$as_me:$LINENO: $am_cv_pathless_PYTHON -c "$prog"" >&5 +- ($am_cv_pathless_PYTHON -c "$prog") >&5 2>&5 +- ac_status=$? +- echo "$as_me:$LINENO: \$? = $ac_status" >&5 +- (exit $ac_status); }; then : +- break +-fi +- done +-fi +-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_pathless_PYTHON" >&5 +-$as_echo "$am_cv_pathless_PYTHON" >&6; } +- # Set $PYTHON to the absolute path of $am_cv_pathless_PYTHON. +- if test "$am_cv_pathless_PYTHON" = none; then +- PYTHON=: +- else +- # Extract the first word of "$am_cv_pathless_PYTHON", so it can be a program name with args. +-set dummy $am_cv_pathless_PYTHON; ac_word=$2 +-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +-$as_echo_n "checking for $ac_word... " >&6; } +-if ${ac_cv_path_PYTHON+:} false; then : +- $as_echo_n "(cached) " >&6 +-else +- case $PYTHON in +- [\\/]* | ?:[\\/]*) +- ac_cv_path_PYTHON="$PYTHON" # Let the user override the test with a path. +- ;; +- *) +- as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +-for as_dir in $PATH +-do +- IFS=$as_save_IFS +- test -z "$as_dir" && as_dir=. +- for ac_exec_ext in '' $ac_executable_extensions; do +- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then +- ac_cv_path_PYTHON="$as_dir/$ac_word$ac_exec_ext" +- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 +- break 2 +- fi +-done +- done +-IFS=$as_save_IFS +- +- ;; +-esac +-fi +-PYTHON=$ac_cv_path_PYTHON +-if test -n "$PYTHON"; then +- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PYTHON" >&5 +-$as_echo "$PYTHON" >&6; } +-else +- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +-$as_echo "no" >&6; } +-fi +- +- +- fi +- am_display_PYTHON=$am_cv_pathless_PYTHON +- fi +- +- +- if test "$PYTHON" = :; then +- as_fn_error $? "no suitable Python interpreter found" "$LINENO" 5 +- else +- +- +- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $am_display_PYTHON version" >&5 +-$as_echo_n "checking for $am_display_PYTHON version... " >&6; } +-if ${am_cv_python_version+:} false; then : +- $as_echo_n "(cached) " >&6 +-else +- am_cv_python_version=`$PYTHON -c "import sys; print sys.version[:3]"` +-fi +-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_python_version" >&5 +-$as_echo "$am_cv_python_version" >&6; } +- PYTHON_VERSION=$am_cv_python_version +- +- +- +- PYTHON_PREFIX='${prefix}' +- +- PYTHON_EXEC_PREFIX='${exec_prefix}' +- +- +- +- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $am_display_PYTHON platform" >&5 +-$as_echo_n "checking for $am_display_PYTHON platform... " >&6; } +-if ${am_cv_python_platform+:} false; then : +- $as_echo_n "(cached) " >&6 +-else +- am_cv_python_platform=`$PYTHON -c "import sys; print sys.platform"` +-fi +-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_python_platform" >&5 +-$as_echo "$am_cv_python_platform" >&6; } +- PYTHON_PLATFORM=$am_cv_python_platform +- +- +- +- +- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $am_display_PYTHON script directory" >&5 +-$as_echo_n "checking for $am_display_PYTHON script directory... " >&6; } +-if ${am_cv_python_pythondir+:} false; then : +- $as_echo_n "(cached) " >&6 +-else +- am_cv_python_pythondir=`$PYTHON -c "from distutils import sysconfig; print sysconfig.get_python_lib(0,0,prefix='$PYTHON_PREFIX')" 2>/dev/null || +- echo "$PYTHON_PREFIX/lib/python$PYTHON_VERSION/site-packages"` +-fi +-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_python_pythondir" >&5 +-$as_echo "$am_cv_python_pythondir" >&6; } +- pythondir=$am_cv_python_pythondir +- +- +- +- pkgpythondir=\${pythondir}/$PACKAGE +- +- +- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $am_display_PYTHON extension module directory" >&5 +-$as_echo_n "checking for $am_display_PYTHON extension module directory... " >&6; } +-if ${am_cv_python_pyexecdir+:} false; then : +- $as_echo_n "(cached) " >&6 +-else +- am_cv_python_pyexecdir=`$PYTHON -c "from distutils import sysconfig; print sysconfig.get_python_lib(1,0,prefix='$PYTHON_EXEC_PREFIX')" 2>/dev/null || +- echo "${PYTHON_EXEC_PREFIX}/lib/python${PYTHON_VERSION}/site-packages"` +-fi +-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_python_pyexecdir" >&5 +-$as_echo "$am_cv_python_pyexecdir" >&6; } +- pyexecdir=$am_cv_python_pyexecdir +- +- +- +- pkgpyexecdir=\${pyexecdir}/$PACKAGE +- +- +- +- fi +- +- +- +-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for headers required to compile python extensions" >&5 +-$as_echo_n "checking for headers required to compile python extensions... " >&6; } +-py_prefix=`$PYTHON -c "import sys; print sys.prefix"` +-py_exec_prefix=`$PYTHON -c "import sys; print sys.exec_prefix"` +-PYTHON_INCLUDES="-I${py_prefix}/include/python${PYTHON_VERSION}" +-if test "$py_prefix" != "$py_exec_prefix"; then +- PYTHON_INCLUDES="$PYTHON_INCLUDES -I${py_exec_prefix}/include/python${PYTHON_VERSION}" +-fi +- +-save_CPPFLAGS="$CPPFLAGS" +-CPPFLAGS="$CPPFLAGS $PYTHON_INCLUDES" +-cat confdefs.h - <<_ACEOF >conftest.$ac_ext +-/* end confdefs.h. */ +-#include <Python.h> +-_ACEOF +-if ac_fn_c_try_cpp "$LINENO"; then : +- { $as_echo "$as_me:${as_lineno-$LINENO}: result: found" >&5 +-$as_echo "found" >&6; } +- +-else +- { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5 +-$as_echo "not found" >&6; } +-as_fn_error $? "could not find Python headers" "$LINENO" 5 +-fi +-rm -f conftest.err conftest.i conftest.$ac_ext +-CPPFLAGS="$save_CPPFLAGS" +- +- +- +-pkg_failed=no +-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for APPINDICATOR_PYTHON" >&5 +-$as_echo_n "checking for APPINDICATOR_PYTHON... " >&6; } +- +-if test -n "$APPINDICATOR_PYTHON_CFLAGS"; then +- pkg_cv_APPINDICATOR_PYTHON_CFLAGS="$APPINDICATOR_PYTHON_CFLAGS" +- elif test -n "$PKG_CONFIG"; then +- if test -n "$PKG_CONFIG" && \ +- { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \" +- pygtk-2.0 >= \$PYGTK_REQUIRED +- gtk+-2.0 >= \$GTK_REQUIRED_VERSION +- pygobject-2.0 >= \$PYGOBJECT_REQUIRED +- \""; } >&5 +- ($PKG_CONFIG --exists --print-errors " +- pygtk-2.0 >= $PYGTK_REQUIRED +- gtk+-2.0 >= $GTK_REQUIRED_VERSION +- pygobject-2.0 >= $PYGOBJECT_REQUIRED +- ") 2>&5 +- ac_status=$? +- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 +- test $ac_status = 0; }; then +- pkg_cv_APPINDICATOR_PYTHON_CFLAGS=`$PKG_CONFIG --cflags " +- pygtk-2.0 >= $PYGTK_REQUIRED +- gtk+-2.0 >= $GTK_REQUIRED_VERSION +- pygobject-2.0 >= $PYGOBJECT_REQUIRED +- " 2>/dev/null` +- test "x$?" != "x0" && pkg_failed=yes +-else +- pkg_failed=yes +-fi +- else +- pkg_failed=untried +-fi +-if test -n "$APPINDICATOR_PYTHON_LIBS"; then +- pkg_cv_APPINDICATOR_PYTHON_LIBS="$APPINDICATOR_PYTHON_LIBS" +- elif test -n "$PKG_CONFIG"; then +- if test -n "$PKG_CONFIG" && \ +- { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \" +- pygtk-2.0 >= \$PYGTK_REQUIRED +- gtk+-2.0 >= \$GTK_REQUIRED_VERSION +- pygobject-2.0 >= \$PYGOBJECT_REQUIRED +- \""; } >&5 +- ($PKG_CONFIG --exists --print-errors " +- pygtk-2.0 >= $PYGTK_REQUIRED +- gtk+-2.0 >= $GTK_REQUIRED_VERSION +- pygobject-2.0 >= $PYGOBJECT_REQUIRED +- ") 2>&5 +- ac_status=$? +- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 +- test $ac_status = 0; }; then +- pkg_cv_APPINDICATOR_PYTHON_LIBS=`$PKG_CONFIG --libs " +- pygtk-2.0 >= $PYGTK_REQUIRED +- gtk+-2.0 >= $GTK_REQUIRED_VERSION +- pygobject-2.0 >= $PYGOBJECT_REQUIRED +- " 2>/dev/null` +- test "x$?" != "x0" && pkg_failed=yes +-else +- pkg_failed=yes +-fi +- else +- pkg_failed=untried +-fi +- +- +- +-if test $pkg_failed = yes; then +- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +-$as_echo "no" >&6; } +- +-if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then +- _pkg_short_errors_supported=yes +-else +- _pkg_short_errors_supported=no +-fi +- if test $_pkg_short_errors_supported = yes; then +- APPINDICATOR_PYTHON_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs " +- pygtk-2.0 >= $PYGTK_REQUIRED +- gtk+-2.0 >= $GTK_REQUIRED_VERSION +- pygobject-2.0 >= $PYGOBJECT_REQUIRED +- " 2>&1` +- else +- APPINDICATOR_PYTHON_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs " +- pygtk-2.0 >= $PYGTK_REQUIRED +- gtk+-2.0 >= $GTK_REQUIRED_VERSION +- pygobject-2.0 >= $PYGOBJECT_REQUIRED +- " 2>&1` +- fi +- # Put the nasty error message in config.log where it belongs +- echo "$APPINDICATOR_PYTHON_PKG_ERRORS" >&5 +- +- as_fn_error $? "Package requirements ( +- pygtk-2.0 >= $PYGTK_REQUIRED +- gtk+-2.0 >= $GTK_REQUIRED_VERSION +- pygobject-2.0 >= $PYGOBJECT_REQUIRED +- ) were not met: +- +-$APPINDICATOR_PYTHON_PKG_ERRORS +- +-Consider adjusting the PKG_CONFIG_PATH environment variable if you +-installed software in a non-standard prefix. +- +-Alternatively, you may set the environment variables APPINDICATOR_PYTHON_CFLAGS +-and APPINDICATOR_PYTHON_LIBS to avoid the need to call pkg-config. +-See the pkg-config man page for more details." "$LINENO" 5 +-elif test $pkg_failed = untried; then +- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +-$as_echo "no" >&6; } +- { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +-as_fn_error $? "The pkg-config script could not be found or is too old. Make sure it +-is in your PATH or set the PKG_CONFIG environment variable to the full +-path to pkg-config. +- +-Alternatively, you may set the environment variables APPINDICATOR_PYTHON_CFLAGS +-and APPINDICATOR_PYTHON_LIBS to avoid the need to call pkg-config. +-See the pkg-config man page for more details. +- +-To get pkg-config, see <http://pkg-config.freedesktop.org/>. +-See \`config.log' for more details" "$LINENO" 5; } +-else +- APPINDICATOR_PYTHON_CFLAGS=$pkg_cv_APPINDICATOR_PYTHON_CFLAGS +- APPINDICATOR_PYTHON_LIBS=$pkg_cv_APPINDICATOR_PYTHON_LIBS +- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +-$as_echo "yes" >&6; } +- +-fi +- +-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for pygtk defs" >&5 +-$as_echo_n "checking for pygtk defs... " >&6; } +-PYGTK_DEFSDIR=`$PKG_CONFIG --variable=defsdir pygtk-2.0` +- +-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $PYGTK_DEFSDIR" >&5 +-$as_echo "$PYGTK_DEFSDIR" >&6; } +- +-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for pygtk codegen" >&5 +-$as_echo_n "checking for pygtk codegen... " >&6; } +-PYGTK_CODEGEN="$PYTHON `$PKG_CONFIG --variable=codegendir pygtk-2.0`/codegen.py" +- +-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $PYGTK_CODEGEN" >&5 +-$as_echo "$PYGTK_CODEGEN" >&6; } + + ######################### + # Check if build tests +@@ -14358,7 +14001,7 @@ fi + # Files + ########################### + +-ac_config_files="$ac_config_files Makefile src/Makefile src/appindicator-0.1.pc src/appindicator3-0.1.pc bindings/Makefile bindings/python/Makefile bindings/python/appindicator.override bindings/vala/Makefile bindings/vala/examples/Makefile tests/Makefile example/Makefile docs/Makefile docs/reference/Makefile docs/reference/version.xml docs/reference/libappindicator-docs.sgml" ++ac_config_files="$ac_config_files Makefile src/Makefile src/appindicator-0.1.pc src/appindicator3-0.1.pc bindings/Makefile bindings/vala/Makefile bindings/vala/examples/Makefile tests/Makefile example/Makefile docs/Makefile docs/reference/Makefile docs/reference/version.xml docs/reference/libappindicator-docs.sgml" + + + if test "x$has_mono" = "xtrue" ; then +@@ -15437,8 +15080,6 @@ do + "src/appindicator-0.1.pc") CONFIG_FILES="$CONFIG_FILES src/appindicator-0.1.pc" ;; + "src/appindicator3-0.1.pc") CONFIG_FILES="$CONFIG_FILES src/appindicator3-0.1.pc" ;; + "bindings/Makefile") CONFIG_FILES="$CONFIG_FILES bindings/Makefile" ;; +- "bindings/python/Makefile") CONFIG_FILES="$CONFIG_FILES bindings/python/Makefile" ;; +- "bindings/python/appindicator.override") CONFIG_FILES="$CONFIG_FILES bindings/python/appindicator.override" ;; + "bindings/vala/Makefile") CONFIG_FILES="$CONFIG_FILES bindings/vala/Makefile" ;; + "bindings/vala/examples/Makefile") CONFIG_FILES="$CONFIG_FILES bindings/vala/examples/Makefile" ;; + "tests/Makefile") CONFIG_FILES="$CONFIG_FILES tests/Makefile" ;; +diff --git a/configure.ac b/configure.ac +index ee03390..4713b22 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -181,33 +181,6 @@ AM_CONDITIONAL(BUILD_MONO_TEST, test x${have_nunit} = xyes) + with_localinstall="no" + AC_ARG_ENABLE(localinstall, AS_HELP_STRING([--enable-localinstall], [install all of the files localy instead of system directories (for distcheck)]), with_localinstall=$enableval, with_localinstall=no) + +-########################### +-# Python +-########################### +- +-PYGTK_REQUIRED=2.14.0 +-PYGOBJECT_REQUIRED=0.22 +- +-AM_PATH_PYTHON(2.3.5) +-AM_CHECK_PYTHON_HEADERS(,[AC_MSG_ERROR(could not find Python headers)]) +- +-PKG_CHECK_MODULES(APPINDICATOR_PYTHON, +- [ +- pygtk-2.0 >= $PYGTK_REQUIRED +- gtk+-2.0 >= $GTK_REQUIRED_VERSION +- pygobject-2.0 >= $PYGOBJECT_REQUIRED +- ]) +- +-AC_MSG_CHECKING(for pygtk defs) +-PYGTK_DEFSDIR=`$PKG_CONFIG --variable=defsdir pygtk-2.0` +-AC_SUBST(PYGTK_DEFSDIR) +-AC_MSG_RESULT($PYGTK_DEFSDIR) +- +-AC_MSG_CHECKING(for pygtk codegen) +-PYGTK_CODEGEN="$PYTHON `$PKG_CONFIG --variable=codegendir pygtk-2.0`/codegen.py" +-AC_SUBST(PYGTK_CODEGEN) +-AC_MSG_RESULT($PYGTK_CODEGEN) +- + ######################### + # Check if build tests + ######################### +@@ -239,8 +212,6 @@ src/Makefile + src/appindicator-0.1.pc + src/appindicator3-0.1.pc + bindings/Makefile +-bindings/python/Makefile +-bindings/python/appindicator.override + bindings/vala/Makefile + bindings/vala/examples/Makefile + tests/Makefile
\ No newline at end of file diff --git a/subprojects/shared-modules/libappindicator/libappindicator.json.in b/subprojects/shared-modules/libappindicator/libappindicator.json.in new file mode 100644 index 00000000..2b383af7 --- /dev/null +++ b/subprojects/shared-modules/libappindicator/libappindicator.json.in @@ -0,0 +1,121 @@ +{ + "name": "libappindicator", + "build-options": { + "cflags": "-Wno-error" + }, + "rm-configure": true, + "config-opts": [ + "--disable-static", + "--disable-gtk-doc", + "--disable-tests", + "--disable-mono-tests", + "--enable-introspection=@INTROSPECTION@", + "--with-gtk=@GTK_VER@" + ], + "cleanup": [ + "/include", + "/lib/pkgconfig", + "/lib/*.la", + "/share/gtk-doc", + "/share/gir-1.0" + ], + "sources": [ + { + "type": "archive", + "url": "https://launchpad.net/libappindicator/12.10/12.10.0/+download/libappindicator-12.10.0.tar.gz", + "sha256": "d5907c1f98084acf28fd19593cb70672caa0ca1cf82d747ba6f4830d4cc3b49f" + }, + { + "type": "patch", + "path": "libappindicator-ftbfs.patch" + }, + { + "type": "patch", + "path": "libappindicator-no-python.patch" + }, + { + "type": "script", + "commands": ["autoreconf -sfi"], + "dest-filename": "autogen.sh" + } + ], + "modules": [ + "../intltool/intltool-0.51.json", + "../dbus-glib/dbus-glib-0.110.json", + { + "name": "libdbusmenu", + "build-options": { + "cflags": "-Wno-error", + "env": { + "HAVE_VALGRIND_FALSE": "#", + "HAVE_VALGRIND_TRUE": "" + } + }, + "cleanup": [ + "/include", + "/libexec", + "/lib/pkgconfig", + "/lib/*.la", + "/share/doc", + "/share/libdbusmenu", + "/share/gtk-doc", + "/share/gir-1.0" + ], + "config-opts": [ + "--disable-static", + "--disable-gtk-doc", + "--enable-introspection=@INTROSPECTION@", + "--disable-vala", + "--disable-dumper", + "--disable-tests", + "--with-gtk=@GTK_VER@" + ], + "sources": [ + { + "type": "archive", + "url": "https://launchpad.net/libdbusmenu/16.04/16.04.0/+download/libdbusmenu-16.04.0.tar.gz", + "sha256": "b9cc4a2acd74509435892823607d966d424bd9ad5d0b00938f27240a1bfa878a" + } + ] + }, + { + "name": "libindicator", + "build-options": { + "cflags": "-Wno-error" + }, + "cleanup": [ + "/include", + "/libexec", + "/lib/pkgconfig", + "/lib/*.la", + "/share/libindicator", + "/share/gtk-doc", + "/share/gir-1.0" + ], + "config-opts": [ + "--disable-static", + "--disable-tests", + "--with-gtk=@GTK_VER@" + ], + "sources": [ + { + "type": "archive", + "url": "https://launchpad.net/libindicator/12.10/12.10.1/+download/libindicator-12.10.1.tar.gz", + "sha256": "b2d2e44c10313d5c9cd60db455d520f80b36dc39562df079a3f29495e8f9447f" + }, + { + "type": "shell", + "commands": [ + "# FTBFS fix", + "sed -e '/LIBINDICATOR_LIBS/ s/\\$LIBM/ $LIBM/' -i configure.ac" + ] + }, + { + "type": "script", + "commands": ["autoreconf -sfi"], + "dest-filename": "autogen.sh" + } + ] + } + ] +} diff --git a/subprojects/shared-modules/libmad/Provide-Thumb-2-alternative-code-for-MAD_F_MLN.diff b/subprojects/shared-modules/libmad/Provide-Thumb-2-alternative-code-for-MAD_F_MLN.diff new file mode 100644 index 00000000..46415107 --- /dev/null +++ b/subprojects/shared-modules/libmad/Provide-Thumb-2-alternative-code-for-MAD_F_MLN.diff @@ -0,0 +1,34 @@ +From: Dave Martin +Subject: "rsc" doesnt exist anymore in thumb2 + +diff --git a/fixed.h b/fixed.h +index 4b58abf..ba4bc26 100644 +--- a/fixed.h ++++ b/fixed.h +@@ -275,12 +275,25 @@ mad_fixed_t mad_f_mul_inline(mad_fixed_t x, mad_fixed_t y) + : "+r" (lo), "+r" (hi) \ + : "%r" (x), "r" (y)) + ++#ifdef __thumb__ ++/* In Thumb-2, the RSB-immediate instruction is only allowed with a zero ++ operand. If needed this code can also support Thumb-1 ++ (simply append "s" to the end of the second two instructions). */ ++# define MAD_F_MLN(hi, lo) \ ++ asm ("rsbs %0, %0, #0\n\t" \ ++ "sbc %1, %1, %1\n\t" \ ++ "sub %1, %1, %2" \ ++ : "+&r" (lo), "=&r" (hi) \ ++ : "r" (hi) \ ++ : "cc") ++#else /* ! __thumb__ */ + # define MAD_F_MLN(hi, lo) \ + asm ("rsbs %0, %2, #0\n\t" \ + "rsc %1, %3, #0" \ +- : "=r" (lo), "=r" (hi) \ ++ : "=&r" (lo), "=r" (hi) \ + : "0" (lo), "1" (hi) \ + : "cc") ++#endif /* __thumb__ */ + + # define mad_f_scale64(hi, lo) \ + ({ mad_fixed_t __result; \ diff --git a/subprojects/shared-modules/libmad/libmad-0.15.1b-cflags-O2.patch b/subprojects/shared-modules/libmad/libmad-0.15.1b-cflags-O2.patch new file mode 100644 index 00000000..61b4b13b --- /dev/null +++ b/subprojects/shared-modules/libmad/libmad-0.15.1b-cflags-O2.patch @@ -0,0 +1,12 @@ +diff -Naur libmad-0.15.1b-orig/configure.ac libmad-0.15.1b/configure.ac +--- libmad-0.15.1b-orig/configure.ac 2007-07-01 12:58:13.000000000 -0600 ++++ libmad-0.15.1b/configure.ac 2007-07-01 12:59:13.000000000 -0600 +@@ -105,7 +105,7 @@ + shift + ;; + -O2) +- optimize="-O" ++ optimize="-O2" + shift + ;; + -fomit-frame-pointer) diff --git a/subprojects/shared-modules/libmad/libmad-0.15.1b-cflags.patch b/subprojects/shared-modules/libmad/libmad-0.15.1b-cflags.patch new file mode 100644 index 00000000..2ec44e34 --- /dev/null +++ b/subprojects/shared-modules/libmad/libmad-0.15.1b-cflags.patch @@ -0,0 +1,146 @@ +diff -Naur libmad-0.15.1b-orig/configure.ac libmad-0.15.1b/configure.ac +--- libmad-0.15.1b-orig/configure.ac 2007-06-30 20:22:31.000000000 -0600 ++++ libmad-0.15.1b/configure.ac 2007-06-30 20:25:31.000000000 -0600 +@@ -122,74 +122,74 @@ + esac + done + +-if test "$GCC" = yes +-then +- if test -z "$arch" +- then +- case "$host" in +- i386-*) ;; +- i?86-*) arch="-march=i486" ;; +- arm*-empeg-*) arch="-march=armv4 -mtune=strongarm1100" ;; +- armv4*-*) arch="-march=armv4 -mtune=strongarm" ;; +- powerpc-*) ;; +- mips*-agenda-*) arch="-mcpu=vr4100" ;; +- mips*-luxsonor-*) arch="-mips1 -mcpu=r3000 -Wa,-m4010" ;; +- esac +- fi +- +- case "$optimize" in +- -O|"-O "*) +- optimize="-O" +- optimize="$optimize -fforce-mem" +- optimize="$optimize -fforce-addr" +- : #x optimize="$optimize -finline-functions" +- : #- optimize="$optimize -fstrength-reduce" +- optimize="$optimize -fthread-jumps" +- optimize="$optimize -fcse-follow-jumps" +- optimize="$optimize -fcse-skip-blocks" +- : #x optimize="$optimize -frerun-cse-after-loop" +- : #x optimize="$optimize -frerun-loop-opt" +- : #x optimize="$optimize -fgcse" +- optimize="$optimize -fexpensive-optimizations" +- optimize="$optimize -fregmove" +- : #* optimize="$optimize -fdelayed-branch" +- : #x optimize="$optimize -fschedule-insns" +- optimize="$optimize -fschedule-insns2" +- : #? optimize="$optimize -ffunction-sections" +- : #? optimize="$optimize -fcaller-saves" +- : #> optimize="$optimize -funroll-loops" +- : #> optimize="$optimize -funroll-all-loops" +- : #x optimize="$optimize -fmove-all-movables" +- : #x optimize="$optimize -freduce-all-givs" +- : #? optimize="$optimize -fstrict-aliasing" +- : #* optimize="$optimize -fstructure-noalias" +- +- case "$host" in +- arm*-*) +- optimize="$optimize -fstrength-reduce" +- ;; +- mips*-*) +- optimize="$optimize -fstrength-reduce" +- optimize="$optimize -finline-functions" +- ;; +- i?86-*) +- optimize="$optimize -fstrength-reduce" +- ;; +- powerpc-apple-*) +- # this triggers an internal compiler error with gcc2 +- : #optimize="$optimize -fstrength-reduce" +- +- # this is really only beneficial with gcc3 +- : #optimize="$optimize -finline-functions" +- ;; +- *) +- # this sometimes provokes bugs in gcc 2.95.2 +- : #optimize="$optimize -fstrength-reduce" +- ;; +- esac +- ;; +- esac +-fi ++#if test "$GCC" = yes ++#then ++# if test -z "$arch" ++# then ++# case "$host" in ++# i386-*) ;; ++# i?86-*) arch="-march=i486" ;; ++# arm*-empeg-*) arch="-march=armv4 -mtune=strongarm1100" ;; ++# armv4*-*) arch="-march=armv4 -mtune=strongarm" ;; ++# powerpc-*) ;; ++# mips*-agenda-*) arch="-mcpu=vr4100" ;; ++# mips*-luxsonor-*) arch="-mips1 -mcpu=r3000 -Wa,-m4010" ;; ++# esac ++# fi ++# ++# case "$optimize" in ++# -O|"-O "*) ++# optimize="-O" ++# optimize="$optimize -fforce-mem" ++# optimize="$optimize -fforce-addr" ++# : #x optimize="$optimize -finline-functions" ++# : #- optimize="$optimize -fstrength-reduce" ++# optimize="$optimize -fthread-jumps" ++# optimize="$optimize -fcse-follow-jumps" ++# optimize="$optimize -fcse-skip-blocks" ++# : #x optimize="$optimize -frerun-cse-after-loop" ++# : #x optimize="$optimize -frerun-loop-opt" ++# : #x optimize="$optimize -fgcse" ++# optimize="$optimize -fexpensive-optimizations" ++# optimize="$optimize -fregmove" ++# : #* optimize="$optimize -fdelayed-branch" ++# : #x optimize="$optimize -fschedule-insns" ++# optimize="$optimize -fschedule-insns2" ++# : #? optimize="$optimize -ffunction-sections" ++# : #? optimize="$optimize -fcaller-saves" ++# : #> optimize="$optimize -funroll-loops" ++# : #> optimize="$optimize -funroll-all-loops" ++# : #x optimize="$optimize -fmove-all-movables" ++# : #x optimize="$optimize -freduce-all-givs" ++# : #? optimize="$optimize -fstrict-aliasing" ++# : #* optimize="$optimize -fstructure-noalias" ++# ++# case "$host" in ++# arm*-*) ++# optimize="$optimize -fstrength-reduce" ++# ;; ++# mips*-*) ++# optimize="$optimize -fstrength-reduce" ++# optimize="$optimize -finline-functions" ++# ;; ++# i?86-*) ++# optimize="$optimize -fstrength-reduce" ++# ;; ++# powerpc-apple-*) ++# # this triggers an internal compiler error with gcc2 ++# : #optimize="$optimize -fstrength-reduce" ++# ++# # this is really only beneficial with gcc3 ++# : #optimize="$optimize -finline-functions" ++# ;; ++# *) ++# # this sometimes provokes bugs in gcc 2.95.2 ++# : #optimize="$optimize -fstrength-reduce" ++# ;; ++# esac ++# ;; ++# esac ++#fi + + case "$host" in + mips*-agenda-*) diff --git a/subprojects/shared-modules/libmad/libmad-0.15.1b-multiarch.patch b/subprojects/shared-modules/libmad/libmad-0.15.1b-multiarch.patch new file mode 100644 index 00000000..51bf663b --- /dev/null +++ b/subprojects/shared-modules/libmad/libmad-0.15.1b-multiarch.patch @@ -0,0 +1,37 @@ +diff -up libmad-0.15.1b/Makefile.am.orig libmad-0.15.1b/Makefile.am +--- libmad-0.15.1b/Makefile.am.orig 2009-01-25 14:35:56.000000000 +0200 ++++ libmad-0.15.1b/Makefile.am 2009-01-25 18:35:07.000000000 +0200 +@@ -110,15 +110,28 @@ mad.h: config.status config.h Makefile.a + echo "# ifdef __cplusplus"; \ + echo 'extern "C" {'; \ + echo "# endif"; echo; \ +- if [ ".$(FPM)" != "." ]; then \ +- echo ".$(FPM)" | sed -e 's|^\.-D|# define |'; echo; \ +- fi; \ ++ echo "# ifdef __i386__"; \ ++ echo "# define FPM_INTEL"; \ ++ echo "# define SIZEOF_LONG 4"; \ ++ echo "# endif"; \ ++ echo "#ifdef __x86_64__";\ ++ echo "# define FPM_64BIT"; \ ++ echo "# define SIZEOF_LONG 8"; \ ++ echo "# endif"; \ ++ echo "#ifdef __powerpc__"; \ ++ echo "#define FPM_PPC"; \ ++ echo "#define SIZEOF_LONG 4"; \ ++ echo "#endif"; \ ++ echo "#ifdef __powerpc64__"; \ ++ echo "#define FPM_PPC"; \ ++ echo "#define SIZEOF_LONG 8"; \ ++ echo "#endif"; echo; \ + sed -ne 's/^# *define *\(HAVE_.*_ASM\).*/# define \1/p' \ + config.h; echo; \ + sed -ne 's/^# *define *OPT_\(SPEED\|ACCURACY\).*/# define OPT_\1/p' \ + config.h; echo; \ +- sed -ne 's/^# *define *\(SIZEOF_.*\)/# define \1/p' \ +- config.h; echo; \ ++ echo "# define SIZEOF_INT 4"; \ ++ echo "# define SIZEOF_LONG_LONG 8"; echo; \ + for header in $(exported_headers); do \ + echo; \ + sed -n -f $(srcdir)/mad.h.sed $(srcdir)/$$header; \ diff --git a/subprojects/shared-modules/libmad/libmad-0.15.1b-ppc.patch b/subprojects/shared-modules/libmad/libmad-0.15.1b-ppc.patch new file mode 100644 index 00000000..fa6ee383 --- /dev/null +++ b/subprojects/shared-modules/libmad/libmad-0.15.1b-ppc.patch @@ -0,0 +1,13 @@ +--- libmad-0.15.1b/fixed.h~ 2004-02-17 02:02:03.000000000 +0000 ++++ libmad-0.15.1b/fixed.h 2009-07-19 13:03:08.000000000 +0100 +@@ -379,8 +379,8 @@ mad_fixed_t mad_f_mul_inline(mad_fixed_t + asm ("addc %0,%2,%3\n\t" \ + "adde %1,%4,%5" \ + : "=r" (lo), "=r" (hi) \ +- : "%r" (lo), "r" (__lo), \ +- "%r" (hi), "r" (__hi) \ ++ : "0" (lo), "r" (__lo), \ ++ "1" (hi), "r" (__hi) \ + : "xer"); \ + }) + # endif diff --git a/subprojects/shared-modules/libmad/libmad.json b/subprojects/shared-modules/libmad/libmad.json new file mode 100644 index 00000000..7ee6cc78 --- /dev/null +++ b/subprojects/shared-modules/libmad/libmad.json @@ -0,0 +1,41 @@ +{ + "name" : "libmad", + "sources" : [ + { + "type" : "archive", + "url" : "https://downloads.sourceforge.net/project/mad/libmad/0.15.1b/libmad-0.15.1b.tar.gz", + "sha256" : "bbfac3ed6bfbc2823d3775ebb931087371e142bb0e9bb1bee51a76a6e0078690" + }, + { + "type": "patch", + "path": "libmad-0.15.1b-multiarch.patch" + }, + { + "type": "patch", + "path": "libmad-0.15.1b-ppc.patch" + }, + { + "type": "patch", + "path": "Provide-Thumb-2-alternative-code-for-MAD_F_MLN.diff" + }, + { + "type": "patch", + "path": "libmad.thumb.diff" + }, + { + "type": "patch", + "path": "libmad-0.15.1b-cflags.patch" + }, + { + "type": "patch", + "path": "libmad-0.15.1b-cflags-O2.patch" + }, + { + "type": "shell", + "commands": [ + "cp /usr/share/gnu-config/config.sub .", + "cp /usr/share/gnu-config/config.guess ." + ] + } + ] +} diff --git a/subprojects/shared-modules/libmad/libmad.thumb.diff b/subprojects/shared-modules/libmad/libmad.thumb.diff new file mode 100644 index 00000000..13edde21 --- /dev/null +++ b/subprojects/shared-modules/libmad/libmad.thumb.diff @@ -0,0 +1,12 @@ +--- ./imdct_l_arm.S.orig 2010-02-25 13:25:23.000000000 +0100 ++++ ./imdct_l_arm.S 2010-02-25 13:27:26.000000000 +0100 +@@ -468,7 +468,7 @@ + + @---- + +- add r2, pc, #(imdct36_long_karray-.-8) @ r2 = base address of Knn array (PIC safe ?) ++ adr r2, imdct36_long_karray + + + loop: + diff --git a/subprojects/shared-modules/libsecret/libsecret.json b/subprojects/shared-modules/libsecret/libsecret.json new file mode 100644 index 00000000..a2d34f58 --- /dev/null +++ b/subprojects/shared-modules/libsecret/libsecret.json @@ -0,0 +1,23 @@ +{ + "name": "libsecret", + "buildsystem": "meson", + "config-opts": [ + "-Dmanpage=false", + "-Dvapi=false", + "-Dgtk_doc=false" + ], + "cleanup": [ + "/bin", + "/include", + "/lib/pkgconfig", + "/share/gir-1.0", + "/share/man" + ], + "sources": [ + { + "type": "archive", + "url": "https://ftp.gnome.org/pub/GNOME/sources/libsecret/0.20/libsecret-0.20.1.tar.xz", + "sha256": "57f73e94ec6263a17a077fb809cf8cf424637a897a7f15b4eec42ce4aef52447" + } + ] +} diff --git a/subprojects/shared-modules/lua5.3/lua-5.3.0-autotoolize.patch b/subprojects/shared-modules/lua5.3/lua-5.3.0-autotoolize.patch new file mode 100644 index 00000000..3e4723a5 --- /dev/null +++ b/subprojects/shared-modules/lua5.3/lua-5.3.0-autotoolize.patch @@ -0,0 +1,192 @@ +diff -up lua-5.3.0/configure.ac.autoxxx lua-5.3.0/configure.ac +--- lua-5.3.0/configure.ac.autoxxx 2015-01-15 10:20:03.826889574 -0500 ++++ lua-5.3.0/configure.ac 2015-01-15 10:20:03.826889574 -0500 +@@ -0,0 +1,69 @@ ++AC_PREREQ(2.59) ++AC_INIT([lua], [5.3.0], [https://bugzilla.redhat.com/], [lua-at], [http://www.lua.org]) ++AC_SUBST([MAJOR_VERSION], [5.3]) ++ ++AC_CONFIG_HEADERS([config.h]) ++AC_CONFIG_SRCDIR([src/lapi.c]) ++ ++AM_INIT_AUTOMAKE([1.9 foreign]) ++ ++AC_PROG_CC ++AC_PROG_LIBTOOL ++ ++AC_ARG_WITH( ++ [readline], ++ [AC_HELP_STRING([--with-readline], [Use readline for interpreter input [default=yes]])], ++ [use_readline=$withval], ++ [use_readline=yes] ++) ++ ++LUA_LIBS="-lm" ++ ++# Check for readline ++READLINE_DEFS="#undef LUA_USE_READLINE" ++if test "x$use_readline" == "xyes"; then ++ AC_CHECK_LIB([readline], [readline], [:], [use_readline=no], [-lncurses]) ++ AC_CHECK_HEADERS([readline/readline.h readline/history.h], [], [use_readline=no]) ++ if test "x$use_readline" == "xno"; then ++ AC_MSG_WARN([readline headers could not be found, disabling readline support]) ++ else ++ READLINE_DEFS="#define LUA_USE_READLINE" ++ READLINE_LIBS="-lreadline -lncurses" ++ fi ++fi ++AC_SUBST(READLINE_DEFS) ++AC_SUBST(READLINE_LIBS) ++ ++case "$host" in ++ *-mingw*) use_os=win32 ;; ++ *-darwin*) use_os=macosx ;; ++ *) use_os=posix ;; ++esac ++ ++POSIX_DEFS="#undef LUA_USE_POSIX" ++LUA_DL_DEFS="#undef LUA_USE_DLOPEN" ++LUA_BUILD_AS_DLL_DEFS="#undef LUA_BUILD_AS_DLL" ++ ++if test "x$use_os" == "xwin32"; then ++ LUA_BUILD_AS_DLL_DEFS="#define LUA_BUILD_AS_DLL" ++elif test "x$use_os" == "xmacosx"; then ++ POSIX_DEFS="#define LUA_USE_POSIX" ++ LUA_DL_DEFS="#define LUA_DL_DYLD" ++elif test "x$use_os" == "xposix"; then ++ POSIX_DEFS="#define LUA_USE_POSIX" ++ LUA_DL_DEFS="#define LUA_DL_DLOPEN" ++ LUA_LIBS="$LUA_LIBS -ldl" ++fi ++AC_SUBST(POSIX_DEFS) ++AC_SUBST(LUA_DL_DEFS) ++AC_SUBST(LUA_BUILD_AS_DLL_DEFS) ++ ++AC_SUBST(LUA_LIBS) ++ ++AC_CONFIG_FILES([Makefile ++ src/Makefile ++ src/lua.pc ++ src/luaconf.h.template ++ doc/Makefile ++]) ++AC_OUTPUT +diff -up lua-5.3.0/doc/Makefile.am.autoxxx lua-5.3.0/doc/Makefile.am +--- lua-5.3.0/doc/Makefile.am.autoxxx 2015-01-15 10:20:03.826889574 -0500 ++++ lua-5.3.0/doc/Makefile.am 2015-01-15 10:20:03.826889574 -0500 +@@ -0,0 +1,4 @@ ++man1_MANS = lua.1 luac.1 ++ ++EXTRA_DIST = \ ++ contents.html logo.gif lua.1 luac.1 lua.css manual.css manual.html osi-certified-72x60.png readme.html +diff -up lua-5.3.0/Makefile.am.autoxxx lua-5.3.0/Makefile.am +--- lua-5.3.0/Makefile.am.autoxxx 2015-01-15 10:20:03.826889574 -0500 ++++ lua-5.3.0/Makefile.am 2015-01-15 10:20:03.826889574 -0500 +@@ -0,0 +1,3 @@ ++SUBDIRS = src doc ++ ++EXTRA_DIST = README +diff -up lua-5.3.0/src/.gitignore.autoxxx lua-5.3.0/src/.gitignore +--- lua-5.3.0/src/.gitignore.autoxxx 2015-01-15 10:20:03.826889574 -0500 ++++ lua-5.3.0/src/.gitignore 2015-01-15 10:20:03.826889574 -0500 +@@ -0,0 +1,5 @@ ++lua ++lua.pc ++luac ++luaconf.h ++luaconf.h.template +diff -up lua-5.3.0/src/luaconf.h.template.in.autoxxx lua-5.3.0/src/luaconf.h.template.in +--- lua-5.3.0/src/luaconf.h.template.in.autoxxx 2015-01-15 10:20:03.828889562 -0500 ++++ lua-5.3.0/src/luaconf.h.template.in 2015-01-15 10:22:37.420027778 -0500 +@@ -11,6 +11,11 @@ + #include <limits.h> + #include <stddef.h> + ++@POSIX_DEFS@ ++@LUA_DL_DEFS@ ++@LUA_BUILD_AS_DLL_DEFS@ ++@READLINE_DEFS@ ++ + + /* + ** =================================================================== +@@ -175,9 +180,9 @@ + + #else /* }{ */ + +-#define LUA_ROOT "/usr/local/" +-#define LUA_LDIR LUA_ROOT "share/lua/" LUA_VDIR "/" +-#define LUA_CDIR LUA_ROOT "lib/lua/" LUA_VDIR "/" ++#define LUA_ROOT "@prefix@/" ++#define LUA_LDIR "@pkgdatadir@/lua/" LUA_VDIR "/" ++#define LUA_CDIR "@libdir@/lua/" LUA_VDIR "/" + #define LUA_PATH_DEFAULT \ + LUA_LDIR"?.lua;" LUA_LDIR"?/init.lua;" \ + LUA_CDIR"?.lua;" LUA_CDIR"?/init.lua;" \ +diff -up lua-5.3.0/src/lua.pc.in.autoxxx lua-5.3.0/src/lua.pc.in +--- lua-5.3.0/src/lua.pc.in.autoxxx 2015-01-15 10:20:03.827889568 -0500 ++++ lua-5.3.0/src/lua.pc.in 2015-01-15 10:20:03.827889568 -0500 +@@ -0,0 +1,13 @@ ++V= @MAJOR_VERSION@ ++R= @VERSION@ ++prefix= @prefix@ ++exec_prefix=${prefix} ++libdir= @libdir@ ++includedir=${prefix}/include ++ ++Name: Lua ++Description: An Extensible Extension Language ++Version: ${R} ++Requires: ++Libs: -llua @LUA_LIBS@ ++Cflags: -I${includedir} +diff -up lua-5.3.0/src/Makefile.am.autoxxx lua-5.3.0/src/Makefile.am +--- lua-5.3.0/src/Makefile.am.autoxxx 2015-01-15 10:20:03.826889574 -0500 ++++ lua-5.3.0/src/Makefile.am 2015-01-15 10:20:03.826889574 -0500 +@@ -0,0 +1,46 @@ ++AM_CFLAGS = -Wall ++ ++include_HEADERS = lua.h lualib.h lauxlib.h lua.hpp ++ ++nodist_include_HEADERS = luaconf.h ++ ++lib_LTLIBRARIES = liblua.la ++liblua_la_LDFLAGS = -release @MAJOR_VERSION@ ++liblua_la_SOURCES = \ ++ lapi.c lauxlib.c lbaselib.c lbitlib.c lcode.c lcorolib.c lctype.c ldblib.c \ ++ ldebug.c ldo.c ldump.c lfunc.c lgc.c linit.c liolib.c llex.c lmathlib.c lmem.c \ ++ loadlib.c lobject.c lopcodes.c loslib.c lparser.c lstate.c lstring.c lstrlib.c \ ++ ltable.c ltablib.c ltm.c lundump.c lutf8lib.c lvm.c lzio.c \ ++ lapi.h lcode.h lctype.h ldebug.h ldo.h lfunc.h lgc.h llex.h llimits.h \ ++ lmem.h lobject.h lopcodes.h lparser.h lstate.h lstring.h ltable.h ltm.h \ ++ lundump.h lvm.h lzio.h ++ ++pkgconfigdir = $(libdir)/pkgconfig ++pkgconfig_DATA = lua.pc ++ ++bin_PROGRAMS = lua luac ++ ++lua_SOURCES = lua.c ++lua_LDADD = liblua.la @LUA_LIBS@ @READLINE_LIBS@ ++lua_DEPENDENCIES = liblua.la ++ ++luac_SOURCES = luac.c ++# Statically link liblua against luac since luac uses symbols not exported in liblua ++luac_LDADD = .libs/liblua.a @LUA_LIBS@ ++luac_DEPENDENCIES = liblua.la ++ ++EXTRA_DIST = luaconf.h.template ++BUILT_SOURCES = luaconf.h ++CLEANFILES = luaconf.h luaconf.h.template ++ ++readline_defs = @READLINE_DEFS@ ++ ++edit = sed \ ++ -e 's,%prefix%,$(prefix),g' \ ++ -e 's,%lua_datadir%,$(datadir),g' \ ++ -e 's,%lua_libdir%,$(libdir),g' ++ ++luaconf.h : luaconf.h.template ++ rm -f $@ $@.tmp ++ $(edit) $< >$@.tmp ++ mv $@.tmp $@ diff --git a/subprojects/shared-modules/lua5.3/lua-5.3.0-configure-compat-module.patch b/subprojects/shared-modules/lua5.3/lua-5.3.0-configure-compat-module.patch new file mode 100644 index 00000000..bd5d41d4 --- /dev/null +++ b/subprojects/shared-modules/lua5.3/lua-5.3.0-configure-compat-module.patch @@ -0,0 +1,35 @@ +diff -up lua-5.2.2/configure.ac.compat-module lua-5.2.2/configure.ac +--- lua-5.2.2/configure.ac.compat-module 2013-05-10 10:16:05.344137597 -0400 ++++ lua-5.2.2/configure.ac 2013-05-10 10:16:05.357137596 -0400 +@@ -11,6 +11,20 @@ AC_PROG_CC + AC_PROG_LIBTOOL + + AC_ARG_WITH( ++ [compat-module], ++ [AC_HELP_STRING([--with-compat-module], [Enable LUA_COMPAT_MODULE functions [default=no]])], ++ [use_compat_module=$withval], ++ [use_compat_module=no] ++) ++ ++COMPAT_DEFS="#undef LUA_COMPAT_ALL" ++if test "x$use_compat_module" == "xyes"; then ++ COMPAT_DEFS="#define LUA_COMPAT_5_1 ++#define LUA_COMPAT_5_2" ++fi ++AC_SUBST(COMPAT_DEFS) ++ ++AC_ARG_WITH( + [readline], + [AC_HELP_STRING([--with-readline], [Use readline for interpreter input [default=yes]])], + [use_readline=$withval], +diff -up lua-5.2.2/src/luaconf.h.template.in.compat-module lua-5.2.2/src/luaconf.h.template.in +--- lua-5.2.2/src/luaconf.h.template.in.compat-module 2013-05-10 10:25:42.586116963 -0400 ++++ lua-5.2.2/src/luaconf.h.template.in 2013-05-10 10:26:29.957115269 -0400 +@@ -15,6 +15,7 @@ + @LUA_DL_DEFS@ + @LUA_BUILD_AS_DLL_DEFS@ + @READLINE_DEFS@ ++@COMPAT_DEFS@ + + + /* diff --git a/subprojects/shared-modules/lua5.3/lua-5.3.0-idsize.patch b/subprojects/shared-modules/lua5.3/lua-5.3.0-idsize.patch new file mode 100644 index 00000000..16107fe2 --- /dev/null +++ b/subprojects/shared-modules/lua5.3/lua-5.3.0-idsize.patch @@ -0,0 +1,12 @@ +diff -up lua-5.3.0/src/luaconf.h.template.in.idsize lua-5.3.0/src/luaconf.h.template.in +--- lua-5.3.0/src/luaconf.h.template.in.idsize 2015-01-15 10:23:20.515801344 -0500 ++++ lua-5.3.0/src/luaconf.h.template.in 2015-01-15 10:23:48.955651916 -0500 +@@ -693,7 +693,7 @@ + @@ of a function in debug information. + ** CHANGE it if you want a different size. + */ +-#define LUA_IDSIZE 60 ++#define LUA_IDSIZE 512 + + + /* diff --git a/subprojects/shared-modules/lua5.3/lua-5.3.5.json b/subprojects/shared-modules/lua5.3/lua-5.3.5.json new file mode 100644 index 00000000..fd5f2682 --- /dev/null +++ b/subprojects/shared-modules/lua5.3/lua-5.3.5.json @@ -0,0 +1,34 @@ +{ + "name": "lua-5.3", + "config-opts": [ + "--with-compat-module" + ], + "sources": [ + { + "type": "archive", + "url": "https://www.lua.org/ftp/lua-5.3.5.tar.gz", + "sha256": "0c2eed3f960446e1a3e4b9a1ca2f3ff893b6ce41942cf54d5dd59ab4b3b058ac" + }, + { + "type": "shell", + "commands": [ "mv src/luaconf.h src/luaconf.h.template.in" ] + }, + { + "type": "patch", + "path": "lua-5.3.0-autotoolize.patch" + }, + { + "type": "patch", + "path": "lua-5.3.0-idsize.patch" + }, + { + "type": "patch", + "path": "lua-5.3.0-configure-compat-module.patch" + }, + { + "type": "shell", + "commands": [ "autoreconf -i" ] + } + ], + "cleanup": [ "/bin", "/include", "/lib/pkgconfig", "/lib/*.a", "/lib/*.la", "/share/man" ] +} diff --git a/subprojects/shared-modules/openjpeg/openjpeg.json b/subprojects/shared-modules/openjpeg/openjpeg.json new file mode 100644 index 00000000..5eefa4c8 --- /dev/null +++ b/subprojects/shared-modules/openjpeg/openjpeg.json @@ -0,0 +1,25 @@ +{ + "name": "openjpeg", + "buildsystem": "cmake-ninja", + "builddir": true, + "config-opts": [ + "-DCMAKE_BUILD_TYPE=RelWithDebInfo", + "-DBUILD_CODEC:BOOL=OFF", + "-DBUILD_DOC:BOOL=OFF", + "-DBUILD_STATIC_LIBS:BOOL=OFF", + "-DBUILD_TESTING:BOOL=OFF" + ], + "sources": [ + { + "type": "archive", + "url": "https://github.com/uclouvain/openjpeg/archive/v2.3.1.tar.gz", + "sha256": "63f5a4713ecafc86de51bfad89cc07bb788e9bba24ebbf0c4ca637621aadb6a9" + } + ], + "cleanup": [ + "/include", + "/lib/openjpeg-*", + "/lib/pkgconfig", + "/share" + ] +} diff --git a/subprojects/shared-modules/pygame/audiofile-gcc6.patch b/subprojects/shared-modules/pygame/audiofile-gcc6.patch new file mode 100644 index 00000000..89afb6d8 --- /dev/null +++ b/subprojects/shared-modules/pygame/audiofile-gcc6.patch @@ -0,0 +1,21 @@ +From b62c902dd258125cac86cd2df21fc898035a43d3 Mon Sep 17 00:00:00 2001 +From: Michael Pruett <michael@68k.org> +Date: Mon, 29 Aug 2016 23:08:26 -0500 +Subject: [PATCH] Fix undefined behavior in sign conversion. +Origin: https://github.com/mpruett/audiofile/commit/b62c902dd258125cac86cd2df21fc898035a43d3 + +--- +diff --git a/libaudiofile/modules/SimpleModule.h b/libaudiofile/modules/SimpleModule.h +index 03c6c69..bad85ad 100644 +--- a/libaudiofile/modules/SimpleModule.h ++++ b/libaudiofile/modules/SimpleModule.h +@@ -123,7 +123,8 @@ struct signConverter + typedef typename IntTypes<Format>::UnsignedType UnsignedType; + + static const int kScaleBits = (Format + 1) * CHAR_BIT - 1; +- static const int kMinSignedValue = -1 << kScaleBits; ++ static const int kMaxSignedValue = (((1 << (kScaleBits - 1)) - 1) << 1) + 1; ++ static const int kMinSignedValue = -kMaxSignedValue - 1; + + struct signedToUnsigned : public std::unary_function<SignedType, UnsignedType> + { diff --git a/subprojects/shared-modules/pygame/fluidsynth-no-rawmidi.patch b/subprojects/shared-modules/pygame/fluidsynth-no-rawmidi.patch new file mode 100644 index 00000000..88a89742 --- /dev/null +++ b/subprojects/shared-modules/pygame/fluidsynth-no-rawmidi.patch @@ -0,0 +1,69 @@ +diff -rupN fluidsynth-1.1.6.orig/src/drivers/fluid_alsa.c fluidsynth-1.1.6/src/drivers/fluid_alsa.c +--- fluidsynth-1.1.6.orig/src/drivers/fluid_alsa.c 2012-08-16 05:01:13.000000000 +0100 ++++ fluidsynth-1.1.6/src/drivers/fluid_alsa.c 2017-02-28 21:26:57.033244239 +0000 +@@ -96,7 +96,7 @@ struct fluid_alsa_formats_t fluid_alsa_f + }; + + +- ++#if 0 + /* + * fluid_alsa_rawmidi_driver_t + * +@@ -119,7 +119,7 @@ fluid_midi_driver_t* new_fluid_alsa_rawm + + int delete_fluid_alsa_rawmidi_driver(fluid_midi_driver_t* p); + static void fluid_alsa_midi_run(void* d); +- ++#endif + + /* + * fluid_alsa_seq_driver_t +@@ -535,7 +535,7 @@ static void fluid_alsa_audio_run_s16 (vo + * + */ + +- ++#if 0 + void fluid_alsa_rawmidi_driver_settings(fluid_settings_t* settings) + { + fluid_settings_register_str(settings, "midi.alsa.device", "default", 0, NULL, NULL); +@@ -698,7 +698,7 @@ fluid_alsa_midi_run(void* d) + } + } + } +- ++#endif + /************************************************************** + * + * Alsa sequencer +diff -rupN fluidsynth-1.1.6.orig/src/drivers/fluid_mdriver.c fluidsynth-1.1.6/src/drivers/fluid_mdriver.c +--- fluidsynth-1.1.6.orig/src/drivers/fluid_mdriver.c 2012-08-16 05:01:13.000000000 +0100 ++++ fluidsynth-1.1.6/src/drivers/fluid_mdriver.c 2017-02-28 21:24:43.887833321 +0000 +@@ -24,11 +24,13 @@ + + /* ALSA */ + #if ALSA_SUPPORT ++#if 0 + fluid_midi_driver_t* new_fluid_alsa_rawmidi_driver(fluid_settings_t* settings, + handle_midi_event_func_t handler, + void* event_handler_data); + int delete_fluid_alsa_rawmidi_driver(fluid_midi_driver_t* p); + void fluid_alsa_rawmidi_driver_settings(fluid_settings_t* settings); ++#endif + + fluid_midi_driver_t* new_fluid_alsa_seq_driver(fluid_settings_t* settings, + handle_midi_event_func_t handler, +@@ -109,10 +111,12 @@ struct fluid_mdriver_definition_t fluid_ + fluid_oss_midi_driver_settings }, + #endif + #if ALSA_SUPPORT ++#if 0 + { "alsa_raw", + new_fluid_alsa_rawmidi_driver, + delete_fluid_alsa_rawmidi_driver, + fluid_alsa_rawmidi_driver_settings }, ++#endif + { "alsa_seq", + new_fluid_alsa_seq_driver, + delete_fluid_alsa_seq_driver, diff --git a/subprojects/shared-modules/pygame/portmidi-no-java.patch b/subprojects/shared-modules/pygame/portmidi-no-java.patch new file mode 100644 index 00000000..00ef8eaa --- /dev/null +++ b/subprojects/shared-modules/pygame/portmidi-no-java.patch @@ -0,0 +1,105 @@ +diff -rupN portmidi.orig/CMakeLists.txt portmidi/CMakeLists.txt +--- portmidi.orig/CMakeLists.txt 2010-09-20 15:57:48.000000000 +0100 ++++ portmidi/CMakeLists.txt 2017-03-03 13:50:58.494561245 +0000 +@@ -71,7 +71,3 @@ add_subdirectory(pm_common) + add_subdirectory(pm_test) + + add_subdirectory(pm_dylib) +- +-# Cannot figure out how to make an xcode Java application with CMake +-add_subdirectory(pm_java) +- +diff -rupN portmidi.orig/pm_common/CMakeLists.txt portmidi/pm_common/CMakeLists.txt +--- portmidi.orig/pm_common/CMakeLists.txt 2010-09-20 15:57:48.000000000 +0100 ++++ portmidi/pm_common/CMakeLists.txt 2017-03-03 14:02:32.851938051 +0000 +@@ -67,14 +67,6 @@ if(UNIX) + message(STATUS "SYSROOT: " ${CMAKE_OSX_SYSROOT}) + else(APPLE) + # LINUX settings... +- include(FindJNI) +- message(STATUS "JAVA_JVM_LIB_PATH is " ${JAVA_JVM_LIB_PATH}) +- message(STATUS "JAVA_INCLUDE_PATH is " ${JAVA_INCLUDE_PATH}) +- message(STATUS "JAVA_INCLUDE_PATH2 is " ${JAVA_INCLUDE_PATH2}) +- message(STATUS "JAVA_JVM_LIBRARY is " ${JAVA_JVM_LIBRARY}) +- set(JAVA_INCLUDE_PATHS ${JAVA_INCLUDE_PATH} ${JAVA_INCLUDE_PATH2}) +- # libjvm.so is found relative to JAVA_INCLUDE_PATH: +- set(JAVAVM_LIB ${JAVA_JVM_LIBRARY}/libjvm.so) + + set(LINUXSRC pmlinuxalsa pmlinux finddefault) + prepend_path(LIBSRC ../pm_linux/ ${LINUXSRC}) +@@ -99,7 +91,6 @@ else(UNIX) + set(PM_NEEDED_LIBS winmm.lib) + endif(WIN32) + endif(UNIX) +-set(JNI_EXTRA_LIBS ${PM_NEEDED_LIBS} ${JAVA_JVM_LIBRARY}) + + # this completes the list of library sources by adding shared code + list(APPEND LIBSRC pmutil portmidi) +@@ -109,19 +100,11 @@ add_library(portmidi-static ${LIBSRC}) + set_target_properties(portmidi-static PROPERTIES OUTPUT_NAME "portmidi_s") + target_link_libraries(portmidi-static ${PM_NEEDED_LIBS}) + +-# define the jni library +-include_directories(${JAVA_INCLUDE_PATHS}) +- +-set(JNISRC ${LIBSRC} ../pm_java/pmjni/pmjni.c) +-add_library(pmjni SHARED ${JNISRC}) +-target_link_libraries(pmjni ${JNI_EXTRA_LIBS}) +-set_target_properties(pmjni PROPERTIES EXECUTABLE_EXTENSION "jnilib") +- + # install the libraries (Linux and Mac OS X command line) + if(UNIX) +- INSTALL(TARGETS portmidi-static pmjni +- LIBRARY DESTINATION /usr/local/lib +- ARCHIVE DESTINATION /usr/local/lib) ++ INSTALL(TARGETS portmidi-static ++ LIBRARY DESTINATION /app/lib ++ ARCHIVE DESTINATION /app/lib) + # .h files installed by pm_dylib/CMakeLists.txt, so don't need them here + # INSTALL(FILES portmidi.h ../porttime/porttime.h + # DESTINATION /usr/local/include) +diff -rupN portmidi.orig/pm_dylib/CMakeLists.txt portmidi/pm_dylib/CMakeLists.txt +--- portmidi.orig/pm_dylib/CMakeLists.txt 2009-11-20 00:41:10.000000000 +0000 ++++ portmidi/pm_dylib/CMakeLists.txt 2017-03-03 14:03:56.807104521 +0000 +@@ -63,7 +63,6 @@ if(UNIX) + message(STATUS "SYSROOT: " ${CMAKE_OSX_SYSROOT}) + else(APPLE) + # LINUX settings... +- include(FindJNI) + # message(STATUS "JAVA_JVM_LIB_PATH is " ${JAVA_JVM_LIB_PATH}) + # message(STATUS "JAVA_INCLUDE_PATH is " ${JAVA_INCLUDE_PATH}) + # note: should use JAVA_JVM_LIB_PATH, but it is not set properly +@@ -75,12 +74,7 @@ if(UNIX) + # JAVA_INCLUDE_PATH2; if no, then we need to make both JAVA_INCLUDE_PATH + # and JAVA_INCLUDE_PATH2 set by user (will need clear documentation + # because JAVA_INCLUDE_PATH2 is pretty obscure) +- set(JAVA_INCLUDE_PATH ${JAVA_INCLUDE_PATH-UNKNOWN} +- CACHE STRING "where to find Java SDK include directory") +- set(JAVA_INCLUDE_PATHS ${JAVA_INCLUDE_PATH} ${JAVA_INCLUDE_PATH}/linux) +- # libjvm.so is found relative to JAVA_INCLUDE_PATH: +- set(JAVAVM_LIB ${JAVA_INCLUDE_PATH}/../jre/lib/i386/client/libjvm.so) +- ++ + set(LINUXSRC pmlinuxalsa pmlinux finddefault) + prepend_path(LIBSRC ../pm_linux/ ${LINUXSRC}) + list(APPEND LIBSRC ../porttime/ptlinux) +@@ -106,7 +100,6 @@ else(UNIX) + # message(STATUS "JAVAVM_LIB: " ${JAVAVM_LIB}) + endif(WIN32) + endif(UNIX) +-set(JNI_EXTRA_LIBS ${PM_NEEDED_LIBS} ${JAVAVM_LIB}) + + # this completes the list of library sources by adding shared code + set(SHARED_FILES pmutil portmidi) +@@ -120,8 +113,8 @@ target_link_libraries(portmidi-dynamic $ + # install the libraries (Linux and Mac OS X command line) + if(UNIX) + INSTALL(TARGETS portmidi-dynamic +- LIBRARY DESTINATION /usr/local/lib +- ARCHIVE DESTINATION /usr/local/lib) ++ LIBRARY DESTINATION /app/lib ++ ARCHIVE DESTINATION /app/lib) + INSTALL(FILES ../pm_common/portmidi.h ../porttime/porttime.h +- DESTINATION /usr/local/include) ++ DESTINATION /app/include) + endif(UNIX) diff --git a/subprojects/shared-modules/pygame/pygame-1.9.4.json b/subprojects/shared-modules/pygame/pygame-1.9.4.json new file mode 100644 index 00000000..b80e892d --- /dev/null +++ b/subprojects/shared-modules/pygame/pygame-1.9.4.json @@ -0,0 +1,112 @@ +{ + "name": "pygame", + "sources": [ + { + "type": "archive", + "url": "https://files.pythonhosted.org/packages/b2/6b/c510f0853765eb2219ca5aa3d416d65bb0dea7cd9bb2984aea0a0e04c24d/pygame-1.9.4.tar.gz", + "sha256": "700d1781c999af25d11bfd1f3e158ebb660f72ebccb2040ecafe5069d0b2c0b6" + } + ], + "buildsystem": "simple", + "build-commands": [ + "pip3 install --ignore-installed --no-deps --prefix=/app ." + ], + "build-options": { + "env": { + "PORTMIDI_INC_PORTTIME": "1", + "PYGAME_EXTRA_BASE": "/app" + }, + "arch": { + "aarch64": { + "env": { + "ORIGLIBDIRS": "/lib:/lib64:/lib/aarch64-linux-gnu" + } + }, + "arm": { + "env": { + "ORIGLIBDIRS": "/lib:/lib/arm-linux-gnueabihf" + } + }, + "i386": { + "env": { + "ORIGLIBDIRS": "/lib:/lib/i386-linux-gnu" + } + }, + "x86_64": { + "env": { + "ORIGLIBDIRS": "/lib:/lib64:/lib/x86_64-linux-gnu" + } + } + } + }, + "modules": [ + "../SDL/SDL-1.2.15.json", + "../SDL/SDL_image-1.2.12.json", + "../SDL/SDL_ttf-2.0.11.json", + "../smpeg/smpeg-0.4.5.json", + "../SDL/SDL_mixer-1.2.12.json", + { + "name": "audiofile", + "sources": [ + { + "type": "archive", + "url": "http://audiofile.68k.org/audiofile-0.3.6.tar.gz", + "sha256": "cdc60df19ab08bfe55344395739bb08f50fc15c92da3962fac334d3bff116965" + }, + { + "type": "patch", + "path": "audiofile-gcc6.patch" + } + ] + }, + { + "name": "libmikmod", + "sources": [ + { + "type": "archive", + "url": "https://sourceforge.net/projects/mikmod/files/libmikmod/3.3.11.1/libmikmod-3.3.11.1.tar.gz", + "sha256": "ad9d64dfc8f83684876419ea7cd4ff4a41d8bcd8c23ef37ecb3a200a16b46d19" + } + ] + }, + { + "name": "fluidsynth", + "buildsystem": "cmake-ninja", + "config-opts": [ + "-DCMAKE_BUILD_TYPE=Release" + ], + "sources": [ + { + "type": "archive", + "url": "https://downloads.sourceforge.net/project/fluidsynth/fluidsynth-1.1.6/fluidsynth-1.1.6.tar.bz2", + "sha256": "d28b47dfbf7f8e426902ae7fa2981d821fbf84f41da9e1b85be933d2d748f601" + }, + { + "type": "patch", + "path": "fluidsynth-no-rawmidi.patch" + } + ] + }, + { + "name": "portmidi", + "buildsystem": "cmake-ninja", + "config-opts": [ + "-DCMAKE_BUILD_TYPE=Release", + "-DCMAKE_LIBRARY_OUTPUT_DIRECTORY:STRING=/app/lib", + "-DCMAKE_ARCHIVE_OUTPUT_DIRECTORY:STRING=/app/lib", + "-DCMAKE_RUNTIME_OUTPUT_DIRECTORY:STRING=/app/bin" + ], + "sources": [ + { + "type": "archive", + "url": "http://downloads.sourceforge.net/project/portmedia/portmidi/217/portmidi-src-217.zip", + "sha256": "08e9a892bd80bdb1115213fb72dc29a7bf2ff108b378180586aa65f3cfd42e0f" + }, + { + "type": "patch", + "path": "portmidi-no-java.patch" + } + ] + } + ] +} diff --git a/subprojects/shared-modules/python2.7/python-2.7.json b/subprojects/shared-modules/python2.7/python-2.7.json new file mode 100644 index 00000000..14253764 --- /dev/null +++ b/subprojects/shared-modules/python2.7/python-2.7.json @@ -0,0 +1,52 @@ +{ + "name": "python-2.7", + "sources": [ + { + "type": "archive", + "url": "https://www.python.org/ftp/python/2.7.17/Python-2.7.17.tar.xz", + "sha256": "4d43f033cdbd0aa7b7023c81b0e986fd11e653b5248dac9144d508f11812ba41" + } + ], + "config-opts": [ + "--enable-shared", + "--with-ensurepip=yes", + "--with-system-expat", + "--with-system-ffi", + "--enable-loadable-sqlite-extensions", + "--with-dbmliborder=gdbm", + "--enable-unicode=ucs4" + ], + "post-install": [ + /* Theres seem to be a permissions missmatch that causes the debug stripping to fail */ + "chmod 644 $FLATPAK_DEST/lib/libpython2.7.so.1.0" + ], + "cleanup": [ + "/bin/2to3*", + "/bin/easy_install*", + "/bin/idle*", + "/bin/pydoc*", + "/bin/python*-config", + "/bin/pyvenv*", + "/include", + "/lib/pkgconfig", + "/lib/python*/config", + "/share", + + /* Test scripts */ + "/lib/python*/test", + "/lib/python*/*/test", + "/lib/python*/*/tests", + "/lib/python*/lib-tk/test", + "/lib/python*/lib-dynload/_*_test.*.so", + "/lib/python*/lib-dynload/_test*.*.so", + + /* Unused modules */ + "/lib/python*/idlelib", + "/lib/python*/tkinter*", + "/lib/python*/turtle*", + "/lib/python*/lib2to3*", + + /* Static library */ + "/lib/python2.7/config/libpython2.7.a" + ] +} diff --git a/subprojects/shared-modules/qt4/disable-sslv3.patch b/subprojects/shared-modules/qt4/disable-sslv3.patch new file mode 100644 index 00000000..5ebd9741 --- /dev/null +++ b/subprojects/shared-modules/qt4/disable-sslv3.patch @@ -0,0 +1,54 @@ +diff -u -r qt-everywhere-opensource-src-4.8.7/src/network/ssl/qsslsocket_openssl.cpp qt-everywhere-opensource-src-4.8.7-nossl3/src/network/ssl/qsslsocket_openssl.cpp +--- qt-everywhere-opensource-src-4.8.7/src/network/ssl/qsslsocket_openssl.cpp 2015-05-07 16:14:44.000000000 +0200 ++++ qt-everywhere-opensource-src-4.8.7-nossl3/src/network/ssl/qsslsocket_openssl.cpp 2016-03-04 11:29:17.119300898 +0100 +@@ -267,7 +267,11 @@ + #endif + break; + case QSsl::SslV3: ++#ifndef OPENSSL_NO_SSL3 + ctx = q_SSL_CTX_new(client ? q_SSLv3_client_method() : q_SSLv3_server_method()); ++#else ++ ctx = 0; // SSL 3 not supported by the system, but chosen deliberately -> error ++#endif + break; + case QSsl::SecureProtocols: // SslV2 will be disabled below + case QSsl::TlsV1SslV3: // SslV2 will be disabled below +diff -u -r qt-everywhere-opensource-src-4.8.7/src/network/ssl/qsslsocket_openssl_symbols.cpp qt-everywhere-opensource-src-4.8.7-nossl3/src/network/ssl/qsslsocket_openssl_symbols.cpp +--- qt-everywhere-opensource-src-4.8.7/src/network/ssl/qsslsocket_openssl_symbols.cpp 2015-05-07 16:14:44.000000000 +0200 ++++ qt-everywhere-opensource-src-4.8.7-nossl3/src/network/ssl/qsslsocket_openssl_symbols.cpp 2016-03-04 11:28:52.806050135 +0100 +@@ -228,13 +228,17 @@ + #ifndef OPENSSL_NO_SSL2 + DEFINEFUNC(const SSL_METHOD *, SSLv2_client_method, DUMMYARG, DUMMYARG, return 0, return) + #endif ++#ifndef OPENSSL_NO_SSL3 + DEFINEFUNC(const SSL_METHOD *, SSLv3_client_method, DUMMYARG, DUMMYARG, return 0, return) ++#endif + DEFINEFUNC(const SSL_METHOD *, SSLv23_client_method, DUMMYARG, DUMMYARG, return 0, return) + DEFINEFUNC(const SSL_METHOD *, TLSv1_client_method, DUMMYARG, DUMMYARG, return 0, return) + #ifndef OPENSSL_NO_SSL2 + DEFINEFUNC(const SSL_METHOD *, SSLv2_server_method, DUMMYARG, DUMMYARG, return 0, return) + #endif ++#ifndef OPENSSL_NO_SSL3 + DEFINEFUNC(const SSL_METHOD *, SSLv3_server_method, DUMMYARG, DUMMYARG, return 0, return) ++#endif + DEFINEFUNC(const SSL_METHOD *, SSLv23_server_method, DUMMYARG, DUMMYARG, return 0, return) + DEFINEFUNC(const SSL_METHOD *, TLSv1_server_method, DUMMYARG, DUMMYARG, return 0, return) + #else +@@ -822,13 +826,17 @@ + #ifndef OPENSSL_NO_SSL2 + RESOLVEFUNC(SSLv2_client_method) + #endif ++#ifndef OPENSSL_NO_SSL3 + RESOLVEFUNC(SSLv3_client_method) ++#endif + RESOLVEFUNC(SSLv23_client_method) + RESOLVEFUNC(TLSv1_client_method) + #ifndef OPENSSL_NO_SSL2 + RESOLVEFUNC(SSLv2_server_method) + #endif ++#ifndef OPENSSL_NO_SSL3 + RESOLVEFUNC(SSLv3_server_method) ++#endif + RESOLVEFUNC(SSLv23_server_method) + RESOLVEFUNC(TLSv1_server_method) + RESOLVEFUNC(X509_NAME_entry_count) diff --git a/subprojects/shared-modules/qt4/qt4-4.8.7-minimal.json b/subprojects/shared-modules/qt4/qt4-4.8.7-minimal.json new file mode 100644 index 00000000..fe7b74a4 --- /dev/null +++ b/subprojects/shared-modules/qt4/qt4-4.8.7-minimal.json @@ -0,0 +1,110 @@ +{ + "name": "qt4", + "config-opts": [ + "-verbose", + "-confirm-license", + "-opensource", + "-release", + "-shared", + "-no-static", + "-fast", + "-datadir", "/app/lib/qt4", + "-importdir", "/app/lib/qt4/imports", + "-plugindir", "/app/lib/qt4/plugins", + "-translationdir", "/app/share/qt4/translations", + "-accessibility", + "-exceptions", + "-fontconfig", + "-glib", + "-dbus-linked", + "-openssl-linked", + "-optimized-qmake", + "-system-libjpeg", + "-system-libpng", + "-system-libtiff", + "-system-proxies", + "-system-zlib", + "-no-cups", + "-no-declarative", + "-no-gtkstyle", + "-no-javascript-jit", + "-no-libmng", + "-no-multimedia", + "-no-nis", + "-no-opengl", + "-no-phonon", + "-no-phonon-backend", + "-no-qt3support", + "-no-rpath", + "-no-script", + "-no-scripttools", + "-no-sql-db2", + "-no-sql-ibase", + "-no-sql-mysql", + "-no-sql-oci", + "-no-sql-odbc", + "-no-sql-psql", + "-no-sql-sqlite", + "-no-sql-sqlite2", + "-no-sql-sqlite_symbian", + "-no-sql-symsql", + "-no-sql-tds", + "-no-svg", + "-no-webkit", + "-no-xmlpatterns", + "-nomake", "demos", + "-nomake", "docs", + "-nomake", "examples" + ], + "build-options": { + "env": { + "CXXFLAGS": "-std=gnu++98 -O2", + "LD_LIBRARY_PATH": "/run/build/qt4/lib/" + } + }, + "sources": [ + { + "type": "archive", + "url": "https://download.qt.io/archive/qt/4.8/4.8.7/qt-everywhere-opensource-src-4.8.7.tar.gz", + "sha256": "e2882295097e47fe089f8ac741a95fef47e0a73a3f3cdf21b56990638f626ea0" + }, + { + "type": "patch", + "path": "qt4-aarch64.patch" + }, + { + "type": "patch", + "path": "disable-sslv3.patch" + }, + { + "type": "shell", + "commands": [ + "sed -i \"s|-O2|${CXXFLAGS}|\" mkspecs/common/{g++,gcc}-base.conf", + "sed -i \"/^QMAKE_LFLAGS_RPATH/s| -Wl,-rpath,||g\" mkspecs/common/gcc-base-unix.conf", + "sed -i \"/^QMAKE_LFLAGS\s/s|+=|+= ${LDFLAGS}|g\" mkspecs/common/gcc-base.conf" + ] + }, + { + "type": "file", + "path": "qt4-openssl-1.1.patch" + }, + { + "type": "shell", + "commands": [ + "echo -e '#include<openssl/opensslv.h>\nint main(){return OPENSSL_VERSION_NUMBER>=0x010100000L?0:1;}' >has_openssl_1_1.c", + "gcc ${CFLAGS} has_openssl_1_1.c -o has_openssl_1_1", + "if ./has_openssl_1_1; then patch -p1 -i qt4-openssl-1.1.patch; fi" + ] + } + ], + "cleanup": [ + "/bin", + "/include", + "/lib/*.a", + "/lib/*.la", + "/lib/*.prl", + "/lib/pkgconfig", + "/lib/qt4/mkspecs", + "/lib/qt4/q3porting.xml" + ] +} diff --git a/subprojects/shared-modules/qt4/qt4-aarch64.patch b/subprojects/shared-modules/qt4/qt4-aarch64.patch new file mode 100644 index 00000000..cbe815de --- /dev/null +++ b/subprojects/shared-modules/qt4/qt4-aarch64.patch @@ -0,0 +1,514 @@ +diff -up qt-everywhere-opensource-src-4.8.7/include/QtCore/headers.pri.aarch64 qt-everywhere-opensource-src-4.8.7/include/QtCore/headers.pri +--- qt-everywhere-opensource-src-4.8.7/include/QtCore/headers.pri.aarch64 2015-05-08 21:48:32.714057739 -0500 ++++ qt-everywhere-opensource-src-4.8.7/include/QtCore/headers.pri 2015-05-08 21:53:21.088761971 -0500 +@@ -1,3 +1,3 @@ +-SYNCQT.HEADER_FILES = ../corelib/kernel/qabstracteventdispatcher.h ../corelib/kernel/qabstractitemmodel.h ../corelib/kernel/qbasictimer.h ../corelib/kernel/qcoreapplication.h ../corelib/kernel/qcoreevent.h ../corelib/kernel/qeventloop.h ../corelib/kernel/qfunctions_nacl.h ../corelib/kernel/qfunctions_vxworks.h ../corelib/kernel/qfunctions_wince.h ../corelib/kernel/qmath.h ../corelib/kernel/qmetaobject.h ../corelib/kernel/qmetatype.h ../corelib/kernel/qmimedata.h ../corelib/kernel/qobject.h ../corelib/kernel/qobjectcleanuphandler.h ../corelib/kernel/qobjectdefs.h ../corelib/kernel/qpointer.h ../corelib/kernel/qsharedmemory.h ../corelib/kernel/qsignalmapper.h ../corelib/kernel/qsocketnotifier.h ../corelib/kernel/qsystemsemaphore.h ../corelib/kernel/qtimer.h ../corelib/kernel/qtranslator.h ../corelib/kernel/qvariant.h ../corelib/animation/qabstractanimation.h ../corelib/animation/qanimationgroup.h ../corelib/animation/qparallelanimationgroup.h ../corelib/animation/qpauseanimation.h ../corelib/animation/qpropertyanimation.h ../corelib/animation/qsequentialanimationgroup.h ../corelib/animation/qvariantanimation.h ../corelib/arch/qatomic_alpha.h ../corelib/arch/qatomic_arch.h ../corelib/arch/qatomic_arm.h ../corelib/arch/qatomic_armv5.h ../corelib/arch/qatomic_armv6.h ../corelib/arch/qatomic_armv7.h ../corelib/arch/qatomic_avr32.h ../corelib/arch/qatomic_bfin.h ../corelib/arch/qatomic_bootstrap.h ../corelib/arch/qatomic_generic.h ../corelib/arch/qatomic_i386.h ../corelib/arch/qatomic_ia64.h ../corelib/arch/qatomic_integrity.h ../corelib/arch/qatomic_m68k.h ../corelib/arch/qatomic_macosx.h ../corelib/arch/qatomic_mips.h ../corelib/arch/qatomic_parisc.h ../corelib/arch/qatomic_powerpc.h ../corelib/arch/qatomic_s390.h ../corelib/arch/qatomic_sh.h ../corelib/arch/qatomic_sh4a.h ../corelib/arch/qatomic_sparc.h ../corelib/arch/qatomic_symbian.h ../corelib/arch/qatomic_vxworks.h ../corelib/arch/qatomic_windows.h ../corelib/arch/qatomic_windowsce.h ../corelib/arch/qatomic_x86_64.h ../corelib/tools/qalgorithms.h ../corelib/tools/qbitarray.h ../corelib/tools/qbytearray.h ../corelib/tools/qbytearraymatcher.h ../corelib/tools/qcache.h ../corelib/tools/qchar.h ../corelib/tools/qcontainerfwd.h ../corelib/tools/qcontiguouscache.h ../corelib/tools/qcryptographichash.h ../corelib/tools/qdatetime.h ../corelib/tools/qeasingcurve.h ../corelib/tools/qelapsedtimer.h ../corelib/tools/qhash.h ../corelib/tools/qiterator.h ../corelib/tools/qline.h ../corelib/tools/qlinkedlist.h ../corelib/tools/qlist.h ../corelib/tools/qlocale.h ../corelib/tools/qlocale_blackberry.h ../corelib/tools/qmap.h ../corelib/tools/qmargins.h ../corelib/tools/qpair.h ../corelib/tools/qpoint.h ../corelib/tools/qqueue.h ../corelib/tools/qrect.h ../corelib/tools/qregexp.h ../corelib/tools/qscopedpointer.h ../corelib/tools/qscopedvaluerollback.h ../corelib/tools/qset.h ../corelib/tools/qshareddata.h ../corelib/tools/qsharedpointer.h ../corelib/tools/qsharedpointer_impl.h ../corelib/tools/qsize.h ../corelib/tools/qstack.h ../corelib/tools/qstring.h ../corelib/tools/qstringbuilder.h ../corelib/tools/qstringlist.h ../corelib/tools/qstringmatcher.h ../corelib/tools/qtextboundaryfinder.h ../corelib/tools/qtimeline.h ../corelib/tools/qvarlengtharray.h ../corelib/tools/qvector.h ../corelib/plugin/qfactoryinterface.h ../corelib/plugin/qlibrary.h ../corelib/plugin/qplugin.h ../corelib/plugin/qpluginloader.h ../corelib/plugin/quuid.h ../corelib/xml/qxmlstream.h ../corelib/thread/qatomic.h ../corelib/thread/qbasicatomic.h ../corelib/thread/qmutex.h ../corelib/thread/qreadwritelock.h ../corelib/thread/qsemaphore.h ../corelib/thread/qthread.h ../corelib/thread/qthreadstorage.h ../corelib/thread/qwaitcondition.h ../corelib/statemachine/qabstractstate.h ../corelib/statemachine/qabstracttransition.h ../corelib/statemachine/qeventtransition.h ../corelib/statemachine/qfinalstate.h ../corelib/statemachine/qhistorystate.h ../corelib/statemachine/qsignaltransition.h ../corelib/statemachine/qstate.h ../corelib/statemachine/qstatemachine.h ../corelib/concurrent/qfuture.h ../corelib/concurrent/qfutureinterface.h ../corelib/concurrent/qfuturesynchronizer.h ../corelib/concurrent/qfuturewatcher.h ../corelib/concurrent/qrunnable.h ../corelib/concurrent/qtconcurrentcompilertest.h ../corelib/concurrent/qtconcurrentexception.h ../corelib/concurrent/qtconcurrentfilter.h ../corelib/concurrent/qtconcurrentfilterkernel.h ../corelib/concurrent/qtconcurrentfunctionwrappers.h ../corelib/concurrent/qtconcurrentiteratekernel.h ../corelib/concurrent/qtconcurrentmap.h ../corelib/concurrent/qtconcurrentmapkernel.h ../corelib/concurrent/qtconcurrentmedian.h ../corelib/concurrent/qtconcurrentreducekernel.h ../corelib/concurrent/qtconcurrentresultstore.h ../corelib/concurrent/qtconcurrentrun.h ../corelib/concurrent/qtconcurrentrunbase.h ../corelib/concurrent/qtconcurrentstoredfunctioncall.h ../corelib/concurrent/qtconcurrentthreadengine.h ../corelib/concurrent/qthreadpool.h ../corelib/io/qabstractfileengine.h ../corelib/io/qbuffer.h ../corelib/io/qdatastream.h ../corelib/io/qdebug.h ../corelib/io/qdir.h ../corelib/io/qdiriterator.h ../corelib/io/qfile.h ../corelib/io/qfileinfo.h ../corelib/io/qfilesystemwatcher.h ../corelib/io/qfsfileengine.h ../corelib/io/qiodevice.h ../corelib/io/qprocess.h ../corelib/io/qresource.h ../corelib/io/qsettings.h ../corelib/io/qtemporaryfile.h ../corelib/io/qtextstream.h ../corelib/io/qurl.h ../corelib/global/qconfig-dist.h ../corelib/global/qconfig-large.h ../corelib/global/qconfig-medium.h ../corelib/global/qconfig-minimal.h ../corelib/global/qconfig-nacl.h ../corelib/global/qconfig-small.h ../corelib/global/qendian.h ../corelib/global/qfeatures.h ../corelib/global/qglobal.h ../corelib/global/qlibraryinfo.h ../corelib/global/qnamespace.h ../corelib/global/qnumeric.h ../corelib/global/qt_windows.h ../corelib/global/qconfig.h ../corelib/codecs/qtextcodec.h ../corelib/codecs/qtextcodecplugin.h ../../include/QtCore/QtCore ++SYNCQT.HEADER_FILES = ../corelib/kernel/qabstracteventdispatcher.h ../corelib/kernel/qabstractitemmodel.h ../corelib/kernel/qbasictimer.h ../corelib/kernel/qcoreapplication.h ../corelib/kernel/qcoreevent.h ../corelib/kernel/qeventloop.h ../corelib/kernel/qfunctions_nacl.h ../corelib/kernel/qfunctions_vxworks.h ../corelib/kernel/qfunctions_wince.h ../corelib/kernel/qmath.h ../corelib/kernel/qmetaobject.h ../corelib/kernel/qmetatype.h ../corelib/kernel/qmimedata.h ../corelib/kernel/qobject.h ../corelib/kernel/qobjectcleanuphandler.h ../corelib/kernel/qobjectdefs.h ../corelib/kernel/qpointer.h ../corelib/kernel/qsharedmemory.h ../corelib/kernel/qsignalmapper.h ../corelib/kernel/qsocketnotifier.h ../corelib/kernel/qsystemsemaphore.h ../corelib/kernel/qtimer.h ../corelib/kernel/qtranslator.h ../corelib/kernel/qvariant.h ../corelib/animation/qabstractanimation.h ../corelib/animation/qanimationgroup.h ../corelib/animation/qparallelanimationgroup.h ../corelib/animation/qpauseanimation.h ../corelib/animation/qpropertyanimation.h ../corelib/animation/qsequentialanimationgroup.h ../corelib/animation/qvariantanimation.h ../corelib/arch/qatomic_aarch64.h ../corelib/arch/qatomic_alpha.h ../corelib/arch/qatomic_arch.h ../corelib/arch/qatomic_arm.h ../corelib/arch/qatomic_armv5.h ../corelib/arch/qatomic_armv6.h ../corelib/arch/qatomic_armv7.h ../corelib/arch/qatomic_avr32.h ../corelib/arch/qatomic_bfin.h ../corelib/arch/qatomic_bootstrap.h ../corelib/arch/qatomic_generic.h ../corelib/arch/qatomic_i386.h ../corelib/arch/qatomic_ia64.h ../corelib/arch/qatomic_integrity.h ../corelib/arch/qatomic_m68k.h ../corelib/arch/qatomic_macosx.h ../corelib/arch/qatomic_mips.h ../corelib/arch/qatomic_parisc.h ../corelib/arch/qatomic_powerpc.h ../corelib/arch/qatomic_s390.h ../corelib/arch/qatomic_sh.h ../corelib/arch/qatomic_sh4a.h ../corelib/arch/qatomic_sparc.h ../corelib/arch/qatomic_symbian.h ../corelib/arch/qatomic_vxworks.h ../corelib/arch/qatomic_windows.h ../corelib/arch/qatomic_windowsce.h ../corelib/arch/qatomic_x86_64.h ../corelib/tools/qalgorithms.h ../corelib/tools/qbitarray.h ../corelib/tools/qbytearray.h ../corelib/tools/qbytearraymatcher.h ../corelib/tools/qcache.h ../corelib/tools/qchar.h ../corelib/tools/qcontainerfwd.h ../corelib/tools/qcontiguouscache.h ../corelib/tools/qcryptographichash.h ../corelib/tools/qdatetime.h ../corelib/tools/qeasingcurve.h ../corelib/tools/qelapsedtimer.h ../corelib/tools/qhash.h ../corelib/tools/qiterator.h ../corelib/tools/qline.h ../corelib/tools/qlinkedlist.h ../corelib/tools/qlist.h ../corelib/tools/qlocale.h ../corelib/tools/qlocale_blackberry.h ../corelib/tools/qmap.h ../corelib/tools/qmargins.h ../corelib/tools/qpair.h ../corelib/tools/qpoint.h ../corelib/tools/qqueue.h ../corelib/tools/qrect.h ../corelib/tools/qregexp.h ../corelib/tools/qscopedpointer.h ../corelib/tools/qscopedvaluerollback.h ../corelib/tools/qset.h ../corelib/tools/qshareddata.h ../corelib/tools/qsharedpointer.h ../corelib/tools/qsharedpointer_impl.h ../corelib/tools/qsize.h ../corelib/tools/qstack.h ../corelib/tools/qstring.h ../corelib/tools/qstringbuilder.h ../corelib/tools/qstringlist.h ../corelib/tools/qstringmatcher.h ../corelib/tools/qtextboundaryfinder.h ../corelib/tools/qtimeline.h ../corelib/tools/qvarlengtharray.h ../corelib/tools/qvector.h ../corelib/plugin/qfactoryinterface.h ../corelib/plugin/qlibrary.h ../corelib/plugin/qplugin.h ../corelib/plugin/qpluginloader.h ../corelib/plugin/quuid.h ../corelib/xml/qxmlstream.h ../corelib/thread/qatomic.h ../corelib/thread/qbasicatomic.h ../corelib/thread/qmutex.h ../corelib/thread/qreadwritelock.h ../corelib/thread/qsemaphore.h ../corelib/thread/qthread.h ../corelib/thread/qthreadstorage.h ../corelib/thread/qwaitcondition.h ../corelib/statemachine/qabstractstate.h ../corelib/statemachine/qabstracttransition.h ../corelib/statemachine/qeventtransition.h ../corelib/statemachine/qfinalstate.h ../corelib/statemachine/qhistorystate.h ../corelib/statemachine/qsignaltransition.h ../corelib/statemachine/qstate.h ../corelib/statemachine/qstatemachine.h ../corelib/concurrent/qfuture.h ../corelib/concurrent/qfutureinterface.h ../corelib/concurrent/qfuturesynchronizer.h ../corelib/concurrent/qfuturewatcher.h ../corelib/concurrent/qrunnable.h ../corelib/concurrent/qtconcurrentcompilertest.h ../corelib/concurrent/qtconcurrentexception.h ../corelib/concurrent/qtconcurrentfilter.h ../corelib/concurrent/qtconcurrentfilterkernel.h ../corelib/concurrent/qtconcurrentfunctionwrappers.h ../corelib/concurrent/qtconcurrentiteratekernel.h ../corelib/concurrent/qtconcurrentmap.h ../corelib/concurrent/qtconcurrentmapkernel.h ../corelib/concurrent/qtconcurrentmedian.h ../corelib/concurrent/qtconcurrentreducekernel.h ../corelib/concurrent/qtconcurrentresultstore.h ../corelib/concurrent/qtconcurrentrun.h ../corelib/concurrent/qtconcurrentrunbase.h ../corelib/concurrent/qtconcurrentstoredfunctioncall.h ../corelib/concurrent/qtconcurrentthreadengine.h ../corelib/concurrent/qthreadpool.h ../corelib/io/qabstractfileengine.h ../corelib/io/qbuffer.h ../corelib/io/qdatastream.h ../corelib/io/qdebug.h ../corelib/io/qdir.h ../corelib/io/qdiriterator.h ../corelib/io/qfile.h ../corelib/io/qfileinfo.h ../corelib/io/qfilesystemwatcher.h ../corelib/io/qfsfileengine.h ../corelib/io/qiodevice.h ../corelib/io/qprocess.h ../corelib/io/qresource.h ../corelib/io/qsettings.h ../corelib/io/qtemporaryfile.h ../corelib/io/qtextstream.h ../corelib/io/qurl.h ../corelib/global/qconfig-dist.h ../corelib/global/qconfig-large.h ../corelib/global/qconfig-medium.h ../corelib/global/qconfig-minimal.h ../corelib/global/qconfig-nacl.h ../corelib/global/qconfig-small.h ../corelib/global/qendian.h ../corelib/global/qfeatures.h ../corelib/global/qglobal.h ../corelib/global/qlibraryinfo.h ../corelib/global/qnamespace.h ../corelib/global/qnumeric.h ../corelib/global/qt_windows.h ../corelib/global/qconfig.h ../corelib/codecs/qtextcodec.h ../corelib/codecs/qtextcodecplugin.h ../../include/QtCore/QtCore + SYNCQT.HEADER_CLASSES = ../../include/QtCore/QAbstractEventDispatcher ../../include/QtCore/QModelIndex ../../include/QtCore/QPersistentModelIndex ../../include/QtCore/QModelIndexList ../../include/QtCore/QAbstractItemModel ../../include/QtCore/QAbstractTableModel ../../include/QtCore/QAbstractListModel ../../include/QtCore/QBasicTimer ../../include/QtCore/QCoreApplication ../../include/QtCore/QtCleanUpFunction ../../include/QtCore/QEvent ../../include/QtCore/QTimerEvent ../../include/QtCore/QChildEvent ../../include/QtCore/QCustomEvent ../../include/QtCore/QDynamicPropertyChangeEvent ../../include/QtCore/QEventLoop ../../include/QtCore/QMetaMethod ../../include/QtCore/QMetaEnum ../../include/QtCore/QMetaProperty ../../include/QtCore/QMetaClassInfo ../../include/QtCore/QMetaType ../../include/QtCore/QMetaTypeId ../../include/QtCore/QMetaTypeId2 ../../include/QtCore/QMimeData ../../include/QtCore/QObjectList ../../include/QtCore/QObjectData ../../include/QtCore/QObject ../../include/QtCore/QObjectUserData ../../include/QtCore/QObjectCleanupHandler ../../include/QtCore/QGenericArgument ../../include/QtCore/QGenericReturnArgument ../../include/QtCore/QArgument ../../include/QtCore/QReturnArgument ../../include/QtCore/QMetaObject ../../include/QtCore/QMetaObjectAccessor ../../include/QtCore/QMetaObjectExtraData ../../include/QtCore/QPointer ../../include/QtCore/QSharedMemory ../../include/QtCore/QSignalMapper ../../include/QtCore/QSocketNotifier ../../include/QtCore/QSystemSemaphore ../../include/QtCore/QTimer ../../include/QtCore/QTranslator ../../include/QtCore/QVariant ../../include/QtCore/QVariantList ../../include/QtCore/QVariantMap ../../include/QtCore/QVariantHash ../../include/QtCore/QVariantComparisonHelper ../../include/QtCore/QAbstractAnimation ../../include/QtCore/QAnimationDriver ../../include/QtCore/QAnimationGroup ../../include/QtCore/QParallelAnimationGroup ../../include/QtCore/QPauseAnimation ../../include/QtCore/QPropertyAnimation ../../include/QtCore/QSequentialAnimationGroup ../../include/QtCore/QVariantAnimation ../../include/QtCore/QtAlgorithms ../../include/QtCore/QBitArray ../../include/QtCore/QBitRef ../../include/QtCore/QByteArray ../../include/QtCore/QByteRef ../../include/QtCore/QByteArrayMatcher ../../include/QtCore/QCache ../../include/QtCore/QLatin1Char ../../include/QtCore/QChar ../../include/QtCore/QtContainerFwd ../../include/QtCore/QContiguousCacheData ../../include/QtCore/QContiguousCacheTypedData ../../include/QtCore/QContiguousCache ../../include/QtCore/QCryptographicHash ../../include/QtCore/QDate ../../include/QtCore/QTime ../../include/QtCore/QDateTime ../../include/QtCore/QEasingCurve ../../include/QtCore/QElapsedTimer ../../include/QtCore/QHashData ../../include/QtCore/QHashDummyValue ../../include/QtCore/QHashDummyNode ../../include/QtCore/QHashNode ../../include/QtCore/QHash ../../include/QtCore/QMultiHash ../../include/QtCore/QHashIterator ../../include/QtCore/QMutableHashIterator ../../include/QtCore/QLine ../../include/QtCore/QLineF ../../include/QtCore/QLinkedListData ../../include/QtCore/QLinkedListNode ../../include/QtCore/QLinkedList ../../include/QtCore/QLinkedListIterator ../../include/QtCore/QMutableLinkedListIterator ../../include/QtCore/QListData ../../include/QtCore/QList ../../include/QtCore/QListIterator ../../include/QtCore/QMutableListIterator ../../include/QtCore/QSystemLocale ../../include/QtCore/QLocale ../../include/QtCore/QBBSystemLocaleData ../../include/QtCore/QMapData ../../include/QtCore/QMapNode ../../include/QtCore/QMapPayloadNode ../../include/QtCore/QMap ../../include/QtCore/QMultiMap ../../include/QtCore/QMapIterator ../../include/QtCore/QMutableMapIterator ../../include/QtCore/QMargins ../../include/QtCore/QPair ../../include/QtCore/QPoint ../../include/QtCore/QPointF ../../include/QtCore/QQueue ../../include/QtCore/QRect ../../include/QtCore/QRectF ../../include/QtCore/QRegExp ../../include/QtCore/QScopedPointerDeleter ../../include/QtCore/QScopedPointerArrayDeleter ../../include/QtCore/QScopedPointerPodDeleter ../../include/QtCore/QScopedPointer ../../include/QtCore/QScopedArrayPointer ../../include/QtCore/QScopedValueRollback ../../include/QtCore/QSet ../../include/QtCore/QSetIterator ../../include/QtCore/QMutableSetIterator ../../include/QtCore/QSharedData ../../include/QtCore/QSharedDataPointer ../../include/QtCore/QExplicitlySharedDataPointer ../../include/QtCore/QSharedPointer ../../include/QtCore/QWeakPointer ../../include/QtCore/QSize ../../include/QtCore/QSizeF ../../include/QtCore/QStack ../../include/QtCore/QStdWString ../../include/QtCore/QString ../../include/QtCore/QLatin1String ../../include/QtCore/QCharRef ../../include/QtCore/QConstString ../../include/QtCore/QStringRef ../../include/QtCore/QLatin1Literal ../../include/QtCore/QAbstractConcatenable ../../include/QtCore/QConcatenable ../../include/QtCore/QStringBuilder ../../include/QtCore/QStringListIterator ../../include/QtCore/QMutableStringListIterator ../../include/QtCore/QStringList ../../include/QtCore/QStringMatcher ../../include/QtCore/QTextBoundaryFinder ../../include/QtCore/QTimeLine ../../include/QtCore/QVarLengthArray ../../include/QtCore/QVectorData ../../include/QtCore/QVectorTypedData ../../include/QtCore/QVector ../../include/QtCore/QVectorIterator ../../include/QtCore/QMutableVectorIterator ../../include/QtCore/QFactoryInterface ../../include/QtCore/QLibrary ../../include/QtCore/QtPlugin ../../include/QtCore/QtPluginInstanceFunction ../../include/QtCore/QPluginLoader ../../include/QtCore/QUuid ../../include/QtCore/QXmlStreamStringRef ../../include/QtCore/QXmlStreamAttribute ../../include/QtCore/QXmlStreamAttributes ../../include/QtCore/QXmlStreamNamespaceDeclaration ../../include/QtCore/QXmlStreamNamespaceDeclarations ../../include/QtCore/QXmlStreamNotationDeclaration ../../include/QtCore/QXmlStreamNotationDeclarations ../../include/QtCore/QXmlStreamEntityDeclaration ../../include/QtCore/QXmlStreamEntityDeclarations ../../include/QtCore/QXmlStreamEntityResolver ../../include/QtCore/QXmlStreamReader ../../include/QtCore/QXmlStreamWriter ../../include/QtCore/QAtomicInt ../../include/QtCore/QAtomicPointer ../../include/QtCore/QBasicAtomicInt ../../include/QtCore/QBasicAtomicPointer ../../include/QtCore/QMutex ../../include/QtCore/QMutexLocker ../../include/QtCore/QMutexData ../../include/QtCore/QReadWriteLock ../../include/QtCore/QReadLocker ../../include/QtCore/QWriteLocker ../../include/QtCore/QSemaphore ../../include/QtCore/QThread ../../include/QtCore/QThreadStorageData ../../include/QtCore/QThreadStorage ../../include/QtCore/QWaitCondition ../../include/QtCore/QAbstractState ../../include/QtCore/QAbstractTransition ../../include/QtCore/QEventTransition ../../include/QtCore/QFinalState ../../include/QtCore/QHistoryState ../../include/QtCore/QSignalTransition ../../include/QtCore/QState ../../include/QtCore/QStateMachine ../../include/QtCore/QFuture ../../include/QtCore/QFutureIterator ../../include/QtCore/QMutableFutureIterator ../../include/QtCore/QFutureInterfaceBase ../../include/QtCore/QFutureInterface ../../include/QtCore/QFutureSynchronizer ../../include/QtCore/QFutureWatcherBase ../../include/QtCore/QFutureWatcher ../../include/QtCore/QRunnable ../../include/QtCore/QtConcurrentFilter ../../include/QtCore/QtConcurrentMap ../../include/QtCore/QtConcurrentRun ../../include/QtCore/QThreadPool ../../include/QtCore/QAbstractFileEngine ../../include/QtCore/QAbstractFileEngineHandler ../../include/QtCore/QAbstractFileEngineIterator ../../include/QtCore/QBuffer ../../include/QtCore/QDataStream ../../include/QtCore/QtDebug ../../include/QtCore/QDebug ../../include/QtCore/QNoDebug ../../include/QtCore/QDir ../../include/QtCore/QDirIterator ../../include/QtCore/QFile ../../include/QtCore/QFileInfo ../../include/QtCore/QFileInfoList ../../include/QtCore/QFileInfoListIterator ../../include/QtCore/QFileSystemWatcher ../../include/QtCore/QFSFileEngine ../../include/QtCore/QIODevice ../../include/QtCore/Q_PID ../../include/QtCore/QProcessEnvironment ../../include/QtCore/QProcess ../../include/QtCore/QResource ../../include/QtCore/QSettings ../../include/QtCore/QTemporaryFile ../../include/QtCore/QTextStream ../../include/QtCore/QTextStreamFunction ../../include/QtCore/QTextStreamManipulator ../../include/QtCore/QTS ../../include/QtCore/QTextIStream ../../include/QtCore/QTextOStream ../../include/QtCore/QUrl ../../include/QtCore/QtEndian ../../include/QtCore/QtGlobal ../../include/QtCore/QIntegerForSize ../../include/QtCore/QNoImplicitBoolCast ../../include/QtCore/Q_INT8 ../../include/QtCore/Q_UINT8 ../../include/QtCore/Q_INT16 ../../include/QtCore/Q_UINT16 ../../include/QtCore/Q_INT32 ../../include/QtCore/Q_UINT32 ../../include/QtCore/Q_INT64 ../../include/QtCore/Q_UINT64 ../../include/QtCore/Q_LLONG ../../include/QtCore/Q_ULLONG ../../include/QtCore/Q_LONG ../../include/QtCore/Q_ULONG ../../include/QtCore/QSysInfo ../../include/QtCore/QtMsgHandler ../../include/QtCore/QGlobalStatic ../../include/QtCore/QGlobalStaticDeleter ../../include/QtCore/QBool ../../include/QtCore/QTypeInfo ../../include/QtCore/QFlag ../../include/QtCore/QIncompatibleFlag ../../include/QtCore/QFlags ../../include/QtCore/QForeachContainer ../../include/QtCore/QForeachContainerBase ../../include/QtCore/QLibraryInfo ../../include/QtCore/Qt ../../include/QtCore/QInternal ../../include/QtCore/QCOORD ../../include/QtCore/QtConfig ../../include/QtCore/QTextCodec ../../include/QtCore/QTextEncoder ../../include/QtCore/QTextDecoder ../../include/QtCore/QTextCodecFactoryInterface ../../include/QtCore/QTextCodecPlugin + SYNCQT.PRIVATE_HEADER_FILES = ../corelib/kernel/qabstracteventdispatcher_p.h ../corelib/kernel/qabstractitemmodel_p.h ../corelib/kernel/qcore_mac_p.h ../corelib/kernel/qcore_symbian_p.h ../corelib/kernel/qcore_unix_p.h ../corelib/kernel/qcoreapplication_p.h ../corelib/kernel/qcorecmdlineargs_p.h ../corelib/kernel/qcoreglobaldata_p.h ../corelib/kernel/qcrashhandler_p.h ../corelib/kernel/qeventdispatcher_blackberry_p.h ../corelib/kernel/qeventdispatcher_glib_p.h ../corelib/kernel/qeventdispatcher_symbian_p.h ../corelib/kernel/qeventdispatcher_unix_p.h ../corelib/kernel/qeventdispatcher_win_p.h ../corelib/kernel/qfunctions_p.h ../corelib/kernel/qmetaobject_p.h ../corelib/kernel/qobject_p.h ../corelib/kernel/qsharedmemory_p.h ../corelib/kernel/qsystemerror_p.h ../corelib/kernel/qsystemsemaphore_p.h ../corelib/kernel/qtranslator_p.h ../corelib/kernel/qvariant_p.h ../corelib/kernel/qwineventnotifier_p.h ../corelib/animation/qabstractanimation_p.h ../corelib/animation/qanimationgroup_p.h ../corelib/animation/qparallelanimationgroup_p.h ../corelib/animation/qpropertyanimation_p.h ../corelib/animation/qsequentialanimationgroup_p.h ../corelib/animation/qvariantanimation_p.h ../corelib/tools/qbytedata_p.h ../corelib/tools/qdatetime_p.h ../corelib/tools/qharfbuzz_p.h ../corelib/tools/qlocale_data_p.h ../corelib/tools/qlocale_p.h ../corelib/tools/qlocale_tools_p.h ../corelib/tools/qpodlist_p.h ../corelib/tools/qringbuffer_p.h ../corelib/tools/qscopedpointer_p.h ../corelib/tools/qsimd_p.h ../corelib/tools/qtools_p.h ../corelib/tools/qunicodetables_p.h ../corelib/plugin/qelfparser_p.h ../corelib/plugin/qfactoryloader_p.h ../corelib/plugin/qlibrary_p.h ../corelib/plugin/qsystemlibrary_p.h ../corelib/xml/qxmlstream_p.h ../corelib/xml/qxmlutils_p.h ../corelib/thread/qmutex_p.h ../corelib/thread/qmutexpool_p.h ../corelib/thread/qorderedmutexlocker_p.h ../corelib/thread/qreadwritelock_p.h ../corelib/thread/qthread_p.h ../corelib/statemachine/qabstractstate_p.h ../corelib/statemachine/qabstracttransition_p.h ../corelib/statemachine/qeventtransition_p.h ../corelib/statemachine/qhistorystate_p.h ../corelib/statemachine/qsignaleventgenerator_p.h ../corelib/statemachine/qsignaltransition_p.h ../corelib/statemachine/qstate_p.h ../corelib/statemachine/qstatemachine_p.h ../corelib/concurrent/qfutureinterface_p.h ../corelib/concurrent/qfuturewatcher_p.h ../corelib/concurrent/qthreadpool_p.h ../corelib/io/qabstractfileengine_p.h ../corelib/io/qdatastream_p.h ../corelib/io/qdataurl_p.h ../corelib/io/qdir_p.h ../corelib/io/qfile_p.h ../corelib/io/qfileinfo_p.h ../corelib/io/qfilesystemengine_p.h ../corelib/io/qfilesystementry_p.h ../corelib/io/qfilesystemiterator_p.h ../corelib/io/qfilesystemmetadata_p.h ../corelib/io/qfilesystemwatcher_dnotify_p.h ../corelib/io/qfilesystemwatcher_fsevents_p.h ../corelib/io/qfilesystemwatcher_inotify_p.h ../corelib/io/qfilesystemwatcher_kqueue_p.h ../corelib/io/qfilesystemwatcher_p.h ../corelib/io/qfilesystemwatcher_symbian_p.h ../corelib/io/qfilesystemwatcher_win_p.h ../corelib/io/qfsfileengine_iterator_p.h ../corelib/io/qfsfileengine_p.h ../corelib/io/qiodevice_p.h ../corelib/io/qnoncontiguousbytedevice_p.h ../corelib/io/qprocess_p.h ../corelib/io/qresource_iterator_p.h ../corelib/io/qresource_p.h ../corelib/io/qsettings_p.h ../corelib/io/qtldurl_p.h ../corelib/io/qurltlds_p.h ../corelib/io/qwindowspipewriter_p.h ../corelib/global/qnumeric_p.h ../corelib/global/qt_pch.h ../corelib/codecs/qfontlaocodec_p.h ../corelib/codecs/qiconvcodec_p.h ../corelib/codecs/qisciicodec_p.h ../corelib/codecs/qlatincodec_p.h ../corelib/codecs/qsimplecodec_p.h ../corelib/codecs/qtextcodec_p.h ../corelib/codecs/qtsciicodec_p.h ../corelib/codecs/qutfcodec_p.h +diff -up qt-everywhere-opensource-src-4.8.7/include/QtCore/qatomic_aarch64.h.aarch64 qt-everywhere-opensource-src-4.8.7/include/QtCore/qatomic_aarch64.h +--- qt-everywhere-opensource-src-4.8.7/include/QtCore/qatomic_aarch64.h.aarch64 2015-05-08 21:48:32.715057744 -0500 ++++ qt-everywhere-opensource-src-4.8.7/include/QtCore/qatomic_aarch64.h 2015-05-08 21:48:32.715057744 -0500 +@@ -0,0 +1 @@ ++#include "../../src/corelib/arch/qatomic_aarch64.h" +diff -up qt-everywhere-opensource-src-4.8.7/src/3rdparty/javascriptcore/JavaScriptCore/JavaScriptCore.pri.aarch64 qt-everywhere-opensource-src-4.8.7/src/3rdparty/javascriptcore/JavaScriptCore/JavaScriptCore.pri +--- qt-everywhere-opensource-src-4.8.7/src/3rdparty/javascriptcore/JavaScriptCore/JavaScriptCore.pri.aarch64 2015-05-07 09:14:47.000000000 -0500 ++++ qt-everywhere-opensource-src-4.8.7/src/3rdparty/javascriptcore/JavaScriptCore/JavaScriptCore.pri 2015-05-08 21:48:33.268061013 -0500 +@@ -66,6 +66,12 @@ contains(JAVASCRIPTCORE_JIT,no) { + } + } + ++# Hack around AARCH64 fail wrt JSValue.h ++equals(QT_ARCH, aarch64) { ++ message("JavaScriptCore aarch64 hack: -fpermissive") ++ QMAKE_CXXFLAGS += -fpermissive ++} ++ + wince* { + INCLUDEPATH += $$QT_SOURCE_TREE/src/3rdparty/ce-compat + SOURCES += $$QT_SOURCE_TREE/src/3rdparty/ce-compat/ce_time.c +diff -up qt-everywhere-opensource-src-4.8.7/src/3rdparty/webkit/Source/JavaScriptCore/JavaScriptCore.pri.aarch64 qt-everywhere-opensource-src-4.8.7/src/3rdparty/webkit/Source/JavaScriptCore/JavaScriptCore.pri +--- qt-everywhere-opensource-src-4.8.7/src/3rdparty/webkit/Source/JavaScriptCore/JavaScriptCore.pri.aarch64 2015-05-07 09:14:45.000000000 -0500 ++++ qt-everywhere-opensource-src-4.8.7/src/3rdparty/webkit/Source/JavaScriptCore/JavaScriptCore.pri 2015-05-08 21:48:33.268061013 -0500 +@@ -63,6 +63,12 @@ contains (CONFIG, text_breaking_with_icu + DEFINES += WTF_USE_QT_ICU_TEXT_BREAKING=1 + } + ++# Hack around AARCH64 fail wrt JSValue.h ++equals(QT_ARCH, aarch64) { ++ message("JavaScriptCore aarch64 hack: -fpermissive") ++ QMAKE_CXXFLAGS += -fpermissive ++} ++ + wince* { + INCLUDEPATH += $$QT_SOURCE_TREE/src/3rdparty/ce-compat + INCLUDEPATH += $$PWD/../JavaScriptCore/os-win32 +diff -up qt-everywhere-opensource-src-4.8.7/src/3rdparty/webkit/Source/JavaScriptCore/wtf/Platform.h.aarch64 qt-everywhere-opensource-src-4.8.7/src/3rdparty/webkit/Source/JavaScriptCore/wtf/Platform.h +--- qt-everywhere-opensource-src-4.8.7/src/3rdparty/webkit/Source/JavaScriptCore/wtf/Platform.h.aarch64 2015-05-07 09:14:45.000000000 -0500 ++++ qt-everywhere-opensource-src-4.8.7/src/3rdparty/webkit/Source/JavaScriptCore/wtf/Platform.h 2015-05-08 21:48:33.269061019 -0500 +@@ -369,7 +369,16 @@ + + #endif /* ARM */ + +-#if CPU(ARM) || CPU(MIPS) || CPU(SH4) ++/* CPU(AARCH64) - AArch64 */ ++#if defined(__aarch64__) ++#define WTF_CPU_AARCH64 1 ++#if defined(__AARCH64EB__) ++#define WTF_CPU_BIG_ENDIAN 1 ++#endif ++#endif ++ ++/* Not sure about this one, qt5-qtwebkit doesn't include it -- rex */ ++#if CPU(ARM) || CPU(MIPS) || CPU(SH4) || CPU(AARCH64) + #define WTF_CPU_NEEDS_ALIGNED_ACCESS 1 + #endif + +@@ -1003,7 +1012,7 @@ + || CPU(SPARC64) \ + || CPU(S390X) \ + || CPU(PPC64) \ +- || CPU(MIPS64) ++ || CPU(MIPS64) || CPU(AARCH64) + #define WTF_USE_JSVALUE64 1 + #else + #define WTF_USE_JSVALUE32_64 1 +diff -up qt-everywhere-opensource-src-4.8.7/src/corelib/arch/aarch64/qatomic_aarch64.cpp.aarch64 qt-everywhere-opensource-src-4.8.7/src/corelib/arch/aarch64/qatomic_aarch64.cpp +--- qt-everywhere-opensource-src-4.8.7/src/corelib/arch/aarch64/qatomic_aarch64.cpp.aarch64 2015-05-08 21:48:33.269061019 -0500 ++++ qt-everywhere-opensource-src-4.8.7/src/corelib/arch/aarch64/qatomic_aarch64.cpp 2015-05-08 21:48:33.269061019 -0500 +@@ -0,0 +1,70 @@ ++/**************************************************************************** ++** ++** Copyright (C) 2012, 2013 Digia Plc and/or its subsidiary(-ies). ++** Contact: http://www.qt-project.org/legal ++** ++** This file is part of the QtCore module of the Qt Toolkit. ++** ++** $QT_BEGIN_LICENSE:LGPL$ ++** Commercial License Usage ++** Licensees holding valid commercial Qt licenses may use this file in ++** accordance with the commercial license agreement provided with the ++** Software or, alternatively, in accordance with the terms contained in ++** a written agreement between you and Digia. For licensing terms and ++** conditions see http://qt.digia.com/licensing. For further information ++** use the contact form at http://qt.digia.com/contact-us. ++** ++** GNU Lesser General Public License Usage ++** Alternatively, this file may be used under the terms of the GNU Lesser ++** General Public License version 2.1 as published by the Free Software ++** Foundation and appearing in the file LICENSE.LGPL included in the ++** packaging of this file. Please review the following information to ++** ensure the GNU Lesser General Public License version 2.1 requirements ++** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ++** ++** In addition, as a special exception, Digia gives you certain additional ++** rights. These rights are described in the Digia Qt LGPL Exception ++** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ++** ++** GNU General Public License Usage ++** Alternatively, this file may be used under the terms of the GNU ++** General Public License version 3.0 as published by the Free Software ++** Foundation and appearing in the file LICENSE.GPL included in the ++** packaging of this file. Please review the following information to ++** ensure the GNU General Public License version 3.0 requirements will be ++** met: http://www.gnu.org/copyleft/gpl.html. ++** ++** ++** $QT_END_LICENSE$ ++** ++****************************************************************************/ ++ ++#include <QtCore/qglobal.h> ++ ++#include <unistd.h> ++#ifdef _POSIX_PRIORITY_SCHEDULING ++# include <sched.h> ++#endif ++#include <time.h> ++ ++QT_BEGIN_NAMESPACE ++ ++QT_USE_NAMESPACE ++ ++Q_CORE_EXPORT void qt_atomic_yield(int *count) ++{ ++#ifdef _POSIX_PRIORITY_SCHEDULING ++ if((*count)++ < 50) { ++ sched_yield(); ++ } else ++#endif ++ { ++ struct timespec tm; ++ tm.tv_sec = 0; ++ tm.tv_nsec = 2000001; ++ nanosleep(&tm, NULL); ++ *count = 0; ++ } ++} ++ ++QT_END_NAMESPACE +diff -up qt-everywhere-opensource-src-4.8.7/src/corelib/arch/arch.pri.aarch64 qt-everywhere-opensource-src-4.8.7/src/corelib/arch/arch.pri +--- qt-everywhere-opensource-src-4.8.7/src/corelib/arch/arch.pri.aarch64 2015-05-07 09:14:48.000000000 -0500 ++++ qt-everywhere-opensource-src-4.8.7/src/corelib/arch/arch.pri 2015-05-08 21:48:33.270061025 -0500 +@@ -31,7 +31,9 @@ integrity:HEADERS += arch/qatomic_integr + arch/qatomic_s390.h \ + arch/qatomic_x86_64.h \ + arch/qatomic_sh.h \ +- arch/qatomic_sh4a.h ++ arch/qatomic_sh4a.h \ ++ arch/qatomic_aarch64.h \ ++ + + QT_ARCH_CPP = $$QT_SOURCE_TREE/src/corelib/arch/$$QT_ARCH + DEPENDPATH += $$QT_ARCH_CPP +diff -up qt-everywhere-opensource-src-4.8.7/src/corelib/arch/qatomic_aarch64.h.aarch64 qt-everywhere-opensource-src-4.8.7/src/corelib/arch/qatomic_aarch64.h +--- qt-everywhere-opensource-src-4.8.7/src/corelib/arch/qatomic_aarch64.h.aarch64 2015-05-08 21:48:33.270061025 -0500 ++++ qt-everywhere-opensource-src-4.8.7/src/corelib/arch/qatomic_aarch64.h 2015-05-08 21:48:33.270061025 -0500 +@@ -0,0 +1,335 @@ ++/**************************************************************************** ++** ++** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). ++** Contact: http://www.qt-project.org/legal ++** ++** This file is part of the QtCore module of the Qt Toolkit. ++** ++** $QT_BEGIN_LICENSE:LGPL$ ++** Commercial License Usage ++** Licensees holding valid commercial Qt licenses may use this file in ++** accordance with the commercial license agreement provided with the ++** Software or, alternatively, in accordance with the terms contained in ++** a written agreement between you and Digia. For licensing terms and ++** conditions see http://qt.digia.com/licensing. For further information ++** use the contact form at http://qt.digia.com/contact-us. ++** ++** GNU Lesser General Public License Usage ++** Alternatively, this file may be used under the terms of the GNU Lesser ++** General Public License version 2.1 as published by the Free Software ++** Foundation and appearing in the file LICENSE.LGPL included in the ++** packaging of this file. Please review the following information to ++** ensure the GNU Lesser General Public License version 2.1 requirements ++** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ++** ++** In addition, as a special exception, Digia gives you certain additional ++** rights. These rights are described in the Digia Qt LGPL Exception ++** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ++** ++** GNU General Public License Usage ++** Alternatively, this file may be used under the terms of the GNU ++** General Public License version 3.0 as published by the Free Software ++** Foundation and appearing in the file LICENSE.GPL included in the ++** packaging of this file. Please review the following information to ++** ensure the GNU General Public License version 3.0 requirements will be ++** met: http://www.gnu.org/copyleft/gpl.html. ++** ++** ++** $QT_END_LICENSE$ ++** ++****************************************************************************/ ++ ++#ifndef QATOMIC_AARCH64_H ++#define QATOMIC_AARCH64_H ++ ++QT_BEGIN_HEADER ++ ++QT_BEGIN_NAMESPACE ++ ++#define Q_ATOMIC_INT_REFERENCE_COUNTING_IS_ALWAYS_NATIVE ++ ++inline bool QBasicAtomicInt::isReferenceCountingNative() ++{ return true; } ++inline bool QBasicAtomicInt::isReferenceCountingWaitFree() ++{ return false; } ++ ++#define Q_ATOMIC_INT_TEST_AND_SET_IS_ALWAYS_NATIVE ++ ++inline bool QBasicAtomicInt::isTestAndSetNative() ++{ return true; } ++inline bool QBasicAtomicInt::isTestAndSetWaitFree() ++{ return false; } ++ ++#define Q_ATOMIC_INT_FETCH_AND_STORE_IS_ALWAYS_NATIVE ++ ++inline bool QBasicAtomicInt::isFetchAndStoreNative() ++{ return true; } ++inline bool QBasicAtomicInt::isFetchAndStoreWaitFree() ++{ return false; } ++ ++#define Q_ATOMIC_INT_FETCH_AND_ADD_IS_ALWAYS_NATIVE ++ ++inline bool QBasicAtomicInt::isFetchAndAddNative() ++{ return true; } ++inline bool QBasicAtomicInt::isFetchAndAddWaitFree() ++{ return false; } ++ ++#define Q_ATOMIC_POINTER_TEST_AND_SET_IS_ALWAYS_NATIVE ++ ++template <typename T> ++Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::isTestAndSetNative() ++{ return true; } ++template <typename T> ++Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::isTestAndSetWaitFree() ++{ return false; } ++ ++#define Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_ALWAYS_NATIVE ++ ++template <typename T> ++Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::isFetchAndStoreNative() ++{ return true; } ++template <typename T> ++Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::isFetchAndStoreWaitFree() ++{ return false; } ++ ++#define Q_ATOMIC_POINTER_FETCH_AND_ADD_IS_ALWAYS_NATIVE ++ ++template <typename T> ++Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::isFetchAndAddNative() ++{ return true; } ++template <typename T> ++Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::isFetchAndAddWaitFree() ++{ return false; } ++ ++#ifndef Q_DATA_MEMORY_BARRIER ++# define Q_DATA_MEMORY_BARRIER asm volatile("dmb sy\n":::"memory") ++#endif ++#ifndef Q_COMPILER_MEMORY_BARRIER ++# define Q_COMPILER_MEMORY_BARRIER asm volatile("":::"memory") ++#endif ++ ++inline bool QBasicAtomicInt::ref() ++{ ++ int newValue; ++ ++ Q_COMPILER_MEMORY_BARRIER; ++ newValue = __atomic_add_fetch(&_q_value, 1, __ATOMIC_ACQ_REL); ++ Q_COMPILER_MEMORY_BARRIER; ++ ++ return newValue != 0; ++} ++ ++inline bool QBasicAtomicInt::deref() ++{ ++ int newValue; ++ ++ Q_COMPILER_MEMORY_BARRIER; ++ newValue = __atomic_sub_fetch(&_q_value, 1, __ATOMIC_ACQ_REL); ++ Q_COMPILER_MEMORY_BARRIER; ++ ++ return newValue != 0; ++} ++ ++inline bool QBasicAtomicInt::testAndSetRelaxed(int expectedValue, int newValue) ++{ ++ bool val; ++ ++ Q_COMPILER_MEMORY_BARRIER; ++ val = __atomic_compare_exchange_n (&_q_value, &expectedValue, newValue, ++ false, __ATOMIC_RELAXED, __ATOMIC_RELAXED); ++ Q_COMPILER_MEMORY_BARRIER; ++ return val; ++} ++ ++inline int QBasicAtomicInt::fetchAndStoreRelaxed(int newValue) ++{ ++ int val; ++ Q_COMPILER_MEMORY_BARRIER; ++ val = __atomic_exchange_n(&_q_value, newValue, __ATOMIC_RELAXED); ++ Q_COMPILER_MEMORY_BARRIER; ++ return val; ++} ++ ++inline int QBasicAtomicInt::fetchAndAddRelaxed(int valueToAdd) ++{ ++ int val; ++ Q_COMPILER_MEMORY_BARRIER; ++ val = __atomic_fetch_add(&_q_value, valueToAdd, __ATOMIC_RELAXED); ++ Q_COMPILER_MEMORY_BARRIER; ++ return val; ++} ++ ++template <typename T> ++Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::testAndSetRelaxed(T *expectedValue, T *newValue) ++{ ++ bool val; ++ Q_COMPILER_MEMORY_BARRIER; ++ val = __atomic_compare_exchange_n (&_q_value, &expectedValue, newValue, ++ false, __ATOMIC_RELAXED, __ATOMIC_RELAXED); ++ Q_COMPILER_MEMORY_BARRIER; ++ return val; ++} ++ ++template <typename T> ++Q_INLINE_TEMPLATE T *QBasicAtomicPointer<T>::fetchAndStoreRelaxed(T *newValue) ++{ ++ T *val; ++ Q_COMPILER_MEMORY_BARRIER; ++ val = __atomic_exchange_n(&_q_value, newValue, __ATOMIC_RELAXED); ++ Q_COMPILER_MEMORY_BARRIER; ++ return val; ++} ++ ++template <typename T> ++Q_INLINE_TEMPLATE T *QBasicAtomicPointer<T>::fetchAndAddRelaxed(qptrdiff valueToAdd) ++{ ++ T *val; ++ Q_COMPILER_MEMORY_BARRIER; ++ val = __atomic_fetch_add(&_q_value, valueToAdd, __ATOMIC_RELAXED); ++ Q_COMPILER_MEMORY_BARRIER; ++ return val; ++} ++ ++inline bool QBasicAtomicInt::testAndSetAcquire(int expectedValue, int newValue) ++{ ++ bool returnValue = testAndSetRelaxed(expectedValue, newValue); ++ Q_DATA_MEMORY_BARRIER; ++ return returnValue; ++} ++ ++inline bool QBasicAtomicInt::testAndSetRelease(int expectedValue, int newValue) ++{ ++ Q_DATA_MEMORY_BARRIER; ++ return testAndSetRelaxed(expectedValue, newValue); ++} ++ ++inline bool QBasicAtomicInt::testAndSetOrdered(int expectedValue, int newValue) ++{ ++ Q_DATA_MEMORY_BARRIER; ++ bool returnValue = testAndSetRelaxed(expectedValue, newValue); ++ Q_COMPILER_MEMORY_BARRIER; ++ return returnValue; ++} ++ ++inline int QBasicAtomicInt::fetchAndStoreAcquire(int newValue) ++{ ++ int returnValue = fetchAndStoreRelaxed(newValue); ++ Q_DATA_MEMORY_BARRIER; ++ return returnValue; ++} ++ ++inline int QBasicAtomicInt::fetchAndStoreRelease(int newValue) ++{ ++ Q_DATA_MEMORY_BARRIER; ++ return fetchAndStoreRelaxed(newValue); ++} ++ ++inline int QBasicAtomicInt::fetchAndStoreOrdered(int newValue) ++{ ++ Q_DATA_MEMORY_BARRIER; ++ int returnValue = fetchAndStoreRelaxed(newValue); ++ Q_COMPILER_MEMORY_BARRIER; ++ return returnValue; ++} ++ ++inline int QBasicAtomicInt::fetchAndAddAcquire(int valueToAdd) ++{ ++ int returnValue = fetchAndAddRelaxed(valueToAdd); ++ Q_DATA_MEMORY_BARRIER; ++ return returnValue; ++} ++ ++inline int QBasicAtomicInt::fetchAndAddRelease(int valueToAdd) ++{ ++ Q_DATA_MEMORY_BARRIER; ++ return fetchAndAddRelaxed(valueToAdd); ++} ++ ++inline int QBasicAtomicInt::fetchAndAddOrdered(int valueToAdd) ++{ ++ Q_DATA_MEMORY_BARRIER; ++ int returnValue = fetchAndAddRelaxed(valueToAdd); ++ Q_COMPILER_MEMORY_BARRIER; ++ return returnValue; ++} ++ ++template <typename T> ++Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::testAndSetAcquire(T *expectedValue, T *newValue) ++{ ++ bool returnValue = testAndSetRelaxed(expectedValue, newValue); ++ Q_DATA_MEMORY_BARRIER; ++ return returnValue; ++} ++ ++template <typename T> ++Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::testAndSetRelease(T *expectedValue, T *newValue) ++{ ++ Q_DATA_MEMORY_BARRIER; ++ return testAndSetRelaxed(expectedValue, newValue); ++} ++ ++template <typename T> ++Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::testAndSetOrdered(T *expectedValue, T *newValue) ++{ ++ Q_DATA_MEMORY_BARRIER; ++ bool returnValue = testAndSetAcquire(expectedValue, newValue); ++ Q_COMPILER_MEMORY_BARRIER; ++ return returnValue; ++} ++ ++template <typename T> ++Q_INLINE_TEMPLATE T *QBasicAtomicPointer<T>::fetchAndStoreAcquire(T *newValue) ++{ ++ T *returnValue = fetchAndStoreRelaxed(newValue); ++ Q_DATA_MEMORY_BARRIER; ++ return returnValue; ++} ++ ++template <typename T> ++Q_INLINE_TEMPLATE T *QBasicAtomicPointer<T>::fetchAndStoreRelease(T *newValue) ++{ ++ Q_DATA_MEMORY_BARRIER; ++ return fetchAndStoreRelaxed(newValue); ++} ++ ++template <typename T> ++Q_INLINE_TEMPLATE T *QBasicAtomicPointer<T>::fetchAndStoreOrdered(T *newValue) ++{ ++ Q_DATA_MEMORY_BARRIER; ++ T *returnValue = fetchAndStoreRelaxed(newValue); ++ Q_COMPILER_MEMORY_BARRIER; ++ return returnValue; ++} ++ ++template <typename T> ++Q_INLINE_TEMPLATE T *QBasicAtomicPointer<T>::fetchAndAddAcquire(qptrdiff valueToAdd) ++{ ++ T *returnValue = fetchAndAddRelaxed(valueToAdd); ++ Q_DATA_MEMORY_BARRIER; ++ return returnValue; ++} ++ ++template <typename T> ++Q_INLINE_TEMPLATE T *QBasicAtomicPointer<T>::fetchAndAddRelease(qptrdiff valueToAdd) ++{ ++ Q_DATA_MEMORY_BARRIER; ++ return fetchAndAddRelaxed(valueToAdd); ++} ++ ++template <typename T> ++Q_INLINE_TEMPLATE T *QBasicAtomicPointer<T>::fetchAndAddOrdered(qptrdiff valueToAdd) ++{ ++ Q_DATA_MEMORY_BARRIER; ++ T *returnValue = fetchAndAddRelaxed(valueToAdd); ++ Q_COMPILER_MEMORY_BARRIER; ++ return returnValue; ++} ++ ++#undef Q_DATA_MEMORY_BARRIER ++#undef Q_COMPILER_MEMORY_BARRIER ++ ++QT_END_NAMESPACE ++ ++QT_END_HEADER ++ ++#endif // QATOMIC_AARCH64_H +diff -up qt-everywhere-opensource-src-4.8.7/src/corelib/arch/qatomic_arch.h.aarch64 qt-everywhere-opensource-src-4.8.7/src/corelib/arch/qatomic_arch.h +--- qt-everywhere-opensource-src-4.8.7/src/corelib/arch/qatomic_arch.h.aarch64 2015-05-07 09:14:48.000000000 -0500 ++++ qt-everywhere-opensource-src-4.8.7/src/corelib/arch/qatomic_arch.h 2015-05-08 21:48:33.271061031 -0500 +@@ -94,6 +94,8 @@ QT_BEGIN_HEADER + # include "QtCore/qatomic_sh4a.h" + #elif defined(QT_ARCH_NACL) + # include "QtCore/qatomic_generic.h" ++#elif defined(QT_ARCH_AARCH64) ++# include "QtCore/qatomic_aarch64.h" + #else + # error "Qt has not been ported to this architecture" + #endif diff --git a/subprojects/shared-modules/qt4/qt4-openssl-1.1.patch b/subprojects/shared-modules/qt4/qt4-openssl-1.1.patch new file mode 100644 index 00000000..87baef87 --- /dev/null +++ b/subprojects/shared-modules/qt4/qt4-openssl-1.1.patch @@ -0,0 +1,409 @@ +Description: Compile with openssl-1.1.0 + * Most changes are related to openssl structures are now opaque. + * The network/ssl threading setup has been disabled because the + old openssl threading model has been removed and is apparently + no longer needed. + * A number of new functions had to be imported (see changes to + src/network/ssl/qsslsocket_openssl_symbols.cpp) +Author: Gert Wollny <gw.fossdev@gmail.com> +Last-Update: 2016-06-28 +Bug-Debian: http://bugs.debian.org/828522 + +--- a/src/network/ssl/qsslcertificate.cpp ++++ b/src/network/ssl/qsslcertificate.cpp +@@ -259,10 +259,10 @@ + QByteArray QSslCertificate::version() const + { + QMutexLocker lock(QMutexPool::globalInstanceGet(d.data())); +- if (d->versionString.isEmpty() && d->x509) ++ if (d->versionString.isEmpty() && d->x509) { + d->versionString = +- QByteArray::number(qlonglong(q_ASN1_INTEGER_get(d->x509->cert_info->version)) + 1); +- ++ QByteArray::number(qlonglong(q_X509_get_version(d->x509)) + 1); ++ } + return d->versionString; + } + +@@ -276,7 +276,7 @@ + { + QMutexLocker lock(QMutexPool::globalInstanceGet(d.data())); + if (d->serialNumberString.isEmpty() && d->x509) { +- ASN1_INTEGER *serialNumber = d->x509->cert_info->serialNumber; ++ ASN1_INTEGER *serialNumber = q_X509_get_serialNumber(d->x509); + // if we cannot convert to a long, just output the hexadecimal number + if (serialNumber->length > 4) { + QByteArray hexString; +@@ -489,24 +489,33 @@ + QSslKey key; + + key.d->type = QSsl::PublicKey; ++#if OPENSSL_VERSION_NUMBER < 0x10100000L + X509_PUBKEY *xkey = d->x509->cert_info->key; ++#else ++ X509_PUBKEY *xkey = q_X509_get_X509_PUBKEY(d->x509); ++#endif + EVP_PKEY *pkey = q_X509_PUBKEY_get(xkey); + Q_ASSERT(pkey); + +- if (q_EVP_PKEY_type(pkey->type) == EVP_PKEY_RSA) { ++ int key_id; ++#if OPENSSL_VERSION_NUMBER < 0x10100000L ++ key_id = q_EVP_PKEY_type(pkey->type); ++#else ++ key_id = q_EVP_PKEY_base_id(pkey); ++#endif ++ if (key_id == EVP_PKEY_RSA) { + key.d->rsa = q_EVP_PKEY_get1_RSA(pkey); + key.d->algorithm = QSsl::Rsa; + key.d->isNull = false; +- } else if (q_EVP_PKEY_type(pkey->type) == EVP_PKEY_DSA) { ++ } else if (key_id == EVP_PKEY_DSA) { + key.d->dsa = q_EVP_PKEY_get1_DSA(pkey); + key.d->algorithm = QSsl::Dsa; + key.d->isNull = false; +- } else if (q_EVP_PKEY_type(pkey->type) == EVP_PKEY_DH) { ++ } else if (key_id == EVP_PKEY_DH) { + // DH unsupported + } else { + // error? + } +- + q_EVP_PKEY_free(pkey); + return key; + } +--- a/src/network/ssl/qsslkey.cpp ++++ b/src/network/ssl/qsslkey.cpp +@@ -321,8 +321,19 @@ + { + if (d->isNull) + return -1; ++#if OPENSSL_VERSION_NUMBER < 0x10100000L + return (d->algorithm == QSsl::Rsa) + ? q_BN_num_bits(d->rsa->n) : q_BN_num_bits(d->dsa->p); ++#else ++ if (d->algorithm == QSsl::Rsa) { ++ return q_RSA_bits(d->rsa); ++ }else{ ++ BIGNUM *p = NULL; ++ q_DSA_get0_pqg(d->dsa, &p, NULL, NULL); ++ return q_BN_num_bits(p); ++ } ++#endif ++ + } + + /*! +--- a/src/network/ssl/qsslsocket_openssl.cpp ++++ b/src/network/ssl/qsslsocket_openssl.cpp +@@ -93,6 +93,7 @@ + bool QSslSocketPrivate::s_loadedCiphersAndCerts = false; + bool QSslSocketPrivate::s_loadRootCertsOnDemand = false; + ++#if OPENSSL_VERSION_NUMBER < 0x10100000L + /* \internal + + From OpenSSL's thread(3) manual page: +@@ -174,6 +175,8 @@ + } + } // extern "C" + ++#endif //OPENSSL_VERSION_NUMBER >= 0x10100000L ++ + QSslSocketBackendPrivate::QSslSocketBackendPrivate() + : ssl(0), + ctx(0), +@@ -222,9 +225,12 @@ + ciph.d->encryptionMethod = descriptionList.at(4).mid(4); + ciph.d->exportable = (descriptionList.size() > 6 && descriptionList.at(6) == QLatin1String("export")); + ++#if OPENSSL_VERSION_NUMBER < 0x10100000L + ciph.d->bits = cipher->strength_bits; + ciph.d->supportedBits = cipher->alg_bits; +- ++#else ++ ciph.d->bits = q_SSL_CIPHER_get_bits(cipher, &ciph.d->supportedBits); ++#endif + } + return ciph; + } +@@ -367,7 +373,7 @@ + // + // See also: QSslContext::fromConfiguration() + if (caCertificate.expiryDate() >= QDateTime::currentDateTime()) { +- q_X509_STORE_add_cert(ctx->cert_store, (X509 *)caCertificate.handle()); ++ q_X509_STORE_add_cert(q_SSL_CTX_get_cert_store(ctx), (X509 *)caCertificate.handle()); + } + } + +@@ -504,8 +510,10 @@ + */ + void QSslSocketPrivate::deinitialize() + { ++#if OPENSSL_VERSION_NUMBER < 0x10100000L + q_CRYPTO_set_id_callback(0); + q_CRYPTO_set_locking_callback(0); ++#endif + } + + /*! +@@ -526,13 +534,17 @@ + return false; + + // Check if the library itself needs to be initialized. ++#if OPENSSL_VERSION_NUMBER < 0x10100000L + QMutexLocker locker(openssl_locks()->initLock()); ++#endif + if (!s_libraryLoaded) { + s_libraryLoaded = true; + + // Initialize OpenSSL. ++#if OPENSSL_VERSION_NUMBER < 0x10100000L + q_CRYPTO_set_id_callback(id_function); + q_CRYPTO_set_locking_callback(locking_function); ++#endif + if (q_SSL_library_init() != 1) + return false; + q_SSL_load_error_strings(); +@@ -571,7 +583,9 @@ + + void QSslSocketPrivate::ensureCiphersAndCertsLoaded() + { +- QMutexLocker locker(openssl_locks()->initLock()); ++#if OPENSSL_VERSION_NUMBER < 0x10100000L ++ QMutexLocker locker(openssl_locks()->initLock()); ++#endif + if (s_loadedCiphersAndCerts) + return; + s_loadedCiphersAndCerts = true; +@@ -663,13 +677,18 @@ + STACK_OF(SSL_CIPHER) *supportedCiphers = q_SSL_get_ciphers(mySsl); + for (int i = 0; i < q_sk_SSL_CIPHER_num(supportedCiphers); ++i) { + if (SSL_CIPHER *cipher = q_sk_SSL_CIPHER_value(supportedCiphers, i)) { +- if (cipher->valid) { ++ ++#if OPENSSL_VERSION_NUMBER < 0x10100000L ++ if (cipher->valid) { ++#endif + QSslCipher ciph = QSslSocketBackendPrivate::QSslCipher_from_SSL_CIPHER(cipher); + if (!ciph.isNull()) { + if (!ciph.name().toLower().startsWith(QLatin1String("adh"))) + ciphers << ciph; + } ++#if OPENSSL_VERSION_NUMBER < 0x10100000L + } ++#endif + } + } + +--- a/src/network/ssl/qsslsocket_openssl_symbols_p.h ++++ b/src/network/ssl/qsslsocket_openssl_symbols_p.h +@@ -399,7 +399,25 @@ + PEM_ASN1_write_bio((int (*)(void*, unsigned char**))q_i2d_DSAPrivateKey,PEM_STRING_DSA,\ + bp,(char *)x,enc,kstr,klen,cb,u) + #endif ++ ++X509_STORE * q_SSL_CTX_get_cert_store(const SSL_CTX *ctx); ++ASN1_INTEGER * q_X509_get_serialNumber(X509 *x); ++ ++#if OPENSSL_VERSION_NUMBER < 0x10100000L + #define q_SSL_CTX_set_options(ctx,op) q_SSL_CTX_ctrl((ctx),SSL_CTRL_OPTIONS,(op),NULL) ++#define q_X509_get_version(x) X509_get_version(x) ++#else ++int q_EVP_PKEY_id(const EVP_PKEY *pkey); ++int q_EVP_PKEY_base_id(const EVP_PKEY *pkey); ++int q_SSL_CIPHER_get_bits(const SSL_CIPHER *cipher, int *alg_bits); ++long q_SSL_CTX_set_options(SSL_CTX *ctx, long options); ++long q_X509_get_version(X509 *x); ++X509_PUBKEY * q_X509_get_X509_PUBKEY(X509 *x); ++int q_RSA_bits(const RSA *rsa); ++int q_DSA_security_bits(const DSA *dsa); ++void q_DSA_get0_pqg(const DSA *d, BIGNUM **p, BIGNUM **q, BIGNUM **g); ++#endif ++ + #define q_SKM_sk_num(type, st) ((int (*)(const STACK_OF(type) *))q_sk_num)(st) + #define q_SKM_sk_value(type, st,i) ((type * (*)(const STACK_OF(type) *, int))q_sk_value)(st, i) + #define q_sk_GENERAL_NAME_num(st) q_SKM_sk_num(GENERAL_NAME, (st)) +@@ -410,8 +428,15 @@ + #define q_sk_SSL_CIPHER_value(st, i) q_SKM_sk_value(SSL_CIPHER, (st), (i)) + #define q_SSL_CTX_add_extra_chain_cert(ctx,x509) \ + q_SSL_CTX_ctrl(ctx,SSL_CTRL_EXTRA_CHAIN_CERT,0,(char *)x509) ++ ++#if OPENSSL_VERSION_NUMBER < 0x10100000L + #define q_X509_get_notAfter(x) X509_get_notAfter(x) + #define q_X509_get_notBefore(x) X509_get_notBefore(x) ++#else ++ASN1_TIME *q_X509_get_notAfter(X509 *x); ++ASN1_TIME *q_X509_get_notBefore(X509 *x); ++#endif ++ + #define q_EVP_PKEY_assign_RSA(pkey,rsa) q_EVP_PKEY_assign((pkey),EVP_PKEY_RSA,\ + (char *)(rsa)) + #define q_EVP_PKEY_assign_DSA(pkey,dsa) q_EVP_PKEY_assign((pkey),EVP_PKEY_DSA,\ +--- a/src/network/ssl/qsslsocket_openssl_symbols.cpp ++++ b/src/network/ssl/qsslsocket_openssl_symbols.cpp +@@ -290,6 +290,22 @@ + DEFINEFUNC(void, OPENSSL_add_all_algorithms_conf, void, DUMMYARG, return, DUMMYARG) + DEFINEFUNC3(int, SSL_CTX_load_verify_locations, SSL_CTX *ctx, ctx, const char *CAfile, CAfile, const char *CApath, CApath, return 0, return) + DEFINEFUNC(long, SSLeay, void, DUMMYARG, return 0, return) ++DEFINEFUNC(X509_STORE *, SSL_CTX_get_cert_store, const SSL_CTX *ctx, ctx, return 0, return) ++ ++DEFINEFUNC(ASN1_INTEGER *, X509_get_serialNumber, X509 *x, x, return 0, return) ++#if OPENSSL_VERSION_NUMBER >= 0x10100000L ++DEFINEFUNC(int, EVP_PKEY_id, const EVP_PKEY *pkey, pkey, return 0, return) ++DEFINEFUNC(int, EVP_PKEY_base_id, const EVP_PKEY *pkey, pkey, return 0, return) ++DEFINEFUNC2(int, SSL_CIPHER_get_bits, const SSL_CIPHER *cipher, cipher, int *alg_bits, alg_bits, return 0, return) ++DEFINEFUNC2(long, SSL_CTX_set_options, SSL_CTX *ctx, ctx, long options, options, return 0, return) ++DEFINEFUNC(long, X509_get_version, X509 *x, x, return 0, return) ++DEFINEFUNC(X509_PUBKEY *, X509_get_X509_PUBKEY, X509 *x, x, return 0, return) ++DEFINEFUNC(int, RSA_bits, const RSA *rsa, rsa, return 0, return) ++DEFINEFUNC(int, DSA_security_bits, const DSA *dsa, dsa, return 0, return) ++DEFINEFUNC(ASN1_TIME *, X509_get_notAfter, X509 *x, x, return 0, return) ++DEFINEFUNC(ASN1_TIME *, X509_get_notBefore, X509 *x, x, return 0, return) ++DEFINEFUNC4(void, DSA_get0_pqg, const DSA *d, d, BIGNUM **p, p, BIGNUM **q, q, BIGNUM **g, g, return, return) ++#endif + + #ifdef Q_OS_SYMBIAN + #define RESOLVEFUNC(func, ordinal, lib) \ +@@ -801,6 +817,7 @@ + RESOLVEFUNC(SSL_CTX_use_PrivateKey) + RESOLVEFUNC(SSL_CTX_use_RSAPrivateKey) + RESOLVEFUNC(SSL_CTX_use_PrivateKey_file) ++ RESOLVEFUNC(SSL_CTX_get_cert_store) + RESOLVEFUNC(SSL_accept) + RESOLVEFUNC(SSL_clear) + RESOLVEFUNC(SSL_connect) +@@ -823,6 +840,23 @@ + RESOLVEFUNC(SSL_set_connect_state) + RESOLVEFUNC(SSL_shutdown) + RESOLVEFUNC(SSL_write) ++ ++ RESOLVEFUNC(X509_get_serialNumber) ++#if OPENSSL_VERSION_NUMBER >= 0x10100000L ++ RESOLVEFUNC(SSL_CTX_ctrl) ++ RESOLVEFUNC(EVP_PKEY_id) ++ RESOLVEFUNC(EVP_PKEY_base_id) ++ RESOLVEFUNC(SSL_CIPHER_get_bits) ++ RESOLVEFUNC(SSL_CTX_set_options) ++ RESOLVEFUNC(X509_get_version) ++ RESOLVEFUNC(X509_get_X509_PUBKEY) ++ RESOLVEFUNC(RSA_bits) ++ RESOLVEFUNC(DSA_security_bits) ++ RESOLVEFUNC(DSA_get0_pqg) ++ RESOLVEFUNC(X509_get_notAfter) ++ RESOLVEFUNC(X509_get_notBefore) ++#endif ++ + #ifndef OPENSSL_NO_SSL2 + RESOLVEFUNC(SSLv2_client_method) + #endif +--- qt-everywhere-opensource-src-4.8.7/src/network/ssl/qsslkey.cpp.0131~ 2017-03-15 02:22:37.053244125 +0100 ++++ qt-everywhere-opensource-src-4.8.7/src/network/ssl/qsslkey.cpp 2017-03-15 02:22:37.055244057 +0100 +@@ -328,7 +328,7 @@ int QSslKey::length() const + if (d->algorithm == QSsl::Rsa) { + return q_RSA_bits(d->rsa); + }else{ +- BIGNUM *p = NULL; ++ const BIGNUM *p = NULL; + q_DSA_get0_pqg(d->dsa, &p, NULL, NULL); + return q_BN_num_bits(p); + } +--- qt-everywhere-opensource-src-4.8.7/src/network/ssl/qsslsocket_openssl_symbols.cpp.0131~ 2017-03-15 02:22:37.054244091 +0100 ++++ qt-everywhere-opensource-src-4.8.7/src/network/ssl/qsslsocket_openssl_symbols.cpp 2017-03-15 02:29:41.155236836 +0100 +@@ -111,16 +111,16 @@ DEFINEFUNC(int, ASN1_STRING_length, ASN1 + DEFINEFUNC2(int, ASN1_STRING_to_UTF8, unsigned char **a, a, ASN1_STRING *b, b, return 0, return); + DEFINEFUNC4(long, BIO_ctrl, BIO *a, a, int b, b, long c, c, void *d, d, return -1, return) + DEFINEFUNC(int, BIO_free, BIO *a, a, return 0, return) +-DEFINEFUNC(BIO *, BIO_new, BIO_METHOD *a, a, return 0, return) ++DEFINEFUNC(BIO *, BIO_new, const BIO_METHOD *a, a, return 0, return) + DEFINEFUNC2(BIO *, BIO_new_mem_buf, void *a, a, int b, b, return 0, return) + DEFINEFUNC3(int, BIO_read, BIO *a, a, void *b, b, int c, c, return -1, return) +-DEFINEFUNC(BIO_METHOD *, BIO_s_mem, void, DUMMYARG, return 0, return) ++DEFINEFUNC(const BIO_METHOD *, BIO_s_mem, void, DUMMYARG, return 0, return) + DEFINEFUNC3(int, BIO_write, BIO *a, a, const void *b, b, int c, c, return -1, return) + DEFINEFUNC(int, BN_num_bits, const BIGNUM *a, a, return 0, return) + DEFINEFUNC(int, CRYPTO_num_locks, DUMMYARG, DUMMYARG, return 0, return) + DEFINEFUNC(void, CRYPTO_set_locking_callback, void (*a)(int, int, const char *, int), a, return, DUMMYARG) + DEFINEFUNC(void, CRYPTO_set_id_callback, unsigned long (*a)(), a, return, DUMMYARG) +-DEFINEFUNC(void, CRYPTO_free, void *a, a, return, DUMMYARG) ++DEFINEFUNC(void, OPENSSL_free, void *a, a, return, DUMMYARG) + DEFINEFUNC(void, DSA_free, DSA *a, a, return, DUMMYARG) + #if OPENSSL_VERSION_NUMBER < 0x00908000L + DEFINEFUNC3(X509 *, d2i_X509, X509 **a, a, unsigned char **b, b, long c, c, return 0, return) +@@ -300,7 +300,7 @@ DEFINEFUNC(int, RSA_bits, const RSA *rs + DEFINEFUNC(int, DSA_security_bits, const DSA *dsa, dsa, return 0, return) + DEFINEFUNC(ASN1_TIME *, X509_get_notAfter, X509 *x, x, return 0, return) + DEFINEFUNC(ASN1_TIME *, X509_get_notBefore, X509 *x, x, return 0, return) +-DEFINEFUNC4(void, DSA_get0_pqg, const DSA *d, d, BIGNUM **p, p, BIGNUM **q, q, BIGNUM **g, g, return, return) ++DEFINEFUNC4(void, DSA_get0_pqg, const DSA *d, d, const BIGNUM **p, p, const BIGNUM **q, q, const BIGNUM **g, g, return, return) + #endif + + #ifdef Q_OS_SYMBIAN +--- qt-everywhere-opensource-src-4.8.7/src/network/ssl/qsslsocket_openssl_symbols_p.h.0131~ 2017-03-15 02:22:37.054244091 +0100 ++++ qt-everywhere-opensource-src-4.8.7/src/network/ssl/qsslsocket_openssl_symbols_p.h 2017-03-15 02:29:50.192986268 +0100 +@@ -59,6 +59,9 @@ + QT_BEGIN_NAMESPACE + + #define DUMMYARG ++#ifndef OPENSSL_NO_SSL2 ++#define OPENSSL_NO_SSL2 1 ++#endif + + #if !defined QT_LINKED_OPENSSL + // **************** Shared declarations ****************** +@@ -207,16 +210,16 @@ int q_ASN1_STRING_length(ASN1_STRING *a) + int q_ASN1_STRING_to_UTF8(unsigned char **a, ASN1_STRING *b); + long q_BIO_ctrl(BIO *a, int b, long c, void *d); + int q_BIO_free(BIO *a); +-BIO *q_BIO_new(BIO_METHOD *a); ++BIO *q_BIO_new(const BIO_METHOD *a); + BIO *q_BIO_new_mem_buf(void *a, int b); + int q_BIO_read(BIO *a, void *b, int c); +-BIO_METHOD *q_BIO_s_mem(); ++const BIO_METHOD *q_BIO_s_mem(); + int q_BIO_write(BIO *a, const void *b, int c); + int q_BN_num_bits(const BIGNUM *a); + int q_CRYPTO_num_locks(); + void q_CRYPTO_set_locking_callback(void (*a)(int, int, const char *, int)); + void q_CRYPTO_set_id_callback(unsigned long (*a)()); +-void q_CRYPTO_free(void *a); ++void q_OPENSSL_free(void *a); + void q_DSA_free(DSA *a); + #if OPENSSL_VERSION_NUMBER >= 0x00908000L + // 0.9.8 broke SC and BC by changing this function's signature. +@@ -326,7 +329,6 @@ void q_SSL_set_accept_state(SSL *a); + void q_SSL_set_connect_state(SSL *a); + int q_SSL_shutdown(SSL *a); + #if OPENSSL_VERSION_NUMBER >= 0x10000000L +-const SSL_METHOD *q_SSLv2_client_method(); + const SSL_METHOD *q_SSLv3_client_method(); + const SSL_METHOD *q_SSLv23_client_method(); + const SSL_METHOD *q_TLSv1_client_method(); +@@ -335,7 +337,6 @@ const SSL_METHOD *q_SSLv3_server_method( + const SSL_METHOD *q_SSLv23_server_method(); + const SSL_METHOD *q_TLSv1_server_method(); + #else +-SSL_METHOD *q_SSLv2_client_method(); + SSL_METHOD *q_SSLv3_client_method(); + SSL_METHOD *q_SSLv23_client_method(); + SSL_METHOD *q_TLSv1_client_method(); +@@ -415,7 +416,7 @@ long q_X509_get_version(X509 *x); + X509_PUBKEY * q_X509_get_X509_PUBKEY(X509 *x); + int q_RSA_bits(const RSA *rsa); + int q_DSA_security_bits(const DSA *dsa); +-void q_DSA_get0_pqg(const DSA *d, BIGNUM **p, BIGNUM **q, BIGNUM **g); ++void q_DSA_get0_pqg(const DSA *d, const BIGNUM **p, const BIGNUM **q, const BIGNUM **g); + #endif + + #define q_SKM_sk_num(type, st) ((int (*)(const STACK_OF(type) *))q_sk_num)(st) +--- qt-everywhere-opensource-src-4.8.7/src/network/ssl/qsslcertificate.cpp.omv~ 2017-03-15 02:27:18.143322736 +0100 ++++ qt-everywhere-opensource-src-4.8.7/src/network/ssl/qsslcertificate.cpp 2017-03-15 02:29:56.215819741 +0100 +@@ -696,7 +696,7 @@ + unsigned char *data = 0; + int size = q_ASN1_STRING_to_UTF8(&data, q_X509_NAME_ENTRY_get_data(e)); + info[QString::fromUtf8(obj)] = QString::fromUtf8((char*)data, size); +- q_CRYPTO_free(data); ++ q_OPENSSL_free(data); + } + return info; + } diff --git a/subprojects/shared-modules/smpeg/smpeg-0.4.5.json b/subprojects/shared-modules/smpeg/smpeg-0.4.5.json new file mode 100644 index 00000000..a4d82aab --- /dev/null +++ b/subprojects/shared-modules/smpeg/smpeg-0.4.5.json @@ -0,0 +1,39 @@ +{ + "name": "smpeg", + "config-opts": ["--disable-static"], + "cleanup": [ + "/bin", + "/man" + ], + "rm-configure": true, + "sources": [ + { + "type": "archive", + "url": "http://http.debian.net/debian/pool/main/s/smpeg/smpeg_0.4.5+cvs20030824.orig.tar.gz", + "sha256": "1276ea797dd9fde8a12dd3f33f180153922544c28ca9fc7b477c018876be1916" + }, + { + "type": "script", + "dest-filename": "autogen.sh", + "commands": [ + "AUTOMAKE=\"automake --foreign --add-missing --force-missing\" autoreconf -vfi" + ] + }, + { + "type": "patch", + "path": "smpeg-am-prog-as.patch" + }, + { + "type": "patch", + "path": "smpeg-export-mpegaudio-class.patch" + }, + { + "type": "patch", + "path": "smpeg-no-gtk.patch" + }, + { + "type": "patch", + "path": "smpeg-gcc6.patch" + } + ] +} diff --git a/subprojects/shared-modules/smpeg/smpeg-am-prog-as.patch b/subprojects/shared-modules/smpeg/smpeg-am-prog-as.patch new file mode 100644 index 00000000..36197d71 --- /dev/null +++ b/subprojects/shared-modules/smpeg/smpeg-am-prog-as.patch @@ -0,0 +1,12 @@ +Index: smpeg-0.4.5+cvs20030824/configure.in +=================================================================== +--- smpeg-0.4.5+cvs20030824.orig/configure.in ++++ smpeg-0.4.5+cvs20030824/configure.in +@@ -57,6 +57,7 @@ + AC_LIBTOOL_WIN32_DLL + AM_PROG_LIBTOOL + AC_PROG_INSTALL ++AM_PROG_AS + + dnl Ugh. + AS="$CC" diff --git a/subprojects/shared-modules/smpeg/smpeg-export-mpegaudio-class.patch b/subprojects/shared-modules/smpeg/smpeg-export-mpegaudio-class.patch new file mode 100644 index 00000000..9ecb9b58 --- /dev/null +++ b/subprojects/shared-modules/smpeg/smpeg-export-mpegaudio-class.patch @@ -0,0 +1,17 @@ +--- smpeg-0.4.5+cvs20030824.orig/MPEGaudio.h ++++ smpeg-0.4.5+cvs20030824/MPEGaudio.h +@@ -149,6 +149,14 @@ + }; + + /* The actual MPEG audio class */ ++ ++class MPEGaudio; ++void Play_MPEGaudioSDL(void *udata, Uint8 *stream, int len); ++int Play_MPEGaudio(MPEGaudio *audio, Uint8 *stream, int len); ++#ifdef THREADED_AUDIO ++int Decode_MPEGaudio(void *udata); ++#endif ++ + class MPEGaudio : public MPEGerror, public MPEGaudioaction { + + friend void Play_MPEGaudioSDL(void *udata, Uint8 *stream, int len); diff --git a/subprojects/shared-modules/smpeg/smpeg-gcc6.patch b/subprojects/shared-modules/smpeg/smpeg-gcc6.patch new file mode 100644 index 00000000..21b30da5 --- /dev/null +++ b/subprojects/shared-modules/smpeg/smpeg-gcc6.patch @@ -0,0 +1,40 @@ +Description: Fix compiling with GCC 6. +Author: Johannes Brandstätter <jbrandst@2ds.eu> +Bug-Debian: https://bugs.debian.org/811742 +Last-Update: <2016-09-24> + +Index: smpeg-0.4.5+cvs20030824/audio/huffmantable.cpp +=================================================================== +--- smpeg-0.4.5+cvs20030824.orig/audio/huffmantable.cpp ++++ smpeg-0.4.5+cvs20030824/audio/huffmantable.cpp +@@ -9,6 +9,7 @@ + #include "config.h" + #endif + ++#include <climits> + #include "MPEGaudio.h" + + static const unsigned int +@@ -550,11 +551,11 @@ htd33[ 31][2]={{ 16, 1},{ 8, 1},{ 4, + + const HUFFMANCODETABLE MPEGaudio::ht[HTN]= + { +- { 0, 0-1, 0-1, 0, 0, htd33}, ++ { 0, UINT_MAX, UINT_MAX, 0, 0, htd33}, + { 1, 2-1, 2-1, 0, 7,htd01}, + { 2, 3-1, 3-1, 0, 17,htd02}, + { 3, 3-1, 3-1, 0, 17,htd03}, +- { 4, 0-1, 0-1, 0, 0, htd33}, ++ { 4, UINT_MAX, UINT_MAX, 0, 0, htd33}, + { 5, 4-1, 4-1, 0, 31,htd05}, + { 6, 4-1, 4-1, 0, 31,htd06}, + { 7, 6-1, 6-1, 0, 71,htd07}, +@@ -564,7 +565,7 @@ const HUFFMANCODETABLE MPEGaudio::ht[HTN + {11, 8-1, 8-1, 0,127,htd11}, + {12, 8-1, 8-1, 0,127,htd12}, + {13,16-1,16-1, 0,511,htd13}, +- {14, 0-1, 0-1, 0, 0, htd33}, ++ {14, UINT_MAX, UINT_MAX, 0, 0, htd33}, + {15,16-1,16-1, 0,511,htd15}, + {16,16-1,16-1, 1,511,htd16}, + {17,16-1,16-1, 2,511,htd16}, diff --git a/subprojects/shared-modules/smpeg/smpeg-no-gtk.patch b/subprojects/shared-modules/smpeg/smpeg-no-gtk.patch new file mode 100644 index 00000000..792596cf --- /dev/null +++ b/subprojects/shared-modules/smpeg/smpeg-no-gtk.patch @@ -0,0 +1,37 @@ +From 62cda978596a323cd7042722f906df906007e5b5 Mon Sep 17 00:00:00 2001 +From: Cosimo Cecchi <cosimoc@gnome.org> +Date: Sat, 15 Apr 2017 13:24:39 -0700 +Subject: [PATCH] Comment out GTK detection + +--- + configure.in | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +diff --git a/configure.in b/configure.in +index 20b1355..2cb4753 100644 +--- a/configure.in ++++ b/configure.in +@@ -208,13 +208,13 @@ AC_ARG_ENABLE(gtk_player, + [ --enable-gtk-player build a GTk sample SMPEG player [default=yes]], + , enable_gtk_player=yes) + have_gtk=no +-if test x$enable_gtk_player = xyes; then +- AM_PATH_GTK(1.2.1, have_gtk=yes) +- if test x$have_gtk = xyes; then +- CFLAGS="$CFLAGS $GTK_CFLAGS" +- fi +- AC_SUBST(GTK_LIBS) +-fi ++dnl if test x$enable_gtk_player = xyes; then ++dnl AM_PATH_GTK(1.2.1, have_gtk=yes) ++dnl if test x$have_gtk = xyes; then ++dnl CFLAGS="$CFLAGS $GTK_CFLAGS" ++dnl fi ++dnl AC_SUBST(GTK_LIBS) ++dnl fi + AM_CONDITIONAL(HAVE_GTK, test x$have_gtk = xyes) + + dnl See if we can build the Mesa player +-- +2.12.2 + |