[seed] Adding GjsPrivate module to Seed



commit b8bd0859870d00a29ea33775e5cf7f73f1f4b8e8
Author: Danilo Cesar Lemes de Paula <danilo cesar collabora co uk>
Date:   Thu Mar 3 15:34:05 2016 -0300

    Adding GjsPrivate module to Seed
    
    This GjsPrivate module will be accessed via GI for modules
    inside the gjs extension in Seed.

 Makefile.am                        |    2 +
 configure.ac                       |    3 +
 extensions/Seed.js.in              |    6 +
 libgjs-private/Makefile.am         |   54 ++++++
 libgjs-private/gjs-gdbus-wrapper.c |  336 ++++++++++++++++++++++++++++++++++++
 libgjs-private/gjs-gdbus-wrapper.h |   74 ++++++++
 libgjs-private/gjs-gtk-util.c      |   63 +++++++
 libgjs-private/gjs-gtk-util.h      |   37 ++++
 libgjs-private/gjs-util.c          |  110 ++++++++++++
 libgjs-private/gjs-util.h          |   58 ++++++
 10 files changed, 743 insertions(+), 0 deletions(-)
---
diff --git a/Makefile.am b/Makefile.am
index c7be24b..15c4472 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,9 +1,11 @@
 ## Process this file with automake to produce Makefile.in
 
 ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS}
+DISTCHECK_CONFIGURE_FLAGS = --enable-introspection
 
 SUBDIRS = po \
        libseed \
+       libgjs-private \
        src \
        extensions \
        modules \
diff --git a/configure.ac b/configure.ac
index a82027d..bfa7351 100644
--- a/configure.ac
+++ b/configure.ac
@@ -112,6 +112,7 @@ AC_SUBST(WEBKIT_LDFLAGS)
 AC_SUBST(SEED_GTK_VERSION)
 
 dnl =========================Introspection=====================================
+GOBJECT_INTROSPECTION_CHECK([1.41.4])
 
 PKG_CHECK_MODULES(GOBJECT_INTROSPECTION, gobject-introspection-1.0 >= 0.6.3)
 AC_SUBST(GOBJECT_INTROSPECTION_CFLAGS)
@@ -485,6 +486,8 @@ doc/modules/sandbox/Makefile
 doc/mapping/mapping.html
 
 libseed/Makefile
+libgjs-private/Makefile
+
 po/Makefile.in
 src/Makefile
 extensions/Makefile
diff --git a/extensions/Seed.js.in b/extensions/Seed.js.in
index b5b7c6c..3d576d0 100644
--- a/extensions/Seed.js.in
+++ b/extensions/Seed.js.in
@@ -35,6 +35,12 @@ if(!imports.searchPath || (imports.searchPath.length == 0))
        imports.searchPath.unshift(".");
 }
 
+// TODO: This will work, but won't work if not installed
+// that's a bit OK at the moment, as Seed doesn't work properly uninstalled anyway.
+// But it should be fixed soon!
+const GIRepository = imports.gi.GIRepository;
+GIRepository.Repository.prepend_search_path("%pkglibdir%/girepository-1.0/");
+
 Seed.sprintf = function ()
 {
     if (typeof arguments == "undefined") { return null; }
diff --git a/libgjs-private/Makefile.am b/libgjs-private/Makefile.am
new file mode 100644
index 0000000..9d8bcc2
--- /dev/null
+++ b/libgjs-private/Makefile.am
@@ -0,0 +1,54 @@
+-include $(INTROSPECTION_MAKEFILE)
+INTROSPECTION_GIRS =
+
+lib_LTLIBRARIES = \
+       libseed_gjsprivate.la
+
+libgjs_private_source_files = \
+       gjs-gdbus-wrapper.c    \
+       gjs-gdbus-wrapper.h      \
+       gjs-util.c     \
+       gjs-util.h       \
+       gjs-gtk-util.h   \
+       gjs-gtk-util.c   \
+       $(NULL)
+
+libseed_gjsprivate_la_SOURCES = $(libgjs_private_source_files)
+
+AM_CPPFLAGS = \
+       -I top_srcdir@/libseed/ \
+       $(GOBJECT_INTROSPECTION_CFLAGS) \
+       $(SEED_DEBUG_CFLAGS) \
+       $(GTK_CFLAGS) \
+       $(SEED_PROFILE_CFLAGS)
+
+libseed_gjsprivate_la_LDFLAGS = \
+       -module -avoid-version \
+       $(GOBJECT_INTROSPECTION_LDFLAGS)
+
+libseed_gjsprivate_la_LIBADD = \
+       $(top_builddir)/libseed/libseed SEED_GTK_VERSION@.la \
+       $(GTK_LIBS) \
+       $(SEED_PROFILE_LIBS)
+
+INTROSPECTION_SCANNER_ARGS = \
+       --add-include-path= top_srcdir@ --add-include-path=$(GTK_CFLAGS) --warn-all
+INTROSPECTION_COMPILER_ARGS = \
+       --includedir= top_srcdir@
+
+GjsPrivate-1.0.gir: libseed_gjsprivate.la
+GjsPrivate_1_0_gir_INCLUDES = GObject-2.0 Gio-2.0
+GjsPrivate_1_0_gir_CFLAGS = $(INCLUDES)
+GjsPrivate_1_0_gir_LIBS = libseed_gjsprivate.la
+GjsPrivate_1_0_gir_FILES = $(libgjs_private_source_files)
+INTROSPECTION_GIRS += GjsPrivate-1.0.gir
+
+GjsPrivate_1_0_gir_SCANNERFLAGS = --identifier-prefix=Gjs --symbol-prefix=gjs_ --warn-all
+girdir = $(datadir)/gir-1.0
+gir_DATA = $(INTROSPECTION_GIRS)
+
+typelibdir = $(pkglibdir)@SEED_GTK_VERSION@/girepository-1.0
+typelib_DATA = $(INTROSPECTION_GIRS:.gir=.typelib)
+
+CLEANFILES = $(gir_DATA) $(typelib_DATA)
+
diff --git a/libgjs-private/gjs-gdbus-wrapper.c b/libgjs-private/gjs-gdbus-wrapper.c
new file mode 100644
index 0000000..f01d629
--- /dev/null
+++ b/libgjs-private/gjs-gdbus-wrapper.c
@@ -0,0 +1,336 @@
+/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
+/* Copyright 2011 Giovanni Campagna. All Rights Reserved. */
+
+#include <config.h>
+#include <string.h>
+
+#include "gjs-gdbus-wrapper.h"
+
+enum
+{
+    PROP_0,
+    PROP_G_INTERFACE_INFO,
+    PROP_LAST
+};
+
+enum
+{
+    SIGNAL_HANDLE_METHOD,
+    SIGNAL_HANDLE_PROPERTY_GET,
+    SIGNAL_HANDLE_PROPERTY_SET,
+    SIGNAL_LAST,
+};
+
+static guint signals[SIGNAL_LAST];
+
+struct _GjsDBusImplementationPrivate
+{
+    GDBusInterfaceVTable vtable;
+    GDBusInterfaceInfo* ifaceinfo;
+
+    // from gchar* to GVariant*
+    GHashTable* outstanding_properties;
+    guint idle_id;
+};
+
+G_DEFINE_TYPE(GjsDBusImplementation,
+              gjs_dbus_implementation,
+              G_TYPE_DBUS_INTERFACE_SKELETON)
+
+static void
+gjs_dbus_implementation_method_call(GDBusConnection* connection,
+                                    const char* sender,
+                                    const char* object_path,
+                                    const char* interface_name,
+                                    const char* method_name,
+                                    GVariant* parameters,
+                                    GDBusMethodInvocation* invocation,
+                                    gpointer user_data)
+{
+    GjsDBusImplementation* self = GJS_DBUS_IMPLEMENTATION(user_data);
+
+    g_signal_emit(self, signals[SIGNAL_HANDLE_METHOD], 0, method_name,
+                  parameters, invocation);
+    g_object_unref(invocation);
+}
+
+static GVariant*
+gjs_dbus_implementation_property_get(GDBusConnection* connection,
+                                     const char* sender,
+                                     const char* object_path,
+                                     const char* interface_name,
+                                     const char* property_name,
+                                     GError** error,
+                                     gpointer user_data)
+{
+    GjsDBusImplementation* self = GJS_DBUS_IMPLEMENTATION(user_data);
+    GVariant* value;
+
+    g_signal_emit(self, signals[SIGNAL_HANDLE_PROPERTY_GET], 0, property_name,
+                  &value);
+
+    /* Marshaling GErrors is not supported, so this is the best we can do
+       (GIO will assert if value is NULL and error is not set) */
+    if (!value)
+        g_set_error(error, g_quark_from_static_string("gjs-error-domain"), 0,
+                    "Property retrieval failed");
+
+    return value;
+}
+
+static gboolean
+gjs_dbus_implementation_property_set(GDBusConnection* connection,
+                                     const char* sender,
+                                     const char* object_path,
+                                     const char* interface_name,
+                                     const char* property_name,
+                                     GVariant* value,
+                                     GError** error,
+                                     gpointer user_data)
+{
+    GjsDBusImplementation* self = GJS_DBUS_IMPLEMENTATION(user_data);
+
+    g_signal_emit(self, signals[SIGNAL_HANDLE_PROPERTY_SET], 0, property_name,
+                  value);
+
+    return TRUE;
+}
+
+static void
+gjs_dbus_implementation_init(GjsDBusImplementation* self)
+{
+    GjsDBusImplementationPrivate* priv
+      = G_TYPE_INSTANCE_GET_PRIVATE(self, GJS_TYPE_DBUS_IMPLEMENTATION,
+                                    GjsDBusImplementationPrivate);
+
+    self->priv = priv;
+
+    priv->vtable.method_call = gjs_dbus_implementation_method_call;
+    priv->vtable.get_property = gjs_dbus_implementation_property_get;
+    priv->vtable.set_property = gjs_dbus_implementation_property_set;
+
+    priv->outstanding_properties
+      = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
+                              (GDestroyNotify) g_variant_unref);
+}
+
+static void
+gjs_dbus_implementation_finalize(GObject* object)
+{
+    GjsDBusImplementation* self = GJS_DBUS_IMPLEMENTATION(object);
+
+    g_dbus_interface_info_unref(self->priv->ifaceinfo);
+    g_hash_table_unref(self->priv->outstanding_properties);
+
+    G_OBJECT_CLASS(gjs_dbus_implementation_parent_class)->finalize(object);
+}
+
+static void
+gjs_dbus_implementation_set_property(GObject* object,
+                                     guint property_id,
+                                     const GValue* value,
+                                     GParamSpec* pspec)
+{
+    GjsDBusImplementation* self = GJS_DBUS_IMPLEMENTATION(object);
+
+    switch (property_id) {
+        case PROP_G_INTERFACE_INFO:
+            self->priv->ifaceinfo
+              = (GDBusInterfaceInfo*) g_value_dup_boxed(value);
+            break;
+        default:
+            G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
+    }
+}
+
+static GDBusInterfaceInfo*
+gjs_dbus_implementation_get_info(GDBusInterfaceSkeleton* skeleton)
+{
+    GjsDBusImplementation* self = GJS_DBUS_IMPLEMENTATION(skeleton);
+
+    return self->priv->ifaceinfo;
+}
+
+static GDBusInterfaceVTable*
+gjs_dbus_implementation_get_vtable(GDBusInterfaceSkeleton* skeleton)
+{
+    GjsDBusImplementation* self = GJS_DBUS_IMPLEMENTATION(skeleton);
+
+    return &(self->priv->vtable);
+}
+
+static GVariant*
+gjs_dbus_implementation_get_properties(GDBusInterfaceSkeleton* skeleton)
+{
+    GjsDBusImplementation* self = GJS_DBUS_IMPLEMENTATION(skeleton);
+
+    GDBusInterfaceInfo* info = self->priv->ifaceinfo;
+    GDBusPropertyInfo** props;
+    GVariantBuilder builder;
+
+    g_variant_builder_init(&builder, G_VARIANT_TYPE_VARDICT);
+
+    for (props = info->properties; *props; ++props) {
+        GDBusPropertyInfo* prop = *props;
+        GVariant* value;
+
+        /* If we have a cached value, we use that instead of querying again */
+        if ((value = (GVariant*) g_hash_table_lookup(
+               self->priv->outstanding_properties, prop->name))) {
+            g_variant_builder_add(&builder, "{sv}", prop->name, value);
+            continue;
+        }
+
+        g_signal_emit(self, signals[SIGNAL_HANDLE_PROPERTY_GET], 0, prop->name,
+                      &value);
+        g_variant_builder_add(&builder, "{sv}", prop->name, value);
+    }
+
+    return g_variant_builder_end(&builder);
+}
+
+static void
+gjs_dbus_implementation_flush(GDBusInterfaceSkeleton* skeleton)
+{
+    GjsDBusImplementation* self = GJS_DBUS_IMPLEMENTATION(skeleton);
+
+    GVariantBuilder changed_props;
+    GVariantBuilder invalidated_props;
+    GHashTableIter iter;
+    GVariant* val;
+    gchar* prop_name;
+
+    g_variant_builder_init(&changed_props, G_VARIANT_TYPE_VARDICT);
+    g_variant_builder_init(&invalidated_props, G_VARIANT_TYPE_STRING_ARRAY);
+
+    g_hash_table_iter_init(&iter, self->priv->outstanding_properties);
+    while (g_hash_table_iter_next(&iter, (void**) &prop_name, (void**) &val)) {
+        if (val)
+            g_variant_builder_add(&changed_props, "{sv}", prop_name, val);
+        else
+            g_variant_builder_add(&invalidated_props, "s", prop_name);
+    }
+
+    g_dbus_connection_emit_signal(
+      g_dbus_interface_skeleton_get_connection(skeleton), NULL, /* bus name */
+      g_dbus_interface_skeleton_get_object_path(skeleton),
+      "org.freedesktop.DBus.Properties", "PropertiesChanged",
+      g_variant_new("(s a{sv}@as)", self->priv->ifaceinfo->name,
+                    g_variant_builder_end(&changed_props),
+                    g_variant_builder_end(&invalidated_props)),
+      NULL /* error */);
+
+    g_hash_table_remove_all(self->priv->outstanding_properties);
+    if (self->priv->idle_id) {
+        g_source_remove(self->priv->idle_id);
+        self->priv->idle_id = 0;
+    }
+}
+
+void
+gjs_dbus_implementation_class_init(GjsDBusImplementationClass* klass)
+{
+    GObjectClass* gobject_class = G_OBJECT_CLASS(klass);
+    GDBusInterfaceSkeletonClass* skeleton_class
+      = G_DBUS_INTERFACE_SKELETON_CLASS(klass);
+
+    g_type_class_add_private(klass, sizeof(GjsDBusImplementationPrivate));
+
+    gobject_class->finalize = gjs_dbus_implementation_finalize;
+    gobject_class->set_property = gjs_dbus_implementation_set_property;
+
+    skeleton_class->get_info = gjs_dbus_implementation_get_info;
+    skeleton_class->get_vtable = gjs_dbus_implementation_get_vtable;
+    skeleton_class->get_properties = gjs_dbus_implementation_get_properties;
+    skeleton_class->flush = gjs_dbus_implementation_flush;
+
+    g_object_class_install_property(
+      gobject_class, PROP_G_INTERFACE_INFO,
+      g_param_spec_boxed("g-interface-info", "Interface Info",
+                         "A DBusInterfaceInfo representing the exported object",
+                         G_TYPE_DBUS_INTERFACE_INFO,
+                         (GParamFlags)(G_PARAM_STATIC_STRINGS | G_PARAM_WRITABLE
+                                       | G_PARAM_CONSTRUCT_ONLY)));
+
+    signals[SIGNAL_HANDLE_METHOD]
+      = g_signal_new("handle-method-call", G_TYPE_FROM_CLASS(klass),
+                     (GSignalFlags) 0,              /* flags */
+                     0,                             /* closure */
+                     NULL,                          /* accumulator */
+                     NULL,                          /* accumulator data */
+                     NULL,                          /* C marshal */
+                     G_TYPE_NONE, 3, G_TYPE_STRING, /* method name */
+                     G_TYPE_VARIANT,                /* parameters */
+                     G_TYPE_DBUS_METHOD_INVOCATION);
+
+    signals[SIGNAL_HANDLE_PROPERTY_GET]
+      = g_signal_new("handle-property-get", G_TYPE_FROM_CLASS(klass),
+                     (GSignalFlags) 0, /* flags */
+                     0,                /* closure */
+                     g_signal_accumulator_first_wins,
+                     NULL, /* accumulator data */
+                     NULL, /* C marshal */
+                     G_TYPE_VARIANT, 1, G_TYPE_STRING /* property name */);
+
+    signals[SIGNAL_HANDLE_PROPERTY_SET]
+      = g_signal_new("handle-property-set", G_TYPE_FROM_CLASS(klass),
+                     (GSignalFlags) 0,              /* flags */
+                     0,                             /* closure */
+                     NULL,                          /* accumulator */
+                     NULL,                          /* accumulator data */
+                     NULL,                          /* C marshal */
+                     G_TYPE_NONE, 2, G_TYPE_STRING, /* property name */
+                     G_TYPE_VARIANT /* parameters */);
+}
+
+static gboolean
+idle_cb(gpointer data)
+{
+    GDBusInterfaceSkeleton* skeleton = G_DBUS_INTERFACE_SKELETON(data);
+
+    g_dbus_interface_skeleton_flush(skeleton);
+    return FALSE;
+}
+
+/**
+ * gjs_dbus_implementation_emit_property_changed:
+ * @self: a #GjsDBusImplementation
+ * @property: the name of the property that changed
+ * @newvalue: (allow-none): the new value, or %NULL to just invalidate it
+ *
+ * Queue a PropertyChanged signal for emission, or update the one queued
+ * adding @property
+ */
+void
+gjs_dbus_implementation_emit_property_changed(GjsDBusImplementation* self,
+                                              gchar* property,
+                                              GVariant* newvalue)
+{
+    g_hash_table_replace(self->priv->outstanding_properties, g_strdup(property),
+                         g_variant_ref(newvalue));
+
+    if (!self->priv->idle_id)
+        self->priv->idle_id = g_idle_add(idle_cb, self);
+}
+
+/**
+ * gjs_dbus_implementation_emit_signal:
+ * @self: a #GjsDBusImplementation
+ * @signal_name: the name of the signal
+ * @parameters: (allow-none): signal parameters, or %NULL for none
+ *
+ * Emits a signal named @signal_name from the object and interface represented
+ * by @self. This signal has no destination.
+ */
+void
+gjs_dbus_implementation_emit_signal(GjsDBusImplementation* self,
+                                    gchar* signal_name,
+                                    GVariant* parameters)
+{
+    GDBusInterfaceSkeleton* skeleton = G_DBUS_INTERFACE_SKELETON(self);
+
+    g_dbus_connection_emit_signal(
+      g_dbus_interface_skeleton_get_connection(skeleton), NULL,
+      g_dbus_interface_skeleton_get_object_path(skeleton),
+      self->priv->ifaceinfo->name, signal_name, parameters, NULL);
+}
diff --git a/libgjs-private/gjs-gdbus-wrapper.h b/libgjs-private/gjs-gdbus-wrapper.h
new file mode 100644
index 0000000..3d55b09
--- /dev/null
+++ b/libgjs-private/gjs-gdbus-wrapper.h
@@ -0,0 +1,74 @@
+/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
+/* Copyright 2011 Giovanni Campagna
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef __GJS_UTIL_DBUS_H__
+#define __GJS_UTIL_DBUS_H__
+
+#include <glib.h>
+#include <glib-object.h>
+#include <gio/gio.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GjsDBusImplementation GjsDBusImplementation;
+typedef struct _GjsDBusImplementationClass GjsDBusImplementationClass;
+typedef struct _GjsDBusImplementationPrivate GjsDBusImplementationPrivate;
+
+#define GJS_TYPE_DBUS_IMPLEMENTATION (gjs_dbus_implementation_get_type())
+#define GJS_DBUS_IMPLEMENTATION(object)                                        \
+    (G_TYPE_CHECK_INSTANCE_CAST((object), GJS_TYPE_DBUS_IMPLEMENTATION,        \
+                                GjsDBusImplementation))
+#define GJS_DBUS_IMPLEMENTATION_CLASS(klass)                                   \
+    (G_TYPE_CHECK_CLASS_CAST((klass), GJS_TYPE_DBUS_IMPLEMENTATION,            \
+                             GjsDBusImplementationClass))
+#define GJS_IS_DBUS_IMPLEMENTATION(object)                                     \
+    (G_TYPE_CHECK_INSTANCE_TYPE((object), GJS_TYPE_DBUS_IMPLEMENTATION))
+#define GJS_IS_DBUS_IMPLEMENTATION_CLASS(klass)                                \
+    (G_TYPE_CHECK_CLASS_TYPE((klass), GJS_TYPE_DBUS_IMPLEMENTATION))
+#define GJS_DBUS_IMPLEMENTATION_GET_CLASS(obj)                                 \
+    (G_TYPE_INSTANCE_GET_CLASS((obj), GJS_TYPE_DBUS_IMPLEMENTATION,            \
+                               GjsDBusImplementationClass))
+
+struct _GjsDBusImplementation
+{
+    GDBusInterfaceSkeleton parent;
+
+    GjsDBusImplementationPrivate* priv;
+};
+
+struct _GjsDBusImplementationClass
+{
+    GDBusInterfaceSkeletonClass parent_class;
+};
+
+GType gjs_dbus_implementation_get_type(void);
+
+void gjs_dbus_implementation_emit_property_changed(GjsDBusImplementation* self,
+                                                   gchar* property,
+                                                   GVariant* newvalue);
+void gjs_dbus_implementation_emit_signal(GjsDBusImplementation* self,
+                                         gchar* signal_name,
+                                         GVariant* parameters);
+
+G_END_DECLS
+
+#endif /* __GJS_UTIL_DBUS_H__ */
diff --git a/libgjs-private/gjs-gtk-util.c b/libgjs-private/gjs-gtk-util.c
new file mode 100644
index 0000000..4a6cebf
--- /dev/null
+++ b/libgjs-private/gjs-gtk-util.c
@@ -0,0 +1,63 @@
+/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
+/* Copyright 2014 Endless Mobile, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <config.h>
+#include <gtk/gtk.h>
+
+#include "gjs-gtk-util.h"
+
+void
+gjs_gtk_container_child_set_property(GtkContainer* container,
+                                     GtkWidget* child,
+                                     const gchar* property,
+                                     const GValue* value)
+{
+    GParamSpec* pspec;
+
+    pspec
+      = gtk_container_class_find_child_property(G_OBJECT_GET_CLASS(container),
+                                                property);
+    if (pspec == NULL) {
+        g_warning("%s does not have a property called %s",
+                  g_type_name(G_OBJECT_TYPE(container)), property);
+        return;
+    }
+
+    if ((G_VALUE_TYPE(value) == G_TYPE_POINTER)
+        && (g_value_get_pointer(value) == NULL)
+        && !g_value_type_transformable(G_VALUE_TYPE(value),
+                                       pspec->value_type)) {
+        /* Set an empty value. This will happen when we set a NULL value from
+         * JS.
+         * Since GJS doesn't know the GParamSpec for this property, it
+         * will just put NULL into a G_TYPE_POINTER GValue, which will later
+         * fail when trying to transform it to the GParamSpec's GType.
+         */
+        GValue null_value = G_VALUE_INIT;
+        g_value_init(&null_value, pspec->value_type);
+        gtk_container_child_set_property(container, child, property,
+                                         &null_value);
+        g_value_unset(&null_value);
+    } else {
+        gtk_container_child_set_property(container, child, property, value);
+    }
+}
diff --git a/libgjs-private/gjs-gtk-util.h b/libgjs-private/gjs-gtk-util.h
new file mode 100644
index 0000000..0f048aa
--- /dev/null
+++ b/libgjs-private/gjs-gtk-util.h
@@ -0,0 +1,37 @@
+/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
+/* Copyright 2014 Endless Mobile, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef __GJS_PRIVATE_GTK_UTIL_H__
+#define __GJS_PRIVATE_GTK_UTIL_H__
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+void gjs_gtk_container_child_set_property(GtkContainer* container,
+                                          GtkWidget* child,
+                                          const gchar* property,
+                                          const GValue* value);
+
+G_END_DECLS
+
+#endif /* __GJS_PRIVATE_GTK_UTIL_H__ */
diff --git a/libgjs-private/gjs-util.c b/libgjs-private/gjs-util.c
new file mode 100644
index 0000000..9bda1c9
--- /dev/null
+++ b/libgjs-private/gjs-util.c
@@ -0,0 +1,110 @@
+/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
+/* Copyright 2012 Giovanni Campagna <scampa giovanni gmail com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <config.h>
+#include <string.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+
+#include "gjs-util.h"
+
+char*
+gjs_format_int_alternative_output(int n)
+{
+    return g_strdup_printf("%Id", n);
+}
+
+GType
+gjs_locale_category_get_type(void)
+{
+    static volatile size_t g_define_type_id__volatile = 0;
+    if (g_once_init_enter(&g_define_type_id__volatile)) {
+        static const GEnumValue v[]
+          = { { GJS_LOCALE_CATEGORY_ALL, "GJS_LOCALE_CATEGORY_ALL", "all" },
+              { GJS_LOCALE_CATEGORY_COLLATE, "GJS_LOCALE_CATEGORY_COLLATE",
+                "collate" },
+              { GJS_LOCALE_CATEGORY_CTYPE, "GJS_LOCALE_CATEGORY_CTYPE",
+                "ctype" },
+              { GJS_LOCALE_CATEGORY_MESSAGES, "GJS_LOCALE_CATEGORY_MESSAGES",
+                "messages" },
+              { GJS_LOCALE_CATEGORY_MONETARY, "GJS_LOCALE_CATEGORY_MONETARY",
+                "monetary" },
+              { GJS_LOCALE_CATEGORY_NUMERIC, "GJS_LOCALE_CATEGORY_NUMERIC",
+                "numeric" },
+              { GJS_LOCALE_CATEGORY_TIME, "GJS_LOCALE_CATEGORY_TIME", "time" },
+              { 0, NULL, NULL } };
+        GType g_define_type_id
+          = g_enum_register_static(g_intern_static_string("GjsLocaleCategory"),
+                                   v);
+
+        g_once_init_leave(&g_define_type_id__volatile, g_define_type_id);
+    }
+    return g_define_type_id__volatile;
+}
+
+/**
+ * gjs_setlocale:
+ * @category:
+ * @locale: (allow-none):
+ *
+ * Returns:
+ */
+const char*
+gjs_setlocale(GjsLocaleCategory category, const char* locale)
+{
+    /* According to man setlocale(3), the return value may be allocated in
+     * static storage. */
+    return (const char*) setlocale(category, locale);
+}
+
+void
+gjs_textdomain(const char* domain)
+{
+    textdomain(domain);
+}
+
+void
+gjs_bindtextdomain(const char* domain, const char* location)
+{
+    bindtextdomain(domain, location);
+    /* Always use UTF-8; we assume it internally here */
+    bind_textdomain_codeset(domain, "UTF-8");
+}
+
+GParamFlags
+gjs_param_spec_get_flags(GParamSpec* pspec)
+{
+    return pspec->flags;
+}
+
+GType
+gjs_param_spec_get_value_type(GParamSpec* pspec)
+{
+    return pspec->value_type;
+}
+
+GType
+gjs_param_spec_get_owner_type(GParamSpec* pspec)
+{
+    return pspec->owner_type;
+}
diff --git a/libgjs-private/gjs-util.h b/libgjs-private/gjs-util.h
new file mode 100644
index 0000000..ae09733
--- /dev/null
+++ b/libgjs-private/gjs-util.h
@@ -0,0 +1,58 @@
+/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
+/* Copyright 2012 Giovanni Campagna <scampa giovanni gmail com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef __GJS_PRIVATE_UTIL_H__
+#define __GJS_PRIVATE_UTIL_H__
+
+#include <locale.h>
+#include <glib.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+/* For imports.format */
+char* gjs_format_int_alternative_output(int n);
+
+/* For imports.gettext */
+typedef enum {
+    GJS_LOCALE_CATEGORY_ALL = LC_ALL,
+    GJS_LOCALE_CATEGORY_COLLATE = LC_COLLATE,
+    GJS_LOCALE_CATEGORY_CTYPE = LC_CTYPE,
+    GJS_LOCALE_CATEGORY_MESSAGES = LC_MESSAGES,
+    GJS_LOCALE_CATEGORY_MONETARY = LC_MONETARY,
+    GJS_LOCALE_CATEGORY_NUMERIC = LC_NUMERIC,
+    GJS_LOCALE_CATEGORY_TIME = LC_TIME
+} GjsLocaleCategory;
+
+const char* gjs_setlocale(GjsLocaleCategory category, const char* locale);
+void gjs_textdomain(const char* domain);
+void gjs_bindtextdomain(const char* domain, const char* location);
+GType gjs_locale_category_get_type(void) G_GNUC_CONST;
+
+/* For imports.overrides.GObject */
+GParamFlags gjs_param_spec_get_flags(GParamSpec* pspec);
+GType gjs_param_spec_get_value_type(GParamSpec* pspec);
+GType gjs_param_spec_get_owner_type(GParamSpec* pspec);
+
+G_END_DECLS
+
+#endif


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]