[gnome-sdk-images] Add gtk2 ibus module



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]