Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package fcitx5-gtk for openSUSE:Factory checked in at 2023-03-19 00:31:18 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/fcitx5-gtk (Old) and /work/SRC/openSUSE:Factory/.fcitx5-gtk.new.31432 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "fcitx5-gtk" Sun Mar 19 00:31:18 2023 rev:9 rq:1072806 version:5.0.22 Changes: -------- --- /work/SRC/openSUSE:Factory/fcitx5-gtk/fcitx5-gtk.changes 2022-12-02 13:13:12.909877575 +0100 +++ /work/SRC/openSUSE:Factory/.fcitx5-gtk.new.31432/fcitx5-gtk.changes 2023-03-19 00:31:22.316317130 +0100 @@ -1,0 +2,8 @@ +Fri Mar 17 17:25:41 UTC 2023 - Dirk Müller <dmuel...@suse.com> + +- update to 5.0.22: + * Implement notify-focus-out signal + * Change GtkIMContext.reset to always commit preedit + * preedit when focus out need to happen before has_focus set + +------------------------------------------------------------------- Old: ---- fcitx5-gtk-5.0.21.tar.xz New: ---- fcitx5-gtk-5.0.22.tar.xz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ fcitx5-gtk.spec ++++++ --- /var/tmp/diff_new_pack.cyhvd9/_old 2023-03-19 00:31:22.932320052 +0100 +++ /var/tmp/diff_new_pack.cyhvd9/_new 2023-03-19 00:31:22.936320071 +0100 @@ -1,7 +1,7 @@ # # spec file for package fcitx5-gtk # -# Copyright (c) 2022 SUSE LLC +# Copyright (c) 2023 SUSE LLC # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -17,7 +17,7 @@ Name: fcitx5-gtk -Version: 5.0.21 +Version: 5.0.22 Release: 0 Summary: Gtk im module for fcitx5 and glib based dbus client library License: LGPL-2.1-or-later ++++++ fcitx5-gtk-5.0.21.tar.xz -> fcitx5-gtk-5.0.22.tar.xz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fcitx5-gtk-5.0.21/CMakeLists.txt new/fcitx5-gtk-5.0.22/CMakeLists.txt --- old/fcitx5-gtk-5.0.21/CMakeLists.txt 2022-11-24 12:33:33.205390200 +0100 +++ new/fcitx5-gtk-5.0.22/CMakeLists.txt 2023-03-11 05:01:57.579068200 +0100 @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.6) -project(fcitx5-gtk VERSION 5.0.21) +project(fcitx5-gtk VERSION 5.0.22) find_package(ECM REQUIRED 1.0.0) set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH}) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fcitx5-gtk-5.0.21/fcitx-gclient/fcitxgclient.c new/fcitx5-gtk-5.0.22/fcitx-gclient/fcitxgclient.c --- old/fcitx5-gtk-5.0.21/fcitx-gclient/fcitxgclient.c 2022-11-12 18:57:28.047163500 +0100 +++ new/fcitx5-gtk-5.0.22/fcitx-gclient/fcitxgclient.c 2022-12-20 16:06:57.910911800 +0100 @@ -162,6 +162,8 @@ " <arg name=\"state\" type=\"u\"/>\n" " <arg name=\"type\" type=\"b\"/>\n" " </signal>\n" + " <signal name=\"NotifyFocusOut\">\n" + " </signal>\n" " </interface>\n" "</node>\n"; @@ -175,6 +177,7 @@ UPDATED_FORMATTED_PREEDIT_SIGNAL, UPDATE_CLIENT_SIDE_UI_SIGNAL, CURRENT_IM_SIGNAL, + NOTIFY_FOCUS_OUT_SIGNAL, LAST_SIGNAL }; @@ -356,6 +359,15 @@ "current-im", FCITX_G_TYPE_CLIENT, G_SIGNAL_RUN_LAST, 0, NULL, NULL, fcitx_marshall_VOID__STRING_STRING_STRING, G_TYPE_NONE, 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING); + /** + * FcitxGClient::notify-focus-out: + * @self: A #FcitxGClient + * + * Emit when focus out happens on server side + */ + signals[NOTIFY_FOCUS_OUT_SIGNAL] = g_signal_new( + "notify-focus-out", FCITX_G_TYPE_CLIENT, G_SIGNAL_RUN_LAST, 0, NULL, + NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); } static void fcitx_g_client_init(FcitxGClient *self) { @@ -1045,6 +1057,8 @@ g_ptr_array_free(aux_up_strings, TRUE); g_ptr_array_free(aux_down_strings, TRUE); g_ptr_array_free(candidate_list, TRUE); + } else if (g_strcmp0(signal_name, "NotifyFocusOut") == 0) { + g_signal_emit(user_data, signals[NOTIFY_FOCUS_OUT_SIGNAL], 0); } } @@ -1062,7 +1076,7 @@ /** * fcitx_g_client_new_with_watcher: - * @connection: the FcitxGWatcher to be used with this client + * @watcher: the FcitxGWatcher to be used with this client * * New a #FcitxGClient * @@ -1086,7 +1100,7 @@ } /** - * fcitx_g_client_set_display: + * fcitx_g_client_set_program: * @self: A #FcitxGClient * @program: program name * diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fcitx5-gtk-5.0.21/gtk2/fcitximcontext.cpp new/fcitx5-gtk-5.0.22/gtk2/fcitximcontext.cpp --- old/fcitx5-gtk-5.0.21/gtk2/fcitximcontext.cpp 2022-11-12 19:02:35.280998700 +0100 +++ new/fcitx5-gtk-5.0.22/gtk2/fcitximcontext.cpp 2023-02-02 21:40:20.115213900 +0100 @@ -17,6 +17,7 @@ #include "fcitx-gclient/fcitxgclient.h" #include "fcitx-gclient/fcitxgwatcher.h" #include "fcitximcontext.h" +#include "utils.h" #include <gdk/gdk.h> #include <gdk/gdkkeysyms.h> #include <gdk/gdkx.h> @@ -29,32 +30,15 @@ #define NEW_GDK_WINDOW_GET_DISPLAY #endif -static constexpr uint32_t HandledMask = (1 << 24); -static constexpr uint32_t IgnoredMask = (1 << 25); -static constexpr unsigned int MAX_CACHED_EVENTS = 30; +using namespace fcitx::gtk; extern "C" { -static bool get_boolean_env(const char *name, bool defval) { - const char *value = getenv(name); - - if (value == nullptr) { - return defval; - } - - if (g_strcmp0(value, "") == 0 || g_strcmp0(value, "0") == 0 || - g_strcmp0(value, "false") == 0 || g_strcmp0(value, "False") == 0 || - g_strcmp0(value, "FALSE") == 0) { - return false; - } - - return true; -} - struct _FcitxIMContext { GtkIMContext parent; GdkWindow *client_window; + gulong button_press_signal; GdkRectangle area; FcitxGClient *client; GtkIMContext *slave; @@ -66,6 +50,7 @@ gboolean support_surrounding_text; gboolean is_inpreedit; gchar *preedit_string; + gchar *commit_preedit_string; gchar *surrounding_text; int cursor_pos; guint64 capability_from_toolkit; @@ -107,6 +92,9 @@ PangoAttrList **attrs, gint *cursor_pos); +static void fcitx_im_context_commit_string(FcitxIMContext *context, + const gchar *str); +static void fcitx_im_context_commit_preedit(FcitxIMContext *context); static gboolean _set_cursor_location_internal(FcitxIMContext *fcitxcontext); static gboolean _defer_request_surrounding_text(FcitxIMContext *fcitxcontext); static void _slave_commit_cb(GtkIMContext *slave, gchar *string, @@ -136,6 +124,8 @@ GPtrArray *array, int cursor_pos, void *user_data); +static void _fcitx_im_context_notify_focus_out_cb(FcitxGClient *client, + void *user_data); static void _fcitx_im_context_process_key_cb(GObject *source_object, GAsyncResult *res, gpointer user_data); @@ -220,25 +210,6 @@ return FCITX_IM_CONTEXT(obj); } -static gboolean check_app_name(const gchar *pattern) { - bool result = FALSE; - const gchar *prgname = g_get_prgname(); - if (!prgname) { - return FALSE; - } - gchar **p; - gchar **apps = g_strsplit(pattern, ",", 0); - for (p = apps; *p != NULL; p++) { - if (g_regex_match_simple(*p, prgname, (GRegexCompileFlags)0, - (GRegexMatchFlags)0)) { - result = TRUE; - break; - } - } - g_strfreev(apps); - return result; -} - /// static void fcitx_im_context_class_init(FcitxIMContextClass *klass, gpointer) { GtkIMContextClass *im_context_class = GTK_IM_CONTEXT_CLASS(klass); @@ -337,6 +308,7 @@ context->last_anchor_pos = -1; context->last_cursor_pos = -1; context->preedit_string = NULL; + context->commit_preedit_string = NULL; context->attrlist = NULL; context->last_updated_capability = (guint64)fcitx::FcitxCapabilityFlag_SurroundingText; @@ -402,6 +374,9 @@ g_signal_connect(context->client, "update-formatted-preedit", G_CALLBACK(_fcitx_im_context_update_formatted_preedit_cb), context); + g_signal_connect(context->client, "notify-focus-out", + G_CALLBACK(_fcitx_im_context_notify_focus_out_cb), + context); context->xkbComposeState = xkbComposeTable @@ -429,6 +404,7 @@ g_clear_object(&context->client); g_clear_pointer(&context->preedit_string, g_free); + g_clear_pointer(&context->commit_preedit_string, g_free); g_clear_pointer(&context->surrounding_text, g_free); g_clear_pointer(&context->attrlist, pango_attr_list_unref); /* https://github.com/GNOME/glib/blob/main/glib/gqueue.c#L164 @@ -441,15 +417,47 @@ G_OBJECT_CLASS(parent_class)->finalize(obj); } +static gboolean +fcitx_im_context_button_press_event_cb(GtkWidget *, GdkEventButton *event, + FcitxIMContext *context) { + if (event->button != 1) + return FALSE; + + if (!context->has_focus) { + return FALSE; + } + + fcitx_im_context_reset(GTK_IM_CONTEXT(context)); + return FALSE; +} + /// static void fcitx_im_context_set_client_window(GtkIMContext *context, GdkWindow *client_window) { FcitxIMContext *fcitxcontext = FCITX_IM_CONTEXT(context); + + GtkWidget *oldwidget = nullptr; + if (fcitxcontext->client_window) { + gdk_window_get_user_data(fcitxcontext->client_window, + (gpointer *)&oldwidget); + } + + g_clear_signal_handler(&fcitxcontext->button_press_signal, oldwidget); g_clear_object(&fcitxcontext->client_window); if (!client_window) { return; } + fcitxcontext->client_window = GDK_WINDOW(g_object_ref(client_window)); + + GtkWidget *widget = nullptr; + gdk_window_get_user_data(fcitxcontext->client_window, (gpointer *)&widget); + /* firefox needs GtkWidget instead of GtkWindow */ + if (GTK_IS_WIDGET(widget)) { + fcitxcontext->button_press_signal = g_signal_connect( + widget, "button-press-event", + G_CALLBACK(fcitx_im_context_button_press_event_cb), fcitxcontext); + } } static gboolean @@ -571,89 +579,101 @@ context->attrlist = pango_attr_list_new(); GString *gstr = g_string_new(NULL); + GString *commit_gstr = g_string_new(NULL); - unsigned int i = 0; - for (i = 0; i < array->len; i++) { - size_t bytelen = strlen(gstr->str); - FcitxGPreeditItem *preedit = - (FcitxGPreeditItem *)g_ptr_array_index(array, i); - const gchar *s = preedit->string; - gint type = preedit->type; - - PangoAttribute *pango_attr = NULL; - if ((type & (guint32)fcitx::FcitxTextFormatFlag_Underline)) { - pango_attr = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE); - pango_attr->start_index = bytelen; - pango_attr->end_index = bytelen + strlen(s); - pango_attr_list_insert(context->attrlist, pango_attr); - } - if ((type & (guint32)fcitx::FcitxTextFormatFlag_Strike)) { - pango_attr = pango_attr_strikethrough_new(true); - pango_attr->start_index = bytelen; - pango_attr->end_index = bytelen + strlen(s); - pango_attr_list_insert(context->attrlist, pango_attr); - } - if ((type & (guint32)fcitx::FcitxTextFormatFlag_Bold)) { - pango_attr = pango_attr_weight_new(PANGO_WEIGHT_BOLD); - pango_attr->start_index = bytelen; - pango_attr->end_index = bytelen + strlen(s); - pango_attr_list_insert(context->attrlist, pango_attr); - } - if ((type & (guint32)fcitx::FcitxTextFormatFlag_Italic)) { - pango_attr = pango_attr_style_new(PANGO_STYLE_ITALIC); - pango_attr->start_index = bytelen; - pango_attr->end_index = bytelen + strlen(s); - pango_attr_list_insert(context->attrlist, pango_attr); - } + if (array) { + for (unsigned int i = 0; i < array->len; i++) { + size_t bytelen = strlen(gstr->str); + FcitxGPreeditItem *preedit = + (FcitxGPreeditItem *)g_ptr_array_index(array, i); + const gchar *s = preedit->string; + gint type = preedit->type; + + PangoAttribute *pango_attr = NULL; + if ((type & (guint32)fcitx::FcitxTextFormatFlag_Underline)) { + pango_attr = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE); + pango_attr->start_index = bytelen; + pango_attr->end_index = bytelen + strlen(s); + pango_attr_list_insert(context->attrlist, pango_attr); + } + if ((type & (guint32)fcitx::FcitxTextFormatFlag_Strike)) { + pango_attr = pango_attr_strikethrough_new(true); + pango_attr->start_index = bytelen; + pango_attr->end_index = bytelen + strlen(s); + pango_attr_list_insert(context->attrlist, pango_attr); + } + if ((type & (guint32)fcitx::FcitxTextFormatFlag_Bold)) { + pango_attr = pango_attr_weight_new(PANGO_WEIGHT_BOLD); + pango_attr->start_index = bytelen; + pango_attr->end_index = bytelen + strlen(s); + pango_attr_list_insert(context->attrlist, pango_attr); + } + if ((type & (guint32)fcitx::FcitxTextFormatFlag_Italic)) { + pango_attr = pango_attr_style_new(PANGO_STYLE_ITALIC); + pango_attr->start_index = bytelen; + pango_attr->end_index = bytelen + strlen(s); + pango_attr_list_insert(context->attrlist, pango_attr); + } - if (type & (guint32)fcitx::FcitxTextFormatFlag_HighLight) { - gboolean hasColor = false; - GdkColor fg; - GdkColor bg; - memset(&fg, 0, sizeof(GdkColor)); - memset(&bg, 0, sizeof(GdkColor)); - - if (context->client_window) { - GtkWidget *widget; - gdk_window_get_user_data(context->client_window, - (gpointer *)&widget); - if (GTK_IS_WIDGET(widget)) { - hasColor = true; - GtkStyle *style = gtk_widget_get_style(widget); - fg = style->text[GTK_STATE_SELECTED]; - bg = style->base[GTK_STATE_SELECTED]; + if (type & (guint32)fcitx::FcitxTextFormatFlag_HighLight) { + gboolean hasColor = false; + GdkColor fg; + GdkColor bg; + memset(&fg, 0, sizeof(GdkColor)); + memset(&bg, 0, sizeof(GdkColor)); + + if (context->client_window) { + GtkWidget *widget; + gdk_window_get_user_data(context->client_window, + (gpointer *)&widget); + if (GTK_IS_WIDGET(widget)) { + hasColor = true; + GtkStyle *style = gtk_widget_get_style(widget); + fg = style->text[GTK_STATE_SELECTED]; + bg = style->base[GTK_STATE_SELECTED]; + } } - } - if (!hasColor) { - fg.red = 0xffff; - fg.green = 0xffff; - fg.blue = 0xffff; - bg.red = 0x43ff; - bg.green = 0xacff; - bg.blue = 0xe8ff; - } + if (!hasColor) { + fg.red = 0xffff; + fg.green = 0xffff; + fg.blue = 0xffff; + bg.red = 0x43ff; + bg.green = 0xacff; + bg.blue = 0xe8ff; + } - pango_attr = pango_attr_foreground_new(fg.red, fg.green, fg.blue); - pango_attr->start_index = bytelen; - pango_attr->end_index = bytelen + strlen(s); - pango_attr_list_insert(context->attrlist, pango_attr); - pango_attr = pango_attr_background_new(bg.red, bg.green, bg.blue); - pango_attr->start_index = bytelen; - pango_attr->end_index = bytelen + strlen(s); - pango_attr_list_insert(context->attrlist, pango_attr); + pango_attr = + pango_attr_foreground_new(fg.red, fg.green, fg.blue); + pango_attr->start_index = bytelen; + pango_attr->end_index = bytelen + strlen(s); + pango_attr_list_insert(context->attrlist, pango_attr); + pango_attr = + pango_attr_background_new(bg.red, bg.green, bg.blue); + pango_attr->start_index = bytelen; + pango_attr->end_index = bytelen + strlen(s); + pango_attr_list_insert(context->attrlist, pango_attr); + } + gstr = g_string_append(gstr, s); + if ((type & (guint32)fcitx::FcitxTextFormatFlag_DontCommit) == 0) { + commit_gstr = g_string_append(commit_gstr, s); + } } - gstr = g_string_append(gstr, s); } gchar *str = g_string_free(gstr, FALSE); context->preedit_string = str; + context->commit_preedit_string = g_string_free(commit_gstr, FALSE); context->cursor_pos = g_utf8_pointer_to_offset(str, str + cursor_pos); if (context->preedit_string != NULL && context->preedit_string[0] == 0) { g_clear_pointer(&context->preedit_string, g_free); } + if (context->commit_preedit_string != NULL && + context->commit_preedit_string[0] == 0) { + g_clear_pointer(&context->commit_preedit_string, g_free); + } } static void _fcitx_im_context_update_formatted_preedit_cb(FcitxGClient *, @@ -675,6 +695,7 @@ g_clear_pointer(&context->preedit_string, g_free); } + g_clear_pointer(&context->commit_preedit_string, g_free); g_clear_pointer(&context->attrlist, pango_attr_list_unref); if (context->use_preedit) { @@ -703,6 +724,16 @@ } } +static void _fcitx_im_context_notify_focus_out_cb(FcitxGClient *, + void *user_data) { + FcitxIMContext *context = FCITX_IM_CONTEXT(user_data); + if (!context->has_focus) { + return; + } + + fcitx_im_context_commit_preedit(context); +} + /// static void fcitx_im_context_focus_in(GtkIMContext *context) { FcitxIMContext *fcitxcontext = FCITX_IM_CONTEXT(context); @@ -753,6 +784,29 @@ return; } +static void fcitx_im_context_commit_string(FcitxIMContext *context, + const gchar *str) { + g_signal_emit(context, _signal_commit_id, 0, str); + + // Better request surrounding after commit. + gdk_threads_add_idle_full( + G_PRIORITY_DEFAULT_IDLE, (GSourceFunc)_defer_request_surrounding_text, + g_object_ref(context), (GDestroyNotify)g_object_unref); +} + +static void fcitx_im_context_commit_preedit(FcitxIMContext *context) { + if (!context->has_focus) { + return; + } + + if (context->commit_preedit_string) { + fcitx_im_context_commit_string(context, context->commit_preedit_string); + } + + _fcitx_im_context_update_formatted_preedit_cb(context->client, nullptr, 0, + context); +} + static void fcitx_im_context_focus_out(GtkIMContext *context) { FcitxIMContext *fcitxcontext = FCITX_IM_CONTEXT(context); @@ -764,6 +818,8 @@ (gpointer *)&_focus_im_context); _focus_im_context = NULL; + fcitx_im_context_commit_preedit(fcitxcontext); + fcitxcontext->has_focus = false; fcitxcontext->last_key_code = 0; fcitxcontext->last_is_release = false; @@ -772,13 +828,6 @@ fcitx_g_client_focus_out(fcitxcontext->client); } - fcitxcontext->cursor_pos = 0; - if (fcitxcontext->preedit_string != NULL) { - g_clear_pointer(&fcitxcontext->preedit_string, g_free); - g_signal_emit(fcitxcontext, _signal_preedit_changed_id, 0); - g_signal_emit(fcitxcontext, _signal_preedit_end_id, 0); - } - gtk_im_context_focus_out(fcitxcontext->slave); return; @@ -982,6 +1031,7 @@ } flags |= (guint64)fcitx::FcitxCapabilityFlag_KeyEventOrderFix; flags |= (guint64)fcitx::FcitxCapabilityFlag_ReportKeyRepeat; + flags |= (guint64)fcitx::FcitxCapabilityFlag_ClientUnfocusCommit; // always run this code against all gtk version // seems visibility != PASSWORD hint @@ -1021,6 +1071,8 @@ static void fcitx_im_context_reset(GtkIMContext *context) { FcitxIMContext *fcitxcontext = FCITX_IM_CONTEXT(context); + fcitx_im_context_commit_preedit(fcitxcontext); + if (fcitx_g_client_is_valid(fcitxcontext->client)) { fcitx_g_client_reset(fcitxcontext->client); } @@ -1125,12 +1177,7 @@ void _fcitx_im_context_commit_string_cb(FcitxGClient *, char *str, void *user_data) { FcitxIMContext *context = FCITX_IM_CONTEXT(user_data); - g_signal_emit(context, _signal_commit_id, 0, str); - - // Better request surrounding after commit. - gdk_threads_add_idle_full( - G_PRIORITY_DEFAULT_IDLE, (GSourceFunc)_defer_request_surrounding_text, - g_object_ref(context), (GDestroyNotify)g_object_unref); + fcitx_im_context_commit_string(context, str); } void _fcitx_im_context_forward_key_cb(FcitxGClient *, guint keyval, guint state, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fcitx5-gtk-5.0.21/gtk2/utils.cpp new/fcitx5-gtk-5.0.22/gtk2/utils.cpp --- old/fcitx5-gtk-5.0.21/gtk2/utils.cpp 1970-01-01 01:00:00.000000000 +0100 +++ new/fcitx5-gtk-5.0.22/gtk2/utils.cpp 2023-03-19 00:31:23.204321343 +0100 @@ -0,0 +1 @@ +symbolic link to ../gtk3/utils.cpp diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fcitx5-gtk-5.0.21/gtk2/utils.h new/fcitx5-gtk-5.0.22/gtk2/utils.h --- old/fcitx5-gtk-5.0.21/gtk2/utils.h 1970-01-01 01:00:00.000000000 +0100 +++ new/fcitx5-gtk-5.0.22/gtk2/utils.h 2023-03-19 00:31:23.212321381 +0100 @@ -0,0 +1 @@ +symbolic link to ../gtk3/utils.h diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fcitx5-gtk-5.0.21/gtk3/fcitximcontext.cpp new/fcitx5-gtk-5.0.22/gtk3/fcitximcontext.cpp --- old/fcitx5-gtk-5.0.21/gtk3/fcitximcontext.cpp 2022-11-12 18:39:05.962027800 +0100 +++ new/fcitx5-gtk-5.0.22/gtk3/fcitximcontext.cpp 2023-02-02 21:40:40.028492000 +0100 @@ -38,48 +38,13 @@ using namespace fcitx::gtk; -static constexpr uint32_t HandledMask = (1 << 24); -static constexpr uint32_t IgnoredMask = (1 << 25); -static constexpr unsigned int MAX_CACHED_EVENTS = 30; - -static const uint64_t purpose_related_capability = - fcitx::FcitxCapabilityFlag_Alpha | fcitx::FcitxCapabilityFlag_Digit | - fcitx::FcitxCapabilityFlag_Number | fcitx::FcitxCapabilityFlag_Dialable | - fcitx::FcitxCapabilityFlag_Url | fcitx::FcitxCapabilityFlag_Email | - fcitx::FcitxCapabilityFlag_Password; - -static const uint64_t hints_related_capability = - fcitx::FcitxCapabilityFlag_SpellCheck | - fcitx::FcitxCapabilityFlag_NoSpellCheck | - fcitx::FcitxCapabilityFlag_WordCompletion | - fcitx::FcitxCapabilityFlag_Lowercase | - fcitx::FcitxCapabilityFlag_Uppercase | - fcitx::FcitxCapabilityFlag_UppercaseWords | - fcitx::FcitxCapabilityFlag_UppwercaseSentences | - fcitx::FcitxCapabilityFlag_NoOnScreenKeyboard; - extern "C" { -static bool get_boolean_env(const char *name, bool defval) { - const char *value = getenv(name); - - if (value == nullptr) { - return defval; - } - - if (g_strcmp0(value, "") == 0 || g_strcmp0(value, "0") == 0 || - g_strcmp0(value, "false") == 0 || g_strcmp0(value, "False") == 0 || - g_strcmp0(value, "FALSE") == 0) { - return false; - } - - return true; -} - struct _FcitxIMContext { GtkIMContext parent; GdkWindow *client_window; + gulong button_press_signal; GdkRectangle area; FcitxGClient *client; GtkIMContext *slave; @@ -92,6 +57,7 @@ gboolean is_inpreedit; gboolean is_wayland; gchar *preedit_string; + gchar *commit_preedit_string; gchar *surrounding_text; int cursor_pos; guint64 capability_from_toolkit; @@ -135,6 +101,9 @@ PangoAttrList **attrs, gint *cursor_pos); +static void fcitx_im_context_commit_string(FcitxIMContext *context, + const gchar *str); +static void fcitx_im_context_commit_preedit(FcitxIMContext *context); static gboolean _set_cursor_location_internal(FcitxIMContext *fcitxcontext); static gboolean _defer_request_surrounding_text(FcitxIMContext *fcitxcontext); static void _slave_commit_cb(GtkIMContext *slave, gchar *string, @@ -164,6 +133,8 @@ GPtrArray *array, int cursor_pos, void *user_data); +static void _fcitx_im_context_notify_focus_out_cb(FcitxGClient *client, + void *user_data); static void _fcitx_im_context_process_key_cb(GObject *source_object, GAsyncResult *res, gpointer user_data); @@ -259,25 +230,6 @@ return FCITX_IM_CONTEXT(obj); } -static gboolean check_app_name(const gchar *pattern) { - bool result = FALSE; - const gchar *prgname = g_get_prgname(); - if (!prgname) { - return FALSE; - } - gchar **p; - gchar **apps = g_strsplit(pattern, ",", 0); - for (p = apps; *p != NULL; p++) { - if (g_regex_match_simple(*p, prgname, (GRegexCompileFlags)0, - (GRegexMatchFlags)0)) { - result = TRUE; - break; - } - } - g_strfreev(apps); - return result; -} - /// static void fcitx_im_context_class_init(FcitxIMContextClass *klass, gpointer) { GtkIMContextClass *im_context_class = GTK_IM_CONTEXT_CLASS(klass); @@ -376,6 +328,7 @@ context->last_anchor_pos = -1; context->last_cursor_pos = -1; context->preedit_string = NULL; + context->commit_preedit_string = NULL; context->attrlist = NULL; context->last_updated_capability = (guint64)fcitx::FcitxCapabilityFlag_SurroundingText; @@ -465,6 +418,9 @@ g_signal_connect(context->client, "update-formatted-preedit", G_CALLBACK(_fcitx_im_context_update_formatted_preedit_cb), context); + g_signal_connect(context->client, "notify-focus-out", + G_CALLBACK(_fcitx_im_context_notify_focus_out_cb), + context); context->xkbComposeState = xkbComposeTable @@ -494,6 +450,7 @@ g_clear_object(&context->client); g_clear_pointer(&context->preedit_string, g_free); + g_clear_pointer(&context->commit_preedit_string, g_free); g_clear_pointer(&context->surrounding_text, g_free); g_clear_pointer(&context->attrlist, pango_attr_list_unref); /* https://github.com/GNOME/glib/blob/main/glib/gqueue.c#L164 @@ -506,6 +463,20 @@ G_OBJECT_CLASS(parent_class)->finalize(obj); } +static gboolean +fcitx_im_context_button_press_event_cb(GtkWidget *, GdkEventButton *event, + FcitxIMContext *context) { + if (event->button != 1) + return FALSE; + + if (!context->has_focus) { + return FALSE; + } + + fcitx_im_context_reset(GTK_IM_CONTEXT(context)); + return FALSE; +} + /// static void fcitx_im_context_set_client_window(GtkIMContext *context, GdkWindow *client_window) { @@ -515,6 +486,14 @@ } delete fcitxcontext->candidate_window; fcitxcontext->candidate_window = nullptr; + + GtkWidget *oldwidget = nullptr; + if (fcitxcontext->client_window) { + gdk_window_get_user_data(fcitxcontext->client_window, + (gpointer *)&oldwidget); + } + + g_clear_signal_handler(&fcitxcontext->button_press_signal, oldwidget); g_clear_object(&fcitxcontext->client_window); if (!client_window) { return; @@ -522,6 +501,15 @@ fcitxcontext->client_window = GDK_WINDOW(g_object_ref(client_window)); + GtkWidget *widget = nullptr; + gdk_window_get_user_data(fcitxcontext->client_window, (gpointer *)&widget); + /* firefox needs GtkWidget instead of GtkWindow */ + if (GTK_IS_WIDGET(widget)) { + fcitxcontext->button_press_signal = g_signal_connect( + widget, "button-press-event", + G_CALLBACK(fcitx_im_context_button_press_event_cb), fcitxcontext); + } + _fcitx_im_context_set_capability(fcitxcontext, FALSE); fcitxcontext->candidate_window = new Gtk3InputWindow( @@ -649,108 +637,124 @@ context->attrlist = pango_attr_list_new(); GString *gstr = g_string_new(NULL); + GString *commit_gstr = g_string_new(NULL); - unsigned int i = 0; - for (i = 0; i < array->len; i++) { - size_t bytelen = strlen(gstr->str); - FcitxGPreeditItem *preedit = - (FcitxGPreeditItem *)g_ptr_array_index(array, i); - const gchar *s = preedit->string; - gint type = preedit->type; - - PangoAttribute *pango_attr = NULL; - if ((type & (guint32)fcitx::FcitxTextFormatFlag_Underline)) { - pango_attr = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE); - pango_attr->start_index = bytelen; - pango_attr->end_index = bytelen + strlen(s); - pango_attr_list_insert(context->attrlist, pango_attr); - } - if ((type & (guint32)fcitx::FcitxTextFormatFlag_Strike)) { - pango_attr = pango_attr_strikethrough_new(true); - pango_attr->start_index = bytelen; - pango_attr->end_index = bytelen + strlen(s); - pango_attr_list_insert(context->attrlist, pango_attr); - } - if ((type & (guint32)fcitx::FcitxTextFormatFlag_Bold)) { - pango_attr = pango_attr_weight_new(PANGO_WEIGHT_BOLD); - pango_attr->start_index = bytelen; - pango_attr->end_index = bytelen + strlen(s); - pango_attr_list_insert(context->attrlist, pango_attr); - } - if ((type & (guint32)fcitx::FcitxTextFormatFlag_Italic)) { - pango_attr = pango_attr_style_new(PANGO_STYLE_ITALIC); - pango_attr->start_index = bytelen; - pango_attr->end_index = bytelen + strlen(s); - pango_attr_list_insert(context->attrlist, pango_attr); - } - - if (type & (guint32)fcitx::FcitxTextFormatFlag_HighLight) { - gboolean hasColor = false; - GdkColor fg; - GdkColor bg; - memset(&fg, 0, sizeof(GdkColor)); - memset(&bg, 0, sizeof(GdkColor)); - - if (context->client_window) { - GtkWidget *widget; - gdk_window_get_user_data(context->client_window, - (gpointer *)&widget); - if (GTK_IS_WIDGET(widget)) { - hasColor = true; - GtkStyleContext *styleContext = - gtk_widget_get_style_context(widget); - GdkRGBA fg_rgba, bg_rgba; - hasColor = - gtk_style_context_lookup_color( - styleContext, "theme_selected_bg_color", - &bg_rgba) && - gtk_style_context_lookup_color( - styleContext, "theme_selected_fg_color", &fg_rgba); - - if (hasColor) { - fg.pixel = 0; - fg.red = CLAMP((gint)(fg_rgba.red * 65535), 0, 65535); - fg.green = - CLAMP((gint)(fg_rgba.green * 65535), 0, 65535); - fg.blue = CLAMP((gint)(fg_rgba.blue * 65535), 0, 65535); - bg.pixel = 0; - bg.red = CLAMP((gint)(bg_rgba.red * 65535), 0, 65535); - bg.green = - CLAMP((gint)(bg_rgba.green * 65535), 0, 65535); - bg.blue = CLAMP((gint)(bg_rgba.blue * 65535), 0, 65535); + if (array) { + for (unsigned int i = 0; i < array->len; i++) { + size_t bytelen = strlen(gstr->str); + FcitxGPreeditItem *preedit = + (FcitxGPreeditItem *)g_ptr_array_index(array, i); + const gchar *s = preedit->string; + gint type = preedit->type; + + PangoAttribute *pango_attr = NULL; + if ((type & (guint32)fcitx::FcitxTextFormatFlag_Underline)) { + pango_attr = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE); + pango_attr->start_index = bytelen; + pango_attr->end_index = bytelen + strlen(s); + pango_attr_list_insert(context->attrlist, pango_attr); + } + if ((type & (guint32)fcitx::FcitxTextFormatFlag_Strike)) { + pango_attr = pango_attr_strikethrough_new(true); + pango_attr->start_index = bytelen; + pango_attr->end_index = bytelen + strlen(s); + pango_attr_list_insert(context->attrlist, pango_attr); + } + if ((type & (guint32)fcitx::FcitxTextFormatFlag_Bold)) { + pango_attr = pango_attr_weight_new(PANGO_WEIGHT_BOLD); + pango_attr->start_index = bytelen; + pango_attr->end_index = bytelen + strlen(s); + pango_attr_list_insert(context->attrlist, pango_attr); + } + if ((type & (guint32)fcitx::FcitxTextFormatFlag_Italic)) { + pango_attr = pango_attr_style_new(PANGO_STYLE_ITALIC); + pango_attr->start_index = bytelen; + pango_attr->end_index = bytelen + strlen(s); + pango_attr_list_insert(context->attrlist, pango_attr); + } + + if (type & (guint32)fcitx::FcitxTextFormatFlag_HighLight) { + gboolean hasColor = false; + GdkColor fg; + GdkColor bg; + memset(&fg, 0, sizeof(GdkColor)); + memset(&bg, 0, sizeof(GdkColor)); + + if (context->client_window) { + GtkWidget *widget; + gdk_window_get_user_data(context->client_window, + (gpointer *)&widget); + if (GTK_IS_WIDGET(widget)) { + hasColor = true; + GtkStyleContext *styleContext = + gtk_widget_get_style_context(widget); + GdkRGBA fg_rgba, bg_rgba; + hasColor = gtk_style_context_lookup_color( + styleContext, "theme_selected_bg_color", + &bg_rgba) && + gtk_style_context_lookup_color( + styleContext, "theme_selected_fg_color", + &fg_rgba); + + if (hasColor) { + fg.pixel = 0; + fg.red = + CLAMP((gint)(fg_rgba.red * 65535), 0, 65535); + fg.green = + CLAMP((gint)(fg_rgba.green * 65535), 0, 65535); + fg.blue = + CLAMP((gint)(fg_rgba.blue * 65535), 0, 65535); + bg.pixel = 0; + bg.red = + CLAMP((gint)(bg_rgba.red * 65535), 0, 65535); + bg.green = + CLAMP((gint)(bg_rgba.green * 65535), 0, 65535); + bg.blue = + CLAMP((gint)(bg_rgba.blue * 65535), 0, 65535); + } } } - } - if (!hasColor) { - fg.red = 0xffff; - fg.green = 0xffff; - fg.blue = 0xffff; - bg.red = 0x43ff; - bg.green = 0xacff; - bg.blue = 0xe8ff; - } + if (!hasColor) { + fg.red = 0xffff; + fg.green = 0xffff; + fg.blue = 0xffff; + bg.red = 0x43ff; + bg.green = 0xacff; + bg.blue = 0xe8ff; + } - pango_attr = pango_attr_foreground_new(fg.red, fg.green, fg.blue); - pango_attr->start_index = bytelen; - pango_attr->end_index = bytelen + strlen(s); - pango_attr_list_insert(context->attrlist, pango_attr); - pango_attr = pango_attr_background_new(bg.red, bg.green, bg.blue); - pango_attr->start_index = bytelen; - pango_attr->end_index = bytelen + strlen(s); - pango_attr_list_insert(context->attrlist, pango_attr); + pango_attr = + pango_attr_foreground_new(fg.red, fg.green, fg.blue); + pango_attr->start_index = bytelen; + pango_attr->end_index = bytelen + strlen(s); + pango_attr_list_insert(context->attrlist, pango_attr); + pango_attr = + pango_attr_background_new(bg.red, bg.green, bg.blue); + pango_attr->start_index = bytelen; + pango_attr->end_index = bytelen + strlen(s); + pango_attr_list_insert(context->attrlist, pango_attr); + } + gstr = g_string_append(gstr, s); + if ((type & (guint32)fcitx::FcitxTextFormatFlag_DontCommit) == 0) { + commit_gstr = g_string_append(commit_gstr, s); + } } - gstr = g_string_append(gstr, s); } gchar *str = g_string_free(gstr, FALSE); context->preedit_string = str; + context->commit_preedit_string = g_string_free(commit_gstr, FALSE); context->cursor_pos = g_utf8_pointer_to_offset(str, str + cursor_pos); if (context->preedit_string != NULL && context->preedit_string[0] == 0) { g_clear_pointer(&context->preedit_string, g_free); } + if (context->commit_preedit_string != NULL && + context->commit_preedit_string[0] == 0) { + g_clear_pointer(&context->commit_preedit_string, g_free); + } } static void _fcitx_im_context_update_formatted_preedit_cb(FcitxGClient *, @@ -772,6 +776,7 @@ g_clear_pointer(&context->preedit_string, g_free); } + g_clear_pointer(&context->commit_preedit_string, g_free); g_clear_pointer(&context->attrlist, pango_attr_list_unref); if (context->use_preedit) { @@ -800,6 +805,16 @@ } } +static void _fcitx_im_context_notify_focus_out_cb(FcitxGClient *, + void *user_data) { + FcitxIMContext *context = FCITX_IM_CONTEXT(user_data); + if (!context->has_focus) { + return; + } + + fcitx_im_context_commit_preedit(context); +} + /// static void fcitx_im_context_focus_in(GtkIMContext *context) { FcitxIMContext *fcitxcontext = FCITX_IM_CONTEXT(context); @@ -850,6 +865,29 @@ return; } +static void fcitx_im_context_commit_string(FcitxIMContext *context, + const gchar *str) { + g_signal_emit(context, _signal_commit_id, 0, str); + + // Better request surrounding after commit. + gdk_threads_add_idle_full( + G_PRIORITY_DEFAULT_IDLE, (GSourceFunc)_defer_request_surrounding_text, + g_object_ref(context), (GDestroyNotify)g_object_unref); +} + +static void fcitx_im_context_commit_preedit(FcitxIMContext *context) { + if (!context->has_focus) { + return; + } + + if (context->commit_preedit_string) { + fcitx_im_context_commit_string(context, context->commit_preedit_string); + } + + _fcitx_im_context_update_formatted_preedit_cb(context->client, nullptr, 0, + context); +} + static void fcitx_im_context_focus_out(GtkIMContext *context) { FcitxIMContext *fcitxcontext = FCITX_IM_CONTEXT(context); @@ -861,6 +899,8 @@ (gpointer *)&_focus_im_context); _focus_im_context = NULL; + fcitx_im_context_commit_preedit(fcitxcontext); + fcitxcontext->has_focus = false; fcitxcontext->last_key_code = 0; fcitxcontext->last_is_release = false; @@ -869,13 +909,6 @@ fcitx_g_client_focus_out(fcitxcontext->client); } - fcitxcontext->cursor_pos = 0; - if (fcitxcontext->preedit_string != NULL) { - g_clear_pointer(&fcitxcontext->preedit_string, g_free); - g_signal_emit(fcitxcontext, _signal_preedit_changed_id, 0); - g_signal_emit(fcitxcontext, _signal_preedit_end_id, 0); - } - gtk_im_context_focus_out(fcitxcontext->slave); return; @@ -1101,6 +1134,7 @@ } flags |= (guint64)fcitx::FcitxCapabilityFlag_KeyEventOrderFix; flags |= (guint64)fcitx::FcitxCapabilityFlag_ReportKeyRepeat; + flags |= (guint64)fcitx::FcitxCapabilityFlag_ClientUnfocusCommit; // always run this code against all gtk version // seems visibility != PASSWORD hint @@ -1140,6 +1174,8 @@ static void fcitx_im_context_reset(GtkIMContext *context) { FcitxIMContext *fcitxcontext = FCITX_IM_CONTEXT(context); + fcitx_im_context_commit_preedit(fcitxcontext); + if (fcitx_g_client_is_valid(fcitxcontext->client)) { fcitx_g_client_reset(fcitxcontext->client); } @@ -1244,12 +1280,7 @@ void _fcitx_im_context_commit_string_cb(FcitxGClient *, char *str, void *user_data) { FcitxIMContext *context = FCITX_IM_CONTEXT(user_data); - g_signal_emit(context, _signal_commit_id, 0, str); - - // Better request surrounding after commit. - gdk_threads_add_idle_full( - G_PRIORITY_DEFAULT_IDLE, (GSourceFunc)_defer_request_surrounding_text, - g_object_ref(context), (GDestroyNotify)g_object_unref); + fcitx_im_context_commit_string(context, str); } void _fcitx_im_context_forward_key_cb(FcitxGClient *, guint keyval, guint state, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fcitx5-gtk-5.0.21/gtk3/utils.h new/fcitx5-gtk-5.0.22/gtk3/utils.h --- old/fcitx5-gtk-5.0.21/gtk3/utils.h 2021-01-25 22:23:36.273540700 +0100 +++ new/fcitx5-gtk-5.0.22/gtk3/utils.h 2022-12-25 19:30:09.284669200 +0100 @@ -7,6 +7,7 @@ #ifndef _GTK3_UTILS_H_ #define _GTK3_UTILS_H_ +#include "fcitxflags.h" #include <cairo.h> #include <glib-object.h> #include <memory> @@ -43,6 +44,63 @@ y <= rect.y + rect.height; } +static inline gboolean check_app_name(const gchar *pattern) { + bool result = FALSE; + const gchar *prgname = g_get_prgname(); + if (!prgname) { + return FALSE; + } + gchar **p; + gchar **apps = g_strsplit(pattern, ",", 0); + for (p = apps; *p != NULL; p++) { + if (g_regex_match_simple(*p, prgname, (GRegexCompileFlags)0, + (GRegexMatchFlags)0)) { + result = TRUE; + break; + } + } + g_strfreev(apps); + return result; +} + +static inline bool get_boolean_env(const char *name, bool defval) { + const char *value = getenv(name); + + if (value == nullptr) { + return defval; + } + + if (g_strcmp0(value, "") == 0 || g_strcmp0(value, "0") == 0 || + g_strcmp0(value, "false") == 0 || g_strcmp0(value, "False") == 0 || + g_strcmp0(value, "FALSE") == 0) { + return false; + } + + return true; +} + +constexpr int MAX_CACHED_HANDLED_EVENT = 40; + +constexpr uint64_t purpose_related_capability = + fcitx::FcitxCapabilityFlag_Alpha | fcitx::FcitxCapabilityFlag_Digit | + fcitx::FcitxCapabilityFlag_Number | fcitx::FcitxCapabilityFlag_Dialable | + fcitx::FcitxCapabilityFlag_Url | fcitx::FcitxCapabilityFlag_Email | + fcitx::FcitxCapabilityFlag_Password; + +constexpr uint64_t hints_related_capability = + fcitx::FcitxCapabilityFlag_SpellCheck | + fcitx::FcitxCapabilityFlag_NoSpellCheck | + fcitx::FcitxCapabilityFlag_WordCompletion | + fcitx::FcitxCapabilityFlag_Lowercase | + fcitx::FcitxCapabilityFlag_Uppercase | + fcitx::FcitxCapabilityFlag_UppercaseWords | + fcitx::FcitxCapabilityFlag_UppwercaseSentences | + fcitx::FcitxCapabilityFlag_NoOnScreenKeyboard; + +constexpr uint32_t HandledMask = (1 << 24); +constexpr uint32_t IgnoredMask = (1 << 25); +constexpr unsigned int MAX_CACHED_EVENTS = 30; + } // namespace fcitx::gtk #endif // _GTK3_UTILS_H_ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fcitx5-gtk-5.0.21/gtk4/fcitximcontext.cpp new/fcitx5-gtk-5.0.22/gtk4/fcitximcontext.cpp --- old/fcitx5-gtk-5.0.21/gtk4/fcitximcontext.cpp 2022-11-24 08:28:11.710383200 +0100 +++ new/fcitx5-gtk-5.0.22/gtk4/fcitximcontext.cpp 2023-02-02 21:40:52.698458700 +0100 @@ -36,24 +36,6 @@ using namespace fcitx::gtk; -constexpr int MAX_CACHED_HANDLED_EVENT = 40; - -static const uint64_t purpose_related_capability = - fcitx::FcitxCapabilityFlag_Alpha | fcitx::FcitxCapabilityFlag_Digit | - fcitx::FcitxCapabilityFlag_Number | fcitx::FcitxCapabilityFlag_Dialable | - fcitx::FcitxCapabilityFlag_Url | fcitx::FcitxCapabilityFlag_Email | - fcitx::FcitxCapabilityFlag_Password; - -static const uint64_t hints_related_capability = - fcitx::FcitxCapabilityFlag_SpellCheck | - fcitx::FcitxCapabilityFlag_NoSpellCheck | - fcitx::FcitxCapabilityFlag_WordCompletion | - fcitx::FcitxCapabilityFlag_Lowercase | - fcitx::FcitxCapabilityFlag_Uppercase | - fcitx::FcitxCapabilityFlag_UppercaseWords | - fcitx::FcitxCapabilityFlag_UppwercaseSentences | - fcitx::FcitxCapabilityFlag_NoOnScreenKeyboard; - struct KeyPressCallbackData { KeyPressCallbackData(FcitxIMContext *context, GdkEvent *event) : context_(FCITX_IM_CONTEXT(g_object_ref(context))), @@ -70,22 +52,6 @@ extern "C" { -static bool get_boolean_env(const char *name, bool defval) { - const char *value = getenv(name); - - if (value == nullptr) { - return defval; - } - - if (g_strcmp0(value, "") == 0 || g_strcmp0(value, "0") == 0 || - g_strcmp0(value, "false") == 0 || g_strcmp0(value, "False") == 0 || - g_strcmp0(value, "FALSE") == 0) { - return false; - } - - return true; -} - /* functions prototype */ static void fcitx_im_context_class_init(FcitxIMContextClass *klass, gpointer); static void fcitx_im_context_class_fini(FcitxIMContextClass *klass, gpointer); @@ -110,6 +76,9 @@ PangoAttrList **attrs, int *cursor_pos); +static void fcitx_im_context_commit_string(FcitxIMContext *context, + const char *str); +static void fcitx_im_context_commit_preedit(FcitxIMContext *context); static gboolean _set_cursor_location_internal(FcitxIMContext *fcitxcontext); static gboolean _defer_request_surrounding_text(FcitxIMContext *fcitxcontext); static void _slave_commit_cb(GtkIMContext *slave, char *string, @@ -125,8 +94,6 @@ int offset_from_cursor, guint nchars, FcitxIMContext *context); -static void _fcitx_im_context_commit_string(FcitxIMContext *context, - const char *str); static void _fcitx_im_context_commit_string_cb(FcitxGClient *client, char *str, void *user_data); static void _fcitx_im_context_forward_key_cb(FcitxGClient *client, guint keyval, @@ -141,6 +108,8 @@ GPtrArray *array, int cursor_pos, void *user_data); +static void _fcitx_im_context_notify_focus_out_cb(FcitxGClient *client, + void *user_data); static void _fcitx_im_context_process_key_cb(GObject *source_object, GAsyncResult *res, gpointer user_data); @@ -219,22 +188,6 @@ return FCITX_IM_CONTEXT(obj); } -static gboolean check_app_name(const char *pattern) { - bool result = FALSE; - const char *prgname = g_get_prgname(); - char **p; - char **apps = g_strsplit(pattern, ",", 0); - for (p = apps; *p != NULL; p++) { - if (g_regex_match_simple(*p, prgname, (GRegexCompileFlags)0, - (GRegexMatchFlags)0)) { - result = TRUE; - break; - } - } - g_strfreev(apps); - return result; -} - /// static void fcitx_im_context_class_init(FcitxIMContextClass *klass, gpointer) { GtkIMContextClass *im_context_class = GTK_IM_CONTEXT_CLASS(klass); @@ -310,6 +263,7 @@ context->last_anchor_pos = -1; context->last_cursor_pos = -1; context->preedit_string = NULL; + context->commit_preedit_string = NULL; context->attrlist = NULL; context->last_updated_capability = (guint64)fcitx::FcitxCapabilityFlag_SurroundingText; @@ -403,6 +357,9 @@ g_signal_connect(context->client, "update-formatted-preedit", G_CALLBACK(_fcitx_im_context_update_formatted_preedit_cb), context); + g_signal_connect(context->client, "notify-focus-out", + G_CALLBACK(_fcitx_im_context_notify_focus_out_cb), + context); context->xkbComposeState = xkbComposeTable @@ -431,6 +388,7 @@ g_clear_object(&context->client); g_clear_pointer(&context->preedit_string, g_free); + g_clear_pointer(&context->commit_preedit_string, g_free); g_clear_pointer(&context->surrounding_text, g_free); g_clear_pointer(&context->attrlist, pango_attr_list_unref); @@ -586,101 +544,116 @@ context->attrlist = pango_attr_list_new(); GString *gstr = g_string_new(NULL); + GString *commit_gstr = g_string_new(NULL); - unsigned int i = 0; - for (i = 0; i < array->len; i++) { - size_t bytelen = strlen(gstr->str); - FcitxGPreeditItem *preedit = - (FcitxGPreeditItem *)g_ptr_array_index(array, i); - const char *s = preedit->string; - int type = preedit->type; - - PangoAttribute *pango_attr = NULL; - if ((type & (guint32)fcitx::FcitxTextFormatFlag_Underline)) { - pango_attr = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE); - pango_attr->start_index = bytelen; - pango_attr->end_index = bytelen + strlen(s); - pango_attr_list_insert(context->attrlist, pango_attr); - } - if ((type & (guint32)fcitx::FcitxTextFormatFlag_Strike)) { - pango_attr = pango_attr_strikethrough_new(true); - pango_attr->start_index = bytelen; - pango_attr->end_index = bytelen + strlen(s); - pango_attr_list_insert(context->attrlist, pango_attr); - } - if ((type & (guint32)fcitx::FcitxTextFormatFlag_Bold)) { - pango_attr = pango_attr_weight_new(PANGO_WEIGHT_BOLD); - pango_attr->start_index = bytelen; - pango_attr->end_index = bytelen + strlen(s); - pango_attr_list_insert(context->attrlist, pango_attr); - } - if ((type & (guint32)fcitx::FcitxTextFormatFlag_Italic)) { - pango_attr = pango_attr_style_new(PANGO_STYLE_ITALIC); - pango_attr->start_index = bytelen; - pango_attr->end_index = bytelen + strlen(s); - pango_attr_list_insert(context->attrlist, pango_attr); - } + if (array) { + for (unsigned int i = 0; i < array->len; i++) { + size_t bytelen = strlen(gstr->str); + FcitxGPreeditItem *preedit = + (FcitxGPreeditItem *)g_ptr_array_index(array, i); + const char *s = preedit->string; + int type = preedit->type; + + PangoAttribute *pango_attr = NULL; + if ((type & (guint32)fcitx::FcitxTextFormatFlag_Underline)) { + pango_attr = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE); + pango_attr->start_index = bytelen; + pango_attr->end_index = bytelen + strlen(s); + pango_attr_list_insert(context->attrlist, pango_attr); + } + if ((type & (guint32)fcitx::FcitxTextFormatFlag_Strike)) { + pango_attr = pango_attr_strikethrough_new(true); + pango_attr->start_index = bytelen; + pango_attr->end_index = bytelen + strlen(s); + pango_attr_list_insert(context->attrlist, pango_attr); + } + if ((type & (guint32)fcitx::FcitxTextFormatFlag_Bold)) { + pango_attr = pango_attr_weight_new(PANGO_WEIGHT_BOLD); + pango_attr->start_index = bytelen; + pango_attr->end_index = bytelen + strlen(s); + pango_attr_list_insert(context->attrlist, pango_attr); + } + if ((type & (guint32)fcitx::FcitxTextFormatFlag_Italic)) { + pango_attr = pango_attr_style_new(PANGO_STYLE_ITALIC); + pango_attr->start_index = bytelen; + pango_attr->end_index = bytelen + strlen(s); + pango_attr_list_insert(context->attrlist, pango_attr); + } - if (type & (guint32)fcitx::FcitxTextFormatFlag_HighLight) { - gboolean hasColor = false; - guint fg_red = 0, fg_green = 0, fg_blue = 0, bg_red = 0, - bg_green = 0, bg_blue = 0; - - if (context->client_widget) { - hasColor = true; - GtkStyleContext *styleContext = - gtk_widget_get_style_context(context->client_widget); - GdkRGBA fg_rgba, bg_rgba; - hasColor = - gtk_style_context_lookup_color( - styleContext, "theme_selected_bg_color", &bg_rgba) && - gtk_style_context_lookup_color( - styleContext, "theme_selected_fg_color", &fg_rgba); - - if (!(fg_rgba.red == bg_rgba.red && - fg_rgba.green == bg_rgba.green && - fg_rgba.blue == bg_rgba.blue)) { - hasColor = false; + if (type & (guint32)fcitx::FcitxTextFormatFlag_HighLight) { + gboolean hasColor = false; + guint fg_red = 0, fg_green = 0, fg_blue = 0, bg_red = 0, + bg_green = 0, bg_blue = 0; + + if (context->client_widget) { + hasColor = true; + GtkStyleContext *styleContext = + gtk_widget_get_style_context(context->client_widget); + GdkRGBA fg_rgba, bg_rgba; + hasColor = + gtk_style_context_lookup_color( + styleContext, "theme_selected_bg_color", + &bg_rgba) && + gtk_style_context_lookup_color( + styleContext, "theme_selected_fg_color", &fg_rgba); + + if (!(fg_rgba.red == bg_rgba.red && + fg_rgba.green == bg_rgba.green && + fg_rgba.blue == bg_rgba.blue)) { + hasColor = false; + } + if (hasColor) { + fg_red = CLAMP((gint)(fg_rgba.red * 65535), 0, 65535); + fg_green = + CLAMP((gint)(fg_rgba.green * 65535), 0, 65535); + fg_blue = CLAMP((gint)(fg_rgba.blue * 65535), 0, 65535); + bg_red = CLAMP((gint)(bg_rgba.red * 65535), 0, 65535); + bg_green = + CLAMP((gint)(bg_rgba.green * 65535), 0, 65535); + bg_blue = CLAMP((gint)(bg_rgba.blue * 65535), 0, 65535); + } } - if (hasColor) { - fg_red = CLAMP((gint)(fg_rgba.red * 65535), 0, 65535); - fg_green = CLAMP((gint)(fg_rgba.green * 65535), 0, 65535); - fg_blue = CLAMP((gint)(fg_rgba.blue * 65535), 0, 65535); - bg_red = CLAMP((gint)(bg_rgba.red * 65535), 0, 65535); - bg_green = CLAMP((gint)(bg_rgba.green * 65535), 0, 65535); - bg_blue = CLAMP((gint)(bg_rgba.blue * 65535), 0, 65535); + + if (!hasColor) { + fg_red = 0xffff; + fg_green = 0xffff; + fg_blue = 0xffff; + bg_red = 0x43ff; + bg_green = 0xacff; + bg_blue = 0xe8ff; } - } - if (!hasColor) { - fg_red = 0xffff; - fg_green = 0xffff; - fg_blue = 0xffff; - bg_red = 0x43ff; - bg_green = 0xacff; - bg_blue = 0xe8ff; + pango_attr = + pango_attr_foreground_new(fg_red, fg_green, fg_blue); + pango_attr->start_index = bytelen; + pango_attr->end_index = bytelen + strlen(s); + pango_attr_list_insert(context->attrlist, pango_attr); + pango_attr = + pango_attr_background_new(bg_red, bg_green, bg_blue); + pango_attr->start_index = bytelen; + pango_attr->end_index = bytelen + strlen(s); + pango_attr_list_insert(context->attrlist, pango_attr); + } + gstr = g_string_append(gstr, s); + if ((type & (guint32)fcitx::FcitxTextFormatFlag_DontCommit) == 0) { + commit_gstr = g_string_append(commit_gstr, s); } - - pango_attr = pango_attr_foreground_new(fg_red, fg_green, fg_blue); - pango_attr->start_index = bytelen; - pango_attr->end_index = bytelen + strlen(s); - pango_attr_list_insert(context->attrlist, pango_attr); - pango_attr = pango_attr_background_new(bg_red, bg_green, bg_blue); - pango_attr->start_index = bytelen; - pango_attr->end_index = bytelen + strlen(s); - pango_attr_list_insert(context->attrlist, pango_attr); } - gstr = g_string_append(gstr, s); } char *str = g_string_free(gstr, FALSE); context->preedit_string = str; + context->commit_preedit_string = g_string_free(commit_gstr, FALSE); context->cursor_pos = g_utf8_pointer_to_offset(str, str + cursor_pos); if (context->preedit_string != NULL && context->preedit_string[0] == 0) { g_clear_pointer(&context->preedit_string, g_free); } + if (context->commit_preedit_string != NULL && + context->commit_preedit_string[0] == 0) { + g_clear_pointer(&context->commit_preedit_string, g_free); + } } static void _fcitx_im_context_update_formatted_preedit_cb(FcitxGClient *, @@ -702,6 +675,7 @@ g_clear_pointer(&context->preedit_string, g_free); } + g_clear_pointer(&context->commit_preedit_string, g_free); g_clear_pointer(&context->attrlist, pango_attr_list_unref); if (context->use_preedit) { @@ -730,6 +704,16 @@ } } +static void _fcitx_im_context_notify_focus_out_cb(FcitxGClient *, + void *user_data) { + FcitxIMContext *context = FCITX_IM_CONTEXT(user_data); + if (!context->has_focus) { + return; + } + + fcitx_im_context_commit_preedit(context); +} + /// static void fcitx_im_context_focus_in(GtkIMContext *context) { FcitxIMContext *fcitxcontext = FCITX_IM_CONTEXT(context); @@ -780,6 +764,31 @@ return; } +static void fcitx_im_context_commit_string(FcitxIMContext *context, + const gchar *str) { + context->ignore_reset = TRUE; + g_signal_emit(context, _signal_commit_id, 0, str); + context->ignore_reset = FALSE; + + // Better request surrounding after commit. + g_idle_add_full(G_PRIORITY_DEFAULT_IDLE, + (GSourceFunc)_defer_request_surrounding_text, + g_object_ref(context), (GDestroyNotify)g_object_unref); +} + +static void fcitx_im_context_commit_preedit(FcitxIMContext *context) { + if (!context->has_focus) { + return; + } + + if (context->commit_preedit_string) { + fcitx_im_context_commit_string(context, context->commit_preedit_string); + } + + _fcitx_im_context_update_formatted_preedit_cb(context->client, nullptr, 0, + context); +} + static void fcitx_im_context_focus_out(GtkIMContext *context) { FcitxIMContext *fcitxcontext = FCITX_IM_CONTEXT(context); @@ -791,6 +800,8 @@ (gpointer *)&_focus_im_context); _focus_im_context = NULL; + fcitx_im_context_commit_preedit(fcitxcontext); + fcitxcontext->has_focus = false; fcitxcontext->last_key_code = 0; fcitxcontext->last_is_release = false; @@ -799,13 +810,6 @@ fcitx_g_client_focus_out(fcitxcontext->client); } - fcitxcontext->cursor_pos = 0; - if (fcitxcontext->preedit_string != NULL) { - g_clear_pointer(&fcitxcontext->preedit_string, g_free); - g_signal_emit(fcitxcontext, _signal_preedit_changed_id, 0); - g_signal_emit(fcitxcontext, _signal_preedit_end_id, 0); - } - gtk_im_context_focus_out(fcitxcontext->slave); return; @@ -1078,6 +1082,7 @@ } } while (0); flags |= (guint64)fcitx::FcitxCapabilityFlag_ReportKeyRepeat; + flags |= (guint64)fcitx::FcitxCapabilityFlag_ClientUnfocusCommit; // always run this code against all gtk version // seems visibility != PASSWORD hint @@ -1107,6 +1112,7 @@ if (fcitxcontext->ignore_reset) { return; } + fcitx_im_context_commit_preedit(fcitxcontext); if (fcitx_g_client_is_valid(fcitxcontext->client)) { fcitx_g_client_reset(fcitxcontext->client); @@ -1209,21 +1215,10 @@ return return_value; } -void _fcitx_im_context_commit_string(FcitxIMContext *context, const char *str) { - context->ignore_reset = TRUE; - g_signal_emit(context, _signal_commit_id, 0, str); - context->ignore_reset = FALSE; -} - void _fcitx_im_context_commit_string_cb(FcitxGClient *, char *str, void *user_data) { FcitxIMContext *context = FCITX_IM_CONTEXT(user_data); - _fcitx_im_context_commit_string(context, str); - - // Better request surrounding after commit. - g_idle_add_full(G_PRIORITY_DEFAULT_IDLE, - (GSourceFunc)_defer_request_surrounding_text, - g_object_ref(context), (GDestroyNotify)g_object_unref); + fcitx_im_context_commit_string(context, str); } void _fcitx_im_context_forward_key_cb(FcitxGClient *, guint, guint, gboolean, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fcitx5-gtk-5.0.21/gtk4/fcitximcontextprivate.h new/fcitx5-gtk-5.0.22/gtk4/fcitximcontextprivate.h --- old/fcitx5-gtk-5.0.21/gtk4/fcitximcontextprivate.h 2022-11-12 18:12:58.154401800 +0100 +++ new/fcitx5-gtk-5.0.22/gtk4/fcitximcontextprivate.h 2022-12-16 19:53:05.867176300 +0100 @@ -26,6 +26,7 @@ gboolean is_inpreedit; gboolean is_wayland; char *preedit_string; + char *commit_preedit_string; char *surrounding_text; int cursor_pos; guint64 capability_from_toolkit;