[gnome-sdk-images] Add gtk2 ibus module
- From: Alexander Larsson <alexl src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-sdk-images] Add gtk2 ibus module
- Date: Wed, 13 Sep 2017 19:13:27 +0000 (UTC)
commit 111a21afad69305dc8b10d181b73e862aef7281f
Author: Alexander Larsson <alexl redhat com>
Date: Wed Sep 13 20:35:24 2017 +0200
Add gtk2 ibus module
ibus-portal.patch | 1695 +++++++++++++++++++++++++++++++++++++++++++++++++
org.gnome.Sdk.json.in | 23 +
2 files changed, 1718 insertions(+), 0 deletions(-)
---
diff --git a/ibus-portal.patch b/ibus-portal.patch
new file mode 100644
index 0000000..0ed5b73
--- /dev/null
+++ b/ibus-portal.patch
@@ -0,0 +1,1695 @@
+From 203a3df5a239d644cf42b7bac03a268eb5babfc7 Mon Sep 17 00:00:00 2001
+From: Alexander Larsson <alexl redhat com>
+Date: Wed, 30 Aug 2017 11:38:09 +0900
+Subject: [PATCH 1/2] Initial version of ibus portal
+
+This adds a dbus service called org.freedesktop.portal.IBus on the
+session bus. It is a very limited service that only implements
+CreateInputContext and the InputContext interface (and Service.Destroy
+for lifetime access).
+
+It uses gdbus code generation for demarshalling the method calls which
+means it will verify that all arguments have the right type.
+
+Additionally all method calls to the input context object have to be
+from the client that created it, so each client is isolated.
+
+BUG=https://github.com/flatpak/flatpak/issues/675
+R=Shawn P Huang gmail com
+
+Review URL: https://codereview.appspot.com/326350043
+
+Patch from Alexander Larsson <alexl redhat com>.
+---
+ Makefile.am | 1 +
+ configure.ac | 5 +-
+ portal/Makefile.am | 95 ++++
+ portal/org.freedesktop.IBus.Portal.xml | 132 +++++
+ portal/org.freedesktop.portal.IBus.service.in | 3 +
+ portal/portal.c | 698 ++++++++++++++++++++++++++
+ src/ibusshare.h | 14 +
+ 7 files changed, 947 insertions(+), 1 deletion(-)
+ create mode 100644 portal/Makefile.am
+ create mode 100644 portal/org.freedesktop.IBus.Portal.xml
+ create mode 100644 portal/org.freedesktop.portal.IBus.service.in
+ create mode 100644 portal/portal.c
+
+diff --git a/Makefile.am b/Makefile.am
+index f703d4c6..c8e802da 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -51,6 +51,7 @@ SUBDIRS = \
+ util \
+ conf \
+ client \
++ portal \
+ data \
+ m4 \
+ po \
+diff --git a/configure.ac b/configure.ac
+index cb48ad4c..14556a3a 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -153,7 +153,7 @@ PKG_CHECK_MODULES(GOBJECT2, [
+ gobject-2.0 >= glib_required_version
+ ])
+ PKG_CHECK_MODULES(GIO2, [
+- gio-2.0 >= glib_required_version
++ gio-2.0 gio-unix-2.0 >= glib_required_version
+ ])
+ PKG_CHECK_MODULES(GTHREAD2, [
+ gthread-2.0 >= glib_required_version
+@@ -660,6 +660,8 @@ PKG_CHECK_MODULES(ISOCODES, [
+ ISOCODES_PREFIX=`$PKG_CONFIG iso-codes --variable=prefix`
+ AC_SUBST(ISOCODES_PREFIX)
+
++AC_SUBST([GDBUS_CODEGEN], [`$PKG_CONFIG --variable gdbus_codegen gio-2.0`])
++
+ # OUTPUT files
+ AC_CONFIG_FILES([ po/Makefile.in
+ Makefile
+@@ -674,6 +676,7 @@ src/Makefile
+ src/ibusversion.h
+ src/tests/Makefile
+ bus/Makefile
++portal/Makefile
+ engine/Makefile
+ util/Makefile
+ util/IMdkit/Makefile
+diff --git a/portal/Makefile.am b/portal/Makefile.am
+new file mode 100644
+index 00000000..954fc591
+--- /dev/null
++++ b/portal/Makefile.am
+@@ -0,0 +1,95 @@
++# vim:set noet ts=4:
++#
++# ibus - The Input Bus
++#
++# Copyright (c) 2007-2013 Peng Huang <shawn p huang gmail com>
++# Copyright (c) 2007-2013 Red Hat, Inc.
++#
++# This library is free software; you can redistribute it and/or
++# modify it under the terms of the GNU Lesser General Public
++# License as published by the Free Software Foundation; either
++# version 2.1 of the License, or (at your option) any later version.
++#
++# This library is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++# Lesser General Public License for more details.
++#
++# You should have received a copy of the GNU Lesser General Public
++# License along with this library; if not, write to the Free Software
++# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
++# USA
++
++NULL =
++
++libibus = $(top_builddir)/src/libibus-@IBUS_API_VERSION@.la
++
++AM_CPPFLAGS = \
++ -I$(top_srcdir)/src \
++ -I$(top_builddir)/src \
++ $(NULL)
++
++AM_CFLAGS = \
++ @GLIB2_CFLAGS@ \
++ @GIO2_CFLAGS@ \
++ @GTHREAD2_CFLAGS@ \
++ -DG_LOG_DOMAIN=\"IBUS\" \
++ -DPKGDATADIR=\"$(pkgdatadir)\" \
++ -DLIBEXECDIR=\"$(libexecdir)\" \
++ -DBINDIR=\"@bindir@\" \
++ -DIBUS_DISABLE_DEPRECATED \
++ $(NULL)
++AM_LDADD = \
++ @GOBJECT2_LIBS@ \
++ @GLIB2_LIBS@ \
++ @GIO2_LIBS@ \
++ @GTHREAD2_LIBS@ \
++ $(libibus) \
++ $(NULL)
++
++ibus_dbus_built_sources = ibus-portal-dbus.c ibus-portal-dbus.h
++BUILT_SOURCES = $(ibus_dbus_built_sources)
++
++libexec_PROGRAMS = ibus-portal
++ibus_portal_DEPENDENCIES = \
++ $(libibus) \
++ $(NULL)
++ibus_portal_SOURCES = \
++ portal.c \
++ $(ibus_dbus_built_sources) \
++ $(NULL)
++ibus_portal_CFLAGS = \
++ $(AM_CFLAGS) \
++ $(NULL)
++ibus_portal_LDADD = \
++ $(AM_LDADD) \
++ $(NULL)
++
++EXTRA_DIST = \
++ $(NULL)
++
++CLEANFILES = \
++ $(NULL)
++
++$(libibus):
++ $(MAKE) -C $(top_builddir)/src
++
++dbusservice_in_files = org.freedesktop.portal.IBus.service.in
++dbusservice_DATA = $(dbusservice_in_files:.service.in=.service)
++dbusservicedir=${datadir}/dbus-1/services
++
++org.freedesktop.portal.IBus.service: org.freedesktop.portal.IBus.service.in
++ $(AM_V_GEN) sed -e "s|\@libexecdir\@|$(libexecdir)|" $< > $@.tmp && mv $@.tmp $@
++
++$(ibus_dbus_built_sources) : org.freedesktop.IBus.Portal.xml
++ $(AM_V_GEN) $(GDBUS_CODEGEN) \
++ --interface-prefix org.freedesktop.IBus. \
++ --c-namespace IBusDbus \
++ --generate-c-code $(builddir)/ibus-portal-dbus \
++ $^ \
++ $(NULL)
++
++EXTRA_DIST += $(dbusservice_in_files)
++CLEANFILES += $(dbusservice_DATA)
++
++-include $(top_srcdir)/git.mk
+diff --git a/portal/org.freedesktop.IBus.Portal.xml b/portal/org.freedesktop.IBus.Portal.xml
+new file mode 100644
+index 00000000..afce4daa
+--- /dev/null
++++ b/portal/org.freedesktop.IBus.Portal.xml
+@@ -0,0 +1,132 @@
++<?xml version="1.0"?>
++<!--
++ Copyright (C) 2017 Red Hat, Inc.
++
++ 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 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/>.
++
++ Author: Alexander Larsson <alexl redhat com>
++-->
++
++<node name="/" xmlns:doc="http://www.freedesktop.org/dbus/1.0/doc.dtd">
++ <!--
++ org.freedesktop.IBus.Portal:
++ @short_description: Portal for ibus client access
++
++ This interface is a minimal interface to IBus that is safe to expose to
++ clients.
++ -->
++ <interface name="org.freedesktop.IBus.Portal">
++ <method name='CreateInputContext'>
++ <arg direction='in' type='s' name='client_name' />
++ <arg direction='out' type='o' name='object_path' />
++ </method>
++ </interface>
++
++ <!-- This is a copy of the interface in inputcontext.c, they should be shared.
++ We want this for the code generator so that we can be sure we verify all
++ caller types, etc.
++ -->
++ <interface name='org.freedesktop.IBus.InputContext'>
++ <method name='ProcessKeyEvent'>
++ <arg direction='in' type='u' name='keyval' />
++ <arg direction='in' type='u' name='keycode' />
++ <arg direction='in' type='u' name='state' />
++ <arg direction='out' type='b' name='handled' />
++ </method>
++ <method name='SetCursorLocation'>
++ <arg direction='in' type='i' name='x' />
++ <arg direction='in' type='i' name='y' />
++ <arg direction='in' type='i' name='w' />
++ <arg direction='in' type='i' name='h' />
++ </method>
++ <method name='SetCursorLocationRelative'>
++ <arg direction='in' type='i' name='x' />
++ <arg direction='in' type='i' name='y' />
++ <arg direction='in' type='i' name='w' />
++ <arg direction='in' type='i' name='h' />
++ </method>
++ <method name='ProcessHandWritingEvent'>
++ <arg direction='in' type='ad' name='coordinates' />
++ </method>
++ <method name='CancelHandWriting'>
++ <arg direction='in' type='u' name='n_strokes' />
++ </method>
++ <method name='FocusIn' />
++ <method name='FocusOut' />
++ <method name='Reset' />
++ <method name='SetCapabilities'>
++ <arg direction='in' type='u' name='caps' />
++ </method>
++ <method name='PropertyActivate'>
++ <arg direction='in' type='s' name='name' />
++ <arg direction='in' type='u' name='state' />
++ </method>
++ <method name='SetEngine'>
++ <arg direction='in' type='s' name='name' />
++ </method>
++ <method name='GetEngine'>
++ <arg direction='out' type='v' name='desc' />
++ </method>
++ <method name='SetSurroundingText'>
++ <arg direction='in' type='v' name='text' />
++ <arg direction='in' type='u' name='cursor_pos' />
++ <arg direction='in' type='u' name='anchor_pos' />
++ </method>
++
++ <signal name='CommitText'>
++ <arg type='v' name='text' />
++ </signal>
++ <signal name='ForwardKeyEvent'>
++ <arg type='u' name='keyval' />
++ <arg type='u' name='keycode' />
++ <arg type='u' name='state' />
++ </signal>
++ <signal name='UpdatePreeditText'>
++ <arg type='v' name='text' />
++ <arg type='u' name='cursor_pos' />
++ <arg type='b' name='visible' />
++ </signal>
++ <signal name='ShowPreeditText'/>
++ <signal name='HidePreeditText'/>
++ <signal name='UpdateAuxiliaryText'>
++ <arg type='v' name='text' />
++ <arg type='b' name='visible' />
++ </signal>
++ <signal name='ShowAuxiliaryText'/>
++ <signal name='HideAuxiliaryText'/>
++ <signal name='UpdateLookupTable'>
++ <arg type='v' name='table' />
++ <arg type='b' name='visible' />
++ </signal>
++ <signal name='ShowLookupTable'/>
++ <signal name='HideLookupTable'/>
++ <signal name='PageUpLookupTable'/>
++ <signal name='PageDownLookupTable'/>
++ <signal name='CursorUpLookupTable'/>
++ <signal name='CursorDownLookupTable'/>
++ <signal name='RegisterProperties'>
++ <arg type='v' name='props' />
++ </signal>
++ <signal name='UpdateProperty'>
++ <arg type='v' name='prop' />
++ </signal>
++
++ <property name='ContentType' type='(uu)' access='write' />
++ </interface>
++
++ <interface name='org.freedesktop.IBus.Service'>
++ <method name='Destroy' />
++ </interface>
++
++</node>
+diff --git a/portal/org.freedesktop.portal.IBus.service.in b/portal/org.freedesktop.portal.IBus.service.in
+new file mode 100644
+index 00000000..47ae9ffc
+--- /dev/null
++++ b/portal/org.freedesktop.portal.IBus.service.in
+@@ -0,0 +1,3 @@
++[D-BUS Service]
++Name=org.freedesktop.portal.IBus
++Exec=@libexecdir@/ibus-portal
+diff --git a/portal/portal.c b/portal/portal.c
+new file mode 100644
+index 00000000..0415f996
+--- /dev/null
++++ b/portal/portal.c
+@@ -0,0 +1,698 @@
++/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
++/* vim:set et sts=4: */
++/* ibus - The Input Bus
++ * Copyright (C) 2017 Red Hat, Inc.
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.1 of the License, or (at your option) any later version.
++ *
++ * This library is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
++ * USA
++ */
++#include <config.h>
++#include <fcntl.h>
++#include <glib.h>
++#include <gio/gio.h>
++#include <ibus.h>
++#include <locale.h>
++#include <pwd.h>
++#include <signal.h>
++#include <stdlib.h>
++#include <sys/types.h>
++#include <sys/stat.h>
++#include <unistd.h>
++
++#include "ibus-portal-dbus.h"
++
++typedef struct _IBusPortal IBusPortal;
++typedef struct _IBusPortalClass IBusPortalClass;
++typedef struct _IBusPortalContext IBusPortalContext;
++typedef struct _IBusPortalContextClass IBusPortalContextClass;
++
++struct _IBusPortalContext
++{
++ IBusDbusInputContextSkeleton parent_instance;
++ IBusInputContext *context;
++ guint id;
++ char *owner;
++ char *object_path;
++ IBusDbusService *service;
++};
++
++struct _IBusPortalContextClass
++{
++ IBusDbusInputContextSkeletonClass parent_class;
++};
++
++struct _IBusPortal
++{
++ IBusDbusPortalSkeleton parent_instance;
++
++};
++
++struct _IBusPortalClass
++{
++ IBusDbusPortalSkeletonClass parent_class;
++};
++
++enum
++{
++ PROP_CONTENT_TYPE = 1,
++ N_PROPERTIES
++};
++
++static GMainLoop *loop = NULL;
++static IBusBus *ibus_bus;
++static IBusPortal *ibus_portal = NULL;
++static gboolean opt_verbose;
++static gboolean opt_replace;
++
++static GList *all_contexts = NULL;
++
++static guint next_context_id;
++
++GType ibus_portal_context_get_type (void) G_GNUC_CONST;
++static void ibus_portal_context_iface_init (IBusDbusInputContextIface *iface);
++
++static void portal_context_g_signal (GDBusProxy *proxy,
++ const gchar *sender_name,
++ const gchar *signal_name,
++ GVariant *parameters,
++ IBusPortalContext *portal_context);
++
++G_DEFINE_TYPE_WITH_CODE (IBusPortalContext,
++ ibus_portal_context,
++ IBUS_DBUS_TYPE_INPUT_CONTEXT_SKELETON,
++ G_IMPLEMENT_INTERFACE (IBUS_DBUS_TYPE_INPUT_CONTEXT,
++ ibus_portal_context_iface_init));
++
++static void
++_forward_method_cb (GObject *source_object,
++ GAsyncResult *res,
++ gpointer user_data)
++{
++ GDBusMethodInvocation *invocation = user_data;
++ IBusPortalContext *portal_context =
++ (IBusPortalContext *) g_dbus_method_invocation_get_user_data (
++ invocation);
++ IBusEngineDesc *desc;
++ GError *error = NULL;
++
++ GVariant *variant = g_dbus_proxy_call_finish ((GDBusProxy *) source_object,
++ res, &error);
++ if (variant == NULL) {
++ g_dbus_method_invocation_return_gerror (invocation, error);
++ g_error_free (error);
++ return;
++ }
++
++ g_dbus_method_invocation_return_value (invocation, variant);
++}
++
++static gboolean
++_forward_method (IBusDbusInputContext *object,
++ GDBusMethodInvocation *invocation)
++{
++ IBusPortalContext *portal_context = (IBusPortalContext *)object;
++ GDBusMessage *message = g_dbus_method_invocation_get_message (invocation);
++
++ g_dbus_proxy_call (G_DBUS_PROXY (portal_context->context),
++ g_dbus_method_invocation_get_method_name (invocation),
++ g_dbus_message_get_body (message),
++ G_DBUS_CALL_FLAGS_NONE,
++ -1,
++ NULL, /* cancellable */
++ _forward_method_cb, invocation);
++ return TRUE;
++}
++
++static gboolean
++ibus_dbus_context_cancel_hand_writing (IBusDbusInputContext *object,
++ GDBusMethodInvocation *invocation,
++ guint arg_n_strokes)
++{
++ return _forward_method (object, invocation);
++}
++
++static gboolean
++ibus_dbus_context_focus_in (IBusDbusInputContext *object,
++ GDBusMethodInvocation *invocation)
++{
++ return _forward_method (object, invocation);
++}
++
++static gboolean
++ibus_dbus_context_focus_out (IBusDbusInputContext *object,
++ GDBusMethodInvocation *invocation)
++{
++ return _forward_method (object, invocation);
++}
++
++static gboolean
++ibus_dbus_context_get_engine (IBusDbusInputContext *object,
++ GDBusMethodInvocation *invocation)
++{
++ return _forward_method (object, invocation);
++}
++
++static gboolean
++ibus_dbus_context_process_hand_writing_event (IBusDbusInputContext *object,
++ GDBusMethodInvocation *invocation,
++ GVariant
++ *arg_coordinates)
++{
++ return _forward_method (object, invocation);
++}
++
++static gboolean
++ibus_dbus_context_process_key_event (IBusDbusInputContext *object,
++ GDBusMethodInvocation *invocation,
++ guint arg_keyval,
++ guint arg_keycode,
++ guint arg_state)
++{
++ return _forward_method (object, invocation);
++}
++
++static gboolean
++ibus_dbus_context_property_activate (IBusDbusInputContext *object,
++ GDBusMethodInvocation *invocation,
++ const gchar *arg_name,
++ guint arg_state)
++{
++ return _forward_method (object, invocation);
++}
++
++static gboolean
++ibus_dbus_context_reset (IBusDbusInputContext *object,
++ GDBusMethodInvocation *invocation)
++{
++ return _forward_method (object, invocation);
++}
++
++static gboolean
++ibus_dbus_context_set_capabilities (IBusDbusInputContext *object,
++ GDBusMethodInvocation *invocation,
++ guint arg_caps)
++{
++ return _forward_method (object, invocation);
++}
++
++static gboolean
++ibus_dbus_context_set_cursor_location (IBusDbusInputContext *object,
++ GDBusMethodInvocation *invocation,
++ gint arg_x,
++ gint arg_y,
++ gint arg_w,
++ gint arg_h)
++{
++ return _forward_method (object, invocation);
++}
++
++static gboolean
++ibus_dbus_context_set_cursor_location_relative (IBusDbusInputContext *object,
++ GDBusMethodInvocation
++ *invocation,
++ gint arg_x,
++ gint arg_y,
++ gint arg_w,
++ gint arg_h)
++{
++ return _forward_method (object, invocation);
++}
++
++static gboolean
++ibus_dbus_context_set_engine (IBusDbusInputContext *object,
++ GDBusMethodInvocation *invocation,
++ const gchar *arg_name)
++{
++ return _forward_method (object, invocation);
++}
++
++static gboolean
++ibus_dbus_context_set_surrounding_text (IBusDbusInputContext *object,
++ GDBusMethodInvocation *invocation,
++ GVariant *arg_text,
++ guint arg_cursor_pos,
++ guint arg_anchor_pos)
++{
++ return _forward_method (object, invocation);
++}
++
++static void
++ibus_portal_context_iface_init (IBusDbusInputContextIface *iface)
++{
++ iface->handle_cancel_hand_writing = ibus_dbus_context_cancel_hand_writing;
++ iface->handle_focus_in = ibus_dbus_context_focus_in;
++ iface->handle_focus_out = ibus_dbus_context_focus_out;
++ iface->handle_get_engine = ibus_dbus_context_get_engine;
++ iface->handle_process_hand_writing_event =
++ ibus_dbus_context_process_hand_writing_event;
++ iface->handle_process_key_event = ibus_dbus_context_process_key_event;
++ iface->handle_property_activate = ibus_dbus_context_property_activate;
++ iface->handle_reset = ibus_dbus_context_reset;
++ iface->handle_set_capabilities = ibus_dbus_context_set_capabilities;
++ iface->handle_set_cursor_location = ibus_dbus_context_set_cursor_location;
++ iface->handle_set_cursor_location_relative =
++ ibus_dbus_context_set_cursor_location_relative;
++ iface->handle_set_engine = ibus_dbus_context_set_engine;
++ iface->handle_set_surrounding_text = ibus_dbus_context_set_surrounding_text;
++}
++
++static void
++ibus_portal_context_init (IBusPortalContext *portal_context)
++{
++}
++
++static void
++ibus_portal_context_finalize (GObject *object)
++{
++ IBusPortalContext *portal_context = (IBusPortalContext *)object;
++
++ all_contexts = g_list_remove (all_contexts, portal_context);
++
++ g_dbus_interface_skeleton_unexport (
++ G_DBUS_INTERFACE_SKELETON (portal_context->service));
++ g_dbus_interface_skeleton_unexport (
++ G_DBUS_INTERFACE_SKELETON (portal_context));
++
++ g_free (portal_context->owner);
++ g_free (portal_context->object_path);
++ g_object_unref (portal_context->service);
++
++ g_signal_handlers_disconnect_by_func (
++ portal_context->context,
++ G_CALLBACK(portal_context_g_signal),
++ portal_context);
++ g_object_unref (portal_context->context);
++
++ G_OBJECT_CLASS (ibus_portal_context_parent_class)->finalize (object);
++}
++
++static void
++ibus_portal_context_set_property (IBusPortalContext *portal_context,
++ guint prop_id,
++ const GValue *value,
++ GParamSpec *pspec)
++{
++ switch (prop_id) {
++ case PROP_CONTENT_TYPE:
++ g_dbus_proxy_call (G_DBUS_PROXY (portal_context->context),
++ "org.freedesktop.DBus.Properties.Set",
++ g_variant_new ("(ssv)",
++ IBUS_INTERFACE_INPUT_CONTEXT,
++ "ContentType",
++ g_value_get_variant (value)),
++ G_DBUS_CALL_FLAGS_NONE,
++ -1,
++ NULL, /* cancellable */
++ NULL, /* callback */
++ NULL /* user_data */
++ );
++ break;
++ default:
++ G_OBJECT_WARN_INVALID_PROPERTY_ID (portal_context, prop_id, pspec);
++ }
++}
++
++static void
++ibus_portal_context_get_property (IBusPortalContext *portal_context,
++ guint prop_id,
++ GValue *value,
++ GParamSpec *pspec)
++{
++ switch (prop_id) {
++ case PROP_CONTENT_TYPE:
++ g_warning ("No support for setting content type");
++ break;
++ default:
++ G_OBJECT_WARN_INVALID_PROPERTY_ID (portal_context, prop_id, pspec);
++ }
++}
++
++static gboolean
++ibus_portal_context_g_authorize_method (GDBusInterfaceSkeleton *interface,
++ GDBusMethodInvocation *invocation)
++{
++ IBusPortalContext *portal_context = (IBusPortalContext *)interface;
++
++ if (g_strcmp0 (g_dbus_method_invocation_get_sender (invocation),
++ portal_context->owner) == 0) {
++ return TRUE;
++ }
++
++ g_dbus_method_invocation_return_error (invocation,
++ G_DBUS_ERROR,
++ G_DBUS_ERROR_FAILED,
++ "Access denied");
++ return FALSE;
++}
++
++
++static void
++ibus_portal_context_class_init (IBusPortalContextClass *klass)
++{
++ GObjectClass *gobject_class;
++ GDBusInterfaceSkeletonClass *skeleton_class;
++
++ gobject_class = G_OBJECT_CLASS (klass);
++ gobject_class->finalize = ibus_portal_context_finalize;
++ gobject_class->set_property =
++ (GObjectSetPropertyFunc) ibus_portal_context_set_property;
++ gobject_class->get_property =
++ (GObjectGetPropertyFunc) ibus_portal_context_get_property;
++
++ skeleton_class = G_DBUS_INTERFACE_SKELETON_CLASS(klass);
++ skeleton_class->g_authorize_method = ibus_portal_context_g_authorize_method;
++
++ ibus_dbus_input_context_override_properties (gobject_class,
++ PROP_CONTENT_TYPE);
++}
++
++static void
++portal_context_g_signal (GDBusProxy *proxy,
++ const gchar *sender_name,
++ const gchar *signal_name,
++ GVariant *parameters,
++ IBusPortalContext *portal_context)
++{
++ GError *error = NULL;
++ GDBusConnection *connection;
++
++ if (g_strcmp0 (sender_name, IBUS_SERVICE_IBUS) != 0)
++ return;
++
++ connection = g_dbus_interface_skeleton_get_connection (
++ G_DBUS_INTERFACE_SKELETON (portal_context));
++ if (!g_dbus_connection_emit_signal (connection,
++ portal_context->owner,
++ portal_context->object_path,
++ IBUS_INTERFACE_INPUT_CONTEXT,
++ signal_name,
++ parameters,
++ &error)) {
++ g_warning ("Unable to emit signal %s: %s", signal_name, error->message);
++ g_error_free (error);
++ }
++
++ g_signal_stop_emission_by_name (proxy, "g-signal");
++}
++
++static gboolean
++ibus_portal_context_handle_destroy (IBusDbusService *object,
++ GDBusMethodInvocation *invocation,
++ IBusPortalContext *portal_context)
++{
++ g_object_unref (portal_context);
++}
++
++static IBusPortalContext *
++ibus_portal_context_new (IBusInputContext *context,
++ GDBusConnection *connection,
++ const char *owner,
++ GError **error)
++{
++ IBusPortalContext *portal_context =
++ g_object_new (ibus_portal_context_get_type (), NULL);
++
++ g_signal_connect (context,
++ "g-signal",
++ G_CALLBACK(portal_context_g_signal),
++ portal_context);
++
++ portal_context->id = ++next_context_id;
++ portal_context->context = g_object_ref (context);
++ portal_context->owner = g_strdup (owner);
++ portal_context->object_path =
++ g_strdup_printf (IBUS_PATH_INPUT_CONTEXT, portal_context->id);
++ portal_context->service = ibus_dbus_service_skeleton_new ();
++
++ g_signal_connect (portal_context->service,
++ "handle-destroy",
++ G_CALLBACK (ibus_portal_context_handle_destroy),
++ portal_context);
++
++ if (!g_dbus_interface_skeleton_export (
++ G_DBUS_INTERFACE_SKELETON (portal_context->service),
++ connection, portal_context->object_path,
++ error) ||
++ !g_dbus_interface_skeleton_export (
++ G_DBUS_INTERFACE_SKELETON (portal_context),
++ connection, portal_context->object_path,
++ error)) {
++ g_object_unref (portal_context);
++ return NULL;
++ }
++
++ all_contexts = g_list_prepend (all_contexts, portal_context);
++
++ return portal_context;
++}
++
++GType ibus_portal_get_type (void) G_GNUC_CONST;
++static void ibus_portal_iface_init (IBusDbusPortalIface *iface);
++
++G_DEFINE_TYPE_WITH_CODE (IBusPortal, ibus_portal,
++ IBUS_DBUS_TYPE_PORTAL_SKELETON,
++ G_IMPLEMENT_INTERFACE (IBUS_DBUS_TYPE_PORTAL,
++ ibus_portal_iface_init));
++
++
++static void
++create_input_context_done (IBusBus *bus,
++ GAsyncResult *res,
++ GDBusMethodInvocation *invocation)
++{
++ GError *error = NULL;
++ IBusInputContext *context;
++ IBusPortalContext *portal_context;
++ char *object_path;
++
++ context = ibus_bus_create_input_context_async_finish (ibus_bus,
++ res,
++ &error);
++ if (context == NULL) {
++ g_dbus_method_invocation_return_gerror (invocation, error);
++ g_error_free (error);
++ return;
++ }
++
++ portal_context = ibus_portal_context_new (
++ context,
++ g_dbus_method_invocation_get_connection (invocation),
++ g_dbus_method_invocation_get_sender (invocation),
++ &error);
++ g_object_unref (context);
++
++ if (portal_context == NULL) {
++ g_dbus_method_invocation_return_gerror (invocation, error);
++ g_error_free (error);
++ g_object_unref (portal_context);
++ return;
++ }
++
++ ibus_dbus_portal_complete_create_input_context (
++ IBUS_DBUS_PORTAL(ibus_portal),
++ invocation, portal_context->object_path);
++}
++
++static gboolean
++ibus_portal_handle_create_input_context (IBusDbusPortal *object,
++ GDBusMethodInvocation *invocation,
++ const gchar *arg_client_name)
++{
++ ibus_bus_create_input_context_async (
++ ibus_bus,
++ arg_client_name, -1,
++ NULL,
++ (GAsyncReadyCallback)create_input_context_done,
++ invocation);
++ return TRUE;
++}
++
++static void
++ibus_portal_iface_init (IBusDbusPortalIface *iface)
++{
++ iface->handle_create_input_context =
++ ibus_portal_handle_create_input_context;
++}
++
++static void
++ibus_portal_init (IBusPortal *portal)
++{
++}
++
++static void
++ibus_portal_class_init (IBusPortalClass *klass)
++{
++}
++
++
++static void
++show_version_and_quit (void)
++{
++ g_print ("%s - Version %s\n", g_get_application_name (), VERSION);
++ exit (EXIT_SUCCESS);
++}
++
++static const GOptionEntry entries[] =
++{
++ { "version", 'V', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK,
++ show_version_and_quit, "Show the application's version.", NULL },
++ { "verbose", 'v', 0, G_OPTION_ARG_NONE,
++ &opt_verbose, "verbose.", NULL },
++ { "replace", 'r', 0, G_OPTION_ARG_NONE,
++ &opt_replace, "Replace.", NULL },
++ { NULL },
++};
++
++static void
++on_bus_acquired (GDBusConnection *connection,
++ const gchar *name,
++ gpointer user_data)
++{
++ GError *error = NULL;
++
++ ibus_portal = g_object_new (ibus_portal_get_type (), NULL);
++
++ if (!g_dbus_interface_skeleton_export (
++ G_DBUS_INTERFACE_SKELETON (ibus_portal),
++ connection,
++ IBUS_PATH_IBUS,
++ &error)) {
++ g_warning ("Error exporting portal: %s", error->message);
++ g_error_free (error);
++ return;
++ }
++}
++
++static void
++on_name_acquired (GDBusConnection *connection,
++ const gchar *name,
++ gpointer user_data)
++{
++}
++
++static void
++on_name_lost (GDBusConnection *connection,
++ const gchar *name,
++ gpointer user_data)
++{
++ g_main_loop_quit (loop);
++}
++
++static void
++name_owner_changed (GDBusConnection *connection,
++ const gchar *sender_name,
++ const gchar *object_path,
++ const gchar *interface_name,
++ const gchar *signal_name,
++ GVariant *parameters,
++ gpointer user_data)
++{
++ const char *name, *from, *to;
++
++ g_variant_get (parameters, "(sss)", &name, &from, &to);
++
++ if (name[0] == ':' &&
++ g_strcmp0 (name, from) == 0 &&
++ g_strcmp0 (to, "") == 0)
++ {
++ GList *l, *next;
++ /* Client disconnected, free any input contexts it may have */
++ for (l = all_contexts; l != NULL; l = next) {
++ IBusPortalContext *portal_context = l->data;
++ next = l->next;
++
++ if (g_strcmp0 (portal_context->owner, name) == 0) {
++ g_object_unref (portal_context);
++ }
++ }
++ }
++}
++
++static void
++_bus_disconnected_cb (IBusBus *ibusbus)
++{
++ g_main_loop_quit (loop);
++}
++
++gint
++main (gint argc, gchar **argv)
++{
++ GDBusConnection *session_bus = NULL;
++ guint owner_id;
++
++ setlocale (LC_ALL, "");
++
++ GOptionContext *context = g_option_context_new ("- ibus daemon");
++ g_option_context_add_main_entries (context, entries, "ibus-daemon");
++
++ GError *error = NULL;
++ if (!g_option_context_parse (context, &argc, &argv, &error)) {
++ g_printerr ("Option parsing failed: %s\n", error->message);
++ g_error_free (error);
++ exit (-1);
++ }
++
++ /* Avoid even loading gvfs to avoid accidental confusion */
++ g_setenv ("GIO_USE_VFS", "local", TRUE);
++
++ ibus_init ();
++
++ ibus_set_log_handler (opt_verbose);
++
++ ibus_bus = ibus_bus_new ();
++ if (!ibus_bus_is_connected (ibus_bus)) {
++ g_printerr ("Not connected to the ibus bus\n");
++ exit (1);
++ }
++
++ g_signal_connect (ibus_bus, "disconnected",
++ G_CALLBACK (_bus_disconnected_cb), NULL);
++
++ loop = g_main_loop_new (NULL, FALSE);
++
++ session_bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
++ if (session_bus == NULL) {
++ g_printerr ("No session bus: %s", error->message);
++ exit (-1);
++ }
++
++ g_dbus_connection_signal_subscribe (session_bus,
++ "org.freedesktop.DBus",
++ "org.freedesktop.DBus",
++ "NameOwnerChanged",
++ "/org/freedesktop/DBus",
++ NULL,
++ G_DBUS_SIGNAL_FLAGS_NONE,
++ name_owner_changed,
++ NULL, NULL);
++
++ owner_id = g_bus_own_name (G_BUS_TYPE_SESSION,
++ IBUS_SERVICE_PORTAL,
++ G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT |
++ (opt_replace ? G_BUS_NAME_OWNER_FLAGS_REPLACE
++ : 0),
++ on_bus_acquired,
++ on_name_acquired,
++ on_name_lost,
++ NULL,
++ NULL);
++
++ g_main_loop_run (loop);
++
++ g_bus_unown_name (owner_id);
++ g_main_loop_unref (loop);
++
++ return 0;
++}
+diff --git a/src/ibusshare.h b/src/ibusshare.h
+index bca477c0..f3e2011e 100644
+--- a/src/ibusshare.h
++++ b/src/ibusshare.h
+@@ -52,6 +52,13 @@
+ #define IBUS_SERVICE_IBUS "org.freedesktop.IBus"
+
+ /**
++ * IBUS_SERVICE_PORTAL:
++ *
++ * Address of IBus portalservice.
++ */
++#define IBUS_SERVICE_PORTAL "org.freedesktop.portal.IBus"
++
++/**
+ * IBUS_SERVICE_PANEL:
+ *
+ * Address of IBus panel service.
+@@ -122,6 +129,13 @@
+ #define IBUS_INTERFACE_IBUS "org.freedesktop.IBus"
+
+ /**
++ * IBUS_INTERFACE_PORTAL:
++ *
++ * D-Bus interface for IBus portal.
++ */
++#define IBUS_INTERFACE_PORTAL "org.freedesktop.IBus.Portal"
++
++/**
+ * IBUS_INTERFACE_INPUT_CONTEXT:
+ *
+ * D-Bus interface for IBus input context.
+--
+2.13.5
+
+From 35ce62474fa97a5460d72c360943700a413a07ae Mon Sep 17 00:00:00 2001
+From: Alexander Larsson <alexl redhat com>
+Date: Thu, 31 Aug 2017 12:03:37 +0900
+Subject: [PATCH 2/2] Support the portal in the gtk im modules
+
+This adds a new way to create an IbusBus, ibus_bus_new_async_client().
+This returns an object that is not guarantee to handle any calls
+that are not needed by a client, meaning CreateInputContext and
+handling the input context.
+
+If you are running in a flatpak, or if IBUS_USE_PORTAL is set, then
+instead of talking to the regular ibus bus we connect to
+org.freedesktop.portal.IBus on the session bus and use the
+limited org.freedesktop.IBus.Portal interface instead of the
+org.freedesktop.IBus interface.
+
+This allows flatpaks (or other sandbox systems) to safely use
+dbus clients (apps).
+
+BUG=https://github.com/flatpak/flatpak/issues/675
+
+Review URL: https://codereview.appspot.com/328410043
+
+Patch from Alexander Larsson <alexl redhat com>.
+---
+ client/gtk2/ibusimcontext.c | 4 +-
+ src/ibusbus.c | 248 +++++++++++++++++++++++++++++++++++++++-----
+ src/ibusbus.h | 23 ++++
+ src/ibusinputcontext.c | 12 ++-
+ 4 files changed, 256 insertions(+), 31 deletions(-)
+
+diff --git a/client/gtk2/ibusimcontext.c b/client/gtk2/ibusimcontext.c
+index 41c7a3af..b4ca8828 100644
+--- a/client/gtk2/ibusimcontext.c
++++ b/client/gtk2/ibusimcontext.c
+@@ -583,7 +583,7 @@ ibus_im_context_class_init (IBusIMContextClass *class)
+
+ /* init bus object */
+ if (_bus == NULL) {
+- _bus = ibus_bus_new_async ();
++ _bus = ibus_bus_new_async_client ();
+
+ /* init the global fake context */
+ if (ibus_bus_is_connected (_bus)) {
+@@ -603,7 +603,7 @@ ibus_im_context_class_init (IBusIMContextClass *class)
+ }
+
+ _daemon_name_watch_id = g_bus_watch_name (G_BUS_TYPE_SESSION,
+- IBUS_SERVICE_IBUS,
++ ibus_bus_get_service_name (_bus),
+ G_BUS_NAME_WATCHER_FLAGS_NONE,
+ daemon_name_appeared,
+ daemon_name_vanished,
+diff --git a/client/gtk2/ibusimcontext.c b/client/gtk2/ibusimcontext.c
+index 41c7a3af..b4ca8828 100644
+--- a/client/gtk3/ibusimcontext.c
++++ b/client/gtk3/ibusimcontext.c
+@@ -583,7 +583,7 @@ ibus_im_context_class_init (IBusIMContextClass *class)
+
+ /* init bus object */
+ if (_bus == NULL) {
+- _bus = ibus_bus_new_async ();
++ _bus = ibus_bus_new_async_client ();
+
+ /* init the global fake context */
+ if (ibus_bus_is_connected (_bus)) {
+@@ -603,7 +603,7 @@ ibus_im_context_class_init (IBusIMContextClass *class)
+ }
+
+ _daemon_name_watch_id = g_bus_watch_name (G_BUS_TYPE_SESSION,
+- IBUS_SERVICE_IBUS,
++ ibus_bus_get_service_name (_bus),
+ G_BUS_NAME_WATCHER_FLAGS_NONE,
+ daemon_name_appeared,
+ daemon_name_vanished,
+diff --git a/src/ibusbus.c b/src/ibusbus.c
+index 75406a37..fc0c9033 100644
+--- a/src/ibusbus.c
++++ b/src/ibusbus.c
+@@ -48,12 +48,14 @@ enum {
+ enum {
+ PROP_0 = 0,
+ PROP_CONNECT_ASYNC,
++ PROP_CLIENT_ONLY,
+ };
+
+ /* IBusBusPriv */
+ struct _IBusBusPrivate {
+ GFileMonitor *monitor;
+ GDBusConnection *connection;
++ gboolean connected;
+ gboolean watch_dbus_signal;
+ guint watch_dbus_signal_id;
+ gboolean watch_ibus_signal;
+@@ -62,7 +64,10 @@ struct _IBusBusPrivate {
+ gchar *unique_name;
+ gboolean connect_async;
+ gchar *bus_address;
++ gboolean use_portal;
++ gboolean client_only;
+ GCancellable *cancellable;
++ guint portal_name_watch_id;
+ };
+
+ static guint bus_signals[LAST_SIGNAL] = { 0 };
+@@ -74,6 +79,7 @@ static GObject *ibus_bus_constructor (GType type,
+ guint n_params,
+ GObjectConstructParam *params);
+ static void ibus_bus_destroy (IBusObject *object);
++static void ibus_bus_connect_async (IBusBus *bus);
+ static void ibus_bus_watch_dbus_signal (IBusBus *bus);
+ static void ibus_bus_unwatch_dbus_signal (IBusBus *bus);
+ static void ibus_bus_watch_ibus_signal (IBusBus *bus);
+@@ -117,8 +123,10 @@ ibus_bus_class_init (IBusBusClass *class)
+ IBusObjectClass *ibus_object_class = IBUS_OBJECT_CLASS (class);
+
+ gobject_class->constructor = ibus_bus_constructor;
+- gobject_class->set_property = (GObjectSetPropertyFunc) ibus_bus_set_property;
+- gobject_class->get_property = (GObjectGetPropertyFunc) ibus_bus_get_property;
++ gobject_class->set_property =
++ (GObjectSetPropertyFunc) ibus_bus_set_property;
++ gobject_class->get_property =
++ (GObjectGetPropertyFunc) ibus_bus_get_property;
+ ibus_object_class->destroy = ibus_bus_destroy;
+
+ /* install properties */
+@@ -128,13 +136,28 @@ ibus_bus_class_init (IBusBusClass *class)
+ * Whether the #IBusBus object should connect asynchronously to the bus.
+ *
+ */
+- g_object_class_install_property (gobject_class,
+- PROP_CONNECT_ASYNC,
+- g_param_spec_boolean ("connect-async",
+- "Connect Async",
+- "Connect asynchronously to the bus",
+- FALSE,
+- G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
++ g_object_class_install_property (
++ gobject_class,
++ PROP_CONNECT_ASYNC,
++ g_param_spec_boolean ("connect-async",
++ "Connect Async",
++ "Connect asynchronously to the bus",
++ FALSE,
++ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
++ /**
++ * IBusBus:client-only:
++ *
++ * Whether the #IBusBus object is for client use only.
++ *
++ */
++ g_object_class_install_property (
++ gobject_class,
++ PROP_CLIENT_ONLY,
++ g_param_spec_boolean ("client-only",
++ "ClientOnly",
++ "Client use only",
++ FALSE,
++ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+ /* install signals */
+ /**
+@@ -294,6 +317,8 @@ ibus_bus_close_connection (IBusBus *bus)
+ g_cancellable_cancel (bus->priv->cancellable);
+ g_cancellable_reset (bus->priv->cancellable);
+
++ bus->priv->connected = FALSE;
++
+ /* unref the old connection at first */
+ if (bus->priv->connection != NULL) {
+ g_signal_handlers_disconnect_by_func (bus->priv->connection,
+@@ -311,6 +336,8 @@ static void
+ ibus_bus_connect_completed (IBusBus *bus)
+ {
+ g_assert (bus->priv->connection);
++
++ bus->priv->connected = TRUE;
+ /* FIXME */
+ ibus_bus_hello (bus);
+
+@@ -329,9 +356,38 @@ ibus_bus_connect_completed (IBusBus *bus)
+ }
+
+ static void
++_bus_connect_start_portal_cb (GObject *source_object,
++ GAsyncResult *res,
++ gpointer user_data)
++{
++ IBusBus *bus = IBUS_BUS (user_data);
++ GVariant *result;
++ GError *error = NULL;
++
++ result = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source_object),
++ res,
++ &error);
++ if (result != NULL) {
++ ibus_bus_connect_completed (bus);
++ g_variant_unref (result);
++ } else {
++ g_error_free (error);
++
++ g_dbus_connection_close (bus->priv->connection, NULL, NULL, NULL);
++ g_object_unref (bus->priv->connection);
++ bus->priv->connection = NULL;
++
++ g_free (bus->priv->bus_address);
++ bus->priv->bus_address = NULL;
++ }
++
++ g_object_unref (bus);
++}
++
++static void
+ _bus_connect_async_cb (GObject *source_object,
+- GAsyncResult *res,
+- gpointer user_data)
++ GAsyncResult *res,
++ gpointer user_data)
+ {
+ g_return_if_fail (user_data != NULL);
+ g_return_if_fail (IBUS_IS_BUS (user_data));
+@@ -349,7 +405,26 @@ _bus_connect_async_cb (GObject *source_object,
+ }
+
+ if (bus->priv->connection != NULL) {
+- ibus_bus_connect_completed (bus);
++ if (bus->priv->use_portal) {
++ g_object_set_data (G_OBJECT (bus->priv->connection),
++ "ibus-portal-connection",
++ GINT_TO_POINTER (TRUE));
++ g_dbus_connection_call (
++ bus->priv->connection,
++ IBUS_SERVICE_PORTAL,
++ IBUS_PATH_IBUS,
++ "org.freedesktop.DBus.Peer",
++ "Ping",
++ g_variant_new ("()"),
++ G_VARIANT_TYPE ("()"),
++ G_DBUS_CALL_FLAGS_NONE,
++ -1,
++ bus->priv->cancellable,
++ (GAsyncReadyCallback) _bus_connect_start_portal_cb,
++ g_object_ref (bus));
++ } else {
++ ibus_bus_connect_completed (bus);
++ }
+ }
+ else {
+ g_free (bus->priv->bus_address);
+@@ -360,21 +435,32 @@ _bus_connect_async_cb (GObject *source_object,
+ g_object_unref (bus);
+ }
+
++static gchar *
++ibus_bus_get_bus_address (IBusBus *bus)
++{
++ if (_bus->priv->use_portal)
++ return g_dbus_address_get_for_bus_sync (G_BUS_TYPE_SESSION, NULL, NULL);
++ else
++ return g_strdup (ibus_get_address ());
++}
++
+ static void
+ ibus_bus_connect_async (IBusBus *bus)
+ {
+- const gchar *bus_address = ibus_get_address ();
++ gchar *bus_address = ibus_bus_get_bus_address (bus);
+
+ if (bus_address == NULL)
+ return;
+
+- if (g_strcmp0 (bus->priv->bus_address, bus_address) == 0)
++ if (g_strcmp0 (bus->priv->bus_address, bus_address) == 0) {
++ g_free (bus_address);
+ return;
++ }
+
+ /* Close current connection and cancel ongoing connect request. */
+ ibus_bus_close_connection (bus);
+
+- bus->priv->bus_address = g_strdup (bus_address);
++ bus->priv->bus_address = bus_address;
+ g_object_ref (bus);
+ g_dbus_connection_new_for_address (
+ bus_address,
+@@ -385,6 +471,28 @@ ibus_bus_connect_async (IBusBus *bus)
+ _bus_connect_async_cb, bus);
+ }
+
++static gboolean
++is_in_flatpak (void)
++{
++ static gboolean flatpak_info_read;
++ static gboolean in_flatpak;
++
++ if (flatpak_info_read)
++ return in_flatpak;
++
++ flatpak_info_read = TRUE;
++ if (g_file_test ("/.flatpak-info", G_FILE_TEST_EXISTS))
++ in_flatpak = TRUE;
++ return in_flatpak;
++}
++
++static gboolean
++ibus_bus_should_connect_portal (IBusBus *bus)
++{
++ return bus->priv->client_only &&
++ (is_in_flatpak () || g_getenv ("IBUS_USE_PORTAL") != NULL);
++}
++
+ static void
+ ibus_bus_connect (IBusBus *bus)
+ {
+@@ -431,7 +539,6 @@ ibus_bus_init (IBusBus *bus)
+ {
+ struct stat buf;
+ gchar *path;
+- GFile *file;
+
+ bus->priv = IBUS_BUS_GET_PRIVATE (bus);
+
+@@ -443,6 +550,7 @@ ibus_bus_init (IBusBus *bus)
+ bus->priv->watch_ibus_signal_id = 0;
+ bus->priv->unique_name = NULL;
+ bus->priv->connect_async = FALSE;
++ bus->priv->client_only = FALSE;
+ bus->priv->bus_address = NULL;
+ bus->priv->cancellable = g_cancellable_new ();
+
+@@ -453,17 +561,12 @@ ibus_bus_init (IBusBus *bus)
+
+ if (stat (path, &buf) == 0) {
+ if (buf.st_uid != getuid ()) {
+- g_warning ("The owner of %s is not %s!", path, ibus_get_user_name ());
++ g_warning ("The owner of %s is not %s!",
++ path, ibus_get_user_name ());
+ return;
+ }
+ }
+
+- file = g_file_new_for_path (ibus_get_socket_path ());
+- bus->priv->monitor = g_file_monitor_file (file, 0, NULL, NULL);
+-
+- g_signal_connect (bus->priv->monitor, "changed", (GCallback) _changed_cb, bus);
+-
+- g_object_unref (file);
+ g_free (path);
+ }
+
+@@ -477,6 +580,9 @@ ibus_bus_set_property (IBusBus *bus,
+ case PROP_CONNECT_ASYNC:
+ bus->priv->connect_async = g_value_get_boolean (value);
+ break;
++ case PROP_CLIENT_ONLY:
++ bus->priv->client_only = g_value_get_boolean (value);
++ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (bus, prop_id, pspec);
+ }
+@@ -492,25 +598,73 @@ ibus_bus_get_property (IBusBus *bus,
+ case PROP_CONNECT_ASYNC:
+ g_value_set_boolean (value, bus->priv->connect_async);
+ break;
++ case PROP_CLIENT_ONLY:
++ g_value_set_boolean (value, bus->priv->client_only);
++ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (bus, prop_id, pspec);
+ }
+ }
+
++static void
++portal_name_appeared (GDBusConnection *connection,
++ const gchar *name,
++ const gchar *owner,
++ gpointer user_data)
++{
++ IBusBus *bus = IBUS_BUS (user_data);
++
++ if (bus->priv->connection == NULL)
++ ibus_bus_connect_async (bus);
++}
++
++static void
++portal_name_vanished (GDBusConnection *connection,
++ const gchar *name,
++ gpointer user_data)
++{
++ IBusBus *bus = IBUS_BUS (user_data);
++
++ if (bus->priv->connection)
++ g_dbus_connection_close (bus->priv->connection, NULL, NULL, NULL);
++}
++
++
+ static GObject*
+ ibus_bus_constructor (GType type,
+ guint n_params,
+ GObjectConstructParam *params)
+ {
+ GObject *object;
++ GFile *file;
+
+ /* share one IBusBus instance in whole application */
+ if (_bus == NULL) {
+- object = G_OBJECT_CLASS (ibus_bus_parent_class)->constructor (type, n_params, params);
++ object = G_OBJECT_CLASS (ibus_bus_parent_class)->constructor (
++ type, n_params, params);
+ /* make bus object sink */
+ g_object_ref_sink (object);
+ _bus = IBUS_BUS (object);
+
++ _bus->priv->use_portal = ibus_bus_should_connect_portal (_bus);
++
++ if (!_bus->priv->use_portal) {
++ file = g_file_new_for_path (ibus_get_socket_path ());
++ _bus->priv->monitor = g_file_monitor_file (file, 0, NULL, NULL);
++ g_signal_connect (_bus->priv->monitor, "changed",
++ (GCallback) _changed_cb, _bus);
++ g_object_unref (file);
++ } else {
++ _bus->priv->portal_name_watch_id =
++ g_bus_watch_name (G_BUS_TYPE_SESSION,
++ IBUS_SERVICE_PORTAL,
++ G_BUS_NAME_WATCHER_FLAGS_NONE,
++ portal_name_appeared,
++ portal_name_vanished,
++ _bus, NULL);
++ }
++
++
+ if (_bus->priv->connect_async)
+ ibus_bus_connect_async (_bus);
+ else
+@@ -561,6 +715,11 @@ ibus_bus_destroy (IBusObject *object)
+ g_object_unref (bus->priv->cancellable);
+ bus->priv->cancellable = NULL;
+
++ if (bus->priv->portal_name_watch_id) {
++ g_bus_unwatch_name (bus->priv->portal_name_watch_id);
++ bus->priv->portal_name_watch_id = 0;
++ }
++
+ IBUS_OBJECT_CLASS (ibus_bus_parent_class)->destroy (object);
+ }
+
+@@ -656,6 +815,7 @@ ibus_bus_new (void)
+ {
+ IBusBus *bus = IBUS_BUS (g_object_new (IBUS_TYPE_BUS,
+ "connect-async", FALSE,
++ "client-only", FALSE,
+ NULL));
+
+ return bus;
+@@ -666,6 +826,18 @@ ibus_bus_new_async (void)
+ {
+ IBusBus *bus = IBUS_BUS (g_object_new (IBUS_TYPE_BUS,
+ "connect-async", TRUE,
++ "client-only", FALSE,
++ NULL));
++
++ return bus;
++}
++
++IBusBus *
++ibus_bus_new_async_client (void)
++{
++ IBusBus *bus = IBUS_BUS (g_object_new (IBUS_TYPE_BUS,
++ "connect-async", TRUE,
++ "client-only", TRUE,
+ NULL));
+
+ return bus;
+@@ -679,7 +851,7 @@ ibus_bus_is_connected (IBusBus *bus)
+ if (bus->priv->connection == NULL || g_dbus_connection_is_closed (bus->priv->connection))
+ return FALSE;
+
+- return TRUE;
++ return bus->priv->connected;
+ }
+
+ IBusInputContext *
+@@ -795,9 +967,9 @@ ibus_bus_create_input_context_async (IBusBus *bus,
+ * 2. New local IBusInputContext proxy of the remote IC
+ */
+ g_dbus_connection_call (bus->priv->connection,
+- IBUS_SERVICE_IBUS,
++ ibus_bus_get_service_name (bus),
+ IBUS_PATH_IBUS,
+- IBUS_INTERFACE_IBUS,
++ bus->priv->use_portal ? IBUS_INTERFACE_PORTAL : IBUS_INTERFACE_IBUS,
+ "CreateInputContext",
+ g_variant_new ("(s)", client_name),
+ G_VARIANT_TYPE("(o)"),
+@@ -1454,6 +1626,14 @@ ibus_bus_get_connection (IBusBus *bus)
+ return bus->priv->connection;
+ }
+
++const gchar *
++ibus_bus_get_service_name (IBusBus *bus)
++{
++ if (bus->priv->use_portal)
++ return IBUS_SERVICE_PORTAL;
++ return IBUS_SERVICE_IBUS;
++}
++
+ gboolean
+ ibus_bus_exit (IBusBus *bus,
+ gboolean restart)
+@@ -2369,6 +2549,13 @@ ibus_bus_call_sync (IBusBus *bus,
+ g_assert (member != NULL);
+ g_return_val_if_fail (ibus_bus_is_connected (bus), NULL);
+
++ if (bus->priv->use_portal &&
++ g_strcmp0 (bus_name, IBUS_SERVICE_IBUS) == 0) {
++ bus_name = IBUS_SERVICE_PORTAL;
++ if (g_strcmp0 (interface, IBUS_INTERFACE_IBUS) == 0)
++ interface = IBUS_INTERFACE_PORTAL;
++ }
++
+ GError *error = NULL;
+ GVariant *result;
+ result = g_dbus_connection_call_sync (bus->priv->connection,
+@@ -2436,6 +2623,13 @@ ibus_bus_call_async (IBusBus *bus,
+ task = g_task_new (bus, cancellable, callback, user_data);
+ g_task_set_source_tag (task, source_tag);
+
++ if (bus->priv->use_portal &&
++ g_strcmp0 (bus_name, IBUS_SERVICE_IBUS) == 0) {
++ bus_name = IBUS_SERVICE_PORTAL;
++ if (g_strcmp0 (interface, IBUS_INTERFACE_IBUS) == 0)
++ interface = IBUS_INTERFACE_PORTAL;
++ }
++
+ g_dbus_connection_call (bus->priv->connection,
+ bus_name,
+ path,
+diff --git a/src/ibusbus.h b/src/ibusbus.h
+index 9f65d36a..dff3dfb7 100644
+--- a/src/ibusbus.h
++++ b/src/ibusbus.h
+@@ -105,6 +105,19 @@ IBusBus *ibus_bus_new (void);
+ */
+ IBusBus *ibus_bus_new_async (void);
+
++/**
++ * ibus_bus_new_async_client:
++ *
++ * Creates a new #IBusBus instance for client use only. It will possibly
++ * be limited in what it can do.
++ *
++ * The instance will asynchronously connect to the IBus daemon.
++ *
++ * Returns: A newly allocated #IBusBus instance, and the instance is not
++ * floating.
++ */
++IBusBus *ibus_bus_new_async_client (void);
++
+
+ /**
+ * ibus_bus_is_connected:
+@@ -128,6 +141,16 @@ GDBusConnection *
+ ibus_bus_get_connection (IBusBus *bus);
+
+ /**
++ * ibus_bus_get_service_name:
++ * @bus: An #IBusBus.
++ *
++ * Return the main service name to use for calls on the ibus connection.
++ *
++ * Returns: at dbus name.
++ */
++const gchar * ibus_bus_get_service_name (IBusBus *bus);
++
++/**
+ * ibus_bus_hello:
+ * @bus: An #IBusBus.
+ *
+diff --git a/src/ibusinputcontext.c b/src/ibusinputcontext.c
+index 9a50acc0..ae7048ad 100644
+--- a/src/ibusinputcontext.c
++++ b/src/ibusinputcontext.c
+@@ -684,16 +684,20 @@ ibus_input_context_new (const gchar *path,
+ {
+ g_assert (path != NULL);
+ g_assert (G_IS_DBUS_CONNECTION (connection));
++ const gchar *service_name = IBUS_SERVICE_IBUS;
+
+ GInitable *initable;
+
+ GDBusProxyFlags flags = G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START;
+
++ if (g_object_get_data (G_OBJECT (connection), "ibus-portal-connection"))
++ service_name = IBUS_SERVICE_PORTAL;
++
+ initable = g_initable_new (IBUS_TYPE_INPUT_CONTEXT,
+ cancellable,
+ error,
+ "g-connection", connection,
+- "g-name", IBUS_SERVICE_IBUS,
++ "g-name", service_name,
+ "g-flags", flags,
+ "g-interface-name", IBUS_INTERFACE_INPUT_CONTEXT,
+ "g-object-path", path,
+@@ -714,16 +718,20 @@ ibus_input_context_new_async (const gchar *path,
+ g_assert (path != NULL);
+ g_assert (G_IS_DBUS_CONNECTION (connection));
+ g_assert (callback != NULL);
++ const gchar *service_name = IBUS_SERVICE_IBUS;
+
+ GDBusProxyFlags flags = G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START;
+
++ if (g_object_get_data (G_OBJECT (connection), "ibus-portal-connection"))
++ service_name = IBUS_SERVICE_PORTAL;
++
+ g_async_initable_new_async (IBUS_TYPE_INPUT_CONTEXT,
+ G_PRIORITY_DEFAULT,
+ cancellable,
+ callback,
+ user_data,
+ "g-connection", connection,
+- "g-name", IBUS_SERVICE_IBUS,
++ "g-name", service_name,
+ "g-flags", flags,
+ "g-interface-name", IBUS_INTERFACE_INPUT_CONTEXT,
+ "g-object-path", path,
+--
+2.13.5
+
diff --git a/org.gnome.Sdk.json.in b/org.gnome.Sdk.json.in
index 439b777..ce5809f 100644
--- a/org.gnome.Sdk.json.in
+++ b/org.gnome.Sdk.json.in
@@ -840,6 +840,29 @@
]
},
{
+ "name": "ibus",
+ "config-opts": ["--disable-xim", "--disable-static", "--disable-dconf",
"--disable-schemas-compile",
+ "--disable-setup", "--disable-ui", "--disable-engine", "--disable-libnotify",
"--disable-emoji-dict",
+ "--disable-appindicator", "--disable-tests"],
+ "cleanup": [
+ "/bin", "/libexec", "/share/bash-completion", "/share/dbus-1",
+ "/share/icons", "/share/man", "/share/ibus" ],
+ "post-install": [ "gtk-query-immodules-3.0 --update-cache",
+ "gtk-query-immodules-2.0 --update-cache" ],
+
+ "sources": [
+ {
+ "type": "archive",
+ "url": "https://github.com/ibus/ibus/releases/download/1.5.16/ibus-1.5.16.tar.gz",
+ "sha256": "36b57bfbe4f92e3281fb535cae65794b6f25164b2a3288e73e6d06b4a409fe1e"
+ },
+ {
+ "type": "patch",
+ "path": "ibus-portal.patch"
+ }
+ ]
+ },
+ {
"name": "os-release",
"sources": [
{
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]