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 <QRegExp>
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  MHPSEntry *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")
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(':'), firstSlash = csPath.indexOf('/');
266  if (firstColon > 0 && firstSlash > 0 && firstColon < firstSlash)
267  return kProtoUnknown;
268 
269  return kProtoDSM;
270 }
271 
272 // Launch and Spawn
273 bool MHEngine::Launch(const MHObjectRef &target, bool fIsSpawn)
274 {
275  if (m_fInTransition)
276  {
277  MHLOG(MHLogWarning, "WARN Launch during transition - ignoring");
278  return false;
279  }
280 
281  if (target.m_GroupId.Size() == 0) return false; // No file name.
282  QString csPath = GetPathName(target.m_GroupId); // Get path relative to root.
283  MHLOG(MHLogNotifications, "NOTE Launching " + csPath);
284 
285  // Check that the file exists before we commit to the transition.
286  // This may block if we cannot be sure whether the object is present.
287  QByteArray text;
288  if (! m_Context->GetCarouselData(csPath, text))
289  {
290  if (!m_fBooting)
291  EngineEvent(2); // GroupIDRefError
292  MHLOG(MHLogWarning, "WARN Launch not found " + csPath);
293  return false;
294  }
295 
296  MHApplication *pProgram = dynamic_cast<MHApplication*>(ParseProgram(text));
297  if (! pProgram)
298  {
299  MHLOG(MHLogWarning, "Empty application");
300  return false;
301  }
302  if (! pProgram->m_fIsApp)
303  {
304  MHLOG(MHLogWarning, "Expected an application");
305  delete pProgram;
306  return false;
307  }
308  if ((__mhlogoptions & MHLogScenes) && __mhlogStream != nullptr) // Print it so we know what's going on.
309  {
310  pProgram->PrintMe(__mhlogStream, 0);
311  }
312 
313  // Clear the action queue of anything pending.
314  m_ActionStack.clear();
315 
316  m_fInTransition = true; // Starting a transition
317 
318  try
319  {
320  if (CurrentApp())
321  {
322  if (fIsSpawn) // Run the CloseDown actions.
323  {
324  AddActions(CurrentApp()->m_CloseDown);
325  RunActions();
326  }
327 
328  if (CurrentScene())
329  {
330  CurrentScene()->Destruction(this);
331  }
332 
333  CurrentApp()->Destruction(this);
334 
335  if (!fIsSpawn)
336  {
337  delete m_ApplicationStack.pop(); // Pop and delete the current app.
338  }
339  }
340 
341  // Save the path we use for this app.
342  pProgram->m_Path = csPath; // Record the path
343  int nPos = pProgram->m_Path.lastIndexOf('/');
344 
345  if (nPos < 0)
346  {
347  pProgram->m_Path = "";
348  }
349  else
350  {
351  pProgram->m_Path = pProgram->m_Path.left(nPos);
352  }
353 
354  // Have now got the application.
355  m_ApplicationStack.push(pProgram);
356 
357  // This isn't in the standard as far as I can tell but we have to do this because
358  // we may have events referring to the old application.
359  while (!m_EventQueue.isEmpty())
360  {
361  delete m_EventQueue.dequeue();
362  }
363 
364  // Activate the application. ....
365  CurrentApp()->Activation(this);
366  m_fInTransition = false; // The transition is complete
367  MHLOG(MHLogNotifications, "NOTE Launch completed OK");
368  return true;
369  }
370  catch (...)
371  {
372  m_fInTransition = false; // The transition is complete
373  return false;
374  }
375 }
376 
378 {
379  if (m_fInTransition)
380  {
381  MHLOG(MHLogWarning, "WARN Quit during transition - ignoring");
382  return;
383  }
384 
385  m_fInTransition = true; // Starting a transition
386 
387  if (CurrentScene())
388  {
389  CurrentScene()->Destruction(this);
390  }
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 = static_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 ((__mhlogoptions & MHLogScenes) && __mhlogStream != nullptr) // Print it so we know what's going on.
508  {
509  pProgram->PrintMe(__mhlogStream, 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 QString();
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(), *pApp = CurrentApp();
578 
579  if (pScene && GetPathName(pScene->m_ObjectReference.m_GroupId) == GetPathName(oRef.m_GroupId))
580  {
581  pSearch = pScene;
582  }
583  else if (pApp && GetPathName(pApp->m_ObjectReference.m_GroupId) == GetPathName(oRef.m_GroupId))
584  {
585  pSearch = pApp;
586  }
587 
588  if (pSearch)
589  {
590  MHRoot *pItem = pSearch->FindByObjectNo(oRef.m_nObjectNo);
591 
592  if (pItem)
593  {
594  return pItem;
595  }
596  }
597 
598  if (failOnNotFound)
599  {
600  // I've seen at least one case where MHEG code has quite deliberately referred to
601  // an object that may or may not exist at a particular time.
602  // Another case was a call to CallActionSlot with an object reference variable
603  // that had been initialised to zero.
604  MHLOG(MHLogWarning, QString("WARN Reference %1 not found").arg(oRef.m_nObjectNo));
605  throw "FindObject failed";
606  }
607 
608  return nullptr; // If we don't generate an error.
609 }
610 
611 // Run queued actions.
613 {
614  while (! m_ActionStack.isEmpty())
615  {
616  // Remove the first action.
617  MHElemAction *pAction = m_ActionStack.pop();
618 
619  // Run it. If it fails and throws an exception catch it and continue with the next.
620  try
621  {
622  if ((__mhlogoptions & MHLogActions) && __mhlogStream != nullptr) // Debugging
623  {
624  fprintf(__mhlogStream, "[freemheg] Action - ");
625  pAction->PrintMe(__mhlogStream, 0);
626  fflush(__mhlogStream);
627  }
628 
629  pAction->Perform(this);
630  }
631  catch (...)
632  {
633  }
634  }
635 }
636 
637 // Called when an event is triggered. Either queues the event or finds a link that matches.
638 void MHEngine::EventTriggered(MHRoot *pSource, enum EventType ev, const MHUnion &evData)
639 {
640  MHLOG(MHLogLinks, QString("Event - %1 from %2")
641  .arg(MHLink::EventTypeToString(ev)).arg(pSource->m_ObjectReference.Printable()));
642 
643  switch (ev)
644  {
646  case EventHeadItems:
647  case EventHighlightOff:
648  case EventHighlightOn:
649  case EventIsAvailable:
650  case EventIsDeleted:
651  case EventIsDeselected:
652  case EventIsRunning:
653  case EventIsSelected:
654  case EventIsStopped:
655  case EventItemDeselected:
656  case EventItemSelected:
658  case EventTailItems:
659  case EventTestEvent:
660  case EventTokenMovedFrom:
661  case EventTokenMovedTo:
662  // Synchronous events. Fire any links that are waiting.
663  // The UK MHEG describes this as the preferred interpretation. We are checking the link
664  // at the time we generate the event rather than queuing the synchronous events until
665  // this elementary action is complete. That matters if we are processing an elementary action
666  // which will activate or deactivate links.
667  CheckLinks(pSource->m_ObjectReference, ev, evData);
668  break;
669  case EventAnchorFired:
670  case EventAsyncStopped:
672  case EventCounterTrigger:
673  case EventCursorEnter:
674  case EventCursorLeave:
675  case EventEngineEvent:
676  case EventEntryFieldFull:
678  case EventStreamEvent:
679  case EventStreamPlaying:
680  case EventStreamStopped:
681  case EventTimerFired:
682  case EventUserInput:
683  case EventFocusMoved: // UK MHEG. Generated by HyperText class
684  case EventSliderValueChanged: // UK MHEG. Generated by Slider class
685  default:
686  {
687  // Asynchronous events. Add to the event queue.
688  MHAsynchEvent *pEvent = new MHAsynchEvent;
689  pEvent->m_pEventSource = pSource;
690  pEvent->m_eventType = ev;
691  pEvent->m_eventData = evData;
692  m_EventQueue.enqueue(pEvent);
693  }
694  break;
695  }
696 }
697 
698 
699 // TO CHECK: If two actions both depend on the same event is the order in which the links are
700 // searched defined? This processes items in the order in which they were activated rather
701 // than their static position in the group.
702 
703 // Check all the links in the application and scene and fire any that match this event.
704 void MHEngine::CheckLinks(const MHObjectRef &sourceRef, enum EventType ev, const MHUnion &un)
705 {
706  for (int i = 0; i < m_LinkTable.size(); i++)
707  {
708  m_LinkTable.at(i)->MatchEvent(sourceRef, ev, un, this);
709  }
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  MHVisible *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  MHVisible *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  MHVisible *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  MHVisible *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  MHExternContent *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")
1064  .arg(pContent->m_pRequester->m_ObjectReference.Printable())
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")
1079  .arg(pContent->m_pRequester->m_ObjectReference.Printable())
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")
1094  .arg(pContent->m_pRequester->m_ObjectReference.Printable())
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  if (fIsLoad) // Copy the data into the variables.
1147  {
1148  // Check that we have sufficient data before we continue?
1149  if (pEntry->m_Data.Size() < variables.Size())
1150  {
1151  MHLOG(MHLogWarning, QString(
1152  "Load Persistent(%1): size mismatch").arg(csFile));
1153  return false;
1154  }
1155 
1156  for (i = 0; i < variables.Size(); i++)
1157  {
1158  MHUnion *pValue = pEntry->m_Data.GetAt(i);
1159  MHLOG(MHLogNotifications, QString("Load Persistent(%1) #%2=%3")
1160  .arg(csFile).arg(i).arg(pValue->Printable()) );
1161  FindObject(*(variables.GetAt(i)))->SetVariableValue(*pValue);
1162  }
1163  }
1164 
1165  else // Get the data from the variables into the store.
1166  {
1167  // Remove any existing data.
1168  while (pEntry->m_Data.Size() != 0)
1169  {
1170  pEntry->m_Data.RemoveAt(0);
1171  }
1172 
1173  // Set the store to the values.
1174  for (i = 0; i < variables.Size(); i++)
1175  {
1176  MHUnion *pValue = new MHUnion;
1177  pEntry->m_Data.Append(pValue);
1178  FindObject(*(variables.GetAt(i)))->GetVariableValue(*pValue, this);
1179  MHLOG(MHLogNotifications, QString("Store Persistent(%1) %2=>#%3")
1180  .arg(csFile).arg(pValue->Printable()).arg(i) );
1181  }
1182  }
1183 
1184  return true;
1185 }
1186 
1187 // Find out what we support.
1189 {
1190  QString csFeat = QString::fromUtf8((const char *)feature.Bytes(), feature.Size());
1191  QStringList strings = csFeat.split(QRegExp("[\\(\\,\\)]"));
1192 
1193  MHLOG(MHLogNotifications, "NOTE GetEngineSupport " + csFeat);
1194 
1195  if (strings[0] == "ApplicationStacking" || strings[0] == "ASt")
1196  {
1197  return true;
1198  }
1199 
1200  // We're required to support cloning for Text, Bitmap and Rectangle.
1201  if (strings[0] == "Cloning" || strings[0] == "Clo")
1202  {
1203  return true;
1204  }
1205 
1206  if (strings[0] == "SceneCoordinateSystem" || strings[0] == "SCS")
1207  {
1208  return strings.count() >= 3 && strings[1] == "720" && strings[2] == "576";
1209 
1210  // I've also seen SceneCoordinateSystem(1,1)
1211  }
1212 
1213  if (strings[0] == "MultipleAudioStreams" || strings[0] == "MAS")
1214  {
1215  return strings.count() >= 2 && (strings[1] == "0" || strings[1] == "1");
1216  }
1217 
1218  if (strings[0] == "MultipleVideoStreams" || strings[0] == "MVS")
1219  {
1220  return strings.count() >= 2 && (strings[1] == "0" || strings[1] == "1");
1221  }
1222 
1223  // We're supposed to return true for all values of N
1224  if (strings[0] == "OverlappingVisibles" || strings[0] == "OvV")
1225  {
1226  return true;
1227  }
1228 
1229  if (strings[0] == "SceneAspectRatio" || strings[0] == "SAR")
1230  {
1231  if (strings.count() < 3)
1232  {
1233  return false;
1234  }
1235  return (strings[1] == "4" && strings[2] == "3") || (strings[1] == "16" && strings[2] == "9");
1236  }
1237 
1238  // We're supposed to support these at least. May also support(10,1440,1152)
1239  if (strings[0] == "VideoScaling" || strings[0] == "VSc")
1240  {
1241  if (strings.count() < 4 || strings[1] != "10")
1242  {
1243  return false;
1244  }
1245  return (strings[2] == "720" && strings[3] == "576") || (strings[2] == "360" && strings[3] == "288");
1246  }
1247 
1248  if (strings[0] == "BitmapScaling" || strings[0] == "BSc")
1249  {
1250  if (strings.count() < 4 || strings[1] != "2")
1251  {
1252  return false;
1253  }
1254  return (strings[2] == "720" && strings[3] == "576") || (strings[2] == "360" && strings[3] == "288");
1255  }
1256 
1257  // I think we only support the video fully on screen
1258  if (strings[0] == "VideoDecodeOffset" || strings[0] == "VDO")
1259  {
1260  return strings.count() >= 3 && strings[1] == "10" && strings[1] == "0";
1261  }
1262 
1263  // We support bitmaps that are partially off screen (don't we?)
1264  if (strings[0] == "BitmapDecodeOffset" || strings[0] == "BDO")
1265  {
1266  if (strings.count() >= 3 && strings[1] == "2" && (strings[2] == "0" || strings[2] == "1"))
1267  {
1268  return true;
1269  }
1270  if (strings.count() >= 2 && (strings[1] == "4" || strings[1] == "6"))
1271  {
1272  return true;
1273  }
1274  return false;
1275  }
1276 
1277  if (strings[0] == "UKEngineProfile" || strings[0] == "UniversalEngineProfile" || strings[0] == "UEP")
1278  {
1279  if (strings.count() < 2)
1280  {
1281  return false;
1282  }
1283 
1284  if (strings[1] == MHEGEngineProviderIdString)
1285  {
1286  return true;
1287  }
1288 
1289  if (strings[1] == m_Context->GetReceiverId())
1290  {
1291  return true;
1292  }
1293 
1294  if (strings[1] == m_Context->GetDSMCCId())
1295  {
1296  return true;
1297  }
1298 
1299  // The UK profile 1.06 seems a bit confused on this point. It is not clear whether
1300  // we are supposed to return true for UKEngineProfile(2) or not.
1301  if (strings[1] == "2")
1302  return true;
1303  if (strings[1] == "1")
1304  return true;
1305  // 'The Space' on Freeview checks this...
1306  if (strings[1] == "PANT11001")
1307  return true;
1308  // Irish DTT expects "1285". From ETSI ES 202 184: UEP(1285) means the receiver has been verified as fully conformant.
1309  if (strings[1] == "1285")
1310  return true;
1311 
1312  return false;
1313  }
1314 
1315  // InteractionChannelExtension.
1316  if (strings[0] == "ICProfile" || strings[0] == "ICP") {
1317  if (strings.count() < 2) return false;
1318  if (strings[1] == "0")
1319  return true; // InteractionChannelExtension.
1320  if (strings[1] == "1")
1321  return true; // ICStreamingExtension. This is a deliberate lie
1322  return false;
1323  }
1324 
1325  if (strings[0] == "HDExtension" || strings[0] == "HDE") {
1326  if (strings.count() < 2) return false;
1327  if (strings[1] == "0")
1328  return false; // HDVideoExtension.
1329  if (strings[1] == "1")
1330  return false; // HDGraphicsPlaneExtension
1331  return false;
1332  }
1333  if (strings[0] == "HDGraphicsPlaneExtension" || strings[0] == "HDG") {
1334  if (strings.count() < 2) return false;
1335  // true if HDGraphicsPlaneExtension
1336  return strings[1] == "0";
1337  }
1338 
1339  // Otherwise return false.
1340  return false;
1341 }
1342 
1343 // Get the various defaults. These are extracted from the current app or the (UK) MHEG defaults.
1345 {
1346  MHApplication *pApp = CurrentApp();
1347 
1348  if (pApp && pApp->m_nCharSet > 0)
1349  {
1350  return pApp->m_nCharSet;
1351  }
1352  return 10; // UK MHEG default.
1353 }
1354 
1356 {
1357  MHApplication *pApp = CurrentApp();
1358 
1359  if (pApp && pApp->m_BGColour.IsSet())
1360  {
1361  colour.Copy(pApp->m_BGColour);
1362  }
1363  else
1364  {
1365  colour.SetFromString("\000\000\000\377", 4); // '=00=00=00=FF' Default - transparent
1366  }
1367 }
1368 
1370 {
1371  MHApplication *pApp = CurrentApp();
1372 
1373  if (pApp && pApp->m_TextColour.IsSet())
1374  {
1375  colour.Copy(pApp->m_TextColour);
1376  }
1377  else
1378  {
1379  colour.SetFromString("\377\377\377\000", 4); // '=FF=FF=FF=00' UK MHEG Default - white
1380  }
1381 }
1382 
1384 {
1385  MHApplication *pApp = CurrentApp();
1386 
1387  if (pApp && pApp->m_ButtonRefColour.IsSet())
1388  {
1389  colour.Copy(pApp->m_ButtonRefColour);
1390  }
1391  else
1392  {
1393  colour.SetFromString("\377\377\377\000", 4); // '=FF=FF=FF=00' ??? Not specified in UK MHEG
1394  }
1395 }
1396 
1398 {
1399  MHApplication *pApp = CurrentApp();
1400 
1401  if (pApp && pApp->m_HighlightRefColour.IsSet())
1402  {
1403  colour.Copy(pApp->m_HighlightRefColour);
1404  }
1405  else
1406  {
1407  colour.SetFromString("\377\377\377\000", 4); // '=FF=FF=FF=00' UK MHEG Default - white
1408  }
1409 }
1410 
1412 {
1413  MHApplication *pApp = CurrentApp();
1414 
1415  if (pApp && pApp->m_SliderRefColour.IsSet())
1416  {
1417  colour.Copy(pApp->m_SliderRefColour);
1418  }
1419  else
1420  {
1421  colour.SetFromString("\377\377\377\000", 4); // '=FF=FF=FF=00' UK MHEG Default - white
1422  }
1423 }
1424 
1426 {
1427  MHApplication *pApp = CurrentApp();
1428 
1429  if (pApp && pApp->m_nTextCHook > 0)
1430  {
1431  return pApp->m_nTextCHook;
1432  }
1433  return 10; // UK MHEG default.
1434 }
1435 
1437 {
1438  MHApplication *pApp = CurrentApp();
1439 
1440  if (pApp && pApp->m_nStrCHook > 0)
1441  {
1442  return pApp->m_nStrCHook;
1443  }
1444  return 10; // UK MHEG default.
1445 }
1446 
1448 {
1449  MHApplication *pApp = CurrentApp();
1450 
1451  if (pApp && pApp->m_nBitmapCHook > 0)
1452  {
1453  return pApp->m_nBitmapCHook;
1454  }
1455  return 4; // UK MHEG default - PNG bitmap
1456 }
1457 
1459 {
1460  MHApplication *pApp = CurrentApp();
1461 
1462  if (pApp && pApp->m_FontAttrs.Size() > 0)
1463  {
1464  str.Copy(pApp->m_FontAttrs);
1465  }
1466  else
1467  {
1468  str.Copy("plain.24.24.0"); // TODO: Check this.
1469  }
1470 }
1471 
1472 // An identifier string required by the UK profile. The "manufacturer" is GNU.
1473 const char *MHEngine::MHEGEngineProviderIdString = "MHGGNU001";
1474 
1475 // Define the logging function and settings
1477 
1478 FILE *__mhlogStream = nullptr;
1479 
1480 // The MHEG engine calls this when it needs to log something.
1481 void __mhlog(const QString& logtext)
1482 {
1483  QByteArray tmp = logtext.toLatin1();
1484  fprintf(__mhlogStream, "[freemheg] %s\n", tmp.constData());
1485 }
1486 
1487 // Called from the user of the library to set the logging.
1488 void MHSetLogging(FILE *logStream, unsigned int logLevel)
1489 {
1490  __mhlogStream = logStream;
1492 }
static void Failure(const char *p)
Definition: ParseNode.cpp:43
void GetDefaultTextColour(MHColour &colour)
Definition: Engine.cpp:1369
bool m_fInTransition
Definition: Engine.h:202
void Deactivation(MHEngine *engine) override
Definition: Groups.cpp:305
int GetDefaultCharSet()
Definition: Engine.cpp:1344
void AddToDisplayStack(MHVisible *pVis)
Definition: Engine.cpp:734
#define MHERROR(__text)
Definition: Logging.h:42
void StreamStarted(MHStream *, bool bStarted) override
Definition: Engine.cpp:963
void RunActions()
Definition: Engine.cpp:612
virtual ~MHEngine()
Definition: Engine.cpp:59
void GetDefaultButtonRefColour(MHColour &colour)
Definition: Engine.cpp:1383
MHColour m_BGColour
Definition: Groups.h:132
virtual void SetVariableValue(const MHUnion &)
Definition: Root.h:101
void RemoveFromDisplayStack(MHVisible *pVis)
Definition: Engine.cpp:746
QList< MHExternContent * > m_ExternContentTable
Definition: Engine.h:197
BASE GetAt(int i) const
Definition: BaseClasses.h:48
MHOwnPtrSequence< MHPSEntry > m_PersistentStore
Definition: Engine.h:200
int GetDefaultStreamCHook()
Definition: Engine.cpp:1436
bool IsSet() const
Definition: BaseClasses.h:141
MHOwnPtrSequence< MHUnion > m_Data
Definition: Engine.h:58
virtual void GetVariableValue(MHUnion &, MHEngine *)
Definition: Root.h:100
void TransitionToScene(const MHObjectRef &)
Definition: Engine.cpp:418
int m_nBitmapCHook
Definition: Groups.h:136
MHColour m_TextColour
Definition: Groups.h:132
MHScene * m_pCurrentScene
Definition: Groups.h:149
void PutBefore(const MHRoot *pVis, const MHRoot *pRef)
Definition: Engine.cpp:790
MHOctetString m_FontAttrs
Definition: Groups.h:139
virtual QRegion GetVisibleArea()
Definition: Visible.cpp:194
void __mhlog(const QString &logtext)
Definition: Engine.cpp:1481
int CheckTimers(MHEngine *engine)
Definition: Groups.cpp:389
void GetDefaultBGColour(MHColour &colour)
Definition: Engine.cpp:1355
MHOwnPtrSequence< MHIngredient > m_Items
Definition: Groups.h:70
QString Printable() const
void GetDefaultSliderRefColour(MHColour &colour)
Definition: Engine.cpp:1411
virtual void Deactivation(MHEngine *engine)
Definition: Root.cpp:85
EProtocol
Definition: Engine.cpp:253
void RequestExternalContent(MHIngredient *pRequester)
Definition: Engine.cpp:969
void InsertAt(BASE b, int n)
Definition: BaseClasses.h:52
void AddLink(MHLink *pLink)
Definition: Engine.cpp:713
const unsigned char * Bytes() const
Definition: BaseClasses.h:122
#define C_SCENE
Definition: ASN1Codes.h:34
MHScene * CurrentScene()
Definition: Engine.h:181
bool Launch(const MHObjectRef &target, bool fIsSpawn=false)
Definition: Engine.cpp:273
void RemoveLink(MHLink *pLink)
Definition: Engine.cpp:718
int m_nCharSet
Definition: Groups.h:131
void Copy(const MHColour &col)
static guint32 * tmp
Definition: goom_core.c:35
#define C_APPLICATION
Definition: ASN1Codes.h:33
static EProtocol PathProtocol(const QString &csPath)
Definition: Engine.cpp:254
MHApplication * CurrentApp()
Definition: Engine.h:175
QTime m_time
Definition: Engine.h:66
void Initialise(MHParseNode *p, MHEngine *engine) override
Definition: Groups.cpp:48
virtual void PrintMe(FILE *fd, int nTabs) const
Definition: BaseActions.cpp:37
QString m_FileName
Definition: Engine.h:64
virtual void ContentArrived(const unsigned char *, int, MHEngine *)
Definition: Ingredients.h:62
int FindOnStack(const MHRoot *pVis)
Definition: Groups.cpp:709
int m_nLockCount
Definition: Groups.h:143
void Redraw(const QRegion &region)
Definition: Engine.cpp:899
int GetDefaultBitmapCHook()
Definition: Engine.cpp:1447
int GetDefaultTextCHook()
Definition: Engine.cpp:1425
virtual void RequireRedraw(const QRegion &region)=0
virtual const char * GetDSMCCId(void)=0
virtual bool CheckStop(void)=0
void SetFromString(const char *str, int nLen)
Definition: freemheg.h:48
MHRoot * FindByObjectNo(int n) override
Definition: Groups.cpp:330
void PrintMe(FILE *fd, int nTabs) const override
Definition: Groups.cpp:571
void GetDefaultHighlightRefColour(MHColour &colour)
Definition: Engine.cpp:1397
void Copy(const MHOctetString &str)
QStack< MHElemAction * > m_ActionStack
Definition: Engine.h:186
MHInteractible * m_Interacting
Definition: Engine.h:211
int Size() const
Definition: BaseClasses.h:117
bool IsShared() override
Definition: Ingredients.h:44
void RemoveAt(int i)
Definition: BaseClasses.h:64
void Preparation(MHEngine *engine) override
Definition: Groups.cpp:258
bool m_fIsApp
Definition: Groups.h:71
QString Printable() const
FILE * __mhlogStream
Definition: Engine.cpp:1478
void CancelExternalContentRequest(MHIngredient *pRequester)
Definition: Engine.cpp:1028
void EventTriggered(MHRoot *pSource, enum EventType ev)
Definition: Engine.h:93
int m_nStrCHook
Definition: Groups.h:135
bool LoadStorePersistent(bool fIsLoad, const MHOctetString &fileName, const MHSequence< MHObjectRef * > &variables)
Definition: Engine.cpp:1110
QRegion m_redrawRegion
Definition: Engine.h:171
virtual void DrawBackground(const QRegion &reg)=0
void CheckContentRequests()
Definition: Engine.cpp:1049
MHGroup * ParseProgram(QByteArray &text)
Definition: Engine.cpp:195
int m_nTextCHook
Definition: Groups.h:133
virtual bool GetCarouselData(QString objectPath, QByteArray &result)=0
void PutBehind(const MHRoot *pVis, const MHRoot *pRef)
Definition: Engine.cpp:821
void CheckLinks(const MHObjectRef &sourceRef, enum EventType ev, const MHUnion &un)
Definition: Engine.cpp:704
Definition: Root.h:43
virtual void Display(MHEngine *)=0
MHObjectRef m_ObjectReference
Definition: Root.h:203
Definition: Groups.h:86
int FILE
Definition: mythburn.py:110
enum EventType m_eventType
Definition: Engine.h:47
virtual QRegion GetOpaqueArea()
Definition: Visible.h:65
int __mhlogoptions
Definition: Engine.cpp:1476
MHUnion m_eventData
Definition: Engine.h:48
MHContext * m_Context
Definition: Engine.h:208
MHColour m_ButtonRefColour
Definition: Groups.h:132
MHEG * MHCreateEngine(MHContext *context)
Definition: Engine.cpp:43
bool IsSet() const
Definition: BaseClasses.h:181
void GetDefaultFontAttrs(MHOctetString &str)
Definition: Engine.cpp:1458
MHRoot * m_pEventSource
Definition: Engine.h:46
void DrawDisplay(QRegion toDraw) override
Definition: Engine.cpp:886
void Destruction(MHEngine *engine) override
Definition: Groups.cpp:319
QStack< MHApplication * > m_ApplicationStack
Definition: Engine.h:174
void UnlockScreen()
Definition: Engine.cpp:905
LogLevel_t logLevel
Definition: logging.cpp:95
MHRoot * FindObject(const MHObjectRef &oRef, bool failOnNotFound=true)
Definition: Engine.cpp:573
QString GetPathName(const MHOctetString &str)
Definition: Engine.cpp:523
virtual void KeyEvent(MHEngine *, int)
Definition: Visible.h:151
virtual bool CheckCarouselObject(QString objectPath)=0
#define MHLOG(__level, __text)
Definition: Logging.h:36
Definition: Groups.h:45
#define CONTENT_CHECK_TIME
Definition: Engine.cpp:78
MHOctetString m_ContentRef
Definition: BaseClasses.h:186
void BringToFront(const MHRoot *pVis)
Definition: Engine.cpp:760
MHOctetString m_GroupId
Definition: BaseClasses.h:167
void DrawRegion(const QRegion &toDraw, int nStackPos)
Definition: Engine.cpp:852
void Activation(MHEngine *engine) override
Definition: Groups.cpp:691
QQueue< MHAsynchEvent * > m_EventQueue
Definition: Engine.h:190
void Quit()
Definition: Engine.cpp:377
MHSequence< MHVisible * > m_DisplayStack
Definition: Groups.h:146
int GetTagNo()
Definition: ParseNode.cpp:49
virtual void SetInputRegister(int nReg)=0
MHColour m_HighlightRefColour
Definition: Groups.h:132
int RunAll(void) override
Definition: Engine.cpp:81
void SetInputRegister(int nReg)
Definition: Engine.cpp:517
void PrintMe(FILE *fd, int nTabs) const override
Definition: Groups.cpp:217
EventType
Definition: Root.h:33
MHEngine(MHContext *context)
Definition: Engine.cpp:48
void Append(BASE b)
Definition: BaseClasses.h:62
void MHSetLogging(FILE *logStream, unsigned int logLevel)
Definition: Engine.cpp:1488
bool m_fRestarting
Definition: Groups.h:150
int Size() const
Definition: BaseClasses.h:46
void SendToBack(const MHRoot *pVis)
Definition: Engine.cpp:775
static const char * MHEGEngineProviderIdString
Definition: Engine.h:157
void AddActions(const MHActionSequence &actions)
Definition: Engine.cpp:724
QList< MHLink * > m_LinkTable
Definition: Engine.h:193
void EngineEvent(int nCode) override
Definition: Engine.cpp:955
MHOctetString m_FileName
Definition: Engine.h:57
MHContentRef m_ContentRef
Definition: Ingredients.h:78
bool m_fBooting
Definition: Engine.h:209
virtual const char * GetReceiverId(void)=0
QString m_Path
Definition: Groups.h:151
MHIngredient * m_pRequester
Definition: Engine.h:65
void Activation(MHEngine *engine) override
Definition: Groups.cpp:275
bool GetEngineSupport(const MHOctetString &feature)
Definition: Engine.cpp:1188
MHColour m_SliderRefColour
Definition: Groups.h:132
void GenerateUserAction(int nCode) override
Definition: Engine.cpp:915
virtual void Perform(MHEngine *engine)=0