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