Skip to content

Commit

Permalink
ui/gtk3: Add an option to run ibus-daemon
Browse files Browse the repository at this point in the history
Now ibus-ui-gtk3 has an option to launch ibus-daemon in case of no
bus connections and also a feature to save a log file of
$XDG_CACHE_HOME/wayland.log by default and an option of the verbose log.

BUG=#2408
  • Loading branch information
fujiwarat committed Jul 27, 2023
1 parent b8ab800 commit ed552e8
Show file tree
Hide file tree
Showing 3 changed files with 245 additions and 6 deletions.
92 changes: 91 additions & 1 deletion client/wayland/ibuswaylandim.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include <glib-object.h>
#include <ibus.h>
#include <string.h>
#include <sys/time.h>
#include <wayland-client.h>
#include <xkbcommon/xkbcommon.h>

Expand All @@ -36,12 +37,16 @@
enum {
PROP_0 = 0,
PROP_BUS,
PROP_DISPLAY
PROP_DISPLAY,
PROP_LOG,
PROP_VERBOSE
};

typedef struct _IBusWaylandIMPrivate IBusWaylandIMPrivate;
struct _IBusWaylandIMPrivate
{
FILE *log;
gboolean verbose;
struct wl_display *display;
struct zwp_input_method_v1 *input_method;
struct zwp_input_method_context_v1 *context;
Expand Down Expand Up @@ -931,6 +936,10 @@ registry_handle_global (void *data,

g_return_if_fail (IBUS_IS_WAYLAND_IM (wlim));
priv = ibus_wayland_im_get_instance_private (wlim);
if (priv->verbose) {
fprintf (priv->log, "wl_reistry gets interface: %s\n", interface);
fflush (priv->log);
}
if (!g_strcmp0 (interface, "zwp_input_method_v1")) {
priv->input_method =
wl_registry_bind (registry, name,
Expand Down Expand Up @@ -999,6 +1008,71 @@ ibus_wayland_im_class_init (IBusWaylandIMClass *class)
"The struct wl_display",
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));

/**
* IBusWaylandIM:log:
*
* The FILE of the logging file
* The default is $XDG_CACHE_HOME/wayland.log
*/
g_object_class_install_property (gobject_class,
PROP_LOG,
g_param_spec_pointer ("log",
"loggin file",
"The FILE of the logging file",
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));

/**
* IBusWaylandIM:verbose:
*
* The verbose logging mode
* %TRUE if output the logging file with verbose, otherwise %FALSE.
*/
g_object_class_install_property (gobject_class,
PROP_VERBOSE,
g_param_spec_boolean ("verbose",
"verbose mode",
"The verbose logging mode",
FALSE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));

}


static gboolean
ibus_wayland_im_open_log (IBusWaylandIM *wlim)
{
IBusWaylandIMPrivate *priv;
char *directory;
char *path;
struct timeval time_val;
struct tm local_time;

priv = ibus_wayland_im_get_instance_private (wlim);
directory = g_build_filename (g_get_user_cache_dir (), "ibus", NULL);
g_return_val_if_fail (directory, FALSE);
errno = 0;
if (g_mkdir_with_parents (directory, 0700) != 0) {
g_error ("mkdir is failed in: %s: %s",
directory, g_strerror (errno));
return FALSE;
}
path = g_build_filename (directory, "wayland.log", NULL);
g_free (directory);
if (!(priv->log = fopen (path, "w"))) {
g_error ("Cannot open log file: %s: %s",
path, g_strerror (errno));
return FALSE;
}
g_free (path);
gettimeofday (&time_val, NULL);
localtime_r (&time_val.tv_sec, &local_time);
fprintf (priv->log, "Start %02d:%02d:%02d.%6d\n",
local_time.tm_hour,
local_time.tm_min,
local_time.tm_sec,
(int)time_val.tv_usec);
fflush (priv->log);
return TRUE;
}


Expand All @@ -1020,6 +1094,8 @@ ibus_wayland_im_constructor (GType type,
g_object_ref_sink (object);
wlim = IBUS_WAYLAND_IM (object);
priv = ibus_wayland_im_get_instance_private (wlim);
if (!priv->log)
g_assert (ibus_wayland_im_open_log (wlim));
if (!priv->display)
priv->display = wl_display_connect (NULL);
if (!priv->display) {
Expand Down Expand Up @@ -1111,6 +1187,14 @@ ibus_wayland_im_set_property (IBusWaylandIM *wlim,
g_assert (priv->display == NULL);
priv->display = g_value_get_pointer (value);
break;
case PROP_LOG:
g_assert (priv->log == NULL);
priv->log = g_value_get_pointer (value);
break;
case PROP_VERBOSE:
g_assert (!priv->verbose);
priv->verbose = g_value_get_boolean (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (wlim, prop_id, pspec);
}
Expand All @@ -1134,6 +1218,12 @@ ibus_wayland_im_get_property (IBusWaylandIM *wlim,
case PROP_DISPLAY:
g_value_set_pointer (value, priv->display);
break;
case PROP_LOG:
g_value_set_pointer (value, priv->log);
break;
case PROP_VERBOSE:
g_value_set_boolean (value, priv->verbose);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (wlim, prop_id, pspec);
}
Expand Down
157 changes: 153 additions & 4 deletions ui/gtk3/application.vala
Original file line number Diff line number Diff line change
Expand Up @@ -21,22 +21,32 @@
* USA
*/

const string IBUS_WAYLAND_VERSION="1.1";
const ulong G_USEC_PER_SEC=1000000L;
const ulong SLEEP_DIV_PER_SEC = 100L;
const ulong MAX_DISPLAY_IDLE_TIME =
G_USEC_PER_SEC * SLEEP_DIV_PER_SEC * 60 * 3;

static string prgname;
static IBus.Bus bus;


class Application {
private Panel m_panel;
private static FileStream m_log;
private static bool m_verbose;
#if USE_GDK_WAYLAND
private static ulong m_realize_surface_id;
private static string m_user;
private static bool m_enable_wayland_im;
private static IBus.WaylandIM m_wayland_im;
private static bool m_exec_daemon;
private static string m_daemon_args;
#endif

public Application() {
GLib.Intl.bindtextdomain(Config.GETTEXT_PACKAGE, Config.LOCALEDIR);
GLib.Intl.bind_textdomain_codeset(Config.GETTEXT_PACKAGE, "UTF-8");
IBus.init();

if (bus == null)
bus = new IBus.Bus();
Expand Down Expand Up @@ -126,18 +136,138 @@ class Application {
}

#if USE_GDK_WAYLAND
private static bool open_log() {
var directory =
Path.build_filename(GLib.Environment.get_user_cache_dir(),
"ibus");
return_val_if_fail(directory != null, false);
Posix.errno = 0;
if (GLib.DirUtils.create_with_parents(directory, 0700) != 0) {
warning("mkdir is failed in %s: %s",
directory, Posix.strerror(Posix.errno));
return false;
}
var path =
Path.build_filename(directory, "wayland.log");
m_log = FileStream.open(path, "w");
unowned Posix.Passwd? pw = Posix.getpwuid(Posix.getuid());
m_user = pw.pw_name.substring(0, 6);
if (m_user == null)
m_user = GLib.Environment.get_variable("USER").substring(0, 6);
if (m_user == null)
m_user = "UNKNOW";
GLib.DateTime now = new GLib.DateTime.now_local();
var msec = now.get_microsecond() / 1000;
m_log.printf("Start %02d:%02d:%02d:%06d\n",
now.get_hour(), now.get_minute(), now.get_second(), msec);
m_log.flush();
return true;
}

private static void check_ps() {
string standard_output = null;
string standard_error = null;
int wait_status = 0;
try {
GLib.Process.spawn_command_line_sync ("ps -ef",
out standard_output,
out standard_error,
out wait_status);
} catch (GLib.SpawnError e) {
m_log.printf("Failed ps %s: %s\n", e.message, standard_error);
m_log.flush();
return;
}
var lines = standard_output.split("\n", -1);
m_log.printf("ps -ef\n");
foreach (var line in lines) {
if (line.index_of(m_user) >= 0 && line.index_of("wayland") >= 0)
m_log.printf(" %s\n", line);
}
m_log.flush();
}

private static void run_ibus_daemon() {
string[] args = { "ibus-daemon" };
foreach (var arg in m_daemon_args.split(" "))
args += arg;
GLib.Pid child_pid = 0;
try {
GLib.Process.spawn_async (null, args, null,
GLib.SpawnFlags.DO_NOT_REAP_CHILD
| GLib.SpawnFlags.SEARCH_PATH,
null,
out child_pid);
} catch (GLib.SpawnError e) {
m_log.printf("ibus-daemon error: %s\n", e.message);
warning("%s\n", e.message);
}
GLib.Thread.usleep(5 * G_USEC_PER_SEC);
}

private static void make_wayland_im() {
assert (open_log());
void *wl_display = null;
ulong i = 0;
while (true) {
var display = Gdk.Display.get_default();
if (display != null)
wl_display = ((GdkWayland.Display)display).get_wl_display();
if (wl_display != null)
break;
if (i == MAX_DISPLAY_IDLE_TIME)
break;
Thread.usleep(G_USEC_PER_SEC / SLEEP_DIV_PER_SEC);
if (m_verbose) {
m_log.printf("Spend %lu/%lu secs\n", i, SLEEP_DIV_PER_SEC);
m_log.flush();
}
++i;
}
int _errno = Posix.errno;
if (m_verbose)
check_ps();
if (wl_display == null) {
m_log.printf("Failed to connect to Wayland server: %s\n",
Posix.strerror(_errno));
m_log.flush();
assert_not_reached();
}
bus = new IBus.Bus();
var display = Gdk.Display.get_default();
var wl_display = ((GdkWayland.Display)display).get_wl_display();
m_wayland_im = new IBus.WaylandIM("bus", bus, "wl_display", wl_display);
if (!bus.is_connected() && m_exec_daemon) {
// The second new IBus.Bus() does not call ibus_bus_connect()
// but increase the ref_count so call IBus.Object.destroy()
// is called here to enable syned IBus.Bus.is_connected().
bus.destroy();
run_ibus_daemon();
bus = new IBus.Bus();
}
if (!bus.is_connected()) {
m_log.printf("Failed to connect to ibus-daemon\n");
m_log.flush();
assert_not_reached();
}
m_wayland_im = new IBus.WaylandIM("bus", bus,
"wl_display", wl_display,
"log", m_log,
"verbose", m_verbose);
}

private void set_wayland_surface(void *surface) {
m_wayland_im.set_surface(surface);
}
#endif

public static bool show_version(string option_name,
string? data,
void *user_data,
out GLib.Error error) {
print("%s %s Wayland %s\n", prgname,
Config.PACKAGE_VERSION,
IBUS_WAYLAND_VERSION);
return true;
}

public static void main(string[] argv) {
// https://bugzilla.redhat.com/show_bug.cgi?id=1226465#c20
// In /etc/xdg/plasma-workspace/env/gtk3_scrolling.sh
Expand All @@ -150,11 +280,27 @@ class Application {
GLib.Environment.unset_variable("GDK_CORE_DEVICE_EVENTS");

OptionEntry entries[] = {
{ "version", 'V', GLib.OptionFlags.NO_ARG, GLib.OptionArg.CALLBACK,
(void *)show_version,
N_("Show version"),
null },
#if USE_GDK_WAYLAND
{ "enable-wayland-im", 'i', 0, GLib.OptionArg.NONE,
&m_enable_wayland_im,
N_("Connect Wayland input method protocol"),
null },
{ "exec-daemon", 'd', 0, GLib.OptionArg.NONE,
&m_exec_daemon,
N_("Execute ibus-daemon if it's not running"),
null },
{ "daemon-args", 'g', 0, GLib.OptionArg.STRING,
&m_daemon_args,
N_("ibus-daemon's arguments"),
null },
{ "verbose", 'v', 0, GLib.OptionArg.NONE,
&m_verbose,
N_("Verbose logging"),
null },
#endif
{ null }
};
Expand All @@ -170,7 +316,10 @@ class Application {
warning(e.message);
}

IBus.init();
#if USE_GDK_WAYLAND
if (m_daemon_args == null)
m_daemon_args = "--xim";
// Should Make IBusWaylandIM after Gtk.init()
if (m_enable_wayland_im)
make_wayland_im();
Expand Down
2 changes: 1 addition & 1 deletion ui/gtk3/ibus-ui-wayland.desktop.in
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[Desktop Entry]
# IBus Wayland is a branding name but not translatable.
#Name=IBus Wayland
Exec=@libexecdir@/ibus-ui-gtk3 --enable-wayland-im
Exec=@libexecdir@/ibus-ui-gtk3 --enable-wayland-im --exec-daemon --daemon-args "--xim --panel disable"
Type=Application
X-KDE-Wayland-VirtualKeyboard=true
Icon=ibus
Expand Down

0 comments on commit ed552e8

Please sign in to comment.