Branch: master

2c730f70 2014-05-15 20:08:00 Slávek Banko
Optimize watching switches on input event devices
This relates to Bugs 1992 and 2052
M tdecore/tdehw/tdeeventdevice.cpp
M tdecore/tdehw/tdeeventdevice.h
M tdecore/tdehw/tdehardwaredevices.cpp
diff --git a/tdecore/tdehw/tdeeventdevice.cpp b/tdecore/tdehw/tdeeventdevice.cpp
index 185c415..d8627d9 100644
--- a/tdecore/tdehw/tdeeventdevice.cpp
+++ b/tdecore/tdehw/tdeeventdevice.cpp
@@ -23,6 +23,7 @@
 #include <linux/input.h>
 
 #include <tqsocketnotifier.h>
+#include <tqtimer.h>
 
 #include "tdelocale.h"
 
@@ -30,14 +31,35 @@
 
 #include "config.h"
 
+#define BITS_PER_LONG (sizeof(long) * 8)
+#define NUM_BITS(x) ((((x) - 1) / BITS_PER_LONG) + 1)
+#define OFF(x)  ((x) % BITS_PER_LONG)
+#define BIT(x)  (1UL << OFF(x))
+#define LONG(x) ((x) / BITS_PER_LONG)
+#define BIT_IS_SET(array, bit)  ((array[LONG(bit)] >> OFF(bit)) & 1)
+
+#if defined(WITH_TDEHWLIB_DAEMONS)
+#include <tqdbusconnection.h>
+#include <tqdbusproxy.h>
+#include <tqdbusmessage.h>
+#include <tqdbusvariant.h>
+#include <tqdbusdata.h>
+#include <tqdbusdatalist.h>
+#endif
+
 TDEEventDevice::TDEEventDevice(TDEGenericDeviceType::TDEGenericDeviceType dt, TQString dn) : TDEGenericDevice(dt, dn) {
 	m_fd = -1;
-	m_fdMonitorActive = false;
+	m_watchTimer = 0;
+	m_monitorActive = false;
 }
 
 TDEEventDevice::~TDEEventDevice() {
 	if (m_fd >= 0) {
 		close(m_fd);
+	}
+	if (m_watchTimer) {
+		m_watchTimer->stop();
+		delete m_watchTimer;
 	}
 }
 
@@ -50,7 +72,109 @@
 }
 
 TDESwitchType::TDESwitchType TDEEventDevice::providedSwitches() {
+	if (!m_monitorActive) {
+		internalReadProvidedSwitches();
+	}
 	return m_providedSwitches;
+}
+
+void TDEEventDevice::internalReadProvidedSwitches() {
+	unsigned long switches[NUM_BITS(EV_CNT)];
+	int r = 0;
+
+	// Figure out which switch types are supported, if any
+	TDESwitchType::TDESwitchType supportedSwitches = TDESwitchType::Null;
+	if (m_fd >= 0) {
+		r = ioctl(m_fd, EVIOCGBIT(EV_SW, EV_CNT), switches);
+	}
+#ifdef WITH_TDEHWLIB_DAEMONS
+	if( r < 1 ) {
+		TQT_DBusConnection dbusConn = TQT_DBusConnection::addConnection(TQT_DBusConnection::SystemBus);
+		if (dbusConn.isConnected()) {
+			TQT_DBusProxy switchesProxy("org.trinitydesktop.hardwarecontrol",
+				"/org/trinitydesktop/hardwarecontrol",
+				"org.trinitydesktop.hardwarecontrol.InputEvents",
+				dbusConn);
+			if (switchesProxy.canSend()) {
+				TQValueList<TQT_DBusData> params;
+				params << TQT_DBusData::fromString(deviceNode().ascii());
+				TQT_DBusMessage reply = switchesProxy.sendWithReply("GetProvidedSwitches", params);
+				if (reply.type() == TQT_DBusMessage::ReplyMessage && reply.count() == 1) {
+					TQValueList<TQ_UINT32> list = reply[0].toList().toUInt32List();
+					TQValueList<TQ_UINT32>::const_iterator it = list.begin();
+					for (r = 0; it != list.end(); ++it, r++) {
+						switches[r] = (*it);
+					}
+				}
+			}
+		}
+	}
+#endif
+	if (r > 0) {
+		if (BIT_IS_SET(switches, SW_LID)) {
+			supportedSwitches = supportedSwitches | TDESwitchType::Lid;
+		}
+		if (BIT_IS_SET(switches, SW_TABLET_MODE)) {
+			supportedSwitches = supportedSwitches | TDESwitchType::TabletMode;
+		}
+		if (BIT_IS_SET(switches, SW_RFKILL_ALL)) {
+			supportedSwitches = supportedSwitches | TDESwitchType::RFKill;
+		}
+		if (BIT_IS_SET(switches, SW_RADIO)) {
+			supportedSwitches = supportedSwitches | TDESwitchType::Radio;
+		}
+		if (BIT_IS_SET(switches, SW_MICROPHONE_INSERT)) {
+			supportedSwitches = supportedSwitches | TDESwitchType::MicrophoneInsert;
+		}
+		if (BIT_IS_SET(switches, SW_DOCK)) {
+			supportedSwitches = supportedSwitches | TDESwitchType::Dock;
+		}
+		if (BIT_IS_SET(switches, SW_LINEOUT_INSERT)) {
+			supportedSwitches = supportedSwitches | TDESwitchType::LineOutInsert;
+		}
+		if (BIT_IS_SET(switches, SW_JACK_PHYSICAL_INSERT)) {
+			supportedSwitches = supportedSwitches | TDESwitchType::JackPhysicalInsert;
+		}
+		if (BIT_IS_SET(switches, SW_VIDEOOUT_INSERT)) {
+			supportedSwitches = supportedSwitches | TDESwitchType::VideoOutInsert;
+		}
+#		ifdef SW_CAMERA_LENS_COVER
+		if (BIT_IS_SET(switches, SW_CAMERA_LENS_COVER)) {
+			supportedSwitches = supportedSwitches | TDESwitchType::CameraLensCover;
+		}
+#		endif
+#		ifdef SW_KEYPAD_SLIDE
+		if (BIT_IS_SET(switches, SW_KEYPAD_SLIDE)) {
+			supportedSwitches = supportedSwitches | TDESwitchType::KeypadSlide;
+		}
+#		endif
+#		ifdef SW_FRONT_PROXIMITY
+		if (BIT_IS_SET(switches, SW_FRONT_PROXIMITY)) {
+			supportedSwitches = supportedSwitches | TDESwitchType::FrontProximity;
+		}
+#		endif
+#		ifdef SW_ROTATE_LOCK
+		if (BIT_IS_SET(switches, SW_ROTATE_LOCK)) {
+			supportedSwitches = supportedSwitches | TDESwitchType::RotateLock;
+		}
+#		endif
+#		ifdef SW_LINEIN_INSERT
+		if (BIT_IS_SET(switches, SW_LINEIN_INSERT)) {
+			supportedSwitches = supportedSwitches | TDESwitchType::LineInInsert;
+		}
+#		endif
+		// Keep in sync with ACPI Event/Input identification routines above
+		if (systemPath().contains("PNP0C0D")) {
+			supportedSwitches = supportedSwitches | TDESwitchType::Lid;
+		}
+		if (systemPath().contains("PNP0C0E") || systemPath().contains("/LNXSLPBN")) {
+			supportedSwitches = supportedSwitches | TDESwitchType::SleepButton;
+		}
+		if (systemPath().contains("PNP0C0C") || systemPath().contains("/LNXPWRBN")) {
+			supportedSwitches = supportedSwitches | TDESwitchType::PowerButton;
+		}
+	}
+	m_providedSwitches = supportedSwitches;
 }
 
 void TDEEventDevice::internalSetProvidedSwitches(TDESwitchType::TDESwitchType sl) {
@@ -58,7 +182,98 @@
 }
 
 TDESwitchType::TDESwitchType TDEEventDevice::activeSwitches() {
+	if (!m_monitorActive) {
+		internalReadActiveSwitches();
+	}
 	return m_switchActive;
+}
+
+void TDEEventDevice::internalReadActiveSwitches() {
+	unsigned long switches[NUM_BITS(EV_CNT)];
+	int r = 0;
+
+	TDESwitchType::TDESwitchType activeSwitches = TDESwitchType::Null;
+	if (m_fd >= 0) {
+		r = ioctl(m_fd, EVIOCGSW(sizeof(switches)), switches);
+	}
+#ifdef WITH_TDEHWLIB_DAEMONS
+	if( r < 1 ) {
+		TQT_DBusConnection dbusConn = TQT_DBusConnection::addConnection(TQT_DBusConnection::SystemBus);
+		if (dbusConn.isConnected()) {
+			TQT_DBusProxy switchesProxy("org.trinitydesktop.hardwarecontrol",
+				"/org/trinitydesktop/hardwarecontrol",
+				"org.trinitydesktop.hardwarecontrol.InputEvents",
+				dbusConn);
+			if (switchesProxy.canSend()) {
+				TQValueList<TQT_DBusData> params;
+				params << TQT_DBusData::fromString(deviceNode().ascii());
+				TQT_DBusMessage reply = switchesProxy.sendWithReply("GetActiveSwitches", params);
+				if (reply.type() == TQT_DBusMessage::ReplyMessage && reply.count() == 1) {
+					TQValueList<TQ_UINT32> list = reply[0].toList().toUInt32List();
+					TQValueList<TQ_UINT32>::const_iterator it = list.begin();
+					for (r = 0; it != list.end(); ++it, r++) {
+						switches[r] = (*it);
+					}
+				}
+			}
+		}
+	}
+#endif
+	if (r > 0) {
+		if (BIT_IS_SET(switches, SW_LID)) {
+			activeSwitches = activeSwitches | TDESwitchType::Lid;
+		}
+		if (BIT_IS_SET(switches, SW_TABLET_MODE)) {
+			activeSwitches = activeSwitches | TDESwitchType::TabletMode;
+		}
+		if (BIT_IS_SET(switches, SW_RFKILL_ALL)) {
+			activeSwitches = activeSwitches | TDESwitchType::RFKill;
+		}
+		if (BIT_IS_SET(switches, SW_RADIO)) {
+			activeSwitches = activeSwitches | TDESwitchType::Radio;
+		}
+		if (BIT_IS_SET(switches, SW_MICROPHONE_INSERT)) {
+			activeSwitches = activeSwitches | TDESwitchType::MicrophoneInsert;
+		}
+		if (BIT_IS_SET(switches, SW_DOCK)) {
+			activeSwitches = activeSwitches | TDESwitchType::Dock;
+		}
+		if (BIT_IS_SET(switches, SW_LINEOUT_INSERT)) {
+			activeSwitches = activeSwitches | TDESwitchType::LineOutInsert;
+		}
+		if (BIT_IS_SET(switches, SW_JACK_PHYSICAL_INSERT)) {
+			activeSwitches = activeSwitches | TDESwitchType::JackPhysicalInsert;
+		}
+		if (BIT_IS_SET(switches, SW_VIDEOOUT_INSERT)) {
+			activeSwitches = activeSwitches | TDESwitchType::VideoOutInsert;
+		}
+#		ifdef SW_CAMERA_LENS_COVER
+		if (BIT_IS_SET(switches, SW_CAMERA_LENS_COVER)) {
+			activeSwitches = activeSwitches | TDESwitchType::CameraLensCover;
+		}
+#		endif
+#		ifdef SW_KEYPAD_SLIDE
+		if (BIT_IS_SET(switches, SW_KEYPAD_SLIDE)) {
+			activeSwitches = activeSwitches | TDESwitchType::KeypadSlide;
+		}
+#		endif
+#		ifdef SW_FRONT_PROXIMITY
+		if (BIT_IS_SET(switches, SW_FRONT_PROXIMITY)) {
+			activeSwitches = activeSwitches | TDESwitchType::FrontProximity;
+		}
+#		endif
+#		ifdef SW_ROTATE_LOCK
+		if (BIT_IS_SET(switches, SW_ROTATE_LOCK)) {
+			activeSwitches = activeSwitches | TDESwitchType::RotateLock;
+		}
+#		endif
+#		ifdef SW_LINEIN_INSERT
+		if (BIT_IS_SET(switches, SW_LINEIN_INSERT)) {
 ** Diff limit reached (max: 250 lines) **