Page MenuHomePhabricator (Chris)

No OneTemporary

Authored By
Unknown
Size
150 KB
Referenced Files
None
Subscribers
None
diff --git a/lightscreen.pro b/lightscreen.pro
index 0a8b704..33f9cad 100644
--- a/lightscreen.pro
+++ b/lightscreen.pro
@@ -1,78 +1,78 @@
TEMPLATE = app
TARGET = lightscreen
HEADERS += dialogs/areadialog.h \
dialogs/historydialog.h \
dialogs/namingdialog.h \
dialogs/optionsdialog.h \
dialogs/previewdialog.h \
dialogs/updaterdialog.h \
lightscreenwindow.h \
tools/os.h \
tools/screenshot.h \
tools/screenshotmanager.h \
tools/uploader.h \
tools/windowpicker.h \
updater/updater.h \
widgets/hotkeywidget.h \
tools/qtsingleapplication/qtlockedfile.h \
tools/qtsingleapplication/qtsinglecoreapplication.h \
tools/uploader/imageuploader.h \
tools/uploader/imguruploader.h \
tools/uploader/uploader.h \
tools/qtwin.h
SOURCES += dialogs/areadialog.cpp \
dialogs/historydialog.cpp \
dialogs/namingdialog.cpp \
dialogs/optionsdialog.cpp \
dialogs/previewdialog.cpp \
dialogs/updaterdialog.cpp \
lightscreenwindow.cpp \
main.cpp \
tools/os.cpp \
tools/screenshot.cpp \
tools/screenshotmanager.cpp \
tools/windowpicker.cpp \
updater/updater.cpp \
widgets/hotkeywidget.cpp \
tools/qtsingleapplication/qtlockedfile.cpp \
tools/qtsingleapplication/qtlockedfile_unix.cpp \
tools/qtsingleapplication/qtlockedfile_win.cpp \
tools/qtsingleapplication/qtsinglecoreapplication.cpp \
tools/uploader/imageuploader.cpp \
tools/uploader/imguruploader.cpp \
tools/uploader/uploader.cpp \
tools/qtwin.cpp
FORMS += dialogs/historydialog.ui \
dialogs/namingdialog.ui \
dialogs/optionsdialog.ui \
lightscreenwindow.ui
RESOURCES += lightscreen.qrc
RC_FILE += lightscreen.rc
CODECFORSRC = UTF-8
QT += network core gui sql multimedia winextras
-include($$PWD/tools/globalshortcut/globalshortcut.pri)
+include($$PWD/tools/qxtglobalshortcut/qxtglobalshortcut.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 abae90e..9743991 100644
--- a/lightscreenwindow.cpp
+++ b/lightscreenwindow.cpp
@@ -1,1013 +1,1037 @@
/*
* Copyright (C) 2014 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 <QDate>
#include <QDesktopServices>
#include <QDesktopWidget>
#include <QFileInfo>
#include <QKeyEvent>
#include <QMainWindow>
#include <QMenu>
#include <QMessageBox>
#include <QPointer>
#include <QProcess>
#include <QSettings>
#include <QSystemTrayIcon>
#include <QTimer>
#include <QToolTip>
#include <QUrl>
#include <QSound>
#ifdef Q_OS_WIN
#include <windows.h>
#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/qxtglobalshortcut/qxtglobalshortcut.h"
#include "tools/uploader/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()
{
ui.setupUi(this);
if (QtWin::isCompositionEnabled()) {
setAttribute(Qt::WA_NoSystemBackground);
QtWin::enableBlurBehindWindow(this);
QtWin::extendFrameIntoClientArea(this, QMargins(-1, -1, -1, -1));
}
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(windowFlags() ^ Qt::WindowMaximizeButtonHint);
#ifdef Q_OS_WIN
if (QSysInfo::windowsVersion() >= QSysInfo::WV_WINDOWS7) {
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()));
+ // Shortcuts
+ connect(&mScreenShortcut , &QxtGlobalShortcut::activated, this, &LightscreenWindow::screenHotkey);
+ connect(&mAreaShortcut , &QxtGlobalShortcut::activated, this, &LightscreenWindow::areaHotkey);
+ connect(&mWindowShortcut , &QxtGlobalShortcut::activated, this, &LightscreenWindow::windowHotkey);
+ connect(&mWindowPickerShortcut, &QxtGlobalShortcut::activated, this, &LightscreenWindow::windowPickerHotkey);
+ connect(&mOpenShortcut , &QxtGlobalShortcut::activated, this, &LightscreenWindow::show);
+ connect(&mDirectoryShortcut , &QxtGlobalShortcut::activated, this, &LightscreenWindow::goToFolder);
+
// Uploader
connect(Uploader::instance(), SIGNAL(progress(int)), this, SLOT(uploadProgress(int)));
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();
+ //GlobalShortcutManager::instance()->clear();
delete mTrayIcon;
}
void LightscreenWindow::action(int mode)
{
if (mode == 4) {
goToFolder();
}
else {
show();
}
}
+
void LightscreenWindow::areaHotkey()
{
- screenshotAction(2);
+ 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"));
#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"));
}
#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->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::screenHotkey()
+{
+ screenshotAction(0);
+}
+
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();
+ //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;
updateUploadStatus();
if (mTrayIcon && !error.isEmpty() && settings()->value("options/message").toBool()) {
mTrayIcon->showMessage(tr("Upload error"), error);
}
notify(Screenshot::Fail);
}
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->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.com.ar/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(int progress)
{
#ifdef Q_OS_WIN
if (mTaskbarButton) {
mTaskbarButton->progress()->setRange(0, 100);
mTaskbarButton->progress()->setValue(progress);
}
if (isVisible() && progress > 0) {
int uploadCount = Uploader::instance()->uploading();
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()
{
+ bool screen = mScreenShortcut.setShortcut(settings()->value("actions/screen/hotkey").value<QKeySequence>());
+ mScreenShortcut.setEnabled(settings()->value("actions/screen/enabled").toBool());
+
+ bool area = mAreaShortcut.setShortcut(settings()->value("actions/area/hotkey").value<QKeySequence>());
+ mAreaShortcut.setEnabled(settings()->value("actions/area/enabled").toBool());
+
+/*
+
// 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 (!window) failed << "window";
if (!windowPicker) failed << "window picker";
if (!open) failed << "open";
- if (!directory) failed << "directory";
+ 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);
}
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 4bf12ca..67fda0b 100644
--- a/lightscreenwindow.h
+++ b/lightscreenwindow.h
@@ -1,117 +1,127 @@
/*
* Copyright (C) 2014 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 "tools/qxtglobalshortcut/qxtglobalshortcut.h"
+
#include "dialogs/previewdialog.h"
#include "ui_lightscreenwindow.h"
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 screenHotkey();
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(int progress);
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;
+ QxtGlobalShortcut mScreenShortcut;
+ QxtGlobalShortcut mAreaShortcut;
+ QxtGlobalShortcut mWindowShortcut;
+ QxtGlobalShortcut mWindowPickerShortcut;
+ QxtGlobalShortcut mOpenShortcut;
+ QxtGlobalShortcut mDirectoryShortcut;
+
#ifdef Q_OS_WIN
QWinTaskbarButton *mTaskbarButton;
#endif
};
#endif // LIGHTSCREENWINDOW_H
diff --git a/tools/globalshortcut/NDKeyboardLayout.h b/tools/globalshortcut/NDKeyboardLayout.h
deleted file mode 100644
index b2688f6..0000000
--- a/tools/globalshortcut/NDKeyboardLayout.h
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- 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
deleted file mode 100644
index 2da9926..0000000
--- a/tools/globalshortcut/NDKeyboardLayout.m
+++ /dev/null
@@ -1,491 +0,0 @@
-/*
- 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
deleted file mode 100644
index 0c788ac..0000000
--- a/tools/globalshortcut/globalshortcut.pri
+++ /dev/null
@@ -1,18 +0,0 @@
-HEADERS += $$PWD/globalshortcutmanager.h $$PWD/globalshortcuttrigger.h
-SOURCES += $$PWD/globalshortcutmanager.cpp
-DEPENDPATH += $$PWD
-
-unix:!mac {
- SOURCES += $$PWD/globalshortcutmanager_x11.cpp
-}
-win32: {
- SOURCES += $$PWD/globalshortcutmanager_win.cpp
-}
-mac: {
- *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
deleted file mode 100644
index d08e1b3..0000000
--- a/tools/globalshortcut/globalshortcutmanager.cpp
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * 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., 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())
-{
-}
-
-GlobalShortcutManager::~GlobalShortcutManager()
-{
- clear();
-}
-
-GlobalShortcutManager* GlobalShortcutManager::instance_ = 0;
-
-/**
- * \brief Returns the instance of GlobalShortcutManager.
- */
-GlobalShortcutManager* GlobalShortcutManager::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) {
- t = new KeyTrigger(key);
-
- if (!t->isValid()) {
- t->deleteLater();
- return false;
- }
-
- instance()->triggers_.insert(key, t);
- }
-
- 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;
- }
-
- QObject::disconnect(t, SIGNAL(triggered()), receiver, slot);
-
- if (!t->isUsed()) {
- delete instance()->triggers_.take(key);
- }
-}
-
-void GlobalShortcutManager::clear()
-{
- foreach (KeyTrigger* t, instance()->triggers_)
- delete t;
- instance()->triggers_.clear();
-}
diff --git a/tools/globalshortcut/globalshortcutmanager.h b/tools/globalshortcut/globalshortcutmanager.h
deleted file mode 100644
index 2cc85e8..0000000
--- a/tools/globalshortcut/globalshortcutmanager.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * 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., 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 bool connect(const QKeySequence& key, QObject* receiver, const char* slot);
- 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_;
-};
-
-#endif
diff --git a/tools/globalshortcut/globalshortcutmanager_mac.mm b/tools/globalshortcut/globalshortcutmanager_mac.mm
deleted file mode 100644
index 9f6f83a..0000000
--- a/tools/globalshortcut/globalshortcutmanager_mac.mm
+++ /dev/null
@@ -1,301 +0,0 @@
-/*
- * 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>
-
-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())
- {
- 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_;
-
- static EventHandlerUPP hot_key_function_;
-
-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 = [[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;
-
-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_->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
deleted file mode 100644
index fcdd5f3..0000000
--- a/tools/globalshortcut/globalshortcutmanager_win.cpp
+++ /dev/null
@@ -1,230 +0,0 @@
-/*
- * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- */
-
-#include "globalshortcutmanager.h"
-#include "globalshortcuttrigger.h"
-
-#include <QWidget>
-#include <windows.h>
-#include <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) :
- 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()
- {
- 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)
- if (m->message == WM_HOTKEY && m->wParam == id_) {
- emit trigger_->triggered();
- return true;
- }
- return false;
- }
-
- 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 = 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_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 },
-};
-
-WPARAM GlobalShortcutManager::KeyTrigger::Impl::nextId = 1;
-
-GlobalShortcutManager::KeyTrigger::KeyTrigger(const QKeySequence& key)
-{
- d = new Impl(this, key);
-}
-
-bool GlobalShortcutManager::KeyTrigger::isValid() const
-{
- return d->valid;
-}
-
-GlobalShortcutManager::KeyTrigger::~KeyTrigger()
-{
- delete d;
- d = 0;
-}
diff --git a/tools/globalshortcut/globalshortcutmanager_x11.cpp b/tools/globalshortcut/globalshortcutmanager_x11.cpp
deleted file mode 100644
index 8553ee2..0000000
--- a/tools/globalshortcut/globalshortcutmanager_x11.cpp
+++ /dev/null
@@ -1,445 +0,0 @@
-/*
- * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- */
-
-#include "globalshortcutmanager.h"
-#include "globalshortcuttrigger.h"
-
-#include <QWidget>
-#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(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];
- };
-
-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(QKeySequence(qkey))) {
- trigger->activate();
- return true;
- }
- }
- }
-
- return QObject::eventFilter(o, e);
- }
-
-private:
- X11KeyTriggerManager()
- : QObject(QCoreApplication::instance())
- {
- QCoreApplication::instance()->installEventFilter(this);
- }
-
- 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 = 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[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_;
- 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(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 }}},
-};
-
-GlobalShortcutManager::KeyTrigger::KeyTrigger(const QKeySequence& key)
-{
- d = new Impl(this, key);
-}
-
-bool GlobalShortcutManager::KeyTrigger::isValid() const
-{
- return true; // TODO
-}
-
-GlobalShortcutManager::KeyTrigger::~KeyTrigger()
-{
- delete d;
- d = 0;
-}
diff --git a/tools/globalshortcut/globalshortcuttrigger.h b/tools/globalshortcut/globalshortcuttrigger.h
deleted file mode 100644
index 280b42d..0000000
--- a/tools/globalshortcut/globalshortcuttrigger.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * 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., 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(triggered())) > 0;
- }
-
- bool isValid() const;
-
-signals:
- 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/qxtglobalshortcut/qxtglobal.cpp b/tools/qxtglobalshortcut/qxtglobal.cpp
new file mode 100644
index 0000000..3da47c1
--- /dev/null
+++ b/tools/qxtglobalshortcut/qxtglobal.cpp
@@ -0,0 +1,251 @@
+
+/****************************************************************************
+** Copyright (c) 2006 - 2011, the LibQxt project.
+** See the Qxt AUTHORS file for a list of authors and copyright holders.
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** * Neither the name of the LibQxt project nor the
+** names of its contributors may be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+** DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
+** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+**
+** <http://libqxt.org> <foundation@libqxt.org>
+*****************************************************************************/
+
+#include "qxtglobal.h"
+
+/*!
+ \headerfile <QxtGlobal>
+ \title Global Qxt Declarations
+ \inmodule QxtCore
+
+ \brief The <QxtGlobal> header provides basic declarations and
+ is included by all other Qxt headers.
+ */
+
+/*!
+ \macro QXT_VERSION
+ \relates <QxtGlobal>
+
+ This macro expands a numeric value of the form 0xMMNNPP (MM =
+ major, NN = minor, PP = patch) that specifies Qxt's version
+ number. For example, if you compile your application against Qxt
+ 0.4.0, the QXT_VERSION macro will expand to 0x000400.
+
+ You can use QXT_VERSION to use the latest Qt features where
+ available. For example:
+ \code
+ #if QXT_VERSION >= 0x000400
+ qxtTabWidget->setTabMovementMode(QxtTabWidget::InPlaceMovement);
+ #endif
+ \endcode
+
+ \sa QXT_VERSION_STR, qxtVersion()
+ */
+
+/*!
+ \macro QXT_VERSION_STR
+ \relates <QxtGlobal>
+
+ This macro expands to a string that specifies Qxt's version number
+ (for example, "0.4.0"). This is the version against which the
+ application is compiled.
+
+ \sa qxtVersion(), QXT_VERSION
+ */
+
+/*!
+ \relates <QxtGlobal>
+
+ Returns the version number of Qxt at run-time as a string (for
+ example, "0.4.0"). This may be a different version than the
+ version the application was compiled against.
+
+ \sa QXT_VERSION_STR
+ */
+const char * qxtVersion()
+{
+ return QXT_VERSION_STR;
+}
+
+/*!
+\headerfile <QxtPimpl>
+\title The Qxt private implementation
+\inmodule QxtCore
+
+\brief The <QxtPimpl> header provides tools for hiding
+details of a class.
+
+Application code generally doesn't have to be concerned about hiding its
+implementation details, but when writing library code it is important to
+maintain a constant interface, both source and binary. Maintaining a constant
+source interface is easy enough, but keeping the binary interface constant
+means moving implementation details into a private class. The PIMPL, or
+d-pointer, idiom is a common method of implementing this separation. QxtPimpl
+offers a convenient way to connect the public and private sides of your class.
+
+\section1 Getting Started
+Before you declare the public class, you need to make a forward declaration
+of the private class. The private class must have the same name as the public
+class, followed by the word Private. For example, a class named MyTest would
+declare the private class with:
+\code
+class MyTestPrivate;
+\endcode
+
+\section1 The Public Class
+Generally, you shouldn't keep any data members in the public class without a
+good reason. Functions that are part of the public interface should be declared
+in the public class, and functions that need to be available to subclasses (for
+calling or overriding) should be in the protected section of the public class.
+To connect the private class to the public class, include the
+QXT_DECLARE_PRIVATE macro in the private section of the public class. In the
+example above, the private class is connected as follows:
+\code
+private:
+ QXT_DECLARE_PRIVATE(MyTest)
+\endcode
+
+Additionally, you must include the QXT_INIT_PRIVATE macro in the public class's
+constructor. Continuing with the MyTest example, your constructor might look
+like this:
+\code
+MyTest::MyTest() {
+ // initialization
+ QXT_INIT_PRIVATE(MyTest);
+}
+\endcode
+
+\section1 The Private Class
+As mentioned above, data members should usually be kept in the private class.
+This allows the memory layout of the private class to change without breaking
+binary compatibility for the public class. Functions that exist only as
+implementation details, or functions that need access to private data members,
+should be implemented here.
+
+To define the private class, inherit from the template QxtPrivate class, and
+include the QXT_DECLARE_PUBLIC macro in its public section. The template
+parameter should be the name of the public class. For example:
+\code
+class MyTestPrivate : public QxtPrivate<MyTest> {
+public:
+ MyTestPrivate();
+ QXT_DECLARE_PUBLIC(MyTest)
+};
+\endcode
+
+\section1 Accessing Private Members
+Use the qxt_d() function (actually a function-like object) from functions in
+the public class to access the private class. Similarly, functions in the
+private class can invoke functions in the public class by using the qxt_p()
+function (this one's actually a function).
+
+For example, assume that MyTest has methods named getFoobar and doBaz(),
+and MyTestPrivate has a member named foobar and a method named doQuux().
+The code might resemble this example:
+\code
+int MyTest::getFoobar() {
+ return qxt_d().foobar;
+}
+
+void MyTestPrivate::doQuux() {
+ qxt_p().doBaz(foobar);
+}
+\endcode
+*/
+
+/*!
+ * \macro QXT_DECLARE_PRIVATE(PUB)
+ * \relates <QxtPimpl>
+ * Declares that a public class has a related private class.
+ *
+ * This shuold be put in the private section of the public class. The
+ * parameter \a PUB must be the name of the public class.
+ */
+
+/*!
+ * \macro QXT_DECLARE_PUBLIC(PUB)
+ * \relates <QxtPimpl>
+ * Declares that a private class has a related public class named \a PUB.
+ *
+ * This may be put anywhere in the declaration of the private class. The parameter is the name of the public class.
+ */
+
+/*!
+ * \macro QXT_INIT_PRIVATE(PUB)
+ * \relates <QxtPimpl>
+ * Initializes resources owned by the private class.
+ *
+ * This should be called from the public class's constructor,
+ * before qxt_d() is used for the first time. The parameter \a PUB must be
+ * the name of the public class.
+ */
+
+/*!
+ * \macro QXT_D(PUB)
+ * \relates <QxtPimpl>
+ * Returns a reference in the current scope named "d" to the private class
+ * associated with the public class \a PUB.
+ *
+ * This function is only available in a class using QXT_DECLARE_PRIVATE().
+ */
+
+/*!
+ * \macro QXT_P(PUB)
+ * \relates <QxtPimpl>
+ * Creates a reference in the current scope named "q" to the public class
+ * named \a PUB.
+ *
+ * This macro only works in a class using QXT_DECLARE_PUBLIC().
+ */
+
+/*!
+ * \fn QxtPrivate<PUB>& PUB::qxt_d()
+ * \relates <QxtPimpl>
+ * Returns a reference to the private class.
+ *
+ * This function is only available in a class using \a QXT_DECLARE_PRIVATE.
+ */
+
+/*!
+ * \fn const QxtPrivate<PUB>& PUB::qxt_d() const
+ * \relates <QxtPimpl>
+ * Returns a const reference to the private class.
+ *
+ * This function is only available in a class using \a QXT_DECLARE_PRIVATE.
+ * This overload will be automatically used in const functions.
+ */
+
+/*!
+ * \fn PUB& QxtPrivate::qxt_p()
+ * \relates <QxtPimpl>
+ * Returns a reference to the public class.
+ *
+ * This function is only available in a class using QXT_DECLARE_PUBLIC().
+ */
+
+/*!
+ * \fn const PUB& QxtPrivate::qxt_p() const
+ * \relates <QxtPimpl>
+ * Returns a const reference to the public class.
+ *
+ * This function is only available in a class using QXT_DECLARE_PUBLIC().
+ * This overload will be automatically used in const functions.
+ */
diff --git a/tools/qxtglobalshortcut/qxtglobal.h b/tools/qxtglobalshortcut/qxtglobal.h
new file mode 100644
index 0000000..7d5abfb
--- /dev/null
+++ b/tools/qxtglobalshortcut/qxtglobal.h
@@ -0,0 +1,233 @@
+
+/****************************************************************************
+** Copyright (c) 2006 - 2011, the LibQxt project.
+** See the Qxt AUTHORS file for a list of authors and copyright holders.
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** * Neither the name of the LibQxt project nor the
+** names of its contributors may be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+** DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
+** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+**
+** <http://libqxt.org> <foundation@libqxt.org>
+*****************************************************************************/
+
+#ifndef QXTGLOBAL_H
+#define QXTGLOBAL_H
+
+#include <QtGlobal>
+
+#define QXT_VERSION 0x000700
+#define QXT_VERSION_STR "0.7.0"
+
+//--------------------------global macros------------------------------
+
+#ifndef QXT_NO_MACROS
+
+#ifndef _countof
+#define _countof(x) (sizeof(x)/sizeof(*x))
+#endif
+
+#endif // QXT_NO_MACROS
+
+//--------------------------export macros------------------------------
+
+#define QXT_DLLEXPORT DO_NOT_USE_THIS_ANYMORE
+
+#if !defined(QXT_STATIC) && !defined(QXT_DOXYGEN_RUN)
+# if defined(BUILD_QXT_CORE)
+# define QXT_CORE_EXPORT Q_DECL_EXPORT
+# else
+# define QXT_CORE_EXPORT Q_DECL_IMPORT
+# endif
+#else
+# define QXT_CORE_EXPORT
+#endif // BUILD_QXT_CORE
+
+#if !defined(QXT_STATIC) && !defined(QXT_DOXYGEN_RUN)
+# if defined(BUILD_QXT_GUI)
+# define QXT_GUI_EXPORT Q_DECL_EXPORT
+# else
+# define QXT_GUI_EXPORT Q_DECL_IMPORT
+# endif
+#else
+# define QXT_GUI_EXPORT
+#endif // BUILD_QXT_GUI
+
+#if !defined(QXT_STATIC) && !defined(QXT_DOXYGEN_RUN)
+# if defined(BUILD_QXT_NETWORK)
+# define QXT_NETWORK_EXPORT Q_DECL_EXPORT
+# else
+# define QXT_NETWORK_EXPORT Q_DECL_IMPORT
+# endif
+#else
+# define QXT_NETWORK_EXPORT
+#endif // BUILD_QXT_NETWORK
+
+#if !defined(QXT_STATIC) && !defined(QXT_DOXYGEN_RUN)
+# if defined(BUILD_QXT_SQL)
+# define QXT_SQL_EXPORT Q_DECL_EXPORT
+# else
+# define QXT_SQL_EXPORT Q_DECL_IMPORT
+# endif
+#else
+# define QXT_SQL_EXPORT
+#endif // BUILD_QXT_SQL
+
+#if !defined(QXT_STATIC) && !defined(QXT_DOXYGEN_RUN)
+# if defined(BUILD_QXT_WEB)
+# define QXT_WEB_EXPORT Q_DECL_EXPORT
+# else
+# define QXT_WEB_EXPORT Q_DECL_IMPORT
+# endif
+#else
+# define QXT_WEB_EXPORT
+#endif // BUILD_QXT_WEB
+
+#if !defined(QXT_STATIC) && !defined(QXT_DOXYGEN_RUN)
+# if defined(BUILD_QXT_BERKELEY)
+# define QXT_BERKELEY_EXPORT Q_DECL_EXPORT
+# else
+# define QXT_BERKELEY_EXPORT Q_DECL_IMPORT
+# endif
+#else
+# define QXT_BERKELEY_EXPORT
+#endif // BUILD_QXT_BERKELEY
+
+#if !defined(QXT_STATIC) && !defined(QXT_DOXYGEN_RUN)
+# if defined(BUILD_QXT_ZEROCONF)
+# define QXT_ZEROCONF_EXPORT Q_DECL_EXPORT
+# else
+# define QXT_ZEROCONF_EXPORT Q_DECL_IMPORT
+# endif
+#else
+# define QXT_ZEROCONF_EXPORT
+#endif // QXT_ZEROCONF_EXPORT
+
+#if defined(BUILD_QXT_CORE) || defined(BUILD_QXT_GUI) || defined(BUILD_QXT_SQL) || defined(BUILD_QXT_NETWORK) || defined(BUILD_QXT_WEB) || defined(BUILD_QXT_BERKELEY) || defined(BUILD_QXT_ZEROCONF)
+# define BUILD_QXT
+#endif
+
+QXT_CORE_EXPORT const char* qxtVersion();
+
+#ifndef QT_BEGIN_NAMESPACE
+#define QT_BEGIN_NAMESPACE
+#endif
+
+#ifndef QT_END_NAMESPACE
+#define QT_END_NAMESPACE
+#endif
+
+#ifndef QT_FORWARD_DECLARE_CLASS
+#define QT_FORWARD_DECLARE_CLASS(Class) class Class;
+#endif
+
+/****************************************************************************
+** This file is derived from code bearing the following notice:
+** The sole author of this file, Adam Higerd, has explicitly disclaimed all
+** copyright interest and protection for the content within. This file has
+** been placed in the public domain according to United States copyright
+** statute and case law. In jurisdictions where this public domain dedication
+** is not legally recognized, anyone who receives a copy of this file is
+** permitted to use, modify, duplicate, and redistribute this file, in whole
+** or in part, with no restrictions or conditions. In these jurisdictions,
+** this file shall be copyright (C) 2006-2008 by Adam Higerd.
+****************************************************************************/
+
+#define QXT_DECLARE_PRIVATE(PUB) friend class PUB##Private; QxtPrivateInterface<PUB, PUB##Private> qxt_d;
+#define QXT_DECLARE_PUBLIC(PUB) friend class PUB;
+#define QXT_INIT_PRIVATE(PUB) qxt_d.setPublic(this);
+#define QXT_D(PUB) PUB##Private& d = qxt_d()
+#define QXT_P(PUB) PUB& p = qxt_p()
+
+template <typename PUB>
+class QxtPrivate
+{
+public:
+ virtual ~QxtPrivate()
+ {}
+ inline void QXT_setPublic(PUB* pub)
+ {
+ qxt_p_ptr = pub;
+ }
+
+protected:
+ inline PUB& qxt_p()
+ {
+ return *qxt_p_ptr;
+ }
+ inline const PUB& qxt_p() const
+ {
+ return *qxt_p_ptr;
+ }
+ inline PUB* qxt_ptr()
+ {
+ return qxt_p_ptr;
+ }
+ inline const PUB* qxt_ptr() const
+ {
+ return qxt_p_ptr;
+ }
+
+private:
+ PUB* qxt_p_ptr;
+};
+
+template <typename PUB, typename PVT>
+class QxtPrivateInterface
+{
+ friend class QxtPrivate<PUB>;
+public:
+ QxtPrivateInterface()
+ {
+ pvt = new PVT;
+ }
+ ~QxtPrivateInterface()
+ {
+ delete pvt;
+ }
+
+ inline void setPublic(PUB* pub)
+ {
+ pvt->QXT_setPublic(pub);
+ }
+ inline PVT& operator()()
+ {
+ return *static_cast<PVT*>(pvt);
+ }
+ inline const PVT& operator()() const
+ {
+ return *static_cast<PVT*>(pvt);
+ }
+ inline PVT * operator->()
+ {
+ return static_cast<PVT*>(pvt);
+ }
+ inline const PVT * operator->() const
+ {
+ return static_cast<PVT*>(pvt);
+ }
+private:
+ QxtPrivateInterface(const QxtPrivateInterface&) { }
+ QxtPrivateInterface& operator=(const QxtPrivateInterface&) { }
+ QxtPrivate<PUB>* pvt;
+};
+
+#endif // QXT_GLOBAL
diff --git a/tools/qxtglobalshortcut/qxtglobalshortcut.cpp b/tools/qxtglobalshortcut/qxtglobalshortcut.cpp
new file mode 100644
index 0000000..e74d21d
--- /dev/null
+++ b/tools/qxtglobalshortcut/qxtglobalshortcut.cpp
@@ -0,0 +1,212 @@
+#include "qxtglobalshortcut.h"
+/****************************************************************************
+** Copyright (c) 2006 - 2011, the LibQxt project.
+** See the Qxt AUTHORS file for a list of authors and copyright holders.
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** * Neither the name of the LibQxt project nor the
+** names of its contributors may be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+** DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
+** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+**
+** <http://libqxt.org> <foundation@libqxt.org>
+*****************************************************************************/
+
+#include "qxtglobalshortcut_p.h"
+#include <QAbstractEventDispatcher>
+#include <QtDebug>
+
+#ifndef Q_WS_MAC
+int QxtGlobalShortcutPrivate::ref = 0;
+#endif // Q_WS_MAC
+QHash<QPair<quint32, quint32>, QxtGlobalShortcut*> QxtGlobalShortcutPrivate::shortcuts;
+
+QxtGlobalShortcutPrivate::QxtGlobalShortcutPrivate() : enabled(true), key(Qt::Key(0)), mods(Qt::NoModifier)
+{
+#ifndef Q_WS_MAC
+ if (ref == 0) {
+ QAbstractEventDispatcher::instance()->installNativeEventFilter(this);
+ }
+ ++ref;
+#endif // Q_WS_MAC
+}
+
+QxtGlobalShortcutPrivate::~QxtGlobalShortcutPrivate()
+{
+#ifndef Q_WS_MAC
+ --ref;
+ if (ref == 0) {
+ QAbstractEventDispatcher *ed = QAbstractEventDispatcher::instance();
+ if (ed != 0) {
+ ed->removeNativeEventFilter(this);
+ }
+ }
+#endif // Q_WS_MAC
+}
+
+bool QxtGlobalShortcutPrivate::setShortcut(const QKeySequence& shortcut)
+{
+ Qt::KeyboardModifiers allMods = Qt::ShiftModifier | Qt::ControlModifier | Qt::AltModifier | Qt::MetaModifier;
+ key = shortcut.isEmpty() ? Qt::Key(0) : Qt::Key((shortcut[0] ^ allMods) & shortcut[0]);
+ mods = shortcut.isEmpty() ? Qt::KeyboardModifiers(0) : Qt::KeyboardModifiers(shortcut[0] & allMods);
+ const quint32 nativeKey = nativeKeycode(key);
+ const quint32 nativeMods = nativeModifiers(mods);
+ const bool res = registerShortcut(nativeKey, nativeMods);
+ if (res)
+ shortcuts.insert(qMakePair(nativeKey, nativeMods), &qxt_p());
+ else
+ qWarning() << "QxtGlobalShortcut failed to register:" << QKeySequence(key + mods).toString();
+ return res;
+}
+
+bool QxtGlobalShortcutPrivate::unsetShortcut()
+{
+ bool res = false;
+ const quint32 nativeKey = nativeKeycode(key);
+ const quint32 nativeMods = nativeModifiers(mods);
+ if (shortcuts.value(qMakePair(nativeKey, nativeMods)) == &qxt_p())
+ res = unregisterShortcut(nativeKey, nativeMods);
+ if (res)
+ shortcuts.remove(qMakePair(nativeKey, nativeMods));
+ else
+ qWarning() << "QxtGlobalShortcut failed to unregister:" << QKeySequence(key + mods).toString();
+ key = Qt::Key(0);
+ mods = Qt::KeyboardModifiers(0);
+ return res;
+}
+
+void QxtGlobalShortcutPrivate::activateShortcut(quint32 nativeKey, quint32 nativeMods)
+{
+ QxtGlobalShortcut* shortcut = shortcuts.value(qMakePair(nativeKey, nativeMods));
+ if (shortcut && shortcut->isEnabled())
+ emit shortcut->activated();
+}
+
+/*!
+ \class QxtGlobalShortcut
+ \inmodule QxtWidgets
+ \brief The QxtGlobalShortcut class provides a global shortcut aka "hotkey".
+
+ A global shortcut triggers even if the application is not active. This
+ makes it easy to implement applications that react to certain shortcuts
+ still if some other application is active or if the application is for
+ example minimized to the system tray.
+
+ Example usage:
+ \code
+ QxtGlobalShortcut* shortcut = new QxtGlobalShortcut(window);
+ connect(shortcut, SIGNAL(activated()), window, SLOT(toggleVisibility()));
+ shortcut->setShortcut(QKeySequence("Ctrl+Shift+F12"));
+ \endcode
+
+ \bold {Note:} Since Qxt 0.6 QxtGlobalShortcut no more requires QxtApplication.
+ */
+
+/*!
+ \fn QxtGlobalShortcut::activated()
+
+ This signal is emitted when the user types the shortcut's key sequence.
+
+ \sa shortcut
+ */
+
+/*!
+ Constructs a new QxtGlobalShortcut with \a parent.
+ */
+QxtGlobalShortcut::QxtGlobalShortcut(QObject* parent)
+ : QObject(parent)
+{
+ QXT_INIT_PRIVATE(QxtGlobalShortcut);
+}
+
+/*!
+ Constructs a new QxtGlobalShortcut with \a shortcut and \a parent.
+ */
+QxtGlobalShortcut::QxtGlobalShortcut(const QKeySequence& shortcut, QObject* parent)
+ : QObject(parent)
+{
+ QXT_INIT_PRIVATE(QxtGlobalShortcut);
+ setShortcut(shortcut);
+}
+
+/*!
+ Destructs the QxtGlobalShortcut.
+ */
+QxtGlobalShortcut::~QxtGlobalShortcut()
+{
+ if (qxt_d().key != 0)
+ qxt_d().unsetShortcut();
+}
+
+/*!
+ \property QxtGlobalShortcut::shortcut
+ \brief the shortcut key sequence
+
+ \bold {Note:} Notice that corresponding key press and release events are not
+ delivered for registered global shortcuts even if they are disabled.
+ Also, comma separated key sequences are not supported.
+ Only the first part is used:
+
+ \code
+ qxtShortcut->setShortcut(QKeySequence("Ctrl+Alt+A,Ctrl+Alt+B"));
+ Q_ASSERT(qxtShortcut->shortcut() == QKeySequence("Ctrl+Alt+A"));
+ \endcode
+ */
+QKeySequence QxtGlobalShortcut::shortcut() const
+{
+ return QKeySequence(qxt_d().key | qxt_d().mods);
+}
+
+bool QxtGlobalShortcut::setShortcut(const QKeySequence& shortcut)
+{
+ if (qxt_d().key != 0)
+ qxt_d().unsetShortcut();
+ return qxt_d().setShortcut(shortcut);
+}
+
+/*!
+ \property QxtGlobalShortcut::enabled
+ \brief whether the shortcut is enabled
+
+ A disabled shortcut does not get activated.
+
+ The default value is \c true.
+
+ \sa setDisabled()
+ */
+bool QxtGlobalShortcut::isEnabled() const
+{
+ return qxt_d().enabled;
+}
+
+void QxtGlobalShortcut::setEnabled(bool enabled)
+{
+ qxt_d().enabled = enabled;
+}
+
+/*!
+ Sets the shortcut \a disabled.
+
+ \sa enabled
+ */
+void QxtGlobalShortcut::setDisabled(bool disabled)
+{
+ qxt_d().enabled = !disabled;
+}
diff --git a/tools/qxtglobalshortcut/qxtglobalshortcut.h b/tools/qxtglobalshortcut/qxtglobalshortcut.h
new file mode 100644
index 0000000..f3083f4
--- /dev/null
+++ b/tools/qxtglobalshortcut/qxtglobalshortcut.h
@@ -0,0 +1,64 @@
+#ifndef QXTGLOBALSHORTCUT_H
+/****************************************************************************
+** Copyright (c) 2006 - 2011, the LibQxt project.
+** See the Qxt AUTHORS file for a list of authors and copyright holders.
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** * Neither the name of the LibQxt project nor the
+** names of its contributors may be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+** DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
+** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+**
+** <http://libqxt.org> <foundation@libqxt.org>
+*****************************************************************************/
+
+#define QXTGLOBALSHORTCUT_H
+
+#include "qxtglobal.h"
+#include <QObject>
+#include <QKeySequence>
+class QxtGlobalShortcutPrivate;
+
+class QxtGlobalShortcut : public QObject
+{
+ Q_OBJECT
+ QXT_DECLARE_PRIVATE(QxtGlobalShortcut)
+ Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled)
+ Q_PROPERTY(QKeySequence shortcut READ shortcut WRITE setShortcut)
+
+public:
+ explicit QxtGlobalShortcut(QObject* parent = 0);
+ explicit QxtGlobalShortcut(const QKeySequence& shortcut, QObject* parent = 0);
+ virtual ~QxtGlobalShortcut();
+
+ QKeySequence shortcut() const;
+ bool setShortcut(const QKeySequence& shortcut);
+
+ bool isEnabled() const;
+
+public Q_SLOTS:
+ void setEnabled(bool enabled = true);
+ void setDisabled(bool disabled = true);
+
+Q_SIGNALS:
+ void activated();
+};
+
+#endif // QXTGLOBALSHORTCUT_H
diff --git a/tools/qxtglobalshortcut/qxtglobalshortcut.pri b/tools/qxtglobalshortcut/qxtglobalshortcut.pri
new file mode 100644
index 0000000..2b34277
--- /dev/null
+++ b/tools/qxtglobalshortcut/qxtglobalshortcut.pri
@@ -0,0 +1,17 @@
+!qws:!symbian {
+ HEADERS += $$PWD/qxtglobalshortcut.h
+ HEADERS += $$PWD/qxtglobalshortcut_p.h
+
+ SOURCES += $$PWD/qxtglobalshortcut.cpp
+
+ unix:!macx {
+ SOURCES += $$PWD/qxtglobalshortcut_x11.cpp
+ }
+ macx {
+ SOURCES += $$PWD/qxtglobalshortcut_mac.cpp
+ }
+ win32 {
+ SOURCES += $$PWD/qxtglobalshortcut_win.cpp
+ }
+}
+
diff --git a/tools/qxtglobalshortcut/qxtglobalshortcut_mac.cpp b/tools/qxtglobalshortcut/qxtglobalshortcut_mac.cpp
new file mode 100644
index 0000000..be2e632
--- /dev/null
+++ b/tools/qxtglobalshortcut/qxtglobalshortcut_mac.cpp
@@ -0,0 +1,258 @@
+#include <Carbon/Carbon.h>
+/****************************************************************************
+** Copyright (c) 2006 - 2011, the LibQxt project.
+** See the Qxt AUTHORS file for a list of authors and copyright holders.
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** * Neither the name of the LibQxt project nor the
+** names of its contributors may be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+** DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
+** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+**
+** <http://libqxt.org> <foundation@libqxt.org>
+*****************************************************************************/
+
+#include "qxtglobalshortcut_p.h"
+#include <QMap>
+#include <QHash>
+#include <QtDebug>
+#include <QApplication>
+
+typedef QPair<uint, uint> Identifier;
+static QMap<quint32, EventHotKeyRef> keyRefs;
+static QHash<Identifier, quint32> keyIDs;
+static quint32 hotKeySerial = 0;
+static bool qxt_mac_handler_installed = false;
+
+OSStatus qxt_mac_handle_hot_key(EventHandlerCallRef nextHandler, EventRef event, void* data)
+{
+ Q_UNUSED(nextHandler);
+ Q_UNUSED(data);
+ if (GetEventClass(event) == kEventClassKeyboard && GetEventKind(event) == kEventHotKeyPressed)
+ {
+ EventHotKeyID keyID;
+ GetEventParameter(event, kEventParamDirectObject, typeEventHotKeyID, NULL, sizeof(keyID), NULL, &keyID);
+ Identifier id = keyIDs.key(keyID.id);
+ QxtGlobalShortcutPrivate::activateShortcut(id.second, id.first);
+ }
+ return noErr;
+}
+
+quint32 QxtGlobalShortcutPrivate::nativeModifiers(Qt::KeyboardModifiers modifiers)
+{
+ quint32 native = 0;
+ if (modifiers & Qt::ShiftModifier)
+ native |= shiftKey;
+ if (modifiers & Qt::ControlModifier)
+ native |= cmdKey;
+ if (modifiers & Qt::AltModifier)
+ native |= optionKey;
+ if (modifiers & Qt::MetaModifier)
+ native |= controlKey;
+ if (modifiers & Qt::KeypadModifier)
+ native |= kEventKeyModifierNumLockMask;
+ return native;
+}
+
+quint32 QxtGlobalShortcutPrivate::nativeKeycode(Qt::Key key)
+{
+ UTF16Char ch;
+ // Constants found in NSEvent.h from AppKit.framework
+ switch (key)
+ {
+ case Qt::Key_Return:
+ return kVK_Return;
+ case Qt::Key_Enter:
+ return kVK_ANSI_KeypadEnter;
+ case Qt::Key_Tab:
+ return kVK_Tab;
+ case Qt::Key_Space:
+ return kVK_Space;
+ case Qt::Key_Backspace:
+ return kVK_Delete;
+ case Qt::Key_Control:
+ return kVK_Command;
+ case Qt::Key_Shift:
+ return kVK_Shift;
+ case Qt::Key_CapsLock:
+ return kVK_CapsLock;
+ case Qt::Key_Option:
+ return kVK_Option;
+ case Qt::Key_Meta:
+ return kVK_Control;
+ case Qt::Key_F17:
+ return kVK_F17;
+ case Qt::Key_VolumeUp:
+ return kVK_VolumeUp;
+ case Qt::Key_VolumeDown:
+ return kVK_VolumeDown;
+ case Qt::Key_F18:
+ return kVK_F18;
+ case Qt::Key_F19:
+ return kVK_F19;
+ case Qt::Key_F20:
+ return kVK_F20;
+ case Qt::Key_F5:
+ return kVK_F5;
+ case Qt::Key_F6:
+ return kVK_F6;
+ case Qt::Key_F7:
+ return kVK_F7;
+ case Qt::Key_F3:
+ return kVK_F3;
+ case Qt::Key_F8:
+ return kVK_F8;
+ case Qt::Key_F9:
+ return kVK_F9;
+ case Qt::Key_F11:
+ return kVK_F11;
+ case Qt::Key_F13:
+ return kVK_F13;
+ case Qt::Key_F16:
+ return kVK_F16;
+ case Qt::Key_F14:
+ return kVK_F14;
+ case Qt::Key_F10:
+ return kVK_F10;
+ case Qt::Key_F12:
+ return kVK_F12;
+ case Qt::Key_F15:
+ return kVK_F15;
+ case Qt::Key_Help:
+ return kVK_Help;
+ case Qt::Key_Home:
+ return kVK_Home;
+ case Qt::Key_PageUp:
+ return kVK_PageUp;
+ case Qt::Key_Delete:
+ return kVK_ForwardDelete;
+ case Qt::Key_F4:
+ return kVK_F4;
+ case Qt::Key_End:
+ return kVK_End;
+ case Qt::Key_F2:
+ return kVK_F2;
+ case Qt::Key_PageDown:
+ return kVK_PageDown;
+ case Qt::Key_F1:
+ return kVK_F1;
+ case Qt::Key_Left:
+ return kVK_LeftArrow;
+ case Qt::Key_Right:
+ return kVK_RightArrow;
+ case Qt::Key_Down:
+ return kVK_DownArrow;
+ case Qt::Key_Up:
+ return kVK_UpArrow;
+ default:
+ ;
+ }
+
+ if (key == Qt::Key_Escape) ch = 27;
+ else if (key == Qt::Key_Return) ch = 13;
+ else if (key == Qt::Key_Enter) ch = 3;
+ else if (key == Qt::Key_Tab) ch = 9;
+ else ch = key;
+
+ CFDataRef currentLayoutData;
+ TISInputSourceRef currentKeyboard = TISCopyCurrentKeyboardInputSource();
+
+ if (currentKeyboard == NULL)
+ return 0;
+
+ currentLayoutData = (CFDataRef)TISGetInputSourceProperty(currentKeyboard, kTISPropertyUnicodeKeyLayoutData);
+ CFRelease(currentKeyboard);
+ if (currentLayoutData == NULL)
+ return 0;
+
+ UCKeyboardLayout* header = (UCKeyboardLayout*)CFDataGetBytePtr(currentLayoutData);
+ UCKeyboardTypeHeader* table = header->keyboardTypeList;
+
+ uint8_t *data = (uint8_t*)header;
+ // God, would a little documentation for this shit kill you...
+ for (quint32 i=0; i < header->keyboardTypeCount; i++)
+ {
+ UCKeyStateRecordsIndex* stateRec = 0;
+ if (table[i].keyStateRecordsIndexOffset != 0)
+ {
+ stateRec = reinterpret_cast<UCKeyStateRecordsIndex*>(data + table[i].keyStateRecordsIndexOffset);
+ if (stateRec->keyStateRecordsIndexFormat != kUCKeyStateRecordsIndexFormat) stateRec = 0;
+ }
+
+ UCKeyToCharTableIndex* charTable = reinterpret_cast<UCKeyToCharTableIndex*>(data + table[i].keyToCharTableIndexOffset);
+ if (charTable->keyToCharTableIndexFormat != kUCKeyToCharTableIndexFormat) continue;
+
+ for (quint32 j=0; j < charTable->keyToCharTableCount; j++)
+ {
+ UCKeyOutput* keyToChar = reinterpret_cast<UCKeyOutput*>(data + charTable->keyToCharTableOffsets[j]);
+ for (quint32 k=0; k < charTable->keyToCharTableSize; k++)
+ {
+ if (keyToChar[k] & kUCKeyOutputTestForIndexMask)
+ {
+ long idx = keyToChar[k] & kUCKeyOutputGetIndexMask;
+ if (stateRec && idx < stateRec->keyStateRecordCount)
+ {
+ UCKeyStateRecord* rec = reinterpret_cast<UCKeyStateRecord*>(data + stateRec->keyStateRecordOffsets[idx]);
+ if (rec->stateZeroCharData == ch) return k;
+ }
+ }
+ else if (!(keyToChar[k] & kUCKeyOutputSequenceIndexMask) && keyToChar[k] < 0xFFFE)
+ {
+ if (keyToChar[k] == ch) return k;
+ }
+ } // for k
+ } // for j
+ } // for i
+ return 0;
+}
+
+bool QxtGlobalShortcutPrivate::registerShortcut(quint32 nativeKey, quint32 nativeMods)
+{
+ if (!qxt_mac_handler_installed)
+ {
+ EventTypeSpec t;
+ t.eventClass = kEventClassKeyboard;
+ t.eventKind = kEventHotKeyPressed;
+ InstallApplicationEventHandler(&qxt_mac_handle_hot_key, 1, &t, NULL, NULL);
+ }
+
+ EventHotKeyID keyID;
+ keyID.signature = 'cute';
+ keyID.id = ++hotKeySerial;
+
+ EventHotKeyRef ref = 0;
+ bool rv = !RegisterEventHotKey(nativeKey, nativeMods, keyID, GetApplicationEventTarget(), 0, &ref);
+ if (rv)
+ {
+ keyIDs.insert(Identifier(nativeMods, nativeKey), keyID.id);
+ keyRefs.insert(keyID.id, ref);
+ }
+ return rv;
+}
+
+bool QxtGlobalShortcutPrivate::unregisterShortcut(quint32 nativeKey, quint32 nativeMods)
+{
+ Identifier id(nativeMods, nativeKey);
+ if (!keyIDs.contains(id)) return false;
+
+ EventHotKeyRef ref = keyRefs.take(keyIDs[id]);
+ keyIDs.remove(id);
+ return !UnregisterEventHotKey(ref);
+}
diff --git a/tools/qxtglobalshortcut/qxtglobalshortcut_p.h b/tools/qxtglobalshortcut/qxtglobalshortcut_p.h
new file mode 100644
index 0000000..732c41e
--- /dev/null
+++ b/tools/qxtglobalshortcut/qxtglobalshortcut_p.h
@@ -0,0 +1,74 @@
+#ifndef QXTGLOBALSHORTCUT_P_H
+/****************************************************************************
+** Copyright (c) 2006 - 2011, the LibQxt project.
+** See the Qxt AUTHORS file for a list of authors and copyright holders.
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** * Neither the name of the LibQxt project nor the
+** names of its contributors may be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+** DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
+** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+**
+** <http://libqxt.org> <foundation@libqxt.org>
+*****************************************************************************/
+
+#define QXTGLOBALSHORTCUT_P_H
+
+#include "qxtglobalshortcut.h"
+#include <QAbstractEventDispatcher>
+#include <QKeySequence>
+#include <QHash>
+
+#include <QAbstractNativeEventFilter>
+
+class QxtGlobalShortcutPrivate : public QxtPrivate<QxtGlobalShortcut>
+ ,public QAbstractNativeEventFilter
+{
+public:
+ QXT_DECLARE_PUBLIC(QxtGlobalShortcut)
+ QxtGlobalShortcutPrivate();
+ ~QxtGlobalShortcutPrivate();
+
+ bool enabled;
+ Qt::Key key;
+ Qt::KeyboardModifiers mods;
+
+ bool setShortcut(const QKeySequence& shortcut);
+ bool unsetShortcut();
+
+ static bool error;
+#ifndef Q_WS_MAC
+ static int ref;
+ virtual bool nativeEventFilter(const QByteArray & eventType, void * message, long * result);
+#endif // Q_WS_MAC
+
+ static void activateShortcut(quint32 nativeKey, quint32 nativeMods);
+
+private:
+ static quint32 nativeKeycode(Qt::Key keycode);
+ static quint32 nativeModifiers(Qt::KeyboardModifiers modifiers);
+
+ static bool registerShortcut(quint32 nativeKey, quint32 nativeMods);
+ static bool unregisterShortcut(quint32 nativeKey, quint32 nativeMods);
+
+ static QHash<QPair<quint32, quint32>, QxtGlobalShortcut*> shortcuts;
+};
+
+#endif // QXTGLOBALSHORTCUT_P_H
diff --git a/tools/qxtglobalshortcut/qxtglobalshortcut_win.cpp b/tools/qxtglobalshortcut/qxtglobalshortcut_win.cpp
new file mode 100644
index 0000000..cf052d4
--- /dev/null
+++ b/tools/qxtglobalshortcut/qxtglobalshortcut_win.cpp
@@ -0,0 +1,247 @@
+#include "qxtglobalshortcut_p.h"
+/****************************************************************************
+** Copyright (c) 2006 - 2011, the LibQxt project.
+** See the Qxt AUTHORS file for a list of authors and copyright holders.
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** * Neither the name of the LibQxt project nor the
+** names of its contributors may be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+** DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
+** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+**
+** <http://libqxt.org> <foundation@libqxt.org>
+*****************************************************************************/
+
+#include <qt_windows.h>
+
+
+#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
+bool QxtGlobalShortcutPrivate::eventFilter(void* message)
+{
+#else
+bool QxtGlobalShortcutPrivate::nativeEventFilter(const QByteArray & eventType,
+ void * message, long * result)
+{
+ Q_UNUSED(eventType);
+ Q_UNUSED(result);
+#endif
+ MSG* msg = static_cast<MSG*>(message);
+ if (msg->message == WM_HOTKEY)
+ {
+ const quint32 keycode = HIWORD(msg->lParam);
+ const quint32 modifiers = LOWORD(msg->lParam);
+ activateShortcut(keycode, modifiers);
+ }
+ return false;
+}
+
+
+quint32 QxtGlobalShortcutPrivate::nativeModifiers(Qt::KeyboardModifiers modifiers)
+{
+ // MOD_ALT, MOD_CONTROL, (MOD_KEYUP), MOD_SHIFT, MOD_WIN
+ quint32 native = 0;
+ if (modifiers & Qt::ShiftModifier)
+ native |= MOD_SHIFT;
+ if (modifiers & Qt::ControlModifier)
+ native |= MOD_CONTROL;
+ if (modifiers & Qt::AltModifier)
+ native |= MOD_ALT;
+ if (modifiers & Qt::MetaModifier)
+ native |= MOD_WIN;
+ // TODO: resolve these?
+ //if (modifiers & Qt::KeypadModifier)
+ //if (modifiers & Qt::GroupSwitchModifier)
+ return native;
+}
+
+quint32 QxtGlobalShortcutPrivate::nativeKeycode(Qt::Key key)
+{
+ switch (key)
+ {
+ case Qt::Key_Escape:
+ return VK_ESCAPE;
+ case Qt::Key_Tab:
+ case Qt::Key_Backtab:
+ return VK_TAB;
+ case Qt::Key_Backspace:
+ return VK_BACK;
+ case Qt::Key_Return:
+ case Qt::Key_Enter:
+ return VK_RETURN;
+ case Qt::Key_Insert:
+ return VK_INSERT;
+ case Qt::Key_Delete:
+ return VK_DELETE;
+ case Qt::Key_Pause:
+ return VK_PAUSE;
+ case Qt::Key_Print:
+ return VK_PRINT;
+ case Qt::Key_Clear:
+ return VK_CLEAR;
+ case Qt::Key_Home:
+ return VK_HOME;
+ case Qt::Key_End:
+ return VK_END;
+ case Qt::Key_Left:
+ return VK_LEFT;
+ case Qt::Key_Up:
+ return VK_UP;
+ case Qt::Key_Right:
+ return VK_RIGHT;
+ case Qt::Key_Down:
+ return VK_DOWN;
+ case Qt::Key_PageUp:
+ return VK_PRIOR;
+ case Qt::Key_PageDown:
+ return VK_NEXT;
+ case Qt::Key_F1:
+ return VK_F1;
+ case Qt::Key_F2:
+ return VK_F2;
+ case Qt::Key_F3:
+ return VK_F3;
+ case Qt::Key_F4:
+ return VK_F4;
+ case Qt::Key_F5:
+ return VK_F5;
+ case Qt::Key_F6:
+ return VK_F6;
+ case Qt::Key_F7:
+ return VK_F7;
+ case Qt::Key_F8:
+ return VK_F8;
+ case Qt::Key_F9:
+ return VK_F9;
+ case Qt::Key_F10:
+ return VK_F10;
+ case Qt::Key_F11:
+ return VK_F11;
+ case Qt::Key_F12:
+ return VK_F12;
+ case Qt::Key_F13:
+ return VK_F13;
+ case Qt::Key_F14:
+ return VK_F14;
+ case Qt::Key_F15:
+ return VK_F15;
+ case Qt::Key_F16:
+ return VK_F16;
+ case Qt::Key_F17:
+ return VK_F17;
+ case Qt::Key_F18:
+ return VK_F18;
+ case Qt::Key_F19:
+ return VK_F19;
+ case Qt::Key_F20:
+ return VK_F20;
+ case Qt::Key_F21:
+ return VK_F21;
+ case Qt::Key_F22:
+ return VK_F22;
+ case Qt::Key_F23:
+ return VK_F23;
+ case Qt::Key_F24:
+ return VK_F24;
+ case Qt::Key_Space:
+ return VK_SPACE;
+ case Qt::Key_Asterisk:
+ return VK_MULTIPLY;
+ case Qt::Key_Plus:
+ return VK_ADD;
+ case Qt::Key_Comma:
+ return VK_SEPARATOR;
+ case Qt::Key_Minus:
+ return VK_SUBTRACT;
+ case Qt::Key_Slash:
+ return VK_DIVIDE;
+ case Qt::Key_MediaNext:
+ return VK_MEDIA_NEXT_TRACK;
+ case Qt::Key_MediaPrevious:
+ return VK_MEDIA_PREV_TRACK;
+ case Qt::Key_MediaPlay:
+ return VK_MEDIA_PLAY_PAUSE;
+ case Qt::Key_MediaStop:
+ return VK_MEDIA_STOP;
+ // couldn't find those in VK_*
+ //case Qt::Key_MediaLast:
+ //case Qt::Key_MediaRecord:
+ case Qt::Key_VolumeDown:
+ return VK_VOLUME_DOWN;
+ case Qt::Key_VolumeUp:
+ return VK_VOLUME_UP;
+ case Qt::Key_VolumeMute:
+ return VK_VOLUME_MUTE;
+
+ // numbers
+ case Qt::Key_0:
+ case Qt::Key_1:
+ case Qt::Key_2:
+ case Qt::Key_3:
+ case Qt::Key_4:
+ case Qt::Key_5:
+ case Qt::Key_6:
+ case Qt::Key_7:
+ case Qt::Key_8:
+ case Qt::Key_9:
+ return key;
+
+ // letters
+ case Qt::Key_A:
+ case Qt::Key_B:
+ case Qt::Key_C:
+ case Qt::Key_D:
+ case Qt::Key_E:
+ case Qt::Key_F:
+ case Qt::Key_G:
+ case Qt::Key_H:
+ case Qt::Key_I:
+ case Qt::Key_J:
+ case Qt::Key_K:
+ case Qt::Key_L:
+ case Qt::Key_M:
+ case Qt::Key_N:
+ case Qt::Key_O:
+ case Qt::Key_P:
+ case Qt::Key_Q:
+ case Qt::Key_R:
+ case Qt::Key_S:
+ case Qt::Key_T:
+ case Qt::Key_U:
+ case Qt::Key_V:
+ case Qt::Key_W:
+ case Qt::Key_X:
+ case Qt::Key_Y:
+ case Qt::Key_Z:
+ return key;
+
+ default:
+ return 0;
+ }
+}
+
+bool QxtGlobalShortcutPrivate::registerShortcut(quint32 nativeKey, quint32 nativeMods)
+{
+ return RegisterHotKey(0, nativeMods ^ nativeKey, nativeMods, nativeKey);
+}
+
+bool QxtGlobalShortcutPrivate::unregisterShortcut(quint32 nativeKey, quint32 nativeMods)
+{
+ return UnregisterHotKey(0, nativeMods ^ nativeKey);
+}
diff --git a/tools/qxtglobalshortcut/qxtglobalshortcut_x11.cpp b/tools/qxtglobalshortcut/qxtglobalshortcut_x11.cpp
new file mode 100644
index 0000000..a10c702
--- /dev/null
+++ b/tools/qxtglobalshortcut/qxtglobalshortcut_x11.cpp
@@ -0,0 +1,215 @@
+#include "qxtglobalshortcut_p.h"
+/****************************************************************************
+** Copyright (c) 2006 - 2011, the LibQxt project.
+** See the Qxt AUTHORS file for a list of authors and copyright holders.
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** * Neither the name of the LibQxt project nor the
+** names of its contributors may be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+** DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
+** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+**
+** <http://libqxt.org> <foundation@libqxt.org>
+*****************************************************************************/
+
+#include <QVector>
+#include <X11/Xlib.h>
+#include <QX11Info>
+#include <xcb/xcb.h>
+
+namespace {
+
+const QVector<quint32> maskModifiers = QVector<quint32>()
+ << 0 << Mod2Mask << LockMask << (Mod2Mask | LockMask);
+
+typedef int (*X11ErrorHandler)(Display *display, XErrorEvent *event);
+
+class QxtX11ErrorHandler {
+public:
+ static bool error;
+
+ static int qxtX11ErrorHandler(Display *display, XErrorEvent *event)
+ {
+ Q_UNUSED(display);
+ switch (event->error_code)
+ {
+ case BadAccess:
+ case BadValue:
+ case BadWindow:
+ if (event->request_code == 33 /* X_GrabKey */ ||
+ event->request_code == 34 /* X_UngrabKey */)
+ {
+ error = true;
+ //TODO:
+ //char errstr[256];
+ //XGetErrorText(dpy, err->error_code, errstr, 256);
+ }
+ }
+ return 0;
+ }
+
+ QxtX11ErrorHandler()
+ {
+ error = false;
+ m_previousErrorHandler = XSetErrorHandler(qxtX11ErrorHandler);
+ }
+
+ ~QxtX11ErrorHandler()
+ {
+ XSetErrorHandler(m_previousErrorHandler);
+ }
+
+private:
+ X11ErrorHandler m_previousErrorHandler;
+};
+
+bool QxtX11ErrorHandler::error = false;
+
+class QxtX11Data {
+public:
+ QxtX11Data()
+ {
+ m_display = QX11Info::display();
+ }
+
+ bool isValid()
+ {
+ return m_display != 0;
+ }
+
+ Display *display()
+ {
+ Q_ASSERT(isValid());
+ return m_display;
+ }
+
+ Window rootWindow()
+ {
+ return DefaultRootWindow(display());
+ }
+
+ bool grabKey(quint32 keycode, quint32 modifiers, Window window)
+ {
+ QxtX11ErrorHandler errorHandler;
+
+ for (int i = 0; !errorHandler.error && i < maskModifiers.size(); ++i) {
+ XGrabKey(display(), keycode, modifiers | maskModifiers[i], window, True,
+ GrabModeAsync, GrabModeAsync);
+ }
+
+ if (errorHandler.error) {
+ ungrabKey(keycode, modifiers, window);
+ return false;
+ }
+
+ return true;
+ }
+
+ bool ungrabKey(quint32 keycode, quint32 modifiers, Window window)
+ {
+ QxtX11ErrorHandler errorHandler;
+
+ foreach (quint32 maskMods, maskModifiers) {
+ XUngrabKey(display(), keycode, modifiers | maskMods, window);
+ }
+
+ return !errorHandler.error;
+ }
+
+private:
+ Display *m_display;
+};
+
+} // namespace
+
+bool QxtGlobalShortcutPrivate::nativeEventFilter(const QByteArray & eventType,
+ void *message, long *result)
+{
+ Q_UNUSED(result);
+
+ xcb_key_press_event_t *kev = 0;
+ if (eventType == "xcb_generic_event_t") {
+ xcb_generic_event_t *ev = static_cast<xcb_generic_event_t *>(message);
+ if ((ev->response_type & 127) == XCB_KEY_PRESS)
+ kev = static_cast<xcb_key_press_event_t *>(message);
+ }
+
+ if (kev != 0) {
+ unsigned int keycode = kev->detail;
+ unsigned int keystate = 0;
+ if(kev->state & XCB_MOD_MASK_1)
+ keystate |= Mod1Mask;
+ if(kev->state & XCB_MOD_MASK_CONTROL)
+ keystate |= ControlMask;
+ if(kev->state & XCB_MOD_MASK_4)
+ keystate |= Mod4Mask;
+ if(kev->state & XCB_MOD_MASK_SHIFT)
+ keystate |= ShiftMask;
+ activateShortcut(keycode,
+ // Mod1Mask == Alt, Mod4Mask == Meta
+ keystate & (ShiftMask | ControlMask | Mod1Mask | Mod4Mask));
+ }
+ return false;
+}
+
+quint32 QxtGlobalShortcutPrivate::nativeModifiers(Qt::KeyboardModifiers modifiers)
+{
+ // ShiftMask, LockMask, ControlMask, Mod1Mask, Mod2Mask, Mod3Mask, Mod4Mask, and Mod5Mask
+ quint32 native = 0;
+ if (modifiers & Qt::ShiftModifier)
+ native |= ShiftMask;
+ if (modifiers & Qt::ControlModifier)
+ native |= ControlMask;
+ if (modifiers & Qt::AltModifier)
+ native |= Mod1Mask;
+ if (modifiers & Qt::MetaModifier)
+ native |= Mod4Mask;
+
+ // TODO: resolve these?
+ //if (modifiers & Qt::MetaModifier)
+ //if (modifiers & Qt::KeypadModifier)
+ //if (modifiers & Qt::GroupSwitchModifier)
+ return native;
+}
+
+quint32 QxtGlobalShortcutPrivate::nativeKeycode(Qt::Key key)
+{
+ QxtX11Data x11;
+ if (!x11.isValid())
+ return 0;
+
+ KeySym keysym = XStringToKeysym(QKeySequence(key).toString().toLatin1().data());
+ if (keysym == NoSymbol)
+ keysym = static_cast<ushort>(key);
+
+ return XKeysymToKeycode(x11.display(), keysym);
+}
+
+bool QxtGlobalShortcutPrivate::registerShortcut(quint32 nativeKey, quint32 nativeMods)
+{
+ QxtX11Data x11;
+ return x11.isValid() && x11.grabKey(nativeKey, nativeMods, x11.rootWindow());
+}
+
+bool QxtGlobalShortcutPrivate::unregisterShortcut(quint32 nativeKey, quint32 nativeMods)
+{
+ QxtX11Data x11;
+ return x11.isValid() && x11.ungrabKey(nativeKey, nativeMods, x11.rootWindow());
+}

File Metadata

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

Event Timeline