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