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 static constexpr std::chrono::milliseconds CONTENT_CHECK_TIME { 2s };
79 
80 // This is the main loop of the engine.
81 std::chrono::milliseconds MHEngine::RunAll()
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 -1ms;
122  }
123  }
124 
125  m_fBooting = false;
126  }
127 
128  std::chrono::milliseconds nNextTime = 0ms;
129 
130  do
131  {
132  // Check to see if we need to close.
133  if (m_context->CheckStop())
134  {
135  return 0ms;
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) : 0ms;
149 
150  if (CurrentApp())
151  {
152  // The UK MHEG profile allows applications to have timers.
153  std::chrono::milliseconds nAppTime = CurrentApp()->CheckTimers(this);
154 
155  if (nAppTime != 0ms && (nNextTime == 0ms || 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 == 0ms || 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),
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  MHScene *scene = CurrentScene();
389  if (scene)
390  scene->Destruction(this);
391 
392  CurrentApp()->Destruction(this);
393 
394  // This isn't in the standard as far as I can tell but we have to do this because
395  // we may have events referring to the old application.
396  while (!m_eventQueue.isEmpty())
397  {
398  delete m_eventQueue.dequeue();
399  }
400 
401  delete m_applicationStack.pop();
402 
403  // If the stack is now empty we return to boot mode.
404  if (m_applicationStack.isEmpty())
405  {
406  m_fBooting = true;
407  }
408  else
409  {
410  CurrentApp()->m_fRestarting = true;
411  CurrentApp()->Activation(this); // This will do any OnRestart actions.
412  // Note - this doesn't activate the previously active scene.
413  }
414 
415  m_fInTransition = false; // The transition is complete
416 }
417 
419 {
420  if (m_fInTransition)
421  {
422  // TransitionTo is not allowed in OnStartUp or OnCloseDown actions.
423  MHLOG(MHLogWarning, "WARN TransitionTo during transition - ignoring");
424  return;
425  }
426 
427  if (target.m_groupId.Size() == 0)
428  {
429  return; // No file name.
430  }
431 
432  QString csPath = GetPathName(target.m_groupId);
433 
434  // Check that the file exists before we commit to the transition.
435  // This may block if we cannot be sure whether the object is present.
436  QByteArray text;
437  if (! m_context->GetCarouselData(csPath, text)) {
438  EngineEvent(2); // GroupIDRefError
439  return;
440  }
441 
442  // Parse and run the file.
443  MHGroup *pProgram = ParseProgram(text);
444 
445  if (!pProgram )
446  MHERROR("Empty scene");
447 
448  if (pProgram->m_fIsApp)
449  {
450  delete pProgram;
451  MHERROR("Expected a scene");
452  }
453 
454  // Clear the action queue of anything pending.
455  m_actionStack.clear();
456 
457  // At this point we have managed to load the scene.
458  // Deactivate any non-shared ingredients in the application.
459  MHApplication *pApp = CurrentApp();
460 
461  for (int i = pApp->m_items.Size(); i > 0; i--)
462  {
463  MHIngredient *pItem = pApp->m_items.GetAt(i - 1);
464 
465  if (! pItem->IsShared())
466  {
467  pItem->Deactivation(this); // This does not remove them from the display stack.
468  }
469  }
470 
471  m_fInTransition = true; // TransitionTo etc are not allowed.
472 
473  if (pApp->m_pCurrentScene)
474  {
475  pApp->m_pCurrentScene->Deactivation(this); // This may involve a call to RunActions
476  pApp->m_pCurrentScene->Destruction(this);
477  }
478 
479  // Everything that belongs to the previous scene should have been removed from the display stack.
480 
481  // At this point we may have added actions to the queue as a result of synchronous
482  // events during the deactivation.
483 
484  // Remove any events from the asynch event queue unless they derive from
485  // the application itself or a shared ingredient.
486 
487  // This was causing crashes with leftover events being invalid.
488  // Changed to clear all events at this point.
489 
490  while (!m_eventQueue.isEmpty())
491  delete m_eventQueue.dequeue();
492 
493  // Can now actually delete the old scene.
494  if (pApp->m_pCurrentScene)
495  {
496  delete(pApp->m_pCurrentScene);
497  pApp->m_pCurrentScene = nullptr;
498  }
499 
500  m_interacting = nullptr;
501 
502  // Switch to the new scene.
503  CurrentApp()->m_pCurrentScene = dynamic_cast< MHScene* >(pProgram);
504  SetInputRegister(CurrentScene()->m_nEventReg);
505  m_redrawRegion = QRegion(0, 0, CurrentScene()->m_nSceneCoordX, CurrentScene()->m_nSceneCoordY); // Redraw the whole screen
506 
507  if ((gMHLogoptions & MHLogScenes) && gMHLogStream != nullptr) // Print it so we know what's going on.
508  {
509  pProgram->PrintMe(gMHLogStream, 0);
510  }
511 
512  pProgram->Preparation(this);
513  pProgram->Activation(this);
514  m_fInTransition = false; // The transition is complete
515 }
516 
518 {
519  m_context->SetInputRegister(nReg); // Enable the appropriate buttons
520 }
521 
522 // Create a canonical path name. The rules are given in the UK MHEG document.
524 {
525  if (str.Size() == 0)
526  return {};
527 
528  QString csPath = QString::fromUtf8((const char *)str.Bytes(), str.Size());
529  switch (PathProtocol(csPath))
530  {
531  default:
532  case kProtoUnknown:
533  case kProtoHybrid:
534  case kProtoHTTP:
535  case kProtoCI:
536  return csPath;
537  case kProtoDSM:
538  break;
539  }
540 
541  if (csPath.startsWith("DSM:"))
542  csPath = csPath.mid(4); // Remove DSM:
543  else if (csPath.startsWith("~"))
544  csPath = csPath.mid(1); // Remove ~
545  if (!csPath.startsWith("//"))
546  {
547  // Add the current application's path name
548  if (CurrentApp())
549  {
550  csPath = CurrentApp()->m_path + csPath;
551  }
552  }
553 
554  // Remove any occurrences of x/../
555  int nPos = -1;
556 
557  while ((nPos = csPath.indexOf("/../")) >= 0)
558  {
559  int nEnd = nPos + 4;
560 
561  while (nPos >= 1 && csPath[nPos-1] != '/')
562  {
563  nPos--;
564  }
565 
566  csPath = csPath.left(nPos) + csPath.mid(nEnd);
567  }
568 
569  return csPath;
570 }
571 
572 // Look up an object. In most cases we just want to fail if the object isn't found.
573 MHRoot *MHEngine::FindObject(const MHObjectRef &oRef, bool failOnNotFound)
574 {
575  // It should match either the application or the scene.
576  MHGroup *pSearch = nullptr;
577  MHGroup *pScene = CurrentScene();
578  MHGroup *pApp = CurrentApp();
579 
580  if (pScene && GetPathName(pScene->m_ObjectReference.m_groupId) == GetPathName(oRef.m_groupId))
581  {
582  pSearch = pScene;
583  }
584  else if (pApp && GetPathName(pApp->m_ObjectReference.m_groupId) == GetPathName(oRef.m_groupId))
585  {
586  pSearch = pApp;
587  }
588 
589  if (pSearch)
590  {
591  MHRoot *pItem = pSearch->FindByObjectNo(oRef.m_nObjectNo);
592 
593  if (pItem)
594  {
595  return pItem;
596  }
597  }
598 
599  if (failOnNotFound)
600  {
601  // I've seen at least one case where MHEG code has quite deliberately referred to
602  // an object that may or may not exist at a particular time.
603  // Another case was a call to CallActionSlot with an object reference variable
604  // that had been initialised to zero.
605  MHLOG(MHLogWarning, QString("WARN Reference %1 not found").arg(oRef.m_nObjectNo));
606  throw "FindObject failed";
607  }
608 
609  return nullptr; // If we don't generate an error.
610 }
611 
612 // Run queued actions.
614 {
615  while (! m_actionStack.isEmpty())
616  {
617  // Remove the first action.
618  MHElemAction *pAction = m_actionStack.pop();
619 
620  // Run it. If it fails and throws an exception catch it and continue with the next.
621  try
622  {
623  if ((gMHLogoptions & MHLogActions) && gMHLogStream != nullptr) // Debugging
624  {
625  fprintf(gMHLogStream, "[freemheg] Action - ");
626  pAction->PrintMe(gMHLogStream, 0);
627  fflush(gMHLogStream);
628  }
629 
630  pAction->Perform(this);
631  }
632  catch (...)
633  {
634  }
635  }
636 }
637 
638 // Called when an event is triggered. Either queues the event or finds a link that matches.
639 void MHEngine::EventTriggered(MHRoot *pSource, enum EventType ev, const MHUnion &evData)
640 {
641  MHLOG(MHLogLinks, QString("Event - %1 from %2")
643 
644  switch (ev)
645  {
647  case EventHeadItems:
648  case EventHighlightOff:
649  case EventHighlightOn:
650  case EventIsAvailable:
651  case EventIsDeleted:
652  case EventIsDeselected:
653  case EventIsRunning:
654  case EventIsSelected:
655  case EventIsStopped:
656  case EventItemDeselected:
657  case EventItemSelected:
659  case EventTailItems:
660  case EventTestEvent:
661  case EventTokenMovedFrom:
662  case EventTokenMovedTo:
663  // Synchronous events. Fire any links that are waiting.
664  // The UK MHEG describes this as the preferred interpretation. We are checking the link
665  // at the time we generate the event rather than queuing the synchronous events until
666  // this elementary action is complete. That matters if we are processing an elementary action
667  // which will activate or deactivate links.
668  CheckLinks(pSource->m_ObjectReference, ev, evData);
669  break;
670  case EventAnchorFired:
671  case EventAsyncStopped:
673  case EventCounterTrigger:
674  case EventCursorEnter:
675  case EventCursorLeave:
676  case EventEngineEvent:
677  case EventEntryFieldFull:
679  case EventStreamEvent:
680  case EventStreamPlaying:
681  case EventStreamStopped:
682  case EventTimerFired:
683  case EventUserInput:
684  case EventFocusMoved: // UK MHEG. Generated by HyperText class
685  case EventSliderValueChanged: // UK MHEG. Generated by Slider class
686  default:
687  {
688  // Asynchronous events. Add to the event queue.
689  auto *pEvent = new MHAsynchEvent;
690  pEvent->m_pEventSource = pSource;
691  pEvent->m_eventType = ev;
692  pEvent->m_eventData = evData;
693  m_eventQueue.enqueue(pEvent);
694  }
695  break;
696  }
697 }
698 
699 
700 // TO CHECK: If two actions both depend on the same event is the order in which the links are
701 // searched defined? This processes items in the order in which they were activated rather
702 // than their static position in the group.
703 
704 // Check all the links in the application and scene and fire any that match this event.
705 void MHEngine::CheckLinks(const MHObjectRef &sourceRef, enum EventType ev, const MHUnion &un)
706 {
707  for (auto *link : std::as_const(m_linkTable))
708  link->MatchEvent(sourceRef, ev, un, this);
709 }
710 
711 // Add and remove links to and from the active link table.
713 {
714  m_linkTable.append(pLink);
715 }
716 
718 {
719  m_linkTable.removeAll(pLink);
720 }
721 
722 // Called when a link fires to add the actions to the action stack.
724 {
725  // Put them on the stack in reverse order so that we will pop the first.
726  for (int i = actions.Size(); i > 0; i--)
727  {
728  m_actionStack.push(actions.GetAt(i - 1));
729  }
730 }
731 
732 // Add a visible to the display stack if it isn't already there.
734 {
735  if (CurrentApp()->FindOnStack(pVis) != -1)
736  {
737  return; // Return if it's already there.
738  }
739 
741  Redraw(pVis->GetVisibleArea()); // Request a redraw
742 }
743 
744 // Remove a visible from the display stack if it is there.
746 {
747  int nPos = CurrentApp()->FindOnStack(pVis);
748 
749  if (nPos == -1)
750  {
751  return;
752  }
753 
755  Redraw(pVis->GetVisibleArea()); // Request a redraw
756 }
757 
758 // Functions to alter the Z-order.
760 {
761  int nPos = CurrentApp()->FindOnStack(p);
762 
763  if (nPos == -1)
764  {
765  return; // If it's not there do nothing
766  }
767 
768  auto *pVis = (MHVisible *)p; // Can now safely cast it.
769  CurrentApp()->m_displayStack.RemoveAt(nPos); // Remove it from its present posn
770  CurrentApp()->m_displayStack.Append(pVis); // Push it on the top.
771  Redraw(pVis->GetVisibleArea()); // Request a redraw
772 }
773 
775 {
776  int nPos = CurrentApp()->FindOnStack(p);
777 
778  if (nPos == -1)
779  {
780  return; // If it's not there do nothing
781  }
782 
783  auto *pVis = (MHVisible *)p; // Can now safely cast it.
784  CurrentApp()->m_displayStack.RemoveAt(nPos); // Remove it from its present posn
785  CurrentApp()->m_displayStack.InsertAt(pVis, 0); // Put it on the bottom.
786  Redraw(pVis->GetVisibleArea()); // Request a redraw
787 }
788 
789 void MHEngine::PutBefore(const MHRoot *p, const MHRoot *pRef)
790 {
791  int nPos = CurrentApp()->FindOnStack(p);
792 
793  if (nPos == -1)
794  {
795  return; // If it's not there do nothing
796  }
797 
798  auto *pVis = (MHVisible *)p; // Can now safely cast it.
799  int nRef = CurrentApp()->FindOnStack(pRef);
800 
801  if (nRef == -1)
802  {
803  return; // If the reference visible isn't there do nothing.
804  }
805 
807 
808  if (nRef >= nPos)
809  {
810  nRef--; // The position of the reference may have shifted
811  }
812 
813  CurrentApp()->m_displayStack.InsertAt(pVis, nRef + 1);
814  // Redraw the area occupied by the moved item. We might be able to reduce
815  // the area to be redrawn by looking at the way it is affected by other items
816  // in the stack. We could also see whether it's currently active.
817  Redraw(pVis->GetVisibleArea()); // Request a redraw
818 }
819 
820 void MHEngine::PutBehind(const MHRoot *p, const MHRoot *pRef)
821 {
822  int nPos = CurrentApp()->FindOnStack(p);
823 
824  if (nPos == -1)
825  {
826  return; // If it's not there do nothing
827  }
828 
829  int nRef = CurrentApp()->FindOnStack(pRef);
830 
831  if (nRef == -1)
832  {
833  return; // If the reference visible isn't there do nothing.
834  }
835 
836  auto *pVis = (MHVisible *)p; // Can now safely cast it.
838 
839  if (nRef >= nPos)
840  {
841  nRef--; // The position of the reference may have shifted
842  }
843 
844  CurrentApp()->m_displayStack.InsertAt(pVis, nRef); // Shift the reference and anything above up.
845  Redraw(pVis->GetVisibleArea()); // Request a redraw
846 }
847 
848 // Draw a region of the screen. This attempts to minimise the drawing by eliminating items
849 // that are completely obscured by items above them. We have to take into account the
850 // transparency of items since items higher up the stack may be semi-transparent.
851 void MHEngine::DrawRegion(const QRegion& toDraw, int nStackPos)
852 {
853  if (toDraw.isEmpty())
854  {
855  return; // Nothing left to draw.
856  }
857 
858  while (nStackPos >= 0)
859  {
860  MHVisible *pItem = CurrentApp()->m_displayStack.GetAt(nStackPos);
861  // Work out how much of the area we want to draw is included in this visible.
862  // The visible area will be empty if the item is transparent or not active.
863  QRegion drawArea = pItem->GetVisibleArea() & toDraw;
864 
865  if (! drawArea.isEmpty()) // It contributes something.
866  {
867  // Remove the opaque area of this item from the region we have left.
868  // If this item is (semi-)transparent this will not remove anything.
869  QRegion newDraw = toDraw - pItem->GetOpaqueArea();
870  DrawRegion(newDraw, nStackPos - 1); // Do the items further down if any.
871  // Now we've drawn anything below this we can draw this item on top.
872  pItem->Display(this);
873  return;
874  }
875 
876  nStackPos--;
877  }
878 
879  // We've drawn all the visibles and there's still some undrawn area.
880  // Fill it with black.
881  m_context->DrawBackground(toDraw);
882 }
883 
884 // Redraw an area of the display. This will be called via the context from Redraw.
885 void MHEngine::DrawDisplay(const QRegion& toDraw)
886 {
887  if (m_fBooting)
888  {
889  return;
890  }
891 
892  int nTopStack = CurrentApp() == nullptr ? -1 : CurrentApp()->m_displayStack.Size() - 1;
893  DrawRegion(toDraw, nTopStack);
894 }
895 
896 // An area of the screen needs to be redrawn. We simply remember this and redraw it
897 // in one go when the timer expires.
898 void MHEngine::Redraw(const QRegion& region)
899 {
900  m_redrawRegion += region;
901 }
902 
903 // Called to decrement the lock count.
905 {
906  if (CurrentApp()->m_nLockCount > 0)
907  {
909  }
910 }
911 
912 
913 // Called from the windowing application, this generates a user event as the result of a button push.
915 {
916  MHScene *pScene = CurrentScene();
917 
918  if (! pScene)
919  {
920  return;
921  }
922 
923  // Various keys generate engine events as well as user events.
924  // These are generated before the user events and even if there
925  // is an interactible.
926  switch (nCode)
927  {
928  case 104:
929  case 105: // Text key
930  EngineEvent(4);
931  break;
932  case 16: // Text Exit/Cancel key
933  case 100: // Red
934  case 101: // Green
935  case 102: // Yellow
936  case 103: // Blue
937  case 300: // EPG
938  EngineEvent(nCode);
939  break;
940  }
941 
942  // If we are interacting with an interactible send the key
943  // there otherwise generate a user event.
944  if (m_interacting)
945  {
946  m_interacting->KeyEvent(this, nCode);
947  }
948  else
949  {
950  EventTriggered(pScene, EventUserInput, nCode);
951  }
952 }
953 
954 void MHEngine::EngineEvent(int nCode)
955 {
956  if (CurrentApp())
958  else if (!m_fBooting)
959  MHLOG(MHLogWarning, QString("WARN EngineEvent %1 but no app").arg(nCode));
960 }
961 
962 void MHEngine::StreamStarted(MHStream *stream, bool bStarted)
963 {
965 }
966 
967 // Called by an ingredient wanting external content.
969 {
970  // It seems that some MHEG applications contain active ingredients with empty contents
971  // This isn't correct but we simply ignore that.
972  if (! pRequester->m_contentRef.IsSet())
973  {
974  return;
975  }
976 
977  // Remove any existing content requests for this ingredient.
978  CancelExternalContentRequest(pRequester);
979 
980  QString csPath = GetPathName(pRequester->m_contentRef.m_contentRef);
981 
982  if (csPath.isEmpty())
983  {
984  MHLOG(MHLogWarning, "RequestExternalContent empty path");
985  return;
986  }
987 
988  if (m_context->CheckCarouselObject(csPath))
989  {
990  // Available now - pass it to the ingredient.
991  QByteArray text;
992  if (m_context->GetCarouselData(csPath, text))
993  {
994  // If the content is not recognized catch the exception and continue
995  try
996  {
997  pRequester->ContentArrived(
998  reinterpret_cast< const unsigned char * >(text.constData()),
999  text.size(), this);
1000  }
1001  catch (...)
1002  {}
1003  }
1004  else
1005  {
1006  MHLOG(MHLogWarning, QString("WARN No file content %1 <= %2")
1007  .arg(pRequester->m_ObjectReference.Printable(), csPath));
1008  if (kProtoHTTP == PathProtocol(csPath))
1009  EngineEvent(203); // 203=RemoteNetworkError if 404 reply
1010  EngineEvent(3); // ContentRefError
1011  }
1012  }
1013  else
1014  {
1015  // Need to record this and check later.
1016  MHLOG(MHLogNotifications, QString("Waiting for %1 <= %2")
1017  .arg(pRequester->m_ObjectReference.Printable(), csPath.left(128)) );
1018  auto *pContent = new MHExternContent;
1019  pContent->m_FileName = csPath;
1020  pContent->m_pRequester = pRequester;
1021  pContent->m_time.start();
1022  m_externContentTable.append(pContent);
1023  }
1024 }
1025 
1026 // Remove any pending requests from the queue.
1028 {
1029  QList<MHExternContent *>::iterator it = m_externContentTable.begin();
1030 
1031  while (it != m_externContentTable.end())
1032  {
1033  MHExternContent *pContent = *it;
1034 
1035  if (pContent->m_pRequester == pRequester)
1036  {
1037  MHLOG(MHLogNotifications, QString("Cancelled wait for %1")
1038  .arg(pRequester->m_ObjectReference.Printable()) );
1039  it = m_externContentTable.erase(it);
1040  delete pContent;
1041  return;
1042  }
1043  ++it;
1044  }
1045 }
1046 
1047 // See if we can satisfy any of the outstanding requests.
1049 {
1050  QList<MHExternContent*>::iterator it = m_externContentTable.begin();
1051  while (it != m_externContentTable.end())
1052  {
1053  MHExternContent *pContent = *it;
1054  if (m_context->CheckCarouselObject(pContent->m_FileName))
1055  {
1056  // Remove from the list.
1057  it = m_externContentTable.erase(it);
1058 
1059  QByteArray text;
1060  if (m_context->GetCarouselData(pContent->m_FileName, text))
1061  {
1062  MHLOG(MHLogNotifications, QString("Received %1 len %2")
1063  .arg(pContent->m_pRequester->m_ObjectReference.Printable())
1064  .arg(text.size()) );
1065  // If the content is not recognized catch the exception and continue
1066  try
1067  {
1068  pContent->m_pRequester->ContentArrived(
1069  reinterpret_cast< const unsigned char * >(text.constData()),
1070  text.size(), this);
1071  }
1072  catch (...)
1073  {}
1074  }
1075  else
1076  {
1077  MHLOG(MHLogWarning, QString("WARN No file content %1 <= %2")
1078  .arg(pContent->m_pRequester->m_ObjectReference.Printable(),
1079  pContent->m_FileName));
1080  if (kProtoHTTP == PathProtocol(pContent->m_FileName))
1081  EngineEvent(203); // 203=RemoteNetworkError if 404 reply
1082  EngineEvent(3); // ContentRefError
1083  }
1084 
1085  delete pContent;
1086  }
1087  else if (pContent->m_time.elapsed() > 60000) // TODO Get this from carousel
1088  {
1089  // Remove from the list.
1090  it = m_externContentTable.erase(it);
1091 
1092  MHLOG(MHLogWarning, QString("WARN File timed out %1 <= %2")
1093  .arg(pContent->m_pRequester->m_ObjectReference.Printable(),
1094  pContent->m_FileName));
1095 
1096  if (kProtoHTTP == PathProtocol(pContent->m_FileName))
1097  EngineEvent(203); // 203=RemoteNetworkError if 404 reply
1098  EngineEvent(3); // ContentRefError
1099 
1100  delete pContent;
1101  }
1102  else
1103  {
1104  ++it;
1105  }
1106  }
1107 }
1108 
1109 bool MHEngine::LoadStorePersistent(bool fIsLoad, const MHOctetString &fileName, const MHSequence<MHObjectRef *> &variables)
1110 {
1111  QString const csFile = QString::fromUtf8(
1112  (const char *)fileName.Bytes(), fileName.Size() );
1113 
1114  // See if there is an entry there already.
1115  MHPSEntry *pEntry = nullptr;
1116  int i = 0;
1117 
1118  for (i = 0; i < m_persistentStore.Size(); i++)
1119  {
1120  pEntry = m_persistentStore.GetAt(i);
1121 
1122  if (pEntry->m_FileName.Equal(fileName))
1123  {
1124  break;
1125  }
1126  }
1127 
1128  if (i == m_persistentStore.Size()) // Not there.
1129  {
1130  // If we're loading then we've failed.
1131  if (fIsLoad)
1132  {
1133  MHLOG(MHLogNotifications, QString(
1134  "Load Persistent(%1) #%2: no such file")
1135  .arg(csFile).arg(variables.Size()) );
1136  return false;
1137  }
1138 
1139  // If we're storing we make a new entry.
1140  pEntry = new MHPSEntry;
1141  pEntry->m_FileName.Copy(fileName);
1142  m_persistentStore.Append(pEntry);
1143  }
1144 
1145  // This should never happen
1146  if (pEntry == nullptr)
1147  return false;
1148 
1149  if (fIsLoad) // Copy the data into the variables.
1150  {
1151  // Check that we have sufficient data before we continue?
1152  if (pEntry->m_Data.Size() < variables.Size())
1153  {
1154  MHLOG(MHLogWarning, QString(
1155  "Load Persistent(%1): size mismatch").arg(csFile));
1156  return false;
1157  }
1158 
1159  for (i = 0; i < variables.Size(); i++)
1160  {
1161  MHUnion *pValue = pEntry->m_Data.GetAt(i);
1162  MHLOG(MHLogNotifications, QString("Load Persistent(%1) #%2=%3")
1163  .arg(csFile).arg(i).arg(pValue->Printable()) );
1164  FindObject(*(variables.GetAt(i)))->SetVariableValue(*pValue);
1165  }
1166  }
1167 
1168  else // Get the data from the variables into the store.
1169  {
1170  // Remove any existing data.
1171  while (pEntry->m_Data.Size() != 0)
1172  {
1173  pEntry->m_Data.RemoveAt(0);
1174  }
1175 
1176  // Set the store to the values.
1177  for (i = 0; i < variables.Size(); i++)
1178  {
1179  auto *pValue = new MHUnion;
1180  pEntry->m_Data.Append(pValue);
1181  FindObject(*(variables.GetAt(i)))->GetVariableValue(*pValue, this);
1182  MHLOG(MHLogNotifications, QString("Store Persistent(%1) %2=>#%3")
1183  .arg(csFile, pValue->Printable(), QString::number(i)) );
1184  }
1185  }
1186 
1187  return true;
1188 }
1189 
1190 // Find out what we support.
1192 {
1193  QString csFeat = QString::fromUtf8((const char *)feature.Bytes(), feature.Size());
1194  static const QRegularExpression kSeparatorRE { R"([\(\,\)])" };
1195  QStringList strings = csFeat.split(kSeparatorRE);
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 }
MHContext::GetCarouselData
virtual bool GetCarouselData(const QString &objectPath, QByteArray &result)=0
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:46
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
MHEngine::RequestExternalContent
void RequestExternalContent(MHIngredient *pRequester)
Definition: Engine.cpp:968
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:86
EventIsDeselected
@ EventIsDeselected
Definition: Root.h:37
MHStream
Definition: Stream.h:32
MHLogLinks
@ MHLogLinks
Definition: freemheg.h:76
MHApplication::m_fRestarting
bool m_fRestarting
Definition: Groups.h:152
ASN1Codes.h
MHEngine
Definition: Engine.h:72
MHEngine::DrawDisplay
void DrawDisplay(const QRegion &toDraw) override
Definition: Engine.cpp:885
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:170
MHApplication::FindOnStack
int FindOnStack(const MHRoot *pVis)
Definition: Groups.cpp:707
MHObjectRef::m_nObjectNo
int m_nObjectNo
Definition: BaseClasses.h:169
logLevel
LogLevel_t logLevel
Definition: logging.cpp:85
MHEngine::ParseProgram
MHGroup * ParseProgram(QByteArray &text)
Definition: Engine.cpp:195
MHEngine::m_eventQueue
QQueue< MHAsynchEvent * > m_eventQueue
Definition: Engine.h:190
MHEngine::RunAll
std::chrono::milliseconds RunAll(void) override
Definition: Engine.cpp:81
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:125
MHGroup::Preparation
void Preparation(MHEngine *engine) override
Definition: Groups.cpp:258
MHEngine::SendToBack
void SendToBack(const MHRoot *pVis)
Definition: Engine.cpp:774
MHExternContent::m_FileName
QString m_FileName
Definition: Engine.h:65
gMHLogoptions
int gMHLogoptions
Definition: Engine.cpp:1480
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:74
MHEngine::m_fBooting
bool m_fBooting
Definition: Engine.h:209
EProtocol
EProtocol
Definition: Engine.cpp:253
EventStreamEvent
@ EventStreamEvent
Definition: Root.h:35
MHInteractible::KeyEvent
virtual void KeyEvent(MHEngine *, int)
Definition: Visible.h:151
C_SCENE
@ C_SCENE
Definition: ASN1Codes.h:37
build_compdb.parser
parser
Definition: build_compdb.py:7
MHEngine::AddLink
void AddLink(MHLink *pLink)
Definition: Engine.cpp:712
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:151
MHApplication::m_buttonRefColour
MHColour m_buttonRefColour
Definition: Groups.h:134
MHSequence< MHObjectRef * >
MHOctetString
Definition: BaseClasses.h:107
EventIsAvailable
@ EventIsAvailable
Definition: Root.h:33
MHLogActions
@ MHLogActions
Definition: freemheg.h:75
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:523
MHApplication::m_bgColour
MHColour m_bgColour
Definition: Groups.h:134
tmp
static guint32 * tmp
Definition: goom_core.cpp:26
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:134
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:745
MHEngine::Redraw
void Redraw(const QRegion &region)
Definition: Engine.cpp:898
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:1027
MHEngine::EventTriggered
void EventTriggered(MHRoot *pSource, enum EventType ev)
Definition: Engine.h:94
MHApplication::m_nBitmapCHook
int m_nBitmapCHook
Definition: Groups.h:138
MHApplication::m_fontAttrs
MHOctetString m_fontAttrs
Definition: Groups.h:141
MHEngine::~MHEngine
~MHEngine() override
Definition: Engine.cpp:59
MHEngine::CheckLinks
void CheckLinks(const MHObjectRef &sourceRef, enum EventType ev, const MHUnion &un)
Definition: Engine.cpp:705
MHEngine::GetDefaultBitmapCHook
int GetDefaultBitmapCHook()
Definition: Engine.cpp:1451
MHContentRef::IsSet
bool IsSet() const
Definition: BaseClasses.h:184
MHUnion
Definition: BaseClasses.h:283
EventAnchorFired
@ EventAnchorFired
Definition: Root.h:34
feature
static const std::array< featureStruct, 7 > feature
Definition: audiooutputsettings.cpp:435
MHLogNotifications
@ MHLogNotifications
Definition: freemheg.h:73
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
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
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:789
ParseText.h
MHEngine::FindObject
MHRoot * FindObject(const MHObjectRef &oRef, bool failOnNotFound=true)
Definition: Engine.cpp:573
MHParseNode::GetTagNo
int GetTagNo()
Definition: ParseNode.cpp:49
MHColour
Definition: BaseClasses.h:139
MHEngine::GetDefaultTextCHook
int GetDefaultTextCHook()
Definition: Engine.cpp:1429
MHExternContent::m_time
QElapsedTimer m_time
Definition: Engine.h:67
MHScene
Definition: Groups.h:88
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:148
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:66
MHEngine::m_applicationStack
QStack< MHApplication * > m_applicationStack
Definition: Engine.h:175
Engine.h
EventIsStopped
@ EventIsStopped
Definition: Root.h:33
MHLogWarning
@ MHLogWarning
Definition: freemheg.h:72
MHGroup::CheckTimers
std::chrono::milliseconds CheckTimers(MHEngine *engine)
Definition: Groups.cpp:387
MHLogError
@ MHLogError
Definition: freemheg.h:71
MHApplication::m_nTextCHook
int m_nTextCHook
Definition: Groups.h:135
MHGroup::PrintMe
void PrintMe(FILE *fd, int nTabs) const override
Definition: Groups.cpp:217
MHApplication::m_nLockCount
int m_nLockCount
Definition: Groups.h:145
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:418
MHIngredient
Definition: Ingredients.h:33
MHParseBase
Definition: ParseNode.h:31
MHSequence::InsertAt
void InsertAt(BASE b, int n)
Definition: BaseClasses.h:53
EventTokenMovedFrom
@ EventTokenMovedFrom
Definition: Root.h:35
MHEngine::AddActions
void AddActions(const MHActionSequence &actions)
Definition: Engine.cpp:723
MHEngine::AddToDisplayStack
void AddToDisplayStack(MHVisible *pVis)
Definition: Engine.cpp:733
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:120
MHEngine::GenerateUserAction
void GenerateUserAction(int nCode) override
Definition: Engine.cpp:914
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:35
MHContentRef::m_contentRef
MHOctetString m_contentRef
Definition: BaseClasses.h:189
MHEngine::m_externContentTable
QList< MHExternContent * > m_externContentTable
Definition: Engine.h:197
MHEngine::UnlockScreen
void UnlockScreen()
Definition: Engine.cpp:904
MHColour::IsSet
bool IsSet() const
Definition: BaseClasses.h:144
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
CONTENT_CHECK_TIME
static constexpr std::chrono::milliseconds CONTENT_CHECK_TIME
Definition: Engine.cpp:78
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
C_APPLICATION
@ C_APPLICATION
Definition: ASN1Codes.h:36
MHActionSequence
Definition: Actions.h:28
MHContext
Definition: freemheg.h:98
MHEngine::EngineEvent
void EngineEvent(int nCode) override
Definition: Engine.cpp:954
MHSequence::Size
int Size() const
Definition: BaseClasses.h:47
MHUnion::Printable
QString Printable() const
Definition: BaseClasses.cpp:690
MHParseBinary
Definition: ParseBinary.h:31
MHParseNode
Definition: ParseNode.h:38
MHEngine::StreamStarted
void StreamStarted(MHStream *stream, bool bStarted) override
Definition: Engine.cpp:962
EventItemDeselected
@ EventItemDeselected
Definition: Root.h:38
MHSequence::GetAt
BASE GetAt(int i) const
Definition: BaseClasses.h:49
kProtoUnknown
@ kProtoUnknown
Definition: Engine.cpp:253
MHEngine::SetInputRegister
void SetInputRegister(int nReg)
Definition: Engine.cpp:517
MHEngine::LoadStorePersistent
bool LoadStorePersistent(bool fIsLoad, const MHOctetString &fileName, const MHSequence< MHObjectRef * > &variables)
Definition: Engine.cpp:1109
MHSequence::Append
void Append(BASE b)
Definition: BaseClasses.h:64
kProtoHTTP
@ kProtoHTTP
Definition: Engine.cpp:253
MHEG
Definition: freemheg.h:54
freemheg.h
MHOctetString::Equal
bool Equal(const MHOctetString &str) const
Definition: BaseClasses.h:123
MHEngine::BringToFront
void BringToFront(const MHRoot *pVis)
Definition: Engine.cpp:759
MHERROR
#define MHERROR(__text)
Definition: Logging.h:42
MHEngine::PutBehind
void PutBehind(const MHRoot *pVis, const MHRoot *pRef)
Definition: Engine.cpp:820
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:137
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:34
MHIngredient::ContentArrived
virtual void ContentArrived(const unsigned char *, int, MHEngine *)
Definition: Ingredients.h:62
MHEngine::RemoveLink
void RemoveLink(MHLink *pLink)
Definition: Engine.cpp:717
MHContext::CheckCarouselObject
virtual bool CheckCarouselObject(const QString &objectPath)=0
MHEngine::DrawRegion
void DrawRegion(const QRegion &toDraw, int nStackPos)
Definition: Engine.cpp:851
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:133
MHApplication::m_highlightRefColour
MHColour m_highlightRefColour
Definition: Groups.h:134
MHElemAction::PrintMe
virtual void PrintMe(FILE *fd, int nTabs) const
Definition: BaseActions.cpp:37
MHApplication::m_textColour
MHColour m_textColour
Definition: Groups.h:134
MHEngine::RunActions
void RunActions()
Definition: Engine.cpp:613
MHVisible::GetOpaqueArea
virtual QRegion GetOpaqueArea()
Definition: Visible.h:65
MHEngine::CheckContentRequests
void CheckContentRequests()
Definition: Engine.cpp:1048
EventCounterTrigger
@ EventCounterTrigger
Definition: Root.h:36
MHEngine::GetEngineSupport
bool GetEngineSupport(const MHOctetString &feature)
Definition: Engine.cpp:1191
MHOctetString::Copy
void Copy(const MHOctetString &str)
Definition: BaseClasses.cpp:131
MHRoot
Definition: Root.h:43
MHEngine::Launch
bool Launch(const MHObjectRef &target, bool fIsSpawn=false)
Definition: Engine.cpp:274
MHParseText
Definition: ParseText.h:32
MHRoot::GetVariableValue
virtual void GetVariableValue(MHUnion &, MHEngine *)
Definition: Root.h:106
MHApplication::m_path
QString m_path
Definition: Groups.h:153
MHObjectRef::Printable
QString Printable() const
Definition: BaseClasses.cpp:313
kProtoCI
@ kProtoCI
Definition: Engine.cpp:253