// Called when an event is triggered. Either queues the event or finds a link that matches. void MHEngine::EventTriggered(MHRoot *pSource, enum EventType ev, const MHUnion &evData) { MHLOG(MHLogLinks, QString("Event - %1 from %2") .arg(MHLink::EventTypeToString(ev)).arg(pSource->m_ObjectReference.Printable())); switch (ev) { case EventFirstItemPresented: case EventHeadItems: case EventHighlightOff: case EventHighlightOn: case EventIsAvailable: case EventIsDeleted: case EventIsDeselected: case EventIsRunning: case EventIsSelected: case EventIsStopped: case EventItemDeselected: case EventItemSelected: case EventLastItemPresented: case EventTailItems: case EventTestEvent: case EventTokenMovedFrom: case EventTokenMovedTo: // Synchronous events. Fire any links that are waiting. // The UK MHEG describes this as the preferred interpretation. We are checking the link // at the time we generate the event rather than queuing the synchronous events until // this elementary action is complete. That matters if we are processing an elementary action // which will activate or deactivate links. CheckLinks(pSource->m_ObjectReference, ev, evData); break; case EventAnchorFired: case EventAsyncStopped: case EventContentAvailable: case EventCounterTrigger: case EventCursorEnter: case EventCursorLeave: case EventEngineEvent: case EventEntryFieldFull: case EventInteractionCompleted: case EventStreamEvent: case EventStreamPlaying: case EventStreamStopped: case EventTimerFired: case EventUserInput: case EventFocusMoved: // UK MHEG. Generated by HyperText class case EventSliderValueChanged: // UK MHEG. Generated by Slider class default: { // Asynchronous events. Add to the event queue. MHAsynchEvent *pEvent = new MHAsynchEvent; pEvent->pEventSource = pSource; pEvent->eventType = ev; pEvent->eventData = evData; m_EventQueue.enqueue(pEvent); } break; } }
// This is the main loop of the engine. int MHEngine::RunAll() { // Request to boot or reboot if (m_fBooting) { // Reset everything while (!m_ApplicationStack.isEmpty()) { delete m_ApplicationStack.pop(); } while (!m_EventQueue.isEmpty()) { delete m_EventQueue.dequeue(); } while (!m_ExternContentTable.isEmpty()) { delete m_ExternContentTable.takeFirst(); } m_LinkTable.clear(); // UK MHEG applications boot from ~//a or ~//startup. Actually the initial // object can also be explicitly given in the MHObjectRef startObj; startObj.m_nObjectNo = 0; startObj.m_GroupId.Copy(MHOctetString("~//a")); // Launch will block until either it finds the appropriate object and // begins the application or discovers that the file definitely isn't // present in the carousel. It is possible that the object might appear // if one of the containing directories is updated. if (! Launch(startObj)) { startObj.m_GroupId.Copy(MHOctetString("~//startup")); if (! Launch(startObj)) { MHLOG(MHLogNotifications, "NOTE Engine auto-boot failed"); return -1; } } m_fBooting = false; } int nNextTime = 0; do { // Check to see if we need to close. if (m_Context->CheckStop()) { return 0; } // Run queued actions. RunActions(); // Now the action stack is empty process the next asynchronous event. // Processing one event may affect how subsequent events are handled. // Check to see if some files we're waiting for have arrived. // This could result in ContentAvailable events. CheckContentRequests(); // Check the timers. This may result in timer events being raised. nNextTime = CurrentScene() ? CurrentScene()->CheckTimers(this) : 0; if (CurrentApp()) { // The UK MHEG profile allows applications to have timers. int nAppTime = CurrentApp()->CheckTimers(this); if (nAppTime != 0 && (nNextTime == 0 || nAppTime < nNextTime)) { nNextTime = nAppTime; } } if (! m_ExternContentTable.isEmpty()) { // If we have an outstanding request for external content we need to set a timer. if (nNextTime == 0 || nNextTime > CONTENT_CHECK_TIME) { nNextTime = CONTENT_CHECK_TIME; } } if (! m_EventQueue.isEmpty()) { MHAsynchEvent *pEvent = m_EventQueue.dequeue(); MHLOG(MHLogLinks, QString("Asynchronous event dequeued - %1 from %2") .arg(MHLink::EventTypeToString(pEvent->eventType)) .arg(pEvent->pEventSource->m_ObjectReference.Printable())); CheckLinks(pEvent->pEventSource->m_ObjectReference, pEvent->eventType, pEvent->eventData); delete pEvent; } } while (! m_EventQueue.isEmpty() || ! m_ActionStack.isEmpty()); // Redraw the display if necessary. if (! m_redrawRegion.isEmpty()) { m_Context->RequireRedraw(m_redrawRegion); m_redrawRegion = QRegion(); } return nNextTime; }
GDALProxyPoolCacheEntry* GDALDatasetPool::_RefDataset(const char* pszFileName, GDALAccess eAccess) { GDALProxyPoolCacheEntry* cur = firstEntry; GIntBig responsiblePID = GDALGetResponsiblePIDForCurrentThread(); GDALProxyPoolCacheEntry* lastEntryWithZeroRefCount = NULL; while(cur) { GDALProxyPoolCacheEntry* next = cur->next; if (strcmp(cur->pszFileName, pszFileName) == 0 && cur->responsiblePID == responsiblePID) { if (cur != firstEntry) { /* Move to begin */ if (cur->next) cur->next->prev = cur->prev; else lastEntry = cur->prev; cur->prev->next = cur->next; cur->prev = NULL; firstEntry->prev = cur; cur->next = firstEntry; firstEntry = cur; #ifdef DEBUG_PROXY_POOL CheckLinks(); #endif } cur->refCount ++; return cur; } if (cur->refCount == 0) lastEntryWithZeroRefCount = cur; cur = next; } if (currentSize == maxSize) { if (lastEntryWithZeroRefCount == NULL) { CPLError(CE_Failure, CPLE_AppDefined, "Too many threads are running for the current value of the dataset pool size (%d).\n" "or too many proxy datasets are opened in a cascaded way.\n" "Try increasing GDAL_MAX_DATASET_POOL_SIZE.", maxSize); return NULL; } CPLFree(lastEntryWithZeroRefCount->pszFileName); lastEntryWithZeroRefCount->pszFileName = NULL; if (lastEntryWithZeroRefCount->poDS) { /* Close by pretending we are the thread that GDALOpen'ed this */ /* dataset */ GDALSetResponsiblePIDForCurrentThread(lastEntryWithZeroRefCount->responsiblePID); refCountOfDisableRefCount ++; GDALClose(lastEntryWithZeroRefCount->poDS); refCountOfDisableRefCount --; lastEntryWithZeroRefCount->poDS = NULL; GDALSetResponsiblePIDForCurrentThread(responsiblePID); } /* Recycle this entry for the to-be-openeded dataset and */ /* moves it to the top of the list */ if (lastEntryWithZeroRefCount->prev) lastEntryWithZeroRefCount->prev->next = lastEntryWithZeroRefCount->next; else { CPLAssert(0); } if (lastEntryWithZeroRefCount->next) lastEntryWithZeroRefCount->next->prev = lastEntryWithZeroRefCount->prev; else { CPLAssert(lastEntryWithZeroRefCount == lastEntry); lastEntry->prev->next = NULL; lastEntry = lastEntry->prev; } lastEntryWithZeroRefCount->prev = NULL; lastEntryWithZeroRefCount->next = firstEntry; firstEntry->prev = lastEntryWithZeroRefCount; cur = firstEntry = lastEntryWithZeroRefCount; #ifdef DEBUG_PROXY_POOL CheckLinks(); #endif } else { /* Prepend */ cur = (GDALProxyPoolCacheEntry*) CPLMalloc(sizeof(GDALProxyPoolCacheEntry)); if (lastEntry == NULL) lastEntry = cur; cur->prev = NULL; cur->next = firstEntry; if (firstEntry) firstEntry->prev = cur; firstEntry = cur; currentSize ++; #ifdef DEBUG_PROXY_POOL CheckLinks(); #endif } cur->pszFileName = CPLStrdup(pszFileName); cur->responsiblePID = responsiblePID; cur->refCount = 1; refCountOfDisableRefCount ++; cur->poDS = (GDALDataset*) GDALOpen(pszFileName, eAccess); refCountOfDisableRefCount --; return cur; }