ckb-next  v0.2.8 at branch master
ckb-next driver for corsair devices
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
MainWindow Class Reference

#include <src/ckb/mainwindow.h>

+ Inheritance diagram for MainWindow:
+ Collaboration diagram for MainWindow:

Public Slots

void showWindow ()
 
void stateChange (Qt::ApplicationState state)
 
void quitApp ()
 

Public Member Functions

 MainWindow (QWidget *parent=0)
 
 ~MainWindow ()
 
void toggleTrayIcon (bool visible)
 

Static Public Attributes

static MainWindowmainWindow = 0
 

Private Slots

void addDevice (Kb *device)
 
void removeDevice (Kb *device)
 
void updateVersion ()
 
void checkFwUpdates ()
 
void timerTick ()
 
void iconClicked (QSystemTrayIcon::ActivationReason reason)
 
void cleanup ()
 
void showFwUpdateNotification (QWidget *widget, float version)
 

Private Member Functions

void closeEvent (QCloseEvent *event)
 

Private Attributes

SettingsWidgetsettingsWidget
 
QList< KbWidget * > kbWidgets
 
QAction * restoreAction
 
QAction * closeAction
 
QMenu * trayIconMenu
 
QSystemTrayIcon * trayIcon
 
Ui::MainWindowui
 

Detailed Description

Definition at line 27 of file mainwindow.h.

Constructor & Destructor Documentation

MainWindow::MainWindow ( QWidget parent = 0)
explicit

Definition at line 49 of file mainwindow.cpp.

References Ui_MainWindow::actionExit, addDevice(), cleanup(), closeAction, configLabel, daemonDialogText, devpath, CkbSettings::get(), iconClicked(), KbManager::init(), KbManager::kbManager(), mainWindow, quitApp(), removeDevice(), restoreAction, KbManager::scanTimer(), SettingsWidget::setStatus(), settingsWidget, Ui_MainWindow::setupUi(), SettingsWidget::setVersion(), showWindow(), stateChange(), Ui_MainWindow::tabWidget, timerTick(), toggleTrayIcon(), trayIcon, trayIconMenu, ui, and updateVersion().

49  :
50  QMainWindow(parent),
51  ui(new Ui::MainWindow)
52 {
53  ui->setupUi(this);
54  mainWindow = this;
55 
56  // Start device manager
57  KbManager::init(CKB_VERSION_STR);
58  connect(KbManager::kbManager(), SIGNAL(kbConnected(Kb*)), this, SLOT(addDevice(Kb*)));
59  connect(KbManager::kbManager(), SIGNAL(kbDisconnected(Kb*)), this, SLOT(removeDevice(Kb*)));
60  connect(KbManager::kbManager(), SIGNAL(versionUpdated()), this, SLOT(updateVersion()));
61  connect(KbManager::scanTimer(), SIGNAL(timeout()), this, SLOT(timerTick()));
62 
63  // Set up tray icon
64  restoreAction = new QAction(tr("Restore"), this);
65  closeAction = new QAction(tr("Quit ckb"), this);
66 #ifdef USE_LIBAPPINDICATOR
67  QString desktop = std::getenv("XDG_CURRENT_DESKTOP");
68  unityDesktop = (desktop.toLower() == "unity");
69 
70  if(unityDesktop){
71  trayIcon = 0;
72 
73  indicatorMenu = gtk_menu_new();
74  indicatorMenuRestoreItem = gtk_menu_item_new_with_label("Restore");
75  indicatorMenuQuitItem = gtk_menu_item_new_with_label("Quit ckb");
76 
77  gtk_menu_shell_append(GTK_MENU_SHELL(indicatorMenu), indicatorMenuRestoreItem);
78  gtk_menu_shell_append(GTK_MENU_SHELL(indicatorMenu), indicatorMenuQuitItem);
79 
80  g_signal_connect(indicatorMenuQuitItem, "activate",
81  G_CALLBACK(quitIndicator), this);
82  g_signal_connect(indicatorMenuRestoreItem, "activate",
83  G_CALLBACK(restoreIndicator), this);
84 
85  gtk_widget_show(indicatorMenuRestoreItem);
86  gtk_widget_show(indicatorMenuQuitItem);
87 
88  indicator = app_indicator_new("ckb", "indicator-messages", APP_INDICATOR_CATEGORY_APPLICATION_STATUS);
89 
90  app_indicator_set_status(indicator, APP_INDICATOR_STATUS_ACTIVE);
91  app_indicator_set_menu(indicator, GTK_MENU(indicatorMenu));
92  app_indicator_set_icon(indicator, "ckb");
93  } else
94 #endif // USE_LIBAPPINDICATOR
95  {
96  trayIconMenu = new QMenu(this);
97  trayIconMenu->addAction(restoreAction);
98  trayIconMenu->addAction(closeAction);
99  trayIcon = new QSystemTrayIcon(QIcon(":/img/ckb-logo.png"), this);
100  trayIcon->setContextMenu(trayIconMenu);
101  connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(iconClicked(QSystemTrayIcon::ActivationReason)));
102  }
103  toggleTrayIcon(!CkbSettings::get("Program/SuppressTrayIcon").toBool());
104 
105 #ifdef Q_OS_MACX
106  // Make a custom "Close" menu action for OSX, as the default one brings up the "still running" popup unnecessarily
107  QMenuBar* menuBar = new QMenuBar(this);
108  setMenuBar(menuBar);
109  this->menuBar()->addMenu("ckb")->addAction(closeAction);
110 #else
111  // On linux, add a handler for Ctrl+Q
112  new QShortcut(QKeySequence("Ctrl+Q"), this, SLOT(quitApp()));
113 #endif
114 
115  connect(ui->actionExit, SIGNAL(triggered()), this, SLOT(quitApp()));
116  connect(closeAction, SIGNAL(triggered()), this, SLOT(quitApp()));
117  connect(restoreAction, SIGNAL(triggered()), this, SLOT(showWindow()));
118  connect(qApp, SIGNAL(applicationStateChanged(Qt::ApplicationState)), this, SLOT(stateChange(Qt::ApplicationState)));
119 
120  connect(qApp, SIGNAL(aboutToQuit()), this, SLOT(cleanup()));
121 
122  ui->tabWidget->addTab(settingsWidget = new SettingsWidget(this), configLabel);
123  settingsWidget->setVersion("ckb-next " CKB_VERSION_STR);
124 
125  // create daemon dialog as a QMessageBox
126  // this will create a focussed dialog, that has to be interacted with,
127  // if the daemon is not running
128  // set the main and informative text to tell the user about the issue
129  QMessageBox dialog;
130  dialog.setText(tr("The ckb-next daemon is not running. This program will <b>not</b> work without it!"));
131  dialog.setInformativeText(daemonDialogText);
132  dialog.setIcon(QMessageBox::Critical);
133 
134  // check, whether daemon is running
135  // the daemon creates the root device path on initialization and thus it
136  // can be assumed, that the daemon is not running if doesn't exist
137  // `.arg(0)` is necessary to interpolate the correct suffix into the path
138  // see `./kbmanager.cpp` for details
139  QFileInfo rootDevPath(devpath.arg(0));
140  if (!rootDevPath.exists()) {
141  // set settings widget's status
142  // show the main window (otherwise only the dialog will be visible)
143  // finally show the dialog
144  settingsWidget->setStatus(tr("The ckb-next daemon is not running."));
145  showWindow();
146  dialog.exec();
147  }
148 }
void stateChange(Qt::ApplicationState state)
Definition: mainwindow.cpp:314
static KbManager * kbManager()
Definition: kbmanager.h:23
Ui::MainWindow * ui
Definition: mainwindow.h:75
void cleanup()
Definition: mainwindow.cpp:333
void quitApp()
Definition: mainwindow.cpp:329
void showWindow()
Definition: mainwindow.cpp:308
static QVariant get(const QString &key, const QVariant &defaultValue=QVariant())
void toggleTrayIcon(bool visible)
Definition: mainwindow.cpp:150
void removeDevice(Kb *device)
Definition: mainwindow.cpp:177
void setStatus(const QString &text)
QMenu * trayIconMenu
Definition: mainwindow.h:53
static QTimer * scanTimer()
Definition: kbmanager.h:43
QAction * restoreAction
Definition: mainwindow.h:43
static const QString configLabel
Definition: mainwindow.cpp:17
void updateVersion()
Definition: mainwindow.cpp:191
Definition: kb.h:11
static void init(QString guiVersion)
Definition: kbmanager.cpp:12
QSystemTrayIcon * trayIcon
Definition: mainwindow.h:54
static MainWindow * mainWindow
Definition: mainwindow.h:35
QString daemonDialogText
Definition: mainwindow.cpp:20
QTabWidget * tabWidget
Definition: ui_mainwindow.h:31
void setVersion(const QString &version)
void setupUi(QMainWindow *MainWindow)
Definition: ui_mainwindow.h:33
void iconClicked(QSystemTrayIcon::ActivationReason reason)
Definition: mainwindow.cpp:295
QAction * closeAction
Definition: mainwindow.h:44
SettingsWidget * settingsWidget
Definition: mainwindow.h:40
QString devpath
Device path base ("/dev/input/ckb" or "/var/run/ckb")
Definition: kbmanager.cpp:4
void timerTick()
Definition: mainwindow.cpp:261
void addDevice(Kb *device)
Definition: mainwindow.cpp:159
QAction * actionExit
Definition: ui_mainwindow.h:27

+ Here is the call graph for this function:

MainWindow::~MainWindow ( )

Definition at line 341 of file mainwindow.cpp.

References cleanup(), and ui.

341  {
342  cleanup();
343  delete ui;
344 }
Ui::MainWindow * ui
Definition: mainwindow.h:75
void cleanup()
Definition: mainwindow.cpp:333

+ Here is the call graph for this function:

Member Function Documentation

void MainWindow::addDevice ( Kb device)
privateslot

Definition at line 159 of file mainwindow.cpp.

References KbWidget::device, kbWidgets, KbWidget::name(), Ui_MainWindow::tabWidget, ui, and updateVersion().

Referenced by MainWindow().

159  {
160  // Connected already?
161  foreach(KbWidget* w, kbWidgets){
162  if(w->device == device)
163  return;
164  }
165  // Add the keyboard
166  KbWidget* widget = new KbWidget(this, device);
167  kbWidgets.append(widget);
168  // Add to tabber; switch to this device if the user is on the settings screen
169  int count = ui->tabWidget->count();
170  ui->tabWidget->insertTab(count - 1, widget, widget->name());
171  if(ui->tabWidget->currentIndex() == count)
172  ui->tabWidget->setCurrentIndex(count - 1);
173  // Update connected device count
174  updateVersion();
175 }
Ui::MainWindow * ui
Definition: mainwindow.h:75
QString name() const
Definition: kbwidget.h:25
void updateVersion()
Definition: mainwindow.cpp:191
QTabWidget * tabWidget
Definition: ui_mainwindow.h:31
QList< KbWidget * > kbWidgets
Definition: mainwindow.h:41
Kb * device
Definition: kbwidget.h:24

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void MainWindow::checkFwUpdates ( )
privateslot

Definition at line 210 of file mainwindow.cpp.

References KbWidget::device, Kb::features, Kb::firmware, KbWidget::hasShownNewFW, kbWidgets, mainWindow, KbWidget::updateFwButton(), and KbFirmware::versionForBoard().

Referenced by timerTick().

210  {
211  if(!mainWindow->isVisible())
212  return;
213  foreach(KbWidget* w, kbWidgets){
214  // Display firmware upgrade notification if a new version is available
215  float version = KbFirmware::versionForBoard(w->device->features);
216  if(version > w->device->firmware.toFloat()){
217  if(w->hasShownNewFW)
218  continue;
219  w->hasShownNewFW = true;
220  w->updateFwButton();
221  // Don't run this method here because it will lock up the timer and prevent devices from working properly
222  // Use a queued invocation instead
223  metaObject()->invokeMethod(this, "showFwUpdateNotification", Qt::QueuedConnection, Q_ARG(QWidget*, w), Q_ARG(float, version));
224  // Don't display more than one of these at once
225  return;
226  }
227  }
228 }
void updateFwButton()
Definition: kbwidget.cpp:326
QString firmware
Definition: kb.h:18
bool hasShownNewFW
Definition: kbwidget.h:28
static MainWindow * mainWindow
Definition: mainwindow.h:35
QString features
Definition: kb.h:18
QList< KbWidget * > kbWidgets
Definition: mainwindow.h:41
Kb * device
Definition: kbwidget.h:24
static float versionForBoard(const QString &features, bool waitForComplete=false)
Definition: kbfirmware.h:22

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void MainWindow::cleanup ( )
privateslot

Definition at line 333 of file mainwindow.cpp.

References CkbSettings::cleanUp(), kbWidgets, and KbManager::stop().

Referenced by MainWindow(), and ~MainWindow().

333  {
334  foreach(KbWidget* w, kbWidgets)
335  delete w;
336  kbWidgets.clear();
337  KbManager::stop();
339 }
static void stop()
Definition: kbmanager.cpp:19
static void cleanUp()
Definition: ckbsettings.cpp:46
QList< KbWidget * > kbWidgets
Definition: mainwindow.h:41

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void MainWindow::closeEvent ( QCloseEvent *  event)
private

Definition at line 247 of file mainwindow.cpp.

References CkbSettings::get(), and CkbSettings::set().

247  {
248  // If the window is hidden already or the event is non-spontaneous (can happen on OSX when using the Quit menu), accept it and close
249  if(!event->spontaneous() || isHidden()){
250  event->accept();
251  return;
252  }
253  if(!CkbSettings::get("Popups/BGWarning").toBool()){
254  QMessageBox::information(this, "ckb", "ckb will still run in the background.\nTo close it, choose Exit from the tray menu\nor click \"Quit ckb\" on the Settings screen.");
255  CkbSettings::set("Popups/BGWarning", true);
256  }
257  hide();
258  event->ignore();
259 }
static void set(const QString &key, const QVariant &value)
static QVariant get(const QString &key, const QVariant &defaultValue=QVariant())

+ Here is the call graph for this function:

void MainWindow::iconClicked ( QSystemTrayIcon::ActivationReason  reason)
privateslot

Definition at line 295 of file mainwindow.cpp.

References showWindow().

Referenced by MainWindow().

295  {
296  // On Linux, hide/show the app when the tray icon is clicked
297  // On OSX this just shows the menu
298 #ifndef Q_OS_MACX
299  if(reason == QSystemTrayIcon::DoubleClick || reason == QSystemTrayIcon::Trigger){
300  if(isVisible())
301  hide();
302  else
303  showWindow();
304  }
305 #endif
306 }
void showWindow()
Definition: mainwindow.cpp:308

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void MainWindow::quitApp ( )
slot

Definition at line 329 of file mainwindow.cpp.

Referenced by MainWindow().

329  {
330  qApp->quit();
331 }

+ Here is the caller graph for this function:

void MainWindow::removeDevice ( Kb device)
privateslot

Definition at line 177 of file mainwindow.cpp.

References KbWidget::device, kbWidgets, Ui_MainWindow::tabWidget, ui, and updateVersion().

Referenced by MainWindow().

177  {
178  foreach(KbWidget* w, kbWidgets){
179  // Remove this device from the UI
180  if(w->device == device){
181  int i = kbWidgets.indexOf(w);
182  ui->tabWidget->removeTab(i);
183  kbWidgets.removeAt(i);
184  w->deleteLater();
185  }
186  }
187  // Update connected device count
188  updateVersion();
189 }
Ui::MainWindow * ui
Definition: mainwindow.h:75
void updateVersion()
Definition: mainwindow.cpp:191
QTabWidget * tabWidget
Definition: ui_mainwindow.h:31
QList< KbWidget * > kbWidgets
Definition: mainwindow.h:41
Kb * device
Definition: kbwidget.h:24

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void MainWindow::showFwUpdateNotification ( QWidget widget,
float  version 
)
privateslot

Definition at line 230 of file mainwindow.cpp.

References KbWidget::device, kbWidgets, KbWidget::showFwUpdate(), KbWidget::showLastTab(), showWindow(), Ui_MainWindow::tabWidget, ui, and Kb::usbModel.

230  {
231  static bool isShowing = false;
232  if(isShowing)
233  return;
234  isShowing = true;
235  showWindow();
236  KbWidget* w = (KbWidget*)widget;
237  // Ask for update
238  if(QMessageBox::information(this, "Firmware update", tr("A new firmware is available for your %1 (v%2)\nWould you like to install it now?").arg(w->device->usbModel, QString::number(version, 'f', 2)), QMessageBox::StandardButtons(QMessageBox::Yes | QMessageBox::No), QMessageBox::Yes) == QMessageBox::Yes){
239  // If accepted, switch to the firmware tab and bring up the update window
240  w->showLastTab();
241  ui->tabWidget->setCurrentIndex(kbWidgets.indexOf(w));
242  w->showFwUpdate();
243  }
244  isShowing = false;
245 }
Ui::MainWindow * ui
Definition: mainwindow.h:75
void showWindow()
Definition: mainwindow.cpp:308
void showFwUpdate()
Definition: kbwidget.h:38
void showLastTab()
Definition: kbwidget.cpp:68
QString usbModel
Definition: kb.h:16
QTabWidget * tabWidget
Definition: ui_mainwindow.h:31
QList< KbWidget * > kbWidgets
Definition: mainwindow.h:41
Kb * device
Definition: kbwidget.h:24

+ Here is the call graph for this function:

void MainWindow::showWindow ( )
slot

Definition at line 308 of file mainwindow.cpp.

Referenced by iconClicked(), MainWindow(), showFwUpdateNotification(), stateChange(), and timerTick().

308  {
309  showNormal();
310  raise();
311  activateWindow();
312 }

+ Here is the caller graph for this function:

void MainWindow::stateChange ( Qt::ApplicationState  state)
slot

Definition at line 314 of file mainwindow.cpp.

References showWindow().

Referenced by MainWindow().

314  {
315  // On OSX it's possible for the app to be brought to the foreground without the window actually reappearing.
316  // We want to make sure it's shown when this happens.
317 #ifdef Q_OS_MAC
318  static quint64 lastStateChange = 0;
319  quint64 now = QDateTime::currentMSecsSinceEpoch();
320  if(state == Qt::ApplicationActive){
321  // This happens once at startup so ignore it. Also don't allow it to be called more than once every 2s.
322  if(lastStateChange != 0 && now >= lastStateChange + 2 * 1000)
323  showWindow();
324  lastStateChange = now;
325  }
326 #endif
327 }
void showWindow()
Definition: mainwindow.cpp:308

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void MainWindow::timerTick ( )
privateslot

Definition at line 261 of file mainwindow.cpp.

References appShare, checkFwUpdates(), KbFirmware::checkUpdates(), CkbSettings::get(), SettingsWidget::pollUpdates(), settingsWidget, and showWindow().

Referenced by MainWindow().

261  {
262  // Check shared memory for changes
263  if(appShare.lock()){
264  void* data = appShare.data();
265  QStringList commands = QString((const char*)data).split("\n");
266  // Restore PID, remove all other data
267  snprintf((char*)appShare.data(), appShare.size(), "PID %ld", (long)getpid());
268  appShare.unlock();
269  // Parse commands
270  foreach(const QString& line, commands){
271  // Old ckb option line - bring application to foreground
272  if(line == "Open")
273  showWindow();
274  if(line.startsWith("Option ")){
275  // New ckb option line
276  QString option = line.split(" ")[1];
277  if(option == "Open")
278  // Bring to foreground
279  showWindow();
280  else if(option == "Close")
281  // Quit application
282  qApp->quit();
283  }
284  }
285  }
286  // Check for firmware updates (when appropriate)
287  if(!CkbSettings::get("Program/DisableAutoFWCheck").toBool()){
289  checkFwUpdates();
290  }
291  // Poll for setting updates
293 }
void checkFwUpdates()
Definition: mainwindow.cpp:210
void showWindow()
Definition: mainwindow.cpp:308
static QVariant get(const QString &key, const QVariant &defaultValue=QVariant())
QSharedMemory appShare
static bool checkUpdates()
Definition: kbfirmware.h:15
SettingsWidget * settingsWidget
Definition: mainwindow.h:40

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void MainWindow::toggleTrayIcon ( bool  visible)

Definition at line 150 of file mainwindow.cpp.

References trayIcon.

Referenced by MainWindow(), and ExtraSettingsWidget::on_trayBox_clicked().

150  {
151 #ifdef USE_LIBAPPINDICATOR
152  if(unityDesktop)
153  app_indicator_set_status(indicator, visible ? APP_INDICATOR_STATUS_ACTIVE : APP_INDICATOR_STATUS_PASSIVE);
154  else
155 #endif // USE_LIBAPPINDICATOR
156  trayIcon->setVisible(visible);
157 }
QSystemTrayIcon * trayIcon
Definition: mainwindow.h:54

+ Here is the caller graph for this function:

void MainWindow::updateVersion ( )
privateslot

Definition at line 191 of file mainwindow.cpp.

References KbManager::ckbDaemonVersion(), KbManager::ckbDaemonVersionF(), KbManager::ckbGuiVersionF(), DAEMON_UNAVAILABLE_STR, kbWidgets, SettingsWidget::setStatus(), and settingsWidget.

Referenced by addDevice(), MainWindow(), and removeDevice().

191  {
192  QString daemonVersion = KbManager::ckbDaemonVersion();
193  if(daemonVersion == DAEMON_UNAVAILABLE_STR){
194  settingsWidget->setStatus("Driver inactive");
195  return;
196  }
197  int count = kbWidgets.count();
198  // Warn if the daemon version doesn't match the GUI
199  QString daemonWarning;
200  if(daemonVersion != CKB_VERSION_STR)
201  daemonWarning = "<br /><br /><b>Warning:</b> Driver version mismatch (" + daemonVersion + "). Please upgrade ckb" + QString(KbManager::ckbDaemonVersionF() > KbManager::ckbGuiVersionF() ? "" : "-daemon") + ". If the problem persists, try rebooting.";
202  if(count == 0)
203  settingsWidget->setStatus("No devices connected" + daemonWarning);
204  else if(count == 1)
205  settingsWidget->setStatus("1 device connected" + daemonWarning);
206  else
207  settingsWidget->setStatus(QString("%1 devices connected").arg(count) + daemonWarning);
208 }
void setStatus(const QString &text)
static float ckbDaemonVersionF()
Definition: kbmanager.h:31
static float ckbGuiVersionF()
Definition: kbmanager.h:30
#define DAEMON_UNAVAILABLE_STR
Definition: kbmanager.h:12
SettingsWidget * settingsWidget
Definition: mainwindow.h:40
static QString ckbDaemonVersion()
Definition: kbmanager.h:27
QList< KbWidget * > kbWidgets
Definition: mainwindow.h:41

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

Field Documentation

QAction* MainWindow::closeAction
private

Definition at line 44 of file mainwindow.h.

Referenced by MainWindow().

QList<KbWidget*> MainWindow::kbWidgets
private
MainWindow * MainWindow::mainWindow = 0
static
QAction* MainWindow::restoreAction
private

Definition at line 43 of file mainwindow.h.

Referenced by MainWindow().

SettingsWidget* MainWindow::settingsWidget
private

Definition at line 40 of file mainwindow.h.

Referenced by MainWindow(), timerTick(), and updateVersion().

QSystemTrayIcon* MainWindow::trayIcon
private

Definition at line 54 of file mainwindow.h.

Referenced by MainWindow(), and toggleTrayIcon().

QMenu* MainWindow::trayIconMenu
private

Definition at line 53 of file mainwindow.h.

Referenced by MainWindow().

Ui::MainWindow* MainWindow::ui
private

The documentation for this class was generated from the following files: