aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib/platform/MSWindowsEventQueueBuffer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/platform/MSWindowsEventQueueBuffer.cpp')
-rw-r--r--src/lib/platform/MSWindowsEventQueueBuffer.cpp146
1 files changed, 146 insertions, 0 deletions
diff --git a/src/lib/platform/MSWindowsEventQueueBuffer.cpp b/src/lib/platform/MSWindowsEventQueueBuffer.cpp
new file mode 100644
index 0000000..f6de157
--- /dev/null
+++ b/src/lib/platform/MSWindowsEventQueueBuffer.cpp
@@ -0,0 +1,146 @@
+/*
+ * barrier -- mouse and keyboard sharing utility
+ * Copyright (C) 2012-2016 Symless Ltd.
+ * Copyright (C) 2004 Chris Schoeneman
+ *
+ * This package is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * found in the file LICENSE that should have accompanied this file.
+ *
+ * This package 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 program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "platform/MSWindowsEventQueueBuffer.h"
+
+#include "arch/win32/ArchMiscWindows.h"
+#include "mt/Thread.h"
+#include "base/IEventQueue.h"
+
+//
+// EventQueueTimer
+//
+
+class EventQueueTimer { };
+
+
+//
+// MSWindowsEventQueueBuffer
+//
+
+MSWindowsEventQueueBuffer::MSWindowsEventQueueBuffer(IEventQueue* events) :
+ m_events(events)
+{
+ // remember thread. we'll be posting messages to it.
+ m_thread = GetCurrentThreadId();
+
+ // create a message type for custom events
+ m_userEvent = RegisterWindowMessage("BARRIER_USER_EVENT");
+
+ // get message type for daemon quit
+ m_daemonQuit = ArchMiscWindows::getDaemonQuitMessage();
+
+ // make sure this thread has a message queue
+ MSG dummy;
+ PeekMessage(&dummy, NULL, WM_USER, WM_USER, PM_NOREMOVE);
+}
+
+MSWindowsEventQueueBuffer::~MSWindowsEventQueueBuffer()
+{
+ // do nothing
+}
+
+void
+MSWindowsEventQueueBuffer::waitForEvent(double timeout)
+{
+ // check if messages are available first. if we don't do this then
+ // MsgWaitForMultipleObjects() will block even if the queue isn't
+ // empty if the messages in the queue were there before the last
+ // call to GetMessage()/PeekMessage().
+ if (!isEmpty()) {
+ return;
+ }
+
+ // convert timeout
+ DWORD t;
+ if (timeout < 0.0) {
+ t = INFINITE;
+ }
+ else {
+ t = (DWORD)(1000.0 * timeout);
+ }
+
+ // wait for a message. we cannot be interrupted by thread
+ // cancellation but that's okay because we're run in the main
+ // thread and we never cancel that thread.
+ HANDLE dummy[1];
+ MsgWaitForMultipleObjects(0, dummy, FALSE, t, QS_ALLINPUT);
+}
+
+IEventQueueBuffer::Type
+MSWindowsEventQueueBuffer::getEvent(Event& event, UInt32& dataID)
+{
+ // peek at messages first. waiting for QS_ALLINPUT will return
+ // if a message has been sent to our window but GetMessage will
+ // dispatch that message behind our backs and block. PeekMessage
+ // will also dispatch behind our backs but won't block.
+ if (!PeekMessage(&m_event, NULL, 0, 0, PM_NOREMOVE) &&
+ !PeekMessage(&m_event, (HWND)-1, 0, 0, PM_NOREMOVE)) {
+ return kNone;
+ }
+
+ // BOOL. yeah, right.
+ BOOL result = GetMessage(&m_event, NULL, 0, 0);
+ if (result == -1) {
+ return kNone;
+ }
+ else if (result == 0) {
+ event = Event(Event::kQuit);
+ return kSystem;
+ }
+ else if (m_daemonQuit != 0 && m_event.message == m_daemonQuit) {
+ event = Event(Event::kQuit);
+ return kSystem;
+ }
+ else if (m_event.message == m_userEvent) {
+ dataID = static_cast<UInt32>(m_event.wParam);
+ return kUser;
+ }
+ else {
+ event = Event(Event::kSystem,
+ m_events->getSystemTarget(), &m_event);
+ return kSystem;
+ }
+}
+
+bool
+MSWindowsEventQueueBuffer::addEvent(UInt32 dataID)
+{
+ return (PostThreadMessage(m_thread, m_userEvent,
+ static_cast<WPARAM>(dataID), 0) != 0);
+}
+
+bool
+MSWindowsEventQueueBuffer::isEmpty() const
+{
+ // don't use QS_POINTER, QS_TOUCH, or any meta-flags that include them (like QS_ALLINPUT)
+ // because they can cause GetQueueStatus() to always return 0 and we miss events
+ return (HIWORD(GetQueueStatus(QS_POSTMESSAGE)) == 0);
+}
+
+EventQueueTimer*
+MSWindowsEventQueueBuffer::newTimer(double, bool) const
+{
+ return new EventQueueTimer;
+}
+
+void
+MSWindowsEventQueueBuffer::deleteTimer(EventQueueTimer* timer) const
+{
+ delete timer;
+}