more cosmetic renames
[jrugr.git] / src / jrugr.cpp
bloba3cfbdf732969d1c621f5239ae2c98cb7177e85b
1 ////////////////////////////////////////
2 // Copyright : GPL //
3 ////////////////////////////////////////
4 #include "jrugr.h"
7 Jrugr::Jrugr (int &argc, char **argv) :
8 QApplication(argc, argv),
9 contextMenu(0),
10 rule(0),
11 xkbConf(0),
12 cfgForm(0)
14 // mandatory to keep it running after closing about dialogs...
15 setQuitOnLastWindowClosed(false);
16 keys = new XKeyboard();
17 setEventNames();
18 setWindowIcon(QIcon(":/about/jrugr.png"));
19 keys->groupInfo(mGroupInfo);
20 mActiveGroup = keys->activeGroup();
24 Jrugr::~Jrugr () {
25 delete keys;
26 delete cfgForm;
27 delete contextMenu;
28 delete xkbConf;
29 //! \warning the trayIcon *has* to be deleted here to prevent XFreeColormap() free corruption.
30 delete trayIcon;
34 void Jrugr::setEventNames () {
35 event_names.insert(0, "0");
36 event_names.insert(1, "1");
37 event_names.insert(2, "KeyPress");
38 event_names.insert(3, "KeyRelease");
39 event_names.insert(4, "ButtonPress");
40 event_names.insert(5, "ButtonRelease");
41 event_names.insert(6, "MotionNotify");
42 event_names.insert(7, "EnterNotify");
43 event_names.insert(8, "LeaveNotify");
44 event_names.insert(9, "FocusIn");
45 event_names.insert(10, "FocusOut");
46 event_names.insert(11, "KeymapNotify");
47 event_names.insert(12, "Expose");
48 event_names.insert(13, "GraphicsExpose");
49 event_names.insert(14, "NoExpose");
50 event_names.insert(15, "VisibilityNotify");
51 event_names.insert(16, "CreateNotify");
52 event_names.insert(17, "DestroyNotify");
53 event_names.insert(18, "UnmapNotify");
54 event_names.insert(19, "MapNotify");
55 event_names.insert(20, "MapRequest");
56 event_names.insert(21, "ReparentNotify");
57 event_names.insert(22, "ConfigureNotify");
58 event_names.insert(23, "ConfigureRequest");
59 event_names.insert(24, "GravityNotify");
60 event_names.insert(25, "ResizeRequest");
61 event_names.insert(26, "CirculateNotify");
62 event_names.insert(27, "CirculateRequest");
63 event_names.insert(28, "PropertyNotify");
64 event_names.insert(29, "SelectionClear");
65 event_names.insert(30, "SelectionRequest");
66 event_names.insert(31, "SelectionNotify");
67 event_names.insert(32, "ColormapNotify");
68 event_names.insert(33, "ClientMessage");
69 event_names.insert(34, "MappingNotify");
71 stat_names.insert(0, "DONT_USE_XKB");
72 stat_names.insert(1, "ONLY_INDICATION");
73 stat_names.insert(2, "USE_XKB");
77 void Jrugr::setStartup () {
78 // Display the config dialog only on first run.
79 // It was really annoying to see it all time
80 bool first = firstStart();
82 QSettings jrugr(QDir::homePath()+"/.config/jrugr.cfg", QSettings::IniFormat, this);
83 jrugr.beginGroup("Style");
84 map_path = jrugr.value("path").toString()+"/language/";
85 jrugr.endGroup(); //Style
86 xkbConf = X11tools::loadXKBconf();
87 trayIcon = new QSystemTrayIcon(this);
88 loadRules();
89 qDebug() << "Use next status:" << stat_names.value(xkbConf->status);
90 init();
91 if (xkbConf->status != DONT_USE_XKB) {
92 qDebug() << " Jrugr:XKB status:" << xkbConf->status;
93 if (xkbConf->status == USE_XKB) configureXkb();
94 qDebug() << " Jrugr:Show single:" << xkbConf->showSingle;
95 if (mGroupInfo.count() > 1 || xkbConf->showSingle) {
96 createMenu();
97 buildIcon();
98 } else {
99 if (first) configure();
101 } else {
102 //if (first) show the cfg dialog whenthere is no tray icon
103 configure();
108 bool Jrugr::firstStart () {
109 if (!QFile::exists(QDir::homePath()+"/.config/jrugr.cfg")) {
110 qDebug() << " Jrugr:Config file not found in:" << QDir::homePath();
111 qDebug() << " Jrugr:Create new";
112 QSettings jrugr(QDir::homePath()+"/.config/jrugr.cfg", QSettings::IniFormat, this);
113 QString themePath;
114 QDir themeDir("/usr/share/jrugr/theme/default");
115 if (themeDir.exists()) themePath = themeDir.path();
116 else themePath = QCoreApplication::applicationDirPath()+"/theme/default";;
117 jrugr.beginGroup("Style");
118 map_path = themePath;
119 jrugr.setValue("path", map_path);
120 jrugr.endGroup(); //Style
121 return true;
123 return false;
127 bool Jrugr::x11EventFilter (XEvent *event) {
128 qDebug() << "Jrugr::x11EventFilter:" << event_names[event->type];
129 switch (event->type) {
130 case FocusIn:
131 qDebug() << "FocusIn:" << (int)(event->xfocus.window);
132 break;
133 case PropertyNotify:
134 qDebug() << "PropertyNotify:" << (int)(event->xproperty.window);
135 default:
136 keys->processEvent(event);
137 return false;
139 return false;
143 void Jrugr::init () {
144 keys->groupInfo(mGroupInfo);
145 if (xkbConf->status == DONT_USE_XKB) return;
146 connect(keys, SIGNAL(groupChanged(int)), this, SLOT(groupChange(int)));
147 connect(keys, SIGNAL(layoutChanged()), this, SLOT(layoutChange()));
148 connect(this, SIGNAL(changeLayout(int)), this, SLOT(onChangeLayout(int)));
152 void Jrugr::buildIcon () {
153 QString sym;
155 if (mGroupInfo.count() == 0) return;
156 if (xkbConf->status == DONT_USE_XKB) {
157 qDebug() << "Jrugr::buildIcon() exit";
158 exit();
160 sym = mGroupInfo[mActiveGroup].sym;
162 trayIcon->setContextMenu(contextMenu);
163 connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(trayClicked(QSystemTrayIcon::ActivationReason)));
164 trayIcon->setToolTip(mGroupInfo[mActiveGroup].name);
165 QString PNGfile = map_path+"/"+fixLayoutName(sym)+".png";
166 QString SVGfile = map_path+"/"+fixLayoutName(sym)+".svg";
167 bool havePNG = QFile::exists(PNGfile);
168 bool haveSVG = QFile::exists(SVGfile);
169 QSvgRenderer flagSVG;
171 if (haveSVG) {
172 flagSVG.load(SVGfile);
173 haveSVG = haveSVG && flagSVG.isValid();
176 if (xkbConf->showFlag && (havePNG || haveSVG)) {
177 if (haveSVG) {
178 QPixmap pix(32, 22);
179 QPainter painter;
180 painter.begin(&pix);
181 flagSVG.render(&painter, QRectF(0, 0, 32, 22));
182 painter.end();
183 trayIcon->setIcon(QIcon(pix));
184 } else if (havePNG) {
185 trayIcon->setIcon(QIcon(PNGfile));
187 } else {
188 qDebug() << ":::" << sym;
189 QFont font("Helvetica [Cronyx]", 15);
190 //QFont font("Tahoma", 15);
191 font.setBold(true);
192 font.setLetterSpacing(QFont::PercentageSpacing, 120);
193 QPixmap pix(sym.length()*20, 26);
194 QPainter painter;
195 painter.begin(&pix);
196 painter.setFont(font);
197 painter.fillRect(pix.rect(), Qt::darkGray);
198 painter.setPen(Qt::white);
199 painter.drawText(pix.rect(), Qt::AlignVCenter|Qt::AlignCenter, sym);
200 painter.end();
201 trayIcon->setIcon(QIcon(pix));
203 if (xkbConf->status > 1) trayIcon->setContextMenu(contextMenu);
204 trayIcon->show();
208 void Jrugr::trayClicked (QSystemTrayIcon::ActivationReason reason) {
209 switch (reason) {
210 case QSystemTrayIcon::Trigger: setNextGroup(); break;
211 case QSystemTrayIcon::DoubleClick: setNextGroup(); break;
212 case QSystemTrayIcon::MiddleClick: setPrevGroup(); break;
213 default: ;
218 void Jrugr::layoutChange () {
219 qDebug()<<"Jrugr::layoutChange : reconfig";
220 reconfigure();
221 qDebug()<<"Jrugr::layoutChange : done";
225 void Jrugr::groupChange (int index) {
226 if (xkbConf->status == DONT_USE_XKB) return;
227 qDebug() << "Jrugr::groupChange: index:" << index;
228 mActiveGroup = index;
229 buildIcon();
233 int Jrugr::setKeyLayout (QString keyConf) {
234 qDebug() << "Jrugr::setKeyLayout:" << keyConf;
235 QStringList argument = keyConf.split(" ");
236 qDebug() << " Jrugr:setxkbmap argumetns:" << argument;
237 int result = QProcess::execute("setxkbmap", argument);
238 qDebug() << " Jrugr:setxkbmap result:" << result;
239 return result;
243 void Jrugr::setNextGroup () {
244 keys->setActiveGroup(mActiveGroup+1>=mGroupInfo.size()?0:mActiveGroup+1);
248 void Jrugr::setPrevGroup () {
249 keys->setActiveGroup(mActiveGroup-1<0?mGroupInfo.size()-1:mActiveGroup-1);
253 void Jrugr::createMenu () {
254 qDebug() << "Jrugr::createMenu" << mGroupInfo.size();
256 if (!contextMenu) contextMenu = new QMenu();
257 contextMenu->clear();
259 for (int index = 0; index < mGroupInfo.size(); ++index) {
260 QString lname = mGroupInfo[index].name, lsym = mGroupInfo[index].sym;
262 qDebug() << " layout:" << fixLayoutName(lsym) << "lname:" << lname << "sym:" << lsym;
264 QAction *act = new QAction(lname, this);
265 QString PNGfile = map_path+fixLayoutName(lsym)+".png";
266 QString SVGfile = map_path+fixLayoutName(lsym)+".svg";
268 if (QFile::exists(SVGfile)) {
269 QSvgRenderer flagSVG(SVGfile);
271 if (flagSVG.isValid()) {
272 QPixmap pix(32, 22);
273 QPainter painter;
274 painter.begin(&pix);
275 flagSVG.render(&painter, QRectF(0, 0, 32, 22));
276 painter.end();
277 act->setIcon(QIcon(pix));
278 } else if (QFile::exists(PNGfile)) {
279 act->setIcon(QIcon(PNGfile));
281 } else if (QFile::exists(PNGfile)) {
282 act->setIcon(QIcon(PNGfile));
284 act->setData(lname);
285 contextMenu->addAction(act);
288 contextMenu->addSeparator();
289 QAction *config = new QAction(tr("Configure"), this);
290 config->setData("configure");
291 contextMenu->addAction(config);
293 contextMenu->addSeparator();
294 QAction *about_qt = new QAction(tr("About Qt"), this);
295 about_qt->setData("about_qt");
296 contextMenu->addAction(about_qt);
298 QAction *about_jrugr = new QAction(tr("About Jrugr"), this);
299 about_jrugr->setData("about_jrugr");
300 contextMenu->addAction(about_jrugr);
302 contextMenu->addSeparator();
304 QAction *jrugrExit = new QAction(tr("Exit"), this);
305 jrugrExit->setData("exit");
306 contextMenu->addAction(jrugrExit);
308 connect(contextMenu, SIGNAL(triggered(QAction *)), SLOT(actionsActivate(QAction *)));
312 void Jrugr::reconfigure () {
313 XKBConf *newConf = X11tools::loadXKBconf();
314 QXkbLayoutList nl;
315 keys->groupInfo(nl);
316 bool diffGI = nl.size() != mGroupInfo.size();
318 if (!diffGI) {
319 for (int f = nl.size()-1; f >= 0; --f) if (nl[f].name != mGroupInfo[f].name || nl[f].sym != mGroupInfo[f].sym) { diffGI = true; break; }
322 if (diffGI || newConf->layouts != xkbConf->layouts || newConf->showFlag != xkbConf->showFlag ||
323 newConf->showSingle != xkbConf->showSingle || newConf->status != xkbConf->status) {
324 /*! \todo This prevent crashing when I remove one language from the
325 destination list. QStringList then contains ("us", "cz", "") and the
326 empty string causes a crash. There should be bettre way how to fix it imho... */
327 delete xkbConf;
328 xkbConf = newConf;
329 init();
330 createMenu();
331 buildIcon();
332 } else {
333 delete newConf;
338 void Jrugr::configureXkb () {
339 if (xkbConf->status == DONT_USE_XKB) return;
340 model = xkbConf->model;
341 for (int f = 0; f < xkbConf->layouts.count(); ++f) {
342 layout += xkbConf->layouts[f].layout;
343 variant += xkbConf->layouts[f].variant;
344 if (f < xkbConf->layouts.count()-1) { layout += ','; variant += ','; }
346 option = xkbConf->options.join(",");
347 qDebug() << "Set layout:" << layout;
348 if (!(model.isEmpty() || model.isNull()) && !(layout.isEmpty() || layout.isNull())) {
349 QString args = "-model "+model+" -layout "+layout;
350 QString tmp = variant;
351 if (!variant.isNull() && !variant.isEmpty() && !tmp.remove(",").isEmpty()) args +=" -variant "+variant;
352 if (!option.isNull() && !option.isEmpty()) args +=" -option "+option;
353 qDebug() << " Jrugr:XKB args " << args;
354 if (setKeyLayout(args) == QProcess::CrashExit) {
355 qDebug() << " Jrugr:XKB isn`t set";
356 qDebug() << " Jrugr:------------------------------";
357 return;
359 qDebug() << " Jrugr:XKB set";
364 void Jrugr::onChangeLayout (int index) {
365 qDebug() << "Jrugr::changeLayout:" << index;
366 for (int f = 5; f > 0; --f) keys->setActiveGroup(index); // k8: don't even ask me why this loop is here
370 void Jrugr::actionsActivate (QAction *action) {
371 QString cmd = action->data().toString();
373 qDebug() << "Jrugr::actionsActivate() command" << cmd;
374 if (cmd == "configure") {
375 configure();
376 } else if (cmd == "about_qt") {
377 aboutQt();
378 } else if (cmd == "about_jrugr") {
379 QMessageBox::about(0,
380 tr("About Jrugr"),
381 tr("<h2>Jrugr, the keyboard layout switcher</h2>"
382 "<b>Version</b>: %1<p>"
383 "Gui tool to configure XKB extentions of X server.<p>"
384 "(c) 2009-2011 Fedor Chelbarakh, Petr Vanek, Ketmar").arg(JRUGR_VERSION));
385 } else if (cmd == "exit") {
386 qDebug() << "Jrugr::actionsActivate() exit";
387 quit();
388 } else {
389 for (int f = mGroupInfo.size()-1; f >= 0; --f) {
390 if (cmd == mGroupInfo[f].name) {
391 //qDebug() << " FOUND!" << f;
392 //keys->setActiveGroup(f);
393 emit changeLayout(f);
394 break;
401 void Jrugr::configure () {
402 if (!cfgForm) {
403 cfgForm = new JrugrConfigForm();
404 xkbConf->lockKeys = true;
405 connect(cfgForm, SIGNAL(saveConfig()), SLOT(reconfigure()));
407 cfgForm->exec();
411 bool Jrugr::loadRules () {
412 /*Load aceptet keyboard language layouts and options from X11
413 (like en,ru,ua etc.)
414 and create list for configuration window
415 Some code taken from kxkb project
416 do no remove this
418 QString x11dir = X11tools::findX11Dir();
419 if (x11dir.isNull() || x11dir.isEmpty()) return false;
420 QString rulesFile = X11tools::findXkbRulesFile(x11dir,QX11Info::display());
421 if (rulesFile.isNull() || rulesFile.isEmpty()) return false;
422 delete rule;
423 rule = X11tools::loadRules(rulesFile,false);
424 return rule!=0;