• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

IJHack / QtPass / 25579973242

08 May 2026 09:16PM UTC coverage: 28.036% (+0.005%) from 28.031%
25579973242

push

github

web-flow
refactor: enable bugprone-* in clang-tidy + fix narrowing conversions (#1435)

After clearing the modernize-* / performance-* findings in #1432,
extended the .clang-tidy check set to include bugprone-* with two
exclusions for noise that doesn't fit the project's idioms:

- bugprone-throwing-static-initialization (67 findings): every
  static QString / QRegularExpression in the codebase. Standard Qt
  pattern; these constructors don't throw in practice. Disabling
  matches the convention in most Qt projects.

- bugprone-easily-swappable-parameters (22 findings): adjacent
  same-typed parameters. Stylistic; would require API-breaking
  signature changes that Qt's slot wiring expects.

That left 10 real bugprone-narrowing-conversions findings, all
qsizetype → int truncations (Qt 6 returns 64-bit qsizetype from
indexOf/size/count, but a lot of the codebase uses int).

Pattern: prefer qsizetype where the value stays internal; cast at
Qt-API boundaries that take int.

- configdialog.cpp setRowCount: static_cast<int> (Qt API)
- executor.cpp var.indexOf: int → qsizetype
- filecontent.cpp line.indexOf: int → qsizetype
- mainwindow.cpp tr count: static_cast<int> (Qt API)
- pass.cpp lastIndexOf: int → qsizetype
- pass.cpp *count = recipients.size(): static_cast<int> (out-param)
- passworddialog.cpp template indices: int → qsizetype
- qtpass.cpp prompt index: int → qsizetype

Validation:
- clang-tidy with new config: 0 findings in QtPass-owned code.
- tst_util: 106/106 pass.
- Full build clean.

cert-* yields no unique findings beyond bugprone aliases (the only
one was cert-err58-cpp = bugprone-throwing-static-initialization),
so not separately enabled.

4 of 7 new or added lines in 6 files covered. (57.14%)

1 existing line in 1 file now uncovered.

1854 of 6613 relevant lines covered (28.04%)

27.12 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

6.72
/src/qtpass.cpp
1
// SPDX-FileCopyrightText: 2018 Anne Jan Brouwer
2
// SPDX-License-Identifier: GPL-3.0-or-later
3
#include "qtpass.h"
4
#include "mainwindow.h"
5
#include "qtpasssettings.h"
6
#include "util.h"
7
#include <QApplication>
8
#include <QClipboard>
9
#include <QDialog>
10
#include <QLabel>
11
#include <QPixmap>
12
#include <QVBoxLayout>
13

14
#ifndef Q_OS_WIN
15
#include <QInputDialog>
16
#include <QLineEdit>
17
#include <QMimeData>
18
#include <utility>
19
#else
20
#define WIN32_LEAN_AND_MEAN /*_KILLING_MACHINE*/
21
#define WIN32_EXTRA_LEAN
22
#include <windows.h>
23
#include <winnetwk.h>
24
#undef DELETE
25
#include <QMimeData>
26
#endif
27

28
#ifdef QT_DEBUG
29
#include "debughelper.h"
30
#endif
31

32
/**
33
 * @brief Constructs a QtPass instance.
34
 * @param mainWindow The main window reference
35
 */
36
QtPass::QtPass(MainWindow *mainWindow) : m_mainWindow(mainWindow) {
×
37
  setClipboardTimer();
×
38
  clearClipboardTimer.setSingleShot(true);
×
39
  connect(&clearClipboardTimer, &QTimer::timeout, this,
×
40
          &QtPass::clearClipboard);
×
41

42
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
43
#pragma GCC diagnostic push
44
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
45
#endif
46
  QObject::connect(qApp, &QApplication::aboutToQuit, this,
×
47
                   &QtPass::clearClipboard);
×
48
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
49
#pragma GCC diagnostic pop
50
#endif
51

52
  setMainWindow();
×
53
}
×
54

55
/**
56
 * @brief QtPass::~QtPass destroy!
57
 */
58
QtPass::~QtPass() {
×
59
#ifdef Q_OS_WIN
60
  if (QtPassSettings::isUseWebDav())
61
    WNetCancelConnection2A(QtPassSettings::getPassStore().toUtf8().constData(),
62
                           0, 1);
63
#else
64
  if (fusedav.state() == QProcess::Running) {
×
65
    fusedav.terminate();
×
66
    fusedav.waitForFinished(2000);
×
67
  }
68
#endif
69
}
×
70

71
/**
72
 * @brief QtPass::init make sure we are ready to go as soon as
73
 * possible
74
 */
75
auto QtPass::init() -> bool {
×
76
  QString passStore = QtPassSettings::getPassStore(Util::findPasswordStore());
×
77
  QtPassSettings::setPassStore(passStore);
×
78

79
  QtPassSettings::initExecutables();
×
80

81
  QString version = QtPassSettings::getVersion();
×
82

83
  // Config updates
84
  if (version.isEmpty()) {
×
85
#ifdef QT_DEBUG
86
    dbg() << "assuming fresh install";
87
#endif
88

89
    if (QtPassSettings::getAutoclearSeconds() < 5) {
×
90
      QtPassSettings::setAutoclearSeconds(10);
×
91
    }
92
    if (QtPassSettings::getAutoclearPanelSeconds() < 5) {
×
93
      QtPassSettings::setAutoclearPanelSeconds(10);
×
94
    }
95
    if (!QtPassSettings::getPwgenExecutable().isEmpty()) {
×
96
      QtPassSettings::setUsePwgen(true);
×
97
    } else {
98
      QtPassSettings::setUsePwgen(false);
×
99
    }
100
    QtPassSettings::setPassTemplate("login\nurl");
×
101
  } else {
102
    if (QtPassSettings::getPassTemplate().isEmpty()) {
×
103
      QtPassSettings::setPassTemplate("login\nurl");
×
104
    }
105
  }
106

107
  QtPassSettings::setVersion(VERSION);
×
108

109
  if (!Util::configIsValid()) {
×
110
    m_mainWindow->config();
×
111
    if (freshStart && !Util::configIsValid()) {
×
112
      return false;
113
    }
114
  }
115

116
  // Note: WebDAV mount needs to happen before accessing the store,
117
  // but ideally should be done after Window is shown to avoid long delay.
118
  if (QtPassSettings::isUseWebDav()) {
×
119
    mountWebDav();
×
120
  }
121

122
  freshStart = false;
×
123
  return true;
×
124
}
125

126
/**
127
 * @brief Sets up the main window and connects signal handlers.
128
 */
129
void QtPass::setMainWindow() {
×
130
  m_mainWindow->restoreWindow();
×
131

132
  fusedav.setParent(m_mainWindow);
×
133

134
  // Signal handlers are connected for both pass implementations
135
  // Note: When pass binary changes, QtPass restart is required to reconnect
136
  // This is acceptable as pass binary change is infrequent
137
  connectPassSignalHandlers(QtPassSettings::getRealPass());
×
138
  connectPassSignalHandlers(QtPassSettings::getImitatePass());
×
139

140
  connect(m_mainWindow, &MainWindow::passShowHandlerFinished, this,
×
141
          &QtPass::passShowHandlerFinished);
×
142

143
  // only for ipass
144
  connect(QtPassSettings::getImitatePass(), &ImitatePass::startReencryptPath,
×
145
          m_mainWindow, &MainWindow::startReencryptPath);
×
146
  connect(QtPassSettings::getImitatePass(), &ImitatePass::endReencryptPath,
×
147
          m_mainWindow, &MainWindow::endReencryptPath);
×
148

149
  connect(m_mainWindow, &MainWindow::passGitInitNeeded, []() {
×
150
#ifdef QT_DEBUG
151
    dbg() << "Pass git init called";
152
#endif
153
    QtPassSettings::getPass()->GitInit();
×
154
  });
×
155

156
  connect(m_mainWindow, &MainWindow::generateGPGKeyPair, m_mainWindow,
×
157
          [this](const QString &batch) {
×
158
            QtPassSettings::getPass()->GenerateGPGKeys(batch);
×
159
            m_mainWindow->showStatusMessage(tr("Generating GPG key pair"),
×
160
                                            60000);
161
          });
×
162
}
×
163

164
/**
165
 * @brief Connects pass signal handlers to QtPass slots.
166
 * @param pass The pass instance to connect
167
 */
168
void QtPass::connectPassSignalHandlers(Pass *pass) {
×
169
  connect(pass, &Pass::error, this, &QtPass::processError);
×
170
  connect(pass, &Pass::processErrorExit, this, &QtPass::processErrorExit);
×
171
  connect(pass, &Pass::critical, m_mainWindow, &MainWindow::critical);
×
172
  connect(pass, &Pass::startingExecuteWrapper, m_mainWindow,
×
173
          &MainWindow::executeWrapperStarted);
×
174
  connect(pass, &Pass::statusMsg, m_mainWindow, &MainWindow::showStatusMessage);
×
175
  connect(pass, &Pass::finishedShow, m_mainWindow,
×
176
          &MainWindow::passShowHandler);
×
177
  connect(pass, &Pass::finishedOtpGenerate, m_mainWindow,
×
178
          &MainWindow::passOtpHandler);
×
179

180
  connect(pass, &Pass::finishedGitInit, this, &QtPass::passStoreChanged);
×
181
  connect(pass, &Pass::finishedGitPull, this, &QtPass::processFinished);
×
182
  connect(pass, &Pass::finishedGitPush, this, &QtPass::processFinished);
×
183
  connect(pass, &Pass::finishedInsert, this, &QtPass::finishedInsert);
×
184
  connect(pass, &Pass::finishedRemove, this, &QtPass::passStoreChanged);
×
185
  connect(pass, &Pass::finishedInit, this, &QtPass::passStoreChanged);
×
186
  connect(pass, &Pass::finishedMove, this, &QtPass::passStoreChanged);
×
187
  connect(pass, &Pass::finishedCopy, this, &QtPass::passStoreChanged);
×
188
  connect(pass, &Pass::finishedGenerateGPGKeys, this,
×
189
          &QtPass::onKeyGenerationComplete);
×
190
  connect(pass, &Pass::finishedGrep, m_mainWindow, &MainWindow::onGrepFinished);
×
191
}
×
192

193
/**
194
 * @brief QtPass::mountWebDav is some scary voodoo magic
195
 */
196
void QtPass::mountWebDav() {
×
197
#ifdef Q_OS_WIN
198
  char dst[20] = {0};
199
  NETRESOURCEA netres;
200
  memset(&netres, 0, sizeof(netres));
201
  netres.dwType = RESOURCETYPE_DISK;
202
  netres.lpLocalName = nullptr;
203
  // Store QByteArray in variables to ensure lifetime during WNetUseConnectionA
204
  // call
205
  QByteArray webDavUrlUtf8 = QtPassSettings::getWebDavUrl().toUtf8();
206
  QByteArray webDavPasswordUtf8 = QtPassSettings::getWebDavPassword().toUtf8();
207
  QByteArray webDavUserUtf8 = QtPassSettings::getWebDavUser().toUtf8();
208
  netres.lpRemoteName = const_cast<char *>(webDavUrlUtf8.constData());
209
  DWORD size = sizeof(dst);
210
  DWORD r = WNetUseConnectionA(
211
      reinterpret_cast<HWND>(m_mainWindow->effectiveWinId()), &netres,
212
      const_cast<char *>(webDavPasswordUtf8.constData()),
213
      const_cast<char *>(webDavUserUtf8.constData()),
214
      CONNECT_TEMPORARY | CONNECT_INTERACTIVE | CONNECT_REDIRECT, dst, &size,
215
      0);
216
  if (r == NO_ERROR) {
217
    QtPassSettings::setPassStore(dst);
218
  } else {
219
    char message[256] = {0};
220
    FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, 0, r, 0, message,
221
                   sizeof(message), 0);
222
    m_mainWindow->flashText(tr("Failed to connect WebDAV:\n") + message +
223
                                " (0x" + QString::number(r, 16) + ")",
224
                            true);
225
  }
226
#else
227
  fusedav.start("fusedav", QStringList()
×
228
                               << "-o"
×
229
                               << "nonempty"
×
230
                               << "-u"
×
231
                               << "\"" + QtPassSettings::getWebDavUser() + "\""
×
232
                               << QtPassSettings::getWebDavUrl()
×
233
                               << "\"" + QtPassSettings::getPassStore() + "\"");
×
234
  fusedav.waitForStarted();
×
235
  if (fusedav.state() == QProcess::Running) {
×
236
    QString pwd = QtPassSettings::getWebDavPassword();
×
237
    bool ok = true;
×
238
    if (pwd.isEmpty()) {
×
239
      pwd = QInputDialog::getText(m_mainWindow, tr("QtPass WebDAV password"),
×
240
                                  tr("Enter password to connect to WebDAV:"),
×
241
                                  QLineEdit::Password, "", &ok);
242
    }
243
    if (ok && !pwd.isEmpty()) {
×
244
      fusedav.write(pwd.toUtf8() + '\n');
×
245
      fusedav.closeWriteChannel();
×
246
      fusedav.waitForFinished(2000);
×
247
    } else {
248
      fusedav.terminate();
×
249
    }
250
  }
251
  QString error = fusedav.readAllStandardError();
×
NEW
252
  qsizetype prompt = error.indexOf("Password:");
×
253
  if (prompt >= 0) {
×
254
    error.remove(0, prompt + 10);
×
255
  }
256
  if (fusedav.state() != QProcess::Running) {
×
257
    error = tr("fusedav exited unexpectedly\n") + error;
×
258
  }
259
  if (error.size() > 0) {
×
260
    m_mainWindow->flashText(
×
261
        tr("Failed to start fusedav to connect WebDAV:\n") + error, true);
×
262
  }
263
#endif
264
}
×
265

266
/**
267
 * @brief QtPass::processError something went wrong
268
 * @param error
269
 */
270
void QtPass::processError(QProcess::ProcessError error) {
×
271
  QString errorString;
×
272
  switch (error) {
×
273
  case QProcess::FailedToStart:
×
274
    errorString = tr("QProcess::FailedToStart");
×
275
    break;
×
276
  case QProcess::Crashed:
×
277
    errorString = tr("QProcess::Crashed");
×
278
    break;
×
279
  case QProcess::Timedout:
×
280
    errorString = tr("QProcess::Timedout");
×
281
    break;
×
282
  case QProcess::ReadError:
×
283
    errorString = tr("QProcess::ReadError");
×
284
    break;
×
285
  case QProcess::WriteError:
×
286
    errorString = tr("QProcess::WriteError");
×
287
    break;
×
288
  case QProcess::UnknownError:
×
289
    errorString = tr("QProcess::UnknownError");
×
290
    break;
×
291
  }
292
  m_mainWindow->flashText(errorString, true);
×
293
  m_mainWindow->setUiElementsEnabled(true);
×
294
}
×
295

296
/**
297
 * @brief Handles process error exit.
298
 * @param exitCode The exit code
299
 * @param p_error The error message
300
 */
301
void QtPass::processErrorExit(int exitCode, const QString &p_error) {
×
302
  if (nullptr != m_mainWindow->getKeygenDialog()) {
×
303
    m_mainWindow->cleanKeygenDialog();
×
304
    if (exitCode != 0) {
×
305
      m_mainWindow->showStatusMessage(tr("GPG key pair generation failed"),
×
306
                                      10000);
307
    }
308
  }
309

310
  if (!p_error.isEmpty()) {
×
311
    QString output;
×
312
    QString error = p_error.toHtmlEscaped();
×
313
    if (exitCode == 0) {
×
314
      //  https://github.com/IJHack/qtpass/issues/111
315
      output = "<span style=\"color: darkgray;\">" + error + "</span><br />";
×
316
    } else {
317
      output = "<span style=\"color: red;\">" + error + "</span><br />";
×
318
    }
319

320
    output.replace(Util::protocolRegex(), R"(<a href="\1">\1</a>)");
×
321
    output.replace(QStringLiteral("\n"), "<br />");
×
322

323
    m_mainWindow->flashText(output, false, true);
×
324
  }
325

326
  m_mainWindow->setUiElementsEnabled(true);
×
327
}
×
328

329
/**
330
 * @brief QtPass::processFinished background process has finished
331
 * @param exitCode
332
 * @param exitStatus
333
 * @param output    stdout from a process
334
 * @param errout    stderr from a process
335
 */
336
void QtPass::processFinished(const QString &p_output, const QString &p_errout) {
×
337
  showInTextBrowser(p_output);
×
338
  //    Sometimes there is error output even with 0 exit code, which is
339
  //    assumed in this function
340
  processErrorExit(0, p_errout);
×
341

342
  m_mainWindow->setUiElementsEnabled(true);
×
343
}
×
344

345
/**
346
 * @brief Called when pass store has changed.
347
 * @param p_out Output from the process
348
 * @param p_err Error output
349
 */
350
void QtPass::passStoreChanged(const QString &p_out, const QString &p_err) {
×
351
  processFinished(p_out, p_err);
×
352
  doGitPush();
×
353
}
×
354

355
/**
356
 * @brief Called when an insert operation has finished.
357
 * @param p_output Output from the process
358
 * @param p_errout Error output
359
 */
360
void QtPass::finishedInsert(const QString &p_output, const QString &p_errout) {
×
361
  processFinished(p_output, p_errout);
×
362
  doGitPush();
×
363
  m_mainWindow->on_treeView_clicked(m_mainWindow->getCurrentTreeViewIndex());
×
364
}
×
365

366
/**
367
 * @brief Called when GPG key generation is complete.
368
 * @param p_output Standard output from the key generation process
369
 * @param p_errout Standard error output from the key generation process
370
 */
371
void QtPass::onKeyGenerationComplete(const QString &p_output,
×
372
                                     const QString &p_errout) {
373
  if (nullptr != m_mainWindow->getKeygenDialog()) {
×
374
#ifdef QT_DEBUG
375
    qDebug() << "Keygen Done";
376
#endif
377

378
    m_mainWindow->cleanKeygenDialog();
×
379
    m_mainWindow->showStatusMessage(tr("GPG key pair generated successfully"),
×
380
                                    10000);
381
  }
382

383
  processFinished(p_output, p_errout);
×
384
}
×
385

386
/**
387
 * @brief Called when the password show handler has finished.
388
 * @param output The password content to display
389
 */
390
void QtPass::passShowHandlerFinished(QString output) {
×
391
  showInTextBrowser(std::move(output));
×
392
}
×
393

394
/**
395
 * @brief Displays output text in the main window's text browser.
396
 * @param output The text to display
397
 * @param prefix Optional prefix to prepend to the output
398
 * @param postfix Optional postfix to append to the output
399
 */
400
void QtPass::showInTextBrowser(QString output, const QString &prefix,
×
401
                               const QString &postfix) {
402
  output = output.toHtmlEscaped();
×
403

404
  output.replace(Util::protocolRegex(), R"(<a href="\1">\1</a>)");
×
405
  output.replace(QStringLiteral("\n"), "<br />");
×
406
  output = prefix + output + postfix;
×
407

408
  m_mainWindow->flashText(output, false, true);
×
409
}
×
410

411
/**
412
 * @brief Performs automatic git push if enabled in settings.
413
 */
414
void QtPass::doGitPush() {
×
415
  if (QtPassSettings::isAutoPush()) {
×
416
    m_mainWindow->onPush();
×
417
  }
418
}
×
419

420
/**
421
 * @brief Sets the text to be stored in clipboard and handles clipboard
422
 * operations.
423
 * @param password The password or text to store
424
 * @param p_output Additional output text
425
 */
426
void QtPass::setClippedText(const QString &password, const QString &p_output) {
×
427
  if (QtPassSettings::getClipBoardType() != Enums::CLIPBOARD_NEVER &&
×
428
      !p_output.isEmpty()) {
429
    clippedText = password;
×
430
    if (QtPassSettings::getClipBoardType() == Enums::CLIPBOARD_ALWAYS) {
×
431
      copyTextToClipboard(password);
×
432
    }
433
  }
434
}
×
435
/**
436
 * @brief Clears the stored clipped text.
437
 */
438
void QtPass::clearClippedText() { clippedText = ""; }
×
439

440
/**
441
 * @brief Sets the clipboard clear timer based on autoclear settings.
442
 */
443
void QtPass::setClipboardTimer() {
×
444
  clearClipboardTimer.setInterval(MS_PER_SECOND *
×
445
                                  QtPassSettings::getAutoclearSeconds());
×
446
}
×
447

448
/**
449
 * @brief MainWindow::clearClipboard remove clipboard contents.
450
 */
451
void QtPass::clearClipboard() {
×
452
  QClipboard *clipboard = QApplication::clipboard();
×
453
  bool cleared = false;
454
  if (this->clippedText == clipboard->text(QClipboard::Selection)) {
×
455
    clipboard->clear(QClipboard::Selection);
×
456
    clipboard->setText(QString(""), QClipboard::Selection);
×
457
    cleared = true;
458
  }
459
  if (this->clippedText == clipboard->text(QClipboard::Clipboard)) {
×
460
    clipboard->clear(QClipboard::Clipboard);
×
461
    cleared = true;
462
  }
463
  if (cleared) {
×
464
    m_mainWindow->showStatusMessage(tr("Clipboard cleared"));
×
465
  } else {
466
    m_mainWindow->showStatusMessage(tr("Clipboard not cleared"));
×
467
  }
468

469
  clippedText.clear();
×
470
}
×
471

472
/**
473
 * @brief Build clipboard MIME data with platform-specific security hints.
474
 * @param text - Plain text to copy
475
 * @return QMimeData with text and security hints
476
 */
477
auto buildClipboardMimeData(const QString &text) -> QMimeData * {
1✔
478
  auto *mimeData = new QMimeData();
1✔
479
  mimeData->setText(text);
1✔
480
#ifdef Q_OS_LINUX
481
  mimeData->setData("x-kde-passwordManagerHint", QByteArray("secret"));
2✔
482
#endif
483
#ifdef Q_OS_MAC
484
  mimeData->setData("application/x-nspasteboard-concealed-type", QByteArray());
485
#endif
486
#ifdef Q_OS_WIN
487
  mimeData->setData("ExcludeClipboardContentFromMonitorProcessing",
488
                    dwordBytes(1));
489
  mimeData->setData("CanIncludeInClipboardHistory", dwordBytes(0));
490
  mimeData->setData("CanUploadToCloudClipboard", dwordBytes(0));
491
#endif
492
  return mimeData;
1✔
493
}
494

495
/**
496
 * @brief MainWindow::copyTextToClipboard copies text to your clipboard
497
 * @param text
498
 */
499
void QtPass::copyTextToClipboard(const QString &text) {
×
500
  QClipboard *clip = QApplication::clipboard();
×
501

502
  QClipboard::Mode mode = QClipboard::Clipboard;
503
  if (QtPassSettings::isUseSelection() && clip->supportsSelection()) {
×
504
    mode = QClipboard::Selection;
505
  }
506

507
  auto *mimeData = buildClipboardMimeData(text);
×
508
  clip->setMimeData(mimeData, mode);
×
509

510
  clippedText = text;
×
511
  m_mainWindow->showStatusMessage(tr("Copied to clipboard"));
×
512
  if (QtPassSettings::isUseAutoclear()) {
×
513
    clearClipboardTimer.start();
×
514
  }
515
}
×
516

517
/**
518
 * @brief displays the text as qrcode
519
 * @param text
520
 */
521
void QtPass::showTextAsQRCode(const QString &text) {
×
522
  QProcess qrencode;
×
523
  qrencode.start(QtPassSettings::getQrencodeExecutable("/usr/bin/qrencode"),
×
524
                 QStringList() << "-o-"
×
525
                               << "-tPNG");
×
526
  qrencode.write(text.toUtf8());
×
527
  qrencode.closeWriteChannel();
×
528
  qrencode.waitForFinished();
×
529
  QByteArray output(qrencode.readAllStandardOutput());
×
530

531
  if (qrencode.exitStatus() || qrencode.exitCode()) {
×
532
    QString error(qrencode.readAllStandardError());
×
533
    m_mainWindow->showStatusMessage(error);
×
534
  } else {
535
    QPixmap image;
×
536
    image.loadFromData(output, "PNG");
×
537
    QDialog *popup = createQRCodePopup(image);
×
538
    popup->exec();
×
539
  }
×
540
}
×
541

542
/**
543
 * @brief QtPass::createQRCodePopup creates a popup dialog with the given QR
544
 * code image. This is extracted for testability. The caller is responsible
545
 * for showing and managing the popup lifecycle.
546
 * @param image The QR code pixmap to display
547
 * @return The created popup dialog
548
 */
549
QDialog *QtPass::createQRCodePopup(const QPixmap &image) {
1✔
550
  auto *popup = new QDialog(nullptr, Qt::Popup | Qt::FramelessWindowHint);
1✔
551
  popup->setAttribute(Qt::WA_DeleteOnClose);
1✔
552
  auto *layout = new QVBoxLayout;
1✔
553
  auto *popupLabel = new QLabel();
1✔
554
  layout->addWidget(popupLabel);
1✔
555
  popupLabel->setPixmap(image);
1✔
556
  popupLabel->setScaledContents(true);
1✔
557
  popupLabel->show();
1✔
558
  popup->setLayout(layout);
1✔
559
  popup->move(QCursor::pos());
1✔
560
  return popup;
1✔
561
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc