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 "qt.h"
36
37 #include <qapplication.h>
38 #include <qlistview.h>
39 #include <qvbuttongroup.h>
40 #include <qradiobutton.h>
41 #include <qsocketnotifier.h>
42 #include <qpushbutton.h>
43 #include <qtextcodec.h>
44 #include <qevent.h>
45 #include <qlayout.h>
46 #include <qsizepolicy.h>
47
48 #include <stdlib.h>
49 #include <locale.h>
50
51 #include <uim/uim-scm.h>
52 #include <uim/uim-custom.h>
53 #include "qtgettext.h"
54
55 #define NAME_COLUMN 0
56
57 static int uim_fd;
58 static bool customEnabled;
59 static QSocketNotifier *notifier = NULL;
60
main(int argc,char ** argv)61 int main( int argc, char **argv )
62 {
63 setlocale(LC_ALL, "");
64 bindtextdomain(PACKAGE, LOCALEDIR);
65 textdomain(PACKAGE);
66 bind_textdomain_codeset(PACKAGE, "UTF-8"); // ensure code encoding is UTF8-
67
68 setenv("XMODIFIERS", "@im=none", 1);
69
70 QApplication a( argc, argv );
71
72 UimImSwitcher switcher;
73 switcher.resize( 550, 400 );
74 switcher.setCaption( _( "uim input method switcher" ) );
75 a.setMainWidget( &switcher );
76 switcher.show();
77
78 return a.exec();
79 }
80
81
UimImSwitcher(QWidget * parent,const char * name)82 UimImSwitcher::UimImSwitcher( QWidget *parent, const char *name )
83 : QDialog( parent, name )
84 {
85 /* connect to uim helper message bus */
86 uim_fd = -1;
87 checkHelperConnection();
88
89 /* to check if another uim-im-switcher exists */
90 uim_helper_send_message( uim_fd, "im_switcher_start\n" );
91
92 /* to load input method list */
93 uim_helper_send_message( uim_fd, "im_list_get\n" );
94
95 uim_init();
96 customEnabled = uim_custom_enable();
97
98 /* create GUI */
99 createGUI();
100 }
101
~UimImSwitcher()102 UimImSwitcher::~UimImSwitcher()
103 {
104 }
105
createGUI()106 void UimImSwitcher::createGUI()
107 {
108 /* im list view */
109 listview = new QListView( this );
110 listview->setSelectionMode( QListView::Single );
111 listview->setAllColumnsShowFocus( true );
112 listview->addColumn( _( "InputMethodName" ) );
113 listview->addColumn( _( "Language" ) );
114 listview->addColumn( _( "Description" ) );
115
116 /* radio buttons for the switcher coverage */
117 QRadioButton *button;
118 vbGroup = new QVButtonGroup( _( "Effective coverage" ), this );
119 button = new QRadioButton( _( "whole desktop" ), vbGroup );
120 vbGroup->insert( button, ID_CHANGE_WHOLE_DESKTOP );
121 button->setChecked( TRUE ); // default is "whole desktop"
122 button = new QRadioButton( _( "current application only" ), vbGroup );
123 vbGroup->insert( button, ID_CHANGE_THIS_APPLICATION_ONLY );
124 button = new QRadioButton( _( "current text area only" ), vbGroup );
125 vbGroup->insert( button, ID_CHANGE_THIS_TEXT_AREA_ONLY );
126
127 /* cancel & ok button */
128 okButton = new QPushButton( this );
129 okButton->setText( _( "OK" ) );
130 okButton->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed );
131 QObject::connect( okButton, SIGNAL( clicked() ),
132 this, SLOT( slotChangeInputMethod() ) );
133 cancelButton = new QPushButton( this );
134 cancelButton->setText( _( "Cancel" ) );
135 cancelButton->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed );
136 QObject::connect( cancelButton, SIGNAL( clicked() ),
137 qApp, SLOT( quit() ) );
138 QHBoxLayout *buttonLayout = new QHBoxLayout;
139 buttonLayout->addStretch( 0 );
140 buttonLayout->addWidget( okButton );
141 buttonLayout->addWidget( cancelButton );
142
143 // main layout
144 QVBoxLayout *mainLayout = new QVBoxLayout( this );
145 mainLayout->setMargin( 6 );
146 mainLayout->setSpacing( 6 );
147 mainLayout->addWidget( listview );
148 mainLayout->addWidget( vbGroup );
149 mainLayout->addLayout( buttonLayout );
150 }
151
152
checkHelperConnection()153 void UimImSwitcher::checkHelperConnection()
154 {
155 if ( uim_fd < 0 )
156 {
157 uim_fd = uim_helper_init_client_fd( helper_disconnect_cb );
158 if ( uim_fd > 0 )
159 {
160 if ( notifier )
161 delete notifier;
162 notifier = new QSocketNotifier( uim_fd, QSocketNotifier::Read );
163 QObject::connect( notifier, SIGNAL( activated( int ) ),
164 this, SLOT( slotStdinActivated( int ) ) );
165 }
166 }
167 }
168
helper_disconnect_cb()169 void UimImSwitcher::helper_disconnect_cb()
170 {
171 uim_fd = -1;
172 QObject::disconnect( notifier, SIGNAL( activated( int ) ), 0, 0 );
173 }
174
slotChangeInputMethod()175 void UimImSwitcher::slotChangeInputMethod()
176 {
177
178 switch ( vbGroup->selectedId() )
179 {
180 case ID_CHANGE_WHOLE_DESKTOP:
181 sendMessageImChange( "im_change_whole_desktop\n" );
182 saveDefaultIm();
183 break;
184 case ID_CHANGE_THIS_APPLICATION_ONLY:
185 sendMessageImChange( "im_change_this_application_only\n" );
186 break;
187 case ID_CHANGE_THIS_TEXT_AREA_ONLY:
188 sendMessageImChange( "im_change_this_text_area_only\n" );
189 break;
190 default:
191 break;
192 }
193
194 qApp->quit();
195 }
196
sendMessageImChange(const QString & change_type)197 void UimImSwitcher::sendMessageImChange( const QString &change_type )
198 {
199 QString imName = selectedImName();
200 if ( imName.isEmpty() )
201 return ;
202
203 /* ensuring connected to message bus */
204 checkHelperConnection();
205
206 QString msg = QString::null;
207 msg.append( change_type );
208 msg.append( imName );
209 msg.append( "\n" );
210
211 uim_helper_send_message( uim_fd, ( const char* ) msg.utf8() );
212 }
213
saveDefaultIm()214 void UimImSwitcher::saveDefaultIm()
215 {
216 if ( customEnabled )
217 {
218 QString imName = selectedImName();
219 if ( imName.isEmpty() )
220 return ;
221
222 uim_scm_callf( "custom-set-value!",
223 "yy",
224 "custom-preserved-default-im-name",
225 ( const char* ) imName.utf8() );
226 uim_custom_save_custom( "custom-preserved-default-im-name" );
227 }
228 }
229
selectedImName() const230 QString UimImSwitcher::selectedImName() const
231 {
232 QListViewItem * selectedItem = listview->selectedItem();
233 if ( selectedItem )
234 {
235 return selectedItem->text( NAME_COLUMN );
236 }
237
238 return QString::null;
239 }
240
slotStdinActivated(int)241 void UimImSwitcher::slotStdinActivated( int /*socket*/ )
242 {
243 uim_helper_read_proc( uim_fd );
244
245 QString msg = QString::null;
246 char *s;
247 while ( ( s = uim_helper_get_message() ) )
248 {
249 const QStringList lines = QStringList::split( "\n", QString( s ) );
250 if ( !lines.isEmpty() && !lines[ 1 ].isEmpty() && lines[ 1 ].startsWith( "charset" ) )
251 {
252 /* get charset */
253 const QString charset = QStringList::split( "=", lines[ 1 ] ) [ 1 ];
254
255 /* convert to unicode */
256 QTextCodec *codec = QTextCodec::codecForName( charset );
257 msg = codec->toUnicode( s );
258 }
259 else
260 {
261 /* no charset */
262 msg = s;
263 }
264
265 if ( msg.startsWith( "focus_in" ) )
266 reloadImList();
267 else if ( msg.startsWith( "im_list" ) )
268 parseHelperStrImList( msg );
269 else if ( msg.startsWith( "im_switcher_start" ) )
270 uim_helper_send_message( uim_fd, "im_switcher_quit\n" );
271 else if ( msg.startsWith( "im_switcher_quit" ) )
272 qApp->quit();
273 }
274 }
275
276
parseHelperStrImList(const QString & message)277 void UimImSwitcher::parseHelperStrImList( const QString &message )
278 {
279 /* delete old items */
280 listview->clear();
281
282 const QStringList lines = QStringList::split( "\n", message );
283 for ( unsigned int i = 2; i < lines.count(); i++ )
284 {
285 const QStringList iminfoList = QStringList::split( "\t", lines[ i ], true );
286
287 if ( !iminfoList.isEmpty()
288 && !iminfoList[ 0 ].isEmpty()
289 // Language of IM with any locale is set as "".
290 // && !iminfoList[ 1 ].isEmpty()
291 && !iminfoList[ 2 ].isEmpty() )
292 {
293 QString lang, short_desc;
294
295 if (iminfoList[1].isEmpty())
296 lang = QString("-");
297 else
298 lang = QString::fromUtf8(gettext(iminfoList[1].utf8()));
299 short_desc = QString::fromUtf8(gettext(iminfoList[2].utf8()));
300
301 // add new item to listview
302 QListViewItem * item = new QListViewItem( listview, iminfoList[ 0 ], lang, short_desc );
303
304 if ( !iminfoList[ 3 ].isEmpty() && QString::compare( iminfoList[ 3 ], "selected" ) == 0 )
305 listview->setSelected( item, TRUE );
306 }
307 }
308 }
309
reloadImList()310 void UimImSwitcher::reloadImList()
311 {
312 checkHelperConnection();
313
314 /* send request to get im list */
315 uim_helper_send_message( uim_fd, "im_list_get\n" );
316 }
317
318 #include "qt.moc"
319