📄 gtkimcontextxim.c
字号:
/* GTK - The GIMP Toolkit * Copyright (C) 2000 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, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */#include <config.h>#include "locale.h"#include <string.h>#include <stdlib.h>#include "gtk/gtkintl.h"#include "gtk/gtklabel.h"#include "gtk/gtksignal.h"#include "gtk/gtkwindow.h"#include "gtkimcontextxim.h"typedef struct _StatusWindow StatusWindow;typedef struct _GtkXIMInfo GtkXIMInfo;struct _GtkIMContextXIM{ GtkIMContext object; GtkXIMInfo *im_info; gchar *locale; gchar *mb_charset; GdkWindow *client_window; GtkWidget *client_widget; /* The status window for this input context; we claim the * status window when we are focused and have created an XIC */ StatusWindow *status_window; gint preedit_size; gint preedit_length; gunichar *preedit_chars; XIMFeedback *feedbacks; gint preedit_cursor; XIMCallback preedit_start_callback; XIMCallback preedit_done_callback; XIMCallback preedit_draw_callback; XIMCallback preedit_caret_callback; XIMCallback status_start_callback; XIMCallback status_done_callback; XIMCallback status_draw_callback; XIMCallback string_conversion_callback; XIC ic; guint filter_key_release : 1; guint use_preedit : 1; guint finalizing : 1; guint in_toplevel : 1; guint has_focus : 1;};struct _GtkXIMInfo{ GdkScreen *screen; XIM im; char *locale; XIMStyle preedit_style_setting; XIMStyle status_style_setting; XIMStyle style; GtkSettings *settings; gulong status_set; gulong preedit_set; XIMStyles *xim_styles; GSList *ics; guint reconnecting :1; guint supports_string_conversion;};/* A context status window; these are kept in the status_windows list. */struct _StatusWindow{ GtkWidget *window; /* Toplevel window to which the status window corresponds */ GtkWidget *toplevel; /* Currently focused GtkIMContextXIM for the toplevel, if any */ GtkIMContextXIM *context;};static void gtk_im_context_xim_class_init (GtkIMContextXIMClass *class);static void gtk_im_context_xim_init (GtkIMContextXIM *im_context_xim);static void gtk_im_context_xim_finalize (GObject *obj);static void gtk_im_context_xim_set_client_window (GtkIMContext *context, GdkWindow *client_window);static gboolean gtk_im_context_xim_filter_keypress (GtkIMContext *context, GdkEventKey *key);static void gtk_im_context_xim_reset (GtkIMContext *context);static void gtk_im_context_xim_focus_in (GtkIMContext *context);static void gtk_im_context_xim_focus_out (GtkIMContext *context);static void gtk_im_context_xim_set_cursor_location (GtkIMContext *context, GdkRectangle *area);static void gtk_im_context_xim_set_use_preedit (GtkIMContext *context, gboolean use_preedit);static void gtk_im_context_xim_get_preedit_string (GtkIMContext *context, gchar **str, PangoAttrList **attrs, gint *cursor_pos);static void reinitialize_ic (GtkIMContextXIM *context_xim);static void set_ic_client_window (GtkIMContextXIM *context_xim, GdkWindow *client_window);static void setup_styles (GtkXIMInfo *info);static void update_client_widget (GtkIMContextXIM *context_xim);static void update_status_window (GtkIMContextXIM *context_xim);static StatusWindow *status_window_get (GtkWidget *toplevel);static void status_window_free (StatusWindow *status_window);static void status_window_set_text (StatusWindow *status_window, const gchar *text);static void xim_destroy_callback (XIM xim, XPointer client_data, XPointer call_data);static XIC gtk_im_context_xim_get_ic (GtkIMContextXIM *context_xim);static GObjectClass *parent_class;GType gtk_type_im_context_xim = 0;GSList *open_ims = NULL;/* List of status windows for different toplevels */static GSList *status_windows = NULL;voidgtk_im_context_xim_register_type (GTypeModule *type_module){ static const GTypeInfo im_context_xim_info = { sizeof (GtkIMContextXIMClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) gtk_im_context_xim_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof (GtkIMContextXIM), 0, (GInstanceInitFunc) gtk_im_context_xim_init, }; gtk_type_im_context_xim = g_type_module_register_type (type_module, GTK_TYPE_IM_CONTEXT, "GtkIMContextXIM", &im_context_xim_info, 0);}#define PREEDIT_MASK (XIMPreeditCallbacks | XIMPreeditPosition | \ XIMPreeditArea | XIMPreeditNothing | XIMPreeditNone)#define STATUS_MASK (XIMStatusCallbacks | XIMStatusArea | \ XIMStatusNothing | XIMStatusNone)#define ALLOWED_MASK (XIMPreeditCallbacks | XIMPreeditNothing | XIMPreeditNone | \ XIMStatusCallbacks | XIMStatusNothing | XIMStatusNone)static XIMStyle choose_better_style (XIMStyle style1, XIMStyle style2) { XIMStyle s1, s2, u; if (style1 == 0) return style2; if (style2 == 0) return style1; if ((style1 & (PREEDIT_MASK | STATUS_MASK)) == (style2 & (PREEDIT_MASK | STATUS_MASK))) return style1; s1 = style1 & PREEDIT_MASK; s2 = style2 & PREEDIT_MASK; u = s1 | s2; if (s1 != s2) { if (u & XIMPreeditCallbacks) return (s1 == XIMPreeditCallbacks) ? style1 : style2; else if (u & XIMPreeditPosition) return (s1 == XIMPreeditPosition) ? style1 :style2; else if (u & XIMPreeditArea) return (s1 == XIMPreeditArea) ? style1 : style2; else if (u & XIMPreeditNothing) return (s1 == XIMPreeditNothing) ? style1 : style2; else if (u & XIMPreeditNone) return (s1 == XIMPreeditNone) ? style1 : style2; } else { s1 = style1 & STATUS_MASK; s2 = style2 & STATUS_MASK; u = s1 | s2; if (u & XIMStatusCallbacks) return (s1 == XIMStatusCallbacks) ? style1 : style2; else if (u & XIMStatusArea) return (s1 == XIMStatusArea) ? style1 : style2; else if (u & XIMStatusNothing) return (s1 == XIMStatusNothing) ? style1 : style2; else if (u & XIMStatusNone) return (s1 == XIMStatusNone) ? style1 : style2; } return 0; /* Get rid of stupid warning */}static voidreinitialize_all_ics (GtkXIMInfo *info){ GSList *tmp_list; for (tmp_list = info->ics; tmp_list; tmp_list = tmp_list->next) reinitialize_ic (tmp_list->data);}static voidstatus_style_change (GtkXIMInfo *info){ GtkIMStatusStyle status_style; g_object_get (info->settings, "gtk-im-status-style", &status_style, NULL); if (status_style == GTK_IM_STATUS_CALLBACK) info->status_style_setting = XIMStatusCallbacks; else if (status_style == GTK_IM_STATUS_NOTHING) info->status_style_setting = XIMStatusNothing; else if (status_style == GTK_IM_STATUS_NONE) info->status_style_setting = XIMStatusNone; else return; setup_styles (info); reinitialize_all_ics (info);}static voidpreedit_style_change (GtkXIMInfo *info){ GtkIMPreeditStyle preedit_style; g_object_get (info->settings, "gtk-im-preedit-style", &preedit_style, NULL); if (preedit_style == GTK_IM_PREEDIT_CALLBACK) info->preedit_style_setting = XIMPreeditCallbacks; else if (preedit_style == GTK_IM_PREEDIT_NOTHING) info->preedit_style_setting = XIMPreeditNothing; else if (preedit_style == GTK_IM_PREEDIT_NONE) info->preedit_style_setting = XIMPreeditNone; else return; setup_styles (info); reinitialize_all_ics (info);}static voidsetup_styles (GtkXIMInfo *info){ int i; unsigned long settings_preference; XIMStyles *xim_styles = info->xim_styles; settings_preference = info->status_style_setting|info->preedit_style_setting; info->style = 0; if (xim_styles) { for (i = 0; i < xim_styles->count_styles; i++) if ((xim_styles->supported_styles[i] & ALLOWED_MASK) == xim_styles->supported_styles[i]) { if (settings_preference == xim_styles->supported_styles[i]) { info->style = settings_preference; break; } info->style = choose_better_style (info->style, xim_styles->supported_styles[i]); } } if (info->style == 0) info->style = XIMPreeditNothing | XIMStatusNothing;}static voidsetup_im (GtkXIMInfo *info){ XIMValuesList *ic_values = NULL; XIMCallback im_destroy_callback; if (info->im == NULL) return; im_destroy_callback.client_data = (XPointer)info; im_destroy_callback.callback = (XIMProc)xim_destroy_callback; XSetIMValues (info->im, XNDestroyCallback, &im_destroy_callback, NULL); XGetIMValues (info->im, XNQueryInputStyle, &info->xim_styles, XNQueryICValuesList, &ic_values, NULL); info->settings = gtk_settings_get_for_screen (info->screen); if (!g_object_class_find_property (G_OBJECT_GET_CLASS (info->settings), "gtk-im-preedit-style")) gtk_settings_install_property (g_param_spec_enum ("gtk-im-preedit-style", P_("IM Preedit style"), P_("How to draw the input method preedit string"), GTK_TYPE_IM_PREEDIT_STYLE, GTK_IM_PREEDIT_CALLBACK, G_PARAM_READWRITE)); if (!g_object_class_find_property (G_OBJECT_GET_CLASS (info->settings), "gtk-im-status-style")) gtk_settings_install_property (g_param_spec_enum ("gtk-im-status-style", P_("IM Status style"), P_("How to draw the input method statusbar"), GTK_TYPE_IM_STATUS_STYLE, GTK_IM_STATUS_CALLBACK, G_PARAM_READWRITE)); info->status_set = g_signal_connect_swapped (info->settings, "notify::gtk-im-status-style", G_CALLBACK (status_style_change), info); info->preedit_set = g_signal_connect_swapped (info->settings, "notify::gtk-im-preedit-style", G_CALLBACK (preedit_style_change), info); info->supports_string_conversion = FALSE; if (ic_values) { int i; for (i = 0; i < ic_values->count_values; i++) if (strcmp (ic_values->supported_values[i], XNStringConversionCallback) == 0) { info->supports_string_conversion = TRUE; break; }#if 0 for (i = 0; i < ic_values->count_values; i++) g_print ("%s\n", ic_values->supported_values[i]); for (i = 0; i < xim_styles->count_styles; i++) g_print ("%#x\n", xim_styles->supported_styles[i]);#endif XFree (ic_values); } status_style_change (info); preedit_style_change (info);}static voidxim_info_display_closed (GdkDisplay *display, gboolean is_error, GtkXIMInfo *info){ GSList *ics, *tmp_list; open_ims = g_slist_remove (open_ims, info); ics = info->ics; info->ics = NULL; for (tmp_list = ics; tmp_list; tmp_list = tmp_list->next) set_ic_client_window (tmp_list->data, NULL); g_slist_free (ics); g_signal_handler_disconnect (info->settings, info->status_set); g_signal_handler_disconnect (info->settings, info->preedit_set); XFree (info->xim_styles->supported_styles); XFree (info->xim_styles); g_free (info->locale); if (info->im) XCloseIM (info->im); g_free (info);}static voidxim_instantiate_callback (Display *display, XPointer client_data, XPointer call_data){ GtkXIMInfo *info = (GtkXIMInfo*)client_data; XIM im = NULL; im = XOpenIM (display, NULL, NULL, NULL); if (!im) return; info->im = im; setup_im (info); XUnregisterIMInstantiateCallback (display, NULL, NULL, NULL, xim_instantiate_callback, (XPointer)info); info->reconnecting = FALSE;}/* initialize info->im */static voidxim_info_try_im (GtkXIMInfo *info){ GdkScreen *screen = info->screen; GdkDisplay *display = gdk_screen_get_display (screen); g_assert (info->im == NULL); if (info->reconnecting) return; if (XSupportsLocale ()) { if (!XSetLocaleModifiers ("")) g_warning ("Unable to set locale modifiers with XSetLocaleModifiers()"); info->im = XOpenIM (GDK_DISPLAY_XDISPLAY (display), NULL, NULL, NULL); if (!info->im) { XRegisterIMInstantiateCallback (GDK_DISPLAY_XDISPLAY(display), NULL, NULL, NULL, xim_instantiate_callback, (XPointer)info); info->reconnecting = TRUE; return; } setup_im (info); g_signal_connect (display, "closed", G_CALLBACK (xim_info_display_closed), info); }}static voidxim_destroy_callback (XIM xim,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -