1 /*
2 
3 Copyright (c) 2003-2013 uim Project https://github.com/uim/uim
4 
5 All rights reserved.
6 
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions
9 are met:
10 
11 1. Redistributions of source code must retain the above copyright
12 notice, this list of conditions and the following disclaimer.
13 2. Redistributions in binary form must reproduce the above copyright
14 notice, this list of conditions and the following disclaimer in the
15 documentation and/or other materials provided with the distribution.
16 3. Neither the name of authors nor the names of its contributors
17 may be used to endorse or promote products derived from this software
18 without specific prior written permission.
19 
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
21 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE
24 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 SUCH DAMAGE.
31 
32 */
33 #include "qhelpermanager.h"
34 
35 #include <QtCore/QSocketNotifier>
36 #include <QtCore/QStringList>
37 #include <QtCore/QTextCodec>
38 
39 #include "uim/uim.h"
40 #include "uim/uim-helper.h"
41 #include "uim/uim-im-switcher.h"
42 #include "uim/uim-util.h"
43 
44 #include "plugin.h"
45 #include "quiminfomanager.h"
46 #if QT_VERSION < 0x050000
47 # include "quiminputcontext.h"
48 #else
49 # include <quimplatforminputcontext.h>
50 #endif
51 
52 static int im_uim_fd = 0;
53 static QSocketNotifier *notifier = 0;
54 
55 #if QT_VERSION < 0x050000
56 extern QUimInputContext *focusedInputContext;
57 #else
58 extern QUimPlatformInputContext *focusedInputContext;
59 #endif
60 extern bool disableFocusedContext;
61 
62 #if QT_VERSION < 0x050000
63 extern QList<QUimInputContext *> contextList;
64 #else
65 extern QList<QUimPlatformInputContext *> contextList;
66 #endif
67 
QUimHelperManager(QObject * parent)68 QUimHelperManager::QUimHelperManager( QObject *parent )
69         : QObject( parent )
70 {
71     notifier = 0;
72     im_uim_fd = -1;
73 }
74 
~QUimHelperManager()75 QUimHelperManager::~QUimHelperManager()
76 {
77     if ( im_uim_fd != -1 )
78         uim_helper_close_client_fd( im_uim_fd );
79 }
80 
checkHelperConnection(uim_context uc)81 void QUimHelperManager::checkHelperConnection(uim_context uc)
82 {
83     if ( im_uim_fd < 0 )
84     {
85         im_uim_fd = uim_helper_init_client_fd( QUimHelperManager::helper_disconnect_cb );
86 
87         if ( im_uim_fd >= 0 )
88         {
89             notifier = new QSocketNotifier( im_uim_fd, QSocketNotifier::Read );
90             connect( notifier, SIGNAL( activated( int ) ),
91                               this, SLOT( slotStdinActivated() ) );
92             uim_set_uim_fd(uc, im_uim_fd);
93         }
94     }
95 }
96 
slotStdinActivated()97 void QUimHelperManager::slotStdinActivated()
98 {
99     char *tmp;
100     uim_helper_read_proc( im_uim_fd );
101     while ((tmp = uim_helper_get_message()))
102     {
103         parseHelperStr(QString::fromUtf8(tmp));
104         free(tmp);
105     }
106 }
107 
parseHelperStr(const QString & str)108 void QUimHelperManager::parseHelperStr( const QString &str )
109 {
110     if ( focusedInputContext && !disableFocusedContext )
111     {
112         if ( str.startsWith( QLatin1String( "prop_list_get" ) ) )
113             uim_prop_list_update( focusedInputContext->uimContext() );
114         else if ( str.startsWith( QLatin1String( "prop_label_get" ) ) )
115             uim_prop_label_update( focusedInputContext->uimContext() );
116         else if ( str.startsWith( QLatin1String( "prop_activate" ) ) )
117         {
118             QStringList list = str.split( '\n' );
119             uim_prop_activate( focusedInputContext->uimContext(),
120                                list[ 1 ].toUtf8().data() );
121         }
122         else if ( str.startsWith( QLatin1String( "im_list_get" ) ) )
123         {
124             sendImList();
125         }
126         else if ( str.startsWith( QLatin1String( "commit_string" ) ) )
127         {
128             QStringList lines = str.split( '\n' );
129             if ( !lines.isEmpty() && !lines[ 1 ].isEmpty() ) {
130                 QString commit_str;
131 
132                 if ( lines[ 1 ].startsWith( QLatin1String( "charset" ) ) ) {
133                     /* get charset */
134                     QString charset = lines[ 1 ].split( '=' ) [ 1 ];
135 
136                     /* convert to unicode */
137                     QTextCodec *codec
138                         = QTextCodec::codecForName( charset.toLatin1() );
139                     if ( codec && !lines[ 2 ].isEmpty() )
140                         commit_str = codec->toUnicode( lines[ 2 ].toLatin1() );
141                 } else {
142                     commit_str = lines[ 1 ];
143                 }
144 
145                 focusedInputContext->commitString( commit_str );
146             }
147         }
148         else if ( str.startsWith( QLatin1String( "focus_in" ) ) )
149         {
150             // We shouldn't do "focusedInputContext = NULL" here, because some
151             // window manager has some focus related bugs.
152             disableFocusedContext = true;
153         }
154     }
155 
156     /**
157      * This part should be processed even if not focused
158      */
159     if ( str.startsWith( QLatin1String( "im_change" ) ) )
160     {
161         // for IM switcher
162         parseHelperStrImChange( str );
163     }
164     else if ( str.startsWith( QLatin1String( "prop_update_custom" ) ) )
165     {
166         // for custom api
167         QStringList list = str.split( '\n' );
168         if ( !list.isEmpty() && !list[ 0 ].isEmpty() &&
169                 !list[ 1 ].isEmpty() && !list[ 2 ].isEmpty() )
170         {
171 #if QT_VERSION < 0x050000
172             QList<QUimInputContext *>::iterator it;
173 #else
174             QList<QUimPlatformInputContext *>::iterator it;
175 #endif
176             for ( it = contextList.begin(); it != contextList.end(); ++it )
177             {
178                 uim_prop_update_custom( ( *it )->uimContext(),
179                                         list[ 1 ].toUtf8().data(),
180                                         list[ 2 ].toUtf8().data() );
181                 if ( list[ 1 ]
182                         == QLatin1String( "candidate-window-position" ) )
183                     ( *it )->updatePosition();
184                 if ( list[ 1 ]
185                         == QLatin1String( "candidate-window-style" ) )
186                     ( *it )->updateStyle();
187                 break;  /* all custom variables are global */
188             }
189         }
190     }
191     else if ( str.startsWith( QLatin1String( "custom_reload_notify" ) ) )
192     {
193         uim_prop_reload_configs();
194 
195         QUimInfoManager *infoManager =
196             UimInputContextPlugin::getQUimInfoManager();
197         infoManager->initUimInfo();
198 
199 #if QT_VERSION < 0x050000
200         QList<QUimInputContext *>::iterator it;
201 #else
202         QList<QUimPlatformInputContext *>::iterator it;
203 #endif
204         for ( it = contextList.begin(); it != contextList.end(); ++it ) {
205             ( *it )->updatePosition();
206             ( *it )->updateStyle();
207         }
208     }
209 }
210 
parseHelperStrImChange(const QString & str)211 void QUimHelperManager::parseHelperStrImChange( const QString &str )
212 {
213     QStringList list = str.split( '\n' );
214     QString im_name = list[ 1 ];
215     QString im_name_sym = '\'' + im_name;
216 
217     if ( str.startsWith( QLatin1String( "im_change_this_text_area_only" ) ) )
218     {
219         if ( focusedInputContext )
220         {
221             uim_switch_im( focusedInputContext->uimContext(),
222                            im_name.toUtf8().data() );
223             uim_prop_list_update( focusedInputContext->uimContext() );
224             focusedInputContext->updatePosition();
225         }
226     }
227     else if ( str.startsWith( QLatin1String( "im_change_whole_desktop" ) ) )
228     {
229 #if QT_VERSION < 0x050000
230         QList<QUimInputContext *>::iterator it;
231 #else
232         QList<QUimPlatformInputContext *>::iterator it;
233 #endif
234         for ( it = contextList.begin(); it != contextList.end(); ++it )
235         {
236             uim_switch_im( ( *it )->uimContext(), im_name.toUtf8().data() );
237             ( *it )->updatePosition();
238             uim_prop_update_custom( ( *it )->uimContext(),
239                                     "custom-preserved-default-im-name",
240                                     im_name_sym.toUtf8().data() );
241         }
242     }
243     else if ( str.startsWith( QLatin1String(
244         "im_change_this_application_only" ) ) )
245     {
246         if ( focusedInputContext )
247         {
248 #if QT_VERSION < 0x050000
249             QList<QUimInputContext *>::iterator it;
250 #else
251             QList<QUimPlatformInputContext *>::iterator it;
252 #endif
253             for ( it = contextList.begin(); it != contextList.end(); ++it )
254             {
255                 uim_switch_im( ( *it )->uimContext(), im_name.toUtf8().data() );
256                 ( *it )->updatePosition();
257                 uim_prop_update_custom( ( *it )->uimContext(),
258                                         "custom-preserved-default-im-name",
259                                         im_name_sym.toUtf8().data() );
260             }
261         }
262     }
263 }
264 
sendImList()265 void QUimHelperManager::sendImList()
266 {
267     if ( !focusedInputContext )
268         return ;
269 
270     QString msg = "im_list\ncharset=UTF-8\n";
271     const char* current_im_name = uim_get_current_im_name( focusedInputContext->uimContext() );
272 
273     QUimInfoManager *infoManager = UimInputContextPlugin::getQUimInfoManager();
274     QList<uimInfo> info = infoManager->getUimInfo();
275     QList<uimInfo>::iterator it;
276 
277     for ( it = info.begin(); it != info.end(); ++it )
278     {
279         QString leafstr;
280         leafstr.sprintf( "%s\t%s\t%s\t",
281                          ( *it ).name.toUtf8().data(),
282                          uim_get_language_name_from_locale( ( *it ).lang.toUtf8().data() ),
283                          ( *it).short_desc.toUtf8().data() );
284 
285         if ( QString::compare( ( *it ).name, current_im_name ) == 0 )
286             leafstr.append( "selected" );
287 
288         leafstr.append( "\n" );
289 
290         msg += leafstr;
291     }
292 
293     uim_helper_send_message( im_uim_fd, msg.toUtf8().data() );
294 }
295 
send_im_change_whole_desktop(const char * name)296 void QUimHelperManager::send_im_change_whole_desktop( const char *name )
297 {
298     QString msg;
299 
300     msg.sprintf("im_change_whole_desktop\n%s\n", name);
301     uim_helper_send_message( im_uim_fd, msg.toUtf8().data() );
302 }
303 
helper_disconnect_cb()304 void QUimHelperManager::helper_disconnect_cb()
305 {
306     im_uim_fd = -1;
307 
308     if ( notifier )
309     {
310         delete notifier;
311         notifier = 0;
312     }
313 }
314 
update_prop_list_cb(void * ptr,const char * str)315 void QUimHelperManager::update_prop_list_cb( void *ptr, const char *str )
316 {
317 #if QT_VERSION < 0x050000
318     QUimInputContext *ic = static_cast<QUimInputContext*>( ptr );
319 #else
320     QUimPlatformInputContext *ic = static_cast<QUimPlatformInputContext*>( ptr );
321 #endif
322 
323     if ( ic != focusedInputContext || disableFocusedContext )
324         return;
325 
326     QString msg = "prop_list_update\ncharset=UTF-8\n";
327     msg += QString::fromUtf8( str );
328 
329     uim_helper_send_message( im_uim_fd, msg.toUtf8().data() );
330 
331     ic->updateIndicator( msg );
332 }
333 
update_prop_label_cb(void * ptr,const char * str)334 void QUimHelperManager::update_prop_label_cb( void *ptr, const char *str )
335 {
336 #if QT_VERSION < 0x050000
337     QUimInputContext *ic = static_cast<QUimInputContext*>( ptr );
338 #else
339     QUimPlatformInputContext *ic = static_cast<QUimPlatformInputContext*>( ptr );
340 #endif
341     if ( ic != focusedInputContext || disableFocusedContext )
342         return;
343 
344     QString msg = "prop_label_update\ncharset=UTF-8\n";
345     msg += QString::fromUtf8( str );
346 
347     uim_helper_send_message( im_uim_fd, msg.toUtf8().data() );
348 }
349