Back to index

im-sdk  12.3.91
iiim-interface.c
Go to the documentation of this file.
00001 /* GNOME INPUT METHOD SWITCHER
00002  * Copyright 2003 Sun Microsystems Inc.
00003  *
00004  * This is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU Lesser General Public
00006  * License as published by the Free Software Foundation; either
00007  * version 2 of the License, or (at your option) any later version.
00008  *
00009  * This library is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * Lesser General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU Lesser General Public
00015  * License along with this library; if not, write to the
00016  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00017  * Boston, MA 02111-1307, USA.
00018  */
00019 
00020 #include <config.h>
00021 
00022 #include <gtk/gtkmain.h>
00023 #include <gtk/gtkdrawingarea.h>
00024 #include <gtk/gtksignal.h>
00025 #include <gdk/gdkx.h>
00026 #include <gnome.h>
00027 #include <X11/Xlib.h>
00028 
00029 #include "gnome-im-switcher.h"
00030 #include "widgets.h"
00031 #include "language.h"
00032 #include "iiim-interface.h"
00033 #include "quick-access-menu.h"
00034 
00035 void process_hotkey (GimletWindow *, gpointer, int);
00036 char *change_hotkey_with_trigger (char *, char *);
00037 
00038 static void
00039 process_language_list (GimletWindow *gimlet,
00040                      gpointer data, int count)
00041 {
00042   gchar *new_lang_list = g_strndup (data, count);
00043   const gchar *delimiter = ";";
00044   gchar **new_client_lang_list;
00045 
00046   new_client_lang_list = g_strsplit (new_lang_list, delimiter, -1);
00047   g_free (new_lang_list);
00048 
00049   if (gimlet->client_lang_list)
00050     {
00051       gchar **p;
00052       gchar **q;
00053       gboolean update = FALSE;
00054       for (p = gimlet->client_lang_list, q = new_client_lang_list;
00055           *p && *q;
00056           p++, q++)
00057        if (strcmp (*p, *q))
00058          {
00059            update = TRUE;
00060            break;
00061          }
00062       if (update == FALSE)
00063        {
00064          g_strfreev (new_client_lang_list);
00065          return;
00066        }
00067       else
00068        g_strfreev (gimlet->client_lang_list);
00069     }
00070   gimlet->client_lang_list = new_client_lang_list;
00071 
00072   gimlet_language_init (gimlet);
00073 
00074   return;
00075 }
00076 
00077 /*
00078  * process_current_input_language:
00079  *
00080  *     called when application input focus is switched and notifies
00081  *     the IIIM input language name a newly focused application is
00082  *      using.
00083  */
00084 static void
00085 process_current_input_language (GimletWindow *gimlet,
00086                             gpointer data, int length)
00087 {
00088   switch (gimlet->input_lang_policy)
00089     {
00090     case FOLLOW_APPLICATION :
00091       if (gimlet->current_iiim_lang)
00092        g_free (gimlet->current_iiim_lang);
00093 
00094       gimlet->current_iiim_lang = g_strndup (data, length);
00095 
00096       gimlet_language_add_active_language (gimlet, gimlet->current_iiim_lang);
00097       break;
00098     case FOLLOW_QUICK_ACCESS_MENU:
00099       /*
00100        notify the application of the language currently selected in quick
00101        access menu
00102       */
00103       gimlet_iiim_language_set (gimlet, gimlet->current_iiim_lang);
00104       break;
00105 #ifdef MEANINGLESS_OPTION_PERHAPS
00106     case FOLLOW_OPTION_MENU:
00107       /*
00108        notify the application of the language currently selected in option
00109        menu
00110       */
00111       gimlet_iiim_language_set (gimlet, gimlet->iiim_lang_in_option_menu);
00112 
00113       if (gimlet->current_iiim_lang)
00114        g_free (gimlet->current_iiim_lang);
00115 
00116       gimlet->current_iiim_lang = g_strdup (gimlet->iiim_lang_in_option_menu);
00117 
00118       gimlet_language_add_active_language (gimlet, gimlet->current_iiim_lang);
00119 
00120       break;
00121     case FOLLOW_CURRENT_LOCALE:
00122       break;
00123 #endif
00124     }
00125 
00126   gimlet_update_lang (gimlet);
00127 }
00128 
00129 static void
00130 process_status_text (GimletWindow *gimlet,
00131                    gpointer data, int length)
00132 {
00133   gchar *text = (char *) data;
00134   gchar *display_name;
00135 
00136   if (length == 1 && text[0] == 0x20)
00137     {
00138       display_name = g_strdup ("");
00139       gimlet->conversion_mode = FALSE;
00140     }    
00141   else
00142     {
00143       display_name = g_strndup (text, length);
00144       gimlet->conversion_mode = TRUE;
00145     }
00146 
00147   gimlet_status_set_text (gimlet, display_name);
00148   g_free (display_name);
00149 
00150   gimlet_update_lang (gimlet);
00151 }
00152 
00153 static void
00154 process_language_engine_list (GimletWindow *gimlet,
00155                            gpointer data, int length)
00156 {
00157   g_free (gimlet->le_list);
00158   gimlet->le_list = g_strndup (data, length);
00159   return;
00160 }
00161 
00162 /* this doesn't seem to get reached currently (iiimgcf bug?) */
00163 static void
00164 process_conversion_mode (GimletWindow *gimlet,
00165                       gpointer data, int length)
00166 {
00167   gimlet->conversion_mode = ((gulong*)data)[0];
00168   gimlet_update_lang (gimlet);
00169 }
00170 
00171 static void
00172 selection_request_switcher_window (GtkWidget *widget, GdkEventSelection *ev,
00173                                GimletWindow *gimlet)
00174 {
00175   GdkDisplay *display = gtk_widget_get_display (widget);
00176 
00177   if (ev->target == gimlet->set_current_client_atom)
00178     {
00179       gimlet->last_client =
00180        gdk_window_foreign_new_for_display (display, ev->requestor);
00181     }
00182   else if (ev->target == gimlet->selection)
00183     {
00184 #if PLACE_HOLDER
00185       gdk_property_change (ev->requestor,
00186                         gimlet->selection,
00187                         gimlet->selection,
00188                         8,
00189                         GDK_PROP_MODE_REPLACE,
00190                         (guchar *)"dummy",
00191                         strlen ("dummy"));
00192 #endif
00193     }
00194   gimlet_update_lang (gimlet);
00195 }
00196 
00197 static void
00198 property_notify_switcher_window (GtkWidget *widget, GdkEventProperty *ev,
00199                              GimletWindow *gimlet)
00200 {
00201   GdkAtom  type;
00202   guchar   *data = NULL;
00203   gint     format;
00204   gint     length = 0;
00205 
00206   gdk_property_get (widget->window, ev->atom, ev->atom,
00207                   0, INT_MAX, FALSE,
00208                   &type, &format, &length, &data);
00209   if (data)
00210     {
00211       if (type == gimlet->set_input_language_list_atom)
00212        process_language_list (gimlet, data, length);
00213       else if (type == gimlet->set_current_input_language_atom)
00214        process_current_input_language (gimlet, data, length);
00215       else if (type == gimlet->set_status_text_atom)
00216        process_status_text (gimlet, data, length);
00217       else if (type == gimlet->set_conversion_mode_atom)
00218        process_conversion_mode (gimlet, data, length);
00219       else if (type == gimlet->set_language_engine_list_atom)
00220        process_language_engine_list (gimlet, data, length);
00221       else if (type == gimlet->set_hotkey_atom)
00222        process_hotkey (gimlet, data, length);
00223 
00224       g_free (data);
00225     }
00226 }
00227 
00228 /* public */
00229 gboolean
00230 gimlet_iiim_selection_set (GimletWindow *gimlet)
00231 {
00232   GdkAtom atom = GDK_NONE;
00233   GdkWindow *owner = NULL;
00234   GdkDisplay *display;
00235   GdkScreen *screen;
00236 
00237   display = gtk_widget_get_display (GTK_WIDGET(gimlet->applet));
00238   screen = gtk_widget_get_screen (GTK_WIDGET(gimlet->applet));
00239   atom = gdk_atom_intern ("_IIIM_SWITCHER", FALSE);
00240   if (atom == GDK_NONE)
00241     return FALSE;
00242 
00243   owner = gdk_selection_owner_get_for_display (display, atom);
00244   if (owner)
00245     {
00246       g_warning ("There is IIIM input method switcher already.");
00247       return FALSE;
00248     }
00249 
00250   gimlet->invisible = gtk_invisible_new_for_screen (screen);
00251   gtk_widget_realize (gimlet->invisible);
00252 
00253   if (!gtk_selection_owner_set_for_display (display, 
00254                                        gimlet->invisible,
00255                                        atom,
00256                                        GDK_CURRENT_TIME))
00257     {
00258       g_warning ("Cannot become IIIM input method switcher selection atom owner.");
00259       return FALSE;
00260     }
00261   gimlet->selection = atom;
00262 
00263   atom = gdk_atom_intern ("_IIIM_SWITCHER_CURRENT_INPUT_LANGUAGE", FALSE);
00264   gimlet->set_current_input_language_atom = atom;
00265 
00266   atom = gdk_atom_intern ("_IIIM_SWITCHER_CURRENT_CLIENT", FALSE);
00267   gimlet->set_current_client_atom = atom;
00268 
00269   atom = gdk_atom_intern ("_IIIM_SWITCHER_INPUT_LANGUAGE_LIST", FALSE);
00270   gimlet->set_input_language_list_atom = atom;
00271 
00272   atom = gdk_atom_intern ("_IIIM_SWITCHER_STATUS_TEXT", FALSE);
00273   gimlet->set_status_text_atom = atom;
00274 
00275   atom = gdk_atom_intern ("_IIIM_SWITCHER_SET_CONVERSION_MODE", FALSE);
00276   gimlet->set_conversion_mode_atom = atom;
00277 
00278   atom = gdk_atom_intern ("_IIIM_SWITCHER_LANGUAGE_ENGINE_LIST", FALSE);
00279   gimlet->set_language_engine_list_atom = atom;
00280 
00281   atom = gdk_atom_intern ("_IIIM_SWITCHER_SET_HOTKEY", FALSE);
00282   gimlet->set_hotkey_atom = atom;
00283 
00284   gtk_widget_add_events (gimlet->invisible,
00285                       GDK_PROPERTY_CHANGE_MASK | GDK_STRUCTURE_MASK);
00286 
00287   g_signal_connect (G_OBJECT (gimlet->invisible),
00288                   "selection-request-event",
00289                   G_CALLBACK (selection_request_switcher_window),
00290                   gimlet);
00291   g_signal_connect (G_OBJECT (gimlet->invisible), "property-notify-event",
00292                   G_CALLBACK (property_notify_switcher_window),
00293                   gimlet);
00294   return TRUE;
00295 }
00296 
00297 void
00298 gimlet_iiim_language_set (GimletWindow *gimlet, 
00299                        const gchar *iiim_lang)
00300 {
00301   g_return_if_fail (iiim_lang != NULL);
00302 
00303   gdk_property_change (gimlet->last_client,
00304                      gimlet->set_current_input_language_atom,
00305                      gimlet->set_current_input_language_atom,
00306                      8,
00307                      GDK_PROP_MODE_REPLACE,
00308                      (guchar *)iiim_lang,
00309                      strlen (iiim_lang) + 1); /* including last NULL */
00310 }
00311 
00312 void
00313 gimlet_iiim_conversion_mode_set (GimletWindow *gimlet, 
00314                              const gchar *conversion_mode)
00315 {
00316   g_return_if_fail (conversion_mode != NULL);
00317 
00318   gdk_property_change (gimlet->last_client,
00319                      gimlet->set_conversion_mode_atom,
00320                      gimlet->set_conversion_mode_atom,
00321                      8,
00322                      GDK_PROP_MODE_REPLACE,
00323                      (guchar *)conversion_mode,
00324                      strlen (conversion_mode) + 1); /* including last NULL */
00325 }
00326 
00327 static void
00328 process_hotkey (GimletWindow *gimlet,
00329                 gpointer data, int length)
00330 {
00331   char *trigger, *old_trigger;
00332   char *hotkey = g_strndup (data, length);
00333 
00334   /*
00335    * FIXME why process_hotkey would be invoked when put focus on the TRIGGER entry
00336    * of the hotkey configuration window?
00337    */
00338 
00339   /*
00340    * FIXME override hotkey with the trigger value from gconf.
00341    */
00342 #if 0
00343   old_trigger = gconf_get_conversion_keys (gimlet);
00344   trigger = get_trigger_from_hotkey (hotkey);
00345   if (old_trigger && strcasecmp (old_trigger, trigger) != 0)
00346     {
00347       char *tmp_hotkey = change_hotkey_with_trigger (hotkey, old_trigger);
00348 
00349       g_free (hotkey);
00350       hotkey = tmp_hotkey;
00351     }
00352 
00353   g_free (old_trigger);
00354   g_free (trigger);
00355 #endif
00356 
00357   g_free (gimlet->hotkey);
00358   gimlet->hotkey = g_strdup (hotkey);
00359 
00360   g_free (hotkey);
00361 }
00362 
00363 static char *
00364 change_hotkey_with_trigger (char *s, char *trigger)
00365 {
00366   char *label_delimiter = ":";
00367   char **hotkeys = g_strsplit (s, label_delimiter, -1);
00368   int num_hotkeys = 0;
00369   int i;
00370 
00371   // num_hotkeys = g_strv_length (hotkeys)/2;
00372   while (hotkeys[num_hotkeys]) ++num_hotkeys;
00373   num_hotkeys /= 2;
00374 
00375   for (i = 0; i < num_hotkeys; ++i)
00376     {
00377       if (!strcmp (hotkeys[i * 2], TRIGGER_KEY_LABEL))
00378         {
00379           g_free (hotkeys[i * 2 + 1]);
00380           hotkeys[i * 2 + 1] = strdup (trigger);
00381         }
00382     }
00383 
00384   return g_strjoinv (label_delimiter, hotkeys);
00385 }
00386 
00387 void
00388 gimlet_iiim_hotkey_set (GimletWindow *gimlet,
00389                         const gchar *trigger)
00390 {
00391   char *hotkey;
00392 
00393   g_return_if_fail (trigger != NULL);
00394 
00395   hotkey = change_hotkey_with_trigger (gimlet->hotkey, trigger);
00396 
00397   gdk_property_change (gimlet->invisible->window,
00398                        gimlet->set_hotkey_atom,
00399                        gimlet->set_hotkey_atom,
00400                        8,
00401                        GDK_PROP_MODE_REPLACE,
00402                        (guchar *)hotkey,
00403                        strlen (hotkey) + 1); /* including last NULL */
00404 }