Page MenuHomePhabricator (Chris)

No OneTemporary

Authored By
Unknown
Size
243 KB
Referenced Files
None
Subscribers
None
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..09b4d02
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+*.2-pre1
\ No newline at end of file
diff --git a/dialogs/historydialog.cpp b/dialogs/historydialog.cpp
index dd8312f..5638ca2 100644
--- a/dialogs/historydialog.cpp
+++ b/dialogs/historydialog.cpp
@@ -1,288 +1,288 @@
#include "historydialog.h"
#include "ui_historydialog.h"
#include "../tools/os.h"
#include "../tools/uploader.h"
#include "../tools/screenshotmanager.h"
#include <QClipboard>
#include <QDesktopServices>
#include <QDir>
#include <QFile>
#include <QFileInfo>
#include <QFileSystemWatcher>
#include <QMenu>
#include <QMessageBox>
#include <QSortFilterProxyModel>
#include <QUrl>
#include <QSettings>
#include <QtSql/QSqlDatabase>
#include <QtSql/QSqlTableModel>
#include <QDebug>
HistoryDialog::HistoryDialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::HistoryDialog)
{
ui->setupUi(this);
ui->filterEdit->setText(tr("Filter.."));
ui->filterEdit->installEventFilter(this);
if (QSqlDatabase::database().isOpen())
{
mModel = new QSqlTableModel(this);
mModel->setTable("history");
mModel->setHeaderData(0, Qt::Horizontal, tr("Screenshot"));
mModel->setHeaderData(1, Qt::Horizontal, tr("URL"));
mModel->select();
mFilterModel = new QSortFilterProxyModel(mModel);
mFilterModel->setSourceModel(mModel);
mFilterModel->setDynamicSortFilter(true);
mFilterModel->setSortCaseSensitivity(Qt::CaseInsensitive);
mFilterModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
mFilterModel->setFilterKeyColumn(-1);
while (mModel->canFetchMore()) {
mModel->fetchMore();
}
ui->tableView->setModel(mFilterModel);
ui->tableView->hideColumn(2); // No delete hash.
ui->tableView->hideColumn(3); // No timestamp.
-/*
- ui->tableView->horizontalHeader()->setClickable(false);
- ui->tableView->horizontalHeader()->setMovable(false);
- ui->tableView->horizontalHeader()->setResizeMode(0, QHeaderView::Stretch);
- ui->tableView->horizontalHeader()->setResizeMode(1, QHeaderView::ResizeToContents);
-*/
+ ui->tableView->horizontalHeader()->setSectionsClickable(false);
+ ui->tableView->horizontalHeader()->setSectionsMovable(false);
+
+ ui->tableView->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
+ ui->tableView->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
+
ui->tableView->verticalHeader()->hide();
ui->tableView->setTextElideMode(Qt::ElideLeft);
ui->tableView->setEditTriggers(QAbstractItemView::NoEditTriggers);
ui->tableView->setAlternatingRowColors(true);
ui->tableView->setSelectionMode(QAbstractItemView::SingleSelection);
ui->tableView->setContextMenuPolicy(Qt::CustomContextMenu);
ui->tableView->setSortingEnabled(true);
if (ui->tableView->model()->rowCount() > 0)
{
ui->clearButton->setEnabled(true);
ui->filterEdit->setEnabled(true);
}
connect(ui->tableView->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), this, SLOT(selectionChanged(QItemSelection,QItemSelection)));
connect(ui->tableView, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(open(QModelIndex)));
connect(ui->tableView, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(contextMenu(QPoint)));
}
else {
ui->tableView->setEnabled(false);
ui->clearButton->setEnabled(false);
}
ui->uploadProgressBar->setValue (Uploader::instance()->progressSent());
if (Uploader::instance()->progressTotal() == 0) {
ui->uploadProgressBar->setMaximum(1);
}
else {
ui->uploadProgressBar->setMaximum(Uploader::instance()->progressTotal());
}
connect(Uploader::instance(), SIGNAL(progress(qint64,qint64)), this, SLOT(uploadProgress(qint64, qint64)));
connect(Uploader::instance(), SIGNAL(done(QString,QString,QString)), this, SLOT(refresh()));
connect(ui->uploadButton, SIGNAL(clicked()), this, SLOT(upload()));
connect(ui->clearButton , SIGNAL(clicked()), this, SLOT(clear()));
}
HistoryDialog::~HistoryDialog()
{
delete ui;
}
void HistoryDialog::clear()
{
if (QMessageBox::question(this,
tr("Clearing the screenshot history"),
tr("Are you sure you want to clear your entire screenshot history?\nThis cannot be undone."),
tr("Clear History"),
tr("Don't Clear")) == 1) {
return;
}
ScreenshotManager::instance()->clearHistory();
close();
}
void HistoryDialog::contextMenu(QPoint point)
{
mContextIndex = ui->tableView->indexAt(point);;
QMenu contextMenu(ui->tableView);
QAction copyAction((mContextIndex.column() == 0) ? tr("Copy Path") : tr("Copy URL"), &contextMenu);
connect(&copyAction, SIGNAL(triggered()), this, SLOT(copy()));
contextMenu.addAction(&copyAction);
QAction deleteAction(tr("Delete from imgur.com"), &contextMenu);
QAction locationAction(tr("Open Location"), &contextMenu);
QAction removeAction(tr("Remove history entry"), &contextMenu);
if (mContextIndex.data().toString().isEmpty()) {
copyAction.setEnabled(false);
deleteAction.setEnabled(false);
}
if (mContextIndex.column() == 0) {
connect(&locationAction, SIGNAL(triggered()), this, SLOT(location()));
contextMenu.addAction(&locationAction);
}
else {
connect(&deleteAction, SIGNAL(triggered()), this, SLOT(deleteImage()));
contextMenu.addAction(&deleteAction);
}
connect(&removeAction, SIGNAL(triggered()), this, SLOT(removeHistoryEntry()));
contextMenu.addAction(&removeAction);
contextMenu.exec(QCursor::pos());
}
void HistoryDialog::copy()
{
qApp->clipboard()->setText(mContextIndex.data().toString());
}
void HistoryDialog::deleteImage()
{
QDesktopServices::openUrl(mContextIndex.sibling(mContextIndex.row(), 2).data().toString());
}
void HistoryDialog::location()
{
QDesktopServices::openUrl("file:///" + QFileInfo(mContextIndex.data().toString()).absolutePath());
}
void HistoryDialog::removeHistoryEntry()
{
if (mContextIndex.column() == 0) {
// File got right clicked:
ScreenshotManager::instance()->removeHistory(mContextIndex.data().toString(), mContextIndex.sibling(mContextIndex.row(), 3).data().toLongLong());
}
else {
// Screenshot URL got right clicked:
ScreenshotManager::instance()->removeHistory(mContextIndex.sibling(mContextIndex.row(), 0).data().toString(), mContextIndex.sibling(mContextIndex.row(), 3).data().toLongLong());
}
refresh();
}
void HistoryDialog::refresh()
{
mModel->select();
}
void HistoryDialog::open(QModelIndex index)
{
if (index.column() == 0) {
QDesktopServices::openUrl(QUrl("file:///" + index.data().toString()));
}
else {
QDesktopServices::openUrl(index.data().toUrl());
}
}
void HistoryDialog::selectionChanged(QItemSelection selected, QItemSelection deselected)
{
Q_UNUSED(deselected);
if (selected.indexes().count() == 0){
return;
}
QModelIndex index = selected.indexes().at(0);
QString screenshot;
if (index.column() == 0) {
screenshot = index.data().toString();
}
else {
screenshot = ui->tableView->model()->index(index.row(), 0).data().toString();
}
mSelectedScreenshot = screenshot;
ui->uploadButton->setEnabled(QFile::exists(screenshot));
}
void HistoryDialog::upload()
{
Uploader::instance()->upload(mSelectedScreenshot);
ui->uploadButton->setEnabled(false);
}
void HistoryDialog::uploadProgress(qint64 sent, qint64 total)
{
ui->uploadProgressBar->setEnabled(true);
ui->uploadProgressBar->setMaximum(total);
ui->uploadProgressBar->setValue(sent);
}
bool HistoryDialog::eventFilter(QObject *object, QEvent *event)
{
if (object == ui->filterEdit) {
if (event->type() == QEvent::FocusIn)
{
if (ui->filterEdit->text() == tr("Filter..")) {
ui->filterEdit->setStyleSheet("");
ui->filterEdit->setText("");
mFilterModel->setFilterWildcard("");
mFilterModel->sort(3, Qt::DescendingOrder);
}
}
else if (event->type() == QEvent::FocusOut)
{
if (ui->filterEdit->text() == "") {
ui->filterEdit->setStyleSheet("color: palette(mid);");
ui->filterEdit->setText(tr("Filter.."));
mFilterModel->sort(3, Qt::DescendingOrder);
}
}
else if (event->type() == QEvent::KeyRelease)
{
if (ui->filterEdit->text() != tr("Filter..") && !ui->filterEdit->text().isEmpty()) {
mFilterModel->setFilterWildcard(ui->filterEdit->text());
mFilterModel->sort(3, Qt::DescendingOrder);
}
else {
mFilterModel->setFilterWildcard("");
mFilterModel->sort(3, Qt::DescendingOrder);
}
}
}
return QDialog::eventFilter(object, event);
}
bool HistoryDialog::event(QEvent *event)
{
if (event->type() == QEvent::Show)
{
restoreGeometry(ScreenshotManager::instance()->settings()->value("geometry/historyDialog").toByteArray());
}
else if (event->type() == QEvent::Close)
{
ScreenshotManager::instance()->settings()->setValue("geometry/historyDialog", saveGeometry());
}
return QDialog::event(event);
}
diff --git a/dialogs/optionsdialog.cpp b/dialogs/optionsdialog.cpp
index 3573aac..b05b7dd 100644
--- a/dialogs/optionsdialog.cpp
+++ b/dialogs/optionsdialog.cpp
@@ -1,734 +1,738 @@
/*
* Copyright (C) 2012 Christian Kaiser
*
* 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 library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include <QCompleter>
#include <QDate>
#include <QDesktopServices>
#include <QDesktopWidget>
#include <QDirModel>
#include <QFileDialog>
#include <QKeyEvent>
#include <QMessageBox>
#include <QProcess>
#include <QSettings>
#include <QTimer>
#include <QUrl>
#include <QDebug>
#ifdef Q_OS_WIN
#include <windows.h>
#endif
#include "optionsdialog.h"
#include "namingdialog.h"
#include "historydialog.h"
#include "../tools/os.h"
#include "../tools/screenshot.h"
#include "../tools/screenshotmanager.h"
#include "../updater/updater.h"
OptionsDialog::OptionsDialog(QWidget *parent) :
QDialog(parent)
{
ui.setupUi(this);
setModal(true);
#if defined(Q_WS_X11)
// KDE-specific style tweaks.
if (qApp->style()->objectName() == "oxygen") {
ui.browsePushButton->setMaximumWidth(30);
ui.namingOptionsButton->setMaximumWidth(30);
ui.fileGroupBox->setFlat(false);
ui.startupGroupBox->setFlat(false);
ui.capturesGroupBox->setFlat(false);
ui.controlGroupBox->setFlat(false);
ui.interfaceGroupBox->setFlat(false);
ui.screenshotsGroupBox->setFlat(false);
ui.previewGroupBox->setFlat(false);
ui.updaterGroupBox->setFlat(false);
ui.historyGroupBox->setFlat(false);
ui.clipboardGroupBox->setFlat(false);
ui.optionsTab->layout()->setContentsMargins(0, 0, 6, 0);
ui.aboutTab->layout()->setMargin(8);
}
#endif
QTimer::singleShot(0, this, SLOT(init()));
QTimer::singleShot(1, this, SLOT(loadSettings()));
}
void OptionsDialog::accepted()
{
if (hotkeyCollision()) {
QMessageBox::critical(this, tr("Hotkey conflict"), tr("You have assigned the same hotkeys to more than one action."));
return;
}
if (ui.prefixLineEdit->text().contains(QRegExp("[?:\\\\/*\"<>|]"))) {
QMessageBox::critical(this, tr("Filename character error"), tr("The filename can't contain any of the following characters: ? : \\ / * \" < > |"));
return;
}
if (!ui.fileGroupBox->isChecked() && !ui.clipboardCheckBox->isChecked()) {
QMessageBox::critical(this, tr("Final Destination"), tr("You can't take screenshots unless you enable either file saving or the clipboard."));
return;
}
saveSettings();
accept();
}
void OptionsDialog::checkUpdatesNow()
{
Updater updater;
updater.checkWithFeedback();
}
void OptionsDialog::languageChange(QString language)
{
os::translate(language);
}
void OptionsDialog::loadSettings()
{
settings()->sync();
os::translate(settings()->value("options/language").toString()); // Why? Don't ask me, I'm just the programmer.
setUpdatesEnabled(false);
if (!settings()->contains("file/format")) {
// If there are no settings, get rid of the cancel button so that the user is forced to save them
ui.buttonBox->clear();
ui.buttonBox->addButton(QDialogButtonBox::Ok);
}
ui.startupCheckBox->toggle();
ui.trayCheckBox->toggle();
ui.previewAutocloseCheckBox->toggle();
QString targetDefault;
if (ScreenshotManager::instance()->portableMode()) {
targetDefault = tr("Screenshots");
}
else {
targetDefault = os::getDocumentsPath() + QDir::separator() + tr("Screenshots");
}
settings()->beginGroup("file");
ui.formatComboBox->setCurrentIndex(settings()->value("format", 1).toInt());
ui.prefixLineEdit->setText(settings()->value("prefix", tr("screenshot.")).toString());
ui.namingComboBox->setCurrentIndex(settings()->value("naming", 0).toInt());
ui.targetLineEdit->setText(settings()->value("target", targetDefault).toString());
ui.fileGroupBox->setChecked(settings()->value("enabled", true).toBool());
settings()->endGroup();
settings()->beginGroup("options");
ui.startupCheckBox->setChecked(settings()->value("startup", false).toBool());
ui.startupHideCheckBox->setChecked(settings()->value("startupHide", true).toBool());
ui.hideCheckBox->setChecked(settings()->value("hide", true).toBool());
ui.delaySpinBox->setValue(settings()->value("delay", 0).toInt());
flipToggled(settings()->value("flip", false).toBool());
ui.trayCheckBox->setChecked(settings()->value("tray", true).toBool());
ui.messageCheckBox->setChecked(settings()->value("message", true).toBool());
ui.qualitySlider->setValue(settings()->value("quality", 100).toInt());
ui.playSoundCheckBox->setChecked(settings()->value("playSound", false).toBool());
ui.updaterCheckBox->setChecked(!settings()->value("disableUpdater", false).toBool());
ui.magnifyCheckBox->setChecked(settings()->value("magnify", false).toBool());
ui.cursorCheckBox->setChecked(settings()->value("cursor", true).toBool());
ui.saveAsCheckBox->setChecked(settings()->value("saveAs", false).toBool());
ui.previewGroupBox->setChecked(settings()->value("preview", false).toBool());
ui.previewSizeSpinBox->setValue(settings()->value("previewSize", 300).toInt());
ui.previewPositionComboBox->setCurrentIndex(settings()->value("previewPosition", 3).toInt());
ui.previewAutocloseCheckBox->setChecked(settings()->value("previewAutoclose", false).toBool());
ui.previewAutocloseTimeSpinBox->setValue(settings()->value("previewAutocloseTime", 15).toInt());
ui.previewAutocloseActionComboBox->setCurrentIndex(settings()->value("previewAutocloseAction", 0).toInt());
ui.previewDefaultActionComboBox->setCurrentIndex(settings()->value("previewDefaultAction", 0).toInt());
ui.areaAutocloseCheckBox->setChecked(settings()->value("areaAutoclose", false).toBool());
// History mode is neat for normal operation but I'll keep it disabled by default on portable mode.
ui.historyCheckBox->setChecked(settings()->value("history", (ScreenshotManager::instance()->portableMode()) ? false : true).toBool());
// Advanced
ui.clipboardCheckBox->setChecked(settings()->value("clipboard", true).toBool());
ui.imgurClipboardCheckBox->setChecked(settings()->value("imgurClipboard", false).toBool());
ui.optiPngCheckBox->setChecked(settings()->value("optipng", true).toBool());
ui.closeHideCheckBox->setChecked(settings()->value("closeHide", true).toBool());
ui.currentMonitorCheckBox->setChecked(settings()->value("currentMonitor", false).toBool());
ui.replaceCheckBox->setChecked(settings()->value("replace", false).toBool());
ui.uploadCheckBox->setChecked(settings()->value("uploadAuto", false).toBool());
#ifdef Q_OS_WIN
if (!QFile::exists(qApp->applicationDirPath() + QDir::separator() + "optipng.exe")) {
ui.optiPngCheckBox->setEnabled(false);
ui.optiPngLabel->setText("optipng.exe not found");
}
#elif defined(Q_WS_X11)
if (!QProcess::startDetached("optipng")) {
ui.optiPngCheckBox->setChecked(false);
ui.optiPngCheckBox->setEnabled(false);
ui.optiPngLabel->setText(tr("Install 'OptiPNG'"));
}
//TODO: Sound cue support on Linux
ui.playSoundCheckBox->setVisible(false);
ui.playSoundCheckBox->setChecked(false);
//TODO: Cursor support on X11
ui.cursorCheckBox->setVisible(false);
ui.cursorCheckBox->setChecked(false);
#endif
//TODO: Must replace with not-stupid system
QString lang = settings()->value("language").toString();
int index = ui.languageComboBox->findText(lang);
if (index == -1)
index = ui.languageComboBox->findText("English");
ui.languageComboBox->setCurrentIndex(index);
settings()->endGroup();
settings()->beginGroup("actions");
// This toggle is for the first run
ui.screenCheckBox->toggle();
ui.areaCheckBox->toggle();
ui.windowCheckBox->toggle();
ui.windowPickerCheckBox->toggle();
ui.openCheckBox->toggle();
ui.directoryCheckBox->toggle();
settings()->beginGroup("screen");
ui.screenCheckBox->setChecked(settings()->value("enabled", true).toBool());
ui.screenHotkeyWidget->setHotkey(settings()->value("hotkey", "Print").toString());
settings()->endGroup();
settings()->beginGroup("area");
ui.areaCheckBox->setChecked(settings()->value("enabled").toBool());
ui.areaHotkeyWidget->setHotkey(settings()->value("hotkey", "Ctrl+Print").toString());
settings()->endGroup();
settings()->beginGroup("window");
ui.windowCheckBox->setChecked(settings()->value("enabled").toBool());
ui.windowHotkeyWidget->setHotkey(settings()->value("hotkey", "Alt+Print").toString());
settings()->endGroup();
settings()->beginGroup("windowPicker");
ui.windowPickerCheckBox->setChecked(settings()->value("enabled").toBool());
ui.windowPickerHotkeyWidget->setHotkey(settings()->value("hotkey", "Ctrl+Alt+Print").toString());
settings()->endGroup();
settings()->beginGroup("open");
ui.openCheckBox->setChecked(settings()->value("enabled").toBool());
ui.openHotkeyWidget->setHotkey(settings()->value("hotkey", "Ctrl+PgUp").toString());
settings()->endGroup();
settings()->beginGroup("directory");
ui.directoryCheckBox->setChecked(settings()->value("enabled").toBool());
ui.directoryHotkeyWidget->setHotkey(settings()->value("hotkey", "Ctrl+PgDown").toString());
settings()->endGroup();
settings()->endGroup();
QTimer::singleShot(0, this, SLOT(updatePreview()));
setEnabled(true);
setUpdatesEnabled(true);
}
void OptionsDialog::openUrl(QString url)
{
if (url == "#aboutqt") {
qApp->aboutQt();
}
else {
QDesktopServices::openUrl(QUrl(url));
}
}
void OptionsDialog::rejected()
{
languageChange(settings()->value("options/language").toString()); // Revert language to default.
}
void OptionsDialog::saveSettings()
{
settings()->beginGroup("file");
settings()->setValue("format", ui.formatComboBox->currentIndex());
settings()->setValue("prefix", ui.prefixLineEdit->text());
settings()->setValue("naming", ui.namingComboBox->currentIndex());
settings()->setValue("target", ui.targetLineEdit->text());
settings()->setValue("enabled", ui.fileGroupBox->isChecked());
settings()->endGroup();
settings()->beginGroup("options");
settings()->setValue("startup", ui.startupCheckBox->isChecked());
settings()->setValue("startupHide", ui.startupHideCheckBox->isChecked());
settings()->setValue("hide", ui.hideCheckBox->isChecked());
settings()->setValue("delay", ui.delaySpinBox->value());
settings()->setValue("tray", ui.trayCheckBox->isChecked());
settings()->setValue("message", ui.messageCheckBox->isChecked());
settings()->setValue("quality", ui.qualitySlider->value());
settings()->setValue("playSound", ui.playSoundCheckBox->isChecked());
// We save the explicit string because addition/removal of language files can cause it to change
settings()->setValue("language", ui.languageComboBox->currentText());
// This settings is inverted because the first iteration of the Updater did not have a settings but instead relied on the messagebox choice of the user.
settings()->setValue("disableUpdater", !ui.updaterCheckBox->isChecked());
settings()->setValue("magnify", ui.magnifyCheckBox->isChecked());
settings()->setValue("cursor", ui.cursorCheckBox->isChecked());
settings()->setValue("saveAs", ui.saveAsCheckBox->isChecked());
settings()->setValue("preview", ui.previewGroupBox->isChecked());
settings()->setValue("previewSize", ui.previewSizeSpinBox->value());
settings()->setValue("previewPosition", ui.previewPositionComboBox->currentIndex());
settings()->setValue("previewAutoclose", ui.previewAutocloseCheckBox->isChecked());
settings()->setValue("previewAutocloseTime", ui.previewAutocloseTimeSpinBox->value());
settings()->setValue("previewAutocloseAction", ui.previewAutocloseActionComboBox->currentIndex());
settings()->setValue("previewDefaultAction", ui.previewDefaultActionComboBox->currentIndex());
settings()->setValue("areaAutoclose", ui.areaAutocloseCheckBox->isChecked());
settings()->setValue("history", ui.historyCheckBox->isChecked());
// Advanced
settings()->setValue("closeHide", ui.closeHideCheckBox->isChecked());
settings()->setValue("clipboard", ui.clipboardCheckBox->isChecked());
settings()->setValue("imgurClipboard", ui.imgurClipboardCheckBox->isChecked());
settings()->setValue("optipng", ui.optiPngCheckBox->isChecked());
settings()->setValue("currentMonitor", ui.currentMonitorCheckBox->isChecked());
settings()->setValue("replace", ui.replaceCheckBox->isChecked());
//Upload
settings()->setValue("uploadAuto", ui.uploadCheckBox->isChecked());
settings()->endGroup();
settings()->beginGroup("actions");
settings()->beginGroup("screen");
settings()->setValue("enabled", ui.screenCheckBox->isChecked());
settings()->setValue("hotkey", ui.screenHotkeyWidget->hotkey());
settings()->endGroup();
settings()->beginGroup("area");
settings()->setValue("enabled", ui.areaCheckBox->isChecked());
settings()->setValue("hotkey", ui.areaHotkeyWidget->hotkey());
settings()->endGroup();
settings()->beginGroup("window");
settings()->setValue("enabled", ui.windowCheckBox->isChecked());
settings()->setValue("hotkey", ui.windowHotkeyWidget->hotkey());
settings()->endGroup();
settings()->beginGroup("windowPicker");
settings()->setValue("enabled", ui.windowPickerCheckBox->isChecked());
settings()->setValue("hotkey", ui.windowPickerHotkeyWidget->hotkey());
settings()->endGroup();
settings()->beginGroup("open");
settings()->setValue("enabled", ui.openCheckBox->isChecked());
settings()->setValue("hotkey", ui.openHotkeyWidget->hotkey());
settings()->endGroup();
settings()->beginGroup("directory");
settings()->setValue("enabled", ui.directoryCheckBox->isChecked());
settings()->setValue("hotkey", ui.directoryHotkeyWidget->hotkey());
settings()->endGroup();
settings()->endGroup();
}
void OptionsDialog::updatePreview()
{
Screenshot::NamingOptions options;
options.naming = (Screenshot::Naming) ui.namingComboBox->currentIndex();
options.flip = settings()->value("options/flip", false).toBool();
options.leadingZeros = settings()->value("options/naming/leadingZeros", 0).toInt();
options.dateFormat = settings()->value("options/naming/dateFormat", "yyyy-MM-dd").toString();
if (ui.fileGroupBox->isChecked()) // Only change the naming button when file options are enabled.
ui.namingOptionsButton->setDisabled((options.naming == Screenshot::Empty));
QString preview = Screenshot::getName(options,
ui.prefixLineEdit->text(),
QDir(ui.targetLineEdit->text()));
preview = QString("%1.%2").arg(preview).arg(ui.formatComboBox->currentText().toLower());
if (preview.length() >= 40) {
preview.truncate(37);
preview.append("...");
}
ui.previewLabel->setText(preview);
}
void OptionsDialog::viewHistory()
{
HistoryDialog historyDialog(this);
historyDialog.exec();
}
//
bool OptionsDialog::event(QEvent* event)
{
if (event->type() == QEvent::LanguageChange) {
// ComboBoxes revert to the first index when translated:
int naming = ui.namingComboBox->currentIndex();
int format = ui.formatComboBox->currentIndex();
int previewPosition = ui.previewPositionComboBox->currentIndex();
int previewAutoclose = ui.previewAutocloseActionComboBox->currentIndex();
int previewDefault = ui.previewDefaultActionComboBox->currentIndex();
ui.retranslateUi(this);
// Restoring comboboxes
ui.namingComboBox->setCurrentIndex(naming);
ui.formatComboBox->setCurrentIndex(format);
ui.previewPositionComboBox->setCurrentIndex(previewPosition);
ui.previewAutocloseActionComboBox->setCurrentIndex(previewAutoclose);
ui.previewDefaultActionComboBox->setCurrentIndex(previewDefault);
updatePreview();
resize(minimumSizeHint());
}
else if (event->type() == QEvent::Close || event->type() == QEvent::Hide) {
settings()->setValue("geometry/optionsDialog", saveGeometry());
if (!settings()->contains("file/format")) {
// I'm afraid I can't let you do that, Dave.
event->ignore();
return false;
}
}
else if (event->type() == QEvent::Show)
{
restoreGeometry(settings()->value("geometry/optionsDialog").toByteArray());
}
return QDialog::event(event);
}
#ifdef Q_OS_WIN
// Qt does not send the print screen key as a regular QKeyPress event, so we must use the Windows API
-bool OptionsDialog::winEvent(MSG *message, long *result)
+bool OptionsDialog::nativeEvent(const QByteArray &eventType, void *message, long *result)
{
- if ((message->message == WM_KEYUP || message->message == WM_SYSKEYUP)
- && message->wParam == VK_SNAPSHOT) {
- qApp->postEvent(qApp->focusWidget(), new QKeyEvent(QEvent::KeyPress, Qt::Key_Print, qApp->keyboardModifiers()));
+ if (eventType == "windows_generic_MSG") {
+ MSG* m = static_cast<MSG*>(message);
+
+ if ((m->message == WM_KEYUP || m->message == WM_SYSKEYUP)
+ && m->wParam == VK_SNAPSHOT) {
+ qApp->postEvent(qApp->focusWidget(), new QKeyEvent(QEvent::KeyPress, Qt::Key_Print, qApp->queryKeyboardModifiers()));
+ }
}
- return QDialog::winEvent(message, result);
+ return QDialog::nativeEvent(eventType, message, result);
}
#endif
//
void OptionsDialog::browse()
{
QString fileName = QFileDialog::getExistingDirectory(this,
tr("Select where you want to save the screenshots"),
ui.targetLineEdit->text());
if (fileName.isEmpty())
return;
ui.targetLineEdit->setText(fileName);
}
void OptionsDialog::dialogButtonClicked(QAbstractButton *button)
{
if (ui.buttonBox->buttonRole(button) == QDialogButtonBox::ResetRole) {
QMessageBox msgBox;
msgBox.setWindowTitle(tr("Lightscreen - Restore Default Options"));
msgBox.setText(tr("Restoring the default options will cause you to lose all of your current configuration."));
msgBox.setIcon(QMessageBox::Warning);
QPushButton *restoreButton = msgBox.addButton(tr("Restore"), QMessageBox::ActionRole);
QPushButton *dontRestoreButton = msgBox.addButton(tr("Don't Restore"), QMessageBox::ActionRole);
msgBox.setDefaultButton(dontRestoreButton);
msgBox.exec();
Q_UNUSED(restoreButton)
if (msgBox.clickedButton() == dontRestoreButton)
return;
QString language = settings()->value("options/language").toString(); // Only mantain language.
settings()->clear();
settings()->setValue("options/language", language);
loadSettings();
}
}
void OptionsDialog::flipToggled(bool checked)
{
setUpdatesEnabled(false);
ui.filenameLayout->removeWidget(ui.prefixLineEdit);
ui.filenameLayout->removeWidget(ui.namingComboBox);
if (checked) {
ui.filenameLayout->addWidget(ui.namingComboBox);
ui.filenameLayout->addWidget(ui.prefixLineEdit);
}
else {
ui.filenameLayout->addWidget(ui.prefixLineEdit);
ui.filenameLayout->addWidget(ui.namingComboBox);
}
if (ui.prefixLineEdit->text() == tr("screenshot.")
&& checked)
ui.prefixLineEdit->setText(tr(".screenshot"));
if (ui.prefixLineEdit->text() == tr(".screenshot")
&& !checked)
ui.prefixLineEdit->setText(tr("screenshot."));
setUpdatesEnabled(true); // Avoids flicker
}
void OptionsDialog::init()
{
// Make the scroll area share the Tab Widget background color
QPalette optionsPalette = ui.optionsScrollArea->palette();
optionsPalette.setColor(QPalette::Window, ui.tabWidget->palette().color(QPalette::Base));
ui.optionsScrollArea->setPalette(optionsPalette);
ui.browsePushButton->setIcon(os::icon("folder"));
ui.namingOptionsButton->setIcon(os::icon("configure"));
ui.buttonBox->addButton(new QPushButton(" " + tr("Restore Defaults") + " ", this), QDialogButtonBox::ResetRole);
// Set up the autocomplete for the directory.
QCompleter *completer = new QCompleter(this);
completer->setModel(new QDirModel(QStringList(), QDir::Dirs, QDir::Name, completer));
ui.targetLineEdit->setCompleter(completer);
// HotkeyWidget icons.
ui.screenHotkeyWidget->setIcon (os::icon("screen"));
ui.windowHotkeyWidget->setIcon (os::icon("window"));
ui.windowPickerHotkeyWidget->setIcon(os::icon("pickWindow"));
ui.areaHotkeyWidget->setIcon (os::icon("area"));
ui.openHotkeyWidget->setIcon (QIcon(":/icons/lightscreen.small"));
ui.directoryHotkeyWidget->setIcon (os::icon("folder"));
// Version
ui.versionLabel->setText(tr("Version %1").arg(qApp->applicationVersion()));
setEnabled(false); // We disable the widgets to prevent any user interaction until the settings have loaded.
//
// Connections
//
connect(ui.buttonBox , SIGNAL(clicked(QAbstractButton*)), this , SLOT(dialogButtonClicked(QAbstractButton*)));
connect(ui.buttonBox , SIGNAL(accepted()) , this , SLOT(accepted()));
connect(ui.buttonBox , SIGNAL(rejected()) , this , SLOT(rejected()));
connect(ui.namingOptionsButton , SIGNAL(clicked()) , this , SLOT(namingOptions()));
connect(ui.prefixLineEdit , SIGNAL(textEdited(QString)) , this , SLOT(updatePreview()));
connect(ui.formatComboBox , SIGNAL(currentIndexChanged(int)) , this , SLOT(updatePreview()));
connect(ui.namingComboBox , SIGNAL(currentIndexChanged(int)) , this , SLOT(updatePreview()));
connect(ui.browsePushButton , SIGNAL(clicked()) , this , SLOT(browse()));
connect(ui.checkUpdatesPushButton , SIGNAL(clicked()) , this , SLOT(checkUpdatesNow()));
connect(ui.historyPushButton , SIGNAL(clicked()) , this , SLOT(viewHistory()));
connect(ui.screenCheckBox , SIGNAL(toggled(bool)), ui.screenHotkeyWidget , SLOT(setEnabled(bool)));
connect(ui.areaCheckBox , SIGNAL(toggled(bool)), ui.areaHotkeyWidget , SLOT(setEnabled(bool)));
connect(ui.windowCheckBox , SIGNAL(toggled(bool)), ui.windowHotkeyWidget , SLOT(setEnabled(bool)));
connect(ui.windowPickerCheckBox, SIGNAL(toggled(bool)), ui.windowPickerHotkeyWidget, SLOT(setEnabled(bool)));
connect(ui.openCheckBox , SIGNAL(toggled(bool)), ui.openHotkeyWidget , SLOT(setEnabled(bool)));
connect(ui.directoryCheckBox , SIGNAL(toggled(bool)), ui.directoryHotkeyWidget, SLOT(setEnabled(bool)));
// "Save as" disables the file target input field.
connect(ui.saveAsCheckBox , SIGNAL(toggled(bool)), ui.targetLineEdit , SLOT(setDisabled(bool)));
connect(ui.saveAsCheckBox , SIGNAL(toggled(bool)), ui.browsePushButton , SLOT(setDisabled(bool)));
connect(ui.saveAsCheckBox , SIGNAL(toggled(bool)), ui.directoryLabel , SLOT(setDisabled(bool)));
connect(ui.startupCheckBox , SIGNAL(toggled(bool)), ui.startupHideCheckBox , SLOT(setEnabled(bool)));
connect(ui.qualitySlider , SIGNAL(valueChanged(int)), ui.qualityValueLabel, SLOT(setNum(int)));
connect(ui.trayCheckBox , SIGNAL(toggled(bool)), ui.messageCheckBox , SLOT(setEnabled(bool)));
// Auto-upload disables the default action button in the previews.
connect(ui.uploadCheckBox , SIGNAL(toggled(bool)), ui.previewDefaultActionLabel , SLOT(setDisabled(bool)));
connect(ui.uploadCheckBox , SIGNAL(toggled(bool)), ui.previewDefaultActionComboBox, SLOT(setDisabled(bool)));
connect(ui.directoryCheckBox , SIGNAL(toggled(bool)), ui.directoryHotkeyWidget, SLOT(setEnabled(bool)));
connect(ui.moreInformationLabel, SIGNAL(linkActivated(QString)) , this, SLOT(openUrl(QString)));
connect(ui.languageComboBox , SIGNAL(currentIndexChanged(QString)), this, SLOT(languageChange(QString)));
connect(ui.mainLabel , SIGNAL(linkActivated(QString)), this, SLOT(openUrl(QString)));
connect(ui.licenseAboutLabel, SIGNAL(linkActivated(QString)), this, SLOT(openUrl(QString)));
connect(ui.linksLabel, SIGNAL(linkActivated(QString)), this, SLOT(openUrl(QString)));
//
// Languages
//
QDir languages(":/translations");
ui.languageComboBox->addItem("English");
foreach (QString language, languages.entryList()) {
ui.languageComboBox->addItem(language);
}
}
void OptionsDialog::namingOptions()
{
NamingDialog namingDialog((Screenshot::Naming) ui.namingComboBox->currentIndex());
namingDialog.exec();
flipToggled(settings()->value("options/flip").toBool());
updatePreview();
}
//
bool OptionsDialog::hotkeyCollision()
{
// Check for hotkey collision (there's probably a better way to do this...=)
if (ui.screenCheckBox->isChecked()) {
if (ui.screenHotkeyWidget->hotkey() == ui.areaHotkeyWidget->hotkey()
&& ui.areaCheckBox->isChecked())
return true;
if (ui.screenHotkeyWidget->hotkey() == ui.windowHotkeyWidget->hotkey()
&& ui.windowCheckBox->isChecked())
return true;
if (ui.screenHotkeyWidget->hotkey() == ui.windowPickerHotkeyWidget->hotkey()
&& ui.windowPickerCheckBox->isChecked())
return true;
if (ui.screenHotkeyWidget->hotkey() == ui.openHotkeyWidget->hotkey()
&& ui.openCheckBox->isChecked())
return true;
if (ui.screenHotkeyWidget->hotkey() == ui.directoryHotkeyWidget->hotkey()
&& ui.directoryCheckBox->isChecked())
return true;
}
if (ui.areaCheckBox->isChecked()) {
if (ui.areaHotkeyWidget->hotkey() == ui.screenHotkeyWidget->hotkey()
&& ui.screenCheckBox->isChecked())
return true;
if (ui.areaHotkeyWidget->hotkey() == ui.windowHotkeyWidget->hotkey()
&& ui.windowCheckBox->isChecked())
return true;
if (ui.areaHotkeyWidget->hotkey() == ui.windowPickerHotkeyWidget->hotkey()
&& ui.windowPickerCheckBox->isChecked())
return true;
if (ui.areaHotkeyWidget->hotkey() == ui.openHotkeyWidget->hotkey()
&& ui.openCheckBox->isChecked())
return true;
if (ui.areaHotkeyWidget->hotkey() == ui.directoryHotkeyWidget->hotkey()
&& ui.directoryCheckBox->isChecked())
return true;
}
if (ui.windowCheckBox->isChecked()) {
if (ui.windowHotkeyWidget->hotkey() == ui.screenHotkeyWidget->hotkey()
&& ui.screenCheckBox->isChecked())
return true;
if (ui.windowHotkeyWidget->hotkey() == ui.areaHotkeyWidget->hotkey()
&& ui.areaCheckBox->isChecked())
return true;
if (ui.windowHotkeyWidget->hotkey() == ui.windowPickerHotkeyWidget->hotkey()
&& ui.windowPickerCheckBox->isChecked())
return true;
if (ui.windowHotkeyWidget->hotkey() == ui.openHotkeyWidget->hotkey()
&& ui.openCheckBox->isChecked())
return true;
if (ui.windowHotkeyWidget->hotkey() == ui.directoryHotkeyWidget->hotkey()
&& ui.directoryCheckBox->isChecked())
return true;
}
if (ui.openCheckBox->isChecked()) {
if (ui.openHotkeyWidget->hotkey() == ui.screenHotkeyWidget->hotkey()
&& ui.screenCheckBox->isChecked())
return true;
if (ui.openHotkeyWidget->hotkey() == ui.areaHotkeyWidget->hotkey()
&& ui.areaCheckBox->isChecked())
return true;
if (ui.openHotkeyWidget->hotkey() == ui.windowPickerHotkeyWidget->hotkey()
&& ui.windowPickerCheckBox->isChecked())
return true;
if (ui.openHotkeyWidget->hotkey() == ui.windowHotkeyWidget->hotkey()
&& ui.windowCheckBox->isChecked())
return true;
if (ui.openHotkeyWidget->hotkey() == ui.directoryHotkeyWidget->hotkey()
&& ui.directoryCheckBox->isChecked())
return true;
}
if (ui.directoryCheckBox->isChecked()) {
if (ui.directoryHotkeyWidget->hotkey() == ui.screenHotkeyWidget->hotkey()
&& ui.screenCheckBox->isChecked())
return true;
if (ui.directoryHotkeyWidget->hotkey() == ui.areaHotkeyWidget->hotkey()
&& ui.areaCheckBox->isChecked())
return true;
if (ui.directoryHotkeyWidget->hotkey() == ui.windowPickerHotkeyWidget->hotkey()
&& ui.windowPickerCheckBox->isChecked())
return true;
if (ui.directoryHotkeyWidget->hotkey() == ui.windowHotkeyWidget->hotkey()
&& ui.windowCheckBox->isChecked())
return true;
if (ui.directoryHotkeyWidget->hotkey() == ui.openHotkeyWidget->hotkey()
&& ui.openCheckBox->isChecked())
return true;
}
return false;
}
QSettings *OptionsDialog::settings() const
{
return ScreenshotManager::instance()->settings();
}
diff --git a/dialogs/optionsdialog.h b/dialogs/optionsdialog.h
index d673785..06c2955 100644
--- a/dialogs/optionsdialog.h
+++ b/dialogs/optionsdialog.h
@@ -1,68 +1,68 @@
/*
* Copyright (C) 2012 Christian Kaiser
*
* 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 library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifndef OPTIONSDIALOG_H
#define OPTIONSDIALOG_H
#include <QDialog>
#include "../updater/updater.h"
#include "ui_optionsdialog.h"
class QSettings;
class QAbstractButton;
class OptionsDialog : public QDialog
{
Q_OBJECT
public:
OptionsDialog(QWidget *parent = 0);
public slots:
void accepted();
void checkUpdatesNow();
void languageChange(QString language);
void loadSettings();
void openUrl(QString url);
void rejected();
void saveSettings();
void updatePreview();
void viewHistory();
protected:
bool event(QEvent *event);
#ifdef Q_OS_WIN
- bool winEvent(MSG *message, long *result);
+ bool nativeEvent(const QByteArray &eventType, void *message, long *result);
#endif
private slots:
void browse();
void dialogButtonClicked(QAbstractButton *button);
void flipToggled(bool checked);
void init();
void namingOptions();
private:
bool hotkeyCollision();
QSettings *settings() const;
private:
Ui::OptionsDialog ui;
};
#endif // OPTIONSDIALOG_H
diff --git a/dialogs/optionsdialog.ui b/dialogs/optionsdialog.ui
index 0ceb3c0..956049b 100644
--- a/dialogs/optionsdialog.ui
+++ b/dialogs/optionsdialog.ui
@@ -1,1445 +1,1445 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>OptionsDialog</class>
<widget class="QDialog" name="OptionsDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>393</width>
<height>314</height>
</rect>
</property>
<property name="windowTitle">
<string>Options - Lightscreen</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_4">
<property name="leftMargin">
<number>6</number>
</property>
<property name="topMargin">
<number>6</number>
</property>
<property name="rightMargin">
<number>6</number>
</property>
<property name="bottomMargin">
<number>6</number>
</property>
<item>
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
- <number>1</number>
+ <number>0</number>
</property>
<widget class="QWidget" name="generalTab">
<attribute name="title">
<string>General</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="bottomMargin">
<number>6</number>
</property>
<item>
<widget class="QGroupBox" name="fileGroupBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="title">
<string>File</string>
</property>
<property name="flat">
<bool>true</bool>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<layout class="QGridLayout" name="fileGroupBoxLayout">
<property name="leftMargin">
<number>6</number>
</property>
<property name="topMargin">
<number>6</number>
</property>
<property name="rightMargin">
<number>6</number>
</property>
<property name="bottomMargin">
<number>6</number>
</property>
<property name="verticalSpacing">
<number>4</number>
</property>
<item row="0" column="0">
<widget class="QLabel" name="directoryLabel">
<property name="text">
<string>&amp;Directory:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>targetLineEdit</cstring>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="targetLineEdit">
<property name="styleSheet">
<string notr="true"/>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QPushButton" name="browsePushButton">
<property name="maximumSize">
<size>
<width>60</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string/>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="filenameLabel">
<property name="toolTip">
<string>The prefix for the screenshot file</string>
</property>
<property name="text">
<string>&amp;Filename:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>prefixLineEdit</cstring>
</property>
</widget>
</item>
<item row="1" column="1">
<layout class="QHBoxLayout" name="filenameLayout">
<property name="spacing">
<number>3</number>
</property>
<item>
<widget class="QLineEdit" name="prefixLineEdit">
<property name="whatsThis">
<string>The prefix will be inserted before the &lt;em&gt;Naming&lt;/em&gt; in the screenshot file and it is usually used to distinguish files. It can be left blank.</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="namingComboBox">
<property name="whatsThis">
<string>The naming is inserted after the prefix and is what makes each screenshot file unique to avoid overwriting.&lt;br /&gt;
&lt;b&gt;Numeric&lt;/b&gt;: inserts a number in sequence, 1, 2, 3..&lt;br /&gt;
&lt;b&gt;Date&lt;/b&gt;: inserts the current date and time, in the form of dd-MM-yyyy, click the &quot;wrench&quot; button on the right to customize the format.&lt;br /&gt;
&lt;b&gt;Timestamp&lt;/b&gt;: inserts a number, a Unix timestamp, which is the number of seconds passed since 1970-1-1 00:00:00.&lt;br /&gt;
</string>
</property>
<item>
<property name="text">
<string>(number)</string>
</property>
</item>
<item>
<property name="text">
<string>(date)</string>
</property>
</item>
<item>
<property name="text">
<string>(timestamp)</string>
</property>
</item>
<item>
<property name="text">
<string>(none)</string>
</property>
</item>
</widget>
</item>
</layout>
</item>
<item row="1" column="2">
<widget class="QPushButton" name="namingOptionsButton">
<property name="autoDefault">
<bool>false</bool>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="formatLabel">
<property name="toolTip">
<string>The file format for the screenshot</string>
</property>
<property name="text">
<string>F&amp;ormat:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>formatComboBox</cstring>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QComboBox" name="formatComboBox">
<item>
<property name="text">
<string notr="true">PNG</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">JPG</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">BMP</string>
</property>
</item>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="qualityLabel">
<property name="text">
<string>&amp;Quality:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>qualitySlider</cstring>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QSlider" name="qualitySlider">
<property name="whatsThis">
<string>This slider goes from 0 to 100. 100 being the highest quality and 0 the lowest.&lt;br&gt;
Quality is related to file size and of course to readability and overall quality of the image.</string>
</property>
<property name="maximum">
<number>100</number>
</property>
<property name="pageStep">
<number>5</number>
</property>
<property name="value">
<number>100</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="4" column="2">
<layout class="QHBoxLayout" name="qualityLayout">
<property name="spacing">
<number>0</number>
</property>
<property name="sizeConstraint">
<enum>QLayout::SetMinimumSize</enum>
</property>
<item>
<widget class="QLabel" name="qualityValueLabel">
<property name="font">
<font>
<pointsize>8</pointsize>
</font>
</property>
<property name="text">
<string notr="true">100</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="qualityPercentLabel">
<property name="font">
<font>
<pointsize>7</pointsize>
</font>
</property>
<property name="text">
<string notr="true">%</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="5" column="0">
<widget class="QLabel" name="previewTextLabel">
<property name="text">
<string>&lt;u&gt;Preview&lt;/u&gt;:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QLabel" name="previewLabel">
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QGroupBox" name="startupGroupBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="title">
<string>System Startup</string>
</property>
<property name="flat">
<bool>true</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QCheckBox" name="startupCheckBox">
<property name="whatsThis">
<string/>
</property>
<property name="text">
<string>&amp;Run Lightscreen at system startup.</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="startupHideLayout">
<item>
<spacer name="startupHideSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>13</width>
<height>15</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QCheckBox" name="startupHideCheckBox">
<property name="whatsThis">
<string/>
</property>
<property name="text">
<string>H&amp;ide the main window.</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="hotkeyTab">
<attribute name="title">
<string>Hotkeys</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QGroupBox" name="capturesGroupBox">
<property name="title">
<string>Captures</string>
</property>
<property name="flat">
<bool>true</bool>
</property>
<layout class="QGridLayout" name="gridLayout">
<property name="leftMargin">
<number>6</number>
</property>
<property name="topMargin">
<number>6</number>
</property>
<property name="rightMargin">
<number>6</number>
</property>
<property name="bottomMargin">
<number>6</number>
</property>
<property name="spacing">
<number>4</number>
</property>
<item row="0" column="0">
<widget class="QCheckBox" name="screenCheckBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>&amp;Fullscreen</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="HotkeyWidget" name="screenHotkeyWidget">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QCheckBox" name="windowPickerCheckBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Window &amp;Picker</string>
</property>
</widget>
</item>
<item row="3" column="2">
<widget class="HotkeyWidget" name="windowPickerHotkeyWidget"/>
</item>
<item row="2" column="1">
<spacer name="horizontalSpacer_4">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
<item row="2" column="0">
<widget class="QCheckBox" name="windowCheckBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Active &amp;Window</string>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="HotkeyWidget" name="windowHotkeyWidget"/>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="areaCheckBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Screen &amp;Area</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="HotkeyWidget" name="areaHotkeyWidget"/>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="controlGroupBox">
<property name="title">
<string>Lightscreen Control</string>
</property>
<property name="flat">
<bool>true</bool>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<property name="leftMargin">
<number>6</number>
</property>
<property name="topMargin">
<number>6</number>
</property>
<property name="rightMargin">
<number>6</number>
</property>
<property name="bottomMargin">
<number>6</number>
</property>
<property name="spacing">
<number>4</number>
</property>
<item row="0" column="0">
<widget class="QCheckBox" name="openCheckBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>&amp;Open the program window</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="HotkeyWidget" name="openHotkeyWidget"/>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="directoryCheckBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Open the &amp;directory</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="HotkeyWidget" name="directoryHotkeyWidget"/>
</item>
<item row="0" column="1">
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="optionsTab">
<attribute name="title">
<string>Options</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_8">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QScrollArea" name="optionsScrollArea">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>375</width>
<height>0</height>
</size>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="widgetResizable">
<bool>true</bool>
</property>
<widget class="QWidget" name="scrollAreaWidgetContents">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>358</width>
<height>780</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_5">
<property name="spacing">
<number>4</number>
</property>
<property name="leftMargin">
<number>6</number>
</property>
<property name="topMargin">
<number>6</number>
</property>
<property name="rightMargin">
<number>6</number>
</property>
<property name="bottomMargin">
<number>6</number>
</property>
<item>
<widget class="QGroupBox" name="interfaceGroupBox">
<property name="title">
<string>Interface</string>
</property>
<property name="flat">
<bool>true</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout_6">
<item>
<widget class="QCheckBox" name="trayCheckBox">
<property name="whatsThis">
<string/>
</property>
<property name="text">
<string>Sho&amp;w a system tray icon.</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="closeHideCheckBox">
<property name="text">
<string>C&amp;losing hides the main window.</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="hideCheckBox">
<property name="text">
<string>&amp;Hide Lightscreen while taking a screenshot.</string>
</property>
</widget>
</item>
<item>
<layout class="QGridLayout" name="notifyLayout">
<property name="topMargin">
<number>2</number>
</property>
<property name="bottomMargin">
<number>2</number>
</property>
<item row="1" column="1">
<widget class="QCheckBox" name="messageCheckBox">
<property name="whatsThis">
<string>Shows a completion message once the screenshot is saved, clicking this message takes you to the directory where the screenshot was saved.</string>
</property>
<property name="text">
<string>Tray icon Popup</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QCheckBox" name="playSoundCheckBox">
<property name="text">
<string>&amp;Sound cue</string>
</property>
</widget>
</item>
<item row="1" column="0">
<spacer name="horizontalSpacer_9">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>15</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="2">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="0" colspan="3">
<widget class="QLabel" name="notifyLabel">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
<underline>true</underline>
</font>
</property>
<property name="text">
<string>&amp;Notify with:</string>
</property>
<property name="buddy">
<cstring>messageCheckBox</cstring>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="languageLayout">
<item>
<widget class="QLabel" name="languageLabel">
<property name="text">
<string>&amp;Language:</string>
</property>
<property name="buddy">
<cstring>languageComboBox</cstring>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="languageComboBox">
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="moreInformationLabel">
<property name="whatsThis">
<string>Click here to go to the Lightscreen homepage to learn more about translations.</string>
</property>
<property name="text">
<string>&lt;a href=&quot;http://lightscreen.sourceforge.net/translation&quot;&gt;More information..&lt;/a&gt;</string>
</property>
</widget>
</item>
<item>
<spacer name="languageSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="previewGroupBox">
<property name="title">
<string>Screenshot Previews</string>
</property>
<property name="flat">
<bool>true</bool>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<property name="checked">
<bool>true</bool>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="0">
<widget class="QLabel" name="previewSizeLabel">
<property name="text">
<string>Maximum Size:</string>
</property>
<property name="buddy">
<cstring>previewSizeSpinBox</cstring>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QSpinBox" name="previewSizeSpinBox">
<property name="buttonSymbols">
<enum>QAbstractSpinBox::PlusMinus</enum>
</property>
<property name="accelerated">
<bool>true</bool>
</property>
<property name="correctionMode">
<enum>QAbstractSpinBox::CorrectToNearestValue</enum>
</property>
<property name="suffix">
<string notr="true"> px</string>
</property>
<property name="minimum">
<number>200</number>
</property>
<property name="maximum">
<number>800</number>
</property>
<property name="singleStep">
<number>10</number>
</property>
<property name="value">
<number>300</number>
</property>
</widget>
</item>
<item row="0" column="4" rowspan="4">
<spacer name="horizontalSpacer_5">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="0">
<widget class="QLabel" name="previewPositionLabel">
<property name="text">
<string>Position:</string>
</property>
<property name="buddy">
<cstring>previewPositionComboBox</cstring>
</property>
</widget>
</item>
<item row="1" column="1" colspan="2">
<widget class="QComboBox" name="previewPositionComboBox">
<property name="currentIndex">
<number>3</number>
</property>
<item>
<property name="text">
<string>Top Left</string>
</property>
</item>
<item>
<property name="text">
<string>Top Right</string>
</property>
</item>
<item>
<property name="text">
<string>Bottom Left</string>
</property>
</item>
<item>
<property name="text">
<string>Bottom Right</string>
</property>
</item>
</widget>
</item>
<item row="2" column="0">
<widget class="QCheckBox" name="previewAutocloseCheckBox">
<property name="text">
<string>Auto-close after</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QSpinBox" name="previewAutocloseTimeSpinBox">
<property name="suffix">
<string> seconds</string>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QLabel" name="andLabel">
<property name="minimumSize">
<size>
<width>20</width>
<height>0</height>
</size>
</property>
<property name="text">
<string> and </string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="buddy">
<cstring>previewAutocloseActionComboBox</cstring>
</property>
</widget>
</item>
<item row="2" column="3">
<widget class="QComboBox" name="previewAutocloseActionComboBox">
<property name="currentIndex">
<number>0</number>
</property>
<item>
<property name="text">
<string>save</string>
</property>
</item>
<item>
<property name="text">
<string>upload</string>
</property>
</item>
<item>
<property name="text">
<string>cancel</string>
</property>
</item>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="previewDefaultActionLabel">
<property name="text">
<string>Default action:</string>
</property>
<property name="buddy">
<cstring>previewDefaultActionComboBox</cstring>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QComboBox" name="previewDefaultActionComboBox">
<item>
<property name="text">
<string>save</string>
</property>
</item>
<item>
<property name="text">
<string>upload</string>
</property>
</item>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="screenshotsGroupBox">
<property name="title">
<string>Screenshots</string>
</property>
<property name="flat">
<bool>true</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout_7">
<item>
<widget class="QCheckBox" name="saveAsCheckBox">
<property name="text">
<string>Choose where to save each screenshot (&quot;&amp;Save as&quot;).</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="currentMonitorCheckBox">
<property name="text">
<string>&amp;Grab only the active monitor.</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="cursorCheckBox">
<property name="text">
<string>Inc&amp;lude the cursor in the screenshot.</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="magnifyCheckBox">
<property name="text">
<string>&amp;Magnify around the mouse in Area mode.</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="spacing">
<number>2</number>
</property>
<item>
<widget class="QCheckBox" name="optiPngCheckBox">
<property name="toolTip">
<string>Runs OptiPNG which reduces screenshot file size.</string>
</property>
<property name="text">
<string>O&amp;ptimize PNG screenshots.</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="optiPngLabel">
<property name="palette">
<palette>
<active>
<colorrole role="WindowText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>128</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
</active>
<inactive>
<colorrole role="WindowText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>128</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
</inactive>
<disabled>
<colorrole role="WindowText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>141</red>
<green>138</green>
<blue>136</blue>
</color>
</brush>
</colorrole>
</disabled>
</palette>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_10">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<widget class="QCheckBox" name="replaceCheckBox">
<property name="text">
<string>Replace screenshots when there's an existing file.</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="areaAutocloseCheckBox">
<property name="text">
<string>Snap area screenshots automatically (no resizing).</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="uploadCheckBox">
<property name="text">
<string>Upload all my screenshots automatically.</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_5">
<item>
<widget class="QLabel" name="delayLabel">
<property name="text">
<string>D&amp;elay:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>delaySpinBox</cstring>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="delaySpinBox">
<property name="whatsThis">
<string>Selecting anything other than 0 in this option will cause the program to &lt;b&gt;wait&lt;/b&gt; that amount of seconds before taking the screenshot.</string>
</property>
<property name="specialValueText">
<string>none</string>
</property>
<property name="accelerated">
<bool>true</bool>
</property>
<property name="correctionMode">
<enum>QAbstractSpinBox::CorrectToNearestValue</enum>
</property>
<property name="suffix">
<string> seconds</string>
</property>
<property name="prefix">
<string/>
</property>
<property name="maximum">
<number>32767</number>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_8">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>114</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="clipboardGroupBox">
<property name="title">
<string>Clipboard</string>
</property>
<property name="flat">
<bool>true</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout_10">
<item>
<widget class="QCheckBox" name="clipboardCheckBox">
<property name="text">
<string>&amp;Copy the screenshot to the clipboard.</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="imgurClipboardCheckBox">
<property name="text">
<string>After uploading, copy the imgur URL to the clipboard.</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="historyGroupBox">
<property name="title">
<string>History</string>
</property>
<property name="flat">
<bool>true</bool>
</property>
<layout class="QHBoxLayout" name="historyLayout">
<item>
<widget class="QCheckBox" name="historyCheckBox">
<property name="text">
<string>Save my screenshot history.</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_6">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>95</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="historyPushButton">
<property name="text">
<string>View &amp;History</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="updaterGroupBox">
<property name="title">
<string>Updater</string>
</property>
<property name="flat">
<bool>true</bool>
</property>
<layout class="QHBoxLayout" name="updaterLayout">
<item>
<widget class="QCheckBox" name="updaterCheckBox">
<property name="text">
<string>Check for updates regularly.</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="checkUpdatesPushButton">
<property name="text">
<string>Chec&amp;k Now</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="aboutTab">
<attribute name="title">
<string>About</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_9">
<item>
<widget class="QLabel" name="mainLabel">
<property name="text">
<string>Lightscreen is a simple tool to take screenshots, designed to be customizable and lightweight.&lt;br&gt;&lt;br&gt;
Created by &lt;a href=&quot;http://ckaiser.com.ar&quot;&gt;Christian Kaiser&lt;/a&gt;, using the &lt;a href=&quot;#aboutqt&quot;&gt;Qt toolkit&lt;/a&gt; for the graphical user interface.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse</set>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="licenseAboutLabel">
<property name="text">
<string>Released under the &lt;a href=&quot;http://www.gnu.org/licenses/gpl-2.0.html&quot;&gt;GNU General Public License&lt;/a&gt;.&lt;br&gt;&lt;br&gt;
Special thanks goes to the &lt;a href=&quot;http://lightscreen.sourceforge.net/about&quot;&gt;Donators and Translators&lt;/a&gt;.</string>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse</set>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="versionLabel">
<property name="font">
<font>
<pointsize>12</pointsize>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="linksLabel">
<property name="text">
<string>&lt;a href=&quot;https://sourceforge.net/projects/lightscreen/&quot;&gt;Visit Sourceforge project site&lt;/a&gt;&lt;br&gt;&lt;br&gt;&lt;a href=&quot;http://lightscreen.sourceforge.net/&quot;&gt;Visit Lightscreen home page&lt;/a&gt;</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse</set>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>HotkeyWidget</class>
<extends>QPushButton</extends>
<header>../widgets/hotkeywidget.h</header>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>fileGroupBox</tabstop>
<tabstop>targetLineEdit</tabstop>
<tabstop>browsePushButton</tabstop>
<tabstop>prefixLineEdit</tabstop>
<tabstop>namingComboBox</tabstop>
<tabstop>namingOptionsButton</tabstop>
<tabstop>formatComboBox</tabstop>
<tabstop>qualitySlider</tabstop>
<tabstop>startupCheckBox</tabstop>
<tabstop>startupHideCheckBox</tabstop>
<tabstop>screenCheckBox</tabstop>
<tabstop>screenHotkeyWidget</tabstop>
<tabstop>areaCheckBox</tabstop>
<tabstop>areaHotkeyWidget</tabstop>
<tabstop>windowCheckBox</tabstop>
<tabstop>windowHotkeyWidget</tabstop>
<tabstop>windowPickerCheckBox</tabstop>
<tabstop>windowPickerHotkeyWidget</tabstop>
<tabstop>openCheckBox</tabstop>
<tabstop>openHotkeyWidget</tabstop>
<tabstop>directoryCheckBox</tabstop>
<tabstop>directoryHotkeyWidget</tabstop>
<tabstop>trayCheckBox</tabstop>
<tabstop>hideCheckBox</tabstop>
<tabstop>messageCheckBox</tabstop>
<tabstop>playSoundCheckBox</tabstop>
<tabstop>previewGroupBox</tabstop>
<tabstop>previewSizeSpinBox</tabstop>
<tabstop>previewPositionComboBox</tabstop>
<tabstop>previewAutocloseCheckBox</tabstop>
<tabstop>previewAutocloseTimeSpinBox</tabstop>
<tabstop>previewAutocloseActionComboBox</tabstop>
<tabstop>previewDefaultActionComboBox</tabstop>
<tabstop>saveAsCheckBox</tabstop>
<tabstop>currentMonitorCheckBox</tabstop>
<tabstop>cursorCheckBox</tabstop>
<tabstop>magnifyCheckBox</tabstop>
<tabstop>optiPngCheckBox</tabstop>
<tabstop>replaceCheckBox</tabstop>
<tabstop>areaAutocloseCheckBox</tabstop>
<tabstop>uploadCheckBox</tabstop>
<tabstop>delaySpinBox</tabstop>
<tabstop>historyCheckBox</tabstop>
<tabstop>historyPushButton</tabstop>
<tabstop>updaterCheckBox</tabstop>
<tabstop>checkUpdatesPushButton</tabstop>
<tabstop>buttonBox</tabstop>
</tabstops>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>OptionsDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>307</x>
<y>304</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>previewAutocloseCheckBox</sender>
<signal>toggled(bool)</signal>
<receiver>previewAutocloseTimeSpinBox</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>118</x>
<y>511</y>
</hint>
<hint type="destinationlabel">
<x>210</x>
<y>529</y>
</hint>
</hints>
</connection>
<connection>
<sender>previewAutocloseCheckBox</sender>
<signal>toggled(bool)</signal>
<receiver>previewAutocloseActionComboBox</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>115</x>
<y>511</y>
</hint>
<hint type="destinationlabel">
<x>302</x>
<y>529</y>
</hint>
</hints>
</connection>
</connections>
</ui>
diff --git a/lightscreen.pro b/lightscreen.pro
index 163b7f4..fa093f2 100644
--- a/lightscreen.pro
+++ b/lightscreen.pro
@@ -1,74 +1,74 @@
TEMPLATE = app
TARGET = lightscreen
HEADERS += tools/os.h \
updater/updater.h \
dialogs/areadialog.h \
dialogs/optionsdialog.h \
widgets/hotkeywidget.h \
lightscreenwindow.h \
tools/screenshot.h \
dialogs/previewdialog.h \
tools/screenshotmanager.h \
tools/windowpicker.h \
tools/uploader.h \
tools/qtimgur.h \
dialogs/updaterdialog.h \
dialogs/namingdialog.h \
dialogs/historydialog.h
SOURCES += tools/os.cpp \
updater/updater.cpp \
dialogs/areadialog.cpp \
dialogs/optionsdialog.cpp \
widgets/hotkeywidget.cpp \
main.cpp \
lightscreenwindow.cpp \
tools/screenshot.cpp \
dialogs/previewdialog.cpp \
tools/screenshotmanager.cpp \
tools/windowpicker.cpp \
tools/uploader.cpp \
tools/qtimgur.cpp \
dialogs/updaterdialog.cpp \
dialogs/namingdialog.cpp \
dialogs/historydialog.cpp
FORMS += dialogs/optionsdialog.ui \
dialogs/namingdialog.ui \
dialogs/historydialog.ui \
lightscreenwindow.ui
RESOURCES += lightscreen.qrc
TRANSLATIONS += translations/untranslated.ts \
translations/spanish.ts \
translations/russian.ts \
translations/portuguese.ts \
translations/polish.ts \
translations/japanese.ts \
translations/italian.ts \
translations/dutch.ts
RC_FILE += lightscreen.rc
CODECFORSRC = UTF-8
-QT += network core gui xml sql multimedia
+QT += network core gui xml sql multimedia winextras
include($$PWD/tools/globalshortcut/globalshortcut.pri)
include($$PWD/tools/qtsingleapplication/qtsingleapplication.pri)
windows{
contains(QMAKE_CC, gcc){
LIBS += libgdi32 libgcc libuser32 libole32 libshell32 libshlwapi libcomctl32
QMAKE_CXXFLAGS = -Wextra -Wall -Wpointer-arith
}
contains(QMAKE_CC, cl){
LIBS += gdi32.lib user32.lib ole32.lib shell32.lib shlwapi.lib comctl32.lib
}
}
unix:LIBS += -lX11
OTHER_FILES += TODO.txt
diff --git a/lightscreenwindow.cpp b/lightscreenwindow.cpp
index 48d87ea..02d91dc 100644
--- a/lightscreenwindow.cpp
+++ b/lightscreenwindow.cpp
@@ -1,1020 +1,1011 @@
/*
* Copyright (C) 2012 Christian Kaiser
*
* 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 library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include <QMainWindow>
#include <QDate>
#include <QDesktopServices>
#include <QDesktopWidget>
#include <QFileInfo>
#include <QKeyEvent>
#include <QMenu>
#include <QMessageBox>
#include <QPointer>
#include <QProcess>
#include <QSettings>
#include <QSystemTrayIcon>
#include <QTimer>
#include <QToolTip>
#include <QUrl>
#include <QSound>
#include <QDebug>
#ifdef Q_OS_WIN
#include <windows.h>
- #include "tools/qwin7utils/Taskbar.h"
- #include "tools/qwin7utils/TaskbarButton.h"
- #include "tools/qwin7utils/Utils.h"
- using namespace QW7;
+ #include <QtWinExtras>
#endif
/*
* Lightscreen includes
*/
#include "lightscreenwindow.h"
#include "dialogs/optionsdialog.h"
#include "dialogs/previewdialog.h"
#include "dialogs/historydialog.h"
#include "tools/globalshortcut/globalshortcutmanager.h"
#include "tools/os.h"
#include "tools/screenshot.h"
#include "tools/screenshotmanager.h"
#include "tools/uploader.h"
#include "updater/updater.h"
LightscreenWindow::LightscreenWindow(QWidget *parent) :
QMainWindow(parent),
mDoCache(false),
mHideTrigger(false),
mReviveMain(false),
mWasVisible(true),
mLastMessage(0),
mLastMode(-1),
mLastScreenshot()
{
os::translate(settings()->value("options/language", "English").toString());
ui.setupUi(this);
ui.screenPushButton->setIcon(os::icon("screen.big"));
ui.areaPushButton->setIcon(os::icon("area.big"));
ui.windowPushButton->setIcon(os::icon("pickWindow.big"));
ui.optionsPushButton->setIcon(os::icon("configure"));
ui.folderPushButton->setIcon(os::icon("folder"));
ui.imgurPushButton->setIcon(os::icon("imgur"));
setMaximumSize(size());
setMinimumSize(size());
setWindowFlags(Qt::Window);
#ifdef Q_OS_WIN
if (QSysInfo::windowsVersion() >= QSysInfo::WV_WINDOWS7) {
- mTaskbarButton = new TaskbarButton(this);
+ mTaskbarButton = new QWinTaskbarButton(this);
}
if (QSysInfo::windowsVersion() < QSysInfo::WV_WINDOWS7) {
ui.centralWidget->setStyleSheet("QPushButton { padding: 2px; border: 1px solid #acacac; background: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #eaeaea, stop:1 #e5e5e5);} QPushButton:hover { border: 1px solid #7eb4ea; background-color: #e4f0fc; }");
}
#endif
// Actions
connect(ui.screenPushButton, SIGNAL(clicked()), this, SLOT(screenshotAction()));
connect(ui.areaPushButton , SIGNAL(clicked()), this, SLOT(areaHotkey()));
connect(ui.windowPushButton, SIGNAL(clicked()), this, SLOT(windowPickerHotkey()));
connect(ui.optionsPushButton, SIGNAL(clicked()), this, SLOT(showOptions()));
connect(ui.folderPushButton , SIGNAL(clicked()), this, SLOT(goToFolder()));
connect(ui.imgurPushButton, SIGNAL(clicked()), this, SLOT(createUploadMenu()));
// Uploader
connect(Uploader::instance(), SIGNAL(progress(qint64, qint64)), this, SLOT(uploadProgress(qint64, qint64)));
connect(Uploader::instance(), SIGNAL(done(QString, QString, QString)), this, SLOT(showUploaderMessage(QString, QString)));
connect(Uploader::instance(), SIGNAL(error(QString)), this, SLOT(showUploaderError(QString)));
// Manager
connect(ScreenshotManager::instance(), SIGNAL(confirm(Screenshot*)), this, SLOT(preview(Screenshot*)));
connect(ScreenshotManager::instance(), SIGNAL(windowCleanup(Screenshot::Options&)), this, SLOT(cleanup(Screenshot::Options&)));
if (!settings()->contains("file/format")) {
showOptions(); // There are no options (or the options config is invalid or incomplete)
}
else {
QTimer::singleShot(0 , this, SLOT(applySettings()));
QTimer::singleShot(5000, this, SLOT(checkForUpdates()));
}
}
LightscreenWindow::~LightscreenWindow()
{
settings()->setValue("lastScreenshot", mLastScreenshot);
settings()->sync();
GlobalShortcutManager::instance()->clear();
delete mTrayIcon;
}
void LightscreenWindow::action(int mode)
{
if (mode == 4) {
goToFolder();
}
else {
show();
}
}
void LightscreenWindow::areaHotkey()
{
screenshotAction(2);
}
void LightscreenWindow::checkForUpdates()
{
if (settings()->value("options/disableUpdater", false).toBool())
return;
if (settings()->value("lastUpdateCheck").toInt() + 7
> QDate::currentDate().dayOfYear())
return; // If 7 days have not passed since the last update check.
mUpdater = new Updater(this);
connect(mUpdater, SIGNAL(done(bool)), this, SLOT(updaterDone(bool)));
mUpdater->check();
}
void LightscreenWindow::cleanup(Screenshot::Options &options)
{
// Reversing settings
if (settings()->value("options/hide").toBool()) {
#ifndef Q_WS_X11 // X is not quick enough and the notification ends up everywhere but in the icon
if (settings()->value("options/tray").toBool() && mTrayIcon) {
mTrayIcon->show();
}
#endif
if (mPreviewDialog) {
if (mPreviewDialog->count() <= 1 && mWasVisible) {
show();
}
mPreviewDialog->show();
}
else if (mWasVisible) {
show();
}
mHideTrigger = false;
}
if (settings()->value("options/tray").toBool() && mTrayIcon) {
notify(options.result);
if (settings()->value("options/message").toBool() && options.file && !options.upload) {
// This message wll get shown only when messages are enabled and the file won't get another upload pop-up soon.
showScreenshotMessage(options.result, options.fileName);
}
}
if (settings()->value("options/playSound", false).toBool()) {
if (options.result == Screenshot::Success) {
QSound::play("sounds/ls.screenshot.wav");
}
else {
#ifdef Q_OS_WIN
QSound::play("afakepathtomakewindowsplaythedefaultsoundtheresprobablyabetterwaybuticantbebothered");
#else
QSound::play("sound/ls.error.wav");
#endif
}
}
updateUploadStatus();
if (options.result != Screenshot::Success)
return;
mLastScreenshot = options.fileName;
}
void LightscreenWindow::closeToTrayWarning()
{
if (!settings()->value("options/closeToTrayWarning", true).toBool())
return;
mLastMessage = 3;
mTrayIcon->showMessage(tr("Closed to tray"), tr("Lightscreen will keep running, you can disable this in the options menu."));
settings()->setValue("options/closeToTrayWarning", false);
}
bool LightscreenWindow::closingWithoutTray()
{
if (settings()->value("options/disableHideAlert", false).toBool())
return false;
QMessageBox msgBox;
msgBox.setWindowTitle(tr("Lightscreen"));
msgBox.setText(tr("You have chosen to hide Lightscreen when there's no system tray icon, so you will not be able to access the program <b>unless you have selected a hotkey to do so</b>.<br>What do you want to do?"));
msgBox.setIcon(QMessageBox::Warning);
msgBox.setStyleSheet("QPushButton { padding: 4px 8px; }");
QPushButton *enableButton = msgBox.addButton(tr("Hide but enable tray"),
QMessageBox::ActionRole);
QPushButton *enableAndDenotifyButton = msgBox.addButton(tr("Hide and don't warn"),
QMessageBox::ActionRole);
QPushButton *hideButton = msgBox.addButton(tr("Just hide"),
QMessageBox::ActionRole);
QPushButton *abortButton = msgBox.addButton(QMessageBox::Cancel);
Q_UNUSED(abortButton);
msgBox.exec();
if (msgBox.clickedButton() == hideButton) {
return true;
}
else if (msgBox.clickedButton() == enableAndDenotifyButton) {
settings()->setValue("options/disableHideAlert", true);
applySettings();
return true;
}
else if (msgBox.clickedButton() == enableButton) {
settings()->setValue("options/tray", true);
applySettings();
return true;
}
return false; // Cancel.
}
void LightscreenWindow::createUploadMenu()
{
QMenu* imgurMenu = new QMenu(tr("Upload"));
QAction *uploadAction = new QAction(os::icon("imgur"), tr("&Upload last"), imgurMenu);
uploadAction->setToolTip(tr("Upload the last screenshot you took to imgur.com"));
connect(uploadAction, SIGNAL(triggered()), this, SLOT(uploadLast()));
QAction *cancelAction = new QAction(os::icon("no"), tr("&Cancel upload"), imgurMenu);
cancelAction->setToolTip(tr("Cancel the currently uploading screenshots"));
cancelAction->setEnabled(false);
connect(this, SIGNAL(uploading(bool)), cancelAction, SLOT(setEnabled(bool)));
connect(cancelAction, SIGNAL(triggered()), this, SLOT(uploadCancel()));
QAction *historyAction = new QAction(os::icon("view-history"), tr("View &History"), imgurMenu);
connect(historyAction, SIGNAL(triggered()), this, SLOT(showHistoryDialog()));
imgurMenu->addAction(uploadAction);
imgurMenu->addAction(cancelAction);
imgurMenu->addAction(historyAction);
imgurMenu->addSeparator();
connect(imgurMenu, SIGNAL(aboutToShow()), this, SLOT(uploadMenuShown()));
ui.imgurPushButton->setMenu(imgurMenu);
ui.imgurPushButton->showMenu();
}
void LightscreenWindow::goToFolder()
{
#ifdef Q_OS_WIN
if (!mLastScreenshot.isEmpty() && QFile::exists(mLastScreenshot)) {
QProcess::startDetached("explorer /select, \"" + mLastScreenshot +"\"");
}
else {
#endif
QString folder = settings()->value("file/target").toString();
if (folder.isEmpty())
folder = qApp->applicationDirPath();
if (QDir::toNativeSeparators(folder.at(folder.size()-1)) != QDir::separator())
folder.append(QDir::separator());
QDesktopServices::openUrl("file:///"+folder);
#ifdef Q_OS_WIN
}
#endif
}
void LightscreenWindow::messageClicked()
{
if (mLastMessage == 1) {
goToFolder();
}
else if (mLastMessage == 3) {
QTimer::singleShot(0, this, SLOT(showOptions()));
}
else {
QDesktopServices::openUrl(QUrl(Uploader::instance()->lastUrl()));
}
}
void LightscreenWindow::messageReceived(const QString &message)
{
if (message.contains(' ')) {
foreach (QString argument, message.split(' ')) {
messageReceived(argument);
}
}
if (message == "--wake") {
show();
qApp->alert(this, 500);
return;
}
if (message == "--screen")
screenshotAction();
else if (message == "--area")
screenshotAction(2);
else if (message == "--activewindow")
screenshotAction(1);
else if (message == "--pickwindow")
screenshotAction(3);
else if (message == "--folder")
action(4);
else if (message == "--uploadlast")
uploadLast();
else if (message == "--viewhistory")
showHistoryDialog();
}
void LightscreenWindow::notify(const Screenshot::Result &result)
{
switch (result)
{
case Screenshot::Success:
mTrayIcon->setIcon(QIcon(":/icons/lightscreen.yes"));
#ifdef Q_OS_WIN
if (mTaskbarButton)
- mTaskbarButton->SetOverlayIcon(os::icon("yes"), tr("Success!"));
+ mTaskbarButton->setOverlayIcon(os::icon("yes"));
#endif
setWindowTitle(tr("Success!"));
break;
case Screenshot::Fail:
mTrayIcon->setIcon(QIcon(":/icons/lightscreen.no"));
setWindowTitle(tr("Failed!"));
#ifdef Q_OS_WIN
- if (mTaskbarButton)
- mTaskbarButton->SetOverlayIcon(os::icon("no"), tr("Failed!"));
+ if (mTaskbarButton) {
+ mTaskbarButton->setOverlayIcon(os::icon("no"));
+ }
#endif
break;
case Screenshot::Cancel:
setWindowTitle(tr("Cancelled!"));
break;
}
QTimer::singleShot(2000, this, SLOT(restoreNotification()));
}
void LightscreenWindow::preview(Screenshot* screenshot)
{
if (screenshot->options().preview) {
if (!mPreviewDialog) {
mPreviewDialog = new PreviewDialog(this);
}
mPreviewDialog->add(screenshot);
}
else {
screenshot->confirm(true);
}
}
void LightscreenWindow::quit()
{
settings()->setValue("position", pos());
int answer = 0;
QString doing;
if (ScreenshotManager::instance()->activeCount() > 0) {
doing = tr("processing");
}
if (Uploader::instance()->uploading() > 0) {
if (doing.isEmpty()) {
doing = tr("uploading");
}
else {
doing = tr("processing and uploading");
}
}
if (!doing.isEmpty()) {
answer = QMessageBox::question(this,
tr("Are you sure you want to quit?"),
tr("Lightscreen is currently %1 screenshots. Are you sure you want to quit?").arg(doing),
tr("Quit"),
tr("Don't Quit"));
}
if (answer == 0)
emit finished();
}
void LightscreenWindow::restoreNotification()
{
if (mTrayIcon)
mTrayIcon->setIcon(QIcon(":/icons/lightscreen.small"));
#ifdef Q_OS_WIN
if (mTaskbarButton)
- mTaskbarButton->SetOverlayIcon(QIcon(), "");
+ mTaskbarButton->clearOverlayIcon();
#endif
updateUploadStatus();
}
void LightscreenWindow::screenshotAction(int mode)
{
int delayms = -1;
bool optionsHide = settings()->value("options/hide").toBool(); // Option cache, used a couple of times.
if (!mHideTrigger) {
mWasVisible = isVisible();
mHideTrigger = true;
}
// Applying pre-screenshot settings
if (optionsHide) {
hide();
#ifndef Q_WS_X11 // X is not quick enough and the notification ends up everywhere but in the icon
if (mTrayIcon)
mTrayIcon->hide();
#endif
}
// Screenshot delay
delayms = settings()->value("options/delay", 0).toInt();
delayms = delayms * 1000; // Converting the delay to milliseconds.
delayms += 400;
if (optionsHide && mPreviewDialog) {
if (mPreviewDialog->count() >= 1) {
mPreviewDialog->hide();
}
}
// The delayed functions works using the static variable lastMode
// which keeps the argument so a QTimer can call this function again.
if (delayms > 0) {
if (mLastMode < 0) {
mLastMode = mode;
QTimer::singleShot(delayms, this, SLOT(screenshotAction()));
return;
}
else {
mode = mLastMode;
mLastMode = -1;
}
}
static Screenshot::Options options;
if (!mDoCache) {
// Populating the option object that will then be passed to the screenshot engine (sounds fancy huh?)
options.file = settings()->value("file/enabled").toBool();
options.format = (Screenshot::Format) settings()->value("file/format").toInt();
options.prefix = settings()->value("file/prefix").toString();
QDir dir(settings()->value("file/target").toString());
dir.makeAbsolute();
options.directory = dir;
options.quality = settings()->value("options/quality", 100).toInt();
options.currentMonitor = settings()->value("options/currentMonitor", false).toBool();
options.clipboard = settings()->value("options/clipboard", true).toBool();
options.imgurClipboard = settings()->value("options/imgurClipboard", false).toBool();
options.preview = settings()->value("options/preview", false).toBool();
options.magnify = settings()->value("options/magnify", false).toBool();
options.cursor = settings()->value("options/cursor", true).toBool();
options.saveAs = settings()->value("options/saveAs", false).toBool();
options.animations = settings()->value("options/animations", true).toBool();
options.replace = settings()->value("options/replace", false).toBool();
options.upload = settings()->value("options/uploadAuto", false).toBool();
options.optimize = settings()->value("options/optipng", false).toBool();
Screenshot::NamingOptions namingOptions;
namingOptions.naming = (Screenshot::Naming) settings()->value("file/naming").toInt();
namingOptions.leadingZeros = settings()->value("options/naming/leadingZeros", 0).toInt();
namingOptions.flip = settings()->value("options/flip", false).toBool();
namingOptions.dateFormat = settings()->value("options/naming/dateFormat", "yyyy-MM-dd").toString();
options.namingOptions = namingOptions;
mDoCache = true;
}
options.mode = mode;
ScreenshotManager::instance()->take(options);
}
void LightscreenWindow::screenshotActionTriggered(QAction* action)
{
screenshotAction(action->data().toInt());
}
void LightscreenWindow::showHotkeyError(const QStringList &hotkeys)
{
static bool dontShow = false;
if (dontShow)
return;
QString messageText;
messageText = tr("Some hotkeys could not be registered, they might already be in use");
if (hotkeys.count() > 1) {
messageText += tr("<br>The failed hotkeys are the following:") + "<ul>";
foreach(const QString &hotkey, hotkeys) {
messageText += QString("%1%2%3").arg("<li><b>").arg(hotkey).arg("</b></li>");
}
messageText += "</ul>";
}
else {
messageText += tr("<br>The failed hotkey is <b>%1</b>").arg(hotkeys[0]);
}
messageText += tr("<br><i>What do you want to do?</i>");
QMessageBox msgBox(this);
msgBox.setWindowTitle(tr("Lightscreen"));
msgBox.setText(messageText);
QPushButton *changeButton = msgBox.addButton(tr("Change") , QMessageBox::ActionRole);
QPushButton *disableButton = msgBox.addButton(tr("Disable"), QMessageBox::ActionRole);
QPushButton *exitButton = msgBox.addButton(tr("Quit") , QMessageBox::ActionRole);
msgBox.exec();
if (msgBox.clickedButton() == exitButton) {
dontShow = true;
QTimer::singleShot(10, this, SLOT(quit()));
}
else if (msgBox.clickedButton() == changeButton) {
showOptions();
}
else if (msgBox.clickedButton() == disableButton) {
foreach(const QString &hotkey, hotkeys) {
settings()->setValue(QString("actions/%1/enabled").arg(hotkey), false);
}
}
}
void LightscreenWindow::showHistoryDialog()
{
HistoryDialog historyDialog(this);
historyDialog.exec();
updateUploadStatus();
}
void LightscreenWindow::showOptions()
{
GlobalShortcutManager::clear();
QPointer<OptionsDialog> optionsDialog = new OptionsDialog(this);
optionsDialog->exec();
optionsDialog->deleteLater();
applySettings();
}
void LightscreenWindow::showScreenshotMessage(const Screenshot::Result &result, const QString &fileName)
{
if (result == Screenshot::Cancel)
return;
// Showing message.
QString title;
QString message;
if (result == Screenshot::Success) {
title = QFileInfo(fileName).fileName();
if (settings()->value("file/target").toString().isEmpty()) {
message = QDir::toNativeSeparators(QCoreApplication::applicationDirPath());
}
else {
message = tr("Saved to \"%1\"").arg(settings()->value("file/target").toString());
}
}
else {
title = tr("The screenshot was not taken");
message = tr("An error occurred.");
}
mLastMessage = 1;
mTrayIcon->showMessage(title, message);
}
void LightscreenWindow::showUploaderError(const QString &error)
{
mLastMessage = -1;
if (mTrayIcon && !error.isEmpty() && settings()->value("options/message").toBool()) {
mTrayIcon->showMessage(tr("Upload error"), error);
}
updateUploadStatus();
}
void LightscreenWindow::showUploaderMessage(QString fileName, QString url)
{
if (mTrayIcon && settings()->value("options/message").toBool() && !url.isEmpty()) {
QString screenshot = QFileInfo(fileName).fileName();
if (screenshot.startsWith(".lstemp."))
screenshot = tr("Screenshot");
mLastMessage = 2;
mTrayIcon->showMessage(tr("%1 uploaded").arg(screenshot), tr("Click here to go to %1").arg(url));
}
updateUploadStatus();
}
void LightscreenWindow::toggleVisibility(QSystemTrayIcon::ActivationReason reason)
{
if (reason != QSystemTrayIcon::DoubleClick)
return;
if (isVisible()) {
hide();
}
else {
show();
os::setForegroundWindow(this);
}
}
void LightscreenWindow::updateUploadStatus()
{
int uploadCount = Uploader::instance()->uploading();
QString statusString;
if (uploadCount > 0) {
statusString = tr("%1 uploading - Lightscreen").arg(uploadCount);
emit uploading(true);
}
else {
statusString = tr("Lightscreen");
emit uploading(false);
#ifdef Q_OS_WIN
if (mTaskbarButton) {
- mTaskbarButton->SetProgresValue(0, 0);
- mTaskbarButton->SetState(STATE_NOPROGRESS);
+ mTaskbarButton->progress()->setVisible(false);
}
#endif
}
if (mTrayIcon) {
mTrayIcon->setToolTip(statusString);
}
setWindowTitle(statusString);
}
void LightscreenWindow::updaterDone(bool result)
{
settings()->setValue("lastUpdateCheck", QDate::currentDate().dayOfYear());
if (!result)
return;
QMessageBox msgBox;
msgBox.setWindowTitle(tr("Lightscreen"));
msgBox.setText(tr("There's a new version of Lightscreen available.<br>Would you like to see more information?<br>(<em>You can turn this notification off</em>)"));
msgBox.setIcon(QMessageBox::Information);
QPushButton *yesButton = msgBox.addButton(QMessageBox::Yes);
QPushButton *turnOffButton = msgBox.addButton(tr("Turn Off"), QMessageBox::ActionRole);
QPushButton *remindButton = msgBox.addButton(tr("Remind Me Later"), QMessageBox::RejectRole);
Q_UNUSED(remindButton);
msgBox.exec();
if (msgBox.clickedButton() == yesButton) {
QDesktopServices::openUrl(QUrl("http://lightscreen.sourceforge.net/whatsnew/?from=" + qApp->applicationVersion()));
}
else if (msgBox.clickedButton() == turnOffButton) {
settings()->setValue("options/disableUpdater", true);
}
mUpdater->deleteLater();
}
void LightscreenWindow::upload(const QString &fileName)
{
Uploader::instance()->upload(fileName);
}
void LightscreenWindow::uploadCancel()
{
if (Uploader::instance()->uploading() <= 0) {
return;
}
int confirm = QMessageBox::question(this, tr("Upload cancel"), tr("Do you want to cancel all screenshot uploads?"), tr("Cancel"), tr("Don't Cancel"));
if (confirm == 0) {
Uploader::instance()->cancel();
updateUploadStatus();
}
}
void LightscreenWindow::uploadLast()
{
upload(mLastScreenshot);
updateUploadStatus();
}
void LightscreenWindow::uploadProgress(qint64 sent, qint64 total)
{
#ifdef Q_OS_WIN
- if (mTaskbarButton)
- mTaskbarButton->SetProgresValue(sent, total);
+ if (mTaskbarButton) {
+ mTaskbarButton->progress()->setRange(0, total);
+ mTaskbarButton->progress()->setValue(sent);
+ }
if (isVisible() && total > 0) {
int uploadCount = Uploader::instance()->uploading();
int progress = (sent*100)/total;
if (uploadCount > 1) {
setWindowTitle(tr("%1% of %2 uploads - Lightscreen").arg(progress).arg(uploadCount));
}
else {
setWindowTitle(tr("%1% - Lightscreen").arg(progress));
}
}
#endif
}
void LightscreenWindow::uploadMenuShown()
{
QMenu *imgurMenu = qobject_cast<QMenu*>(sender());
imgurMenu->actions().at(0)->setEnabled(!mLastScreenshot.isEmpty());
}
void LightscreenWindow::windowHotkey()
{
screenshotAction(1);
}
void LightscreenWindow::windowPickerHotkey()
{
screenshotAction(3);
}
void LightscreenWindow::applySettings()
{
bool tray = settings()->value("options/tray").toBool();
if (tray && !mTrayIcon) {
createTrayIcon();
mTrayIcon->show();
}
else if (!tray && mTrayIcon) {
mTrayIcon->deleteLater();
}
connectHotkeys();
mDoCache = false;
if (settings()->value("lastScreenshot").isValid() && mLastScreenshot.isEmpty())
mLastScreenshot = settings()->value("lastScreenshot").toString();
os::setStartup(settings()->value("options/startup").toBool(), settings()->value("options/startupHide").toBool());
}
void LightscreenWindow::connectHotkeys()
{
// Set to true because if the hotkey is disabled it will show an error.
bool screen = true, area = true, window = true, windowPicker = true, open = true, directory = true;
if (settings()->value("actions/screen/enabled").toBool())
screen = GlobalShortcutManager::instance()->connect(settings()->value(
"actions/screen/hotkey").value<QKeySequence> (), this, SLOT(screenshotAction()));
if (settings()->value("actions/area/enabled").toBool())
area = GlobalShortcutManager::instance()->connect(settings()->value(
"actions/area/hotkey").value<QKeySequence> (), this, SLOT(areaHotkey()));
if (settings()->value("actions/window/enabled").toBool())
window = GlobalShortcutManager::instance()->connect(settings()->value(
"actions/window/hotkey").value<QKeySequence> (), this, SLOT(windowHotkey()));
if (settings()->value("actions/windowPicker/enabled").toBool())
windowPicker = GlobalShortcutManager::instance()->connect(settings()->value(
"actions/windowPicker/hotkey").value<QKeySequence> (), this, SLOT(windowPickerHotkey()));
if (settings()->value("actions/open/enabled").toBool())
open = GlobalShortcutManager::instance()->connect(settings()->value(
"actions/open/hotkey").value<QKeySequence> (), this, SLOT(show()));
if (settings()->value("actions/directory/enabled").toBool())
directory = GlobalShortcutManager::instance()->connect(settings()->value(
"actions/directory/hotkey").value<QKeySequence> (), this, SLOT(goToFolder()));
QStringList failed;
if (!screen) failed << "screen";
if (!area) failed << "area";
if (!window) failed << "window";
if (!windowPicker) failed << "window picker";
if (!open) failed << "open";
if (!directory) failed << "directory";
if (!failed.isEmpty())
showHotkeyError(failed);
}
void LightscreenWindow::createTrayIcon()
{
mTrayIcon = new QSystemTrayIcon(QIcon(":/icons/lightscreen.small"), this);
updateUploadStatus();
connect(mTrayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(toggleVisibility(QSystemTrayIcon::ActivationReason)));
connect(mTrayIcon, SIGNAL(messageClicked()), this, SLOT(messageClicked()));
QAction *hideAction = new QAction(QIcon(":/icons/lightscreen.small"), tr("Show&/Hide"), mTrayIcon);
connect(hideAction, SIGNAL(triggered()), this, SLOT(toggleVisibility()));
QAction *screenAction = new QAction(os::icon("screen"), tr("&Screen"), mTrayIcon);
screenAction->setData(QVariant(0));
QAction *windowAction = new QAction(os::icon("window"), tr("Active &Window"), this);
windowAction->setData(QVariant(1));
QAction *windowPickerAction = new QAction(os::icon("pickWindow"), tr("&Pick Window"), this);
windowPickerAction->setData(QVariant(3));
QAction *areaAction = new QAction(os::icon("area"), tr("&Area"), mTrayIcon);
areaAction->setData(QVariant(2));
QActionGroup *screenshotGroup = new QActionGroup(mTrayIcon);
screenshotGroup->addAction(screenAction);
screenshotGroup->addAction(areaAction);
screenshotGroup->addAction(windowAction);
screenshotGroup->addAction(windowPickerAction);
connect(screenshotGroup, SIGNAL(triggered(QAction*)), this, SLOT(screenshotActionTriggered(QAction*)));
// Duplicated for the screenshot button :(
QAction *uploadAction = new QAction(os::icon("imgur"), tr("&Upload last"), mTrayIcon);
uploadAction->setToolTip(tr("Upload the last screenshot you took to imgur.com"));
connect(uploadAction, SIGNAL(triggered()), this, SLOT(uploadLast()));
QAction *cancelAction = new QAction(os::icon("no"), tr("&Cancel upload"), mTrayIcon);
cancelAction->setToolTip(tr("Cancel the currently uploading screenshots"));
cancelAction->setEnabled(false);
connect(this, SIGNAL(uploading(bool)), cancelAction, SLOT(setEnabled(bool)));
connect(cancelAction, SIGNAL(triggered()), this, SLOT(uploadCancel()));
QAction *historyAction = new QAction(os::icon("view-history"), tr("View History"), mTrayIcon);
connect(historyAction, SIGNAL(triggered()), this, SLOT(showHistoryDialog()));
//
QAction *optionsAction = new QAction(os::icon("configure"), tr("View &Options"), mTrayIcon);
connect(optionsAction, SIGNAL(triggered()), this, SLOT(showOptions()));
QAction *goAction = new QAction(os::icon("folder"), tr("&Go to Folder"), mTrayIcon);
connect(goAction, SIGNAL(triggered()), this, SLOT(goToFolder()));
QAction *quitAction = new QAction(tr("&Quit"), mTrayIcon);
connect(quitAction, SIGNAL(triggered()), this, SLOT(quit()));
QMenu* screenshotMenu = new QMenu(tr("Screenshot"));
screenshotMenu->addAction(screenAction);
screenshotMenu->addAction(areaAction);
screenshotMenu->addAction(windowAction);
screenshotMenu->addAction(windowPickerAction);
// Duplicated for the screenshot button :(
QMenu* imgurMenu = new QMenu(tr("Upload"));
imgurMenu->addAction(uploadAction);
imgurMenu->addAction(cancelAction);
imgurMenu->addAction(historyAction);
imgurMenu->addSeparator();
QMenu* trayIconMenu = new QMenu;
trayIconMenu->addAction(hideAction);
trayIconMenu->addSeparator();
trayIconMenu->addMenu(imgurMenu);
trayIconMenu->addSeparator();
trayIconMenu->addMenu(screenshotMenu);
trayIconMenu->addAction(optionsAction);
trayIconMenu->addAction(goAction);
trayIconMenu->addSeparator();
trayIconMenu->addAction(quitAction);
mTrayIcon->setContextMenu(trayIconMenu);
}
-#ifdef Q_OS_WIN
-bool LightscreenWindow::winEvent(MSG *message, long *result)
-{
- Taskbar::GetInstance()->winEvent(message, result);
- return false;
-}
-#endif
-
QSettings *LightscreenWindow::settings() const
{
return ScreenshotManager::instance()->settings();
}
// Event handling
bool LightscreenWindow::event(QEvent *event)
{
if (event->type() == QEvent::Hide) {
settings()->setValue("position", pos());
}
else if (event->type() == QEvent::Close) {
if (settings()->value("options/tray").toBool() && settings()->value("options/closeHide").toBool()) {
closeToTrayWarning();
hide();
}
else if (settings()->value("options/closeHide").toBool()) {
if (closingWithoutTray())
hide();
}
else {
quit();
}
}
else if (event->type() == QEvent::Show) {
QPoint savedPosition = settings()->value("position").toPoint();
if (!savedPosition.isNull() && qApp->desktop()->availableGeometry().contains(QRect(savedPosition, size())))
move(savedPosition);
}
else if (event->type() == QEvent::KeyPress) {
QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
#ifdef Q_WS_MAC
if (keyEvent->modifiers() == Qt::ControlModifier && e->key() == Qt::Key_Period) {
keyEvent->ignore();
if(isVisible())
toggleVisibility();
return false;
}
else
#endif
if (!keyEvent->modifiers() && keyEvent->key() == Qt::Key_Escape) {
keyEvent->ignore();
if(isVisible())
toggleVisibility();
return false;
}
}
else if (event->type() == QEvent::LanguageChange) {
ui.retranslateUi(this);
resize(minimumSizeHint());
}
return QMainWindow::event(event);
}
diff --git a/lightscreenwindow.h b/lightscreenwindow.h
index 1c30bde..92d6910 100644
--- a/lightscreenwindow.h
+++ b/lightscreenwindow.h
@@ -1,120 +1,117 @@
/*
* Copyright (C) 2012 Christian Kaiser
*
* 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 library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifndef LIGHTSCREENWINDOW_H
#define LIGHTSCREENWINDOW_H
#include <QMainWindow>
#include <QPointer>
#include <QSystemTrayIcon>
#include "updater/updater.h"
#include "tools/screenshot.h"
#include "dialogs/previewdialog.h"
#include "ui_lightscreenwindow.h"
-#ifdef Q_OS_WIN
- #include "tools/qwin7utils/TaskbarButton.h"
-#endif
-
class QHttp;
class Updater;
class QSettings;
+class QWinTaskbarButton;
class LightscreenWindow : public QMainWindow
{
Q_OBJECT
public:
LightscreenWindow(QWidget *parent = 0);
~LightscreenWindow();
public slots:
void action(int mode = 3);
void areaHotkey();
void checkForUpdates();
void cleanup(Screenshot::Options &options);
void closeToTrayWarning();
bool closingWithoutTray();
void createUploadMenu();
void goToFolder();
void messageClicked();
void messageReceived(const QString &message);
void notify(const Screenshot::Result &result);
void preview(Screenshot* screenshot);
void quit();
void restoreNotification();
void screenshotAction(int mode = 0);
void screenshotActionTriggered(QAction* action);
void showHotkeyError(const QStringList &hotkeys);
void showHistoryDialog();
void showOptions();
void showScreenshotMessage(const Screenshot::Result &result, const QString &fileName);
void showUploaderError(const QString &error);
void showUploaderMessage(QString fileName, QString url);
void toggleVisibility(QSystemTrayIcon::ActivationReason reason = QSystemTrayIcon::DoubleClick);
void updateUploadStatus();
void updaterDone(bool result);
void upload(const QString &fileName);
void uploadCancel();
void uploadLast();
void uploadProgress(qint64 sent, qint64 total);
void uploadMenuShown();
void windowHotkey();
void windowPickerHotkey();
private slots:
void applySettings();
signals:
void uploading(bool uploading);
void finished();
private:
void connectHotkeys();
void createTrayIcon();
#ifdef Q_OS_WIN
bool winEvent(MSG *message, long *result);
#endif
// Convenience function
QSettings *settings() const;
protected:
bool event(QEvent *event);
private:
bool mDoCache;
bool mHideTrigger;
bool mReviveMain;
bool mWasVisible;
int mLastMessage;
int mLastMode;
QString mLastScreenshot;
QPointer<QSystemTrayIcon> mTrayIcon;
QPointer<PreviewDialog> mPreviewDialog;
QPointer<Updater> mUpdater;
Ui::LightscreenWindowClass ui;
#ifdef Q_OS_WIN
- QW7::TaskbarButton *mTaskbarButton;
+ QWinTaskbarButton *mTaskbarButton;
#endif
};
#endif // LIGHTSCREENWINDOW_H
diff --git a/main.cpp b/main.cpp
index a0388d2..1a4acc5 100644
--- a/main.cpp
+++ b/main.cpp
@@ -1,102 +1,97 @@
/*
* Copyright (C) 2012 Christian Kaiser
*
* 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 library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include <QApplication>
#include <QDesktopWidget>
#include <QLocale>
#include <QDebug>
#ifdef Q_OS_WIN
- #include "tools/qwin7utils/AppUserModel.h"
- #include "tools/qwin7utils/JumpList.h"
- #include "tools/qwin7utils/Taskbar.h"
- using namespace QW7;
+ #include <QtWinExtras>
#endif
#include "tools/os.h"
#include <QtSingleApplication>
#include "lightscreenwindow.h"
int main(int argc, char *argv[])
{
QtSingleApplication application(argc, argv);
application.setOrganizationName("K");
application.setApplicationName ("Lightscreen");
application.setApplicationVersion("2.0");
application.setQuitOnLastWindowClosed(false);
if (application.isRunning()) {
if (application.arguments().size() > 1) {
QStringList arguments = application.arguments();
arguments.removeFirst();
application.sendMessage(arguments.join(" "));
}
else {
application.sendMessage("--wake");
}
return 0;
}
LightscreenWindow lightscreen;
#ifdef Q_OS_WIN
// Windows 7 jumplists.
if (QSysInfo::windowsVersion() >= QSysInfo::WV_WINDOWS7) {
- AppUserModel::SetCurrentProcessExplicitAppUserModelID("Lightscreen");
-
- JumpList jumpList("Lightscreen");
-
- QList<JumpListItem> tasks;
- tasks.append(JumpListItem(application.applicationFilePath(), "--screen" , QObject::tr("Screen") , "", "", 0, application.applicationDirPath()));
- tasks.append(JumpListItem(application.applicationFilePath(), "--area" , QObject::tr("Area") , "", "", 0, application.applicationDirPath()));
- tasks.append(JumpListItem(application.applicationFilePath(), "--activewindow", QObject::tr("Active Window"), "", "", 0, application.applicationDirPath()));
- tasks.append(JumpListItem(application.applicationFilePath(), "--pickwindow" , QObject::tr("Pick Window") , "", "", 0, application.applicationDirPath()));
- tasks.append(JumpListItem());
- tasks.append(JumpListItem(application.applicationFilePath(), "--uploadlast" , QObject::tr("Upload Last") , "", "", 0, application.applicationDirPath()));
- tasks.append(JumpListItem(application.applicationFilePath(), "--viewhistory" , QObject::tr("View History") , "", "", 0, application.applicationDirPath()));
- tasks.append(JumpListItem());
- tasks.append(JumpListItem(application.applicationFilePath(), "--folder" , QObject::tr("Go to Folder") , "", "", 0, application.applicationDirPath()));
-
- jumpList.Begin();
- jumpList.AddUserTasks(tasks);
- jumpList.Commit();
- }
+ QWinJumpList* jumplist = new QWinJumpList(&lightscreen);
+
+ QWinJumpListCategory* screenshotCategory = new QWinJumpListCategory("Screenshot");
+ screenshotCategory->setVisible(true);
+ screenshotCategory->addLink(os::icon("screen") , QObject::tr("Screen") , application.applicationFilePath(), QStringList("--screen"));
+ screenshotCategory->addLink(os::icon("area") , QObject::tr("Area") , application.applicationFilePath(), QStringList("--area"));
+ screenshotCategory->addLink(os::icon("window") , QObject::tr("Active Window"), application.applicationFilePath(), QStringList("--activewindow"));
+ screenshotCategory->addLink(os::icon("pickWindow"), QObject::tr("Pick Window") , application.applicationFilePath(), QStringList("--activewindow"));
+
+ QWinJumpListCategory* uploadCategory = new QWinJumpListCategory("Upload");
+ uploadCategory->setVisible(true);
+ uploadCategory->addLink(os::icon("imgur") , QObject::tr("Upload Last") , application.applicationFilePath(), QStringList("--uploadlast"));
+ uploadCategory->addLink(os::icon("view-history"), QObject::tr("View History"), application.applicationFilePath(), QStringList("--viewhistory"));
+
+ QWinJumpListCategory* folderCategory = new QWinJumpListCategory;
+ folderCategory->setVisible(true);
+ folderCategory->addLink(os::icon("folder"), QObject::tr("Go to Folder") , application.applicationFilePath(), QStringList("--folder"));
+
+ jumplist->addCategory(screenshotCategory);
+ jumplist->addCategory(uploadCategory);
+ jumplist->addCategory(folderCategory);
+}
#endif
if (application.arguments().size() > 1) {
foreach (QString argument, application.arguments()) {
lightscreen.messageReceived(argument);
}
}
else {
lightscreen.show();
}
QObject::connect(&application, SIGNAL(messageReceived(const QString&)), &lightscreen, SLOT(messageReceived(const QString&)));
QObject::connect(&lightscreen, SIGNAL(finished()), &application, SLOT(quit()));
int result = application.exec();
-
-#ifdef Q_OS_WIN
- Taskbar::ReleaseInstance();
-#endif
-
return result;
}
diff --git a/tools/globalshortcut/NDKeyboardLayout.h b/tools/globalshortcut/NDKeyboardLayout.h
new file mode 100644
index 0000000..b2688f6
--- /dev/null
+++ b/tools/globalshortcut/NDKeyboardLayout.h
@@ -0,0 +1,135 @@
+/*
+ NDKeyboardLayout.h
+
+ Created by Nathan Day on 01.18.10 under a MIT-style license.
+ Copyright (c) 2010 Nathan Day
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+ */
+
+/*!
+ @header NDKeyboardLayout.h
+ @abstract Header file for NDKeyboardLayout
+ @author Nathan Day
+ */
+
+#import <Cocoa/Cocoa.h>
+#import <CoreServices/CoreServices.h>
+#import <Carbon/Carbon.h>
+
+struct ReverseMappingEntry;
+
+extern NSString * const NDKeyboardLayoutSelectedKeyboardInputSourceChangedNotification;
+extern NSString * const NDKeyboardLayoutPreviousKeyboardLayoutUserInfoKey;
+
+/*!
+ @function NDCocoaModifierFlagsForCarbonModifierFlags
+ Convert Carbon modifer flags to Cocoa modifier flags.
+ @param modifierFlags one or more of the flags <tt>shiftKey</tt>, <tt>controlKey</tt>, <tt>optionKey</tt>, <tt>cmdKey</tt>
+ */
+NSUInteger NDCocoaModifierFlagsForCarbonModifierFlags( NSUInteger modifierFlags );
+/*!
+ @function NDCarbonModifierFlagsForCocoaModifierFlags
+ Convert Cocoa modifer flags to Carbon modifier flags.
+ @param modifierFlags one or more of the flags <tt>NSShiftKeyMask</tt>, <tt>NSControlKeyMask</tt>, <tt>NSAlternateKeyMask</tt>, <tt>NSCommandKeyMask</tt>
+ */
+NSUInteger NDCarbonModifierFlagsForCocoaModifierFlags( NSUInteger modifierFlags );
+
+/*!
+ @class NDKeyboardLayout
+ @abstract Class for translating between key codes and key characters.
+ @discussion The key code for each key character can change between hardware and with localisation, <tt>NDKeyboardLayout</tt> handles translation between key codes and key characters as well as for generating strings for display purposes.
+ @helps Used by <tt>NDHotKeyEvent</tt>.
+ */
+@interface NDKeyboardLayout : NSObject {
+ CFDataRef keyboardLayoutData;
+ struct ReverseMappingEntry *mappings;
+ NSUInteger numberOfMappings;
+}
+
+@property(readonly, nonatomic) const UCKeyboardLayout *keyboardLayoutPtr;
+
+/*!
+ @method keyboardLayout
+ Get a keyboard layout for the current keyboard
+ */
++ (id)keyboardLayout;
+
+/*!
+ @method init
+ initialise a keyboard layout for the current keyboard, if that fails a keyboard layout for one of the languages
+ returned from <tt>[NSLocale preferredLanguages]</tt> is attempted and if finally if that fails a keyboard layout
+ for the most recently used ASCII-capable keyboard is created. If that fails then this method returns <tt>nil</tt>.
+ */
+- (id)init;
+/*!
+ @method initWithLanguage:
+ @abstract initialise a keyboard layout.
+ @discussion Initialises a KeyboardLayout with an <tt>TISInputSourceRef</tt> for the supplied language.
+ */
+- (id)initWithLanguage:(NSString *)langauge;
+/*!
+ @method initWithInputSource:
+ @abstract initialise a keyboard layout.
+ @discussion Initialises a KeyboardLayout with an <tt>TISInputSourceRef</tt>, this method is called with the result from <tt>initWithInputSource:TISCopyCurrentKeyboardInputSource()</tt>.
+ */
+- (id)initWithInputSource:(TISInputSourceRef)source;
+
+/*!
+ @method stringForCharacter:modifierFlags:
+ @abstract Get a string for display purposes.
+ @discussion <tt>stringForCharacter:modifierFlags:</tt> returns a string that can be displayed to the user, For example command-z would produce &#x2318;Z, shift-T would produce &#x21E7;T.
+ @param character The unmodified character on the keyboard.
+ @param modifierFlags Modifier flags <tt>NSControlKeyMask</tt>, <tt>NSAlternateKeyMask</tt>, <tt>NSShiftKeyMask</tt>, <tt>NSCommandKeyMask</tt> and <tt>NSNumericPadKeyMask</tt>.
+ */
+- (NSString*)stringForCharacter:(unichar)character modifierFlags:(UInt32)modifierFlags;
+/*!
+ @method stringForKeyCode:modifierFlags:
+ @abstract Get a string for display purposes.
+ @discussion <tt>stringForKeyCode:modifierFlags:</tt> returns a string that can be displayed to the user. This method is called by <tt>stringForCharacter::modifierFlags</tt> and is problem more useful most of the time.
+ @param keyCode A value specifying the virtual key code that is to be translated. For ADB keyboards, virtual key codes are in the range from 0 to 127.
+ @param modifierFlags Modifier flags <tt>NSControlKeyMask</tt>, <tt>NSAlternateKeyMask</tt>, <tt>NSShiftKeyMask</tt>, <tt>NSCommandKeyMask</tt> and <tt>NSNumericPadKeyMask</tt>.
+ */
+- (NSString*)stringForKeyCode:(UInt16)keyCode modifierFlags:(UInt32)modifierFlags;
+/*!
+ @method characterForKeyCode:
+ @abstract Get the key character for a given key code.
+ @discussion The character returned is the unmodified version on the keyboard.
+ @param keyCode A value specifying the virtual key code that is to be translated. For ADB keyboards, virtual key codes are in the range from 0 to 127.
+ @result The character for the unmodified version of the key.
+ */
+- (unichar)characterForKeyCode:(UInt16)keyCode;
+/*!
+ @method keyCodeForCharacter:numericPad:
+ @abstract Get the key code for a given key character.
+ @discussion The character pass in must be the unshifter character for the key, for example to get the key code for the '?' on keyboards where you type shift-/ to get '?' you should pass in the character '/"
+ @param character The unmodified character on the keyboard.
+ @param numericPad For the keycode of a key on the keypad where the same character is also on the main keyboard this flag needs to be <tt>YES</tt>.
+ */
+- (UInt16)keyCodeForCharacter:(unichar)character numericPad:(BOOL)numericPad;
+/*!
+ @method keyCodeForCharacter:
+ @abstract Get the key code for a given key character.
+ @discussion Calls <tt>keyCodeForCharacter:numericPad:</tt> with the keypad flag set to <tt>NO</tt>
+ @param character The unmodified character on the keyboard.
+ @result A value specifying the virtual key code that is to be translated. For ADB keyboards, virtual key codes are in the range from 0 to 127.
+ */
+- (UInt16)keyCodeForCharacter:(unichar)character;
+
+@end
diff --git a/tools/globalshortcut/NDKeyboardLayout.m b/tools/globalshortcut/NDKeyboardLayout.m
new file mode 100644
index 0000000..2da9926
--- /dev/null
+++ b/tools/globalshortcut/NDKeyboardLayout.m
@@ -0,0 +1,491 @@
+/*
+ NDKeyboardLayout.m
+
+ Created by Nathan Day on 01.18.10 under a MIT-style license.
+ Copyright (c) 2010 Nathan Day
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+ */
+
+#import "NDKeyboardLayout.h"
+#include <libkern/OSAtomic.h>
+
+NSString * const NDKeyboardLayoutSelectedKeyboardInputSourceChangedNotification = @"NDKeyboardLayoutSelectedKeyboardInputSourceChanged";
+NSString * const NDKeyboardLayoutPreviousKeyboardLayoutUserInfoKey = @"NDKeyboardLayoutPreviousKeyboardLayout";
+
+struct ReverseMappingEntry
+{
+ UniChar character;
+ BOOL keypad;
+ UInt16 keyCode;
+};
+
+struct UnmappedEntry
+{
+ UniChar character;
+ UInt16 keyCode;
+ unichar description[4];
+};
+
+struct UnmappedEntry unmappedKeys[] =
+{
+ {NSDeleteFunctionKey, 0x33, {0x232B,'\0','\0','\0'}},
+ {NSF17FunctionKey, 0x40, {'F','1','7','\0'}},
+ {NSClearDisplayFunctionKey, 0x47, {0x2327,'\0','\0','\0'}},
+ {NSF18FunctionKey, 0x4F, {'F','1','8','\0'}},
+ {NSF19FunctionKey, 0x50, {'F','1','9','\0'}},
+ {NSF5FunctionKey, 0x60, {'F','5','\0','\0'}},
+ {NSF6FunctionKey, 0x61, {'F','6','\0','\0'}},
+ {NSF7FunctionKey, 0x62, {'F','7','\0','\0'}},
+ {NSF3FunctionKey, 0x63, {'F','3','\0','\0'}},
+ {NSF8FunctionKey, 0x64, {'F','8','\0','\0'}},
+ {NSF9FunctionKey, 0x65, {'F','9','\0','\0'}},
+ {NSF11FunctionKey, 0x67, {'F','1','1','\0'}},
+ {NSF14FunctionKey, 0x68, {'F','1','4','\0'}},
+ {NSF13FunctionKey, 0x69, {'F','1','3','\0'}},
+ {NSF16FunctionKey, 0x6A, {'F','1','6','\0'}},
+ {NSF10FunctionKey, 0x6D, {'F','1','0','\0'}},
+ {NSF12FunctionKey, 0x6F, {'F','1','2','\0'}},
+ {NSF15FunctionKey, 0x71, {'F','1','5','\0'}},
+ {NSHomeFunctionKey, 0x73, {0x21F1,'\0','\0','\0'}},
+ {NSPageUpFunctionKey, 0x74, {0x21DE,'\0','\0','\0'}},
+ {NSDeleteCharFunctionKey, 0x75, {0x2326,'\0','\0','\0'}},
+ {NSF4FunctionKey, 0x76, {'F','4','\0','\0'}},
+ {NSEndFunctionKey, 0x77, {0x21F2,'\0','\0','\0'}},
+ {NSF2FunctionKey, 0x78, {'F','2','\0','\0'}},
+ {NSPageDownFunctionKey, 0x79, {0x21DF,'\0','\0','\0'}},
+ {NSF1FunctionKey, 0x7A, {'F','1','\0','\0'}},
+ {NSLeftArrowFunctionKey, 0x7B, {0x2190,'\0','\0','\0'}},
+ {NSRightArrowFunctionKey, 0x7C, {0x2192,'\0','\0','\0'}},
+ {NSDownArrowFunctionKey, 0x7D, {0x2193,'\0','\0','\0'}},
+ {NSUpArrowFunctionKey, 0x7E, {0x2191,'\0','\0','\0'}}
+// {NSF20FunctionKey, 0xXXXX},
+// {NSF21FunctionKey, 0xXXXX},
+// {NSF22FunctionKey, 0xXXXX},
+// {NSF23FunctionKey, 0xXXXX},
+// {NSF24FunctionKey, 0xXXXX},
+// {NSF25FunctionKey, 0xXXXX},
+// {NSF26FunctionKey, 0xXXXX},
+// {NSF27FunctionKey, 0xXXXX},
+// {NSF28FunctionKey, 0xXXXX},
+// {NSF29FunctionKey, 0xXXXX},
+// {NSF30FunctionKey, 0xXXXX},
+// {NSF31FunctionKey, 0xXXXX},
+// {NSF32FunctionKey, 0xXXXX},
+// {NSF33FunctionKey, 0xXXXX},
+// {NSF34FunctionKey, 0xXXXX},
+// {NSF35FunctionKey, 0xXXXX},
+// {NSInsertFunctionKey, 0xXXXX},
+// {NSBeginFunctionKey, 0xXXXX},
+// {NSPrintScreenFunctionKey, 0xXXXX},
+// {NSScrollLockFunctionKey, 0xXXXX},
+// {NSPauseFunctionKey, 0xXXXX},
+// {NSSysReqFunctionKey, 0xXXXX},
+// {NSBreakFunctionKey, 0xXXXX},
+// {NSResetFunctionKey, 0xXXXX},
+// {NSStopFunctionKey, 0xXXXX},
+// {NSMenuFunctionKey, 0xXXXX},
+// {NSUserFunctionKey, 0xXXXX},
+// {NSSystemFunctionKey, 0xXXXX},
+// {NSPrintFunctionKey, 0xXXXX},
+// {NSClearLineFunctionKey, 0xXXXX},
+// {NSInsertLineFunctionKey, 0xXXXX},
+// {NSDeleteLineFunctionKey, 0xXXXX},
+// {NSInsertCharFunctionKey, 0xXXXX},
+// {NSPrevFunctionKey, 0xXXXX},
+// {NSNextFunctionKey, 0xXXXX},
+// {NSSelectFunctionKey, 0xXXXX},
+// {NSExecuteFunctionKey, 0xXXXX},
+// {NSUndoFunctionKey, 0xXXXX},
+// {NSRedoFunctionKey, 0xXXXX},
+// {NSFindFunctionKey, 0xXXXX},
+// {NSHelpFunctionKey, 0xXXXX},
+// {NSModeSwitchFunctionKey, 0xXXXX}
+};
+
+/*@interface NDKeyboardLayout ()
+{
+@private
+ CFDataRef keyboardLayoutData;
+ struct ReverseMappingEntry * mappings;
+ NSUInteger numberOfMappings;
+}
+
+@property(readonly,nonatomic) const UCKeyboardLayout * keyboardLayoutPtr;
+
+@end*/
+
+static int _reverseMappingEntryCmpFunc( const void * a, const void * b )
+{
+ struct ReverseMappingEntry * theA = (struct ReverseMappingEntry*)a,
+ * theB = (struct ReverseMappingEntry*)b;
+ return theA->character != theB->character ? theA->character - theB->character : theA->keypad - theB->keypad;
+}
+
+static struct ReverseMappingEntry * _searchreverseMapping( struct ReverseMappingEntry * aMapping, NSUInteger aLength, struct ReverseMappingEntry * aSearchValue )
+{
+ NSInteger low = 0,
+ high = aLength - 1,
+ mid,
+ result;
+
+ while( low <= high )
+ {
+ mid = (low + high)>>1;
+ result = _reverseMappingEntryCmpFunc( &aMapping[mid], aSearchValue );
+ if( result > 0 )
+ high = mid - 1;
+ else if( result < 0 )
+ low = mid + 1;
+ else
+ return &aMapping[mid];
+ }
+ return NULL;
+}
+
+static struct UnmappedEntry * _unmappedEntryForKeyCode( UInt16 aKeyCode )
+{
+ NSInteger low = 0,
+ high = sizeof(unmappedKeys)/sizeof(*unmappedKeys) - 1,
+ mid,
+ result;
+
+ while( low <= high )
+ {
+ mid = (low + high)>>1;
+ result = unmappedKeys[mid].keyCode - aKeyCode;
+ if( result > 0 )
+ high = mid - 1;
+ else if( result < 0 )
+ low = mid + 1;
+ else
+ return &unmappedKeys[mid];
+ }
+ return '\0';
+}
+
+static const size_t kBufferSize = 4;
+static NSUInteger _characterForModifierFlags( unichar aBuff[kBufferSize], UInt32 aModifierFlags )
+{
+ NSUInteger thePos = 0;
+ memset( aBuff, 0, kBufferSize );
+ if(aModifierFlags & NSControlKeyMask)
+ aBuff[thePos++] = kControlUnicode;
+
+ if(aModifierFlags & NSAlternateKeyMask)
+ aBuff[thePos++] = kOptionUnicode;
+
+ if(aModifierFlags & NSShiftKeyMask)
+ aBuff[thePos++] = kShiftUnicode;
+
+ if(aModifierFlags & NSCommandKeyMask)
+ aBuff[thePos++] = kCommandUnicode;
+ return thePos;
+}
+
+/*
+ * NDCocoaModifierFlagsForCarbonModifierFlags()
+ */
+NSUInteger NDCocoaModifierFlagsForCarbonModifierFlags( NSUInteger aModifierFlags )
+{
+ NSUInteger theCocoaModifierFlags = 0;
+
+ if(aModifierFlags & shiftKey)
+ theCocoaModifierFlags |= NSShiftKeyMask;
+
+ if(aModifierFlags & controlKey)
+ theCocoaModifierFlags |= NSControlKeyMask;
+
+ if(aModifierFlags & optionKey)
+ theCocoaModifierFlags |= NSAlternateKeyMask;
+
+ if(aModifierFlags & cmdKey)
+ theCocoaModifierFlags |= NSCommandKeyMask;
+
+ return theCocoaModifierFlags;
+}
+
+/*
+ * NDCarbonModifierFlagsForCocoaModifierFlags()
+ */
+NSUInteger NDCarbonModifierFlagsForCocoaModifierFlags( NSUInteger aModifierFlags )
+{
+ NSUInteger theCarbonModifierFlags = 0;
+
+ if(aModifierFlags & NSShiftKeyMask)
+ theCarbonModifierFlags |= shiftKey;
+
+ if(aModifierFlags & NSControlKeyMask)
+ theCarbonModifierFlags |= controlKey;
+
+ if(aModifierFlags & NSAlternateKeyMask)
+ theCarbonModifierFlags |= optionKey;
+
+ if(aModifierFlags & NSCommandKeyMask)
+ theCarbonModifierFlags |= cmdKey;
+
+ return theCarbonModifierFlags;
+}
+
+@implementation NDKeyboardLayout
+
+#pragma mark Utility Methods
+
+- (void)generateMappings
+{
+ mappings = (struct ReverseMappingEntry*)calloc( 128 + sizeof(unmappedKeys)/sizeof(*unmappedKeys), sizeof(struct ReverseMappingEntry) );
+
+ numberOfMappings = 0;
+
+ for( NSUInteger i = 0; i < 128; i++ )
+ {
+ UInt32 theDeadKeyState = 0;
+ UniCharCount theLength = 0;
+
+ if( UCKeyTranslate( self.keyboardLayoutPtr,
+ i,
+ kUCKeyActionDisplay,
+ 0,
+ LMGetKbdType(),
+ kUCKeyTranslateNoDeadKeysBit,
+ &theDeadKeyState,
+ 1,
+ &theLength,
+ &mappings[numberOfMappings].character ) == noErr && theLength > 0 && isprint(mappings[numberOfMappings].character) )
+ {
+ mappings[numberOfMappings].keyCode = i;
+ numberOfMappings++;
+ }
+ }
+
+ /* add unmapped keys */
+ for( NSUInteger i = 0; i < sizeof(unmappedKeys)/sizeof(*unmappedKeys); i++ )
+ {
+ mappings[numberOfMappings].character = unmappedKeys[i].character;
+ mappings[numberOfMappings].keyCode = unmappedKeys[i].keyCode;
+ numberOfMappings++;
+ }
+
+ mappings = (struct ReverseMappingEntry*)realloc( (void*)mappings, numberOfMappings*sizeof(struct ReverseMappingEntry) );
+
+ // sort so we can perform binary searches
+ qsort( (void *)mappings, numberOfMappings, sizeof(struct ReverseMappingEntry), _reverseMappingEntryCmpFunc );
+
+ /* find keypad keys and set the keypad flag */
+ for( NSUInteger i = 1; i < numberOfMappings; i++ )
+ {
+ NSParameterAssert( mappings[i-1].keyCode != mappings[i].keyCode );
+ if( mappings[i-1].character == mappings[i].character ) // assume large keycode is a keypad
+ {
+ if( mappings[i-1].keyCode > mappings[i].keyCode ) // make the keypad entry is second
+ {
+ UInt16 theTemp = mappings[i-1].keyCode;
+ mappings[i-1].keyCode = mappings[i].keyCode;
+ mappings[i].keyCode = theTemp;
+ }
+ mappings[i].keypad = YES;
+ }
+ }
+
+#ifdef DEBUGGING_CODE
+ for( NSUInteger i = 1; i < numberOfMappings; i++ )
+ {
+ fprintf( stderr, "%d -> %c[%d]%s\n",
+ mappings[i].keyCode,
+ (char)mappings[i].character,
+ mappings[i].character,
+ mappings[i].keypad ? " keypad" : ""
+ );
+ NSAssert3( mappings[i-1].character <= mappings[i].character, @"[%d] %d <= %d", i, mappings[i-1].character, mappings[i].character );
+ }
+#endif
+}
+
+#pragma mark Constructor Methods
+
+static volatile NDKeyboardLayout * kCurrentKeyboardLayout = nil;
+
+void NDKeyboardLayoutNotificationCallback( CFNotificationCenterRef aCenter, void * self, CFStringRef aName, const void * anObj, CFDictionaryRef aUserInfo )
+{
+ NSDictionary * theUserInfo = [NSDictionary dictionaryWithObject:kCurrentKeyboardLayout forKey:NDKeyboardLayoutPreviousKeyboardLayoutUserInfoKey];
+ @synchronized(self) { [kCurrentKeyboardLayout release], kCurrentKeyboardLayout = nil; }
+ [[NSNotificationCenter defaultCenter] postNotificationName:NDKeyboardLayoutSelectedKeyboardInputSourceChangedNotification object:self userInfo:theUserInfo];
+}
+
++ (void)initialize
+{
+ CFNotificationCenterAddObserver( CFNotificationCenterGetLocalCenter(),
+ (const void *)self,
+ NDKeyboardLayoutNotificationCallback,
+ kTISNotifySelectedKeyboardInputSourceChanged,
+ NULL,
+ CFNotificationSuspensionBehaviorDeliverImmediately
+ );
+}
+
++ (id)keyboardLayout
+{
+ if( kCurrentKeyboardLayout == nil )
+ {
+ @synchronized(self)
+ { /*
+ Try different method until we succeed.
+ */
+ TISInputSourceRef (*theInputSourceFunctions[])() = {
+ TISCopyInputMethodKeyboardLayoutOverride,
+ TISCopyCurrentKeyboardLayoutInputSource,
+ TISCopyCurrentASCIICapableKeyboardLayoutInputSource
+ };
+
+ for( NSUInteger i = 0; i < sizeof(theInputSourceFunctions)/sizeof(*theInputSourceFunctions) && kCurrentKeyboardLayout == nil; i++ )
+ {
+ TISInputSourceRef theInputSource = theInputSourceFunctions[i]();
+ if( theInputSource != NULL )
+ {
+ kCurrentKeyboardLayout = [[self alloc] initWithInputSource:theInputSource];
+ CFRelease(theInputSource);
+ }
+ }
+ }
+ }
+
+ return kCurrentKeyboardLayout;
+}
+
+- (id)init
+{
+ [self release];
+ return [[NDKeyboardLayout keyboardLayout] retain];
+}
+
+- (id)initWithLanguage:(NSString *)aLangauge { return [self initWithInputSource:TISCopyInputSourceForLanguage((CFStringRef)aLangauge)]; }
+
+- (id)initWithInputSource:(TISInputSourceRef)aSource
+{
+ if( (self = [super init]) != nil )
+ {
+ if( aSource != NULL && (keyboardLayoutData = (CFDataRef)CFMakeCollectable(TISGetInputSourceProperty(aSource, kTISPropertyUnicodeKeyLayoutData))) != nil )
+ {
+ CFRetain( keyboardLayoutData );
+ }
+ else
+ self = nil, [self release];
+ }
+ return self;
+}
+
+- (void)dealloc
+{
+ if( mappings != NULL )
+ free( (void*)mappings );
+ if( keyboardLayoutData != NULL )
+ CFRelease( keyboardLayoutData );
+ [super dealloc];
+}
+
+- (NSString*)stringForCharacter:(unichar)aCharacter modifierFlags:(UInt32)aModifierFlags
+{
+ return [self stringForKeyCode:[self keyCodeForCharacter:aCharacter numericPad:(aModifierFlags&NSNumericPadKeyMask) != 0] modifierFlags:aModifierFlags];
+}
+
+- (NSString*)stringForKeyCode:(UInt16)aKeyCode modifierFlags:(UInt32)aModifierFlags
+{
+ NSString * theResult = nil;
+ struct UnmappedEntry * theEntry = _unmappedEntryForKeyCode( aKeyCode ); // is it one of the unmapped values
+
+ if( theEntry != NULL )
+ {
+ unichar theCharacter[sizeof(theEntry->description)/sizeof(*theEntry->description)+4+1];
+ memset( theCharacter, 0, sizeof(theCharacter) );
+ NSUInteger thePos = _characterForModifierFlags(theCharacter,aModifierFlags);
+ memcpy( theCharacter+thePos, theEntry->description, sizeof(theEntry->description) );
+ theResult = [NSString stringWithCharacters:theCharacter length:sizeof(theEntry->description)/sizeof(*theEntry->description)+thePos];
+ }
+ else
+ {
+ UInt32 theDeadKeyState = 0;
+ UniCharCount theLength = 0;
+ UniChar theCharacter[260];
+
+ NSUInteger thePos = _characterForModifierFlags(theCharacter,aModifierFlags);
+
+ if( UCKeyTranslate( self.keyboardLayoutPtr, aKeyCode,
+ kUCKeyActionDisplay,
+ NDCarbonModifierFlagsForCocoaModifierFlags(aModifierFlags),
+ LMGetKbdType(),
+ kUCKeyTranslateNoDeadKeysBit,
+ &theDeadKeyState,
+ sizeof(theCharacter)/sizeof(*theCharacter)-thePos,
+ &theLength,
+ theCharacter+thePos ) == noErr )
+ {
+
+ theResult = [[NSString stringWithCharacters:theCharacter length:theLength+thePos] uppercaseString];
+ }
+ }
+ return theResult;
+}
+
+- (unichar)characterForKeyCode:(UInt16)aKeyCode
+{
+ unichar theChar = 0;
+ struct UnmappedEntry * theEntry = _unmappedEntryForKeyCode( aKeyCode );
+
+ if( theEntry == NULL ) // is it one of the unmapped values
+ {
+ UInt32 theDeadKeyState = 0;
+ UniCharCount theLength = 0;
+ UniChar theCharacter[256];
+
+ if( UCKeyTranslate( self.keyboardLayoutPtr, aKeyCode,
+ kUCKeyActionDisplay,
+ 0,
+ LMGetKbdType(),
+ kUCKeyTranslateNoDeadKeysBit,
+ &theDeadKeyState,
+ sizeof(theCharacter)/sizeof(*theCharacter),
+ &theLength,
+ theCharacter ) == noErr )
+ {
+ theChar = theCharacter[0];
+ }
+ }
+ else
+ theChar = theEntry->character;
+ return toupper(theChar);
+}
+
+- (UInt16)keyCodeForCharacter:(unichar)aCharacter { return [self keyCodeForCharacter:aCharacter numericPad:NO]; }
+
+- (UInt16)keyCodeForCharacter:(unichar)aCharacter numericPad:(BOOL)aNumericPad
+{
+ struct ReverseMappingEntry theSearchValue = { tolower(aCharacter), aNumericPad, 0 };
+ struct ReverseMappingEntry * theEntry = NULL;
+ if( mappings == NULL )
+ [self generateMappings];
+ theEntry = _searchreverseMapping( mappings, numberOfMappings, &theSearchValue );
+ return theEntry ? theEntry->keyCode : '\0';
+}
+
+#pragma mark - private
+
+- (const UCKeyboardLayout *)keyboardLayoutPtr { return (const UCKeyboardLayout *)CFDataGetBytePtr(keyboardLayoutData); }
+
+@end
+
diff --git a/tools/globalshortcut/globalshortcut.pri b/tools/globalshortcut/globalshortcut.pri
index 9a23c0a..0c788ac 100644
--- a/tools/globalshortcut/globalshortcut.pri
+++ b/tools/globalshortcut/globalshortcut.pri
@@ -1,14 +1,18 @@
HEADERS += $$PWD/globalshortcutmanager.h $$PWD/globalshortcuttrigger.h
SOURCES += $$PWD/globalshortcutmanager.cpp
-INCLUDEPATH += $$PWD
DEPENDPATH += $$PWD
unix:!mac {
SOURCES += $$PWD/globalshortcutmanager_x11.cpp
}
win32: {
SOURCES += $$PWD/globalshortcutmanager_win.cpp
}
mac: {
- SOURCES += $$PWD/globalshortcutmanager_mac.cpp
+ *g++*:QMAKE_OBJECTIVE_CFLAGS += -std=gnu99
+ OBJECTIVE_SOURCES += \
+ $$PWD/globalshortcutmanager_mac.mm \
+ $$PWD/NDKeyboardLayout.m
+ HEADERS += \
+ $$PWD/NDKeyboardLayout.h
}
diff --git a/tools/globalshortcut/globalshortcutmanager.cpp b/tools/globalshortcut/globalshortcutmanager.cpp
index 4735360..d08e1b3 100644
--- a/tools/globalshortcut/globalshortcutmanager.cpp
+++ b/tools/globalshortcut/globalshortcutmanager.cpp
@@ -1,98 +1,101 @@
/*
* globalshortcutmanager.cpp - Class managing global shortcuts
* Copyright (C) 2006 Maciej Niedzielski
*
* 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 library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#include "globalshortcutmanager.h"
#include <QCoreApplication>
+
#include "globalshortcuttrigger.h"
/**
* \brief Constructs new GlobalShortcutManager.
*/
GlobalShortcutManager::GlobalShortcutManager()
- : QObject(QCoreApplication::instance())
+ : QObject(QCoreApplication::instance())
{
}
GlobalShortcutManager::~GlobalShortcutManager()
{
- clear();
+ clear();
}
GlobalShortcutManager* GlobalShortcutManager::instance_ = 0;
/**
* \brief Returns the instance of GlobalShortcutManager.
*/
GlobalShortcutManager* GlobalShortcutManager::instance()
{
- if (!instance_)
- instance_ = new GlobalShortcutManager();
- return instance_;
+ if (!instance_)
+ instance_ = new GlobalShortcutManager();
+ return instance_;
}
/**
* \brief Connects a key sequence with a slot.
* \param key, global shortcut to be connected
* \param receiver, object which should receive the notification
* \param slot, the SLOT() of the \a receiver which should be triggerd if the \a key is activated
*/
bool GlobalShortcutManager::connect(const QKeySequence& key, QObject* receiver, const char* slot)
{
- KeyTrigger* t = instance()->triggers_[key];
- if (!t) {
+ KeyTrigger* t = instance()->triggers_[key];
+ if (!t) {
t = new KeyTrigger(key);
- if (!t->isValid())
+ if (!t->isValid()) {
+ t->deleteLater();
return false;
+ }
- instance()->triggers_.insert(key, t);
- }
+ instance()->triggers_.insert(key, t);
+ }
- QObject::connect(t, SIGNAL(activated()), receiver, slot);
+ QObject::connect(t, SIGNAL(triggered()), receiver, slot);
return true;
}
/**
* \brief Disonnects a key sequence from a slot.
* \param key, global shortcut to be disconnected
* \param receiver, object which \a slot is about to be disconnected
* \param slot, the SLOT() of the \a receiver which should no longer be triggerd if the \a key is activated
*/
void GlobalShortcutManager::disconnect(const QKeySequence& key, QObject* receiver, const char* slot)
{
- KeyTrigger* t = instance()->triggers_[key];
- if (!t) {
- return;
- }
+ KeyTrigger* t = instance()->triggers_[key];
+ if (!t) {
+ return;
+ }
- QObject::disconnect(t, SIGNAL(activated()), receiver, slot);
+ QObject::disconnect(t, SIGNAL(triggered()), receiver, slot);
- if (!t->isUsed()) {
- delete instance()->triggers_.take(key);
- }
+ if (!t->isUsed()) {
+ delete instance()->triggers_.take(key);
+ }
}
void GlobalShortcutManager::clear()
{
- foreach (KeyTrigger* t, instance()->triggers_)
- delete t;
- instance()->triggers_.clear();
+ foreach (KeyTrigger* t, instance()->triggers_)
+ delete t;
+ instance()->triggers_.clear();
}
diff --git a/tools/globalshortcut/globalshortcutmanager.h b/tools/globalshortcut/globalshortcutmanager.h
index 236598a..2cc85e8 100644
--- a/tools/globalshortcut/globalshortcutmanager.h
+++ b/tools/globalshortcut/globalshortcutmanager.h
@@ -1,47 +1,47 @@
/*
* globalshortcutmanager.h - Class managing global shortcuts
* Copyright (C) 2006 Maciej Niedzielski
*
* 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 library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifndef GLOBALSHORTCUTMANAGER_H
#define GLOBALSHORTCUTMANAGER_H
#include <QObject>
#include <QKeySequence>
#include <QMap>
class QObject;
class KeyTrigger;
class GlobalShortcutManager : public QObject
{
public:
- static GlobalShortcutManager* instance();
+ static GlobalShortcutManager* instance();
static bool connect(const QKeySequence& key, QObject* receiver, const char* slot);
- static void disconnect(const QKeySequence& key, QObject* receiver, const char* slot);
- static void clear();
+ static void disconnect(const QKeySequence& key, QObject* receiver, const char* slot);
+ static void clear();
private:
- GlobalShortcutManager();
- ~GlobalShortcutManager();
- static GlobalShortcutManager* instance_;
- class KeyTrigger;
- QMap<QKeySequence, KeyTrigger*> triggers_;
+ GlobalShortcutManager();
+ ~GlobalShortcutManager();
+ static GlobalShortcutManager* instance_;
+ class KeyTrigger;
+ QMap<QKeySequence, KeyTrigger*> triggers_;
};
#endif
diff --git a/tools/globalshortcut/globalshortcutmanager_mac.cpp b/tools/globalshortcut/globalshortcutmanager_mac.mm
similarity index 69%
rename from tools/globalshortcut/globalshortcutmanager_mac.cpp
rename to tools/globalshortcut/globalshortcutmanager_mac.mm
index c49a545..9f6f83a 100644
--- a/tools/globalshortcut/globalshortcutmanager_mac.cpp
+++ b/tools/globalshortcut/globalshortcutmanager_mac.mm
@@ -1,414 +1,301 @@
/*
* globalshortcutmanager_mac.cpp - Mac OS X implementation of global shortcuts
* Copyright (C) 2003-2007 Eric Smith, Michail Pishchagin
*
* 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 library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
+#include <Carbon/Carbon.h>
+#import "NDKeyboardLayout.h"
+
#include "globalshortcutmanager.h"
#include "globalshortcuttrigger.h"
// TODO:
// - don't invoke hotkey if there is a modal dialog?
// - do multi-mapping, like the x11 version
#include <QCoreApplication>
-#include <Carbon/Carbon.h>
-
class MacKeyTrigger
{
public:
virtual ~MacKeyTrigger() {}
virtual void activate() = 0;
virtual bool isAccepted(int id) const = 0;
};
class MacKeyTriggerManager : public QObject
{
public:
static MacKeyTriggerManager* instance()
{
if(!instance_)
instance_ = new MacKeyTriggerManager();
return instance_;
}
void addTrigger(MacKeyTrigger* trigger)
{
triggers_ << trigger;
}
void removeTrigger(MacKeyTrigger* trigger)
{
triggers_.removeAll(trigger);
}
private:
MacKeyTriggerManager()
: QObject(QCoreApplication::instance())
{
- initAscii2KeyCodeTable(&key_codes_);
hot_key_function_ = NewEventHandlerUPP(hotKeyHandler);
EventTypeSpec type;
type.eventClass = kEventClassKeyboard;
type.eventKind = kEventHotKeyPressed;
InstallApplicationEventHandler(hot_key_function_, 1, &type, this, NULL);
}
/**
* Callback function invoked when the user hits a hot-key.
*/
static pascal OSStatus hotKeyHandler(EventHandlerCallRef /*nextHandler*/, EventRef theEvent, void* userData)
{
EventHotKeyID hkID;
GetEventParameter(theEvent, kEventParamDirectObject, typeEventHotKeyID, NULL, sizeof(EventHotKeyID), NULL, &hkID);
static_cast<MacKeyTriggerManager*>(userData)->activated(hkID.id);
return noErr;
}
void activated(int id)
{
foreach(MacKeyTrigger* trigger, triggers_) {
if (trigger->isAccepted(id)) {
trigger->activate();
break;
}
}
}
static MacKeyTriggerManager* instance_;
QList<MacKeyTrigger*> triggers_;
- typedef struct
- {
- short kchrID;
- Str255 KCHRname;
- short transtable[256];
- } Ascii2KeyCodeTable;
-
- enum {
- kTableCountOffset = 256 + 2,
- kFirstTableOffset = 256 + 4,
- kTableSize = 128
- };
-
static EventHandlerUPP hot_key_function_;
- static Ascii2KeyCodeTable key_codes_;
-
-private:
- /**
- * initAscii2KeyCodeTable initializes the ascii to key code
- * look up table using the currently active KCHR resource. This
- * routine calls GetResource so it cannot be called at interrupt time.
- */
- static OSStatus initAscii2KeyCodeTable(Ascii2KeyCodeTable* ttable)
- {
- unsigned char* theCurrentKCHR, *ithKeyTable;
- short count, i, j, resID;
- Handle theKCHRRsrc;
- ResType rType;
-
- // set up our table to all minus ones
- for (i = 0; i < 256; i++)
- ttable->transtable[i] = -1;
-
- // find the current kchr resource ID
- ttable->kchrID = (short)GetScriptVariable(smCurrentScript, smScriptKeys);
-
- // get the current KCHR resource
- theKCHRRsrc = GetResource('KCHR', ttable->kchrID);
- if (theKCHRRsrc == NULL)
- return resNotFound;
- GetResInfo(theKCHRRsrc, &resID, &rType, ttable->KCHRname);
-
- // dereference the resource
- theCurrentKCHR = (unsigned char *)(*theKCHRRsrc);
-
- // get the count from the resource
- count = *(short*)(theCurrentKCHR + kTableCountOffset);
-
- // build inverse table by merging all key tables
- for (i = 0; i < count; i++) {
- ithKeyTable = theCurrentKCHR + kFirstTableOffset + (i * kTableSize);
- for (j = 0; j < kTableSize; j++) {
- if (ttable->transtable[ ithKeyTable[j] ] == -1)
- ttable->transtable[ ithKeyTable[j] ] = j;
- }
- }
-
- return noErr;
- }
-
- /**
- * validateAscii2KeyCodeTable verifies that the ascii to key code
- * lookup table is synchronized with the current KCHR resource. If
- * it is not synchronized, then the table is re-built. This routine calls
- * GetResource so it cannot be called at interrupt time.
- *
- * Should probably call this at some point, in case the user has switched keyboard
- * layouts while we were running.
- */
- static OSStatus validateAscii2KeyCodeTable(Ascii2KeyCodeTable* ttable, Boolean* wasChanged)
- {
- short theID;
- theID = (short) GetScriptVariable(smCurrentScript, smScriptKeys);
- if (theID != ttable->kchrID) {
- *wasChanged = true;
- return initAscii2KeyCodeTable(ttable);
- }
- else {
- *wasChanged = false;
- return noErr;
- }
- }
-
- /**
- * asciiToKeyCode looks up the ascii character in the key
- * code look up table and returns the virtual key code for that
- * letter. If there is no virtual key code for that letter, then
- * the value -1 will be returned.
- */
- static short asciiToKeyCode(Ascii2KeyCodeTable* ttable, short asciiCode)
- {
- if (asciiCode >= 0 && asciiCode <= 255)
- return ttable->transtable[asciiCode];
- else return false;
- }
-
- /**
- * Not used.
- */
- static char keyCodeToAscii(short virtualKeyCode)
- {
- unsigned long state;
- long keyTrans;
- char charCode;
- Ptr kchr;
- state = 0;
- kchr = (Ptr)GetScriptVariable(smCurrentScript, smKCHRCache);
- keyTrans = KeyTranslate(kchr, virtualKeyCode, &state);
- charCode = keyTrans;
- if (!charCode)
- charCode = (keyTrans >> 16);
- return charCode;
- }
private:
struct Qt_Mac_Keymap
{
int qt_key;
int mac_key;
};
static Qt_Mac_Keymap qt_keymap[];
public:
static bool convertKeySequence(const QKeySequence& ks, quint32* _key, quint32* _mod)
{
int code = ks[0];
quint32 mod = 0;
if (code & Qt::META)
mod |= controlKey;
if (code & Qt::SHIFT)
mod |= shiftKey;
if (code & Qt::CTRL)
mod |= cmdKey;
if (code & Qt::ALT)
mod |= optionKey;
code &= ~Qt::KeyboardModifierMask;
quint32 key = 0;
for (int n = 0; qt_keymap[n].qt_key != Qt::Key_unknown; ++n) {
if (qt_keymap[n].qt_key == code) {
key = qt_keymap[n].mac_key;
break;
}
}
if (key == 0) {
- key = asciiToKeyCode(&key_codes_, code & 0xffff);
+ key = [[NDKeyboardLayout keyboardLayout] keyCodeForCharacter:(code & 0xffff)];
}
if (_mod)
*_mod = mod;
if (_key)
*_key = key;
return true;
}
};
MacKeyTriggerManager* MacKeyTriggerManager::instance_ = NULL;
EventHandlerUPP MacKeyTriggerManager::hot_key_function_ = NULL;
-MacKeyTriggerManager::Ascii2KeyCodeTable MacKeyTriggerManager::key_codes_;
class GlobalShortcutManager::KeyTrigger::Impl : public MacKeyTrigger
{
private:
KeyTrigger* trigger_;
EventHotKeyRef hotKey_;
int id_;
static int nextId;
public:
/**
* Constructor registers the hotkey.
*/
Impl(GlobalShortcutManager::KeyTrigger* t, const QKeySequence& ks)
: trigger_(t)
, id_(0)
{
MacKeyTriggerManager::instance()->addTrigger(this);
quint32 key, mod;
if (MacKeyTriggerManager::convertKeySequence(ks, &key, &mod)) {
EventHotKeyID hotKeyID;
hotKeyID.signature = 'QtHK';
hotKeyID.id = nextId;
OSStatus ret = RegisterEventHotKey(key, mod, hotKeyID, GetApplicationEventTarget(), 0, &hotKey_);
if (ret != 0) {
qWarning("RegisterEventHotKey(%d, %d): %d", key, mod, (int)ret);
return;
}
id_ = nextId++;
}
}
/**
* Destructor unregisters the hotkey.
*/
~Impl()
{
MacKeyTriggerManager::instance()->removeTrigger(this);
if (id_)
UnregisterEventHotKey(hotKey_);
}
void activate()
{
- emit trigger_->activated();
+ emit trigger_->triggered();
}
bool isAccepted(int id) const
{
return id_ == id;
}
};
/*
* The following table is from Apple sample-code.
* Apple's headers don't appear to define any constants for the virtual key
* codes of special keys, but these constants are somewhat documented in the chart at
* <http://developer.apple.com/techpubs/mac/Text/Text-571.html#MARKER-9-18>
*
* The constants on the chartappear to be the same values as are used in Apple's iGetKeys
* sample.
* <http://developer.apple.com/samplecode/Sample_Code/Human_Interface_Toolbox/Mac_OS_High_Level_Toolbox/iGetKeys.htm>.
*
* See also <http://www.mactech.com/articles/mactech/Vol.04/04.12/Macinkeys/>.
*/
MacKeyTriggerManager::Qt_Mac_Keymap
MacKeyTriggerManager::qt_keymap[] = {
{ Qt::Key_Escape, 0x35 },
{ Qt::Key_Tab, 0x30 },
{ Qt::Key_Backtab, 0 },
{ Qt::Key_Backspace, 0x33 },
{ Qt::Key_Return, 0x24 },
{ Qt::Key_Enter, 0x4c }, // Return & Enter are different on the Mac
{ Qt::Key_Insert, 0 },
{ Qt::Key_Delete, 0x75 },
{ Qt::Key_Pause, 0 },
{ Qt::Key_Print, 0 },
{ Qt::Key_SysReq, 0 },
{ Qt::Key_Clear, 0x47 },
{ Qt::Key_Home, 0x73 },
{ Qt::Key_End, 0x77 },
{ Qt::Key_Left, 0x7b },
{ Qt::Key_Up, 0x7e },
{ Qt::Key_Right, 0x7c },
{ Qt::Key_Down, 0x7d },
{ Qt::Key_PageUp, 0x74 }, // Page Up
{ Qt::Key_PageDown, 0x79 }, // Page Down
{ Qt::Key_Shift, 0x38 },
{ Qt::Key_Control, 0x3b },
{ Qt::Key_Meta, 0x37 }, // Command
{ Qt::Key_Alt, 0x3a }, // Option
{ Qt::Key_CapsLock, 57 },
{ Qt::Key_NumLock, 0 },
{ Qt::Key_ScrollLock, 0 },
{ Qt::Key_F1, 0x7a },
{ Qt::Key_F2, 0x78 },
{ Qt::Key_F3, 0x63 },
{ Qt::Key_F4, 0x76 },
{ Qt::Key_F5, 0x60 },
{ Qt::Key_F6, 0x61 },
{ Qt::Key_F7, 0x62 },
{ Qt::Key_F8, 0x64 },
{ Qt::Key_F9, 0x65 },
{ Qt::Key_F10, 0x6d },
{ Qt::Key_F11, 0x67 },
{ Qt::Key_F12, 0x6f },
{ Qt::Key_F13, 0x69 },
{ Qt::Key_F14, 0x6b },
{ Qt::Key_F15, 0x71 },
{ Qt::Key_F16, 0 },
{ Qt::Key_F17, 0 },
{ Qt::Key_F18, 0 },
{ Qt::Key_F19, 0 },
{ Qt::Key_F20, 0 },
{ Qt::Key_F21, 0 },
{ Qt::Key_F22, 0 },
{ Qt::Key_F23, 0 },
{ Qt::Key_F24, 0 },
{ Qt::Key_F25, 0 },
{ Qt::Key_F26, 0 },
{ Qt::Key_F27, 0 },
{ Qt::Key_F28, 0 },
{ Qt::Key_F29, 0 },
{ Qt::Key_F30, 0 },
{ Qt::Key_F31, 0 },
{ Qt::Key_F32, 0 },
{ Qt::Key_F33, 0 },
{ Qt::Key_F34, 0 },
{ Qt::Key_F35, 0 },
{ Qt::Key_Super_L, 0 },
{ Qt::Key_Super_R, 0 },
{ Qt::Key_Menu, 0 },
{ Qt::Key_Hyper_L, 0 },
{ Qt::Key_Hyper_R, 0 },
{ Qt::Key_Help, 0x72 },
{ Qt::Key_Direction_L, 0 },
{ Qt::Key_Direction_R, 0 },
{ Qt::Key_unknown, 0 }
};
int GlobalShortcutManager::KeyTrigger::Impl::nextId = 1;
GlobalShortcutManager::KeyTrigger::KeyTrigger(const QKeySequence& key)
{
d = new Impl(this, key);
}
GlobalShortcutManager::KeyTrigger::~KeyTrigger()
{
delete d;
d = 0;
}
diff --git a/tools/globalshortcut/globalshortcutmanager_win.cpp b/tools/globalshortcut/globalshortcutmanager_win.cpp
index a484d73..fcdd5f3 100644
--- a/tools/globalshortcut/globalshortcutmanager_win.cpp
+++ b/tools/globalshortcut/globalshortcutmanager_win.cpp
@@ -1,222 +1,230 @@
/*
- *
* globalshortcutmanager_win.cpp - Windows implementation of global shortcuts
* Copyright (C) 2003-2006 Justin Karneges, Maciej Niedzielski
*
* 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 library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
-
#include "globalshortcutmanager.h"
#include "globalshortcuttrigger.h"
#include <QWidget>
-#include <QAbstractNativeEventFilter>
-
#include <windows.h>
+#include <QAbstractNativeEventFilter>
-class GlobalShortcutManager::KeyTrigger::Impl : public QWidget, public QAbstractNativeEventFilter
+class GlobalShortcutManager::KeyTrigger::Impl : public QWidget
{
+ class WinEventFilter : public QAbstractNativeEventFilter
+ {
+ GlobalShortcutManager::KeyTrigger::Impl *impl;
+
+ public:
+ WinEventFilter(GlobalShortcutManager::KeyTrigger::Impl *parent) : impl(parent) {}
+
+ virtual bool nativeEventFilter(const QByteArray &eventType, void *m, long *result) Q_DECL_OVERRIDE
+ {
+ if (eventType == "windows_generic_MSG") {
+ return impl->winEvent(static_cast<MSG*>(m), result);
+ }
+ return false;
+ }
+ };
+
public:
- /**
- * Constructor registers the hotkey.
- */
- Impl(GlobalShortcutManager::KeyTrigger* t, const QKeySequence& ks)
- : trigger_(t)
- , id_(0)
- , valid(false)
- {
- UINT mod = 0, key;
- if (convertKeySequence(ks, &mod, &key))
+ /**
+ * Constructor registers the hotkey.
+ */
+ Impl(GlobalShortcutManager::KeyTrigger* t, const QKeySequence& ks) :
+ filter(new WinEventFilter(this)),
+ trigger_(t),
+ id_(0),
+ valid(false)
+ {
+ UINT mod, key;
+ if (convertKeySequence(ks, &mod, &key))
if (valid = RegisterHotKey((HWND)winId(), nextId, mod, key))
- id_ = nextId++;
- }
-
- /**
- * Destructor unregisters the hotkey.
- */
- ~Impl()
- {
- if (id_)
- UnregisterHotKey((HWND)winId(), id_);
- }
-
- /**
- * Triggers activated() signal when the hotkey is activated.
- */
- bool nativeEventFilter(const QByteArray &eventType, void* message, long* result)
- {
- if (eventType != "windows_dispatcher_MSG")
- return false;
-
+ id_ = nextId++;
+ }
+
+ /**
+ * Destructor unregisters the hotkey.
+ */
+ ~Impl()
+ {
+ delete filter;
+ if (id_)
+ UnregisterHotKey((HWND)winId(), id_);
+ }
+
+ /**
+ * Triggers triggered() signal when the hotkey is activated.
+ */
+ bool winEvent(MSG* m, long* result)
+ {
Q_UNUSED(result)
-
- MSG* m = (MSG*) message;
-
- if (m->message == WM_HOTKEY && m->wParam == id_) {
- emit trigger_->activated();
- return true;
- }
+ if (m->message == WM_HOTKEY && m->wParam == id_) {
+ emit trigger_->triggered();
+ return true;
+ }
+ return false;
}
- bool isValid() { return valid; }
-
-private:
- KeyTrigger* trigger_;
- int id_;
- static int nextId;
bool valid;
+private:
+ WinEventFilter *filter;
+ KeyTrigger* trigger_;
+ WPARAM id_;
+ static WPARAM nextId;
private:
- struct Qt_VK_Keymap
- {
- int key;
- UINT vk;
- };
- static Qt_VK_Keymap qt_vk_table[];
-
- static bool convertKeySequence(const QKeySequence& ks, UINT* mod_, UINT* key_)
- {
- int code = (int) ks;
-
- UINT mod = 0;
- if (code & Qt::META)
- mod |= MOD_WIN;
- if (code & Qt::SHIFT)
- mod |= MOD_SHIFT;
- if (code & Qt::CTRL)
- mod |= MOD_CONTROL;
- if (code & Qt::ALT)
- mod |= MOD_ALT;
-
- UINT key = 0;
- code &= ~Qt::KeyboardModifierMask;
- if (code >= 0x20 && code <= 0x7f)
- key = code;
- else {
- for (int n = 0; qt_vk_table[n].key != Qt::Key_unknown; ++n) {
- if (qt_vk_table[n].key == code) {
- key = qt_vk_table[n].vk;
- break;
- }
- }
- if (!key)
- return false;
- }
-
- if (mod)
- *mod_ = mod;
-
- if (key)
- *key_ = key;
-
- return true;
- }
+ struct Qt_VK_Keymap
+ {
+ int key;
+ UINT vk;
+ };
+ static Qt_VK_Keymap qt_vk_table[];
+
+ static bool convertKeySequence(const QKeySequence& ks, UINT* mod_, UINT* key_)
+ {
+ int code = ks[0];
+
+ UINT mod = 0;
+ if (code & Qt::META)
+ mod |= MOD_WIN;
+ if (code & Qt::SHIFT)
+ mod |= MOD_SHIFT;
+ if (code & Qt::CTRL)
+ mod |= MOD_CONTROL;
+ if (code & Qt::ALT)
+ mod |= MOD_ALT;
+
+ UINT key = 0;
+ code &= ~Qt::KeyboardModifierMask;
+ if (code >= 0x20 && code <= 0x7f)
+ key = code;
+ else {
+ for (int n = 0; qt_vk_table[n].key != Qt::Key_unknown; ++n) {
+ if (qt_vk_table[n].key == code) {
+ key = qt_vk_table[n].vk;
+ break;
+ }
+ }
+ if (!key)
+ return false;
+ }
+
+ if (mod)
+ *mod_ = mod;
+ if (key)
+ *key_ = key;
+
+ return true;
+ }
};
GlobalShortcutManager::KeyTrigger::Impl::Qt_VK_Keymap
GlobalShortcutManager::KeyTrigger::Impl::qt_vk_table[] = {
- { Qt::Key_Escape, VK_ESCAPE },
- { Qt::Key_Tab, VK_TAB },
- { Qt::Key_Backtab, 0 },
- { Qt::Key_Backspace, VK_BACK },
- { Qt::Key_Return, VK_RETURN },
- { Qt::Key_Enter, VK_RETURN },
- { Qt::Key_Insert, VK_INSERT },
- { Qt::Key_Delete, VK_DELETE },
- { Qt::Key_Pause, VK_PAUSE },
- { Qt::Key_Print, VK_SNAPSHOT }, // Was changed from VK_PRINT
- { Qt::Key_SysReq, 0 },
- { Qt::Key_Clear, VK_CLEAR },
- { Qt::Key_Home, VK_HOME },
- { Qt::Key_End, VK_END },
- { Qt::Key_Left, VK_LEFT },
- { Qt::Key_Up, VK_UP },
- { Qt::Key_Right, VK_RIGHT },
- { Qt::Key_Down, VK_DOWN },
- { Qt::Key_PageUp, VK_PRIOR },
- { Qt::Key_PageDown, VK_NEXT },
- { Qt::Key_Shift, VK_SHIFT },
- { Qt::Key_Control, VK_CONTROL },
- { Qt::Key_Meta, VK_LWIN },
- { Qt::Key_Alt, VK_MENU },
- { Qt::Key_CapsLock, VK_CAPITAL },
- { Qt::Key_NumLock, VK_NUMLOCK },
- { Qt::Key_ScrollLock, VK_SCROLL },
- { Qt::Key_F1, VK_F1 },
- { Qt::Key_F2, VK_F2 },
- { Qt::Key_F3, VK_F3 },
- { Qt::Key_F4, VK_F4 },
- { Qt::Key_F5, VK_F5 },
- { Qt::Key_F6, VK_F6 },
- { Qt::Key_F7, VK_F7 },
- { Qt::Key_F8, VK_F8 },
- { Qt::Key_F9, VK_F9 },
- { Qt::Key_F10, VK_F10 },
- { Qt::Key_F11, VK_F11 },
- { Qt::Key_F12, VK_F12 },
- { Qt::Key_F13, VK_F13 },
- { Qt::Key_F14, VK_F14 },
- { Qt::Key_F15, VK_F15 },
- { Qt::Key_F16, VK_F16 },
- { Qt::Key_F17, VK_F17 },
- { Qt::Key_F18, VK_F18 },
- { Qt::Key_F19, VK_F19 },
- { Qt::Key_F20, VK_F20 },
- { Qt::Key_F21, VK_F21 },
- { Qt::Key_F22, VK_F22 },
- { Qt::Key_F23, VK_F23 },
- { Qt::Key_F24, VK_F24 },
- { Qt::Key_F25, 0 },
- { Qt::Key_F26, 0 },
- { Qt::Key_F27, 0 },
- { Qt::Key_F28, 0 },
- { Qt::Key_F29, 0 },
- { Qt::Key_F30, 0 },
- { Qt::Key_F31, 0 },
- { Qt::Key_F32, 0 },
- { Qt::Key_F33, 0 },
- { Qt::Key_F34, 0 },
- { Qt::Key_F35, 0 },
- { Qt::Key_Super_L, 0 },
- { Qt::Key_Super_R, 0 },
- { Qt::Key_Menu, 0 },
- { Qt::Key_Hyper_L, 0 },
- { Qt::Key_Hyper_R, 0 },
- { Qt::Key_Help, 0 },
- { Qt::Key_Direction_L, 0 },
- { Qt::Key_Direction_R, 0 },
-
- { Qt::Key_unknown, 0 },
+ { Qt::Key_Escape, VK_ESCAPE },
+ { Qt::Key_Tab, VK_TAB },
+ { Qt::Key_Backtab, 0 },
+ { Qt::Key_Backspace, VK_BACK },
+ { Qt::Key_Return, VK_RETURN },
+ { Qt::Key_Enter, VK_RETURN },
+ { Qt::Key_Insert, VK_INSERT },
+ { Qt::Key_Delete, VK_DELETE },
+ { Qt::Key_Pause, VK_PAUSE },
+ { Qt::Key_Print, VK_PRINT },
+ { Qt::Key_SysReq, 0 },
+ { Qt::Key_Clear, VK_CLEAR },
+ { Qt::Key_Home, VK_HOME },
+ { Qt::Key_End, VK_END },
+ { Qt::Key_Left, VK_LEFT },
+ { Qt::Key_Up, VK_UP },
+ { Qt::Key_Right, VK_RIGHT },
+ { Qt::Key_Down, VK_DOWN },
+ { Qt::Key_PageUp, VK_PRIOR },
+ { Qt::Key_PageDown, VK_NEXT },
+ { Qt::Key_Shift, VK_SHIFT },
+ { Qt::Key_Control, VK_CONTROL },
+ { Qt::Key_Meta, VK_LWIN },
+ { Qt::Key_Alt, VK_MENU },
+ { Qt::Key_CapsLock, VK_CAPITAL },
+ { Qt::Key_NumLock, VK_NUMLOCK },
+ { Qt::Key_ScrollLock, VK_SCROLL },
+ { Qt::Key_F1, VK_F1 },
+ { Qt::Key_F2, VK_F2 },
+ { Qt::Key_F3, VK_F3 },
+ { Qt::Key_F4, VK_F4 },
+ { Qt::Key_F5, VK_F5 },
+ { Qt::Key_F6, VK_F6 },
+ { Qt::Key_F7, VK_F7 },
+ { Qt::Key_F8, VK_F8 },
+ { Qt::Key_F9, VK_F9 },
+ { Qt::Key_F10, VK_F10 },
+ { Qt::Key_F11, VK_F11 },
+ { Qt::Key_F12, VK_F12 },
+ { Qt::Key_F13, VK_F13 },
+ { Qt::Key_F14, VK_F14 },
+ { Qt::Key_F15, VK_F15 },
+ { Qt::Key_F16, VK_F16 },
+ { Qt::Key_F17, VK_F17 },
+ { Qt::Key_F18, VK_F18 },
+ { Qt::Key_F19, VK_F19 },
+ { Qt::Key_F20, VK_F20 },
+ { Qt::Key_F21, VK_F21 },
+ { Qt::Key_F22, VK_F22 },
+ { Qt::Key_F23, VK_F23 },
+ { Qt::Key_F24, VK_F24 },
+ { Qt::Key_F25, 0 },
+ { Qt::Key_F26, 0 },
+ { Qt::Key_F27, 0 },
+ { Qt::Key_F28, 0 },
+ { Qt::Key_F29, 0 },
+ { Qt::Key_F30, 0 },
+ { Qt::Key_F31, 0 },
+ { Qt::Key_F32, 0 },
+ { Qt::Key_F33, 0 },
+ { Qt::Key_F34, 0 },
+ { Qt::Key_F35, 0 },
+ { Qt::Key_Super_L, 0 },
+ { Qt::Key_Super_R, 0 },
+ { Qt::Key_Menu, 0 },
+ { Qt::Key_Hyper_L, 0 },
+ { Qt::Key_Hyper_R, 0 },
+ { Qt::Key_Help, 0 },
+ { Qt::Key_Direction_L, 0 },
+ { Qt::Key_Direction_R, 0 },
+
+ { Qt::Key_unknown, 0 },
};
-int GlobalShortcutManager::KeyTrigger::Impl::nextId = 1;
+WPARAM GlobalShortcutManager::KeyTrigger::Impl::nextId = 1;
GlobalShortcutManager::KeyTrigger::KeyTrigger(const QKeySequence& key)
{
- d = new Impl(this, key);
+ d = new Impl(this, key);
}
bool GlobalShortcutManager::KeyTrigger::isValid() const
{
- return d->isValid();
+ return d->valid;
}
GlobalShortcutManager::KeyTrigger::~KeyTrigger()
{
- delete d;
- d = 0;
+ delete d;
+ d = 0;
}
diff --git a/tools/globalshortcut/globalshortcutmanager_x11.cpp b/tools/globalshortcut/globalshortcutmanager_x11.cpp
index caa228d..8553ee2 100644
--- a/tools/globalshortcut/globalshortcutmanager_x11.cpp
+++ b/tools/globalshortcut/globalshortcutmanager_x11.cpp
@@ -1,446 +1,445 @@
/*
* globalshortcutmanager_x11.cpp - X11 implementation of global shortcuts
* Copyright (C) 2003-2007 Justin Karneges, Michail Pishchagin
*
* 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 library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#include "globalshortcutmanager.h"
#include "globalshortcuttrigger.h"
#include <QWidget>
-#include <QX11Info>
#include <QKeyEvent>
#include <QCoreApplication>
#include <X11/X.h>
#include <X11/Xlib.h>
#include <X11/keysym.h>
+#include "x11info.h"
+
#ifdef KeyPress
// defined by X11 headers
const int XKeyPress = KeyPress;
const int XKeyRelease = KeyRelease;
#undef KeyPress
#endif
class X11KeyTrigger
{
public:
- virtual ~X11KeyTrigger() {}
- virtual void activate() = 0;
- virtual bool isAccepted(int qkey) const = 0;
+ virtual ~X11KeyTrigger() {}
+ virtual void activate() = 0;
+ virtual bool isAccepted(const QKeySequence &qkey) const = 0;
};
class X11KeyTriggerManager : public QObject
{
public:
- static X11KeyTriggerManager* instance()
- {
- if(!instance_)
- instance_ = new X11KeyTriggerManager();
- return instance_;
- }
-
- void addTrigger(X11KeyTrigger* trigger)
- {
- triggers_ << trigger;
- }
-
- void removeTrigger(X11KeyTrigger* trigger)
- {
- triggers_.removeAll(trigger);
- }
-
- struct Qt_XK_Keygroup
- {
- char num;
- int sym[3];
- };
+ static X11KeyTriggerManager* instance()
+ {
+ if(!instance_)
+ instance_ = new X11KeyTriggerManager();
+ return instance_;
+ }
+
+ void addTrigger(X11KeyTrigger* trigger)
+ {
+ triggers_ << trigger;
+ }
+
+ void removeTrigger(X11KeyTrigger* trigger)
+ {
+ triggers_.removeAll(trigger);
+ }
+
+ struct Qt_XK_Keygroup
+ {
+ char num;
+ int sym[3];
+ };
protected:
- // reimplemented
- bool eventFilter(QObject* o, QEvent* e)
- {
- if(e->type() == QEvent::KeyPress) {
- QKeyEvent* k = static_cast<QKeyEvent*>(e);
- int qkey = k->key();
- if (k->modifiers() & Qt::ShiftModifier)
- qkey |= Qt::SHIFT;
- if (k->modifiers() & Qt::ControlModifier)
- qkey |= Qt::CTRL;
- if (k->modifiers() & Qt::AltModifier)
- qkey |= Qt::ALT;
- if (k->modifiers() & Qt::MetaModifier)
- qkey |= Qt::META;
-
- foreach(X11KeyTrigger* trigger, triggers_) {
- if (trigger->isAccepted(qkey)) {
- trigger->activate();
- return true;
- }
- }
- }
-
- return QObject::eventFilter(o, e);
- }
+ // reimplemented
+ bool eventFilter(QObject* o, QEvent* e)
+ {
+ if(e->type() == QEvent::KeyPress) {
+ QKeyEvent* k = static_cast<QKeyEvent*>(e);
+ int qkey = k->key();
+ if (k->modifiers() & Qt::ShiftModifier)
+ qkey |= Qt::SHIFT;
+ if (k->modifiers() & Qt::ControlModifier)
+ qkey |= Qt::CTRL;
+ if (k->modifiers() & Qt::AltModifier)
+ qkey |= Qt::ALT;
+ if (k->modifiers() & Qt::MetaModifier)
+ qkey |= Qt::META;
+
+ foreach(X11KeyTrigger* trigger, triggers_) {
+ if (trigger->isAccepted(QKeySequence(qkey))) {
+ trigger->activate();
+ return true;
+ }
+ }
+ }
+
+ return QObject::eventFilter(o, e);
+ }
private:
- X11KeyTriggerManager()
- : QObject(QCoreApplication::instance())
- {
- QCoreApplication::instance()->installEventFilter(this);
- }
+ X11KeyTriggerManager()
+ : QObject(QCoreApplication::instance())
+ {
+ QCoreApplication::instance()->installEventFilter(this);
+ }
- static X11KeyTriggerManager* instance_;
- QList<X11KeyTrigger*> triggers_;
+ static X11KeyTriggerManager* instance_;
+ QList<X11KeyTrigger*> triggers_;
private:
- struct Qt_XK_Keymap
- {
- int key;
- Qt_XK_Keygroup xk;
- };
-
- static Qt_XK_Keymap qt_xk_table[];
- static long alt_mask;
- static long meta_mask;
- static long super_mask;
- static long hyper_mask;
- static long numlock_mask;
- static bool haveMods;
-
- // adapted from qapplication_x11.cpp
- static void ensureModifiers()
- {
- if (haveMods)
- return;
-
- Display* appDpy = QX11Info::display();
- XModifierKeymap* map = XGetModifierMapping(appDpy);
- if (map) {
- // XKeycodeToKeysym helper code adapeted from xmodmap
- int min_keycode, max_keycode, keysyms_per_keycode = 1;
- XDisplayKeycodes (appDpy, &min_keycode, &max_keycode);
- XFree(XGetKeyboardMapping (appDpy, min_keycode, (max_keycode - min_keycode + 1), &keysyms_per_keycode));
-
- int i, maskIndex = 0, mapIndex = 0;
- for (maskIndex = 0; maskIndex < 8; maskIndex++) {
- for (i = 0; i < map->max_keypermod; i++) {
- if (map->modifiermap[mapIndex]) {
- KeySym sym;
- int symIndex = 0;
- do {
- sym = XKeycodeToKeysym(appDpy, map->modifiermap[mapIndex], symIndex);
- symIndex++;
- } while ( !sym && symIndex < keysyms_per_keycode);
- if (alt_mask == 0 && (sym == XK_Alt_L || sym == XK_Alt_R)) {
- alt_mask = 1 << maskIndex;
- }
- if (meta_mask == 0 && (sym == XK_Meta_L || sym == XK_Meta_R)) {
- meta_mask = 1 << maskIndex;
- }
- if (super_mask == 0 && (sym == XK_Super_L || sym == XK_Super_R)) {
- super_mask = 1 << maskIndex;
- }
- if (hyper_mask == 0 && (sym == XK_Hyper_L || sym == XK_Hyper_R)) {
- hyper_mask = 1 << maskIndex;
- }
- if (numlock_mask == 0 && (sym == XK_Num_Lock)) {
- numlock_mask = 1 << maskIndex;
- }
- }
- mapIndex++;
- }
- }
-
- XFreeModifiermap(map);
-
- // logic from qt source see gui/kernel/qkeymapper_x11.cpp
- if (meta_mask == 0 || meta_mask == alt_mask) {
- // no meta keys... s,meta,super,
- meta_mask = super_mask;
- if (meta_mask == 0 || meta_mask == alt_mask) {
- // no super keys either? guess we'll use hyper then
- meta_mask = hyper_mask;
- }
- }
- }
- else {
- // assume defaults
- alt_mask = Mod1Mask;
- meta_mask = Mod4Mask;
- }
-
- haveMods = true;
- }
+ struct Qt_XK_Keymap
+ {
+ int key;
+ Qt_XK_Keygroup xk;
+ };
+
+ static Qt_XK_Keymap qt_xk_table[];
+ static long alt_mask;
+ static long meta_mask;
+ static long super_mask;
+ static long hyper_mask;
+ static long numlock_mask;
+ static bool haveMods;
+
+ // adapted from qapplication_x11.cpp
+ static void ensureModifiers()
+ {
+ if (haveMods)
+ return;
+
+ Display* appDpy = X11Info::display();
+ XModifierKeymap* map = XGetModifierMapping(appDpy);
+ if (map) {
+ // XKeycodeToKeysym helper code adapeted from xmodmap
+ int min_keycode, max_keycode, keysyms_per_keycode_return, keysyms_per_keycode = 1;
+ XDisplayKeycodes (appDpy, &min_keycode, &max_keycode);
+ XFree(XGetKeyboardMapping (appDpy, min_keycode, (max_keycode - min_keycode + 1), &keysyms_per_keycode));
+
+ int i, maskIndex = 0, mapIndex = 0;
+ for (maskIndex = 0; maskIndex < 8; maskIndex++) {
+ for (i = 0; i < map->max_keypermod; i++) {
+ if (map->modifiermap[mapIndex]) {
+ KeySym *sym = 0;
+ int symIndex = 0;
+ do {
+ sym = XGetKeyboardMapping(appDpy,map->modifiermap[mapIndex], 1, &keysyms_per_keycode_return);
+ symIndex++;
+ } while ( !sym[0] && symIndex < keysyms_per_keycode);
+ if (alt_mask == 0 && (sym[0] == XK_Alt_L || sym[0] == XK_Alt_R)) {
+ alt_mask = 1 << maskIndex;
+ }
+ if (meta_mask == 0 && (sym[0] == XK_Meta_L || sym[0] == XK_Meta_R)) {
+ meta_mask = 1 << maskIndex;
+ }
+ if (super_mask == 0 && (sym[0] == XK_Super_L || sym[0] == XK_Super_R)) {
+ super_mask = 1 << maskIndex;
+ }
+ if (hyper_mask == 0 && (sym[0] == XK_Hyper_L || sym[0] == XK_Hyper_R)) {
+ hyper_mask = 1 << maskIndex;
+ }
+ if (numlock_mask == 0 && (sym[0] == XK_Num_Lock)) {
+ numlock_mask = 1 << maskIndex;
+ }
+ XFree(sym);
+ }
+ mapIndex++;
+ }
+ }
+
+ XFreeModifiermap(map);
+
+ // logic from qt source see gui/kernel/qkeymapper_x11.cpp
+ if (meta_mask == 0 || meta_mask == alt_mask) {
+ // no meta keys... s,meta,super,
+ meta_mask = super_mask;
+ if (meta_mask == 0 || meta_mask == alt_mask) {
+ // no super keys either? guess we'll use hyper then
+ meta_mask = hyper_mask;
+ }
+ }
+ }
+ else {
+ // assume defaults
+ alt_mask = Mod1Mask;
+ meta_mask = Mod4Mask;
+ }
+
+ haveMods = true;
+ }
public:
- static bool convertKeySequence(const QKeySequence& ks, unsigned int* _mod, Qt_XK_Keygroup* _kg)
- {
- int code = ks;
- ensureModifiers();
-
- unsigned int mod = 0;
- if (code & Qt::META)
- mod |= meta_mask;
- if (code & Qt::SHIFT)
- mod |= ShiftMask;
- if (code & Qt::CTRL)
- mod |= ControlMask;
- if (code & Qt::ALT)
- mod |= alt_mask;
-
- Qt_XK_Keygroup kg;
- kg.num = 0;
- kg.sym[0] = 0;
- code &= ~Qt::KeyboardModifierMask;
-
- bool found = false;
- for (int n = 0; qt_xk_table[n].key != Qt::Key_unknown; ++n) {
- if (qt_xk_table[n].key == code) {
- kg = qt_xk_table[n].xk;
- found = true;
- break;
- }
- }
-
- if (!found) {
- // try latin1
- if (code >= 0x20 && code <= 0x7f) {
- kg.num = 1;
- kg.sym[0] = code;
- }
- }
-
- if (!kg.num)
- return false;
-
- if (_mod)
- *_mod = mod;
- if (_kg)
- *_kg = kg;
-
- return true;
- }
-
- static QList<long> ignModifiersList()
- {
- QList<long> ret;
- if (numlock_mask) {
- ret << 0 << LockMask << numlock_mask << (LockMask | numlock_mask);
- }
- else {
- ret << 0 << LockMask;
- }
- return ret;
- }
+ static bool convertKeySequence(const QKeySequence& ks, unsigned int* _mod, Qt_XK_Keygroup* _kg)
+ {
+ int code = ks[0];
+ Qt_XK_Keygroup kg;
+ kg.num = 0;
+ kg.sym[0] = 0;
+
+ ensureModifiers();
+
+ unsigned int mod = 0;
+ if (code & Qt::META)
+ mod |= meta_mask;
+ if (code & Qt::SHIFT)
+ mod |= ShiftMask;
+ if (code & Qt::CTRL)
+ mod |= ControlMask;
+ if (code & Qt::ALT)
+ mod |= alt_mask;
+
+ code &= ~Qt::KeyboardModifierMask;
+
+ bool found = false;
+ for (int n = 0; qt_xk_table[n].key != Qt::Key_unknown; ++n) {
+ if (qt_xk_table[n].key == code) {
+ kg = qt_xk_table[n].xk;
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ // try latin1
+ if (code >= 0x20 && code <= 0x7f) {
+ kg.num = 1;
+ kg.sym[0] = code;
+ }
+ }
+
+ if (!kg.num)
+ return false;
+
+ if (_mod)
+ *_mod = mod;
+ if (_kg)
+ *_kg = kg;
+
+ return true;
+ }
+
+ static QList<long> ignModifiersList()
+ {
+ QList<long> ret;
+ if (numlock_mask) {
+ ret << 0 << LockMask << numlock_mask << (LockMask | numlock_mask);
+ }
+ else {
+ ret << 0 << LockMask;
+ }
+ return ret;
+ }
};
X11KeyTriggerManager* X11KeyTriggerManager::instance_ = NULL;
class GlobalShortcutManager::KeyTrigger::Impl : public X11KeyTrigger
{
private:
- KeyTrigger* trigger_;
- int qkey_;
-
- struct GrabbedKey {
- int code;
- uint mod;
- };
- QList<GrabbedKey> grabbedKeys_;
-
- static bool failed;
- static int XGrabErrorHandler(Display *, XErrorEvent *)
- {
- qWarning("failed to grab key");
- failed = true;
- return 0;
- }
-
- void bind(int keysym, unsigned int mod)
- {
- int code = XKeysymToKeycode(QX11Info::display(), keysym);
-
- // don't grab keys with empty code (because it means just the modifier key)
- if (keysym && !code)
- return;
-
- failed = false;
- XErrorHandler savedErrorHandler = XSetErrorHandler(XGrabErrorHandler);
- WId w = QX11Info::appRootWindow();
- foreach(long mask_mod, X11KeyTriggerManager::ignModifiersList()) {
- XGrabKey(QX11Info::display(), code, mod | mask_mod, w, False, GrabModeAsync, GrabModeAsync);
- GrabbedKey grabbedKey;
- grabbedKey.code = code;
- grabbedKey.mod = mod | mask_mod;
- grabbedKeys_ << grabbedKey;
- }
- XSync(QX11Info::display(), False);
- XSetErrorHandler(savedErrorHandler);
- }
+ KeyTrigger* trigger_;
+ QKeySequence qkey_;
+
+ struct GrabbedKey {
+ int code;
+ uint mod;
+ };
+ QList<GrabbedKey> grabbedKeys_;
+
+ static bool failed;
+ static int XGrabErrorHandler(Display *, XErrorEvent *)
+ {
+ qWarning("failed to grab key");
+ failed = true;
+ return 0;
+ }
+
+ void bind(int keysym, unsigned int mod)
+ {
+ int code = XKeysymToKeycode(X11Info::display(), keysym);
+
+ // don't grab keys with empty code (because it means just the modifier key)
+ if (keysym && !code)
+ return;
+
+ failed = false;
+ XErrorHandler savedErrorHandler = XSetErrorHandler(XGrabErrorHandler);
+ WId w = X11Info::appRootWindow();
+ foreach(long mask_mod, X11KeyTriggerManager::ignModifiersList()) {
+ XGrabKey(X11Info::display(), code, mod | mask_mod, w, False, GrabModeAsync, GrabModeAsync);
+ GrabbedKey grabbedKey;
+ grabbedKey.code = code;
+ grabbedKey.mod = mod | mask_mod;
+ grabbedKeys_ << grabbedKey;
+ }
+ XSync(X11Info::display(), False);
+ XSetErrorHandler(savedErrorHandler);
+ }
public:
- /**
- * Constructor registers the hotkey.
- */
- Impl(GlobalShortcutManager::KeyTrigger* t, const QKeySequence& ks)
- : trigger_(t)
- , qkey_(ks)
- {
- X11KeyTriggerManager::instance()->addTrigger(this);
-
- X11KeyTriggerManager::Qt_XK_Keygroup kg;
- unsigned int mod;
- if (X11KeyTriggerManager::convertKeySequence(ks, &mod, &kg))
- for (int n = 0; n < kg.num; ++n)
- bind(kg.sym[n], mod);
- }
-
- /**
- * Destructor unregisters the hotkey.
- */
- ~Impl()
- {
- X11KeyTriggerManager::instance()->removeTrigger(this);
-
- foreach(GrabbedKey key, grabbedKeys_)
- XUngrabKey(QX11Info::display(), key.code, key.mod, QX11Info::appRootWindow());
- }
-
- void activate()
- {
- emit trigger_->activated();
- }
-
- bool isAccepted(int qkey) const
- {
- return qkey_ == qkey;
- }
-
- bool isValid() { return !failed; }
+ /**
+ * Constructor registers the hotkey.
+ */
+ Impl(GlobalShortcutManager::KeyTrigger* t, const QKeySequence& ks)
+ : trigger_(t)
+ , qkey_(ks)
+ {
+ X11KeyTriggerManager::instance()->addTrigger(this);
+
+ X11KeyTriggerManager::Qt_XK_Keygroup kg;
+ unsigned int mod;
+ if (X11KeyTriggerManager::convertKeySequence(ks, &mod, &kg))
+ for (int n = 0; n < kg.num; ++n)
+ bind(kg.sym[n], mod);
+ }
+
+ /**
+ * Destructor unregisters the hotkey.
+ */
+ ~Impl()
+ {
+ X11KeyTriggerManager::instance()->removeTrigger(this);
+
+ foreach(GrabbedKey key, grabbedKeys_)
+ XUngrabKey(X11Info::display(), key.code, key.mod, X11Info::appRootWindow());
+ }
+
+ void activate()
+ {
+ emit trigger_->triggered();
+ }
+
+ bool isAccepted(const QKeySequence &qkey) const
+ {
+ return qkey_ == qkey;
+ }
};
bool GlobalShortcutManager::KeyTrigger::Impl::failed;
long X11KeyTriggerManager::alt_mask = 0;
long X11KeyTriggerManager::meta_mask = 0;
long X11KeyTriggerManager::super_mask = 0;
long X11KeyTriggerManager::hyper_mask = 0;
long X11KeyTriggerManager::numlock_mask = 0;
bool X11KeyTriggerManager::haveMods = false;
X11KeyTriggerManager::Qt_XK_Keymap
X11KeyTriggerManager::qt_xk_table[] = {
- { Qt::Key_Escape, {1, { XK_Escape }}},
- { Qt::Key_Tab, {2, { XK_Tab, XK_KP_Tab }}},
- { Qt::Key_Backtab, {1, { XK_ISO_Left_Tab }}},
- { Qt::Key_Backspace, {1, { XK_BackSpace }}},
- { Qt::Key_Return, {1, { XK_Return }}},
- { Qt::Key_Enter, {1, { XK_KP_Enter }}},
- { Qt::Key_Insert, {2, { XK_Insert, XK_KP_Insert }}},
- { Qt::Key_Delete, {3, { XK_Delete, XK_KP_Delete, XK_Clear }}},
- { Qt::Key_Pause, {1, { XK_Pause }}},
- { Qt::Key_Print, {1, { XK_Print }}},
- { Qt::Key_SysReq, {1, { XK_Sys_Req }}},
- { Qt::Key_Clear, {1, { XK_KP_Begin }}},
- { Qt::Key_Home, {2, { XK_Home, XK_KP_Home }}},
- { Qt::Key_End, {2, { XK_End, XK_KP_End }}},
- { Qt::Key_Left, {2, { XK_Left, XK_KP_Left }}},
- { Qt::Key_Up, {2, { XK_Up, XK_KP_Up }}},
- { Qt::Key_Right, {2, { XK_Right, XK_KP_Right }}},
- { Qt::Key_Down, {2, { XK_Down, XK_KP_Down }}},
- { Qt::Key_PageUp, {2, { XK_Prior, XK_KP_Prior }}},
- { Qt::Key_PageDown, {2, { XK_Next, XK_KP_Next }}},
- { Qt::Key_Shift, {3, { XK_Shift_L, XK_Shift_R, XK_Shift_Lock }}},
- { Qt::Key_Control, {2, { XK_Control_L, XK_Control_R }}},
- { Qt::Key_Meta, {2, { XK_Meta_L, XK_Meta_R }}},
- { Qt::Key_Alt, {2, { XK_Alt_L, XK_Alt_R }}},
- { Qt::Key_CapsLock, {1, { XK_Caps_Lock }}},
- { Qt::Key_NumLock, {1, { XK_Num_Lock }}},
- { Qt::Key_ScrollLock, {1, { XK_Scroll_Lock }}},
- { Qt::Key_Space, {2, { XK_space, XK_KP_Space }}},
- { Qt::Key_Equal, {2, { XK_equal, XK_KP_Equal }}},
- { Qt::Key_Asterisk, {2, { XK_asterisk, XK_KP_Multiply }}},
- { Qt::Key_Plus, {2, { XK_plus, XK_KP_Add }}},
- { Qt::Key_Comma, {2, { XK_comma, XK_KP_Separator }}},
- { Qt::Key_Minus, {2, { XK_minus, XK_KP_Subtract }}},
- { Qt::Key_Period, {2, { XK_period, XK_KP_Decimal }}},
- { Qt::Key_Slash, {2, { XK_slash, XK_KP_Divide }}},
- { Qt::Key_F1, {1, { XK_F1 }}},
- { Qt::Key_F2, {1, { XK_F2 }}},
- { Qt::Key_F3, {1, { XK_F3 }}},
- { Qt::Key_F4, {1, { XK_F4 }}},
- { Qt::Key_F5, {1, { XK_F5 }}},
- { Qt::Key_F6, {1, { XK_F6 }}},
- { Qt::Key_F7, {1, { XK_F7 }}},
- { Qt::Key_F8, {1, { XK_F8 }}},
- { Qt::Key_F9, {1, { XK_F9 }}},
- { Qt::Key_F10, {1, { XK_F10 }}},
- { Qt::Key_F11, {1, { XK_F11 }}},
- { Qt::Key_F12, {1, { XK_F12 }}},
- { Qt::Key_F13, {1, { XK_F13 }}},
- { Qt::Key_F14, {1, { XK_F14 }}},
- { Qt::Key_F15, {1, { XK_F15 }}},
- { Qt::Key_F16, {1, { XK_F16 }}},
- { Qt::Key_F17, {1, { XK_F17 }}},
- { Qt::Key_F18, {1, { XK_F18 }}},
- { Qt::Key_F19, {1, { XK_F19 }}},
- { Qt::Key_F20, {1, { XK_F20 }}},
- { Qt::Key_F21, {1, { XK_F21 }}},
- { Qt::Key_F22, {1, { XK_F22 }}},
- { Qt::Key_F23, {1, { XK_F23 }}},
- { Qt::Key_F24, {1, { XK_F24 }}},
- { Qt::Key_F25, {1, { XK_F25 }}},
- { Qt::Key_F26, {1, { XK_F26 }}},
- { Qt::Key_F27, {1, { XK_F27 }}},
- { Qt::Key_F28, {1, { XK_F28 }}},
- { Qt::Key_F29, {1, { XK_F29 }}},
- { Qt::Key_F30, {1, { XK_F30 }}},
- { Qt::Key_F31, {1, { XK_F31 }}},
- { Qt::Key_F32, {1, { XK_F32 }}},
- { Qt::Key_F33, {1, { XK_F33 }}},
- { Qt::Key_F34, {1, { XK_F34 }}},
- { Qt::Key_F35, {1, { XK_F35 }}},
- { Qt::Key_Super_L, {1, { XK_Super_L }}},
- { Qt::Key_Super_R, {1, { XK_Super_R }}},
- { Qt::Key_Menu, {1, { XK_Menu }}},
- { Qt::Key_Hyper_L, {1, { XK_Hyper_L }}},
- { Qt::Key_Hyper_R, {1, { XK_Hyper_R }}},
- { Qt::Key_Help, {1, { XK_Help }}},
- { Qt::Key_Direction_L, {0, { 0 }}},
- { Qt::Key_Direction_R, {0, { 0 }}},
-
- { Qt::Key_unknown, {0, { 0 }}},
+ { Qt::Key_Escape, {1, { XK_Escape }}},
+ { Qt::Key_Tab, {2, { XK_Tab, XK_KP_Tab }}},
+ { Qt::Key_Backtab, {1, { XK_ISO_Left_Tab }}},
+ { Qt::Key_Backspace, {1, { XK_BackSpace }}},
+ { Qt::Key_Return, {1, { XK_Return }}},
+ { Qt::Key_Enter, {1, { XK_KP_Enter }}},
+ { Qt::Key_Insert, {2, { XK_Insert, XK_KP_Insert }}},
+ { Qt::Key_Delete, {3, { XK_Delete, XK_KP_Delete, XK_Clear }}},
+ { Qt::Key_Pause, {1, { XK_Pause }}},
+ { Qt::Key_Print, {1, { XK_Print }}},
+ { Qt::Key_SysReq, {1, { XK_Sys_Req }}},
+ { Qt::Key_Clear, {1, { XK_KP_Begin }}},
+ { Qt::Key_Home, {2, { XK_Home, XK_KP_Home }}},
+ { Qt::Key_End, {2, { XK_End, XK_KP_End }}},
+ { Qt::Key_Left, {2, { XK_Left, XK_KP_Left }}},
+ { Qt::Key_Up, {2, { XK_Up, XK_KP_Up }}},
+ { Qt::Key_Right, {2, { XK_Right, XK_KP_Right }}},
+ { Qt::Key_Down, {2, { XK_Down, XK_KP_Down }}},
+ { Qt::Key_PageUp, {2, { XK_Prior, XK_KP_Prior }}},
+ { Qt::Key_PageDown, {2, { XK_Next, XK_KP_Next }}},
+ { Qt::Key_Shift, {3, { XK_Shift_L, XK_Shift_R, XK_Shift_Lock }}},
+ { Qt::Key_Control, {2, { XK_Control_L, XK_Control_R }}},
+ { Qt::Key_Meta, {2, { XK_Meta_L, XK_Meta_R }}},
+ { Qt::Key_Alt, {2, { XK_Alt_L, XK_Alt_R }}},
+ { Qt::Key_CapsLock, {1, { XK_Caps_Lock }}},
+ { Qt::Key_NumLock, {1, { XK_Num_Lock }}},
+ { Qt::Key_ScrollLock, {1, { XK_Scroll_Lock }}},
+ { Qt::Key_Space, {2, { XK_space, XK_KP_Space }}},
+ { Qt::Key_Equal, {2, { XK_equal, XK_KP_Equal }}},
+ { Qt::Key_Asterisk, {2, { XK_asterisk, XK_KP_Multiply }}},
+ { Qt::Key_Plus, {2, { XK_plus, XK_KP_Add }}},
+ { Qt::Key_Comma, {2, { XK_comma, XK_KP_Separator }}},
+ { Qt::Key_Minus, {2, { XK_minus, XK_KP_Subtract }}},
+ { Qt::Key_Period, {2, { XK_period, XK_KP_Decimal }}},
+ { Qt::Key_Slash, {2, { XK_slash, XK_KP_Divide }}},
+ { Qt::Key_F1, {1, { XK_F1 }}},
+ { Qt::Key_F2, {1, { XK_F2 }}},
+ { Qt::Key_F3, {1, { XK_F3 }}},
+ { Qt::Key_F4, {1, { XK_F4 }}},
+ { Qt::Key_F5, {1, { XK_F5 }}},
+ { Qt::Key_F6, {1, { XK_F6 }}},
+ { Qt::Key_F7, {1, { XK_F7 }}},
+ { Qt::Key_F8, {1, { XK_F8 }}},
+ { Qt::Key_F9, {1, { XK_F9 }}},
+ { Qt::Key_F10, {1, { XK_F10 }}},
+ { Qt::Key_F11, {1, { XK_F11 }}},
+ { Qt::Key_F12, {1, { XK_F12 }}},
+ { Qt::Key_F13, {1, { XK_F13 }}},
+ { Qt::Key_F14, {1, { XK_F14 }}},
+ { Qt::Key_F15, {1, { XK_F15 }}},
+ { Qt::Key_F16, {1, { XK_F16 }}},
+ { Qt::Key_F17, {1, { XK_F17 }}},
+ { Qt::Key_F18, {1, { XK_F18 }}},
+ { Qt::Key_F19, {1, { XK_F19 }}},
+ { Qt::Key_F20, {1, { XK_F20 }}},
+ { Qt::Key_F21, {1, { XK_F21 }}},
+ { Qt::Key_F22, {1, { XK_F22 }}},
+ { Qt::Key_F23, {1, { XK_F23 }}},
+ { Qt::Key_F24, {1, { XK_F24 }}},
+ { Qt::Key_F25, {1, { XK_F25 }}},
+ { Qt::Key_F26, {1, { XK_F26 }}},
+ { Qt::Key_F27, {1, { XK_F27 }}},
+ { Qt::Key_F28, {1, { XK_F28 }}},
+ { Qt::Key_F29, {1, { XK_F29 }}},
+ { Qt::Key_F30, {1, { XK_F30 }}},
+ { Qt::Key_F31, {1, { XK_F31 }}},
+ { Qt::Key_F32, {1, { XK_F32 }}},
+ { Qt::Key_F33, {1, { XK_F33 }}},
+ { Qt::Key_F34, {1, { XK_F34 }}},
+ { Qt::Key_F35, {1, { XK_F35 }}},
+ { Qt::Key_Super_L, {1, { XK_Super_L }}},
+ { Qt::Key_Super_R, {1, { XK_Super_R }}},
+ { Qt::Key_Menu, {1, { XK_Menu }}},
+ { Qt::Key_Hyper_L, {1, { XK_Hyper_L }}},
+ { Qt::Key_Hyper_R, {1, { XK_Hyper_R }}},
+ { Qt::Key_Help, {1, { XK_Help }}},
+ { Qt::Key_Direction_L, {0, { 0 }}},
+ { Qt::Key_Direction_R, {0, { 0 }}},
+
+ { Qt::Key_unknown, {0, { 0 }}},
};
GlobalShortcutManager::KeyTrigger::KeyTrigger(const QKeySequence& key)
{
- d = new Impl(this, key);
+ d = new Impl(this, key);
}
-GlobalShortcutManager::KeyTrigger::~KeyTrigger()
+bool GlobalShortcutManager::KeyTrigger::isValid() const
{
- delete d;
- d = 0;
+ return true; // TODO
}
-
-bool GlobalShortcutManager::KeyTrigger::isValid() const
+GlobalShortcutManager::KeyTrigger::~KeyTrigger()
{
- return d->isValid();
+ delete d;
+ d = 0;
}
-
diff --git a/tools/globalshortcut/globalshortcuttrigger.h b/tools/globalshortcut/globalshortcuttrigger.h
index 81828b0..280b42d 100644
--- a/tools/globalshortcut/globalshortcuttrigger.h
+++ b/tools/globalshortcut/globalshortcuttrigger.h
@@ -1,63 +1,63 @@
/*
* globalshortcuttrigger.h - Helper class activating global shortcut
* Copyright (C) 2006 Maciej Niedzielski
*
* 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 library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifndef GLOBALSHORTCUTTRIGGER_H
#define GLOBALSHORTCUTTRIGGER_H
#include "globalshortcutmanager.h"
#include <QObject>
class GlobalShortcutManager::KeyTrigger : public QObject
{
Q_OBJECT
public:
/**
* Is there any slot connected to this hotkey?
*/
bool isUsed() const
{
- return QObject::receivers(SIGNAL(activated())) > 0;
- }
+ return QObject::receivers(SIGNAL(triggered())) > 0;
+ }
- bool isValid() const;
+ bool isValid() const;
signals:
- void activated();
+ void triggered();
private:
/**
* Registers the \a key.
*/
KeyTrigger(const QKeySequence& key);
/**
* Unregisters the key.
*/
~KeyTrigger();
friend class GlobalShortcutManager;
/**
* Platform-specific helper
*/
class Impl;
Impl* d;
};
#endif
diff --git a/tools/os.cpp b/tools/os.cpp
index 023c486..701039e 100644
--- a/tools/os.cpp
+++ b/tools/os.cpp
@@ -1,419 +1,417 @@
/*
* Copyright (C) 2012 Christian Kaiser
*
* 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 library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include <QApplication>
#include <QBitmap>
#include <QDesktopServices>
#include <QDesktopWidget>
#include <QDialog>
#include <QDir>
#include <QGraphicsDropShadowEffect>
#include <QLibrary>
#include <QPixmap>
#include <QPointer>
#include <QProcess>
#include <QSettings>
#include <QTextEdit>
#include <QTimeLine>
#include <QTimer>
#include <QTranslator>
#include <QUrl>
#include <QWidget>
#include <QIcon>
#include <string>
#include <QDebug>
#include <QMessageBox>
-#include "qtwin.h"
-
#ifdef Q_OS_WIN
+ #include <QtWin>
#include <qt_windows.h>
#include <shlobj.h>
#elif defined(Q_WS_X11)
#include <QX11Info>
#include <X11/X.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
#endif
#include "os.h"
void os::addToRecentDocuments(QString fileName)
{
#ifdef Q_OS_WIN
- QT_WA ( {
- SHAddToRecentDocs (0x00000003, QDir::toNativeSeparators(fileName).utf16());
- } , {
- SHAddToRecentDocs (0x00000002, QDir::toNativeSeparators(fileName).toLocal8Bit().data());
- } ); // QT_WA
+ SHAddToRecentDocs (0x00000003, QDir::toNativeSeparators(fileName).utf16());
#else
Q_UNUSED(fileName)
#endif
}
QPixmap os::cursor()
{
#ifdef Q_OS_WIN
/*
- * Taken from: git://github.com/arrai/mumble-record.git � src � mumble � Overlay.cpp
+ * Taken from: git://github.com/arrai/mumble-record.git > src > mumble > Overlay.cpp
* BSD License.
*/
QPixmap pixmap;
CURSORINFO cursorInfo;
cursorInfo.cbSize = sizeof(cursorInfo);
::GetCursorInfo(&cursorInfo);
HICON cursor = cursorInfo.hCursor;
ICONINFO iconInfo;
::GetIconInfo(cursor, &iconInfo);
ICONINFO info;
ZeroMemory(&info, sizeof(info));
if (::GetIconInfo(cursor, &info)) {
if (info.hbmColor) {
- pixmap = QPixmap::fromWinHBITMAP(info.hbmColor, QPixmap::Alpha);
+ pixmap = QtWin::fromHBITMAP(info.hbmColor, QtWin::HBitmapAlpha);
}
else {
- QBitmap orig(QPixmap::fromWinHBITMAP(info.hbmMask));
+ QBitmap orig(QtWin::fromHBITMAP(info.hbmMask));
QImage img = orig.toImage();
int h = img.height() / 2;
int w = img.bytesPerLine() / sizeof(quint32);
QImage out(img.width(), h, QImage::Format_MonoLSB);
QImage outmask(img.width(), h, QImage::Format_MonoLSB);
for (int i=0;i<h; ++i) {
const quint32 *srcimg = reinterpret_cast<const quint32 *>(img.scanLine(i + h));
const quint32 *srcmask = reinterpret_cast<const quint32 *>(img.scanLine(i));
quint32 *dstimg = reinterpret_cast<quint32 *>(out.scanLine(i));
quint32 *dstmask = reinterpret_cast<quint32 *>(outmask.scanLine(i));
for (int j=0;j<w;++j) {
dstmask[j] = srcmask[j];
dstimg[j] = srcimg[j];
}
}
pixmap = QBitmap::fromImage(out, Qt::ColorOnly);
}
if (info.hbmMask)
::DeleteObject(info.hbmMask);
if (info.hbmColor)
::DeleteObject(info.hbmColor);
}
return pixmap;
#else
return QPixmap();
#endif
}
void os::effect(QObject* target, const char *slot, int frames, int duration, const char* cleanup)
{
QTimeLine* timeLine = new QTimeLine(duration);
timeLine->setFrameRange(0, frames);
timeLine->connect(timeLine, SIGNAL(frameChanged(int)), target, slot);
if (cleanup != 0)
timeLine->connect(timeLine, SIGNAL(finished()), target, SLOT(cleanup()));
timeLine->connect(timeLine, SIGNAL(finished()), timeLine, SLOT(deleteLater()));
timeLine->start();
}
QString os::getDocumentsPath()
{
#ifdef Q_OS_WIN
TCHAR szPath[MAX_PATH];
if (SUCCEEDED(SHGetFolderPath(NULL,
CSIDL_PERSONAL|CSIDL_FLAG_CREATE,
NULL,
0,
szPath)))
{
std::wstring path(szPath);
return QString::fromWCharArray(path.c_str());
}
return QDir::homePath() + QDir::separator() + "My Documents";
#else
return QDir::homePath() + QDir::separator() + "Documents";
#endif
}
QPixmap os::grabWindow(WId winId)
{
#ifdef Q_OS_WIN
RECT rcWindow;
- GetWindowRect(winId, &rcWindow);
- if (IsZoomed(winId)) {
+ HWND hwndId = (HWND)winId;
+
+ GetWindowRect(hwndId, &rcWindow);
+
+ if (IsZoomed(hwndId)) {
int margin = GetSystemMetrics(SM_CXSIZEFRAME);
rcWindow.right -= margin;
rcWindow.left += margin;
rcWindow.top += margin;
rcWindow.bottom -= margin;
}
int width, height;
width = rcWindow.right - rcWindow.left;
height = rcWindow.bottom - rcWindow.top;
RECT rcScreen;
GetWindowRect(GetDesktopWindow(), &rcScreen);
RECT rcResult;
UnionRect(&rcResult, &rcWindow, &rcScreen);
QPixmap pixmap;
// Comparing the rects to determine if the window is outside the boundaries of the screen,
// the window DC method has the disadvantage that it does not show Aero glass transparency,
// so we'll avoid it for the screenshots that don't need it.
HDC hdcMem;
HBITMAP hbmCapture;
if (EqualRect(&rcScreen, &rcResult)) {
// Grabbing the window from the Screen DC.
HDC hdcScreen = GetDC(NULL);
- BringWindowToTop(winId);
+ BringWindowToTop(hwndId);
hdcMem = CreateCompatibleDC(hdcScreen);
hbmCapture = CreateCompatibleBitmap(hdcScreen, width, height);
SelectObject(hdcMem, hbmCapture);
BitBlt(hdcMem, 0, 0, width, height, hdcScreen, rcWindow.left, rcWindow.top, SRCCOPY);
}
else {
// Grabbing the window by its own DC
- HDC hdcWindow = GetWindowDC(winId);
+ HDC hdcWindow = GetWindowDC(hwndId);
hdcMem = CreateCompatibleDC(hdcWindow);
hbmCapture = CreateCompatibleBitmap(hdcWindow, width, height);
SelectObject(hdcMem, hbmCapture);
BitBlt(hdcMem, 0, 0, width, height, hdcWindow, 0, 0, SRCCOPY);
}
- ReleaseDC(winId, hdcMem);
+ ReleaseDC(hwndId, hdcMem);
DeleteDC(hdcMem);
- pixmap = QPixmap::fromWinHBITMAP(hbmCapture);
+ pixmap = QtWin::fromHBITMAP(hbmCapture);
DeleteObject(hbmCapture);
return pixmap;
#else
return QPixmap::grabWindow(winId);
#endif
}
void os::setForegroundWindow(QWidget *window)
{
#ifdef Q_OS_WIN
- ShowWindow(window->winId(), SW_RESTORE);
- SetForegroundWindow(window->winId());
+ ShowWindow((HWND)window->winId(), SW_RESTORE);
+ SetForegroundWindow((HWND)window->winId());
#else
Q_UNUSED(window)
#endif
}
void os::setStartup(bool startup, bool hide)
{
QString lightscreen = QDir::toNativeSeparators(qApp->applicationFilePath());
if (hide)
lightscreen.append(" -h");
#ifdef Q_OS_WIN
// Windows startup settings
QSettings init("Microsoft", "Windows");
init.beginGroup("CurrentVersion");
init.beginGroup("Run");
if (startup) {
init.setValue("Lightscreen", lightscreen);
}
else {
init.remove("Lightscreen");
}
init.endGroup();
init.endGroup();
#endif
#if defined(Q_WS_X11)
QFile desktopFile(QDir::homePath() + "/.config/autostart/lightscreen.desktop");
desktopFile.remove();
if (startup) {
desktopFile.open(QIODevice::WriteOnly);
desktopFile.write(QString("[Desktop Entry]\nExec=%1\nType=Application").arg(lightscreen).toAscii());
}
#endif
}
QGraphicsEffect* os::shadow(QColor color, int blurRadius, int offset) {
QGraphicsDropShadowEffect* shadowEffect = new QGraphicsDropShadowEffect;
shadowEffect->setBlurRadius(blurRadius);
shadowEffect->setOffset(offset);
shadowEffect->setColor(color);
return shadowEffect;
}
void os::translate(QString language)
{
static QTranslator *translator = 0;
static QTranslator *translator_qt = 0;
if ((language.compare("English", Qt::CaseInsensitive) == 0
|| language.isEmpty()) && translator) {
qApp->removeTranslator(translator);
qApp->removeTranslator(translator_qt);
QLocale::setDefault(QLocale::c());
return;
}
if (translator) {
delete translator;
delete translator_qt;
}
translator = new QTranslator(qApp);
translator_qt = new QTranslator(qApp);
- if (language == "Espa�ol")
+ if (language == "Español")
QLocale::setDefault(QLocale::Spanish);
if (translator->load(language, ":/translations")) {
qApp->installTranslator(translator);
}
if (translator_qt->load(language, ":/translations_qt")) {
qApp->installTranslator(translator_qt);
}
}
QIcon os::icon(QString name)
{
static int value = -1;
if (value < 0) {
value = qApp->desktop()->palette().color(QPalette::Button).value();
}
if (value > 125) {
return QIcon(":/icons/" + name);
}
else {
return QIcon(":/icons/inv/" + name);
}
}
#ifdef Q_WS_X11
// Taken from KSnapshot. Oh KDE, what would I do whithout you :D
Window os::findRealWindow(Window w, int depth)
{
if( depth > 5 ) {
return None;
}
static Atom wm_state = XInternAtom( QX11Info::display(), "WM_STATE", False );
Atom type;
int format;
unsigned long nitems, after;
unsigned char* prop;
if( XGetWindowProperty( QX11Info::display(), w, wm_state, 0, 0, False, AnyPropertyType,
&type, &format, &nitems, &after, &prop ) == Success ) {
if( prop != NULL ) {
XFree( prop );
}
if( type != None ) {
return w;
}
}
Window root, parent;
Window* children;
unsigned int nchildren;
Window ret = None;
if( XQueryTree( QX11Info::display(), w, &root, &parent, &children, &nchildren ) != 0 ) {
for( unsigned int i = 0;
i < nchildren && ret == None;
++i ) {
ret = os::findRealWindow( children[ i ], depth + 1 );
}
if( children != NULL ) {
XFree( children );
}
}
return ret;
}
Window os::windowUnderCursor(bool includeDecorations)
{
Window root;
Window child;
uint mask;
int rootX, rootY, winX, winY;
XQueryPointer( QX11Info::display(), QX11Info::appRootWindow(), &root, &child,
&rootX, &rootY, &winX, &winY, &mask );
if( child == None ) {
child = QX11Info::appRootWindow();
}
if( !includeDecorations ) {
Window real_child = os::findRealWindow( child );
if( real_child != None ) { // test just in case
child = real_child;
}
}
return child;
}
#endif
diff --git a/tools/screenshotmanager.cpp b/tools/screenshotmanager.cpp
index ded7a43..f5b6230 100644
--- a/tools/screenshotmanager.cpp
+++ b/tools/screenshotmanager.cpp
@@ -1,210 +1,210 @@
/*
* Copyright (C) 2012 Christian Kaiser
*
* 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 library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include "screenshotmanager.h"
#include "screenshot.h"
#include "uploader.h"
#include <QApplication>
#include <QDateTime>
#include <QDebug>
#include <QStandardPaths>
#include <QFile>
#include <QSettings>
#include <QtSql/QSqlDatabase>
#include <QtSql/QSqlQuery>
#include <QtSql/QSqlRecord>
#include <QtSql/QSqlError>
ScreenshotManager::ScreenshotManager(QObject *parent = 0) : QObject(parent)
{
QString historyPath;
- if (QFile::exists(qApp->applicationDirPath() + "/config.ini")) {
+ if (QFile::exists(qApp->applicationDirPath() + QDir::separator() + "config.ini")) {
mSettings = new QSettings(qApp->applicationDirPath() + QDir::separator() + "config.ini", QSettings::IniFormat);
mPortableMode = true;
historyPath = qApp->applicationDirPath() + QDir::separator();
}
else {
mSettings = new QSettings();
mPortableMode = false;
historyPath = QStandardPaths::writableLocation(QStandardPaths::DataLocation) + QDir::separator();
}
// Creating the SQLite database.
QSqlDatabase history = QSqlDatabase::addDatabase("QSQLITE");
QDir hp(historyPath);
if (!hp.exists())
hp.mkpath(historyPath);
history.setHostName("localhost");
history.setDatabaseName(historyPath + "history.sqlite");
if (history.open()) {
history.exec("CREATE TABLE IF NOT EXISTS history (fileName text, URL text, deleteURL text, time integer)");
}
else {
qCritical() << "Could not open SQLite DB.";
}
connect(Uploader::instance(), SIGNAL(done(QString, QString, QString)), this, SLOT(uploadDone(QString, QString, QString)));
}
ScreenshotManager::~ScreenshotManager()
{
delete mSettings;
}
int ScreenshotManager::activeCount() const
{
return mScreenshots.count();
}
bool ScreenshotManager::portableMode()
{
return mPortableMode;
}
void ScreenshotManager::saveHistory(QString fileName, QString url, QString deleteHash)
{
if (!mSettings->value("/options/history", true).toBool())
return;
QString deleteUrl;
if (!deleteHash.isEmpty())
deleteUrl = "http://imgur.com/delete/" + deleteHash;
QSqlQuery query;
query.prepare("INSERT INTO history (fileName, URL, deleteURL, time) VALUES(?, ?, ?, ?)");
query.addBindValue(fileName);
query.addBindValue(url);
query.addBindValue(deleteUrl);
query.addBindValue(QDateTime::currentMSecsSinceEpoch());
query.exec();
}
void ScreenshotManager::updateHistory(QString fileName, QString url, QString deleteHash)
{
if (!mSettings->value("/options/history", true).toBool())
return;
QSqlQuery query;
query.prepare("SELECT fileName FROM history WHERE URL IS NOT EMPTY AND fileName = ?");
query.addBindValue(fileName);
query.exec();
if (query.record().count() > 0 && !url.isEmpty()) {
// Makes sure to only update the latest file, in case something weird happened with the files (deleted screenshots, etc). Though that might still happen in some edge cases that I'm too lazy to account for.
QSqlQuery updateQuery;
updateQuery.prepare("UPDATE history SET URL = ?, deleteURL = ?, time = ? WHERE fileName = ?");
updateQuery.addBindValue(url);
updateQuery.addBindValue("http://imgur.com/delete/" + deleteHash);
updateQuery.addBindValue(QDateTime::currentMSecsSinceEpoch());
updateQuery.addBindValue(fileName);
updateQuery.exec();
}
else {
saveHistory(fileName, url, deleteHash);
}
}
void ScreenshotManager::removeHistory(QString fileName, qint64 time)
{
QSqlQuery removeQuery;
removeQuery.prepare("DELETE FROM history WHERE fileName = ? AND time = ?");
removeQuery.addBindValue(fileName);
removeQuery.addBindValue(time);
removeQuery.exec();
}
void ScreenshotManager::clearHistory()
{
QSqlQuery clearQuery("DROP TABLE history");
clearQuery.exec();
}
//
void ScreenshotManager::askConfirmation()
{
Screenshot* s = qobject_cast<Screenshot*>(sender());
emit confirm(s);
}
void ScreenshotManager::cleanup()
{
Screenshot* screenshot = qobject_cast<Screenshot*>(sender());
emit windowCleanup(screenshot->options());
}
void ScreenshotManager::finished()
{
Screenshot* screenshot = qobject_cast<Screenshot*>(sender());
mScreenshots.removeOne(screenshot);
screenshot->deleteLater();
}
void ScreenshotManager::take(Screenshot::Options &options)
{
Screenshot* newScreenshot = new Screenshot(this, options);
mScreenshots.append(newScreenshot);
connect(newScreenshot, SIGNAL(askConfirmation()), this, SLOT(askConfirmation()));
connect(newScreenshot, SIGNAL(cleanup()) , this, SLOT(cleanup()));
connect(newScreenshot, SIGNAL(finished()) , this, SLOT(finished()));
newScreenshot->take();
}
void ScreenshotManager::uploadDone(QString fileName, QString url, QString deleteHash)
{
foreach (Screenshot* screenshot, mScreenshots) {
if (screenshot->options().fileName == fileName
|| screenshot->unloadedFileName() == fileName) {
screenshot->uploadDone(url);
if (screenshot->options().file) {
updateHistory(fileName, url, deleteHash);
}
else {
saveHistory("", url, deleteHash);
}
return;
}
}
// If we get here, it's because the screenshot upload wasn't on the current screenshot list, which means it's a View History/Upload Later upload.
updateHistory(fileName, url, deleteHash);
}
// Singleton
ScreenshotManager* ScreenshotManager::mInstance = 0;
ScreenshotManager *ScreenshotManager::instance()
{
if (!mInstance)
mInstance = new ScreenshotManager();
return mInstance;
}
diff --git a/tools/windowpicker.cpp b/tools/windowpicker.cpp
index d2c6187..396882b 100644
--- a/tools/windowpicker.cpp
+++ b/tools/windowpicker.cpp
@@ -1,305 +1,311 @@
/*
* Copyright (C) 2012 Christian Kaiser
*
* 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 library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include <QApplication>
#include <QDesktopWidget>
#include <QLabel>
#include <QMouseEvent>
#include <QPushButton>
#include <QRubberBand>
#include <QRubberBand>
#include <QVBoxLayout>
#include <QWidget>
#include <QDebug>
-#include "winextras/qwinfunctions.h"
#include "windowpicker.h"
#include "os.h"
#if defined(Q_OS_WIN)
+ #include <QtWin>
#include <windows.h>
+
+#ifdef _WIN64
+ #define GCL_HICON GCLP_HICON
+ #define GCL_HICONSM GCLP_HICONSM
+#endif
+
#elif defined(Q_WS_X11)
#include <QX11Info>
#include <X11/X.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
#endif
WindowPicker::WindowPicker() : QWidget(0), mCrosshair(":/icons/picker"), mWindowLabel(0), mTaken(false)
{
#if defined(Q_OS_WIN)
setWindowFlags(Qt::SplashScreen | Qt::WindowStaysOnTopHint);
#elif defined(Q_WS_X11)
setWindowFlags(Qt::WindowStaysOnTopHint);
#endif
setWindowTitle(tr("Lightscreen Window Picker"));
setStyleSheet("QWidget { color: #000; } #frame { padding: 7px 10px; border: 4px solid #232323; background-color: rgba(250, 250, 250, 255); }");
QLabel *helpLabel = new QLabel(tr("Grab the window picker by clicking and holding down the mouse button, then drag it to the window of your choice and release it to capture."), this);
helpLabel->setMinimumWidth(400);
helpLabel->setMaximumWidth(400);
helpLabel->setWordWrap(true);
mWindowIcon = new QLabel(this);
mWindowIcon->setMinimumSize(22, 22);
mWindowIcon->setMaximumSize(22, 22);
mWindowIcon->setScaledContents(true);
mWindowLabel = new QLabel(tr(" - Start dragging to select windows"), this);
mWindowLabel->setStyleSheet("font-weight: bold");
mCrosshairLabel = new QLabel(this);
mCrosshairLabel->setAlignment(Qt::AlignHCenter);
mCrosshairLabel->setPixmap(mCrosshair);
QPushButton *closeButton = new QPushButton(tr("Close"));
connect(closeButton, SIGNAL(clicked()), this, SLOT(close()));
QHBoxLayout *windowLayout = new QHBoxLayout;
windowLayout->addWidget(mWindowIcon);
windowLayout->addWidget(mWindowLabel);
windowLayout->setMargin(0);
QHBoxLayout *buttonLayout = new QHBoxLayout;
buttonLayout->addStretch(0);
buttonLayout->addWidget(closeButton);
buttonLayout->setMargin(0);
QHBoxLayout *crosshairLayout = new QHBoxLayout;
crosshairLayout->addStretch(0);
crosshairLayout->addWidget(mCrosshairLabel);
crosshairLayout->addStretch(0);
crosshairLayout->setMargin(0);
QVBoxLayout *fl = new QVBoxLayout;
fl->addWidget(helpLabel);
fl->addLayout(windowLayout);
fl->addLayout(crosshairLayout);
fl->addLayout(buttonLayout);
fl->setMargin(0);
QFrame *frame = new QFrame(this);
frame->setObjectName("frame");
frame->setLayout(fl);
QVBoxLayout *l = new QVBoxLayout;
l->setMargin(0);
l->addWidget(frame);
setLayout(l);
resize(sizeHint());
move(QApplication::desktop()->screenGeometry(QApplication::desktop()->screenNumber(QCursor::pos())).center()-QPoint(width()/2, height()/2));
show();
}
WindowPicker::~WindowPicker() {
qApp->restoreOverrideCursor();
}
void WindowPicker::cancel() {
mWindowIcon->setPixmap(QPixmap());
mCrosshairLabel->setPixmap(mCrosshair);
qApp->restoreOverrideCursor();
}
void WindowPicker::closeEvent(QCloseEvent*)
{
if (!mTaken)
emit pixmap(QPixmap());
qApp->restoreOverrideCursor();
deleteLater();
}
void WindowPicker::mouseMoveEvent(QMouseEvent *event)
{
QString windowName;
#if defined(Q_OS_WIN)
POINT mousePos;
mousePos.x = event->globalX();
mousePos.y = event->globalY();
HWND cWindow = GetAncestor(WindowFromPoint(mousePos), GA_ROOT);
mCurrentWindow = (WId) cWindow;
if (mCurrentWindow == winId()) {
mWindowIcon->setPixmap(QPixmap());
mWindowLabel->setText("");
return;
}
// Text
WCHAR str[60];
HICON icon;
::GetWindowText((HWND)mCurrentWindow, str, 60);
windowName = QString::fromWCharArray(str);
///
// Retrieving the application icon
icon = (HICON)::GetClassLong((HWND)mCurrentWindow, GCL_HICON);
if (icon != NULL) {
- mWindowIcon->setPixmap(QWinExtras::fromHICON(icon));
+ mWindowIcon->setPixmap(QtWin::fromHICON(icon));
}
else {
mWindowIcon->setPixmap(QPixmap());
}
#elif defined(Q_WS_X11)
Window cWindow = os::windowUnderCursor(false);
if (cWindow == mCurrentWindow) {
return;
}
mCurrentWindow = cWindow;
if (mCurrentWindow == winId()) {
mWindowIcon->setPixmap(QPixmap());
mWindowLabel->setText("");
return;
}
// Getting the window name property.
XTextProperty tp;
char **text;
int count;
if (XGetTextProperty(QX11Info::display(), cWindow, &tp, XA_WM_NAME) != 0 && tp.value != NULL ) {
if (tp.encoding == XA_STRING) {
windowName = QString::fromLocal8Bit((const char*) tp.value);
}
else if (XmbTextPropertyToTextList( QX11Info::display(), &tp, &text, &count) == Success &&
text != NULL && count > 0) {
windowName = QString::fromLocal8Bit(text[0]);
XFreeStringList(text);
}
XFree(tp.value);
}
// Retrieving the _NET_WM_ICON property.
Atom type_ret = None;
unsigned char *data = 0;
int format = 0;
unsigned long n = 0;
unsigned long extra = 0;
int width = 0;
int height = 0;
Atom _net_wm_icon = XInternAtom(QX11Info::display(), "_NET_WM_ICON", False);
if (XGetWindowProperty(QX11Info::display(), cWindow, _net_wm_icon, 0, 1, False,
XA_CARDINAL, &type_ret, &format, &n, &extra, (unsigned char **)&data) == Success && data)
{
width = data[0];
XFree(data);
}
if (XGetWindowProperty(QX11Info::display(), cWindow, _net_wm_icon, 1, 1, False,
XA_CARDINAL, &type_ret, &format, &n, &extra, (unsigned char **)&data) == Success && data)
{
height = data[0];
XFree(data);
}
if (XGetWindowProperty(QX11Info::display(), cWindow, _net_wm_icon, 2, width*height, False,
XA_CARDINAL, &type_ret, &format, &n, &extra, (unsigned char **)&data) == Success && data)
{
QImage img(data, width, height, QImage::Format_ARGB32);
mWindowIcon->setPixmap(QPixmap::fromImage(img));
XFree(data);
}
else {
mWindowIcon->setPixmap(QPixmap());
}
#endif
QString windowText;
if (!mWindowIcon->pixmap()) {
windowText = QString(" - %1").arg(windowName);
}
else {
windowText = windowName;
}
if (windowText == " - ") {
mWindowLabel->setText("");
return;
}
if (windowText.length() == 62) {
mWindowLabel->setText(windowText + "...");
}
else {
mWindowLabel->setText(windowText);
}
}
void WindowPicker::mousePressEvent(QMouseEvent *event)
{
qApp->setOverrideCursor(QCursor(mCrosshair));
mCrosshairLabel->setMinimumWidth(mCrosshairLabel->width());
mCrosshairLabel->setMinimumHeight(mCrosshairLabel->height());
mCrosshairLabel->setPixmap(QPixmap());
QWidget::mousePressEvent(event);
}
void WindowPicker::mouseReleaseEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton) {
#if defined(Q_OS_WIN)
POINT mousePos;
mousePos.x = event->globalX();
mousePos.y = event->globalY();
HWND window = GetAncestor(WindowFromPoint(mousePos), GA_ROOT);
#elif defined(Q_WS_X11)
Window window = os::windowUnderCursor(false);
#endif
if ((WId)window == winId()) {
cancel();
return;
}
mTaken = true;
setWindowFlags(windowFlags() ^ Qt::WindowStaysOnTopHint);
close();
#ifdef Q_WS_X11
emit pixmap(QPixmap::grabWindow(mCurrentWindow));
#else
emit pixmap(os::grabWindow((WId)window));
#endif
return;
}
close();
}

File Metadata

Mime Type
text/x-diff
Expires
Tue, Jun 16, 1:28 AM (2 w, 18 h ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
70137
Default Alt Text
(243 KB)

Event Timeline