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 <config.h>
34 
35 #include <qsocketnotifier.h>
36 #include <qstring.h>
37 #include <qstringlist.h>
38 #include <qtextcodec.h>
39 
40 #include "uim/uim.h"
41 #include "uim/uim-util.h"
42 #include "uim/uim-helper.h"
43 #include "uim/uim-im-switcher.h"
44 
45 #include "qhelpermanager.h"
46 #include "quiminputcontext.h"
47 #include "quiminfomanager.h"
48 #include "plugin.h"
49 
50 static int im_uim_fd = 0;
51 static QSocketNotifier *notifier = NULL;
52 
53 extern QUimInputContext *focusedInputContext;
54 extern bool disableFocusedContext;
55 
56 extern QPtrList<QUimInputContext> contextList;
57 
QUimHelperManager(QObject * parent,const char * name)58 QUimHelperManager::QUimHelperManager( QObject *parent, const char *name )
59         : QObject( parent, name )
60 {
61     notifier = NULL;
62     im_uim_fd = -1;
63 }
64 
~QUimHelperManager()65 QUimHelperManager::~QUimHelperManager()
66 {
67     if ( im_uim_fd != -1 )
68         uim_helper_close_client_fd( im_uim_fd );
69 }
70 
checkHelperConnection()71 void QUimHelperManager::checkHelperConnection()
72 {
73     if ( im_uim_fd < 0 )
74     {
75         im_uim_fd = uim_helper_init_client_fd( QUimHelperManager::helper_disconnect_cb );
76 
77         if ( im_uim_fd >= 0 )
78         {
79             notifier = new QSocketNotifier( im_uim_fd, QSocketNotifier::Read );
80             QObject::connect( notifier, SIGNAL( activated( int ) ),
81                               this, SLOT( slotStdinActivated( int ) ) );
82         }
83     }
84 }
85 
slotStdinActivated(int)86 void QUimHelperManager::slotStdinActivated( int /*socket*/ )
87 {
88     QString tmp;
89 
90     uim_helper_read_proc( im_uim_fd );
91     while ( ( tmp = QString::fromUtf8( uim_helper_get_message() ) ) )
92         parseHelperStr( tmp );
93 }
94 
parseHelperStr(const QString & str)95 void QUimHelperManager::parseHelperStr( const QString &str )
96 {
97     if ( focusedInputContext && !disableFocusedContext )
98     {
99         if ( str.startsWith( "prop_list_get" ) )
100             uim_prop_list_update( focusedInputContext->uimContext() );
101         else if ( str.startsWith( "prop_label_get" ) )
102             uim_prop_label_update( focusedInputContext->uimContext() );
103         else if ( str.startsWith( "prop_activate" ) )
104         {
105             QStringList lines = QStringList::split( "\n", str );
106             uim_prop_activate( focusedInputContext->uimContext(), ( const char* ) lines[ 1 ] );
107         }
108         else if ( str.startsWith( "im_list_get" ) )
109         {
110             sendImList();
111         }
112         else if ( str.startsWith( "commit_string" ) )
113         {
114             QStringList lines = QStringList::split( "\n", str );
115             if ( !lines.isEmpty() && !lines[ 1 ].isEmpty() ) {
116                 QString commit_str = QString::null;
117 
118                 if ( lines[ 1 ].startsWith( "charset" ) ) {
119                     /* get charset */
120                     QString charset = QStringList::split( "=", lines[ 1 ] ) [ 1 ];
121 
122                     /* convert to unicode */
123                     QTextCodec *codec = QTextCodec::codecForName( charset );
124                     if ( codec && !lines[ 2 ].isEmpty() )
125                         commit_str = codec->toUnicode( lines[ 2 ] );
126                 } else {
127                     commit_str = lines[ 1 ];
128                 }
129 
130                 focusedInputContext->commitString( commit_str );
131             }
132         }
133         else if ( str.startsWith( "focus_in" ) )
134         {
135             // We shouldn't do "focusedInputContext = NULL" here, because some
136             // window manager has some focus related bugs.
137             disableFocusedContext = true;
138         }
139     }
140 
141     /**
142      * This part should be processed even if not focused
143      */
144     if ( str.startsWith( "im_change" ) )
145     {
146         // for IM switcher
147         parseHelperStrImChange( str );
148     }
149     else if ( str.startsWith( "prop_update_custom" ) )
150     {
151         // for custom api
152         QUimInputContext * cc;
153         QStringList list = QStringList::split( "\n", str );
154         if ( !list.isEmpty() && !list[ 0 ].isEmpty() &&
155                 !list[ 1 ].isEmpty() && !list[ 2 ].isEmpty() )
156         {
157             for ( cc = contextList.first(); cc; cc = contextList.next() )
158             {
159                 uim_prop_update_custom( cc->uimContext(), list[ 1 ], list[ 2 ] );
160                 break;  /* all custom variables are global */
161             }
162         }
163     }
164     else if ( str.startsWith( "custom_reload_notify" ) )
165     {
166         uim_prop_reload_configs();
167 
168         QUimInfoManager *infoManager =
169             UimInputContextPlugin::getQUimInfoManager();
170 	infoManager->initUimInfo();
171     }
172 }
173 
parseHelperStrImChange(const QString & str)174 void QUimHelperManager::parseHelperStrImChange( const QString &str )
175 {
176     QUimInputContext * cc;
177     QStringList list = QStringList::split( "\n", str );
178     QString im_name = list[ 1 ];
179     QString im_name_sym = "'" + im_name;
180 
181     if ( str.startsWith( "im_change_this_text_area_only" ) )
182     {
183         if ( focusedInputContext )
184         {
185             uim_switch_im( focusedInputContext->uimContext(), ( const char* ) im_name );
186             uim_prop_list_update( focusedInputContext->uimContext() );
187             focusedInputContext->readIMConf();
188         }
189     }
190     else if ( str.startsWith( "im_change_whole_desktop" ) )
191     {
192         for ( cc = contextList.first(); cc; cc = contextList.next() )
193         {
194             uim_switch_im( cc->uimContext(), ( const char* ) im_name );
195             cc->readIMConf();
196             uim_prop_update_custom( cc->uimContext(),
197 	                            "custom-preserved-default-im-name",
198 				    ( const char* ) im_name_sym );
199         }
200     }
201     else if ( str.startsWith( "im_change_this_application_only" ) )
202     {
203         if ( focusedInputContext )
204         {
205             for ( cc = contextList.first(); cc; cc = contextList.next() )
206             {
207                 uim_switch_im( cc->uimContext(), ( const char* ) im_name );
208                 cc->readIMConf();
209                 uim_prop_update_custom( cc->uimContext(),
210                                         "custom-preserved-default-im-name",
211                                         ( const char* ) im_name_sym );
212             }
213         }
214     }
215 }
216 
sendImList()217 void QUimHelperManager::sendImList()
218 {
219     if ( !focusedInputContext )
220         return ;
221 
222     QString msg = "im_list\ncharset=UTF-8\n";
223     const char* current_im_name = uim_get_current_im_name( focusedInputContext->uimContext() );
224 
225     QUimInfoManager *infoManager = UimInputContextPlugin::getQUimInfoManager();
226     QValueList<uimInfo> info = infoManager->getUimInfo();
227     QValueList<uimInfo>::iterator it;
228 
229     for ( it = info.begin(); it != info.end(); ++it )
230     {
231         QString leafstr;
232         leafstr.sprintf( "%s\t%s\t%s\t",
233                          (const char *)( *it ).name,
234                          uim_get_language_name_from_locale( ( *it ).lang ),
235                          (const char *)( *it).short_desc );
236 
237         if ( QString::compare( ( *it ).name, current_im_name ) == 0 )
238             leafstr.append( "selected" );
239 
240         leafstr.append( "\n" );
241 
242         msg += leafstr;
243     }
244 
245     uim_helper_send_message( im_uim_fd, ( const char* ) msg.utf8() );
246 }
247 
send_im_change_whole_desktop(const char * name)248 void QUimHelperManager::send_im_change_whole_desktop( const char *name )
249 {
250     QString msg;
251 
252     msg.sprintf("im_change_whole_desktop\n%s\n", name);
253     uim_helper_send_message( im_uim_fd, ( const char* ) msg );
254 }
255 
helper_disconnect_cb()256 void QUimHelperManager::helper_disconnect_cb()
257 {
258     im_uim_fd = -1;
259 
260     if ( notifier )
261     {
262         delete notifier;
263         notifier = 0;
264     }
265 }
266 
update_prop_list_cb(void * ptr,const char * str)267 void QUimHelperManager::update_prop_list_cb( void *ptr, const char *str )
268 {
269     QUimInputContext *ic = ( QUimInputContext* ) ptr;
270     if ( ic != focusedInputContext || disableFocusedContext )
271         return;
272 
273     QString msg = "prop_list_update\ncharset=UTF-8\n";
274     msg += QString::fromUtf8( str );
275 
276     uim_helper_send_message( im_uim_fd, ( const char* ) msg.utf8() );
277 }
278 
update_prop_label_cb(void * ptr,const char * str)279 void QUimHelperManager::update_prop_label_cb( void *ptr, const char *str )
280 {
281     QUimInputContext *ic = ( QUimInputContext* ) ptr;
282     if ( ic != focusedInputContext || disableFocusedContext )
283         return;
284 
285     QString msg = "prop_label_update\ncharset=UTF-8\n";
286     msg += QString::fromUtf8( str );
287 
288     uim_helper_send_message( im_uim_fd, ( const char* ) msg.utf8() );
289 }
290 
291 #include "qhelpermanager.moc"
292