root/src/pgtkim.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. im_context_commit_cb
  2. im_context_retrieve_surrounding_cb
  3. im_context_delete_surrounding_cb
  4. make_color_string
  5. im_context_preedit_changed_cb
  6. im_context_preedit_end_cb
  7. im_context_preedit_start_cb
  8. pgtk_im_focus_in
  9. pgtk_im_focus_out
  10. pgtk_im_filter_keypress
  11. pgtk_im_set_cursor_location
  12. pgtk_im_use_context
  13. pgtk_im_init
  14. pgtk_im_finish
  15. syms_of_pgtkim

     1 /* Pure Gtk+-3 communication module.
     2 
     3 Copyright (C) 1989, 1993-1994, 2005-2006, 2008-2023 Free Software
     4 Foundation, Inc.
     5 
     6 This file is part of GNU Emacs.
     7 
     8 GNU Emacs is free software: you can redistribute it and/or modify
     9 it under the terms of the GNU General Public License as published by
    10 the Free Software Foundation, either version 3 of the License, or (at
    11 your option) any later version.
    12 
    13 GNU Emacs is distributed in the hope that it will be useful,
    14 but WITHOUT ANY WARRANTY; without even the implied warranty of
    15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    16 GNU General Public License for more details.
    17 
    18 You should have received a copy of the GNU General Public License
    19 along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.  */
    20 
    21 /* This should be the first include, as it may set up #defines affecting
    22    interpretation of even the system includes. */
    23 #include <config.h>
    24 
    25 #include "pgtkterm.h"
    26 
    27 static void
    28 im_context_commit_cb (GtkIMContext *imc,
    29                       gchar *str,
    30                       gpointer user_data)
    31 {
    32   struct pgtk_display_info *dpyinfo = user_data;
    33   struct frame *f = dpyinfo->im.focused_frame;
    34 
    35   if (dpyinfo->im.context == NULL)
    36     return;
    37   if (f == NULL)
    38     return;
    39 
    40   pgtk_enqueue_string (f, str);
    41 }
    42 
    43 static gboolean
    44 im_context_retrieve_surrounding_cb (GtkIMContext *imc, gpointer user_data)
    45 {
    46   gtk_im_context_set_surrounding (imc, "", -1, 0);
    47   return TRUE;
    48 }
    49 
    50 static gboolean
    51 im_context_delete_surrounding_cb (GtkIMContext *imc, int offset, int n_chars,
    52                                   gpointer user_data)
    53 {
    54   return TRUE;
    55 }
    56 
    57 static Lisp_Object
    58 make_color_string (PangoAttrColor *pac)
    59 {
    60   char buf[256];
    61   sprintf (buf, "#%02x%02x%02x",
    62            pac->color.red >> 8, pac->color.green >> 8, pac->color.blue >> 8);
    63   return build_string (buf);
    64 }
    65 
    66 static void
    67 im_context_preedit_changed_cb (GtkIMContext *imc, gpointer user_data)
    68 {
    69   struct pgtk_display_info *dpyinfo = user_data;
    70   struct frame *f = dpyinfo->im.focused_frame;
    71   char *str;
    72   PangoAttrList *attrs;
    73   int pos;
    74 
    75   if (dpyinfo->im.context == NULL)
    76     return;
    77   if (f == NULL)
    78     return;
    79 
    80   gtk_im_context_get_preedit_string (imc, &str, &attrs, &pos);
    81 
    82 
    83   /*
    84    * (
    85    *   (TEXT (ul . COLOR) (bg . COLOR) (fg . COLOR))
    86    *   ...
    87    * )
    88    */
    89   Lisp_Object list = Qnil;
    90 
    91   PangoAttrIterator *iter;
    92   iter = pango_attr_list_get_iterator (attrs);
    93   do
    94     {
    95       int st, ed;
    96       int has_underline = 0;
    97       Lisp_Object part = Qnil;
    98 
    99       pango_attr_iterator_range (iter, &st, &ed);
   100 
   101       if (ed > strlen (str))
   102         ed = strlen (str);
   103       if (st >= ed)
   104         continue;
   105 
   106       Lisp_Object text = make_string (str + st, ed - st);
   107       part = Fcons (text, part);
   108 
   109       PangoAttrInt *ul =
   110         (PangoAttrInt *) pango_attr_iterator_get (iter, PANGO_ATTR_UNDERLINE);
   111       if (ul != NULL)
   112         {
   113           if (ul->value != PANGO_UNDERLINE_NONE)
   114             has_underline = 1;
   115         }
   116 
   117       PangoAttrColor *pac;
   118       if (has_underline)
   119         {
   120           pac =
   121             (PangoAttrColor *) pango_attr_iterator_get (iter,
   122                                                         PANGO_ATTR_UNDERLINE_COLOR);
   123           if (pac != NULL)
   124             part = Fcons (Fcons (Qul, make_color_string (pac)), part);
   125           else
   126             part = Fcons (Fcons (Qul, Qt), part);
   127         }
   128 
   129       pac =
   130         (PangoAttrColor *) pango_attr_iterator_get (iter,
   131                                                     PANGO_ATTR_FOREGROUND);
   132       if (pac != NULL)
   133         part = Fcons (Fcons (Qfg, make_color_string (pac)), part);
   134 
   135       pac =
   136         (PangoAttrColor *) pango_attr_iterator_get (iter,
   137                                                     PANGO_ATTR_BACKGROUND);
   138       if (pac != NULL)
   139         part = Fcons (Fcons (Qbg, make_color_string (pac)), part);
   140 
   141       part = Fnreverse (part);
   142       list = Fcons (part, list);
   143     }
   144   while (pango_attr_iterator_next (iter));
   145 
   146   list = Fnreverse (list);
   147   pgtk_enqueue_preedit (f, list);
   148 
   149   g_free (str);
   150   pango_attr_list_unref (attrs);
   151 }
   152 
   153 static void
   154 im_context_preedit_end_cb (GtkIMContext *imc, gpointer user_data)
   155 {
   156   struct pgtk_display_info *dpyinfo = user_data;
   157   struct frame *f = dpyinfo->im.focused_frame;
   158 
   159   if (dpyinfo->im.context == NULL)
   160     return;
   161   if (f == NULL)
   162     return;
   163 
   164   pgtk_enqueue_preedit (f, Qnil);
   165 }
   166 
   167 static void
   168 im_context_preedit_start_cb (GtkIMContext *imc, gpointer user_data)
   169 {
   170 }
   171 
   172 void
   173 pgtk_im_focus_in (struct frame *f)
   174 {
   175   struct pgtk_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
   176   if (dpyinfo->im.context != NULL)
   177     {
   178       gtk_im_context_reset (dpyinfo->im.context);
   179       gtk_im_context_set_client_window (dpyinfo->im.context,
   180                                         gtk_widget_get_window
   181                                         (FRAME_GTK_WIDGET (f)));
   182       gtk_im_context_focus_in (dpyinfo->im.context);
   183     }
   184   dpyinfo->im.focused_frame = f;
   185 }
   186 
   187 void
   188 pgtk_im_focus_out (struct frame *f)
   189 {
   190   struct pgtk_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
   191   if (dpyinfo->im.focused_frame == f)
   192     {
   193       if (dpyinfo->im.context != NULL)
   194         {
   195           gtk_im_context_reset (dpyinfo->im.context);
   196           gtk_im_context_focus_out (dpyinfo->im.context);
   197           gtk_im_context_set_client_window (dpyinfo->im.context, NULL);
   198         }
   199       dpyinfo->im.focused_frame = NULL;
   200     }
   201 }
   202 
   203 bool
   204 pgtk_im_filter_keypress (struct frame *f, GdkEventKey * ev)
   205 {
   206   struct pgtk_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
   207   if (dpyinfo->im.context != NULL)
   208     {
   209       if (gtk_im_context_filter_keypress (dpyinfo->im.context, ev))
   210         return true;
   211     }
   212   return false;
   213 }
   214 
   215 void
   216 pgtk_im_set_cursor_location (struct frame *f, int x, int y, int width,
   217                              int height)
   218 {
   219   struct pgtk_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
   220   if (dpyinfo->im.context != NULL && dpyinfo->im.focused_frame == f)
   221     {
   222       GdkRectangle area = { x, y, width, height };
   223       gtk_im_context_set_cursor_location (dpyinfo->im.context, &area);
   224     }
   225 }
   226 
   227 static void
   228 pgtk_im_use_context (struct pgtk_display_info *dpyinfo, bool use_p)
   229 {
   230   if (!use_p)
   231     {
   232       if (dpyinfo->im.context != NULL)
   233         {
   234           gtk_im_context_reset (dpyinfo->im.context);
   235           gtk_im_context_focus_out (dpyinfo->im.context);
   236           gtk_im_context_set_client_window (dpyinfo->im.context, NULL);
   237 
   238           g_object_unref (dpyinfo->im.context);
   239           dpyinfo->im.context = NULL;
   240         }
   241     }
   242   else
   243     {
   244       if (dpyinfo->im.context == NULL)
   245         {
   246           dpyinfo->im.context = gtk_im_multicontext_new ();
   247           g_signal_connect (dpyinfo->im.context, "commit",
   248                             G_CALLBACK (im_context_commit_cb), dpyinfo);
   249           g_signal_connect (dpyinfo->im.context, "retrieve-surrounding",
   250                             G_CALLBACK (im_context_retrieve_surrounding_cb),
   251                             dpyinfo);
   252           g_signal_connect (dpyinfo->im.context, "delete-surrounding",
   253                             G_CALLBACK (im_context_delete_surrounding_cb),
   254                             dpyinfo);
   255           g_signal_connect (dpyinfo->im.context, "preedit-changed",
   256                             G_CALLBACK (im_context_preedit_changed_cb),
   257                             dpyinfo);
   258           g_signal_connect (dpyinfo->im.context, "preedit-end",
   259                             G_CALLBACK (im_context_preedit_end_cb), dpyinfo);
   260           g_signal_connect (dpyinfo->im.context, "preedit-start",
   261                             G_CALLBACK (im_context_preedit_start_cb),
   262                             dpyinfo);
   263           gtk_im_context_set_use_preedit (dpyinfo->im.context, TRUE);
   264 
   265           if (dpyinfo->im.focused_frame)
   266             pgtk_im_focus_in (dpyinfo->im.focused_frame);
   267         }
   268     }
   269 }
   270 
   271 void
   272 pgtk_im_init (struct pgtk_display_info *dpyinfo)
   273 {
   274   dpyinfo->im.context = NULL;
   275 
   276   pgtk_im_use_context (dpyinfo, !NILP (Vpgtk_use_im_context_on_new_connection));
   277 }
   278 
   279 void
   280 pgtk_im_finish (struct pgtk_display_info *dpyinfo)
   281 {
   282   if (dpyinfo->im.context != NULL)
   283     g_object_unref (dpyinfo->im.context);
   284   dpyinfo->im.context = NULL;
   285 }
   286 
   287 DEFUN ("pgtk-use-im-context", Fpgtk_use_im_context, Spgtk_use_im_context, 1, 2, 0,
   288        doc: /* Set whether to use GtkIMContext. */)
   289   (Lisp_Object use_p, Lisp_Object terminal)
   290 {
   291   struct pgtk_display_info *dpyinfo = check_pgtk_display_info (terminal);
   292 
   293   pgtk_im_use_context (dpyinfo, !NILP (use_p));
   294 
   295   return Qnil;
   296 }
   297 
   298 void
   299 syms_of_pgtkim (void)
   300 {
   301   defsubr (&Spgtk_use_im_context);
   302 
   303   DEFSYM (Qpgtk_refresh_preedit, "pgtk-refresh-preedit");
   304   DEFSYM (Qul, "ul");
   305   DEFSYM (Qfg, "fg");
   306   DEFSYM (Qbg, "bg");
   307 
   308   DEFVAR_LISP ("pgtk-use-im-context-on-new-connection", Vpgtk_use_im_context_on_new_connection,
   309                doc: /* Whether to use GtkIMContext on a new connection.
   310 If you want to change it after connection, use the `pgtk-use-im-context'
   311 function.  */ );
   312   Vpgtk_use_im_context_on_new_connection = Qt;
   313 }

/* [<][>][^][v][top][bottom][index][help] */