NXWidgets  1.19
cnxterm.cxx
Go to the documentation of this file.
1 /********************************************************************************************
2  * NxWidgets/nxwm/src/cnxterm.cxx
3  *
4  * Copyright (C) 2012. 2104 Gregory Nutt. All rights reserved.
5  * Author: Gregory Nutt <gnutt@nuttx.org>
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  * notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  * notice, this list of conditions and the following disclaimer in
15  * the documentation and/or other materials provided with the
16  * distribution.
17  * 3. Neither the name NuttX, NxWidgets, nor the names of its contributors
18  * me be used to endorse or promote products derived from this software
19  * without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
28  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *
34  ********************************************************************************************/
35 
36 /********************************************************************************************
37  * Included Files
38  ********************************************************************************************/
39 
40 #include <nuttx/config.h>
41 
42 #include <cstdio>
43 #include <cstdlib>
44 #include <cunistd>
45 #include <ctime>
46 
47 #include <fcntl.h>
48 #include <semaphore.h>
49 #include <sched.h>
50 #include <debug.h>
51 
52 #include "nshlib/nshlib.h"
53 
54 #include "cwidgetcontrol.hxx"
55 
56 #include "nxwmconfig.hxx"
57 #include "nxwmglyphs.hxx"
58 #include "cnxterm.hxx"
59 
60 /********************************************************************************************
61  * Pre-Processor Definitions
62  ********************************************************************************************/
63 /* Configuration ****************************************************************************/
64 
65 #ifdef CONFIG_NSH_USBKBD
66 # warning You probably do not really want CONFIG_NSH_USBKBD, try CONFIG_NXWM_KEYBOARD_USBHOST
67 #endif
68 
69 /* If Telnet is used and both IPv6 and IPv4 are enabled, then we need to
70  * pick one.
71  */
72 
73 #ifdef CONFIG_NET_IPv6
74 # define ADDR_FAMILY AF_INET6
75 #else
76 # define ADDR_FAMILY AF_INET
77 #endif
78 /********************************************************************************************
79  * Private Types
80  ********************************************************************************************/
81 
82 namespace NxWM
83 {
84  /**
85  * This structure is used to pass start up parameters to the NxTerm task and to assure the
86  * the NxTerm is successfully started.
87  */
88 
89  struct SNxTerm
90  {
91  FAR void *console; /**< The console 'this' pointer use with on_exit() */
92  sem_t exclSem; /**< Sem that gives exclusive access to this structure */
93  sem_t waitSem; /**< Sem that posted when the task is initialized */
94  NXTKWINDOW hwnd; /**< Window handle */
95  NXTERM nxterm; /**< NxTerm handle */
96  int minor; /**< Next device minor number */
97  struct nxterm_window_s wndo; /**< Describes the NxTerm window */
98  bool result; /**< True if successfully initialized */
99  };
100 
101 /********************************************************************************************
102  * Private Data
103  ********************************************************************************************/
104 
105  /**
106  * This global data structure is used to pass start parameters to NxTerm task and to
107  * assure that the NxTerm is successfully started.
108  */
109 
110  static struct SNxTerm g_nxtermvars;
111 }
112 
113 /********************************************************************************************
114  * Private Functions
115  ********************************************************************************************/
116 
117 /********************************************************************************************
118  * CNxTerm Method Implementations
119  ********************************************************************************************/
120 
121 using namespace NxWM;
122 
123 /**
124  * CNxTerm constructor
125  *
126  * @param window. The application window
127  */
128 
130 {
131  // Save the constructor data
132 
133  m_taskbar = taskbar;
134  m_window = window;
135 
136  // The NxTerm is not runing
137 
138  m_pid = -1;
139  m_nxterm = 0;
140 
141  // Add our personalized window label
142 
143  NXWidgets::CNxString myName = getName();
144  window->setWindowLabel(myName);
145 
146  // Add our callbacks with the application window
147 
148  window->registerCallbacks(static_cast<IApplicationCallback *>(this));
149 }
150 
151 /**
152  * CNxTerm destructor
153  *
154  * @param window. The application window
155  */
156 
158 {
159  // There would be a problem if we were stopped with the NxTerm task
160  // running... that should never happen but we'll check anyway:
161 
162  stop();
163 
164  // Although we didn't create it, we are responsible for deleting the
165  // application window
166 
167  delete m_window;
168 }
169 
170 /**
171  * Each implementation of IApplication must provide a method to recover
172  * the contained CApplicationWindow instance.
173  */
174 
176 {
177  return static_cast<IApplicationWindow*>(m_window);
178 }
179 
180 /**
181  * Get the icon associated with the application
182  *
183  * @return An instance if IBitmap that may be used to rend the
184  * application's icon. This is an new IBitmap instance that must
185  * be deleted by the caller when it is no long needed.
186  */
187 
189 {
191  new NXWidgets::CRlePaletteBitmap(&CONFIG_NXWM_NXTERM_ICON);
192 
193  return bitmap;
194 }
195 
196 /**
197  * Get the name string associated with the application
198  *
199  * @return A copy if CNxString that contains the name of the application.
200  */
201 
203 {
204  return NXWidgets::CNxString("NuttShell");
205 }
206 
207 /**
208  * Start the application (perhaps in the minimized state).
209  *
210  * @return True if the application was successfully started.
211  */
212 
213 bool CNxTerm::run(void)
214 {
215  // Some sanity checking
216 
217  if (m_pid >= 0 || m_nxterm != 0)
218  {
219  gerr("ERROR: All ready running or connected\n");
220  return false;
221  }
222 
223  // Get exclusive access to the global data structure
224 
225  if (sem_wait(&g_nxtermvars.exclSem) != 0)
226  {
227  // This might fail if a signal is received while we are waiting.
228 
229  gerr("ERROR: Failed to get semaphore\n");
230  return false;
231  }
232 
233  // Recover the NXTK window instance contained in the application window
234 
235  NXWidgets::INxWindow *window = m_window->getWindow();
236 
237  // Get the widget control associated with the NXTK window
238 
239  NXWidgets::CWidgetControl *control = window->getWidgetControl();
240 
241  // Get the window handle from the widget control
242 
243  g_nxtermvars.hwnd = control->getWindowHandle();
244 
245  // Describe the NxTerm
246 
247  g_nxtermvars.wndo.wcolor[0] = CONFIG_NXWM_NXTERM_WCOLOR;
248  g_nxtermvars.wndo.fcolor[0] = CONFIG_NXWM_NXTERM_FONTCOLOR;
249  g_nxtermvars.wndo.fontid = CONFIG_NXWM_NXTERM_FONTID;
250 
251  // Get the size of the window
252 
253  (void)window->getSize(&g_nxtermvars.wndo.wsize);
254 
255  // Start the NxTerm task
256 
257  g_nxtermvars.console = (FAR void *)this;
258  g_nxtermvars.result = false;
259  g_nxtermvars.nxterm = 0;
260 
261  sched_lock();
262  m_pid = task_create("NxTerm", CONFIG_NXWM_NXTERM_PRIO,
263  CONFIG_NXWM_NXTERM_STACKSIZE, nxterm,
264  (FAR char * const *)0);
265 
266  // Did we successfully start the NxTerm task?
267 
268  bool result = true;
269  if (m_pid < 0)
270  {
271  gerr("ERROR: Failed to create the NxTerm task\n");
272  result = false;
273  }
274  else
275  {
276  // Wait for up to two seconds for the task to initialize
277 
278  struct timespec abstime;
279  clock_gettime(CLOCK_REALTIME, &abstime);
280  abstime.tv_sec += 2;
281 
282  int ret = sem_timedwait(&g_nxtermvars.waitSem, &abstime);
283  sched_unlock();
284 
285  if (ret == OK && g_nxtermvars.result)
286  {
287  // Re-direct NX keyboard input to the new NxTerm driver
288 
289  DEBUGASSERT(g_nxtermvars.nxterm != 0);
290 #ifdef CONFIG_NXTERM_NXKBDIN
291  window->redirectNxTerm(g_nxtermvars.nxterm);
292 #endif
293  // Save the handle to use in the stop method
294 
295  m_nxterm = g_nxtermvars.nxterm;
296  }
297  else
298  {
299  // sem_timedwait failed OR the NxTerm task reported a
300  // failure. Stop the application
301 
302  gerr("ERROR: Failed start the NxTerm task\n");
303  stop();
304  result = false;
305  }
306  }
307 
308  sem_post(&g_nxtermvars.exclSem);
309  return result;
310 }
311 
312 /**
313  * Stop the application.
314  */
315 
316 void CNxTerm::stop(void)
317 {
318  // Delete the NxTerm task if it is still running (this could strand
319  // resources). If we get here due to CTaskbar::stopApplication() processing
320  // initialed by CNxTerm::exitHandler, then do *not* delete the task (it
321  // is already being deleted).
322 
323  if (m_pid >= 0)
324  {
325  // Calling task_delete() will also invoke the on_exit() handler. We se
326  // m_pid = -1 before calling task_delete() to let the on_exit() handler,
327  // CNxTerm::exitHandler(), know that it should not do anything
328 
329  pid_t pid = m_pid;
330  m_pid = -1;
331 
332  // Then delete the NSH task, possibly stranding resources
333 
334  task_delete(pid);
335  }
336 
337  // Destroy the NX console device
338 
339  if (m_nxterm)
340  {
341  // Re-store NX keyboard input routing
342 
343 #ifdef CONFIG_NXTERM_NXKBDIN
344  NXWidgets::INxWindow *window = m_window->getWindow();
345  window->redirectNxTerm((NXTERM)0);
346 #endif
347 
348  // Unregister the NxTerm driver
349 
350  nxterm_unregister(m_nxterm);
351  m_nxterm = 0;
352  }
353 }
354 
355 /**
356  * Destroy the application and free all of its resources. This method
357  * will initiate blocking of messages from the NX server. The server
358  * will flush the window message queue and reply with the blocked
359  * message. When the block message is received by CWindowMessenger,
360  * it will send the destroy message to the start window task which
361  * will, finally, safely delete the application.
362  */
363 
365 {
366  // Block any further window messages
367 
368  m_window->block(this);
369 
370  // Make sure that the application is stopped
371 
372  stop();
373 }
374 
375 /**
376  * The application window is hidden (either it is minimized or it is
377  * maximized, but not at the top of the hierarchy
378  */
379 
380 void CNxTerm::hide(void)
381 {
382  // Disable drawing and events
383 }
384 
385 /**
386  * Redraw the entire window. The application has been maximized or
387  * otherwise moved to the top of the hierarchy. This method is call from
388  * CTaskbar when the application window must be displayed
389  */
390 
391 void CNxTerm::redraw(void)
392 {
393  // Recover the NXTK window instance contained in the application window
394 
395  NXWidgets::INxWindow *window = m_window->getWindow();
396 
397  // Get the size of the window
398 
399  struct nxgl_size_s windowSize;
400  (void)window->getSize(&windowSize);
401 
402  // Redraw the entire NxTerm window
403 
404  struct nxgl_rect_s rect;
405  rect.pt1.x = 0;
406  rect.pt1.y = 0;
407  rect.pt2.x = windowSize.w - 1;
408  rect.pt2.y = windowSize.h - 1;
409 
410  nxterm_redraw(m_nxterm, &rect, false);
411 }
412 
413 /**
414  * Report of this is a "normal" window or a full screen window. The
415  * primary purpose of this method is so that window manager will know
416  * whether or not it show draw the task bar.
417  *
418  * @return True if this is a full screen window.
419  */
420 
421 bool CNxTerm::isFullScreen(void) const
422 {
423  return m_window->isFullScreen();
424 }
425 
426 /**
427  * This is the NxTerm task. This function first redirects output to the
428  * console window then calls to start the NSH logic.
429  */
430 
431 int CNxTerm::nxterm(int argc, char *argv[])
432 {
433  // To stop compiler complaining about "jump to label crosses initialization
434  // of 'int fd'
435 
436  int fd = -1;
437 
438  // Set up an on_exit() event that will be called when this task exits
439 
440  if (on_exit(exitHandler, g_nxtermvars.console) != 0)
441  {
442  gerr("ERROR: on_exit failed\n");
443  goto errout;
444  }
445 
446  // Use the window handle to create the NX console
447 
448  g_nxtermvars.nxterm = nxtk_register(g_nxtermvars.hwnd, &g_nxtermvars.wndo,
449  g_nxtermvars.minor);
450  if (!g_nxtermvars.nxterm)
451  {
452  gerr("ERROR: Failed register the console device\n");
453  goto errout;
454  }
455 
456  // Construct the driver name using this minor number
457 
458  char devname[32];
459  snprintf(devname, 32, "/dev/nxterm%d", g_nxtermvars.minor);
460 
461  // Increment the minor number while it is protect by the semaphore
462 
463  g_nxtermvars.minor++;
464 
465  // Open the NxTerm driver
466 
467 #ifdef CONFIG_NXTERM_NXKBDIN
468  fd = open(devname, O_RDWR);
469 #else
470  fd = open(devname, O_WRONLY);
471 #endif
472  if (fd < 0)
473  {
474  gerr("ERROR: Failed open the console device\n");
475  goto errout_with_nxterm;
476  }
477 
478  // Now re-direct stdout and stderr so that they use the NX console driver.
479  // Notes: (1) stdin is retained (file descriptor 0, probably the the serial
480  // console). (2) Don't bother trying to put debug instrumentation in the
481  // following becaue it will end up in the NxTerm window.
482 
483  (void)std::fflush(stdout);
484  (void)std::fflush(stderr);
485 
486 #ifdef CONFIG_NXTERM_NXKBDIN
487  (void)std::fclose(stdin);
488 #endif
489  (void)std::fclose(stdout);
490  (void)std::fclose(stderr);
491 
492 #ifdef CONFIG_NXTERM_NXKBDIN
493  (void)std::dup2(fd, 0);
494 #endif
495  (void)std::dup2(fd, 1);
496  (void)std::dup2(fd, 2);
497 
498 #ifdef CONFIG_NXTERM_NXKBDIN
499  (void)std::fdopen(0, "r");
500 #endif
501  (void)std::fdopen(1, "w");
502  (void)std::fdopen(2, "w");
503 
504  // And we can close our original driver file descriptor
505 
506  std::close(fd);
507 
508  // Inform the parent thread that we successfully initialized
509 
510  g_nxtermvars.result = true;
511  sem_post(&g_nxtermvars.waitSem);
512 
513  // Run the NSH console
514 
515 #ifdef CONFIG_NSH_CONSOLE
516  (void)nsh_consolemain(argc, argv);
517 #endif
518 
519  // We get here if the NSH console should exits. nsh_consolemain() ALWAYS
520  // exits by calling nsh_exit() (which is a pointer to nsh_consoleexit())
521  // which, in turn, calls exit()
522 
523  return EXIT_SUCCESS;
524 
525 errout_with_nxterm:
526  nxterm_unregister(g_nxtermvars.nxterm);
527 
528 errout:
529  g_nxtermvars.nxterm = 0;
530  g_nxtermvars.result = false;
531  sem_post(&g_nxtermvars.waitSem);
532  return EXIT_FAILURE;
533 }
534 
535 /**
536  * This is the NxTerm task exit handler. It registered with on_exit()
537  * and called automatically when the nxterm task exits.
538  */
539 
540 void CNxTerm::exitHandler(int code, FAR void *arg)
541 {
542  CNxTerm *This = (CNxTerm *)arg;
543 
544  // If we got here because of the task_delete() call in CNxTerm::stop(),
545  // then m_pid will be set to -1 to let us know that we do not need to do
546  // anything
547 
548  if (This->m_pid >= 0)
549  {
550  // Set m_pid to -1 to prevent calling detlete_task() in CNxTerm::stop().
551  // CNxTerm::stop() is called by the processing initiated by the following
552  // call to CTaskbar::stopApplication()
553 
554  This->m_pid = -1;
555 
556  // Remove the NxTerm application from the taskbar
557 
558  This->m_taskbar->stopApplication(This);
559  }
560 }
561 
562 /**
563  * Called when the window minimize button is pressed.
564  */
565 
567 {
568  m_taskbar->minimizeApplication(static_cast<IApplication*>(this));
569 }
570 
571 /**
572  * Called when the window close button is pressed.
573  */
574 
575 void CNxTerm::close(void)
576 {
577  m_taskbar->stopApplication(static_cast<IApplication*>(this));
578 }
579 
580 /**
581  * CNxTermFactory Constructor
582  *
583  * @param taskbar. The taskbar instance used to terminate the console
584  */
585 
587 {
588  m_taskbar = taskbar;
589 }
590 
591 /**
592  * Create a new instance of an CNxTerm (as IApplication).
593  */
594 
596 {
597  // Call CTaskBar::openFullScreenWindow to create a full screen window for
598  // the NxTerm application
599 
600  CApplicationWindow *window = m_taskbar->openApplicationWindow();
601  if (!window)
602  {
603  gerr("ERROR: Failed to create CApplicationWindow\n");
604  return (IApplication *)0;
605  }
606 
607  // Open the window (it is hot in here)
608 
609  if (!window->open())
610  {
611  gerr("ERROR: Failed to open CApplicationWindow\n");
612  delete window;
613  return (IApplication *)0;
614  }
615 
616  // Instantiate the application, providing the window to the application's
617  // constructor
618 
619  CNxTerm *nxterm = new CNxTerm(m_taskbar, window);
620  if (!nxterm)
621  {
622  gerr("ERROR: Failed to instantiate CNxTerm\n");
623  delete window;
624  return (IApplication *)0;
625  }
626 
627  return static_cast<IApplication*>(nxterm);
628 }
629 
630 /**
631  * Get the icon associated with the application
632  *
633  * @return An instance if IBitmap that may be used to rend the
634  * application's icon. This is an new IBitmap instance that must
635  * be deleted by the caller when it is no long needed.
636  */
637 
639 {
641  new NXWidgets::CRlePaletteBitmap(&CONFIG_NXWM_NXTERM_ICON);
642 
643  return bitmap;
644 }
645 
646 /**
647  * One time NSH initialization. This function must be called exactly
648  * once during the boot-up sequence to initialize the NSH library.
649  *
650  * @return True on successful initialization
651  */
652 
654 {
655  // Initialize the global data structure
656 
657  sem_init(&g_nxtermvars.exclSem, 0, 1);
658  sem_init(&g_nxtermvars.waitSem, 0, 0);
659 
660  // Initialize the NSH library
661 
662  nsh_initialize();
663 
664  // If the Telnet console is selected as a front-end, then start the
665  // Telnet daemon.
666 
667 #ifdef CONFIG_NSH_TELNET
668  int ret = nsh_telnetstart(ADDR_FAMILY);
669  if (ret < 0)
670  {
671  // The daemon is NOT running!
672 
673  return false;
674  }
675 #endif
676 
677  return true;
678 }
679 
NXWidgets::IBitmap * getIcon(void)
Definition: cnxterm.cxx:188
FAR void * console
Definition: cnxterm.cxx:91
bool stopApplication(IApplication *app)
Definition: ctaskbar.cxx:667
CTaskbar * m_taskbar
Definition: cnxterm.hxx:81
virtual void redirectNxTerm(NXTERM handle)=0
static int nxterm(int argc, char *argv[])
Definition: cnxterm.cxx:431
IApplication * create(void)
Definition: cnxterm.cxx:595
bool isFullScreen(void) const
Definition: cnxterm.cxx:421
void setWindowLabel(NXWidgets::CNxString &appname)
~CNxTerm(void)
Definition: cnxterm.cxx:157
IApplicationWindow * getWindow(void) const
Definition: cnxterm.cxx:175
virtual bool getSize(FAR struct nxgl_size_s *pSize)=0
void stop(void)
Definition: cnxterm.cxx:316
void redraw(void)
Definition: cnxterm.cxx:391
bool nshlibInitialize(void)
Definition: cnxterm.cxx:653
NXTERM nxterm
Definition: cnxterm.cxx:95
void hide(void)
Definition: cnxterm.cxx:380
void registerCallbacks(IApplicationCallback *callback)
NXTKWINDOW hwnd
Definition: cnxterm.cxx:94
CNxTermFactory(CTaskbar *taskbar)
Definition: cnxterm.cxx:586
NXWidgets::IBitmap * getIcon(void)
Definition: cnxterm.cxx:638
pid_t m_pid
Definition: cnxterm.hxx:84
bool run(void)
Definition: cnxterm.cxx:213
NXWidgets::CNxString getName(void)
Definition: cnxterm.cxx:202
sem_t waitSem
Definition: cnxterm.cxx:93
struct nxterm_window_s wndo
Definition: cnxterm.cxx:97
void destroy(void)
Definition: cnxterm.cxx:364
CNxTerm(CTaskbar *taskbar, CApplicationWindow *window)
Definition: cnxterm.cxx:129
void minimize(void)
Definition: cnxterm.cxx:566
virtual CWidgetControl * getWidgetControl(void) const =0
static const NXWidgets::SRlePaletteBitmapEntry bitmap[]
void close(void)
Definition: cnxterm.cxx:575
sem_t exclSem
Definition: cnxterm.cxx:92
static void exitHandler(int code, FAR void *arg)
Definition: cnxterm.cxx:540
static struct SNxTerm g_nxtermvars
Definition: cnxterm.cxx:110