diff --git a/qt/main.cpp b/qt/main.cpp index 70a009d..f236781 100644 --- a/qt/main.cpp +++ b/qt/main.cpp @@ -1,364 +1,382 @@ /* main.cpp - A Qt dialog for PIN entry. * Copyright (C) 2002, 2008 Klarälvdalens Datakonsult AB (KDAB) * Copyright (C) 2003 g10 Code GmbH * Copyright 2007 Ingo Klöcker * * Written by Steffen Hansen . * Modified by Marcus Brinkmann . * Modified by Marc Mutz * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * SPDX-License-Identifier: GPL-2.0+ */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "pinentryconfirm.h" #include "pinentrydialog.h" #include "pinentry.h" -#include +#include +#include #include -#include -#include -#include +#include #include +#include +#include +#include #include #include #include #include #include #ifdef FALLBACK_CURSES #include #endif #if QT_VERSION >= 0x050000 && defined(QT_STATIC) #include #ifdef Q_OS_WIN #include #include Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin) #elif defined(Q_OS_MAC) Q_IMPORT_PLUGIN(QCocoaIntegrationPlugin) #else Q_IMPORT_PLUGIN(QXcbIntegrationPlugin) #endif #endif +#ifdef Q_OS_WIN +#include +#endif + static QString escape_accel(const QString &s) { QString result; result.reserve(s.size()); bool afterUnderscore = false; for (unsigned int i = 0, end = s.size() ; i != end ; ++i) { const QChar ch = s[i]; if (ch == QLatin1Char('_')) { if (afterUnderscore) { // escaped _ result += QLatin1Char('_'); afterUnderscore = false; } else { // accel afterUnderscore = true; } } else { if (afterUnderscore || // accel ch == QLatin1Char('&')) { // escape & from being interpreted by Qt result += QLatin1Char('&'); } result += ch; afterUnderscore = false; } } if (afterUnderscore) // trailing single underscore: shouldn't happen, but deal with it robustly: { result += QLatin1Char('_'); } return result; } -/* Hack for creating a QWidget with a "foreign" window ID */ -class ForeignWidget : public QWidget -{ -public: - explicit ForeignWidget(WId wid) : QWidget(0) - { - QWidget::destroy(); - create(wid, false, false); - } - - ~ForeignWidget() - { - destroy(false, false); - } -}; - namespace { class InvalidUtf8 : public std::invalid_argument { public: InvalidUtf8() : std::invalid_argument("invalid utf8") {} ~InvalidUtf8() throw() {} }; } static const bool GPG_AGENT_IS_PORTED_TO_ONLY_SEND_UTF8 = false; static QString from_utf8(const char *s) { const QString result = QString::fromUtf8(s); if (result.contains(QChar::ReplacementCharacter)) { if (GPG_AGENT_IS_PORTED_TO_ONLY_SEND_UTF8) { throw InvalidUtf8(); } else { return QString::fromLocal8Bit(s); } } return result; } +static void +setup_foreground_window(QWidget *widget, WId parentWid) +{ + /* For windows set the desktop window as the transient parent */ + QWindow *parentWindow = nullptr; + if (parentWid) { + parentWindow = QWindow::fromWinId(parentWid); + } +#ifdef Q_OS_WIN + if (!parentWindow) { + HWND desktop = GetDesktopWindow(); + if (desktop) { + parentWindow = QWindow::fromWinId((WId) desktop); + } + } +#endif + if (parentWindow) { + // Ensure that we have a native wid + widget->winId(); + QWindow *wndHandle = widget->windowHandle(); + + if (wndHandle) { + wndHandle->setTransientParent(parentWindow); + } + } + widget->setWindowFlags(Qt::Window | + Qt::CustomizeWindowHint | + Qt::WindowTitleHint | + Qt::WindowCloseButtonHint | + Qt::WindowStaysOnTopHint | + Qt::WindowMinimizeButtonHint); +} + static int qt_cmd_handler(pinentry_t pe) { - QWidget *parent = 0; char *str; - /* FIXME: Add parent window ID to pinentry and GTK. */ - if (pe->parent_wid) { - parent = new ForeignWidget((WId) pe->parent_wid); - } - int want_pass = !!pe->pin; const QString ok = pe->ok ? escape_accel(from_utf8(pe->ok)) : pe->default_ok ? escape_accel(from_utf8(pe->default_ok)) : /* else */ QLatin1String("&OK") ; const QString cancel = pe->cancel ? escape_accel(from_utf8(pe->cancel)) : pe->default_cancel ? escape_accel(from_utf8(pe->default_cancel)) : /* else */ QLatin1String("&Cancel") ; str = pinentry_get_title (pe); const QString title = str ? from_utf8(str) : /* else */ QLatin1String("pinentry-qt") ; free (str); const QString repeatError = pe->repeat_error_string ? from_utf8(pe->repeat_error_string) : QLatin1String("Passphrases do not match"); const QString repeatString = pe->repeat_passphrase ? from_utf8(pe->repeat_passphrase) : QString(); const QString visibilityTT = pe->default_tt_visi ? from_utf8(pe->default_tt_visi) : QLatin1String("Show passphrase"); const QString hideTT = pe->default_tt_hide ? from_utf8(pe->default_tt_hide) : QLatin1String("Hide passphrase"); if (want_pass) { char *str; - PinEntryDialog pinentry(parent, 0, pe->timeout, true, !!pe->quality_bar, + PinEntryDialog pinentry(nullptr, 0, pe->timeout, true, !!pe->quality_bar, repeatString, visibilityTT, hideTT); - + setup_foreground_window(&pinentry, pe->parent_wid); pinentry.setPinentryInfo(pe); pinentry.setPrompt(escape_accel(from_utf8(pe->prompt))); pinentry.setDescription(from_utf8(pe->description)); pinentry.setRepeatErrorText(repeatError); str = pinentry_get_title (pe); if (str) { pinentry.setWindowTitle(from_utf8(str)); free (str); } /* If we reuse the same dialog window. */ pinentry.setPin(QString()); pinentry.setOkText(ok); pinentry.setCancelText(cancel); if (pe->error) { pinentry.setError(from_utf8(pe->error)); } if (pe->quality_bar) { pinentry.setQualityBar(from_utf8(pe->quality_bar)); } if (pe->quality_bar_tt) { pinentry.setQualityBarTT(from_utf8(pe->quality_bar_tt)); } bool ret = pinentry.exec(); if (!ret) { if (pinentry.timedOut()) pe->specific_err = gpg_error (GPG_ERR_TIMEOUT); return -1; } const QString pinStr = pinentry.pin(); QByteArray pin = pinStr.toUtf8(); if (!!pe->repeat_passphrase) { /* Should not have been possible to accept the dialog in that case but we do a safety check here */ pe->repeat_okay = (pinStr == pinentry.repeatedPin()); } int len = strlen(pin.constData()); if (len >= 0) { pinentry_setbufferlen(pe, len + 1); if (pe->pin) { strcpy(pe->pin, pin.constData()); return len; } } return -1; } else { const QString desc = pe->description ? from_utf8(pe->description) : QString(); const QString notok = pe->notok ? escape_accel(from_utf8(pe->notok)) : QString(); const QMessageBox::StandardButtons buttons = pe->one_button ? QMessageBox::Ok : pe->notok ? QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel : /* else */ QMessageBox::Ok | QMessageBox::Cancel ; - PinentryConfirm box(QMessageBox::Information, pe->timeout, title, desc, buttons, parent); + PinentryConfirm box(QMessageBox::Information, pe->timeout, title, desc, buttons, nullptr); + setup_foreground_window(&box, pe->parent_wid); const struct { QMessageBox::StandardButton button; QString label; } buttonLabels[] = { { QMessageBox::Ok, ok }, { QMessageBox::Yes, ok }, { QMessageBox::No, notok }, { QMessageBox::Cancel, cancel }, }; for (size_t i = 0 ; i < sizeof buttonLabels / sizeof * buttonLabels ; ++i) if ((buttons & buttonLabels[i].button) && !buttonLabels[i].label.isEmpty()) { box.button(buttonLabels[i].button)->setText(buttonLabels[i].label); #ifndef QT_NO_ACCESSIBILITY box.button(buttonLabels[i].button)->setAccessibleDescription(buttonLabels[i].label); #endif } box.setIconPixmap(icon()); if (!pe->one_button) { box.setDefaultButton(QMessageBox::Cancel); } box.show(); - raiseWindow(&box); + box.raise(); const int rc = box.exec(); if (rc == QMessageBox::Cancel) { pe->canceled = true; } if (box.timedOut()) { pe->specific_err = gpg_error (GPG_ERR_TIMEOUT); } return rc == QMessageBox::Ok || rc == QMessageBox::Yes ; } } static int qt_cmd_handler_ex(pinentry_t pe) { try { return qt_cmd_handler(pe); } catch (const InvalidUtf8 &) { pe->locale_err = true; return pe->pin ? -1 : false ; } catch (...) { pe->canceled = true; return pe->pin ? -1 : false ; } } pinentry_cmd_handler_t pinentry_cmd_handler = qt_cmd_handler_ex; int main(int argc, char *argv[]) { pinentry_init("pinentry-qt"); QApplication *app = NULL; #ifdef FALLBACK_CURSES if (!pinentry_have_display(argc, argv)) { pinentry_cmd_handler = curses_cmd_handler; pinentry_set_flavor_flag ("curses"); } else #endif { /* Qt does only understand -display but not --display; thus we are fixing that here. The code is pretty simply and may get confused if an argument is called "--display". */ char **new_argv, *p; size_t n; int i, done; for (n = 0, i = 0; i < argc; i++) { n += strlen(argv[i]) + 1; } n++; new_argv = (char **)calloc(argc + 1, sizeof * new_argv); if (new_argv) { *new_argv = (char *)malloc(n); } if (!new_argv || !*new_argv) { fprintf(stderr, "pinentry-qt: can't fixup argument list: %s\n", strerror(errno)); exit(EXIT_FAILURE); } for (done = 0, p = *new_argv, i = 0; i < argc; i++) if (!done && !strcmp(argv[i], "--display")) { new_argv[i] = strcpy(p, argv[i] + 1); p += strlen(argv[i] + 1) + 1; done = 1; } else { new_argv[i] = strcpy(p, argv[i]); p += strlen(argv[i]) + 1; } i = argc; app = new QApplication(i, new_argv); app->setWindowIcon(QIcon(QLatin1String(":/document-encrypt.png"))); } pinentry_parse_opts(argc, argv); int rc = pinentry_loop(); delete app; return rc ? EXIT_FAILURE : EXIT_SUCCESS ; } diff --git a/qt/pinentryconfirm.cpp b/qt/pinentryconfirm.cpp index 65b191c..e549e10 100644 --- a/qt/pinentryconfirm.cpp +++ b/qt/pinentryconfirm.cpp @@ -1,77 +1,77 @@ /* pinentryconfirm.cpp - A QMessageBox with a timeout * * Copyright (C) 2011 Ben Kibbey * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * SPDX-License-Identifier: GPL-2.0+ */ #include "pinentryconfirm.h" #include "pinentrydialog.h" #include #include #include #include PinentryConfirm::PinentryConfirm(Icon icon, int timeout, const QString &title, const QString &desc, StandardButtons buttons, QWidget *parent) : QMessageBox(icon, title, desc, buttons, parent) { _timed_out = false; if (timeout > 0) { _timer = new QTimer(this); connect(_timer, SIGNAL(timeout()), this, SLOT(slotTimeout())); _timer->start(timeout * 1000); } #ifndef QT_NO_ACCESSIBILITY setAccessibleDescription(desc); setAccessibleName(title); #endif - raiseWindow(this); + raise(); } bool PinentryConfirm::timedOut() const { return _timed_out; } void PinentryConfirm::showEvent(QShowEvent *event) { static bool resized; if (!resized) { QGridLayout* lay = dynamic_cast (layout()); if (lay) { QSize textSize = fontMetrics().size(Qt::TextExpandTabs, text(), fontMetrics().maxWidth()); QSpacerItem* horizontalSpacer = new QSpacerItem(textSize.width() + iconPixmap().width(), 0, QSizePolicy::Minimum, QSizePolicy::Expanding); lay->addItem(horizontalSpacer, lay->rowCount(), 1, 1, lay->columnCount() - 1); } resized = true; } QDialog::showEvent(event); - raiseWindow(this); + raise(); } void PinentryConfirm::slotTimeout() { QAbstractButton *b = button(QMessageBox::Cancel); _timed_out = true; if (b) { b->animateClick(0); } } #include "pinentryconfirm.moc" diff --git a/qt/pinentrydialog.cpp b/qt/pinentrydialog.cpp index cb52d7c..9bff8d2 100644 --- a/qt/pinentrydialog.cpp +++ b/qt/pinentrydialog.cpp @@ -1,476 +1,482 @@ /* pinentrydialog.cpp - A (not yet) secure Qt 4 dialog for PIN entry. * Copyright (C) 2002, 2008 Klarälvdalens Datakonsult AB (KDAB) * Copyright 2007 Ingo Klöcker * Copyright 2016 Intevation GmbH * * Written by Steffen Hansen . * Modified by Andre Heinecke * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * SPDX-License-Identifier: GPL-2.0+ */ #include "pinentrydialog.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef Q_OS_WIN #include #endif +#if 0 /* I [wk] have no idea for what this code was supposed to do. Foregrounding a window is heavily restricted by modern Windows versions. This is the reason why gpg-agent employs its AllowSetForegroundWindow callback machinery to ask the supposed to be be calling process to allow a pinentry to go into the foreground. [ah] This is a Hack to workaround the fact that Foregrounding a Window is so restricted that it AllowSetForegroundWindow does not always work (e.g. when the ForegroundWindow timeout has not expired. + + [ah 2018-02-28] Disabled this again in favor of using + windows stays on top hint. The code that is in main + setup_foreground_window. */ #ifdef Q_OS_WIN WINBOOL SetForegroundWindowEx(HWND hWnd) { //Attach foreground window thread to our thread const DWORD ForeGroundID = GetWindowThreadProcessId(::GetForegroundWindow(), NULL); const DWORD CurrentID = GetCurrentThreadId(); WINBOOL retval; AttachThreadInput(ForeGroundID, CurrentID, TRUE); //Do our stuff here HWND hLastActivePopupWnd = GetLastActivePopup(hWnd); retval = SetForegroundWindow(hLastActivePopupWnd); //Detach the attached thread AttachThreadInput(ForeGroundID, CurrentID, FALSE); return retval; }// End SetForegroundWindowEx #endif void raiseWindow(QWidget *w) { /* Maybe Qt will become aggressive enough one day that * this is enough on windows too*/ w->raise(); #ifdef Q_OS_WIN HWND wid = (HWND)w->effectiveWinId(); /* In the meantime we do our own attention grabbing */ if (!SetForegroundWindow(wid) && !SetForegroundWindowEx(wid)) { OutputDebugString("SetForegroundWindow (ex) failed"); /* Yet another fallback which will not work on some * versions and is not recommended by msdn */ if (!ShowWindow(wid, SW_SHOWNORMAL)) { OutputDebugString("ShowWindow failed."); } } /* Even if SetForgeoundWindow / SetForegroundWinowEx don't fail * we sometimes are still not in the foreground. So we try yet * another hack by using SetWindowPos */ if (!SetWindowPos(wid, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW)) { OutputDebugString("SetWindowPos failed."); } else { /* Without moving back to NOTOPMOST we just stay on top. * Even if the user changes focus. */ SetWindowPos(wid, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW); } #endif } +#endif + QPixmap icon(QStyle::StandardPixmap which) { QPixmap pm = qApp->windowIcon().pixmap(48, 48); if (which != QStyle::SP_CustomBase) { const QIcon ic = qApp->style()->standardIcon(which); QPainter painter(&pm); const int emblemSize = 22; painter.drawPixmap(pm.width() - emblemSize, 0, ic.pixmap(emblemSize, emblemSize)); } return pm; } void PinEntryDialog::slotTimeout() { _timed_out = true; reject(); } PinEntryDialog::PinEntryDialog(QWidget *parent, const char *name, int timeout, bool modal, bool enable_quality_bar, const QString &repeatString, const QString &visibilityTT, const QString &hideTT) - : QDialog(parent, Qt::WindowStaysOnTopHint), + : QDialog(parent), mRepeat(NULL), _grabbed(false), mVisibilityTT(visibilityTT), mHideTT(hideTT), mVisiActionEdit(NULL), mVisiCB(NULL) { _timed_out = false; - setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); if (modal) { setWindowModality(Qt::ApplicationModal); } _icon = new QLabel(this); _icon->setPixmap(icon()); _error = new QLabel(this); QPalette pal; pal.setColor(QPalette::WindowText, Qt::red); _error->setPalette(pal); _error->hide(); _desc = new QLabel(this); _desc->hide(); _prompt = new QLabel(this); _prompt->hide(); _edit = new QLineEdit(this); _edit->setMaxLength(256); _edit->setEchoMode(QLineEdit::Password); _prompt->setBuddy(_edit); if (enable_quality_bar) { _quality_bar_label = new QLabel(this); _quality_bar_label->setAlignment(Qt::AlignVCenter); _quality_bar = new QProgressBar(this); _quality_bar->setAlignment(Qt::AlignCenter); _have_quality_bar = true; } else { _have_quality_bar = false; } QDialogButtonBox *const buttons = new QDialogButtonBox(this); buttons->setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); _ok = buttons->button(QDialogButtonBox::Ok); _cancel = buttons->button(QDialogButtonBox::Cancel); _ok->setDefault(true); if (style()->styleHint(QStyle::SH_DialogButtonBox_ButtonsHaveIcons)) { _ok->setIcon(style()->standardIcon(QStyle::SP_DialogOkButton)); _cancel->setIcon(style()->standardIcon(QStyle::SP_DialogCancelButton)); } if (timeout > 0) { _timer = new QTimer(this); connect(_timer, SIGNAL(timeout()), this, SLOT(slotTimeout())); _timer->start(timeout * 1000); } else { _timer = NULL; } connect(buttons, SIGNAL(accepted()), this, SLOT(accept())); connect(buttons, SIGNAL(rejected()), this, SLOT(reject())); connect(_edit, SIGNAL(textChanged(QString)), this, SLOT(updateQuality(QString))); connect(_edit, SIGNAL(textChanged(QString)), this, SLOT(textChanged(QString))); _edit->setFocus(); QGridLayout *const grid = new QGridLayout(this); int row = 1; grid->addWidget(_error, row++, 1, 1, 2); grid->addWidget(_desc, row++, 1, 1, 2); //grid->addItem( new QSpacerItem( 0, _edit->height() / 10, QSizePolicy::Minimum, QSizePolicy::Fixed ), 1, 1 ); grid->addWidget(_prompt, row, 1); grid->addWidget(_edit, row++, 2); if (!repeatString.isNull()) { mRepeat = new QLineEdit; mRepeat->setMaxLength(256); mRepeat->setEchoMode(QLineEdit::Password); connect(mRepeat, SIGNAL(textChanged(QString)), this, SLOT(textChanged(QString))); QLabel *repeatLabel = new QLabel(repeatString); repeatLabel->setBuddy(mRepeat); grid->addWidget(repeatLabel, row, 1); grid->addWidget(mRepeat, row++, 2); setTabOrder(_edit, mRepeat); setTabOrder(mRepeat, _ok); } if (enable_quality_bar) { grid->addWidget(_quality_bar_label, row, 1); grid->addWidget(_quality_bar, row++, 2); } /* Set up the show password action */ const QIcon visibilityIcon = QIcon::fromTheme(QLatin1String("visibility")); const QIcon hideIcon = QIcon::fromTheme(QLatin1String("hint")); #if QT_VERSION >= 0x050200 if (!visibilityIcon.isNull() && !hideIcon.isNull()) { mVisiActionEdit = _edit->addAction(visibilityIcon, QLineEdit::TrailingPosition); mVisiActionEdit->setVisible(false); mVisiActionEdit->setToolTip(mVisibilityTT); connect(mVisiActionEdit, SIGNAL(triggered()), this, SLOT(toggleVisibility())); } else #endif { if (!mVisibilityTT.isNull()) { mVisiCB = new QCheckBox(mVisibilityTT); connect(mVisiCB, SIGNAL(toggled(bool)), this, SLOT(toggleVisibility())); grid->addWidget(mVisiCB, row++, 1, 1, 2, Qt::AlignLeft); } } grid->addWidget(buttons, ++row, 0, 1, 3); grid->addWidget(_icon, 0, 0, row - 1, 1, Qt::AlignVCenter | Qt::AlignLeft); grid->setSizeConstraint(QLayout::SetFixedSize); connect(qApp, SIGNAL(focusChanged(QWidget *, QWidget *)), this, SLOT(focusChanged(QWidget *, QWidget *))); } void PinEntryDialog::showEvent(QShowEvent *event) { QDialog::showEvent(event); - raiseWindow(this); + raise(); } void PinEntryDialog::setDescription(const QString &txt) { _desc->setVisible(!txt.isEmpty()); _desc->setText(txt); #ifndef QT_NO_ACCESSIBILITY _desc->setAccessibleDescription(txt); #endif _icon->setPixmap(icon()); setError(QString::null); } QString PinEntryDialog::description() const { return _desc->text(); } void PinEntryDialog::setError(const QString &txt) { if (!txt.isNull()) { _icon->setPixmap(icon(QStyle::SP_MessageBoxCritical)); } _error->setText(txt); #ifndef QT_NO_ACCESSIBILITY _error->setAccessibleDescription(txt); #endif _error->setVisible(!txt.isEmpty()); } QString PinEntryDialog::error() const { return _error->text(); } void PinEntryDialog::setPin(const QString &txt) { _edit->setText(txt); } QString PinEntryDialog::pin() const { return _edit->text(); } void PinEntryDialog::setPrompt(const QString &txt) { _prompt->setText(txt); _prompt->setVisible(!txt.isEmpty()); } QString PinEntryDialog::prompt() const { return _prompt->text(); } void PinEntryDialog::setOkText(const QString &txt) { _ok->setText(txt); #ifndef QT_NO_ACCESSIBILITY _ok->setAccessibleDescription(txt); #endif _ok->setVisible(!txt.isEmpty()); } void PinEntryDialog::setCancelText(const QString &txt) { _cancel->setText(txt); #ifndef QT_NO_ACCESSIBILITY _cancel->setAccessibleDescription(txt); #endif _cancel->setVisible(!txt.isEmpty()); } void PinEntryDialog::setQualityBar(const QString &txt) { if (_have_quality_bar) { _quality_bar_label->setText(txt); #ifndef QT_NO_ACCESSIBILITY _quality_bar_label->setAccessibleDescription(txt); #endif } } void PinEntryDialog::setQualityBarTT(const QString &txt) { if (_have_quality_bar) { _quality_bar->setToolTip(txt); } } void PinEntryDialog::updateQuality(const QString &txt) { int length; int percent; QPalette pal; if (_timer) { _timer->stop(); } if (!_have_quality_bar || !_pinentry_info) { return; } const QByteArray utf8_pin = txt.toUtf8(); const char *pin = utf8_pin.constData(); length = strlen(pin); percent = length ? pinentry_inq_quality(_pinentry_info, pin, length) : 0; if (!length) { _quality_bar->reset(); } else { pal = _quality_bar->palette(); if (percent < 0) { pal.setColor(QPalette::Highlight, QColor("red")); percent = -percent; } else { pal.setColor(QPalette::Highlight, QColor("green")); } _quality_bar->setPalette(pal); _quality_bar->setValue(percent); } } void PinEntryDialog::setPinentryInfo(pinentry_t peinfo) { _pinentry_info = peinfo; } void PinEntryDialog::focusChanged(QWidget *old, QWidget *now) { // Grab keyboard. It might be a little weird to do it here, but it works! // Previously this code was in showEvent, but that did not work in Qt4. if (!_pinentry_info || _pinentry_info->grab) { if (_grabbed && old && (old == _edit || old == mRepeat)) { old->releaseKeyboard(); _grabbed = false; } if (!_grabbed && now && (now == _edit || now == mRepeat)) { now->grabKeyboard(); _grabbed = true; } } } void PinEntryDialog::textChanged(const QString &text) { Q_UNUSED(text); if (mRepeat && mRepeat->text() == _edit->text()) { _ok->setEnabled(true); _ok->setToolTip(QString()); } else if (mRepeat) { _ok->setEnabled(false); _ok->setToolTip(mRepeatError); } if (mVisiActionEdit && sender() == _edit) { mVisiActionEdit->setVisible(!_edit->text().isEmpty()); } } void PinEntryDialog::toggleVisibility() { if (sender() == mVisiActionEdit) { if (_edit->echoMode() == QLineEdit::Password) { mVisiActionEdit->setIcon(QIcon::fromTheme(QLatin1String("hint"))); mVisiActionEdit->setToolTip(mHideTT); _edit->setEchoMode(QLineEdit::Normal); if (mRepeat) { mRepeat->setEchoMode(QLineEdit::Normal); } } else { mVisiActionEdit->setIcon(QIcon::fromTheme(QLatin1String("visibility"))); mVisiActionEdit->setToolTip(mVisibilityTT); _edit->setEchoMode(QLineEdit::Password); if (mRepeat) { mRepeat->setEchoMode(QLineEdit::Password); } } } if (sender() == mVisiCB) { if (mVisiCB->isChecked()) { if (mRepeat) { mRepeat->setEchoMode(QLineEdit::Normal); } _edit->setEchoMode(QLineEdit::Normal); } else { if (mRepeat) { mRepeat->setEchoMode(QLineEdit::Password); } _edit->setEchoMode(QLineEdit::Password); } } } QString PinEntryDialog::repeatedPin() const { if (mRepeat) { return mRepeat->text(); } return QString(); } bool PinEntryDialog::timedOut() const { return _timed_out; } void PinEntryDialog::setRepeatErrorText(const QString &err) { mRepeatError = err; } #include "pinentrydialog.moc"