1 /***************************************************************************
2 * Copyright (C) 2005-2008 by Tarek Saidi, Felix Geyer *
3 * tarek.saidi@arcor.de *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; version 2 of the License. *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19 ***************************************************************************/
21 #include "AutoTypeGlobalX11.h"
23 #include "mainwindow.h"
24 #include "lib/HelperX11.h"
25 #include "dialogs/AutoTypeDlg.h"
28 AutoTypeGlobal* autoType = NULL;
30 void initAutoType(KeepassMainWindow* mainWin) {
31 autoType = new AutoTypeGlobalX11(mainWin);
34 AutoTypeGlobalX11::AutoTypeGlobalX11(KeepassMainWindow* mainWin) : AutoTypeX11(mainWin) {
35 wm_state = XInternAtom(dpy, "WM_STATE", true);
36 windowRoot = XRootWindow(dpy, mainWin->x11Info().screen());
41 inGlobalAutoType = false;
43 //windowBlacklist << "kicker" << "KDE Desktop";
44 classBlacklist << "desktop_window" << "gnome-panel"; // Gnome
45 classBlacklist << "kdesktop" << "kicker"; // KDE 3
46 classBlacklist << "Plasma"; // KDE 4
47 classBlacklist << "xfdesktop" << "xfce4-panel"; // Xfce 4
50 void AutoTypeGlobalX11::updateKeymap() {
51 AutoTypeX11::updateKeymap();
52 registerGlobalShortcut(shortcut);
55 void AutoTypeGlobalX11::perform(IEntryHandle* entry, bool hideWindow, int nr, bool wasLocked){
58 inGlobalAutoType = true;
60 if (focusedWindow && (!hideWindow || wasLocked)) { // detect if global auto-type
61 XSetInputFocus(dpy, focusedWindow, RevertToPointerRoot, CurrentTime);
68 AutoTypeX11::perform(entry, hideWindow, nr, wasLocked);
70 inGlobalAutoType = false;
73 void AutoTypeGlobalX11::windowTitles(Window window, QStringList& titleList){
76 unsigned long nitems, after;
78 XGetWindowProperty(dpy, window, wm_state, 0, 0, false, AnyPropertyType, &type, &format, &nitems, &after, &data);
80 XTextProperty textProp;
81 if (XGetWMName(dpy, window, &textProp) != 0) {
84 if (Xutf8TextPropertyToTextList(dpy, &textProp, &list, &count)>=0 && list){
85 QString title = QString::fromUtf8(list[0]);
88 XClassHint* wmClass = XAllocClassHint();
89 if (XGetClassHint(dpy, window, wmClass)!=0 && wmClass->res_name!=NULL)
90 className = QString::fromLocal8Bit(wmClass->res_name);
93 if (window!=windowRoot && window!=mainWin->winId() &&
94 (QApplication::activeWindow()==NULL || window!=QApplication::activeWindow()->winId()) &&
95 // !windowBlacklist.contains(title) &&
96 (className.isNull() || !classBlacklist.contains(className))
98 titleList.append(title);
100 XFreeStringList(list);
107 Window* children = NULL;
108 unsigned int num_children;
109 int tree = XQueryTree(dpy, window, &root, &parent, &children, &num_children);
110 if (tree && children) {
111 for (uint i=0; i<num_children; i++)
112 windowTitles(children[i], titleList);
119 QStringList AutoTypeGlobalX11::getAllWindowTitles(){
120 QStringList titleList;
121 if (wm_state) // don't do anything if WM_STATE doesn't exist
122 windowTitles(windowRoot, titleList);
126 void AutoTypeGlobalX11::performGlobal(){
127 if (AutoTypeDlg::isDialogVisible()) {
128 qWarning("Already performing auto-type, ignoring this one");
132 focusWindow = getFocusWindow();
134 bool wasLocked = mainWin->isLocked();
136 mainWin->OnUnLockWorkspace();
138 if (!mainWin->isOpened())
142 int revert_to_return;
143 XGetInputFocus(dpy, &w, &revert_to_return);
147 XTextProperty textProp;
148 if (XGetWMName(dpy, w, &textProp) != 0) {
150 if (Xutf8TextPropertyToTextList(dpy, &textProp, &list, &count)<0) return;
155 Window* children = NULL;
156 unsigned int num_children;
157 tree = XQueryTree(dpy, w, &root, &parent, &children, &num_children);
159 if (children) XFree(children);
162 QString title = QString::fromUtf8(list[0]).toLower();
163 XFreeStringList(list);
165 QList<IEntryHandle*> validEntries;
166 QList<int> entryNumbers;
167 QList<IEntryHandle*> entries = mainWin->db->entries();
168 QRegExp lineMatch("Auto-Type-Window(?:-(\\d+)|):([^\\n]+)", Qt::CaseInsensitive, QRegExp::RegExp2);
169 QDateTime now = QDateTime::currentDateTime();
170 for (int i=0; i<entries.size(); i++){
171 if ( (entries[i]->expire()!=Date_Never && entries[i]->expire()<now) ||
172 (getRootGroupName(entries[i]).compare("backup",Qt::CaseInsensitive)==0)
177 bool hasWindowEntry=false;
178 QString comment = entries[i]->comment();
180 while ( (offset=lineMatch.indexIn(comment, offset))!=-1 ){
181 QStringList captured = lineMatch.capturedTexts();
182 offset += captured[0].length();
186 if (captured.size()==2){
188 entryWindow = captured[1].trimmed().toLower();
191 nr = captured[1].toInt();
192 entryWindow = captured[2].trimmed().toLower();
194 if (entryWindow.length()==0) continue;
196 hasWindowEntry = true;
197 bool wildStart = (entryWindow[0]=='*');
198 bool wildEnd = (entryWindow[entryWindow.size()-1]=='*');
199 if (wildStart&&wildEnd){
200 entryWindow.remove(0,1);
201 if (entryWindow.length()!=0){
202 entryWindow.remove(entryWindow.size()-1,1);
203 valid = title.contains(entryWindow);
209 entryWindow.remove(0,1);
210 valid = title.endsWith(entryWindow);
213 entryWindow.remove(entryWindow.size()-1,1);
214 valid = title.startsWith(entryWindow);
217 valid = (title==entryWindow);
221 validEntries << entries[i];
227 if (!hasWindowEntry && config->entryTitlesMatch()){
228 QString entryTitle = entries[i]->title().toLower();
229 if (!entryTitle.isEmpty() && title.contains(entryTitle)){
230 validEntries << entries[i];
236 if (validEntries.size()==1){
238 perform(validEntries[0],wasLocked,entryNumbers[0],wasLocked);
240 else if (validEntries.size()>1){
242 AutoTypeDlg* dlg = new AutoTypeDlg(validEntries, entryNumbers, wasLocked);
247 bool AutoTypeGlobalX11::registerGlobalShortcut(const Shortcut& s){
251 int code=XKeysymToKeycode(dpy, HelperX11::getKeysym(s.key));
252 uint mod=HelperX11::getShortcutModifierMask(s);
254 if (s.key==shortcut.key && s.ctrl==shortcut.ctrl && s.shift==shortcut.shift && s.alt==shortcut.alt && s.altgr==shortcut.altgr && s.win==shortcut.win && code==oldCode && mod==oldMod)
257 HelperX11::startCatchErrors();
258 XGrabKey(dpy, code, mod, windowRoot, true, GrabModeAsync, GrabModeAsync);
259 XGrabKey(dpy, code, mod | Mod2Mask, windowRoot, true, GrabModeAsync, GrabModeAsync);
260 XGrabKey(dpy, code, mod | LockMask, windowRoot, true, GrabModeAsync, GrabModeAsync);
261 XGrabKey(dpy, code, mod | Mod2Mask | LockMask, windowRoot, true, GrabModeAsync, GrabModeAsync);
262 HelperX11::stopCatchErrors();
264 if (HelperX11::errorOccurred()){
265 XUngrabKey(dpy, code, mod, windowRoot);
266 XUngrabKey(dpy, code, mod | Mod2Mask, windowRoot);
267 XUngrabKey(dpy, code, mod | LockMask, windowRoot);
268 XUngrabKey(dpy, code, mod | Mod2Mask | LockMask, windowRoot);
272 unregisterGlobalShortcut();
280 void AutoTypeGlobalX11::unregisterGlobalShortcut(){
281 if (shortcut.key==0) return;
283 XUngrabKey(dpy, oldCode, oldMod, windowRoot);
284 XUngrabKey(dpy, oldCode, oldMod | Mod2Mask, windowRoot);
285 XUngrabKey(dpy, oldCode, oldMod | LockMask, windowRoot);
286 XUngrabKey(dpy, oldCode, oldMod | Mod2Mask | LockMask, windowRoot);
293 QString AutoTypeGlobalX11::getRootGroupName(IEntryHandle* entry){
294 IGroupHandle* group = entry->group();
295 int level = group->level();
296 for (int i=0; i<level; i++)
297 group = group->parent();
299 return group->title();