branches/KDE/3.5/kdelibs/kio/misc/kwalletd

Luboš Luňák l.lunak at kde.org
Tue Aug 29 16:09:38 BST 2006


SVN commit 578532 by lunakl:

Replace the wallet dialog hacks that were supposed to work around #91940
and caused #113057 with slightly better hacks. If somebody notices
some problems with kwallet dialogs after this change please yell.
CCMAIL: kde-core-devel at kde.org
BUG: 113057



 M  +50 -26    kwalletd.cpp  
 M  +7 -2      kwalletd.h  


--- branches/KDE/3.5/kdelibs/kio/misc/kwalletd/kwalletd.cpp #578531:578532
@@ -50,10 +50,6 @@
 
 #include <assert.h>
 
-#ifdef Q_WS_X11
-#include <X11/Xlib.h>
-#endif
-
 extern "C" {
    KDE_EXPORT KDEDModule *create_kwalletd(const QCString &name) {
 	   return new KWalletD(name);
@@ -67,6 +63,7 @@
 			tType = Unknown;
 			transaction = 0L;
 			client = 0L;
+			modal = false;
 		}
 
 		~KWalletTransaction() {
@@ -83,6 +80,7 @@
 		QCString appid;
 		uint wId;
 		QString wallet;
+		bool modal;
 };
 
 
@@ -149,7 +147,7 @@
 
 		switch (xact->tType) {
 			case KWalletTransaction::Open:
-				res = doTransactionOpen(xact->appid, xact->wallet, xact->wId);
+				res = doTransactionOpen(xact->appid, xact->wallet, xact->wId, xact->modal);
 				replyType = "int";
 				if (!xact->returnObject.isEmpty()) {
 					DCOPRef(xact->rawappid, xact->returnObject).send("walletOpenResult", res);
@@ -232,6 +230,7 @@
 	DCOPRef(appid, returnObject).send("walletOpenResult", 0);
 
 	QTimer::singleShot(0, this, SLOT(processTransactions()));
+	checkActiveDialog();
 }
 
 
@@ -266,18 +265,53 @@
 	xact->wallet = wallet;
 	xact->wId = wId;
 	xact->tType = KWalletTransaction::Open;
+	xact->modal = true; // mark dialogs as modal, the app has blocking wait
 	QTimer::singleShot(0, this, SLOT(processTransactions()));
+	checkActiveDialog();
 	return 0; // process later
 }
 
 
-int KWalletD::doTransactionOpen(const QCString& appid, const QString& wallet, uint wId) {
+// Sets up a dialog that will be shown by kwallet.
+void KWalletD::setupDialog( QWidget* dialog, WId wId, const QCString& appid, bool modal ) {
+	if( wId != 0 ) 
+		KWin::setMainWindow( dialog, wId ); // correct, set dialog parent
+	else {
+		if( appid.isEmpty())
+			kdWarning() << "Using kwallet without parent window!" << endl;
+		else
+			kdWarning() << "Application '" << appid << "' using kwallet without parent window!" << endl;
+		// allow dialog activation even if it interrupts, better than trying hacks
+		// with keeping the dialog on top or on all desktops
+		kapp->updateUserTimestamp();
+	}
+	if( modal )
+		KWin::setState( dialog->winId(), NET::Modal );
+	else
+		KWin::clearState( dialog->winId(), NET::Modal );
+	activeDialog = dialog;
+}
+
+// If there's a dialog already open and another application tries some operation that'd lead to
+// opening a dialog, that application will be blocked by this dialog. A proper solution would
+// be to set the second application's window also as a parent for the active dialog, so that
+// KWin properly handles focus changes and so on, but there's currently no support for multiple
+// dialog parents. Hopefully to be done in KDE4, for now just use all kinds of bad hacks to make
+//  sure the user doesn't overlook the active dialog.
+void KWalletD::checkActiveDialog() {
+	if( !activeDialog || !activeDialog->isShown())
+		return;
+	kapp->updateUserTimestamp();
+	KWin::setState( activeDialog->winId(), NET::KeepAbove );
+	KWin::setOnAllDesktops( activeDialog->winId(), true );
+	KWin::forceActiveWindow( activeDialog->winId());
+}
+
+int KWalletD::doTransactionOpen(const QCString& appid, const QString& wallet, uint wId, bool modal) {
 	if (_firstUse && !wallets().contains(KWallet::Wallet::LocalWallet())) {
 		// First use wizard
 		KWalletWizard *wiz = new KWalletWizard(0);
-#ifdef Q_WS_X11
-		XSetTransientForHint(qt_xdisplay(), wiz->winId(), wId);
-#endif
+		setupDialog( wiz, wId, appid, modal );
 		int rc = wiz->exec();
 		if (rc == QDialog::Accepted) {
 			KConfig cfg("kwalletrc");
@@ -317,12 +351,12 @@
 		cfg.sync();
 	}
 
-	int rc = internalOpen(appid, wallet, false, wId);
+	int rc = internalOpen(appid, wallet, false, wId, modal);
 	return rc;
 }
 
 
-int KWalletD::internalOpen(const QCString& appid, const QString& wallet, bool isPath, WId w) {
+int KWalletD::internalOpen(const QCString& appid, const QString& wallet, bool isPath, WId w, bool modal) {
 	int rc = -1;
 	bool brandNew = false;
 
@@ -402,11 +436,7 @@
 		const char *p = 0L;
 		while (!b->isOpen()) {
 			assert(kpd); // kpd can't be null if isOpen() is false
-#ifdef Q_WS_X11
-			XSetTransientForHint(qt_xdisplay(), kpd->winId(), w);
-#endif
-			KWin::setState( kpd->winId(), NET::KeepAbove );
-			KWin::setOnAllDesktops(kpd->winId(), true);
+			setupDialog( kpd, w, appid, modal );
 			if (kpd->exec() == KDialog::Accepted) {
 				p = kpd->password();
 				int rc = b->open(QByteArray().duplicate(p, strlen(p)));
@@ -489,12 +519,7 @@
 		} else {
 			dialog->setLabel(i18n("<qt>The application '<b>%1</b>' has requested access to the open wallet '<b>%2</b>'.").arg(QStyleSheet::escape(QString(appid))).arg(QStyleSheet::escape(wallet)));
 		}
-#ifdef Q_WS_X11
-		XSetTransientForHint(qt_xdisplay(), dialog->winId(), w);
-#endif
-		KWin::setState(dialog->winId(), NET::KeepAbove);
-		KWin::setOnAllDesktops(dialog->winId(), true);
-
+		setupDialog( dialog, w, appid, false );
 		response = dialog->exec();
 		delete dialog;
 	}
@@ -560,6 +585,7 @@
 	_transactions.append(xact);
 
 	QTimer::singleShot(0, this, SLOT(processTransactions()));
+	checkActiveDialog();
 }
 
 
@@ -576,7 +602,7 @@
 	}
 
 	if (!it.current()) {
-		handle = doTransactionOpen(appid, wallet, wId);
+		handle = doTransactionOpen(appid, wallet, wId,false);
 		if (-1 == handle) {
 			KMessageBox::sorryWId(wId, i18n("Unable to open wallet. The wallet must be opened in order to change the password."), i18n("KDE Wallet Service"));
 			return;
@@ -596,9 +622,7 @@
 	kpd->setPrompt(i18n("<qt>Please choose a new password for the wallet '<b>%1</b>'.").arg(QStyleSheet::escape(wallet)));
 	kpd->setCaption(i18n("KDE Wallet Service"));
 	kpd->setAllowEmptyPasswords(true);
-#ifdef Q_WS_X11
-	XSetTransientForHint(qt_xdisplay(), kpd->winId(), wId);
-#endif
+	setupDialog( kpd, wId, appid, false );
 	if (kpd->exec() == KDialog::Accepted) {
 		const char *p = kpd->password();
 		if (p) {
--- branches/KDE/3.5/kdelibs/kio/misc/kwalletd/kwalletd.h #578531:578532
@@ -26,6 +26,7 @@
 #include <qintdict.h>
 #include <qstring.h>
 #include <qwidget.h>
+#include <qguardedptr.h>
 #include "kwalletbackend.h"
 
 #include <time.h>
@@ -150,7 +151,7 @@
 		void processTransactions();
 
 	private:
-		int internalOpen(const QCString& appid, const QString& wallet, bool isPath = false, WId w = 0);
+		int internalOpen(const QCString& appid, const QString& wallet, bool isPath = false, WId w = 0, bool modal = false);
 		bool isAuthorizedApp(const QCString& appid, const QString& wallet, WId w);
 		// This also validates the handle.  May return NULL.
 		KWallet::Backend* getWallet(const QCString& appid, int handle);
@@ -169,8 +170,11 @@
 		QCString friendlyDCOPPeerName();
 
 		void doTransactionChangePassword(const QCString& appid, const QString& wallet, uint wId);
-		int doTransactionOpen(const QCString& appid, const QString& wallet, uint wId);
+		int doTransactionOpen(const QCString& appid, const QString& wallet, uint wId, bool modal);
 
+		void setupDialog( QWidget* dialog, WId wId, const QCString& appid, bool modal );
+		void checkActiveDialog();
+
 		QIntDict<KWallet::Backend> _wallets;
 		QMap<QCString,QValueList<int> > _handles;
 		QMap<QString,QCString> _passwords;
@@ -184,6 +188,7 @@
 		KTimeout *_timeouts;
 
 		QPtrList<KWalletTransaction> _transactions;
+		QGuardedPtr< QWidget > activeDialog;
 };
 
 




More information about the kde-core-devel mailing list