Main MRPT website > C++ reference for MRPT 1.5.7
WxSubsystem.cpp
Go to the documentation of this file.
1 /* +---------------------------------------------------------------------------+
2  | Mobile Robot Programming Toolkit (MRPT) |
3  | http://www.mrpt.org/ |
4  | |
5  | Copyright (c) 2005-2017, Individual contributors, see AUTHORS file |
6  | See: http://www.mrpt.org/Authors - All rights reserved. |
7  | Released under BSD License. See details in http://www.mrpt.org/License |
8  +---------------------------------------------------------------------------+ */
9 
10 #include "gui-precomp.h" // Precompiled headers
11 
12 #include <mrpt/config.h>
13 
17 
18 #include <mrpt/system/os.h>
19 
20 #include <mrpt/gui/WxSubsystem.h>
21 #include <mrpt/gui/WxUtils.h>
22 
23 //#define WXSUBSYSTEM_VERBOSE
24 
25 // ------------------------------------------------------------------------
26 // Defined: Try to wait for all windows & the thread to exit cleanly.
27 // Undefined: Just to a sleep() and quit crossing our fingers.
28 //
29 // Problem with the "clean way" is: As of feb/2011, I get this error
30 // at the end:
31 // ** (MRPT:11711): CRITICAL **: giop_thread_request_push: assertion `tdata != NULL' failed
32 // ------------------------------------------------------------------------
33 //#define WXSHUTDOWN_DO_IT_CLEAN
34 
35 #if MRPT_HAS_WXWIDGETS
36 
37 
38 using namespace mrpt;
39 using namespace mrpt::gui;
40 using namespace mrpt::utils;
41 using namespace mrpt::synch;
42 using namespace std;
43 
46 
47 std::queue<WxSubsystem::TRequestToWxMainThread*> * WxSubsystem::listPendingWxRequests = NULL;
49 
51 volatile bool WxSubsystem::isConsoleApp = true;
52 
54 
55 
56 // Auxiliary class implementation:
58 {
59 }
61 {
63  {
64 #ifdef WXSUBSYSTEM_VERBOSE
65  printf("[~CAuxWxSubsystemShutdowner] Sending 999...\n");
66 #endif
67  // Shut down:
68  try
69  {
71  REQ->OPCODE = 999;
73 
74  //mrpt::system::sleep(100); // JL: I found no better way of doing this, sorry :-( See WxSubsystem::waitWxShutdownsIfNoWindows()
76  } catch (...) { } // Just in case we got an out-of-mem error.
77  } // is console app.
78 
79 
80 #ifdef WXSUBSYSTEM_VERBOSE
81  printf("[~CAuxWxSubsystemShutdowner] Deleting static objects.\n");
82 #endif
83  // This is the final point where all dynamic memory must be deleted:
87 }
88 
89 
90 // ---------------------------------------------------------------------------------------
91 // Auxiliary dialog class for the "ask user to open a camera":
92 // ---------------------------------------------------------------------------------------
93 class CDialogAskUserForCamera : public wxDialog
94 {
95 public:
97 
98  static const long ID_BTN_OK;
99  static const long ID_BTN_CANCEL;
100 
101  CDialogAskUserForCamera() : wxDialog(NULL,wxID_ANY,wxT("Select image source"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE, wxDialogNameStr)
102  {
103  wxFlexGridSizer *f1 = new wxFlexGridSizer(2, 1, 0, 0);
104  panel = new mrpt::gui::CPanelCameraSelection(this, wxID_ANY);
105  f1->Add(panel, 1, wxALL|wxALIGN_BOTTOM|wxALIGN_CENTER_HORIZONTAL, 5);
106 
107  wxFlexGridSizer *f2 = new wxFlexGridSizer(1, 2, 0, 0);
108  wxButton *btnOk = new wxButton(this,ID_BTN_OK,wxT("Ok"), wxDefaultPosition, wxDefaultSize);
109  wxButton *btnCancel = new wxButton(this,ID_BTN_CANCEL,wxT("Cancel"), wxDefaultPosition, wxDefaultSize);
110  f1->Add(f2, 1, wxALL|wxALIGN_BOTTOM|wxALIGN_CENTER_HORIZONTAL, 5);
111 
112  f2->Add(btnOk, 1, wxALL|wxALIGN_BOTTOM|wxALIGN_CENTER_HORIZONTAL, 5);
113  f2->Add(btnCancel, 1, wxALL|wxALIGN_BOTTOM|wxALIGN_CENTER_HORIZONTAL, 5);
114 
115  Connect(ID_BTN_OK,wxEVT_COMMAND_BUTTON_CLICKED,(wxObjectEventFunction)&CDialogAskUserForCamera::OnBtnOk);
116  Connect(ID_BTN_CANCEL,wxEVT_COMMAND_BUTTON_CLICKED,(wxObjectEventFunction)&CDialogAskUserForCamera::OnBtnCancel);
117 
118  SetSizer(f1);
119  Fit();
120 
121  btnOk->SetFocus(); // So the default params can be accepted by just pressing ENTER.
122  }
123 
125  {
126  }
127 
128  void OnBtnOk(wxCommandEvent& event)
129  {
130  EndModal(wxID_OK);
131  }
132 
133  void OnBtnCancel(wxCommandEvent& event)
134  {
135  EndModal(wxID_CANCEL);
136  }
137 };
138 
139 const long CDialogAskUserForCamera::ID_BTN_OK = wxNewId();
140 const long CDialogAskUserForCamera::ID_BTN_CANCEL = wxNewId();
141 
142 
143 // ---------------------------------------------------------------------------------------
144 // The wx dummy frame:
145 // ---------------------------------------------------------------------------------------
146 BEGIN_EVENT_TABLE(WxSubsystem::CWXMainFrame,wxFrame)
147 
148 END_EVENT_TABLE()
149 
150 
151 const long ID_TIMER_WX_PROCESS_REQUESTS = wxNewId();
152 
153 
154 WxSubsystem::CWXMainFrame::CWXMainFrame(wxWindow* parent,wxWindowID id)
155 {
156  Create(
157  parent,
158  id,
159  _("MRPT-dummy frame window"),
160  wxDefaultPosition,
161  wxSize(1,1),
162  0, //wxDEFAULT_FRAME_STYLE,
163  _T("id"));
164 
165  if (oneInstance)
166  {
167  cerr << "[CWXMainFrame] More than one instance running!" << endl;
168  }
169  oneInstance = this;
170 
171  // ------------------------------------------------------------------------------------------
172  // Create a timer so requests from the main application thread can be processed regularly:
173  // ------------------------------------------------------------------------------------------
174  Connect(ID_TIMER_WX_PROCESS_REQUESTS, wxEVT_TIMER ,(wxObjectEventFunction)&CWXMainFrame::OnTimerProcessRequests);
175  m_theTimer = new wxTimer(this, ID_TIMER_WX_PROCESS_REQUESTS );
176 
177  m_theTimer->Start( 10, true ); // One-shot
178 }
179 
181 {
182 #ifdef WXSUBSYSTEM_VERBOSE
183  cout << "[CWXMainFrame] Destructor." << endl;
184 #endif
185  delete m_theTimer;
186  oneInstance=NULL;
187 
188  // Purge all pending requests:
190  while (NULL!=(msg= popPendingWxRequest()))
191  delete[] msg;
192 
193 }
194 
196 {
197  CCriticalSectionLocker lock(&cs_windowCount);
198  return ++m_windowCount;
199 }
200 
202 {
203  int ret;
204  {
205  CCriticalSectionLocker lock(&cs_windowCount);
206  ret = --m_windowCount;
207  }
208 
209  if (ret==0)
210  {
211  // That was the last window... we should close the wx subsystem:
212  if (oneInstance)
213  {
214 #ifdef WXSHUTDOWN_DO_IT_CLEAN
215  CWXMainFrame * me = (CWXMainFrame*)(oneInstance); // cast away the "volatile".
216  me->Close();
217 #endif
218 
219 #ifdef WXSUBSYSTEM_VERBOSE
220  cout << "[CWXMainFrame::notifyWindowDestruction] numWindows=0. me->Close() called." << endl;
221 #endif
222  }
223  }
224 
225  return ret;
226 }
227 
228 /** Thread-safe method to return the next pending request, or NULL if there is none (After usage, FREE the memory!)
229  */
231 {
232  if (!cs_listPendingWxRequests)
233  {
234  cs_listPendingWxRequests= new CCriticalSection();
235  listPendingWxRequests = new std::queue<TRequestToWxMainThread*>;
236  }
237 
238  synch::CCriticalSectionLocker locker( cs_listPendingWxRequests );
239 
240  // Is empty?
241  if (listPendingWxRequests->empty())
242  return NULL;
243 
244  TRequestToWxMainThread *ret=listPendingWxRequests->front();
245  listPendingWxRequests->pop(); // Remove from the queue
246 
247  return ret;
248 }
249 
250 /** Thread-safe method to insert a new pending request (The memory must be dinamically allocated with "new T[1]", will be freed by receiver.)
251  */
253 {
255  {
256  #ifdef WXSUBSYSTEM_VERBOSE
257  cout << "[WxSubsystem::pushPendingWxRequest] IGNORING request since app seems already closed.\n";
258  #endif
259  delete[] data;
260  return; // wx subsystem already closed, ignore.
261  }
262 
263  if (!cs_listPendingWxRequests)
264  {
265  cs_listPendingWxRequests= new CCriticalSection();
266  listPendingWxRequests = new std::queue<TRequestToWxMainThread*>;
267  }
268 
269  CCriticalSectionLocker locker(cs_listPendingWxRequests);
270  listPendingWxRequests->push( data );
271 }
272 
273 
274 /** This method processes the pending requests from the main MRPT application thread.
275  * The requests may be to create a new window, close another one, change title, etc...
276  */
278 {
279  bool app_closed = false;
280  try
281  {
283 
284 #ifdef WXSUBSYSTEM_VERBOSE
285  cout << "[OnTimerProcessRequests] Entering" << endl;
286 #endif
287 
288  // For each pending request:
289  while ( NULL != (msg = popPendingWxRequest() ) )
290  {
291  // Process it:
292  switch (msg->OPCODE)
293  {
294  // CREATE NEW WINDOW
295  case 200:
296  if (msg->source2D)
297  {
298  CWindowDialog *wnd = new CWindowDialog(msg->source2D, this, (wxWindowID) -1, msg->str, wxSize(msg->x,msg->y) );
299 
300  // Set the "m_hwnd" member of the window:
301  * ((void**)msg->voidPtr) = (void*)wnd;
302 
303  // Signal to the constructor (still waiting) that the window is now ready so it can continue:
305 
306  wnd->Show();
307  }
308  break;
309  // UPDATE IMAGE
310  case 201:
311  if (msg->source2D)
312  {
313  CWindowDialog *wnd = (CWindowDialog*) msg->voidPtr; //msg->source2D->getWxObject();
314  if (!wnd) break;
315  wxImage *img = (wxImage*) msg->voidPtr2;
316  if (!img) break;
317 
318  wnd->m_image->AssignImage(new wxBitmap(*img)); // Memory will be freed by the object.
319 
320  if (wnd->m_image->GetSize().GetX() != img->GetWidth() &&
321  wnd->m_image->GetSize().GetY() != img->GetHeight() )
322  {
323  wnd->m_image->SetSize( img->GetWidth(), img->GetHeight() );
324  wnd->m_image->SetMinSize( wxSize( img->GetWidth(), img->GetHeight() ));
325  wnd->m_image->SetMaxSize( wxSize( img->GetWidth(), img->GetHeight() ));
326  wnd->Fit();
327  //wnd->SetClientSize(img->GetWidth(), img->GetHeight());
328  }
329  delete img;
330  wnd->m_image->Refresh(false); // false: Do NOT erase background: avoid flickering
331  }
332  break;
333  // Set position
334  case 202:
335  if (msg->source2D)
336  {
338  if (wnd)
339  wnd->SetSize( msg->x, msg->y, wxDefaultCoord, wxDefaultCoord );
340  }
341  break;
342  // Set size
343  case 203:
344  if (msg->source2D)
345  {
347  if (wnd)
348  wnd->SetClientSize( msg->x, msg->y );
349  }
350  break;
351  // Set window's title:
352  case 204:
353  if (msg->source2D)
354  {
356  if (wnd)
357  wnd->SetTitle( _U(msg->str.c_str()) );
358  }
359  break;
360  // DESTROY EXISTING WINDOW:
361  case 299:
362  if (msg->source2D)
363  {
365  if (wnd)
366  {
367  //delete wnd;
368  wnd->Close();
369  }
370  }
371  break;
372 
373  // CREATE NEW WINDOW
374  case 300:
375  if (msg->source3D )
376  {
377  C3DWindowDialog *wnd = new C3DWindowDialog(msg->source3D, this, (wxWindowID) -1, msg->str, wxSize(msg->x,msg->y) );
378 
379  // Set the "m_hwnd" member of the window:
380  * ((void**)msg->voidPtr) = (void*)wnd;
381 
382  // Signal to the constructor (still waiting) that the window is now ready so it can continue:
384 
385  wnd->Show();
386  }
387  break;
388  // Set position
389  case 302:
390  if (msg->source3D )
391  {
393  if (wnd)
394  wnd->SetSize( msg->x, msg->y, wxDefaultCoord, wxDefaultCoord );
395  }
396  break;
397  // Set size
398  case 303:
399  if (msg->source3D )
400  {
402  if (wnd)
403  wnd->SetClientSize( msg->x, msg->y );
404  }
405  break;
406  // Set window's title:
407  case 304:
408  if (msg->source3D )
409  {
411  if (wnd)
412  wnd->SetTitle( _U(msg->str.c_str()) );
413  }
414  break;
415  // FORCE REPAINT
416  case 350:
417  if (msg->source3D )
418  {
420  if (wnd)
421  {
422  wnd->Refresh(false);
423  }
424  }
425  break;
426  // Add a 2D text message: vector_x: [0]:x, [1]:y, [2,3,4]:R G B, "x": enum of desired font. "y": unique index, "str": String.
427  case 360:
428  if (msg->source3D )
429  {
431  if (wnd)
432  {
433  wnd->addTextMessage(
434  msg->vector_x[0],msg->vector_x[1],
435  msg->str,
436  mrpt::utils::TColorf(msg->vector_x[2],msg->vector_x[3],msg->vector_x[4]),
437  size_t(msg->y),
439  }
440  }
441  break;
442  // Clear 2D text messages
443  case 361:
444  if (msg->source3D )
445  {
447  if (wnd)
448  {
449  wnd->clearTextMessages();
450  }
451  }
452  break;
453  // Add a 2D text message: vector_x: [0]:x, [1]:y, [2,3,4]:R G B, "x": enum of desired font. "y": unique index, "str": String.
454  case 362:
455  if (msg->source3D )
456  {
458  if (wnd)
459  {
460  wnd->addTextMessage(
461  msg->vector_x[0],msg->vector_x[1],
462  msg->str,
463  mrpt::utils::TColorf(msg->vector_x[2],msg->vector_x[3],msg->vector_x[4]),
464  msg->plotName,
465  msg->vector_x[5],
467  size_t(msg->y),
468  msg->vector_x[6],msg->vector_x[7],
469  msg->vector_x[8]!=0,
470  mrpt::utils::TColorf(msg->vector_x[9],msg->vector_x[10],msg->vector_x[11])
471  );
472  }
473  }
474  break;
475 
476  // DESTROY EXISTING WINDOW:
477  case 399:
478  if (msg->source3D )
479  {
481  if (wnd)
482  {
483  //delete wnd;
484  wnd->Close();
485  }
486  }
487  break;
488 
489  // CREATE NEW WINDOW
490  case 400:
491  if (msg->sourcePlots )
492  {
493  CWindowDialogPlots *wnd = new CWindowDialogPlots(msg->sourcePlots, this, (wxWindowID) -1, msg->str, wxSize(msg->x,msg->y) );
494 
495  // Set the "m_hwnd" member of the window:
496  * ((void**)msg->voidPtr) = (void*)wnd;
497 
498  // Signal to the constructor (still waiting) that the window is now ready so it can continue:
500 
501  wnd->Show();
502  }
503  break;
504  // Set position
505  case 402:
506  if (msg->sourcePlots )
507  {
509  if (wnd)
510  wnd->SetSize( msg->x, msg->y, wxDefaultCoord, wxDefaultCoord );
511  }
512  break;
513  // Set size
514  case 403:
515  if (msg->sourcePlots )
516  {
518  if (wnd)
519  wnd->SetClientSize( msg->x, msg->y );
520  }
521  break;
522  // Set window's title:
523  case 404:
524  if (msg->sourcePlots )
525  {
527  if (wnd)
528  wnd->SetTitle( _U(msg->str.c_str()) );
529  }
530  break;
531  // Mouse pan
532  case 410:
533  if (msg->sourcePlots )
534  {
536  if (wnd) wnd->m_plot->EnableMousePanZoom(msg->boolVal);
537  }
538  break;
539  // Aspect ratio
540  case 411:
541  if (msg->sourcePlots )
542  {
544  if (wnd) wnd->m_plot->LockAspect(msg->boolVal);
545  }
546  break;
547 
548  // Zoom over a rectangle vectorx[0-1] & vectory[0-1]
549  case 412:
550  if (msg->sourcePlots )
551  {
553  if (wnd)
554  {
555  if (msg->vector_x.size()==2 && msg->vector_y.size()==2)
556  {
557  wnd->m_plot->Fit( msg->vector_x[0],msg->vector_x[1],msg->vector_y[0],msg->vector_y[1] );
558  wnd->m_plot->LockAspect(msg->boolVal);
559  }
560  }
561  }
562  break;
563  // Axis fit, with aspect ratio fix to boolVal.
564  case 413:
565  if (msg->sourcePlots )
566  {
568  if (wnd)
569  {
570  wnd->m_plot->LockAspect(msg->boolVal);
571  wnd->m_plot->Fit();
572  }
573  }
574  break;
575  // Clear all objects:
576  case 414:
577  if (msg->sourcePlots )
578  {
580  if (wnd)
581  {
582  wnd->m_plot->DelAllLayers(true,true);
583  wnd->m_plot->AddLayer( new mpScaleX() );
584  wnd->m_plot->AddLayer( new mpScaleY() );
585  }
586  }
587  break;
588 
589  // Create/modify 2D plot
590  case 420:
591  if (msg->sourcePlots )
592  {
594  if (wnd)
595  wnd->plot( msg->vector_x, msg->vector_y, msg->str, msg->plotName );
596  }
597  break;
598 
599  // Create/modify 2D ellipse
600  case 421:
601  if (msg->sourcePlots )
602  {
604  if (wnd)
605  wnd->plotEllipse( msg->vector_x, msg->vector_y, msg->str, msg->plotName, msg->boolVal );
606  }
607  break;
608 
609  // Create/modify bitmap image
610  case 422:
611  if (msg->sourcePlots )
612  {
614  if (wnd)
615  wnd->image(
616  msg->voidPtr2,
617  msg->vector_x[0],
618  msg->vector_x[1],
619  msg->vector_x[2],
620  msg->vector_x[3],
621  msg->plotName );
622  }
623  break;
624 
625  // 440: Insert submenu in the popup menu. name=menu label, x=ID
626  case 440:
627  if (msg->sourcePlots )
628  {
630  if (wnd)
631  {
632  const long MENUITEM_ID = wxNewId();
633  // Remember the association between this ID and the user ID:
634  wnd->m_ID2ID[MENUITEM_ID] = msg->x;
635 
636  wxMenu *popupMnu = wnd->m_plot->GetPopupMenu();
637  if (wnd->m_firstSubmenu)
638  {
639  wnd->m_firstSubmenu=false;
640  popupMnu->InsertSeparator(0);
641  }
642  wxMenuItem *mnuTarget = new wxMenuItem(popupMnu, MENUITEM_ID, _U(msg->plotName.c_str()), wxEmptyString, wxITEM_NORMAL);
643  popupMnu->Insert(0,mnuTarget);
644 
645  wnd->Connect( MENUITEM_ID, wxEVT_COMMAND_MENU_SELECTED, (wxObjectEventFunction) &CWindowDialogPlots::OnMenuSelected );
646 
647  }
648  }
649  break;
650 
651  // DESTROY EXISTING WINDOW:
652  case 499:
653  if (msg->sourcePlots )
654  {
656  if (wnd)
657  {
658  //delete wnd;
659  wnd->Close();
660  }
661  }
662  break;
663 
664  // CREATE NEW WINDOW
665  case 700:
666  if (msg->sourceCameraSelectDialog)
667  {
668  mrpt::synch::CSemaphore *sem = reinterpret_cast<mrpt::synch::CSemaphore*>(msg->voidPtr);
669 
671  // Signal that the window is ready:
672  sem->release(1);
673 
674  // Show
675  const bool wasOk = (dlg->ShowModal() == wxID_OK);
676 
677  // send selection to caller:
679 
680  // Parse selection as a config text block:
682  ret->accepted_by_user = wasOk;
683 
684  delete dlg;
685 
686  sem->release(1);
687 
688  } break;
689 
690 
691  // wxSubsystem shutdown:
692  case 999:
693  {
694 #ifdef WXSUBSYSTEM_VERBOSE
695  cout << "[WxSubsystem:999] Shutdown" << endl;
696 #endif
697  app_closed = true; // Do NOT launch a timer again
700 #ifdef WXSUBSYSTEM_VERBOSE
701  cout << "[WxSubsystem:999] Shutdown done" << endl;
702 #endif
703  }
704  break;
705 
706  } // end switch OPCODE
707 
708  // Free the memory:
709  delete[] msg;
710  } // end while
711  }
712  catch(...)
713  {
714  }
715 
716  if (!app_closed)
717  m_theTimer->Start( 10, true ); // One-shot
718 }
719 
720 // ---------------------------------------------------------------------------------------
721 // MRPT Icons
722 // ---------------------------------------------------------------------------------------
723 const char * mrpt_default_icon_xpm[] = {
724 "32 32 2 1",
725 " c None",
726 ". c #000000",
727 " ",
728 " ",
729 " ",
730 " ..... ..... ......... ",
731 " .... .... ... .... ",
732 " ..... .... ... ... ",
733 " . ... . ... ... ... ",
734 " . ... . ... ... ... ",
735 " . ... . ... ... ... ",
736 " . ... . ... ........ ",
737 " . ..... ... ... .... ",
738 " . ... ... ... .... ",
739 " . ... ... ... .... ",
740 " . .. ... ... .... ",
741 " ... . ..... ..... ..... ",
742 " ",
743 " ",
744 " ........ ........... ",
745 " ... .... .. ... .. ",
746 " ... ... . ... . ",
747 " ... ... ... ",
748 " ... ... ... ",
749 " ... ... ... ",
750 " ....... ... ",
751 " ... ... ",
752 " ... ... ",
753 " ... ... ",
754 " ... ... ",
755 " ..... ..... ",
756 " ",
757 " ",
758 " "};
759 
761 {
762  // To avoid an error in wx, always resize the icon to the expected size:
763 #ifdef MRPT_OS_WINDOWS
764  const wxSize iconsSize(::GetSystemMetrics(SM_CXICON), ::GetSystemMetrics(SM_CYICON));
765  return wxBitmap(wxBitmap(mrpt_default_icon_xpm).ConvertToImage().Scale(iconsSize.x,iconsSize.y));
766 #else
767  return wxBitmap(mrpt_default_icon_xpm);
768 #endif
769 }
770 
771 // ---------------------------------------------------------------------------------------
772 // The wx app:
773 // ---------------------------------------------------------------------------------------
774 class CDisplayWindow_WXAPP : public wxApp
775 {
776  public:
777  virtual bool OnInit();
778  virtual int OnExit();
779 };
780 
782 {
783  // Starting in wxWidgets 2.9.0, we must reset numerics locale to "C",
784  // if we want numbers to use "." in all countries. The App::OnInit() is a perfect place to undo
785  // the default wxWidgets settings. (JL @ Sep-2009)
786  wxSetlocale(LC_NUMERIC, wxString(wxT("C")) );
787 
788  wxInitAllImageHandlers();
789 
790  //cout << "[wxApp::OnInit] wxApplication OnInit called." << endl;
791 
792  // Create a dummy frame:
794  Frame->Hide();
795 
796  // We are ready!!
797  //cout << "[wxMainThread] Signaling semaphore." << endl;
799 
800  return true;
801 }
802 
803 // This will be called when all the windows / frames are closed.
805 {
806 #ifdef WXSUBSYSTEM_VERBOSE
807  cout << "[wxApp::OnExit] wxApplication OnExit called." << endl;
808 #endif
809 
810  CCriticalSectionLocker lock(& WxSubsystem::GetWxMainThreadInstance().m_csWxMainThreadId );
811 
812  wxApp::OnExit();
813  CleanUp();
814  //WxSubsystem::GetWxMainThreadInstance().m_wxMainThreadId.clear(); // Moved to wxMainThread()
815  return 0;
816 }
817 
818 
819 /** This method must be called in the destructor of the user class FROM THE MAIN THREAD, in order to wait for the shutdown of the wx thread if this was the last open window.
820  */
822 {
823 #ifndef WXSHUTDOWN_DO_IT_CLEAN
824 
825  #ifdef WXSUBSYSTEM_VERBOSE
826  cout << "[WxSubsystem::waitWxShutdownsIfNoWindows] Doing a quick sleep() and returning.\n";
827  #endif
828  mrpt::system::sleep(100);
829  return;
830 #else
831  // Just let know a global object that, at its destruction, it must ....
832  // Any open windows?
833  int nOpenWnds;
834  {
835  CCriticalSectionLocker locker(&CWXMainFrame::cs_windowCount);
836  nOpenWnds = CWXMainFrame::m_windowCount;
837  }
838 
839  if (!nOpenWnds && WxSubsystem::isConsoleApp)
840  {
841 #ifdef WXSUBSYSTEM_VERBOSE
842  cout << "[WxSubsystem::waitWxShutdownsIfNoWindows] Waiting for WxWidgets thread to shutdown...\n";
843 #endif
844 
845  // Then we must be shutting down in the wx thread (we are in the main MRPT application thread)...
846  // Wait until wx is safely shut down:
847  bool done=false;
848  int maxTimeout =
849 #ifdef _DEBUG
850  3000;
851 #else
852  500;
853 #endif
854  while (!done && --maxTimeout >0)
855  {
856  system::sleep(10);
860  }
861 
862  if (maxTimeout<=0)
863  {
864  cerr << "[WxSubsystem::waitWxShutdownsIfNoWindows] Timeout waiting for WxWidgets thread to shutdown!" << endl;
865  }
866  }
867 #endif
868 }
869 
870 wxAppConsole *mrpt_wxCreateApp()
871 {
872  wxAppConsole::CheckBuildOptions(WX_BUILD_OPTIONS_SIGNATURE, "your program");
873  return new CDisplayWindow_WXAPP;
874 }
875 
876 //DECLARE_APP(CDisplayWindow_WXAPP)
878 
879 
880 // Aux. funcs used in WxSubsystem::wxMainThread
881 // --------------------------------------------------
882 int mrpt_wxEntryReal(int argc, char **argv)
883 {
884  // library initialization
885  if ( !wxEntryStart(argc, argv) )
886  {
887 #if wxUSE_LOG
888  // flush any log messages explaining why we failed
889  delete wxLog::SetActiveTarget(NULL);
890 #endif
891  return -1;
892  }
893 
894  // if wxEntryStart succeeded, we must call wxEntryCleanup even if the code
895  // below returns or throws
896  try
897  {
898  // app initialization
899  if ( ! wxTheApp->CallOnInit() )
900  return -1; // don't call OnExit() if OnInit() failed
901 
902  // app execution
903  int ret = wxTheApp->OnRun();
904 
905  {
906  wxLogNull logNo; // Skip any warning in this scope.
907 
908  wxTheApp->OnExit(); // This replaces the above callOnExit class
909  wxEntryCleanup();
910  }
911 
912  return ret;
913  }
914  catch(...)
915  {
916  wxTheApp->OnUnhandledException();
917  wxEntryCleanup();
918  return -1;
919  }
920 
921 }
922 
923 /*---------------------------------------------------------------
924  wxMainThread
925  This will be the "MAIN" of wxWidgets: It starts an application
926  object and does not end until all the windows are closed.
927  Only for console apps, not for user GUI apps already with wx.
928  ---------------------------------------------------------------*/
930 {
931  MRPT_START
932 
933  // Prepare wxWidgets:
934  int argc=1;
935  static const char *dummy_prog_name = "./MRPT";
936  char *argv[2] = { const_cast<char*>(dummy_prog_name), NULL };
937 
938 #ifdef WXSUBSYSTEM_VERBOSE
939  cout << "[wxMainThread] Starting..." << endl;
940 #endif
941 
942  // Are we in a console or wxGUI application????
943  wxAppConsole *app_gui = wxApp::GetInstance();
944  if (!app_gui)
945  {
946  // We are NOT in a wx application (it's a console program)
947  // ---------------------------------------------------------
948 #ifdef WXSUBSYSTEM_VERBOSE
949  cout << "[wxMainThread] I am in a console app" << endl;
950 #endif
951  // Start a new wx application object:
952 
953  // JLBC OCT2008: wxWidgets little hack to enable console/gui mixed applications:
954  wxApp::SetInitializerFunction( (wxAppInitializerFunction) mrpt_wxCreateApp );
955  mrpt_wxEntryReal(argc,argv);
956 
957 #ifdef WXSUBSYSTEM_VERBOSE
958  cout << "[wxMainThread] Finished" << endl;
959 #endif
960 
961  // Now this thread is ready. The main thread is free to end now:
963  }
964  else
965  {
966  // We are ALREADY in a wx application:
967  // ---------------------------------------------------------
968 #ifdef WXSUBSYSTEM_VERBOSE
969  cout << "[wxMainThread] I am in a GUI app" << endl;
970 #endif
971  wxWindow *topWin = static_cast<wxApp*>(app_gui)->GetTopWindow();
972 
974  Frame->Hide();
975 
976  // We are ready!!
977 #ifdef WXSUBSYSTEM_VERBOSE
978  cout << "[wxMainThread] Signaling semaphore." << endl;
979 #endif
981 
982  }
983 
984  MRPT_END
985 }
986 
988 {
989  //static TWxMainThreadData dat;
990  // Create as dynamic memory, since it'll be deleted in CAuxWxSubsystemShutdowner:
991  static TWxMainThreadData *dat=NULL;
992  static bool first_creat = true;
993  if (!dat && first_creat) { first_creat=false; dat = new TWxMainThreadData; }
994  return *dat;
995 }
996 
998  m_wxMainThreadId(),
999  m_semWxMainThreadReady(0,1),
1000  m_csWxMainThreadId("csWxMainThreadId")
1001 {
1002 }
1003 
1004 
1005 /*---------------------------------------------------------------
1006  createOneInstanceMainThread
1007  ---------------------------------------------------------------*/
1009 {
1012 
1013  wxAppConsole *app_con = wxApp::GetInstance();
1014  if (app_con && wxmtd.m_wxMainThreadId.isClear())
1015  {
1016  // We are NOT in a console application: There is already a wxApp instance running and it's not us.
1017  WxSubsystem::isConsoleApp = false;
1018  //cout << "[createOneInstanceMainThread] Mode: User GUI." << endl;
1020  {
1021  // Create our main hidden frame:
1022  wxWindow *topWin = static_cast<wxApp*>(app_con)->GetTopWindow();
1023 
1025  //Frame->Show();
1026  //SetTopWindow(Frame);
1027  Frame->Hide();
1028  }
1029  }
1030  else
1031  {
1032  //cout << "[createOneInstanceMainThread] Mode: Console." << endl;
1034  if (wxmtd.m_wxMainThreadId.isClear())
1035  {
1036 #ifdef WXSUBSYSTEM_VERBOSE
1037  printf("[WxSubsystem::createOneInstanceMainThread] Launching wxMainThread() thread...\n");
1038 #endif
1039  // Create a thread for message processing there:
1041 
1042  int maxTimeout =
1043 #ifdef _DEBUG
1044  30000;
1045 #else
1046  5000;
1047 #endif
1048 
1049  // If we have an "MRPT_WXSUBSYS_TIMEOUT_MS" environment variable, use that timeout instead:
1050  const char *envVal = getenv("MRPT_WXSUBSYS_TIMEOUT_MS");
1051  if (envVal)
1052  maxTimeout = atoi(envVal);
1053 
1054  if(! wxmtd.m_semWxMainThreadReady.waitForSignal(maxTimeout) ) // A few secs should be enough...
1055  {
1056  cerr << "[WxSubsystem::createOneInstanceMainThread] Timeout waiting wxApplication to start up!" << endl;
1057  return false;
1058  }
1059  }
1060  }
1061 
1062  return true; // OK
1063 }
1064 
1065 
1066 #endif // MRPT_HAS_WXWIDGETS
An auxiliary global object used just to launch a final request to the wxSubsystem for shutdown: ...
Definition: WxSubsystem.h:118
static void pushPendingWxRequest(TRequestToWxMainThread *data)
Thread-safe method to insert a new pending request (The memory must be dinamically allocated with "ne...
void * voidPtr
Parameters, depending on OPCODE.
Definition: WxSubsystem.h:214
virtual bool OnInit()
This class provides simple critical sections functionality.
A class acquiring a CCriticalSection at its constructor, and releasing it at destructor.
void writeConfigFromVideoSourcePanel(const std::string &sect, mrpt::utils::CConfigFileBase *cfg) const
Definition: WxUtils.cpp:722
static const long ID_BTN_CANCEL
Definition: WxSubsystem.cpp:99
Classes for serialization, sockets, ini-file manipulation, streams, list of properties-values, timewatch, extensions to STL.
Definition: zip.h:16
static TRequestToWxMainThread * popPendingWxRequest()
Thread-safe method to return the next pending request, or NULL if there is none (After usage...
mrpt::gui::CDisplayWindow3D * source3D
Only one of source* can be non-NULL, indicating the class that generated the request.
Definition: WxSubsystem.h:200
The data structure for each inter-thread request:
Definition: WxSubsystem.h:182
#define _U(x)
Definition: WxSubsystem.h:470
static int notifyWindowCreation()
Atomically increments the number of windows created with the main frame as parent.
void AssignImage(wxBitmap *img)
Assigns this image. This object has the ownship of the image and will delete it when appropriate...
void OnTimerProcessRequests(wxTimerEvent &event)
This method processes the pending requests from the main MRPT application thread. ...
mrpt::gui::CPanelCameraSelection * panel
Definition: WxSubsystem.cpp:96
The wx dialog for gui::CDisplayWindowPlots.
Definition: WxSubsystem.h:403
mrpt::synch::CSemaphore m_semWxMainThreadReady
This is signaled when wxMainThread is ready.
Definition: WxSubsystem.h:168
static wxBitmap getMRPTDefaultIcon()
bool waitForSignal(unsigned int timeout_ms=0)
Blocks until the count of the semaphore to be non-zero.
Definition: CSemaphore.cpp:24
STL namespace.
const char * mrpt_default_icon_xpm[]
static volatile CWXMainFrame * oneInstance
Definition: WxSubsystem.h:148
static TWxMainThreadData & GetWxMainThreadInstance()
void OnBtnOk(wxCommandEvent &event)
int mrpt_wxEntryReal(int argc, char **argv)
TThreadHandle createThread(void(*func)(T), T param)
Creates a new thread from a function (or static method) with one generic parameter.
Definition: threads.h:80
int OPCODE
Valid codes are: For CDisplayWindow:
Definition: WxSubsystem.h:259
const long ID_TIMER_WX_PROCESS_REQUESTS
static std::queue< TRequestToWxMainThread * > * listPendingWxRequests
Do not access directly to this, use the thread-safe functions.
Definition: WxSubsystem.h:280
wxMRPTImageControl * m_image
Definition: WxSubsystem.h:330
static const long ID_BTN_OK
Definition: WxSubsystem.cpp:98
void leave() const MRPT_OVERRIDE
Leave.
void OnMenuSelected(wxCommandEvent &ev)
TOpenGLFont
Existing fonts for 2D texts in mrpt::opengl methods.
Definition: opengl_fonts.h:26
static synch::CCriticalSection * cs_listPendingWxRequests
Definition: WxSubsystem.h:281
wxAppConsole * mrpt_wxCreateApp()
#define MRPT_END
void addTextMessage(const double x_frac, const double y_frac, const std::string &text, const mrpt::utils::TColorf &color, const size_t unique_index, const mrpt::opengl::TOpenGLFont font)
void BASE_IMPEXP sleep(int time_ms) MRPT_NO_THROWS
An OS-independent method for sending the current thread to "sleep" for a given period of time...
Definition: threads.cpp:57
GLint GLvoid * img
Definition: glext.h:3645
TOpenGLFontStyle
Different style for vectorized font rendering.
Definition: opengl_fonts.h:37
void * getWxObject()
Read-only access to the wxDialog object.
void enter() const MRPT_OVERRIDE
Enter.
void plot(const mrpt::math::CVectorFloat &x, const mrpt::math::CVectorFloat &y, const std::string &lineFormat, const std::string &plotName)
Redirected from CDisplayWindowPlots::plot.
The main frame of the wxWidgets application.
Definition: WxSubsystem.h:130
void release(unsigned int increaseCount=1)
Increments the count of the semaphore by a given amount.
Definition: CSemaphore.cpp:41
The wx dialog for gui::CDisplayWindow.
Definition: WxSubsystem.h:290
void OnBtnCancel(wxCommandEvent &event)
bool sourceCameraSelectDialog
Only one of source* can be non-NULL, indicating the class that generated the request.
Definition: WxSubsystem.h:206
bool isClear() const
Returns true if the handle is uninitialized.
Definition: threads.h:45
This namespace provides multitask, synchronization utilities.
virtual int OnExit()
static void wxMainThread()
This will be the "MAIN" of wxWidgets: It starts an application object and does not end until all the ...
void clear()
Mark the handle as invalid.
Definition: threads.h:38
virtual ~CDialogAskUserForCamera()
void image(void *theWxImage, const float &x0, const float &y0, const float &w, const float &h, const std::string &plotName)
Redirected from CDisplayWindowPlots::image.
static void waitWxShutdownsIfNoWindows()
This method must be called in the destructor of the user class FROM THE MAIN THREAD, in order to wait for the shutdown of the wx thread if this was the last open window.
#define MRPT_START
This is the global namespace for all Mobile Robot Programming Toolkit (MRPT) libraries.
This class implements the GUI thread required for the wxWidgets-based GUI.
Definition: WxSubsystem.h:99
CDisplayWindow_WXAPP & wxGetApp()
void plotEllipse(const mrpt::math::CVectorFloat &x, const mrpt::math::CVectorFloat &y, const std::string &lineFormat, const std::string &plotName, bool showName=false)
Redirected from CDisplayWindowPlots::plotEllipse.
A RGB color - floats in the range [0,1].
Definition: TColor.h:80
static CAuxWxSubsystemShutdowner global_wxsubsystem_shutdown
Definition: WxSubsystem.h:125
A panel to select the camera input from all the formats supported by MRPT.
Definition: WxUtils.h:163
mrpt::gui::CDisplayWindowPlots * sourcePlots
Only one of source* can be non-NULL, indicating the class that generated the request.
Definition: WxSubsystem.h:203
mrpt::synch::CCriticalSection m_csWxMainThreadId
The critical section for accessing "m_wxMainThreadId".
Definition: WxSubsystem.h:169
mrpt::utils::CConfigFileMemory selectedConfig
Definition: WxUtils.h:293
Classes for creating GUI windows for 2D and 3D visualization.
std::map< long, long > m_ID2ID
wxIDs to user IDs for submenus.
Definition: WxSubsystem.h:417
static synch::CCriticalSection cs_windowCount
Definition: WxSubsystem.h:153
static volatile bool isConsoleApp
Will be set to true at runtime if it&#39;s not detected a running wxApp instance.
Definition: WxSubsystem.h:114
mrpt::gui::CDisplayWindow * source2D
Only one of source* can be non-NULL, indicating the class that generated the request.
Definition: WxSubsystem.h:197
std::string str
Parameters, depending on OPCODE.
Definition: WxSubsystem.h:210
void notifySemThreadReady()
Called by wx main thread to signal the semaphore that the wx window is built and ready.
GLsizei GLsizei GLenum GLenum const GLvoid * data
Definition: glext.h:3520
mrpt::system::TThreadHandle m_wxMainThreadId
The thread ID of wxMainThread, or 0 if it is not running.
Definition: WxSubsystem.h:167
A semaphore for inter-thread synchronization.
Definition: CSemaphore.h:31
static bool createOneInstanceMainThread()
Thread-safe method to create one single instance of the main wxWidgets thread: it will create the thr...
static int notifyWindowDestruction()
Atomically decrements the number of windows created with the main frame as parent.
bool m_firstSubmenu
to know whether to insert a separator the first time.
Definition: WxSubsystem.h:416



Page generated by Doxygen 1.8.14 for MRPT 1.5.7 Git: 5902e14cc Wed Apr 24 15:04:01 2019 +0200 at lun oct 28 01:39:17 CET 2019