MythTV  master
Engine.cpp
Go to the documentation of this file.
1 /* Engine.cpp
2 
3  Copyright (C) David C. J. Matthews 2004, 2008 dm at prolingua.co.uk
4 
5  This program is free software; you can redistribute it and/or
6  modify it under the terms of the GNU General Public License
7  as published by the Free Software Foundation; either version 2
8  of the License, or (at your option) any later version.
9 
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with this program; if not, write to the Free Software
17  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
18  Or, point your browser to http://www.gnu.org/copyleft/gpl.html
19 
20 */
21 
22 #include <QStringList>
23 #include <QRegularExpression>
24 #include <QThread>
25 
26 #include "Engine.h"
27 #include "ParseNode.h"
28 #include "ParseBinary.h"
29 #include "ParseText.h"
30 #include "Root.h"
31 #include "Groups.h"
32 #include "ASN1Codes.h"
33 #include "Logging.h"
34 #include "freemheg.h"
35 #include "Visible.h" // For MHInteractible
36 #include "Stream.h"
37 
38 #include <cstdarg>
39 #include <cstdio>
40 #include <cstdlib>
41 
42 // External creation function.
44 {
45  return new MHEngine(context);
46 }
47 
48 MHEngine::MHEngine(MHContext *context): m_context(context)
49 {
50  // Required for BBC Freeview iPlayer
51  auto *pEntry = new MHPSEntry;
52  pEntry->m_FileName.Copy("ram://bbcipstr");
53  pEntry->m_Data.Append(new MHUnion(true)); // Default true
54  // The next value must be true to enable Freeview interaction channel
55  pEntry->m_Data.Append(new MHUnion(true)); // Default false
56  m_persistentStore.Append(pEntry);
57 }
58 
60 {
61  while (!m_applicationStack.isEmpty())
62  {
63  delete m_applicationStack.pop();
64  }
65 
66  while (!m_eventQueue.isEmpty())
67  {
68  delete m_eventQueue.dequeue();
69  }
70 
71  while (!m_externContentTable.isEmpty())
72  {
73  delete m_externContentTable.takeFirst();
74  }
75 }
76 
77 // Check for external content every 2 seconds.
78 #define CONTENT_CHECK_TIME 2000
79 
80 // This is the main loop of the engine.
82 {
83  // Request to boot or reboot
84  if (m_fBooting)
85  {
86  // Reset everything
87  while (!m_applicationStack.isEmpty())
88  {
89  delete m_applicationStack.pop();
90  }
91 
92  while (!m_eventQueue.isEmpty())
93  {
94  delete m_eventQueue.dequeue();
95  }
96 
97  while (!m_externContentTable.isEmpty())
98  {
99  delete m_externContentTable.takeFirst();
100  }
101 
102  m_linkTable.clear();
103 
104  // UK MHEG applications boot from ~//a or ~//startup. Actually the initial
105  // object can also be explicitly given in the
106  MHObjectRef startObj;
107  startObj.m_nObjectNo = 0;
108  startObj.m_groupId.Copy(MHOctetString("~//a"));
109 
110  // Launch will block until either it finds the appropriate object and
111  // begins the application or discovers that the file definitely isn't
112  // present in the carousel. It is possible that the object might appear
113  // if one of the containing directories is updated.
114  if (! Launch(startObj))
115  {
116  startObj.m_groupId.Copy(MHOctetString("~//startup"));
117 
118  if (! Launch(startObj))
119  {
120  MHLOG(MHLogNotifications, "NOTE Engine auto-boot failed");
121  return -1;
122  }
123  }
124 
125  m_fBooting = false;
126  }
127 
128  int nNextTime = 0;
129 
130  do
131  {
132  // Check to see if we need to close.
133  if (m_context->CheckStop())
134  {
135  return 0;
136  }
137 
138  // Run queued actions.
139  RunActions();
140  // Now the action stack is empty process the next asynchronous event.
141  // Processing one event may affect how subsequent events are handled.
142 
143  // Check to see if some files we're waiting for have arrived.
144  // This could result in ContentAvailable events.
146 
147  // Check the timers. This may result in timer events being raised.
148  nNextTime = CurrentScene() ? CurrentScene()->CheckTimers(this) : 0;
149 
150  if (CurrentApp())
151  {
152  // The UK MHEG profile allows applications to have timers.
153  int nAppTime = CurrentApp()->CheckTimers(this);
154 
155  if (nAppTime != 0 && (nNextTime == 0 || nAppTime < nNextTime))
156  {
157  nNextTime = nAppTime;
158  }
159  }
160 
161  if (! m_externContentTable.isEmpty())
162  {
163  // If we have an outstanding request for external content we need to set a timer.
164  if (nNextTime == 0 || nNextTime > CONTENT_CHECK_TIME)
165  {
166  nNextTime = CONTENT_CHECK_TIME;
167  }
168  }
169 
170  if (! m_eventQueue.isEmpty())
171  {
172  MHAsynchEvent *pEvent = m_eventQueue.dequeue();
173  MHLOG(MHLogLinks, QString("Asynchronous event dequeued - %1 from %2")
174  .arg(MHLink::EventTypeToString(pEvent->m_eventType))
175  .arg(pEvent->m_pEventSource->m_ObjectReference.Printable()));
177  pEvent->m_eventType, pEvent->m_eventData);
178  delete pEvent;
179  }
180  }
181  while (! m_eventQueue.isEmpty() || ! m_actionStack.isEmpty());
182 
183  // Redraw the display if necessary.
184  if (! m_redrawRegion.isEmpty())
185  {
187  m_redrawRegion = QRegion();
188  }
189 
190  return nNextTime;
191 }
192 
193 
194 // Convert the parse tree for an application or scene into an object node.
195 MHGroup *MHEngine::ParseProgram(QByteArray &text)
196 {
197  if (text.size() == 0)
198  {
199  return nullptr;
200  }
201 
202  // Look at the first byte to decide whether this is text or binary. Binary
203  // files will begin with 0xA0 or 0xA1, text files with white space, comment ('/')
204  // or curly bracket.
205  // This is only there for testing: all downloaded objects will be in ASN1
206  unsigned char ch = text[0];
207  MHParseBase *parser = nullptr;
208  MHParseNode *pTree = nullptr;
209  MHGroup *pRes = nullptr;
210 
211  if (ch >= 128)
212  {
213  parser = new MHParseBinary(text);
214  }
215  else
216  {
217  parser = new MHParseText(text);
218  }
219 
220  try
221  {
222  // Parse the binary or text.
223  pTree = parser->Parse();
224 
225  switch (pTree->GetTagNo()) // The parse node should be a tagged item.
226  {
227  case C_APPLICATION:
228  pRes = new MHApplication;
229  break;
230  case C_SCENE:
231  pRes = new MHScene;
232  break;
233  default:
234  MHParseNode::Failure("Expected Application or Scene"); // throws exception.
235  }
236 
237  pRes->Initialise(pTree, this); // Convert the parse tree.
238  delete(pTree);
239  delete(parser);
240  }
241  catch (...)
242  {
243  delete(parser);
244  delete(pTree);
245  delete(pRes);
246  throw;
247  }
248 
249  return pRes;
250 }
251 
252 // Determine protocol for a file
254 static EProtocol PathProtocol(const QString& csPath)
255 {
256  if (csPath.isEmpty() || csPath.startsWith("DSM:") || csPath.startsWith("~"))
257  return kProtoDSM;
258  if (csPath.startsWith("hybrid:"))
259  return kProtoHybrid;
260  if (csPath.startsWith("http:") || csPath.startsWith("https:"))
261  return kProtoHTTP;
262  if (csPath.startsWith("CI:"))
263  return kProtoCI;
264 
265  int firstColon = csPath.indexOf(':');
266  int firstSlash = csPath.indexOf('/');
267  if (firstColon > 0 && firstSlash > 0 && firstColon < firstSlash)
268  return kProtoUnknown;
269 
270  return kProtoDSM;
271 }
272 
273 // Launch and Spawn
274 bool MHEngine::Launch(const MHObjectRef &target, bool fIsSpawn)
275 {
276  if (m_fInTransition)
277  {
278  MHLOG(MHLogWarning, "WARN Launch during transition - ignoring");
279  return false;
280  }
281 
282  if (target.m_groupId.Size() == 0) return false; // No file name.
283  QString csPath = GetPathName(target.m_groupId); // Get path relative to root.
284  MHLOG(MHLogNotifications, "NOTE Launching " + csPath);
285 
286  // Check that the file exists before we commit to the transition.
287  // This may block if we cannot be sure whether the object is present.
288  QByteArray text;
289  if (! m_context->GetCarouselData(csPath, text))
290  {
291  if (!m_fBooting)
292  EngineEvent(2); // GroupIDRefError
293  MHLOG(MHLogWarning, "WARN Launch not found " + csPath);
294  return false;
295  }
296 
297  auto *pProgram = dynamic_cast<MHApplication*>(ParseProgram(text));
298  if (! pProgram)
299  {
300  MHLOG(MHLogWarning, "Empty application");
301  return false;
302  }
303  if (! pProgram->m_fIsApp)
304  {
305  MHLOG(MHLogWarning, "Expected an application");
306  delete pProgram;
307  return false;
308  }
309  if ((gMHLogoptions & MHLogScenes) && gMHLogStream != nullptr) // Print it so we know what's going on.
310  {
311  pProgram->PrintMe(gMHLogStream, 0);
312  }
313 
314  // Clear the action queue of anything pending.
315  m_actionStack.clear();
316 
317  m_fInTransition = true; // Starting a transition
318 
319  try
320  {
321  if (CurrentApp())
322  {
323  if (fIsSpawn) // Run the CloseDown actions.
324  {
325  AddActions(CurrentApp()->m_closeDown);
326  RunActions();
327  }
328 
329  if (CurrentScene())
330  {
331  CurrentScene()->Destruction(this);
332  }
333 
334  CurrentApp()->Destruction(this);
335 
336  if (!fIsSpawn)
337  {
338  delete m_applicationStack.pop(); // Pop and delete the current app.
339  }
340  }
341 
342  // Save the path we use for this app.
343  pProgram->m_path = csPath; // Record the path
344  int nPos = pProgram->m_path.lastIndexOf('/');
345 
346  if (nPos < 0)
347  {
348  pProgram->m_path = "";
349  }
350  else
351  {
352  pProgram->m_path = pProgram->m_path.left(nPos);
353  }
354 
355  // Have now got the application.
356  m_applicationStack.push(pProgram);
357 
358  // This isn't in the standard as far as I can tell but we have to do this because
359  // we may have events referring to the old application.
360  while (!m_eventQueue.isEmpty())
361  {
362  delete m_eventQueue.dequeue();
363  }
364 
365  // Activate the application. ....
366  CurrentApp()->Activation(this);
367  m_fInTransition = false; // The transition is complete
368  MHLOG(MHLogNotifications, "NOTE Launch completed OK");
369  return true;
370  }
371  catch (...)
372  {
373  m_fInTransition = false; // The transition is complete
374  return false;
375  }
376 }
377 
379 {
380  if (m_fInTransition)
381  {
382  MHLOG(MHLogWarning, "WARN Quit during transition - ignoring");
383  return;
384  }
385 
386  m_fInTransition = true; // Starting a transition
387 
388  if (CurrentScene())
389  {
390  CurrentScene()->Destruction(this);
391  }
392 
393  CurrentApp()->Destruction(this);
394 
395  // This isn't in the standard as far as I can tell but we have to do this because
396  // we may have events referring to the old application.
397  while (!m_eventQueue.isEmpty())
398  {
399  delete m_eventQueue.dequeue();
400  }
401 
402  delete m_applicationStack.pop();
403 
404  // If the stack is now empty we return to boot mode.
405  if (m_applicationStack.isEmpty())
406  {
407  m_fBooting = true;
408  }
409  else
410  {
411  CurrentApp()->m_fRestarting = true;
412  CurrentApp()->Activation(this); // This will do any OnRestart actions.
413  // Note - this doesn't activate the previously active scene.
414  }
415 
416  m_fInTransition = false; // The transition is complete
417 }
418 
420 {
421  if (m_fInTransition)
422  {
423  // TransitionTo is not allowed in OnStartUp or OnCloseDown actions.
424  MHLOG(MHLogWarning, "WARN TransitionTo during transition - ignoring");
425  return;
426  }
427 
428  if (target.m_groupId.Size() == 0)
429  {
430  return; // No file name.
431  }
432 
433  QString csPath = GetPathName(target.m_groupId);
434 
435  // Check that the file exists before we commit to the transition.
436  // This may block if we cannot be sure whether the object is present.
437  QByteArray text;
438  if (! m_context->GetCarouselData(csPath, text)) {
439  EngineEvent(2); // GroupIDRefError
440  return;
441  }
442 
443  // Parse and run the file.
444  MHGroup *pProgram = ParseProgram(text);
445 
446  if (!pProgram )
447  MHERROR("Empty scene");
448 
449  if (pProgram->m_fIsApp)
450  {
451  delete pProgram;
452  MHERROR("Expected a scene");
453  }
454 
455  // Clear the action queue of anything pending.
456  m_actionStack.clear();
457 
458  // At this point we have managed to load the scene.
459  // Deactivate any non-shared ingredients in the application.
460  MHApplication *pApp = CurrentApp();
461 
462  for (int i = pApp->m_items.Size(); i > 0; i--)
463  {
464  MHIngredient *pItem = pApp->m_items.GetAt(i - 1);
465 
466  if (! pItem->IsShared())
467  {
468  pItem->Deactivation(this); // This does not remove them from the display stack.
469  }
470  }
471 
472  m_fInTransition = true; // TransitionTo etc are not allowed.
473 
474  if (pApp->m_pCurrentScene)
475  {
476  pApp->m_pCurrentScene->Deactivation(this); // This may involve a call to RunActions
477  pApp->m_pCurrentScene->Destruction(this);
478  }
479 
480  // Everything that belongs to the previous scene should have been removed from the display stack.
481 
482  // At this point we may have added actions to the queue as a result of synchronous
483  // events during the deactivation.
484 
485  // Remove any events from the asynch event queue unless they derive from
486  // the application itself or a shared ingredient.
487 
488  // This was causing crashes with leftover events being invalid.
489  // Changed to clear all events at this point.
490 
491  while (!m_eventQueue.isEmpty())
492  delete m_eventQueue.dequeue();
493 
494  // Can now actually delete the old scene.
495  if (pApp->m_pCurrentScene)
496  {
497  delete(pApp->m_pCurrentScene);
498  pApp->m_pCurrentScene = nullptr;
499  }
500 
501  m_interacting = nullptr;
502 
503  // Switch to the new scene.
504  CurrentApp()->m_pCurrentScene = dynamic_cast< MHScene* >(pProgram);
505  SetInputRegister(CurrentScene()->m_nEventReg);
506  m_redrawRegion = QRegion(0, 0, CurrentScene()->m_nSceneCoordX, CurrentScene()->m_nSceneCoordY); // Redraw the whole screen
507 
508  if ((gMHLogoptions & MHLogScenes) && gMHLogStream != nullptr) // Print it so we know what's going on.
509  {
510  pProgram->PrintMe(gMHLogStream, 0);
511  }
512 
513  pProgram->Preparation(this);
514  pProgram->Activation(this);
515  m_fInTransition = false; // The transition is complete
516 }
517 
519 {
520  m_context->SetInputRegister(nReg); // Enable the appropriate buttons
521 }
522 
523 // Create a canonical path name. The rules are given in the UK MHEG document.
525 {
526  if (str.Size() == 0)
527  return QString();
528 
529  QString csPath = QString::fromUtf8((const char *)str.Bytes(), str.Size());
530  switch (PathProtocol(csPath))
531  {
532  default:
533  case kProtoUnknown:
534  case kProtoHybrid:
535  case kProtoHTTP:
536  case kProtoCI:
537  return csPath;
538  case kProtoDSM:
539  break;
540  }
541 
542  if (csPath.startsWith("DSM:"))
543  csPath = csPath.mid(4); // Remove DSM:
544  else if (csPath.startsWith("~"))
545  csPath = csPath.mid(1); // Remove ~
546  if (!csPath.startsWith("//"))
547  {
548  // Add the current application's path name
549  if (CurrentApp())
550  {
551  csPath = CurrentApp()->m_path + csPath;
552  }
553  }
554 
555  // Remove any occurrences of x/../
556  int nPos = -1;
557 
558  while ((nPos = csPath.indexOf("/../")) >= 0)
559  {
560  int nEnd = nPos + 4;
561 
562  while (nPos >= 1 && csPath[nPos-1] != '/')
563  {
564  nPos--;
565  }
566 
567  csPath = csPath.left(nPos) + csPath.mid(nEnd);
568  }
569 
570  return csPath;
571 }
572 
573 // Look up an object. In most cases we just want to fail if the object isn't found.
574 MHRoot *MHEngine::FindObject(const MHObjectRef &oRef, bool failOnNotFound)
575 {
576  // It should match either the application or the scene.
577  MHGroup *pSearch = nullptr;
578  MHGroup *pScene = CurrentScene();
579  MHGroup *pApp = CurrentApp();
580 
581  if (pScene && GetPathName(pScene->m_ObjectReference.m_groupId) == GetPathName(oRef.m_groupId))
582  {
583  pSearch = pScene;
584  }
585  else if (pApp && GetPathName(pApp->m_ObjectReference.m_groupId) == GetPathName(oRef.m_groupId))
586  {
587  pSearch = pApp;
588  }
589 
590  if (pSearch)
591  {
592  MHRoot *pItem = pSearch->FindByObjectNo(oRef.m_nObjectNo);
593 
594  if (pItem)
595  {
596  return pItem;
597  }
598  }
599 
600  if (failOnNotFound)
601  {
602  // I've seen at least one case where MHEG code has quite deliberately referred to
603  // an object that may or may not exist at a particular time.
604  // Another case was a call to CallActionSlot with an object reference variable
605  // that had been initialised to zero.
606  MHLOG(MHLogWarning, QString("WARN Reference %1 not found").arg(oRef.m_nObjectNo));
607  throw "FindObject failed";
608  }
609 
610  return nullptr; // If we don't generate an error.
611 }
612 
613 // Run queued actions.
615 {
616  while (! m_actionStack.isEmpty())
617  {
618  // Remove the first action.
619  MHElemAction *pAction = m_actionStack.pop();
620 
621  // Run it. If it fails and throws an exception catch it and continue with the next.
622  try
623  {
624  if ((gMHLogoptions & MHLogActions) && gMHLogStream != nullptr) // Debugging
625  {
626  fprintf(gMHLogStream, "[freemheg] Action - ");
627  pAction->PrintMe(gMHLogStream, 0);
628  fflush(gMHLogStream);
629  }
630 
631  pAction->Perform(this);
632  }
633  catch (...)
634  {
635  }
636  }
637 }
638 
639 // Called when an event is triggered. Either queues the event or finds a link that matches.
640 void MHEngine::EventTriggered(MHRoot *pSource, enum EventType ev, const MHUnion &evData)
641 {
642  MHLOG(MHLogLinks, QString("Event - %1 from %2")
644 
645  switch (ev)
646  {
648  case EventHeadItems:
649  case EventHighlightOff:
650  case EventHighlightOn:
651  case EventIsAvailable:
652  case EventIsDeleted:
653  case EventIsDeselected:
654  case EventIsRunning:
655  case EventIsSelected:
656  case EventIsStopped:
657  case EventItemDeselected:
658  case EventItemSelected:
660  case EventTailItems:
661  case EventTestEvent:
662  case EventTokenMovedFrom:
663  case EventTokenMovedTo:
664  // Synchronous events. Fire any links that are waiting.
665  // The UK MHEG describes this as the preferred interpretation. We are checking the link
666  // at the time we generate the event rather than queuing the synchronous events until
667  // this elementary action is complete. That matters if we are processing an elementary action
668  // which will activate or deactivate links.
669  CheckLinks(pSource->m_ObjectReference, ev, evData);
670  break;
671  case EventAnchorFired:
672  case EventAsyncStopped:
674  case EventCounterTrigger:
675  case EventCursorEnter:
676  case EventCursorLeave:
677  case EventEngineEvent:
678  case EventEntryFieldFull:
680  case EventStreamEvent:
681  case EventStreamPlaying:
682  case EventStreamStopped:
683  case EventTimerFired:
684  case EventUserInput:
685  case EventFocusMoved: // UK MHEG. Generated by HyperText class
686  case EventSliderValueChanged: // UK MHEG. Generated by Slider class
687  default:
688  {
689  // Asynchronous events. Add to the event queue.
690  auto *pEvent = new MHAsynchEvent;
691  pEvent->m_pEventSource = pSource;
692  pEvent->m_eventType = ev;
693  pEvent->m_eventData = evData;
694  m_eventQueue.enqueue(pEvent);
695  }
696  break;
697  }
698 }
699 
700 
701 // TO CHECK: If two actions both depend on the same event is the order in which the links are
702 // searched defined? This processes items in the order in which they were activated rather
703 // than their static position in the group.
704 
705 // Check all the links in the application and scene and fire any that match this event.
706 void MHEngine::CheckLinks(const MHObjectRef &sourceRef, enum EventType ev, const MHUnion &un)
707 {
708  for (auto *link : qAsConst(m_linkTable))
709  link->MatchEvent(sourceRef, ev, un, this);
710 }
711 
712 // Add and remove links to and from the active link table.
714 {
715  m_linkTable.append(pLink);
716 }
717 
719 {
720  m_linkTable.removeAll(pLink);
721 }
722 
723 // Called when a link fires to add the actions to the action stack.
725 {
726  // Put them on the stack in reverse order so that we will pop the first.
727  for (int i = actions.Size(); i > 0; i--)
728  {
729  m_actionStack.push(actions.GetAt(i - 1));
730  }
731 }
732 
733 // Add a visible to the display stack if it isn't already there.
735 {
736  if (CurrentApp()->FindOnStack(pVis) != -1)
737  {
738  return; // Return if it's already there.
739  }
740 
742  Redraw(pVis->GetVisibleArea()); // Request a redraw
743 }
744 
745 // Remove a visible from the display stack if it is there.
747 {
748  int nPos = CurrentApp()->FindOnStack(pVis);
749 
750  if (nPos == -1)
751  {
752  return;
753  }
754 
756  Redraw(pVis->GetVisibleArea()); // Request a redraw
757 }
758 
759 // Functions to alter the Z-order.
761 {
762  int nPos = CurrentApp()->FindOnStack(p);
763 
764  if (nPos == -1)
765  {
766  return; // If it's not there do nothing
767  }
768 
769  auto *pVis = (MHVisible *)p; // Can now safely cast it.
770  CurrentApp()->m_displayStack.RemoveAt(nPos); // Remove it from its present posn
771  CurrentApp()->m_displayStack.Append(pVis); // Push it on the top.
772  Redraw(pVis->GetVisibleArea()); // Request a redraw
773 }
774 
776 {
777  int nPos = CurrentApp()->FindOnStack(p);
778 
779  if (nPos == -1)
780  {
781  return; // If it's not there do nothing
782  }
783 
784  auto *pVis = (MHVisible *)p; // Can now safely cast it.
785  CurrentApp()->m_displayStack.RemoveAt(nPos); // Remove it from its present posn
786  CurrentApp()->m_displayStack.InsertAt(pVis, 0); // Put it on the bottom.
787  Redraw(pVis->GetVisibleArea()); // Request a redraw
788 }
789 
790 void MHEngine::PutBefore(const MHRoot *p, const MHRoot *pRef)
791 {
792  int nPos = CurrentApp()->FindOnStack(p);
793 
794  if (nPos == -1)
795  {
796  return; // If it's not there do nothing
797  }
798 
799  auto *pVis = (MHVisible *)p; // Can now safely cast it.
800  int nRef = CurrentApp()->FindOnStack(pRef);
801 
802  if (nRef == -1)
803  {
804  return; // If the reference visible isn't there do nothing.
805  }
806 
808 
809  if (nRef >= nPos)
810  {
811  nRef--; // The position of the reference may have shifted
812  }
813 
814  CurrentApp()->m_displayStack.InsertAt(pVis, nRef + 1);
815  // Redraw the area occupied by the moved item. We might be able to reduce
816  // the area to be redrawn by looking at the way it is affected by other items
817  // in the stack. We could also see whether it's currently active.
818  Redraw(pVis->GetVisibleArea()); // Request a redraw
819 }
820 
821 void MHEngine::PutBehind(const MHRoot *p, const MHRoot *pRef)
822 {
823  int nPos = CurrentApp()->FindOnStack(p);
824 
825  if (nPos == -1)
826  {
827  return; // If it's not there do nothing
828  }
829 
830  int nRef = CurrentApp()->FindOnStack(pRef);
831 
832  if (nRef == -1)
833  {
834  return; // If the reference visible isn't there do nothing.
835  }
836 
837  auto *pVis = (MHVisible *)p; // Can now safely cast it.
839 
840  if (nRef >= nPos)
841  {
842  nRef--; // The position of the reference may have shifted
843  }
844 
845  CurrentApp()->m_displayStack.InsertAt(pVis, nRef); // Shift the reference and anything above up.
846  Redraw(pVis->GetVisibleArea()); // Request a redraw
847 }
848 
849 // Draw a region of the screen. This attempts to minimise the drawing by eliminating items
850 // that are completely obscured by items above them. We have to take into account the
851 // transparency of items since items higher up the stack may be semi-transparent.
852 void MHEngine::DrawRegion(const QRegion& toDraw, int nStackPos)
853 {
854  if (toDraw.isEmpty())
855  {
856  return; // Nothing left to draw.
857  }
858 
859  while (nStackPos >= 0)
860  {
861  MHVisible *pItem = CurrentApp()->m_displayStack.GetAt(nStackPos);
862  // Work out how much of the area we want to draw is included in this visible.
863  // The visible area will be empty if the item is transparent or not active.
864  QRegion drawArea = pItem->GetVisibleArea() & toDraw;
865 
866  if (! drawArea.isEmpty()) // It contributes something.
867  {
868  // Remove the opaque area of this item from the region we have left.
869  // If this item is (semi-)transparent this will not remove anything.
870  QRegion newDraw = toDraw - pItem->GetOpaqueArea();
871  DrawRegion(newDraw, nStackPos - 1); // Do the items further down if any.
872  // Now we've drawn anything below this we can draw this item on top.
873  pItem->Display(this);
874  return;
875  }
876 
877  nStackPos--;
878  }
879 
880  // We've drawn all the visibles and there's still some undrawn area.
881  // Fill it with black.
882  m_context->DrawBackground(toDraw);
883 }
884 
885 // Redraw an area of the display. This will be called via the context from Redraw.
886 void MHEngine::DrawDisplay(QRegion toDraw)
887 {
888  if (m_fBooting)
889  {
890  return;
891  }
892 
893  int nTopStack = CurrentApp() == nullptr ? -1 : CurrentApp()->m_displayStack.Size() - 1;
894  DrawRegion(toDraw, nTopStack);
895 }
896 
897 // An area of the screen needs to be redrawn. We simply remember this and redraw it
898 // in one go when the timer expires.
899 void MHEngine::Redraw(const QRegion& region)
900 {
901  m_redrawRegion += region;
902 }
903 
904 // Called to decrement the lock count.
906 {
907  if (CurrentApp()->m_nLockCount > 0)
908  {
910  }
911 }
912 
913 
914 // Called from the windowing application, this generates a user event as the result of a button push.
916 {
917  MHScene *pScene = CurrentScene();
918 
919  if (! pScene)
920  {
921  return;
922  }
923 
924  // Various keys generate engine events as well as user events.
925  // These are generated before the user events and even if there
926  // is an interactible.
927  switch (nCode)
928  {
929  case 104:
930  case 105: // Text key
931  EngineEvent(4);
932  break;
933  case 16: // Text Exit/Cancel key
934  case 100: // Red
935  case 101: // Green
936  case 102: // Yellow
937  case 103: // Blue
938  case 300: // EPG
939  EngineEvent(nCode);
940  break;
941  }
942 
943  // If we are interacting with an interactible send the key
944  // there otherwise generate a user event.
945  if (m_interacting)
946  {
947  m_interacting->KeyEvent(this, nCode);
948  }
949  else
950  {
951  EventTriggered(pScene, EventUserInput, nCode);
952  }
953 }
954 
955 void MHEngine::EngineEvent(int nCode)
956 {
957  if (CurrentApp())
959  else if (!m_fBooting)
960  MHLOG(MHLogWarning, QString("WARN EngineEvent %1 but no app").arg(nCode));
961 }
962 
963 void MHEngine::StreamStarted(MHStream *stream, bool bStarted)
964 {
966 }
967 
968 // Called by an ingredient wanting external content.
970 {
971  // It seems that some MHEG applications contain active ingredients with empty contents
972  // This isn't correct but we simply ignore that.
973  if (! pRequester->m_contentRef.IsSet())
974  {
975  return;
976  }
977 
978  // Remove any existing content requests for this ingredient.
979  CancelExternalContentRequest(pRequester);
980 
981  QString csPath = GetPathName(pRequester->m_contentRef.m_contentRef);
982 
983  if (csPath.isEmpty())
984  {
985  MHLOG(MHLogWarning, "RequestExternalContent empty path");
986  return;
987  }
988 
989  if (m_context->CheckCarouselObject(csPath))
990  {
991  // Available now - pass it to the ingredient.
992  QByteArray text;
993  if (m_context->GetCarouselData(csPath, text))
994  {
995  // If the content is not recognized catch the exception and continue
996  try
997  {
998  pRequester->ContentArrived(
999  reinterpret_cast< const unsigned char * >(text.constData()),
1000  text.size(), this);
1001  }
1002  catch (...)
1003  {}
1004  }
1005  else
1006  {
1007  MHLOG(MHLogWarning, QString("WARN No file content %1 <= %2")
1008  .arg(pRequester->m_ObjectReference.Printable()).arg(csPath));
1009  if (kProtoHTTP == PathProtocol(csPath))
1010  EngineEvent(203); // 203=RemoteNetworkError if 404 reply
1011  EngineEvent(3); // ContentRefError
1012  }
1013  }
1014  else
1015  {
1016  // Need to record this and check later.
1017  MHLOG(MHLogNotifications, QString("Waiting for %1 <= %2")
1018  .arg(pRequester->m_ObjectReference.Printable()).arg(csPath.left(128)) );
1019  auto *pContent = new MHExternContent;
1020  pContent->m_FileName = csPath;
1021  pContent->m_pRequester = pRequester;
1022  pContent->m_time.start();
1023  m_externContentTable.append(pContent);
1024  }
1025 }
1026 
1027 // Remove any pending requests from the queue.
1029 {
1030  QList<MHExternContent *>::iterator it = m_externContentTable.begin();
1031 
1032  while (it != m_externContentTable.end())
1033  {
1034  MHExternContent *pContent = *it;
1035 
1036  if (pContent->m_pRequester == pRequester)
1037  {
1038  MHLOG(MHLogNotifications, QString("Cancelled wait for %1")
1039  .arg(pRequester->m_ObjectReference.Printable()) );
1040  it = m_externContentTable.erase(it);
1041  delete pContent;
1042  return;
1043  }
1044  ++it;
1045  }
1046 }
1047 
1048 // See if we can satisfy any of the outstanding requests.
1050 {
1051  QList<MHExternContent*>::iterator it = m_externContentTable.begin();
1052  while (it != m_externContentTable.end())
1053  {
1054  MHExternContent *pContent = *it;
1055  if (m_context->CheckCarouselObject(pContent->m_FileName))
1056  {
1057  // Remove from the list.
1058  it = m_externContentTable.erase(it);
1059 
1060  QByteArray text;
1061  if (m_context->GetCarouselData(pContent->m_FileName, text))
1062  {
1063  MHLOG(MHLogNotifications, QString("Received %1 len %2")
1065  .arg(text.size()) );
1066  // If the content is not recognized catch the exception and continue
1067  try
1068  {
1069  pContent->m_pRequester->ContentArrived(
1070  reinterpret_cast< const unsigned char * >(text.constData()),
1071  text.size(), this);
1072  }
1073  catch (...)
1074  {}
1075  }
1076  else
1077  {
1078  MHLOG(MHLogWarning, QString("WARN No file content %1 <= %2")
1080  .arg(pContent->m_FileName));
1081  if (kProtoHTTP == PathProtocol(pContent->m_FileName))
1082  EngineEvent(203); // 203=RemoteNetworkError if 404 reply
1083  EngineEvent(3); // ContentRefError
1084  }
1085 
1086  delete pContent;
1087  }
1088  else if (pContent->m_time.elapsed() > 60000) // TODO Get this from carousel
1089  {
1090  // Remove from the list.
1091  it = m_externContentTable.erase(it);
1092 
1093  MHLOG(MHLogWarning, QString("WARN File timed out %1 <= %2")
1095  .arg(pContent->m_FileName));
1096 
1097  if (kProtoHTTP == PathProtocol(pContent->m_FileName))
1098  EngineEvent(203); // 203=RemoteNetworkError if 404 reply
1099  EngineEvent(3); // ContentRefError
1100 
1101  delete pContent;
1102  }
1103  else
1104  {
1105  ++it;
1106  }
1107  }
1108 }
1109 
1110 bool MHEngine::LoadStorePersistent(bool fIsLoad, const MHOctetString &fileName, const MHSequence<MHObjectRef *> &variables)
1111 {
1112  QString const csFile = QString::fromUtf8(
1113  (const char *)fileName.Bytes(), fileName.Size() );
1114 
1115  // See if there is an entry there already.
1116  MHPSEntry *pEntry = nullptr;
1117  int i = 0;
1118 
1119  for (i = 0; i < m_persistentStore.Size(); i++)
1120  {
1121  pEntry = m_persistentStore.GetAt(i);
1122 
1123  if (pEntry->m_FileName.Equal(fileName))
1124  {
1125  break;
1126  }
1127  }
1128 
1129  if (i == m_persistentStore.Size()) // Not there.
1130  {
1131  // If we're loading then we've failed.
1132  if (fIsLoad)
1133  {
1134  MHLOG(MHLogNotifications, QString(
1135  "Load Persistent(%1) #%2: no such file")
1136  .arg(csFile).arg(variables.Size()) );
1137  return false;
1138  }
1139 
1140  // If we're storing we make a new entry.
1141  pEntry = new MHPSEntry;
1142  pEntry->m_FileName.Copy(fileName);
1143  m_persistentStore.Append(pEntry);
1144  }
1145 
1146  // This should never happen
1147  if (pEntry == nullptr)
1148  return false;
1149 
1150  if (fIsLoad) // Copy the data into the variables.
1151  {
1152  // Check that we have sufficient data before we continue?
1153  if (pEntry->m_Data.Size() < variables.Size())
1154  {
1155  MHLOG(MHLogWarning, QString(
1156  "Load Persistent(%1): size mismatch").arg(csFile));
1157  return false;
1158  }
1159 
1160  for (i = 0; i < variables.Size(); i++)
1161  {
1162  MHUnion *pValue = pEntry->m_Data.GetAt(i);
1163  MHLOG(MHLogNotifications, QString("Load Persistent(%1) #%2=%3")
1164  .arg(csFile).arg(i).arg(pValue->Printable()) );
1165  FindObject(*(variables.GetAt(i)))->SetVariableValue(*pValue);
1166  }
1167  }
1168 
1169  else // Get the data from the variables into the store.
1170  {
1171  // Remove any existing data.
1172  while (pEntry->m_Data.Size() != 0)
1173  {
1174  pEntry->m_Data.RemoveAt(0);
1175  }
1176 
1177  // Set the store to the values.
1178  for (i = 0; i < variables.Size(); i++)
1179  {
1180  auto *pValue = new MHUnion;
1181  pEntry->m_Data.Append(pValue);
1182  FindObject(*(variables.GetAt(i)))->GetVariableValue(*pValue, this);
1183  MHLOG(MHLogNotifications, QString("Store Persistent(%1) %2=>#%3")
1184  .arg(csFile).arg(pValue->Printable()).arg(i) );
1185  }
1186  }
1187 
1188  return true;
1189 }
1190 
1191 // Find out what we support.
1193 {
1194  QString csFeat = QString::fromUtf8((const char *)feature.Bytes(), feature.Size());
1195  QStringList strings = csFeat.split(QRegularExpression(R"([\‍(\,\)])"));
1196 
1197  MHLOG(MHLogNotifications, "NOTE GetEngineSupport " + csFeat);
1198 
1199  if (strings[0] == "ApplicationStacking" || strings[0] == "ASt")
1200  {
1201  return true;
1202  }
1203 
1204  // We're required to support cloning for Text, Bitmap and Rectangle.
1205  if (strings[0] == "Cloning" || strings[0] == "Clo")
1206  {
1207  return true;
1208  }
1209 
1210  if (strings[0] == "SceneCoordinateSystem" || strings[0] == "SCS")
1211  {
1212  return strings.count() >= 3 && strings[1] == "720" && strings[2] == "576";
1213 
1214  // I've also seen SceneCoordinateSystem(1,1)
1215  }
1216 
1217  if (strings[0] == "MultipleAudioStreams" || strings[0] == "MAS")
1218  {
1219  return strings.count() >= 2 && (strings[1] == "0" || strings[1] == "1");
1220  }
1221 
1222  if (strings[0] == "MultipleVideoStreams" || strings[0] == "MVS")
1223  {
1224  return strings.count() >= 2 && (strings[1] == "0" || strings[1] == "1");
1225  }
1226 
1227  // We're supposed to return true for all values of N
1228  if (strings[0] == "OverlappingVisibles" || strings[0] == "OvV")
1229  {
1230  return true;
1231  }
1232 
1233  if (strings[0] == "SceneAspectRatio" || strings[0] == "SAR")
1234  {
1235  if (strings.count() < 3)
1236  {
1237  return false;
1238  }
1239  return (strings[1] == "4" && strings[2] == "3") || (strings[1] == "16" && strings[2] == "9");
1240  }
1241 
1242  // We're supposed to support these at least. May also support(10,1440,1152)
1243  if (strings[0] == "VideoScaling" || strings[0] == "VSc")
1244  {
1245  if (strings.count() < 4 || strings[1] != "10")
1246  {
1247  return false;
1248  }
1249  return (strings[2] == "720" && strings[3] == "576") || (strings[2] == "360" && strings[3] == "288");
1250  }
1251 
1252  if (strings[0] == "BitmapScaling" || strings[0] == "BSc")
1253  {
1254  if (strings.count() < 4 || strings[1] != "2")
1255  {
1256  return false;
1257  }
1258  return (strings[2] == "720" && strings[3] == "576") || (strings[2] == "360" && strings[3] == "288");
1259  }
1260 
1261  // I think we only support the video fully on screen
1262  if (strings[0] == "VideoDecodeOffset" || strings[0] == "VDO")
1263  {
1264  return strings.count() >= 3 && strings[1] == "10" && strings[1] == "0";
1265  }
1266 
1267  // We support bitmaps that are partially off screen (don't we?)
1268  if (strings[0] == "BitmapDecodeOffset" || strings[0] == "BDO")
1269  {
1270  if (strings.count() >= 3 && strings[1] == "2" && (strings[2] == "0" || strings[2] == "1"))
1271  {
1272  return true;
1273  }
1274  if (strings.count() >= 2 && (strings[1] == "4" || strings[1] == "6"))
1275  {
1276  return true;
1277  }
1278  return false;
1279  }
1280 
1281  if (strings[0] == "UKEngineProfile" || strings[0] == "UniversalEngineProfile" || strings[0] == "UEP")
1282  {
1283  if (strings.count() < 2)
1284  {
1285  return false;
1286  }
1287 
1288  if (strings[1] == MHEGEngineProviderIdString)
1289  {
1290  return true;
1291  }
1292 
1293  if (strings[1] == m_context->GetReceiverId())
1294  {
1295  return true;
1296  }
1297 
1298  if (strings[1] == m_context->GetDSMCCId())
1299  {
1300  return true;
1301  }
1302 
1303  // The UK profile 1.06 seems a bit confused on this point. It is not clear whether
1304  // we are supposed to return true for UKEngineProfile(2) or not.
1305  if (strings[1] == "2")
1306  return true;
1307  if (strings[1] == "1")
1308  return true;
1309  // 'The Space' on Freeview checks this...
1310  if (strings[1] == "PANT11001")
1311  return true;
1312  // Irish DTT expects "1285". From ETSI ES 202 184: UEP(1285) means the receiver has been verified as fully conformant.
1313  if (strings[1] == "1285")
1314  return true;
1315 
1316  return false;
1317  }
1318 
1319  // InteractionChannelExtension.
1320  if (strings[0] == "ICProfile" || strings[0] == "ICP") {
1321  if (strings.count() < 2) return false;
1322  if (strings[1] == "0")
1323  return true; // InteractionChannelExtension.
1324  if (strings[1] == "1")
1325  return true; // ICStreamingExtension. This is a deliberate lie
1326  return false;
1327  }
1328 
1329  if (strings[0] == "HDExtension" || strings[0] == "HDE") {
1330  if (strings.count() < 2) return false;
1331  if (strings[1] == "0")
1332  return false; // HDVideoExtension.
1333  if (strings[1] == "1")
1334  return false; // HDGraphicsPlaneExtension
1335  return false;
1336  }
1337  if (strings[0] == "HDGraphicsPlaneExtension" || strings[0] == "HDG") {
1338  if (strings.count() < 2) return false;
1339  // true if HDGraphicsPlaneExtension
1340  return strings[1] == "0";
1341  }
1342 
1343  // Otherwise return false.
1344  return false;
1345 }
1346 
1347 // Get the various defaults. These are extracted from the current app or the (UK) MHEG defaults.
1349 {
1350  MHApplication *pApp = CurrentApp();
1351 
1352  if (pApp && pApp->m_nCharSet > 0)
1353  {
1354  return pApp->m_nCharSet;
1355  }
1356  return 10; // UK MHEG default.
1357 }
1358 
1360 {
1361  MHApplication *pApp = CurrentApp();
1362 
1363  if (pApp && pApp->m_bgColour.IsSet())
1364  {
1365  colour.Copy(pApp->m_bgColour);
1366  }
1367  else
1368  {
1369  colour.SetFromString("\000\000\000\377", 4); // '=00=00=00=FF' Default - transparent
1370  }
1371 }
1372 
1374 {
1375  MHApplication *pApp = CurrentApp();
1376 
1377  if (pApp && pApp->m_textColour.IsSet())
1378  {
1379  colour.Copy(pApp->m_textColour);
1380  }
1381  else
1382  {
1383  colour.SetFromString("\377\377\377\000", 4); // '=FF=FF=FF=00' UK MHEG Default - white
1384  }
1385 }
1386 
1388 {
1389  MHApplication *pApp = CurrentApp();
1390 
1391  if (pApp && pApp->m_buttonRefColour.IsSet())
1392  {
1393  colour.Copy(pApp->m_buttonRefColour);
1394  }
1395  else
1396  {
1397  colour.SetFromString("\377\377\377\000", 4); // '=FF=FF=FF=00' ??? Not specified in UK MHEG
1398  }
1399 }
1400 
1402 {
1403  MHApplication *pApp = CurrentApp();
1404 
1405  if (pApp && pApp->m_highlightRefColour.IsSet())
1406  {
1407  colour.Copy(pApp->m_highlightRefColour);
1408  }
1409  else
1410  {
1411  colour.SetFromString("\377\377\377\000", 4); // '=FF=FF=FF=00' UK MHEG Default - white
1412  }
1413 }
1414 
1416 {
1417  MHApplication *pApp = CurrentApp();
1418 
1419  if (pApp && pApp->m_sliderRefColour.IsSet())
1420  {
1421  colour.Copy(pApp->m_sliderRefColour);
1422  }
1423  else
1424  {
1425  colour.SetFromString("\377\377\377\000", 4); // '=FF=FF=FF=00' UK MHEG Default - white
1426  }
1427 }
1428 
1430 {
1431  MHApplication *pApp = CurrentApp();
1432 
1433  if (pApp && pApp->m_nTextCHook > 0)
1434  {
1435  return pApp->m_nTextCHook;
1436  }
1437  return 10; // UK MHEG default.
1438 }
1439 
1441 {
1442  MHApplication *pApp = CurrentApp();
1443 
1444  if (pApp && pApp->m_nStrCHook > 0)
1445  {
1446  return pApp->m_nStrCHook;
1447  }
1448  return 10; // UK MHEG default.
1449 }
1450 
1452 {
1453  MHApplication *pApp = CurrentApp();
1454 
1455  if (pApp && pApp->m_nBitmapCHook > 0)
1456  {
1457  return pApp->m_nBitmapCHook;
1458  }
1459  return 4; // UK MHEG default - PNG bitmap
1460 }
1461 
1463 {
1464  MHApplication *pApp = CurrentApp();
1465 
1466  if (pApp && pApp->m_fontAttrs.Size() > 0)
1467  {
1468  str.Copy(pApp->m_fontAttrs);
1469  }
1470  else
1471  {
1472  str.Copy("plain.24.24.0"); // TODO: Check this.
1473  }
1474 }
1475 
1476 // An identifier string required by the UK profile. The "manufacturer" is GNU.
1477 const char *MHEngine::MHEGEngineProviderIdString = "MHGGNU001";
1478 
1479 // Define the logging function and settings
1481 
1482 FILE *gMHLogStream = nullptr;
1483 
1484 // The MHEG engine calls this when it needs to log something.
1485 void mhlog_fn(const QString& logtext)
1486 {
1487  QByteArray tmp = logtext.toLatin1();
1488  fprintf(gMHLogStream, "[freemheg] %s\n", tmp.constData());
1489 }
1490 
1491 // Called from the user of the library to set the logging.
1492 void MHSetLogging(FILE *logStream, unsigned int logLevel)
1493 {
1494  gMHLogStream = logStream;
1496 }
EventFocusMoved
@ EventFocusMoved
Definition: Root.h:41
EventStreamPlaying
@ EventStreamPlaying
Definition: Root.h:35
EventHighlightOn
@ EventHighlightOn
Definition: Root.h:36
MHObjectRef
Definition: BaseClasses.h:153
MHGroup
Definition: Groups.h:47
MHContext::SetInputRegister
virtual void SetInputRegister(int nReg)=0
MHEngine::CurrentScene
MHScene * CurrentScene()
Definition: Engine.h:181
MHPSEntry::m_FileName
MHOctetString m_FileName
Definition: Engine.h:58
MHGroup::CheckTimers
int CheckTimers(MHEngine *engine)
Definition: Groups.cpp:387
MHEngine::RequestExternalContent
void RequestExternalContent(MHIngredient *pRequester)
Definition: Engine.cpp:969
EventTestEvent
@ EventTestEvent
Definition: Root.h:37
MHEngine::GetDefaultBGColour
void GetDefaultBGColour(MHColour &colour)
Definition: Engine.cpp:1359
Groups.h
MHEngine::m_interacting
MHInteractible * m_interacting
Definition: Engine.h:211
EventContentAvailable
@ EventContentAvailable
Definition: Root.h:33
EventHeadItems
@ EventHeadItems
Definition: Root.h:38
MHRoot::Deactivation
virtual void Deactivation(MHEngine *engine)
Definition: Root.cpp:85
EventIsDeselected
@ EventIsDeselected
Definition: Root.h:37
MHStream
Definition: Stream.h:33
MHLogLinks
@ MHLogLinks
Definition: freemheg.h:70
MHApplication::m_fRestarting
bool m_fRestarting
Definition: Groups.h:151
ASN1Codes.h
MHEngine
Definition: Engine.h:72
MHApplication
Definition: Groups.h:117
MHEngine::MHEGEngineProviderIdString
static const char * MHEGEngineProviderIdString
Definition: Engine.h:158
MHApplication::Activation
void Activation(MHEngine *engine) override
Definition: Groups.cpp:689
MHEngine::MHEngine
MHEngine(MHContext *context)
Definition: Engine.cpp:48
MHObjectRef::m_groupId
MHOctetString m_groupId
Definition: BaseClasses.h:169
MHApplication::FindOnStack
int FindOnStack(const MHRoot *pVis)
Definition: Groups.cpp:707
MHObjectRef::m_nObjectNo
int m_nObjectNo
Definition: BaseClasses.h:168
logLevel
LogLevel_t logLevel
Definition: logging.cpp:92
MHEngine::ParseProgram
MHGroup * ParseProgram(QByteArray &text)
Definition: Engine.cpp:195
MHEngine::m_eventQueue
QQueue< MHAsynchEvent * > m_eventQueue
Definition: Engine.h:190
MHGroup::Activation
void Activation(MHEngine *engine) override
Definition: Groups.cpp:275
EventTokenMovedTo
@ EventTokenMovedTo
Definition: Root.h:35
PathProtocol
static EProtocol PathProtocol(const QString &csPath)
Definition: Engine.cpp:254
MHContext::DrawBackground
virtual void DrawBackground(const QRegion &reg)=0
MHOctetString::Bytes
const unsigned char * Bytes() const
Definition: BaseClasses.h:124
MHGroup::Preparation
void Preparation(MHEngine *engine) override
Definition: Groups.cpp:258
MHEngine::SendToBack
void SendToBack(const MHRoot *pVis)
Definition: Engine.cpp:775
MHExternContent::m_FileName
QString m_FileName
Definition: Engine.h:65
gMHLogoptions
int gMHLogoptions
Definition: Engine.cpp:1480
arg
arg(title).arg(filename).arg(doDelete))
MHAsynchEvent
Definition: Engine.h:45
EventHighlightOff
@ EventHighlightOff
Definition: Root.h:36
MHEngine::GetDefaultButtonRefColour
void GetDefaultButtonRefColour(MHColour &colour)
Definition: Engine.cpp:1387
EventLastItemPresented
@ EventLastItemPresented
Definition: Root.h:37
MHLogScenes
@ MHLogScenes
Definition: freemheg.h:68
MHEngine::m_fBooting
bool m_fBooting
Definition: Engine.h:209
EProtocol
EProtocol
Definition: Engine.cpp:253
EventStreamEvent
@ EventStreamEvent
Definition: Root.h:35
MHContext::CheckCarouselObject
virtual bool CheckCarouselObject(QString objectPath)=0
MHInteractible::KeyEvent
virtual void KeyEvent(MHEngine *, int)
Definition: Visible.h:151
build_compdb.parser
parser
Definition: build_compdb.py:7
MHEngine::AddLink
void AddLink(MHLink *pLink)
Definition: Engine.cpp:713
Visible.h
MHRoot::SetVariableValue
virtual void SetVariableValue(const MHUnion &)
Definition: Root.h:108
MHEngine::GetDefaultSliderRefColour
void GetDefaultSliderRefColour(MHColour &colour)
Definition: Engine.cpp:1415
MHAsynchEvent::m_eventData
MHUnion m_eventData
Definition: Engine.h:49
kProtoHybrid
@ kProtoHybrid
Definition: Engine.cpp:253
EventIsRunning
@ EventIsRunning
Definition: Root.h:33
MHApplication::m_pCurrentScene
MHScene * m_pCurrentScene
Definition: Groups.h:150
MHApplication::m_buttonRefColour
MHColour m_buttonRefColour
Definition: Groups.h:133
MHSequence< MHObjectRef * >
MHOctetString
Definition: BaseClasses.h:107
EventIsAvailable
@ EventIsAvailable
Definition: Root.h:33
MHLogActions
@ MHLogActions
Definition: freemheg.h:69
mythburn.FILE
int FILE
Definition: mythburn.py:139
kProtoDSM
@ kProtoDSM
Definition: Engine.cpp:253
MHGroup::Destruction
void Destruction(MHEngine *engine) override
Definition: Groups.cpp:319
MHEngine::GetPathName
QString GetPathName(const MHOctetString &str)
Definition: Engine.cpp:524
MHApplication::m_bgColour
MHColour m_bgColour
Definition: Groups.h:133
tmp
static guint32 * tmp
Definition: goom_core.cpp:30
MHGroup::Deactivation
void Deactivation(MHEngine *engine) override
Definition: Groups.cpp:305
EventIsSelected
@ EventIsSelected
Definition: Root.h:37
MHEngine::m_context
MHContext * m_context
Definition: Engine.h:208
MHApplication::m_sliderRefColour
MHColour m_sliderRefColour
Definition: Groups.h:133
MHEngine::GetDefaultStreamCHook
int GetDefaultStreamCHook()
Definition: Engine.cpp:1440
ParseBinary.h
MHRoot::m_ObjectReference
MHObjectRef m_ObjectReference
Definition: Root.h:247
MHEngine::RemoveFromDisplayStack
void RemoveFromDisplayStack(MHVisible *pVis)
Definition: Engine.cpp:746
MHEngine::Redraw
void Redraw(const QRegion &region)
Definition: Engine.cpp:899
MHColour::SetFromString
void SetFromString(const char *str, int nLen)
Definition: BaseClasses.cpp:260
MHGroup::m_items
MHOwnPtrSequence< MHIngredient > m_items
Definition: Groups.h:71
MHEngine::CancelExternalContentRequest
void CancelExternalContentRequest(MHIngredient *pRequester)
Definition: Engine.cpp:1028
MHEngine::EventTriggered
void EventTriggered(MHRoot *pSource, enum EventType ev)
Definition: Engine.h:94
MHApplication::m_nBitmapCHook
int m_nBitmapCHook
Definition: Groups.h:137
MHApplication::m_fontAttrs
MHOctetString m_fontAttrs
Definition: Groups.h:140
MHEngine::~MHEngine
~MHEngine() override
Definition: Engine.cpp:59
MHEngine::CheckLinks
void CheckLinks(const MHObjectRef &sourceRef, enum EventType ev, const MHUnion &un)
Definition: Engine.cpp:706
MHEngine::GetDefaultBitmapCHook
int GetDefaultBitmapCHook()
Definition: Engine.cpp:1451
MHContentRef::IsSet
bool IsSet() const
Definition: BaseClasses.h:183
MHUnion
Definition: BaseClasses.h:283
EventAnchorFired
@ EventAnchorFired
Definition: Root.h:34
MHLogNotifications
@ MHLogNotifications
Definition: freemheg.h:67
hardwareprofile.config.p
p
Definition: config.py:33
EventFirstItemPresented
@ EventFirstItemPresented
Definition: Root.h:37
EventCursorLeave
@ EventCursorLeave
Definition: Root.h:36
mhlog_fn
void mhlog_fn(const QString &logtext)
Definition: Engine.cpp:1485
MHEngine::GetDefaultHighlightRefColour
void GetDefaultHighlightRefColour(MHColour &colour)
Definition: Engine.cpp:1401
MHContext::GetCarouselData
virtual bool GetCarouselData(QString objectPath, QByteArray &result)=0
ParseNode.h
EventAsyncStopped
@ EventAsyncStopped
Definition: Root.h:34
EventType
EventType
Definition: Root.h:33
EventTimerFired
@ EventTimerFired
Definition: Root.h:34
EventIsDeleted
@ EventIsDeleted
Definition: Root.h:33
C_SCENE
#define C_SCENE
Definition: ASN1Codes.h:34
MHSetLogging
void MHSetLogging(FILE *logStream, unsigned int logLevel)
Definition: Engine.cpp:1492
EventUserInput
@ EventUserInput
Definition: Root.h:34
EventItemSelected
@ EventItemSelected
Definition: Root.h:38
MHEngine::PutBefore
void PutBefore(const MHRoot *pVis, const MHRoot *pRef)
Definition: Engine.cpp:790
ParseText.h
MHEngine::FindObject
MHRoot * FindObject(const MHObjectRef &oRef, bool failOnNotFound=true)
Definition: Engine.cpp:574
MHParseNode::GetTagNo
int GetTagNo()
Definition: ParseNode.cpp:49
MHColour
Definition: BaseClasses.h:138
MHEngine::GetDefaultTextCHook
int GetDefaultTextCHook()
Definition: Engine.cpp:1429
MHExternContent::m_time
QElapsedTimer m_time
Definition: Engine.h:67
MHScene
Definition: Groups.h:88
CONTENT_CHECK_TIME
#define CONTENT_CHECK_TIME
Definition: Engine.cpp:78
MHLOG
#define MHLOG(__level, __text)
Definition: Logging.h:36
MHGroup::FindByObjectNo
MHRoot * FindByObjectNo(int n) override
Definition: Groups.cpp:330
MHVisible::GetVisibleArea
virtual QRegion GetVisibleArea()
Definition: Visible.cpp:197
MHApplication::m_displayStack
MHSequence< MHVisible * > m_displayStack
Definition: Groups.h:147
MHCreateEngine
MHEG * MHCreateEngine(MHContext *context)
Definition: Engine.cpp:43
EventCursorEnter
@ EventCursorEnter
Definition: Root.h:36
MHGroup::m_fIsApp
bool m_fIsApp
Definition: Groups.h:72
MHSequence::RemoveAt
void RemoveAt(int i)
Definition: BaseClasses.h:65
MHEngine::m_applicationStack
QStack< MHApplication * > m_applicationStack
Definition: Engine.h:175
Engine.h
EventIsStopped
@ EventIsStopped
Definition: Root.h:33
MHLogWarning
@ MHLogWarning
Definition: freemheg.h:66
MHLogError
@ MHLogError
Definition: freemheg.h:65
MHApplication::m_nTextCHook
int m_nTextCHook
Definition: Groups.h:134
MHGroup::PrintMe
void PrintMe(FILE *fd, int nTabs) const override
Definition: Groups.cpp:217
MHApplication::m_nLockCount
int m_nLockCount
Definition: Groups.h:144
gMHLogStream
FILE * gMHLogStream
Definition: Engine.cpp:1482
MHEngine::GetDefaultTextColour
void GetDefaultTextColour(MHColour &colour)
Definition: Engine.cpp:1373
MHEngine::TransitionToScene
void TransitionToScene(const MHObjectRef &target)
Definition: Engine.cpp:419
MHIngredient
Definition: Ingredients.h:34
MHParseBase
Definition: ParseNode.h:31
MHSequence::InsertAt
void InsertAt(BASE b, int n)
Definition: BaseClasses.h:52
EventTokenMovedFrom
@ EventTokenMovedFrom
Definition: Root.h:35
MHEngine::AddActions
void AddActions(const MHActionSequence &actions)
Definition: Engine.cpp:724
MHEngine::AddToDisplayStack
void AddToDisplayStack(MHVisible *pVis)
Definition: Engine.cpp:734
EventStreamStopped
@ EventStreamStopped
Definition: Root.h:35
MHEngine::GetDefaultFontAttrs
void GetDefaultFontAttrs(MHOctetString &str)
Definition: Engine.cpp:1462
MHGroup::Initialise
void Initialise(MHParseNode *p, MHEngine *engine) override
Definition: Groups.cpp:48
MHEngine::m_actionStack
QStack< MHElemAction * > m_actionStack
Definition: Engine.h:186
MHContext::GetDSMCCId
virtual const char * GetDSMCCId(void)=0
Root.h
EventSliderValueChanged
@ EventSliderValueChanged
Definition: Root.h:41
MHOctetString::Size
int Size() const
Definition: BaseClasses.h:119
MHEngine::GenerateUserAction
void GenerateUserAction(int nCode) override
Definition: Engine.cpp:915
MHPSEntry::m_Data
MHOwnPtrSequence< MHUnion > m_Data
Definition: Engine.h:59
MHPSEntry
Definition: Engine.h:55
MHEngine::m_redrawRegion
QRegion m_redrawRegion
Definition: Engine.h:172
MHParseNode::Failure
static void Failure(const char *p)
Definition: ParseNode.cpp:43
MHVisible
Definition: Visible.h:36
MHContentRef::m_contentRef
MHOctetString m_contentRef
Definition: BaseClasses.h:188
MHEngine::m_externContentTable
QList< MHExternContent * > m_externContentTable
Definition: Engine.h:197
MHEngine::UnlockScreen
void UnlockScreen()
Definition: Engine.cpp:905
MHColour::IsSet
bool IsSet() const
Definition: BaseClasses.h:143
MHEngine::CurrentApp
MHApplication * CurrentApp()
Definition: Engine.h:176
MHEngine::GetDefaultCharSet
int GetDefaultCharSet()
Definition: Engine.cpp:1348
MHIngredient::IsShared
bool IsShared() override
Definition: Ingredients.h:44
MHColour::Copy
void Copy(const MHColour &col)
Definition: BaseClasses.cpp:266
EventEngineEvent
@ EventEngineEvent
Definition: Root.h:39
MHContext::RequireRedraw
virtual void RequireRedraw(const QRegion &region)=0
MHActionSequence
Definition: Actions.h:29
MHContext
Definition: freemheg.h:93
MHEngine::EngineEvent
void EngineEvent(int nCode) override
Definition: Engine.cpp:955
MHSequence::Size
int Size() const
Definition: BaseClasses.h:46
MHUnion::Printable
QString Printable() const
Definition: BaseClasses.cpp:695
MHEngine::DrawDisplay
void DrawDisplay(QRegion toDraw) override
Definition: Engine.cpp:886
MHParseBinary
Definition: ParseBinary.h:32
MHParseNode
Definition: ParseNode.h:39
MHEngine::StreamStarted
void StreamStarted(MHStream *stream, bool bStarted) override
Definition: Engine.cpp:963
EventItemDeselected
@ EventItemDeselected
Definition: Root.h:38
MHSequence::GetAt
BASE GetAt(int i) const
Definition: BaseClasses.h:48
kProtoUnknown
@ kProtoUnknown
Definition: Engine.cpp:253
MHEngine::SetInputRegister
void SetInputRegister(int nReg)
Definition: Engine.cpp:518
MHEngine::LoadStorePersistent
bool LoadStorePersistent(bool fIsLoad, const MHOctetString &fileName, const MHSequence< MHObjectRef * > &variables)
Definition: Engine.cpp:1110
MHSequence::Append
void Append(BASE b)
Definition: BaseClasses.h:63
kProtoHTTP
@ kProtoHTTP
Definition: Engine.cpp:253
MHEG
Definition: freemheg.h:49
freemheg.h
MHOctetString::Equal
bool Equal(const MHOctetString &str) const
Definition: BaseClasses.h:122
MHEngine::BringToFront
void BringToFront(const MHRoot *pVis)
Definition: Engine.cpp:760
MHERROR
#define MHERROR(__text)
Definition: Logging.h:42
MHEngine::PutBehind
void PutBehind(const MHRoot *pVis, const MHRoot *pRef)
Definition: Engine.cpp:821
Logging.h
MHExternContent::m_pRequester
MHIngredient * m_pRequester
Definition: Engine.h:66
MHEngine::m_fInTransition
bool m_fInTransition
Definition: Engine.h:202
MHApplication::m_nStrCHook
int m_nStrCHook
Definition: Groups.h:136
C_APPLICATION
#define C_APPLICATION
Definition: ASN1Codes.h:33
MHEngine::RunAll
int RunAll(void) override
Definition: Engine.cpp:81
MHElemAction::Perform
virtual void Perform(MHEngine *engine)=0
Stream.h
MHAsynchEvent::m_pEventSource
MHRoot * m_pEventSource
Definition: Engine.h:47
EventTailItems
@ EventTailItems
Definition: Root.h:38
MHElemAction
Definition: BaseActions.h:35
MHIngredient::ContentArrived
virtual void ContentArrived(const unsigned char *, int, MHEngine *)
Definition: Ingredients.h:62
MHEngine::RemoveLink
void RemoveLink(MHLink *pLink)
Definition: Engine.cpp:718
MHEngine::DrawRegion
void DrawRegion(const QRegion &toDraw, int nStackPos)
Definition: Engine.cpp:852
MHExternContent
Definition: Engine.h:63
MHContext::GetReceiverId
virtual const char * GetReceiverId(void)=0
MHEngine::m_persistentStore
MHOwnPtrSequence< MHPSEntry > m_persistentStore
Definition: Engine.h:200
MHContext::CheckStop
virtual bool CheckStop(void)=0
EventInteractionCompleted
@ EventInteractionCompleted
Definition: Root.h:34
MHEngine::Quit
void Quit()
Definition: Engine.cpp:378
EventEntryFieldFull
@ EventEntryFieldFull
Definition: Root.h:38
MHVisible::Display
virtual void Display(MHEngine *)=0
MHEngine::m_linkTable
QList< MHLink * > m_linkTable
Definition: Engine.h:193
MHIngredient::m_contentRef
MHContentRef m_contentRef
Definition: Ingredients.h:78
MHApplication::m_nCharSet
int m_nCharSet
Definition: Groups.h:132
MHApplication::m_highlightRefColour
MHColour m_highlightRefColour
Definition: Groups.h:133
MHElemAction::PrintMe
virtual void PrintMe(FILE *fd, int nTabs) const
Definition: BaseActions.cpp:37
MHApplication::m_textColour
MHColour m_textColour
Definition: Groups.h:133
MHEngine::RunActions
void RunActions()
Definition: Engine.cpp:614
MHVisible::GetOpaqueArea
virtual QRegion GetOpaqueArea()
Definition: Visible.h:65
MHEngine::CheckContentRequests
void CheckContentRequests()
Definition: Engine.cpp:1049
EventCounterTrigger
@ EventCounterTrigger
Definition: Root.h:36
MHEngine::GetEngineSupport
bool GetEngineSupport(const MHOctetString &feature)
Definition: Engine.cpp:1192
MHOctetString::Copy
void Copy(const MHOctetString &str)
Definition: BaseClasses.cpp:131
MHRoot
Definition: Root.h:44
MHEngine::Launch
bool Launch(const MHObjectRef &target, bool fIsSpawn=false)
Definition: Engine.cpp:274
MHParseText
Definition: ParseText.h:31
MHRoot::GetVariableValue
virtual void GetVariableValue(MHUnion &, MHEngine *)
Definition: Root.h:106
MHApplication::m_path
QString m_path
Definition: Groups.h:152
MHObjectRef::Printable
QString Printable() const
Definition: BaseClasses.cpp:313
kProtoCI
@ kProtoCI
Definition: Engine.cpp:253