Pārlūkot izejas kodu

CEventLoop: Allow manually driving the event loop

Move the bulk of exec() into a new pump(). Since SDL wants to drive the
event loop itself, this is a requirement. We also add a WaitMode flag to
allow for immediately pumping events -- again, this is required because
SDL wants to be in full control of the event loop, and not let us wait.
Robin Burchell 6 gadi atpakaļ
vecāks
revīzija
d791bce6af
2 mainītis faili ar 65 papildinājumiem un 43 dzēšanām
  1. 54 42
      LibCore/CEventLoop.cpp
  2. 11 1
      LibCore/CEventLoop.h

+ 54 - 42
LibCore/CEventLoop.cpp

@@ -92,51 +92,56 @@ int CEventLoop::exec()
     for (;;) {
         if (m_exit_requested)
             return m_exit_code;
-        do_processing();
+        pump();
+    }
+    ASSERT_NOT_REACHED();
+}
 
-        if (m_queued_events.is_empty()) {
-            wait_for_event();
-            do_processing();
-        }
-        decltype(m_queued_events) events;
-        {
-            LOCKER(m_lock);
-            events = move(m_queued_events);
-        }
+void CEventLoop::pump(WaitMode mode)
+{
+    // window server event processing...
+    do_processing();
+
+    if (m_queued_events.is_empty()) {
+        wait_for_event(mode);
+        do_processing();
+    }
+    decltype(m_queued_events) events;
+    {
+        LOCKER(m_lock);
+        events = move(m_queued_events);
+    }
 
-        for (auto& queued_event : events) {
-            auto* receiver = queued_event.receiver.ptr();
-            auto& event = *queued_event.event;
+    for (auto& queued_event : events) {
+        auto* receiver = queued_event.receiver.ptr();
+        auto& event = *queued_event.event;
 #ifdef CEVENTLOOP_DEBUG
-            dbgprintf("CEventLoop: %s{%p} event %u\n", receiver->class_name(), receiver, (unsigned)event.type());
+        dbgprintf("CEventLoop: %s{%p} event %u\n", receiver->class_name(), receiver, (unsigned)event.type());
 #endif
-            if (!receiver) {
-                switch (event.type()) {
-                case CEvent::Quit:
-                    ASSERT_NOT_REACHED();
-                    return 0;
-                default:
-                    dbgprintf("Event type %u with no receiver :(\n", event.type());
-                }
-            } else if (event.type() == CEvent::Type::DeferredInvoke) {
+        if (!receiver) {
+            switch (event.type()) {
+            case CEvent::Quit:
+                ASSERT_NOT_REACHED();
+                return;
+            default:
+                dbgprintf("Event type %u with no receiver :(\n", event.type());
+            }
+        } else if (event.type() == CEvent::Type::DeferredInvoke) {
 #ifdef DEFERRED_INVOKE_DEBUG
-                printf("DeferredInvoke: receiver=%s{%p}\n", receiver->class_name(), receiver);
+            printf("DeferredInvoke: receiver=%s{%p}\n", receiver->class_name(), receiver);
 #endif
-                static_cast<CDeferredInvocationEvent&>(event).m_invokee(*receiver);
-            } else {
-                receiver->event(event);
-            }
+            static_cast<CDeferredInvocationEvent&>(event).m_invokee(*receiver);
+        } else {
+            receiver->event(event);
+        }
 
-            if (m_exit_requested) {
-                LOCKER(m_lock);
-                auto rejigged_event_queue = move(events);
-                rejigged_event_queue.append(move(m_queued_events));
-                m_queued_events = move(rejigged_event_queue);
-                return m_exit_code;
-            }
+        if (m_exit_requested) {
+            LOCKER(m_lock);
+            auto rejigged_event_queue = move(events);
+            rejigged_event_queue.append(move(m_queued_events));
+            m_queued_events = move(rejigged_event_queue);
         }
     }
-    ASSERT_NOT_REACHED();
 }
 
 void CEventLoop::post_event(CObject& receiver, OwnPtr<CEvent>&& event)
@@ -148,7 +153,7 @@ void CEventLoop::post_event(CObject& receiver, OwnPtr<CEvent>&& event)
     m_queued_events.append({ receiver.make_weak_ptr(), move(event) });
 }
 
-void CEventLoop::wait_for_event()
+void CEventLoop::wait_for_event(WaitMode mode)
 {
     fd_set rfds;
     fd_set wfds;
@@ -182,13 +187,20 @@ void CEventLoop::wait_for_event()
 
     timeval now;
     struct timeval timeout = { 0, 0 };
-    if (!s_timers->is_empty() && queued_events_is_empty) {
-        gettimeofday(&now, nullptr);
-        get_next_timer_expiration(timeout);
-        AK::timeval_sub(&timeout, &now, &timeout);
+    bool should_wait_forever = false;
+    if (mode == WaitMode::WaitForEvents) {
+        if (!s_timers->is_empty() && queued_events_is_empty) {
+            gettimeofday(&now, nullptr);
+            get_next_timer_expiration(timeout);
+            AK::timeval_sub(&timeout, &now, &timeout);
+        } else {
+            should_wait_forever = true;
+        }
+    } else {
+        should_wait_forever = false;
     }
 
-    int rc = select(max_fd + 1, &rfds, &wfds, nullptr, (queued_events_is_empty && s_timers->is_empty()) ? nullptr : &timeout);
+    int rc = select(max_fd + 1, &rfds, &wfds, nullptr, should_wait_forever ? nullptr : &timeout);
     if (rc < 0) {
         ASSERT_NOT_REACHED();
     }

+ 11 - 1
LibCore/CEventLoop.h

@@ -20,6 +20,15 @@ public:
 
     int exec();
 
+    enum class WaitMode {
+        WaitForEvents,
+        PollForEvents,
+    };
+
+    // processe events, generally called by exec() in a loop.
+    // this should really only be used for integrating with other event loops
+    void pump(WaitMode = WaitMode::WaitForEvents);
+
     void post_event(CObject& receiver, OwnPtr<CEvent>&&);
 
     static CEventLoop& main();
@@ -46,13 +55,14 @@ protected:
     virtual void do_processing() { }
 
 private:
-    void wait_for_event();
+    void wait_for_event(WaitMode);
     void get_next_timer_expiration(timeval&);
 
     struct QueuedEvent {
         WeakPtr<CObject> receiver;
         OwnPtr<CEvent> event;
     };
+
     Vector<QueuedEvent, 64> m_queued_events;
 
     bool m_running { false };