📄 gtkimcontextxim.c
字号:
XPointer client_data, XPointer call_data){ GtkXIMInfo *info = (GtkXIMInfo*)client_data; info->im = NULL; g_signal_handler_disconnect (info->settings, info->status_set); g_signal_handler_disconnect (info->settings, info->preedit_set); reinitialize_all_ics (info); xim_info_try_im (info); return;} static GtkXIMInfo *get_im (GdkWindow *client_window, const char *locale){ GSList *tmp_list; GtkXIMInfo *info; GdkScreen *screen = gdk_drawable_get_screen (client_window); info = NULL; tmp_list = open_ims; while (tmp_list) { GtkXIMInfo *tmp_info = tmp_list->data; if (tmp_info->screen == screen && strcmp (tmp_info->locale, locale) == 0) { if (tmp_info->im) { return tmp_info; } else { tmp_info = tmp_info; break; } } tmp_list = tmp_list->next; } if (info == NULL) { info = g_new (GtkXIMInfo, 1); open_ims = g_slist_prepend (open_ims, info); info->screen = screen; info->locale = g_strdup (locale); info->xim_styles = NULL; info->preedit_style_setting = 0; info->status_style_setting = 0; info->settings = NULL; info->preedit_set = 0; info->status_set = 0; info->ics = NULL; info->reconnecting = FALSE; info->im = NULL; } xim_info_try_im (info); return info;}static voidgtk_im_context_xim_class_init (GtkIMContextXIMClass *class){ GtkIMContextClass *im_context_class = GTK_IM_CONTEXT_CLASS (class); GObjectClass *gobject_class = G_OBJECT_CLASS (class); parent_class = g_type_class_peek_parent (class); im_context_class->set_client_window = gtk_im_context_xim_set_client_window; im_context_class->filter_keypress = gtk_im_context_xim_filter_keypress; im_context_class->reset = gtk_im_context_xim_reset; im_context_class->get_preedit_string = gtk_im_context_xim_get_preedit_string; im_context_class->focus_in = gtk_im_context_xim_focus_in; im_context_class->focus_out = gtk_im_context_xim_focus_out; im_context_class->set_cursor_location = gtk_im_context_xim_set_cursor_location; im_context_class->set_use_preedit = gtk_im_context_xim_set_use_preedit; gobject_class->finalize = gtk_im_context_xim_finalize;}static voidgtk_im_context_xim_init (GtkIMContextXIM *im_context_xim){ im_context_xim->use_preedit = TRUE; im_context_xim->filter_key_release = FALSE; im_context_xim->finalizing = FALSE; im_context_xim->has_focus = FALSE; im_context_xim->in_toplevel = FALSE;}static voidgtk_im_context_xim_finalize (GObject *obj){ GtkIMContextXIM *context_xim = GTK_IM_CONTEXT_XIM (obj); context_xim->finalizing = TRUE; if (context_xim->im_info && !context_xim->im_info->ics->next) { GdkDisplay *display; display = gdk_screen_get_display (context_xim->im_info->screen); if (context_xim->im_info->reconnecting) XUnregisterIMInstantiateCallback (GDK_DISPLAY_XDISPLAY (display), NULL, NULL, NULL, xim_instantiate_callback, (XPointer)context_xim->im_info); else { XIMCallback im_destroy_callback; im_destroy_callback.client_data = NULL; im_destroy_callback.callback = NULL; XSetIMValues (context_xim->im_info->im, XNDestroyCallback, &im_destroy_callback, NULL); } } set_ic_client_window (context_xim, NULL); g_free (context_xim->locale); g_free (context_xim->mb_charset); G_OBJECT_CLASS (parent_class)->finalize (obj);}static voidreinitialize_ic (GtkIMContextXIM *context_xim){ if (context_xim->ic) { XDestroyIC (context_xim->ic); context_xim->ic = NULL; update_status_window (context_xim); if (context_xim->preedit_length) { context_xim->preedit_length = 0; if (!context_xim->finalizing) g_signal_emit_by_name (context_xim, "preedit_changed"); } } /* reset filter_key_release flag, otherwise keystrokes will be doubled until reconnecting to XIM. */ context_xim->filter_key_release = FALSE;}static voidset_ic_client_window (GtkIMContextXIM *context_xim, GdkWindow *client_window){ reinitialize_ic (context_xim); if (context_xim->client_window) { context_xim->im_info->ics = g_slist_remove (context_xim->im_info->ics, context_xim); context_xim->im_info = NULL; } context_xim->client_window = client_window; if (context_xim->client_window) { context_xim->im_info = get_im (context_xim->client_window, context_xim->locale); context_xim->im_info->ics = g_slist_prepend (context_xim->im_info->ics, context_xim); } update_client_widget (context_xim);}static voidgtk_im_context_xim_set_client_window (GtkIMContext *context, GdkWindow *client_window){ GtkIMContextXIM *context_xim = GTK_IM_CONTEXT_XIM (context); set_ic_client_window (context_xim, client_window);}GtkIMContext *gtk_im_context_xim_new (void){ GtkIMContextXIM *result; const gchar *charset; result = g_object_new (GTK_TYPE_IM_CONTEXT_XIM, NULL); result->locale = g_strdup (setlocale (LC_CTYPE, NULL)); g_get_charset (&charset); result->mb_charset = g_strdup (charset); return GTK_IM_CONTEXT (result);}static char *mb_to_utf8 (GtkIMContextXIM *context_xim, const char *str){ GError *error = NULL; gchar *result; if (strcmp (context_xim->mb_charset, "UTF-8") == 0) result = g_strdup (str); else { result = g_convert (str, -1, "UTF-8", context_xim->mb_charset, NULL, NULL, &error); if (!result) { g_warning ("Error converting text from IM to UTF-8: %s\n", error->message); g_error_free (error); } } return result;}static gbooleangtk_im_context_xim_filter_keypress (GtkIMContext *context, GdkEventKey *event){ GtkIMContextXIM *context_xim = GTK_IM_CONTEXT_XIM (context); XIC ic = gtk_im_context_xim_get_ic (context_xim); gchar static_buffer[256]; gchar *buffer = static_buffer; gint buffer_size = sizeof(static_buffer) - 1; gint num_bytes = 0; KeySym keysym; Status status; gboolean result = FALSE; GdkWindow *root_window = gdk_screen_get_root_window (gdk_drawable_get_screen (event->window)); XKeyPressedEvent xevent; if (event->type == GDK_KEY_RELEASE && !context_xim->filter_key_release) return FALSE; xevent.type = (event->type == GDK_KEY_PRESS) ? KeyPress : KeyRelease; xevent.serial = 0; /* hope it doesn't matter */ xevent.send_event = event->send_event; xevent.display = GDK_DRAWABLE_XDISPLAY (event->window); xevent.window = GDK_DRAWABLE_XID (event->window); xevent.root = GDK_DRAWABLE_XID (root_window); xevent.subwindow = xevent.window; xevent.time = event->time; xevent.x = xevent.x_root = 0; xevent.y = xevent.y_root = 0; xevent.state = event->state; xevent.keycode = event->hardware_keycode; xevent.same_screen = True; if (XFilterEvent ((XEvent *)&xevent, GDK_DRAWABLE_XID (context_xim->client_window))) return TRUE; again: if (ic) num_bytes = XmbLookupString (ic, &xevent, buffer, buffer_size, &keysym, &status); else { num_bytes = XLookupString (&xevent, buffer, buffer_size, &keysym, NULL); status = XLookupBoth; } if (status == XBufferOverflow) { buffer_size = num_bytes; if (buffer != static_buffer) g_free (buffer); buffer = g_malloc (num_bytes + 1); goto again; } /* I don't know how we should properly handle XLookupKeysym or XLookupBoth * here ... do input methods actually change the keysym? we can't really * feed it back to accelerator processing at this point... */ if (status == XLookupChars || status == XLookupBoth) { char *result_utf8; buffer[num_bytes] = '\0'; result_utf8 = mb_to_utf8 (context_xim, buffer); if (result_utf8) { if ((guchar)result_utf8[0] >= 0x20 && result_utf8[0] != 0x7f) /* Some IM have a nasty habit of converting * control characters into strings */ { g_signal_emit_by_name (context, "commit", result_utf8); result = TRUE; } g_free (result_utf8); } } if (buffer != static_buffer) g_free (buffer); return result;}static voidgtk_im_context_xim_focus_in (GtkIMContext *context){ GtkIMContextXIM *context_xim = GTK_IM_CONTEXT_XIM (context); if (!context_xim->has_focus) { XIC ic = gtk_im_context_xim_get_ic (context_xim); context_xim->has_focus = TRUE; update_status_window (context_xim); if (ic) XSetICFocus (ic); } return;}static voidgtk_im_context_xim_focus_out (GtkIMContext *context){ GtkIMContextXIM *context_xim = GTK_IM_CONTEXT_XIM (context); if (context_xim->has_focus) { XIC ic = gtk_im_context_xim_get_ic (context_xim); context_xim->has_focus = FALSE; update_status_window (context_xim); if (ic) XUnsetICFocus (ic); } return;}static voidgtk_im_context_xim_set_cursor_location (GtkIMContext *context, GdkRectangle *area){ GtkIMContextXIM *context_xim = GTK_IM_CONTEXT_XIM (context); XIC ic = gtk_im_context_xim_get_ic (context_xim); XVaNestedList preedit_attr; XPoint spot; if (!ic) return; spot.x = area->x; spot.y = area->y; preedit_attr = XVaCreateNestedList (0, XNSpotLocation, &spot, NULL); XSetICValues (ic, XNPreeditAttributes, preedit_attr, NULL); XFree(preedit_attr); return;}static voidgtk_im_context_xim_set_use_preedit (GtkIMContext *context, gboolean use_preedit){ GtkIMContextXIM *context_xim = GTK_IM_CONTEXT_XIM (context); use_preedit = use_preedit != FALSE; if (context_xim->use_preedit != use_preedit) { context_xim->use_preedit = use_preedit; reinitialize_ic (context_xim); } return;}static voidgtk_im_context_xim_reset (GtkIMContext *context){ GtkIMContextXIM *context_xim = GTK_IM_CONTEXT_XIM (context); XIC ic = gtk_im_context_xim_get_ic (context_xim); gchar *result; /* restore conversion state after resetting ic later */ XIMPreeditState preedit_state = XIMPreeditUnKnown; XVaNestedList preedit_attr; gboolean have_preedit_state = FALSE; if (!ic) return; if (context_xim->preedit_length == 0) return; preedit_attr = XVaCreateNestedList(0, XNPreeditState, &preedit_state, NULL); if (!XGetICValues(ic, XNPreeditAttributes, preedit_attr, NULL)) have_preedit_state = TRUE; XFree(preedit_attr); result = XmbResetIC (ic); preedit_attr = XVaCreateNestedList(0, XNPreeditState, preedit_state, NULL); if (have_preedit_state) XSetICValues(ic, XNPreeditAttributes, preedit_attr, NULL); XFree(preedit_attr); if (result) { char *result_utf8 = mb_to_utf8 (context_xim, result); if (result_utf8) { g_signal_emit_by_name (context, "commit", result_utf8); g_free (result_utf8); } } if (context_xim->preedit_length) { context_xim->preedit_length = 0; g_signal_emit_by_name (context, "preedit_changed"); } XFree (result);}/* Mask of feedback bits that we render */#define FEEDBACK_MASK (XIMReverse | XIMUnderline)static voidadd_feedback_attr (PangoAttrList *attrs, const gchar *str, XIMFeedback feedback, gint start_pos, gint end_pos)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -