mirror of
https://github.com/zealdocs/zeal.git
synced 2024-11-22 21:53:03 +03:00
Alt+Space hotkey, tray icon
This commit is contained in:
parent
f817f9375d
commit
88011d5009
@ -28,7 +28,7 @@ Do `tar -jxvf file.tar.bz2` in docsets directory to enable given docset.
|
||||
|
||||
## TODO
|
||||
|
||||
* Alt+Space / configurable hotkey for showing Zeal + tray icon
|
||||
* Configuration (customisable hotkey instead of hardcoded Alt+Space, remember window size, etc.)
|
||||
* Search enhancements - some ideas:
|
||||
1. Allow selecting subset of docsets to search in.
|
||||
2. Substring match in case current startswith matching doesn't return anything.
|
||||
|
@ -1,11 +1,84 @@
|
||||
#include "mainwindow.h"
|
||||
#include <QApplication>
|
||||
#include <QLocalSocket>
|
||||
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/keysym.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
void run_grabkey();
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QApplication a(argc, argv);
|
||||
MainWindow w;
|
||||
w.show();
|
||||
|
||||
return a.exec();
|
||||
if(argc > 1 && argv[1] == string("--grabkey")) {
|
||||
run_grabkey();
|
||||
return -1; // infinite loop - shouldn't terminate
|
||||
} else {
|
||||
// detect already running instance
|
||||
QLocalSocket socket;
|
||||
socket.connectToServer(serverName);
|
||||
if (socket.waitForConnected(500)) {
|
||||
cerr << "Already running. Terminating." << endl;
|
||||
return -1; // Exit already a process running
|
||||
}
|
||||
|
||||
QApplication a(argc, argv);
|
||||
MainWindow w;
|
||||
w.show();
|
||||
return a.exec();
|
||||
}
|
||||
}
|
||||
|
||||
void run_grabkey()
|
||||
{
|
||||
Display *display = XOpenDisplay(NULL);
|
||||
|
||||
unsigned int AltMask = 0;
|
||||
|
||||
XModifierKeymap *xmk = XGetModifierMapping(display);
|
||||
if(xmk) {
|
||||
KeyCode altKeyCode = XKeysymToKeycode(display, XK_Alt_L);
|
||||
KeyCode *c = xmk->modifiermap;
|
||||
int m, k;
|
||||
for(m = 0; m < 8; m++) {
|
||||
for(k = 0; k < xmk->max_keypermod; k++, c++)
|
||||
{
|
||||
if(*c == NoSymbol) {
|
||||
continue;
|
||||
}
|
||||
if(*c == altKeyCode) {
|
||||
AltMask = (1 << m);
|
||||
}
|
||||
}
|
||||
}
|
||||
XFreeModifiermap (xmk);
|
||||
}
|
||||
|
||||
if(AltMask == 0) {
|
||||
cout << "failed" << endl;
|
||||
} else {
|
||||
cout << "ok" << endl;
|
||||
}
|
||||
|
||||
KeyCode hotKey = XKeysymToKeycode(display, XStringToKeysym("space"));
|
||||
XGrabKey(display, hotKey, AnyModifier, DefaultRootWindow(display), True, GrabModeSync, GrabModeSync);
|
||||
|
||||
XEvent e;
|
||||
for(;;)
|
||||
{
|
||||
XNextEvent(display, &e);
|
||||
if(e.type == KeyPress){
|
||||
if(e.xkey.keycode == hotKey && e.xkey.state & AltMask)
|
||||
{
|
||||
cout << "1" << endl;
|
||||
XAllowEvents(display, AsyncKeyboard, e.xkey.time);
|
||||
} else {
|
||||
XAllowEvents(display, ReplayKeyboard, e.xkey.time);
|
||||
XFlush(display);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,12 +9,48 @@ using namespace std;
|
||||
|
||||
#include <QStandardPaths>
|
||||
#include <QMessageBox>
|
||||
#include <QSystemTrayIcon>
|
||||
#include <QLocalSocket>
|
||||
#include <QDir>
|
||||
|
||||
const QString serverName = "zeal_process_running";
|
||||
|
||||
MainWindow::MainWindow(QWidget *parent) :
|
||||
QMainWindow(parent),
|
||||
ui(new Ui::MainWindow)
|
||||
{
|
||||
// server for detecting already running instances
|
||||
localServer = new QLocalServer(this);
|
||||
connect(localServer, &QLocalServer::newConnection, [&]() {
|
||||
bringToFront();
|
||||
});
|
||||
QLocalServer::removeServer(serverName); // remove in case previous instance crashed
|
||||
localServer->listen(serverName);
|
||||
|
||||
// initialise icons
|
||||
setWindowIcon(QIcon::fromTheme("edit-find"));
|
||||
createTrayIcon();
|
||||
|
||||
// initialise key grabber
|
||||
keyGrabber.setParent(this);
|
||||
keyGrabber.start(qApp->applicationFilePath(), {"--grabkey"});
|
||||
connect(&keyGrabber, &QProcess::readyRead, [&]() {
|
||||
char buf[100];
|
||||
keyGrabber.readLine(buf, sizeof(buf));
|
||||
if(QString(buf) == "failed\n") {
|
||||
QMessageBox::warning(this, "grabkey process init failed",
|
||||
QString("Failed to grab keyboard - Alt+Space will not work."));
|
||||
}
|
||||
//first = false;
|
||||
if(QString(buf) == "1\n") {
|
||||
if(isVisible()) hide();
|
||||
else {
|
||||
bringToFront();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// initialise docsets
|
||||
auto dataLocation = QStandardPaths::writableLocation(QStandardPaths::DataLocation);
|
||||
auto dataDir = QDir(dataLocation);
|
||||
if(!dataDir.cd("docsets")) {
|
||||
@ -28,6 +64,8 @@ MainWindow::MainWindow(QWidget *parent) :
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// initialise ui
|
||||
ui->setupUi(this);
|
||||
ui->lineEdit->setTreeView(ui->treeView);
|
||||
ui->treeView->setModel(&zealList);
|
||||
@ -53,4 +91,34 @@ MainWindow::MainWindow(QWidget *parent) :
|
||||
MainWindow::~MainWindow()
|
||||
{
|
||||
delete ui;
|
||||
delete localServer;
|
||||
keyGrabber.terminate();
|
||||
keyGrabber.waitForFinished(500);
|
||||
}
|
||||
|
||||
void MainWindow::createTrayIcon()
|
||||
{
|
||||
auto trayIconMenu = new QMenu(this);
|
||||
auto quitAction = trayIconMenu->addAction("&Quit");
|
||||
connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit()));
|
||||
auto trayIcon = new QSystemTrayIcon(this);
|
||||
trayIcon->setContextMenu(trayIconMenu);
|
||||
trayIcon->setIcon(QIcon::fromTheme("edit-find"));
|
||||
trayIcon->setToolTip("Zeal");
|
||||
connect(trayIcon, &QSystemTrayIcon::activated, [&](QSystemTrayIcon::ActivationReason reason) {
|
||||
if(reason == QSystemTrayIcon::Trigger || reason == QSystemTrayIcon::DoubleClick) {
|
||||
if(isVisible()) hide();
|
||||
else show();
|
||||
}
|
||||
});
|
||||
trayIcon->show();
|
||||
}
|
||||
|
||||
void MainWindow::bringToFront()
|
||||
{
|
||||
show();
|
||||
setWindowState( (windowState() & ~Qt::WindowMinimized) | Qt::WindowActive);
|
||||
raise();
|
||||
activateWindow();
|
||||
ui->lineEdit->setFocus();
|
||||
}
|
||||
|
@ -2,6 +2,8 @@
|
||||
#define MAINWINDOW_H
|
||||
|
||||
#include <QMainWindow>
|
||||
#include <QProcess>
|
||||
#include <QLocalServer>
|
||||
#include "zeallistmodel.h"
|
||||
#include "zealsearchmodel.h"
|
||||
|
||||
@ -9,6 +11,8 @@ namespace Ui {
|
||||
class MainWindow;
|
||||
}
|
||||
|
||||
extern const QString serverName;
|
||||
|
||||
class MainWindow : public QMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
@ -18,9 +22,13 @@ public:
|
||||
~MainWindow();
|
||||
|
||||
private:
|
||||
void bringToFront();
|
||||
Ui::MainWindow *ui;
|
||||
ZealListModel zealList;
|
||||
ZealSearchModel zealSearch;
|
||||
QProcess keyGrabber;
|
||||
QLocalServer *localServer;
|
||||
void createTrayIcon();
|
||||
};
|
||||
|
||||
#endif // MAINWINDOW_H
|
||||
|
Loading…
Reference in New Issue
Block a user