RunLoop::EventSourcePtr AsyncPipe::AsyncEventSource() { return RunLoop::EventSource::New([this](RunLoop::EventSource&) { // atomically pull out the event flags here ThreadEvent t = _event.exchange(Wait); if ( t == Wait ) return; if ( (t & Exceptional) == Exceptional ) { // fire our own item if ( _eventDispatchSource != nullptr && _targetRunLoop != nullptr ) { _eventDispatchSource->Signal(); } else if ( bool(_eventHandler) ) { if ( _err != 0 ) { _eventHandler(AsyncEvent::ErrorOccurred, this); } else if ( _eof != 0 ) { _eventHandler(AsyncEvent::EndEncountered, this); } } } bool hasRead = false, hasWritten = false; if ( (t & ReadSpaceAvailable) == ReadSpaceAvailable ) { // data pulled out of here, so room to write there hasRead = true; } if ( (t & DataToWrite) == DataToWrite ) { hasWritten = true; } auto counterpart = _counterpart.lock(); if ( (hasRead || hasWritten) && bool(counterpart) ) { auto source = counterpart->_eventDispatchSource; if ( bool(source) && !source->IsCancelled() ) { source->Signal(); } else { auto handler = counterpart->_eventHandler; if ( bool(handler) ) { if ( hasRead ) { handler(AsyncEvent::HasSpaceAvailable, counterpart.get()); } if ( hasWritten ) { handler(AsyncEvent::HasBytesAvailable, counterpart.get()); } } } } }); }
RunLoop::EventSourcePtr AsyncByteStream::EventDispatchSource() { return RunLoop::EventSource::New([this](RunLoop::EventSource&) { if ( _err != 0 ) { if ( bool(_eventHandler) ) _eventHandler(AsyncEvent::ErrorOccurred, this); if ( bool(_eventDispatchSource) ) _eventDispatchSource->Cancel(); if ( bool(_eventSource) ) _eventSource->Cancel(); return; } if ( _eof ) { if ( bool(_eventHandler) ) _eventHandler(AsyncEvent::EndEncountered, this); if ( bool(_eventDispatchSource) ) _eventDispatchSource->Cancel(); if ( bool(_eventSource) ) _eventSource->Cancel(); return; } if ( BytesAvailable() && bool(_eventHandler) ) _eventHandler(AsyncEvent::HasBytesAvailable, this); if ( SpaceAvailable() && bool(_eventHandler) ) _eventHandler(AsyncEvent::HasSpaceAvailable, this); }); }
void AsyncByteStream::InitAsyncHandler() { if ( _asyncIOThread.joinable() ) throw std::logic_error("The async IO thread already been started"); _asyncIOThread = std::thread([&](){ // atomically pull out the event flags here ThreadEvent t = _event.exchange(Wait); if ( t == Terminate ) { return; } bool hasRead = false, hasWritten = false; uint8_t buf[4096]; if ( (t & ReadSpaceAvailable) == ReadSpaceAvailable ) { std::lock_guard<RingBuffer> _(_ringbuf); size_type read = this->read_for_async(buf, _ringbuf.SpaceAvailable()); if ( read != 0 ) { _ringbuf.WriteBytes(buf, read); hasRead = true; } } if ( (t & DataToWrite) == DataToWrite ) { std::lock_guard<RingBuffer> _(_ringbuf); size_type written = _ringbuf.ReadBytes(buf, _ringbuf.BytesAvailable()); written = this->write_for_async(buf, written); if ( written != 0 ) { // only remove as much as actually went out _ringbuf.RemoveBytes(written); hasWritten = true; } } if ( hasRead ) _eventHandler(AsyncEvent::HasBytesAvailable, this); if ( hasWritten ) _eventHandler(AsyncEvent::HasSpaceAvailable, this); std::unique_lock<std::mutex> __l(_condMutex); _threadSignal.wait(__l, [&](){ return _event != Wait; }); }); }
bool WgTablist::SelectTab( int id ) { WgTab * pTab = _findTab(id); if( pTab == m_pTabSelected ) return true; // Not an error... if( pTab ) { m_pTabSelected = pTab; pTab->m_bAlert = false; // Selecting automatically stops any alert. _resizeTabs(); // fonts have changed _requestRender(); WgEventHandler * pHandler = _eventHandler(); if( pHandler ) { WgItemInfo * p = new WgItemInfo[1]; p->id = pTab->m_id; //TODO: Should set index too (and in the future, a pointer to the widget of the tab). pHandler->QueueEvent( new WgItemsSelectEvent(this, 1, p) ); } return true; } _resizeTabs(); // fonts have changed _requestRender(); return false; }
bool WgPopupLayer::ClosePopup( const WgWidgetPtr& pWidget ) { if( !pWidget || pWidget->Parent() != this || pWidget == m_baseHook.Widget() ) return false; WgEventHandler * pEH = _eventHandler(); WgPopupHook * pHook = (WgPopupHook *) pWidget->_hook(); while( pHook ) { WgPopupHook * p = pHook; pHook = pHook->_next(); if( pEH ) pEH->QueueEvent( new WgPopupClosedEvent( p->_widget(), p->m_pOpener ) ); p->_requestRender(); delete p; } _restoreKeyboardFocus(); return true; }
void WgTablePanel::_updateMarkedRowColumn( int row, int column ) { // Update m_markedRow/Column right away so change has happened before signals are emitted. int oldRow = m_markedRow; int oldColumn = m_markedColumn; m_markedRow = row; m_markedColumn = column; // WgEventHandler * pHandler = _eventHandler(); if( pHandler && (column != oldColumn || row != oldRow) ) { if( oldRow != -1 && oldColumn != -1 ) pHandler->QueueEvent( new WgEvent::TableCellUnmarked(this, oldRow, oldColumn, GetCellContent(oldRow, oldColumn) ) ); if( row != -1 && column != -1 ) pHandler->QueueEvent( new WgEvent::TableCellMarked(this, row, column, GetCellContent(row, column) ) ); } }
void OpenGLWindow::gameLoop(){ SDL_Event event; bool isRunning = true; //start the game loop while(isRunning){ //check and handle for any events while(SDL_PollEvent(&event)){ switch(event.type){ //exit on escape key case SDL_KEYUP: if(event.key.keysym.sym == SDLK_ESCAPE) isRunning = false; break; //exit on close button pressed case SDL_QUIT: isRunning = false; break; //resize on resizing the window case SDL_VIDEORESIZE: setWidth(event.resize.w); setHeight(event.resize.h); setCanvas( SDL_SetVideoMode( width(), height() , 32 , flags() ) ); (*_resizeFunc)(event.resize.w,event.resize.h); break; } //call additional event handler provided by user _eventHandler(event); } //render screen (*_renderFunc)(); } }
void AsyncByteStream::InitAsyncHandler() { if ( _eventSource != nullptr ) throw std::logic_error("This stream is already set up for async operation."); Weak<RingBuffer> weakReadBuf = _readbuf; Weak<RingBuffer> weakWriteBuf = _writebuf; _eventSource = new RunLoop::EventSource([=](RunLoop::EventSource&) { // atomically pull out the event flags here ThreadEvent t = _event.exchange(Wait); bool hasRead = false, hasWritten = false; uint8_t buf[4096]; Shared<RingBuffer> readBuf = weakReadBuf.lock(); Shared<RingBuffer> writeBuf = weakWriteBuf.lock(); if ( (t & ReadSpaceAvailable) == ReadSpaceAvailable && readBuf ) { std::lock_guard<RingBuffer> _(*readBuf); size_type read = this->read_for_async(buf, readBuf->SpaceAvailable()); if ( read != 0 ) { readBuf->WriteBytes(buf, read); hasRead = true; } } if ( (t & DataToWrite) == DataToWrite && writeBuf ) { std::lock_guard<RingBuffer> _(*writeBuf); size_type written = writeBuf->ReadBytes(buf, writeBuf->BytesAvailable()); written = this->write_for_async(buf, written); if ( written != 0 ) { // only remove as much as actually went out writeBuf->RemoveBytes(written); hasWritten = true; } } auto invocation = [this, hasRead, hasWritten] () { if ( hasRead ) _eventHandler(AsyncEvent::HasBytesAvailable, this); if ( hasWritten ) _eventHandler(AsyncEvent::HasSpaceAvailable, this); }; if ( _targetRunLoop != nullptr ) { _targetRunLoop->PerformFunction(invocation); } else { invocation(); } }); if ( _asyncRunLoop == nullptr ) { std::mutex __mut; std::condition_variable __inited; std::unique_lock<std::mutex> __lock(__mut); _asyncIOThread = std::thread([&](){ AsyncByteStream::_asyncRunLoop = RunLoop::CurrentRunLoop(); { std::unique_lock<std::mutex> __(__mut); __inited.notify_all(); } // now run the run loop // only spin an empty run loop a certain amount of time before giving up // and exiting the thread entirely // FIXME: There's a gap here where a race could lose an EventSource addition static constexpr unsigned kMaxEmptyTicks(1000); static constexpr std::chrono::milliseconds kTickLen(10); unsigned __emptyTickCounter = 0; do { RunLoop::ExitReason __r = RunLoop::CurrentRunLoop()->Run(true, std::chrono::seconds(20)); if ( __r == RunLoop::ExitReason::RunFinished ) { if ( ++__emptyTickCounter == kMaxEmptyTicks ) break; // exit the thread // wait a bit and try again std::this_thread::sleep_for(kTickLen); } // by definition not an empty runloop __emptyTickCounter = 0; } while (1); // nullify the global before we quit // deletion isn't necessary, it's done by TLS in run_loop.cpp _asyncRunLoop = nullptr; }); // wait for the runloop to be set __inited.wait(__lock, [&](){return _asyncRunLoop != nullptr;}); } // install the event source into the run loop, then we're all done _asyncRunLoop->AddEventSource(_eventSource); }
bool event(SPEventContext *ec, GdkEvent *e) { return _eventHandler(ec, e); }
RunLoop::EventSourcePtr AsyncByteStream::AsyncEventSource() { weak_ptr<RingBuffer> weakReadBuf = _readbuf; weak_ptr<RingBuffer> weakWriteBuf = _writebuf; return RunLoop::EventSource::New([=](RunLoop::EventSource&) { // atomically pull out the event flags here ThreadEvent t = _event.exchange(Wait); if ( t == Wait ) return; bool hasRead = false, hasWritten = false; uint8_t buf[4096]; shared_ptr<RingBuffer> readBuf = weakReadBuf.lock(); shared_ptr<RingBuffer> writeBuf = weakWriteBuf.lock(); if ( (t & ReadSpaceAvailable) == ReadSpaceAvailable && readBuf ) { std::lock_guard<RingBuffer> _(*readBuf); size_type read = this->read_for_async(buf, readBuf->SpaceAvailable()); if ( read != 0 ) { readBuf->WriteBytes(buf, read); hasRead = true; } else { _eof = true; } } if ( (t & DataToWrite) == DataToWrite && writeBuf ) { std::lock_guard<RingBuffer> _(*writeBuf); size_type written = writeBuf->ReadBytes(buf, writeBuf->BytesAvailable()); written = this->write_for_async(buf, written); if ( written != 0 ) { // only remove as much as actually went out writeBuf->RemoveBytes(written); hasWritten = true; } else { _eof = true; } } if ( _targetRunLoop != nullptr ) { _eventDispatchSource->Signal(); } else if ( bool(_eventHandler) ) { if ( readBuf->HasData() ) _eventHandler(AsyncEvent::HasBytesAvailable, this); if ( writeBuf->HasSpace() ) _eventHandler(AsyncEvent::HasSpaceAvailable, this); } }); }