main.cpp 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396
  1. /*
  2. * Copyright (C) 2010-2015 Michael Buesch <m@bues.ch>
  3. *
  4. * This program is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU General Public License
  6. * as published by the Free Software Foundation; either version 2
  7. * of the License, or (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. */
  14. #include "main.h"
  15. #include "backend.h"
  16. #include "util.h"
  17. #include <QtGui/QApplication>
  18. #include <QtGui/QMessageBox>
  19. #include <QtGui/QGridLayout>
  20. #include <QtGui/QCursor>
  21. #include <iostream>
  22. #include <stdint.h>
  23. #include <sys/signal.h>
  24. using namespace std;
  25. TrayWindow::TrayWindow(TrayIcon *_tray)
  26. : QMenu(NULL)
  27. , tray (_tray)
  28. , blockBrightnessChange (false)
  29. , realBrightnessMinVal (0)
  30. {
  31. struct pt_message m;
  32. int err;
  33. QLabel *label;
  34. QGridLayout *l = new QGridLayout(this);
  35. setLayout(l);
  36. label = new QLabel("LCD:", this);
  37. l->addWidget(label, 0, 0);
  38. brightness = new QSlider(this);
  39. brightness->setOrientation(Qt::Horizontal);
  40. l->addWidget(brightness, 0, 1, 1, 2);
  41. brAutoAdj = new QCheckBox("Auto", this);
  42. l->addWidget(brAutoAdj, 1, 1);
  43. brAutoAdjAC = new QCheckBox("Auto on AC", this);
  44. l->addWidget(brAutoAdjAC, 1, 2);
  45. battLabel = new QLabel(this);
  46. l->addWidget(battLabel, 3, 0);
  47. battBar = new QProgressBar(this);
  48. l->addWidget(battBar, 3, 1, 1, 2);
  49. update();
  50. err = tray->getBackend()->getBacklightState(&m);
  51. if (err) {
  52. cerr << "Failed to fetch initial backlight state" << endl;
  53. } else {
  54. bool autodim = !!(m.bl_stat.flags & htonl(PT_BL_FLG_AUTODIM));
  55. bool autoac = !!(m.bl_stat.flags & htonl(PT_BL_FLG_AUTODIM_AC));
  56. brAutoAdj->setCheckState(autodim ? Qt::Checked : Qt::Unchecked);
  57. brAutoAdjAC->setCheckState(autoac ? Qt::Checked : Qt::Unchecked);
  58. brightness->setValue(ntohl(m.bl_stat.brightness));
  59. //TODO slider min/max?
  60. updateBacklightToolTip(autodim);
  61. }
  62. connect(brightness, SIGNAL(valueChanged(int)),
  63. this, SLOT(desiredBrightnessChanged(int)));
  64. connect(brAutoAdj, SIGNAL(stateChanged(int)),
  65. this, SLOT(brightnessAutoAdjChanged(int)));
  66. connect(brAutoAdjAC, SIGNAL(stateChanged(int)),
  67. this, SLOT(brightnessAutoAdjChanged(int)));
  68. }
  69. TrayWindow::~TrayWindow()
  70. {
  71. }
  72. void TrayWindow::updateBacklightToolTip(bool autodim)
  73. {
  74. if (autodim)
  75. tray->setBacklightToolTip("LCD in autodim mode");
  76. else
  77. tray->setBacklightToolTip("");
  78. }
  79. void TrayWindow::brightnessAutoAdjChanged(int unused)
  80. {
  81. bool on = (brAutoAdj->checkState() == Qt::Checked);
  82. bool on_ac = (brAutoAdjAC->checkState() == Qt::Checked);
  83. int err;
  84. int minval, maxval, range, val;
  85. if (blockBrightnessChange)
  86. return;
  87. if (on) {
  88. /* Auto-adjust on */
  89. minval = realBrightnessMinVal;
  90. maxval = brightness->maximum();
  91. range = maxval - minval;
  92. val = brightness->value();
  93. if (range) {
  94. val = div_round(static_cast<int64_t>(val) * 100,
  95. static_cast<int64_t>(range));
  96. } else
  97. val = 0;
  98. err = tray->getBackend()->setBacklightAutodim(true, on_ac, val);
  99. if (err)
  100. cerr << "Failed to enable auto-dimming" << endl;
  101. brAutoAdjAC->setEnabled(true);
  102. } else {
  103. /* Auto-adjust off */
  104. err = tray->getBackend()->setBacklightAutodim(false, on_ac, 0);
  105. if (err)
  106. cerr << "Failed to disable auto-dimming" << endl;
  107. brAutoAdjAC->setEnabled(false);
  108. }
  109. updateBacklightSlider();
  110. updateBacklightToolTip(on);
  111. }
  112. void TrayWindow::update()
  113. {
  114. updateBacklightSlider();
  115. updateBattBar();
  116. }
  117. void TrayWindow::updateBattBar(struct pt_message *msg)
  118. {
  119. struct pt_message m;
  120. int err;
  121. unsigned int minval, maxval, curval;
  122. unsigned int range, percent;
  123. QString battText("No bat. info");
  124. if (!msg) {
  125. err = tray->getBackend()->getBatteryState(&m);
  126. if (err) {
  127. cerr << "Failed to fetch battery state" << endl;
  128. return;
  129. }
  130. msg = &m;
  131. }
  132. minval = ntohl(msg->bat_stat.min_level);
  133. maxval = ntohl(msg->bat_stat.max_level);
  134. curval = ntohl(msg->bat_stat.level);
  135. if (minval == maxval) {
  136. /* No batt info */
  137. minval = 0;
  138. maxval = 1;
  139. curval = 0;
  140. } else {
  141. battText = "Bat.";
  142. if (msg->bat_stat.flags & htonl(PT_BAT_FLG_ACUNKNOWN))
  143. battText += " / AC?";
  144. else if (msg->bat_stat.flags & htonl(PT_BAT_FLG_ONAC))
  145. battText += " / AC";
  146. if (msg->bat_stat.flags & htonl(PT_BAT_FLG_CHUNKNOWN))
  147. battText += " / charg.?";
  148. else if (msg->bat_stat.flags & htonl(PT_BAT_FLG_CHARGING))
  149. battText += " / charg.";
  150. battText += ":";
  151. }
  152. battBar->setMinimum(minval);
  153. battBar->setMaximum(maxval);
  154. battBar->setValue(curval);
  155. battLabel->setText(battText);
  156. range = maxval - minval;
  157. if (range)
  158. percent = div_round(static_cast<uint64_t>(curval - minval) * 100,
  159. static_cast<uint64_t>(range));
  160. else
  161. percent = 0;
  162. tray->setBatteryToolTip(QString("%1 %2%").arg(battText).arg(percent));
  163. }
  164. void TrayWindow::updateBacklightSlider(struct pt_message *msg)
  165. {
  166. struct pt_message m;
  167. int err;
  168. unsigned int step, flags, val, minval, maxval;
  169. if (!msg) {
  170. err = tray->getBackend()->getBacklightState(&m);
  171. if (err) {
  172. cerr << "Failed to fetch backlight state" << endl;
  173. return;
  174. }
  175. msg = &m;
  176. }
  177. step = ntohl(msg->bl_stat.brightness_step);
  178. flags = ntohl(msg->bl_stat.flags);
  179. val = ntohl(msg->bl_stat.brightness);
  180. minval = ntohl(msg->bl_stat.min_brightness);
  181. maxval = ntohl(msg->bl_stat.max_brightness);
  182. /* Force minval to >= 1%, but save the original minval. */
  183. realBrightnessMinVal = minval;
  184. if (flags & PT_BL_FLG_AUTODIM)
  185. minval = max(minval, 1u);
  186. else
  187. minval = div_round((maxval - minval) * 1, 100) + minval;
  188. minval = round_up(minval, step);
  189. blockBrightnessChange = true;
  190. brightness->setSingleStep(step);
  191. brightness->setMinimum(minval);
  192. brightness->setMaximum(maxval);
  193. brightness->setValue(val);
  194. blockBrightnessChange = false;
  195. }
  196. void TrayWindow::desiredBrightnessChanged(int newVal)
  197. {
  198. bool autodim = (brAutoAdj->checkState() == Qt::Checked);
  199. bool autodim_ac = (brAutoAdjAC->checkState() == Qt::Checked);
  200. int err;
  201. if (blockBrightnessChange)
  202. return;
  203. if (autodim) {
  204. err = tray->getBackend()->setBacklightAutodim(true, autodim_ac, newVal);
  205. if (err)
  206. cerr << "Failed to set autodim max" << endl;
  207. } else {
  208. tray->getBackend()->setBacklight(newVal);
  209. }
  210. }
  211. void TrayWindow::showEvent(QShowEvent *event)
  212. {
  213. QPoint cursor(QCursor::pos());
  214. int x = cursor.x() - width();
  215. int y = cursor.y() - height();
  216. move(max(x, 0), max(y, 0));
  217. QMenu::showEvent(event);
  218. }
  219. TrayIcon::TrayIcon()
  220. : window (NULL)
  221. , backend (NULL)
  222. {
  223. setIcon(QIcon(stringify(PREFIX) "/share/pwrtray/bulb.png"));
  224. }
  225. TrayIcon::~TrayIcon()
  226. {
  227. delete window;
  228. delete backend;
  229. }
  230. bool TrayIcon::init()
  231. {
  232. int err;
  233. backend = new Backend();
  234. err = backend->connectToBackend();
  235. if (err) {
  236. delete backend;
  237. backend = NULL;
  238. return false;
  239. }
  240. window = new TrayWindow(this);
  241. connect(this, SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
  242. this, SLOT(wasActivated(QSystemTrayIcon::ActivationReason)));
  243. connect(backend, SIGNAL(batteryStateChanged(struct pt_message *)),
  244. this, SLOT(batteryStateChanged(struct pt_message *)));
  245. connect(backend, SIGNAL(backlightStateChanged(struct pt_message *)),
  246. this, SLOT(backlightStateChanged(struct pt_message *)));
  247. return true;
  248. }
  249. void TrayIcon::setBacklightToolTip(const QString &text)
  250. {
  251. backlightToolTip = text;
  252. updateToolTip();
  253. }
  254. void TrayIcon::setBatteryToolTip(const QString &text)
  255. {
  256. batteryToolTip = text;
  257. updateToolTip();
  258. }
  259. void TrayIcon::updateToolTip()
  260. {
  261. QString tt(backlightToolTip);
  262. if (!tt.isEmpty())
  263. tt += "\n";
  264. tt += batteryToolTip;
  265. setToolTip(tt);
  266. }
  267. void TrayIcon::wasActivated(ActivationReason reason)
  268. {
  269. window->show();
  270. }
  271. void TrayIcon::batteryStateChanged(struct pt_message *msg)
  272. {
  273. window->updateBattBar(msg);
  274. }
  275. void TrayIcon::backlightStateChanged(struct pt_message *msg)
  276. {
  277. window->updateBacklightSlider(msg);
  278. }
  279. static bool waitForSystray()
  280. {
  281. unsigned int count = 0;
  282. cout << "PwrTray: Waiting for systray ..." << flush;
  283. while (!QSystemTrayIcon::isSystemTrayAvailable()) {
  284. if (count++ >= 240) {
  285. QMessageBox::critical(NULL, "PwrTray: No systray found",
  286. "PwrTray: Could not find a systray.");
  287. return false;
  288. }
  289. msleep(500);
  290. cout << "." << flush;
  291. }
  292. cout << " found" << endl;
  293. return true;
  294. }
  295. static void signal_terminate(int signal)
  296. {
  297. cout << "Terminating signal received." << endl;
  298. QApplication::exit(0);
  299. }
  300. static int install_sighandler(int signal, void (*handler)(int))
  301. {
  302. struct sigaction act;
  303. memset(&act, 0, sizeof(act));
  304. sigemptyset(&act.sa_mask);
  305. act.sa_flags = 0;
  306. act.sa_handler = handler;
  307. return sigaction(signal, &act, NULL);
  308. }
  309. static int setup_signal_handlers(void)
  310. {
  311. int err = 0;
  312. err |= install_sighandler(SIGINT, signal_terminate);
  313. err |= install_sighandler(SIGTERM, signal_terminate);
  314. return err ? -1 : 0;
  315. }
  316. int main(int argc, char **argv)
  317. {
  318. int err;
  319. QApplication app(argc, argv);
  320. err = setup_signal_handlers();
  321. if (err) {
  322. cerr << "Failed to initilize signal handlers" << endl;
  323. return 1;
  324. }
  325. if (!waitForSystray())
  326. return 1;
  327. TrayIcon icon;
  328. icon.show();
  329. if (!icon.init())
  330. return 1;
  331. return app.exec();
  332. }
  333. #include "moc/main.moc"