From 20958add7b2acc205e71569a3f318196baf7b7cf Mon Sep 17 00:00:00 2001 From: patacongo Date: Wed, 16 May 2012 22:43:40 +0000 Subject: NxWM: Add IApplicationFactory so that we can create multiple instances of applications; And, as a result of that, re-vamp entire threading model. this is now buggier than it was before git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@4742 42af7a65-404d-4744-a932-0658087f49c3 --- NxWidgets/nxwm/doc/NxWM-ThreadingModel.ppt | Bin 0 -> 92672 bytes NxWidgets/nxwm/include/capplicationwindow.hxx | 8 ++ NxWidgets/nxwm/include/ccalibration.hxx | 40 ++++++ NxWidgets/nxwm/include/cfullscreenwindow.hxx | 8 ++ NxWidgets/nxwm/include/cnxconsole.hxx | 37 +++++ NxWidgets/nxwm/include/cstartwindow.hxx | 71 ++++++++-- NxWidgets/nxwm/include/cwindowcontrol.hxx | 21 +++ NxWidgets/nxwm/include/iapplication.hxx | 56 +++++++- NxWidgets/nxwm/include/iapplicationwindow.hxx | 19 ++- NxWidgets/nxwm/include/nxwmconfig.hxx | 50 ++++++- NxWidgets/nxwm/src/capplicationwindow.cxx | 12 ++ NxWidgets/nxwm/src/ccalibration.cxx | 74 +++++++++- NxWidgets/nxwm/src/cfullscreenwindow.cxx | 12 ++ NxWidgets/nxwm/src/cnxconsole.cxx | 72 ++++++++++ NxWidgets/nxwm/src/cstartwindow.cxx | 196 +++++++++++++++++++++++--- NxWidgets/nxwm/src/ctaskbar.cxx | 9 +- NxWidgets/nxwm/src/cwindowcontrol.cxx | 159 ++++++++++++++++----- 17 files changed, 760 insertions(+), 84 deletions(-) create mode 100644 NxWidgets/nxwm/doc/NxWM-ThreadingModel.ppt (limited to 'NxWidgets/nxwm') diff --git a/NxWidgets/nxwm/doc/NxWM-ThreadingModel.ppt b/NxWidgets/nxwm/doc/NxWM-ThreadingModel.ppt new file mode 100644 index 000000000..382f69dd8 Binary files /dev/null and b/NxWidgets/nxwm/doc/NxWM-ThreadingModel.ppt differ diff --git a/NxWidgets/nxwm/include/capplicationwindow.hxx b/NxWidgets/nxwm/include/capplicationwindow.hxx index 8eda8d28a..f923f28b4 100644 --- a/NxWidgets/nxwm/include/capplicationwindow.hxx +++ b/NxWidgets/nxwm/include/capplicationwindow.hxx @@ -150,6 +150,14 @@ namespace NxWM NXWidgets::INxWindow *getWindow(void) const; + /** + * Recover the contained window control + * + * @return. The window control used by this application + */ + + CWindowControl *getWindowControl(void) const ; + /** * Set the window label * diff --git a/NxWidgets/nxwm/include/ccalibration.hxx b/NxWidgets/nxwm/include/ccalibration.hxx index 3d90d59a8..55cef6d84 100644 --- a/NxWidgets/nxwm/include/ccalibration.hxx +++ b/NxWidgets/nxwm/include/ccalibration.hxx @@ -314,6 +314,46 @@ namespace NxWM bool isFullScreen(void) const; }; + + class CCalibrationFactory : public IApplicationFactory + { + private: + CTaskbar *m_taskbar; /**< The taskbar */ + CTouchscreen *m_touchscreen; /**< The touchscreen device */ + + public: + /** + * CCalibrationFactory Constructor + * + * @param taskbar. The taskbar instance used to terminate calibration + * @param touchscreen. An instance of the class that wraps the + * touchscreen device. + */ + + CCalibrationFactory(CTaskbar *taskbar, CTouchscreen *touchscreen); + + /** + * CCalibrationFactory Destructor + */ + + inline ~CCalibrationFactory(void) { } + + /** + * Create a new instance of an CCalibration (as IApplication). + */ + + IApplication *create(void); + + /** + * Get the icon associated with the application + * + * @return An instance if IBitmap that may be used to rend the + * application's icon. This is an new IBitmap instance that must + * be deleted by the caller when it is no long needed. + */ + + NXWidgets::IBitmap *getIcon(void); + }; } #endif // __INCLUDE_CCALIBRATION_HXX diff --git a/NxWidgets/nxwm/include/cfullscreenwindow.hxx b/NxWidgets/nxwm/include/cfullscreenwindow.hxx index 3c4117689..2e3fbd45d 100644 --- a/NxWidgets/nxwm/include/cfullscreenwindow.hxx +++ b/NxWidgets/nxwm/include/cfullscreenwindow.hxx @@ -114,6 +114,14 @@ namespace NxWM NXWidgets::INxWindow *getWindow(void) const; + /** + * Recover the contained window control + * + * @return. The window control used by this application + */ + + CWindowControl *getWindowControl(void) const; + /** * Set the window label * diff --git a/NxWidgets/nxwm/include/cnxconsole.hxx b/NxWidgets/nxwm/include/cnxconsole.hxx index 91fb941d8..b95c86406 100644 --- a/NxWidgets/nxwm/include/cnxconsole.hxx +++ b/NxWidgets/nxwm/include/cnxconsole.hxx @@ -191,6 +191,43 @@ namespace NxWM bool isFullScreen(void) const; }; + + class CNxConsoleFactory : public IApplicationFactory + { + private: + CTaskbar *m_taskbar; /**< The taskbar */ + + public: + /** + * CNxConsoleFactory Constructor + * + * @param taskbar. The taskbar instance used to terminate calibration + */ + + CNxConsoleFactory(CTaskbar *taskbar); + + /** + * CNxConsoleFactory Destructor + */ + + inline ~CNxConsoleFactory(void) { } + + /** + * Create a new instance of an CNxConsole (as IApplication). + */ + + IApplication *create(void); + + /** + * Get the icon associated with the application + * + * @return An instance if IBitmap that may be used to rend the + * application's icon. This is an new IBitmap instance that must + * be deleted by the caller when it is no long needed. + */ + + NXWidgets::IBitmap *getIcon(void); + }; } #endif // __cplusplus diff --git a/NxWidgets/nxwm/include/cstartwindow.hxx b/NxWidgets/nxwm/include/cstartwindow.hxx index d0ae5ec84..b0cad6127 100644 --- a/NxWidgets/nxwm/include/cstartwindow.hxx +++ b/NxWidgets/nxwm/include/cstartwindow.hxx @@ -42,6 +42,8 @@ #include +#include + #include "tnxarray.hxx" #include "iapplication.hxx" @@ -59,8 +61,35 @@ namespace NxWM { + /** + * Forward references + */ + class CTaskbar; + /** + * Start window message opcodes and format + */ + + enum EStartWindowMessageOpcodes + { + MSGID_POSITIONAL_CHANGE = 1, /**< Change in window positional data (not used) */ + MSGID_REDRAW_REQUEST, /**< Request to redraw a portion of the window (not used) */ + MSGID_MOUSE_INPUT, /**< New mouse input is available */ + MSGID_KEYBOARD_INPUT, /**< New keyboard input is available */ + MSGID_DESTROY_APP /**< Destroy the application */ + }; + + struct SStartWindowMessage + { + enum EStartWindowMessageOpcodes msgId; /**< The message opcode */ + FAR void *instance; /**< Object instance. */ + }; + + /** + * This class is the the start window application. + */ + class CStartWindow : public IApplication, private IApplicationCallback, private NXWidgets::CWidgetEventHandler @@ -72,7 +101,7 @@ namespace NxWM struct SStartWindowSlot { - IApplication *app; /**< A reference to the icon */ + IApplicationFactory *app; /**< A reference to the icon */ NXWidgets::CImage *image; /**< The icon image that goes with the application */ }; @@ -84,6 +113,33 @@ namespace NxWM CApplicationWindow *m_window; /**< Reference to the application window */ TNxArray m_slots; /**< List of apps in the start window */ struct nxgl_size_s m_iconSize; /**< A box big enough to hold the largest icon */ + pid_t m_taskId; /**< ID of the start window task */ + + /** + * This is the start window task. This function receives window events from + * the NX listener threads indirectly through this sequence: + * + * 1. The NX listener thread receives a windows event. The NX listener thread + * which is part of CTaskBar and was created when NX server connection was + * established). This event may be a positional change notification, a + * redraw request, or mouse or keyboard input. + * 2. The NX listener thread handles the message by calling nx_eventhandler(). + * nx_eventhandler() dispatches the message by calling a method in the + * NXWidgets::CCallback instance associated with the window. + * NXWidgets::CCallback is a part of the CWidgetControl. + * 3. NXWidgets::CCallback calls into NXWidgets::CWidgetControl to process + * the event. + * 4. NXWidgets::CWidgetControl records the new state data and raises a + * window event. + * 5. NXWidgets::CWindowEventHandlerList will give the event to + * NxWM::CWindowControl. + * 6. NxWM::CWindowControl will send the a message on a well-known message + * queue. + * 7. This CStartWindow::startWindow task will receive and process that + * message. + */ + + static int startWindow(int argc, char *argv[]); /** * Called when the window minimize button is pressed. @@ -107,7 +163,7 @@ namespace NxWM * Stop all applications */ - void stopAllApplications(void); + void removeAllApplications(void); /** * Handle a widget action event. For CImage, this is a mouse button pre-release event. @@ -202,18 +258,15 @@ namespace NxWM * Add the application to the start window. The general sequence for * setting up the start window is: * - * 1. Call CTaskBar::openApplicationWindow to create a window for the start window, - * 2. Use the window to instantiate CStartWindow - * 3. Call CStartWindow::addApplication numerous times to install applications - * in the start window. - * 4. Call CTaskBar::startApplication (initially minimized) to start the start - * window application. + * 1. Call IAppicationFactory::create to a new instance of the application + * 2. Call CStartWindow::addApplication to add the application to the + * start window. * * @param app. The new application to add to the start window * @return true on success */ - bool addApplication(IApplication *app); + bool addApplication(IApplicationFactory *app); /** * Simulate a mouse click on the icon at index. This inline method is only diff --git a/NxWidgets/nxwm/include/cwindowcontrol.hxx b/NxWidgets/nxwm/include/cwindowcontrol.hxx index acec12727..91e430c5c 100644 --- a/NxWidgets/nxwm/include/cwindowcontrol.hxx +++ b/NxWidgets/nxwm/include/cwindowcontrol.hxx @@ -43,6 +43,8 @@ #include #include +#include + #include #include @@ -61,6 +63,12 @@ namespace NxWM { + /** + * Forward references. + */ + + class IApplication; + /** * The class CWindowControl integrates the widget control with some special * handling of mouse and keyboard inputs neesed by NxWM @@ -70,6 +78,9 @@ namespace NxWM private NXWidgets::CWindowEventHandler { private: + mqd_t m_mqd; /**< Message queue descriptor used to commincate with the + ** start window thread. */ + /** * Handle an NX window mouse input event. * @@ -105,6 +116,16 @@ namespace NxWM */ ~CWindowControl(void); + + /** + * Destroy the application window and everything in it. This is + * handled by CWindowControl (vs just calling the destructors) because + * in the case where an application destroys itself (because of pressing + * the stop button), then we need to unwind and get out of the application + * logic before destroying all of its objects. + */ + + void destroy(IApplication *app); }; } #endif // __cplusplus diff --git a/NxWidgets/nxwm/include/iapplication.hxx b/NxWidgets/nxwm/include/iapplication.hxx index 0d33db7bc..45067d900 100644 --- a/NxWidgets/nxwm/include/iapplication.hxx +++ b/NxWidgets/nxwm/include/iapplication.hxx @@ -44,6 +44,8 @@ #include "cnxstring.hxx" #include "ibitmap.hxx" + +#include "cwindowcontrol.hxx" #include "capplicationwindow.hxx" /**************************************************************************** @@ -65,14 +67,25 @@ namespace NxWM class IApplication { protected: - // These values (and the accessors that go with them) violate the "purity" - // of the base class. These are really part of the task bar implementation: - // Each application provides this state information needed by the taskbar. + /** + * These values (and the accessors that go with them) violate the "purity" + * of the base class. These are really part of the task bar implementation: + * Each application provides this state information needed by the taskbar. + */ bool m_minimized; /**< True if the application is minimized */ bool m_topapp; /**< True if this application is at the top in the hiearchy */ public: + /** + * A virtual destructor is required in order to override the IApplication + * destructor. We do this because if we delete IApplication, we want the + * destructor of the class that inherits from IApplication to run, not this + * one. + */ + + virtual ~IApplication(void) { } + /** * Each implementation of IApplication must provide a method to recover * the contained CApplicationWindow instance. @@ -80,6 +93,18 @@ namespace NxWM virtual IApplicationWindow *getWindow(void) const = 0; + /** + * Get the window widget control. + * + * @return The widget control of the underlying window instance. + */ + + virtual inline CWindowControl *getWindowControl(void) const + { + IApplicationWindow *window = getWindow(); + return window->getWindowControl(); + } + /** * Get the icon associated with the application * @@ -181,6 +206,31 @@ namespace NxWM virtual bool isFullScreen(void) const = 0; }; + + /** + * IApplicationFactory provides a mechanism for creating multiple instances + * of an application. + */ + + class IApplicationFactory + { + public: + /** + * Create a new instance of an application. + */ + + virtual IApplication *create(void) = 0; + + /** + * Get the icon associated with the application + * + * @return An instance if IBitmap that may be used to rend the + * application's icon. This is an new IBitmap instance that must + * be deleted by the caller when it is no long needed. + */ + + virtual NXWidgets::IBitmap *getIcon(void) = 0; + }; } #endif // __cplusplus diff --git a/NxWidgets/nxwm/include/iapplicationwindow.hxx b/NxWidgets/nxwm/include/iapplicationwindow.hxx index b00a03fa2..fe8830c2f 100644 --- a/NxWidgets/nxwm/include/iapplicationwindow.hxx +++ b/NxWidgets/nxwm/include/iapplicationwindow.hxx @@ -42,13 +42,10 @@ #include -#include "cnxtkwindow.hxx" -#include "cnxtoolbar.hxx" -#include "cwidgeteventargs.hxx" -#include "cwidgeteventhandler.hxx" -#include "cimage.hxx" -#include "clabel.hxx" -#include "crlepalettebitmap.hxx" +#include "inxwindow.hxx" +#include "cnxstring.hxx" + +#include "cwindowcontrol.hxx" /**************************************************************************** * Pre-Processor Definitions @@ -121,6 +118,14 @@ namespace NxWM virtual NXWidgets::INxWindow *getWindow(void) const = 0; + /** + * Recover the contained window control + * + * @return. The window control used by this application + */ + + virtual CWindowControl *getWindowControl(void) const = 0; + /** * Set the window label * diff --git a/NxWidgets/nxwm/include/nxwmconfig.hxx b/NxWidgets/nxwm/include/nxwmconfig.hxx index 34721d777..3605f8c4f 100644 --- a/NxWidgets/nxwm/include/nxwmconfig.hxx +++ b/NxWidgets/nxwm/include/nxwmconfig.hxx @@ -263,6 +263,19 @@ * CONFIG_NXWM_STARTWINDOW_VSPACING - Vertical spacing. Default: 2 pixels * CONFIG_NXWM_STARTWINDOW_HSPACING - Horizontal spacing. Default: 2 rows * CONFIG_NXWM_STARTWINDOW_ICON - The glyph to use as the start window icon + * CONFIG_NXWM_STARTWINDOW_MQNAME - The well known name of the message queue + * Used to communicated from CWindowControl tothe start window thread. + * Default: "/dev/nxwm" + * CONFIG_NXWM_STARTWINDOW_MXMSGS - The maximum number of messages to queue + * before blocking. Defualt 32 + * CONFIG_NXWM_STARTWINDOW_MXMPRIO - The message priority. Default: 42. + * CONFIG_NXWM_STARTWINDOW_PRIO - Priority of the NxConsole task. Default: + * SCHED_PRIORITY_DEFAULT. NOTE: This priority should be less than + * CONFIG_NXWIDGETS_SERVERPRIO or else there may be data overrun errors. + * Such errors would most likely appear as duplicated rows of data on the + * display. + * CONFIG_NXWM_STARTWINDOW_STACKSIZE - The stack size to use when starting the + * NxConsole task. Default: 2048 bytes. */ #ifndef CONFIG_NXWM_STARTWINDOW_VSPACING @@ -281,6 +294,39 @@ # define CONFIG_NXWM_STARTWINDOW_ICON NxWM::g_playBitmap #endif +/** + * Start window task parameters + */ + +#ifndef CONFIG_NXWM_STARTWINDOW_MQNAME +# define CONFIG_NXWM_STARTWINDOW_MQNAME "/dev/nxwm" +#endif + +#ifndef CONFIG_NXWM_STARTWINDOW_MXMSGS +# ifdef CONFIG_NX_MXCLIENTMSGS +# define CONFIG_NXWM_STARTWINDOW_MXMSGS CONFIG_NX_MXCLIENTMSGS +# else +# define CONFIG_NXWM_STARTWINDOW_MXMSGS 32 +# endif +#endif + +#ifndef CONFIG_NXWM_STARTWINDOW_MXMPRIO +# define CONFIG_NXWM_STARTWINDOW_MXMPRIO 42 +#endif + +#ifndef CONFIG_NXWM_STARTWINDOW_PRIO +# define CONFIG_NXWM_STARTWINDOW_PRIO SCHED_PRIORITY_DEFAULT +#endif + +#if CONFIG_NXWIDGETS_SERVERPRIO <= CONFIG_NXWM_STARTWINDOW_PRIO +# warning "CONFIG_NXWIDGETS_SERVERPRIO <= CONFIG_NXWM_STARTWINDOW_PRIO" +# warning" -- This can result in data overrun errors" +#endif + +#ifndef CONFIG_NXWM_STARTWINDOW_STACKSIZE +# define CONFIG_NXWM_STARTWINDOW_STACKSIZE 2048 +#endif + /* NxConsole Window *********************************************************/ /** * NxConsole Window Configuration @@ -347,7 +393,7 @@ * CONFIG_NXWM_TOUCHSCREEN_LISTENERPRIO - Priority of the touchscreen listener * thread. Default: SCHED_PRIORITY_DEFAULT * CONFIG_NXWM_TOUCHSCREEN_LISTENERSTACK - Touchscreen listener thread stack - * size. Default 2048 + * size. Default 1024 */ #ifndef CONFIG_NXWM_TOUCHSCREEN_DEVNO @@ -367,7 +413,7 @@ #endif #ifndef CONFIG_NXWM_TOUCHSCREEN_LISTENERSTACK -# define CONFIG_NXWM_TOUCHSCREEN_LISTENERSTACK 2048 +# define CONFIG_NXWM_TOUCHSCREEN_LISTENERSTACK 1024 #endif /* Calibration display ******************************************************/ diff --git a/NxWidgets/nxwm/src/capplicationwindow.cxx b/NxWidgets/nxwm/src/capplicationwindow.cxx index df8c69f11..15d4a4a9d 100644 --- a/NxWidgets/nxwm/src/capplicationwindow.cxx +++ b/NxWidgets/nxwm/src/capplicationwindow.cxx @@ -413,6 +413,18 @@ NXWidgets::INxWindow *CApplicationWindow::getWindow(void) const return static_cast(m_window); } +/** + * Recover the contained window control + * + * @return. The window control used by this application + */ + +CWindowControl *CApplicationWindow::getWindowControl(void) const +{ + NXWidgets::CWidgetControl *control = m_window->getWidgetControl(); + return static_cast(control); +} + /** * Set the window label * diff --git a/NxWidgets/nxwm/src/ccalibration.cxx b/NxWidgets/nxwm/src/ccalibration.cxx index 2f9adb2e0..248aca838 100644 --- a/NxWidgets/nxwm/src/ccalibration.cxx +++ b/NxWidgets/nxwm/src/ccalibration.cxx @@ -1,5 +1,5 @@ /**************************************************************************** - * NxWidgets/nxwm/src/capplicationwindow.cxx + * NxWidgets/nxwm/src/ccalibration.cxx * * Copyright (C) 2012 Gregory Nutt. All rights reserved. * Author: Gregory Nutt @@ -107,6 +107,11 @@ CCalibration::CCalibration(CTaskbar *taskbar, CFullScreenWindow *window, CCalibration::~CCalibration(void) { + // Make sure that the application is not running (it should already + // have been stopped) + + stop(); + // Although we did not create the window, the rule is that I have to dispose // of it @@ -788,4 +793,71 @@ bool CCalibration::createCalibrationData(struct SCalibrationData &data) return true; } +/** + * CCalibrationFactory Constructor + * + * @param taskbar. The taskbar instance used to terminate calibration + * @param touchscreen. An instance of the class that wraps the + * touchscreen device. + */ + +CCalibrationFactory::CCalibrationFactory(CTaskbar *taskbar, CTouchscreen *touchscreen) +{ + m_taskbar = taskbar; + m_touchscreen = touchscreen; +} + +/** + * Create a new instance of an CCalibration (as IApplication). + */ + +IApplication *CCalibrationFactory::create(void) +{ + // Call CTaskBar::openFullScreenWindow to create a full screen window for + // the calibation application + + CFullScreenWindow *window = m_taskbar->openFullScreenWindow(); + if (!window) + { + gdbg("ERROR: Failed to create CFullScreenWindow\n"); + return (IApplication *)0; + } + + // Open the window (it is hot in here) + + if (!window->open()) + { + gdbg("ERROR: Failed to open CFullScreenWindow \n"); + delete window; + return (IApplication *)0; + } + // Instantiate the application, providing the window to the application's + // constructor + + CCalibration *calibration = new CCalibration(m_taskbar, window, m_touchscreen); + if (!calibration) + { + gdbg("ERROR: Failed to instantiate CCalibration\n"); + delete window; + return (IApplication *)0; + } + + return static_cast(calibration); +} + +/** + * Get the icon associated with the application + * + * @return An instance if IBitmap that may be used to rend the + * application's icon. This is an new IBitmap instance that must + * be deleted by the caller when it is no long needed. + */ + +NXWidgets::IBitmap *CCalibrationFactory::getIcon(void) +{ + NXWidgets::CRlePaletteBitmap *bitmap = + new NXWidgets::CRlePaletteBitmap(&CONFIG_NXWM_CALIBRATION_ICON); + + return bitmap; +} diff --git a/NxWidgets/nxwm/src/cfullscreenwindow.cxx b/NxWidgets/nxwm/src/cfullscreenwindow.cxx index 7d63b02d7..40647d8e9 100644 --- a/NxWidgets/nxwm/src/cfullscreenwindow.cxx +++ b/NxWidgets/nxwm/src/cfullscreenwindow.cxx @@ -127,6 +127,18 @@ NXWidgets::INxWindow *CFullScreenWindow::getWindow(void) const return static_cast(m_window); } +/** + * Recover the contained window control + * + * @return. The window control used by this application + */ + +CWindowControl *CFullScreenWindow::getWindowControl(void) const +{ + NXWidgets::CWidgetControl *control = m_window->getWidgetControl(); + return static_cast(control); +} + /** * Set the window label * diff --git a/NxWidgets/nxwm/src/cnxconsole.cxx b/NxWidgets/nxwm/src/cnxconsole.cxx index ec43c5656..577bf661e 100644 --- a/NxWidgets/nxwm/src/cnxconsole.cxx +++ b/NxWidgets/nxwm/src/cnxconsole.cxx @@ -47,6 +47,7 @@ #include #include #include +#include #include @@ -141,6 +142,11 @@ CNxConsole::CNxConsole(CTaskbar *taskbar, CApplicationWindow *window) CNxConsole::~CNxConsole(void) { + // There would be a problem if we were stopped with the NxConsole task + // running... that should never happen but we'll check anyway: + + stop(); + // Although we didn't create it, we are responsible for deleting the // application window @@ -504,6 +510,72 @@ void CNxConsole::close(void) m_taskbar->stopApplication(static_cast(this)); } +/** + * CNxConsoleFactory Constructor + * + * @param taskbar. The taskbar instance used to terminate the console + */ + +CNxConsoleFactory::CNxConsoleFactory(CTaskbar *taskbar) +{ + m_taskbar = taskbar; +} + +/** + * Create a new instance of an CNxConsole (as IApplication). + */ + +IApplication *CNxConsoleFactory::create(void) +{ + // Call CTaskBar::openFullScreenWindow to create a full screen window for + // the NxConsole application + + CApplicationWindow *window = m_taskbar->openApplicationWindow(); + if (!window) + { + gdbg("ERROR: Failed to create CApplicationWindow\n"); + return (IApplication *)0; + } + + // Open the window (it is hot in here) + + if (!window->open()) + { + gdbg("ERROR: Failed to open CApplicationWindow\n"); + delete window; + return (IApplication *)0; + } + + // Instantiate the application, providing the window to the application's + // constructor + + CNxConsole *nxconsole = new CNxConsole(m_taskbar, window); + if (!nxconsole) + { + gdbg("ERROR: Failed to instantiate CNxConsole\n"); + delete window; + return (IApplication *)0; + } + + return static_cast(nxconsole); +} + +/** + * Get the icon associated with the application + * + * @return An instance if IBitmap that may be used to rend the + * application's icon. This is an new IBitmap instance that must + * be deleted by the caller when it is no long needed. + */ + +NXWidgets::IBitmap *CNxConsoleFactory::getIcon(void) +{ + NXWidgets::CRlePaletteBitmap *bitmap = + new NXWidgets::CRlePaletteBitmap(&CONFIG_NXWM_NXCONSOLE_ICON); + + return bitmap; +} + /** * One time NSH initialization. This function must be called exactly * once during the boot-up sequence to initialize the NSH library. diff --git a/NxWidgets/nxwm/src/cstartwindow.cxx b/NxWidgets/nxwm/src/cstartwindow.cxx index de35662d5..1c997fbb7 100644 --- a/NxWidgets/nxwm/src/cstartwindow.cxx +++ b/NxWidgets/nxwm/src/cstartwindow.cxx @@ -39,6 +39,13 @@ #include +#include +#include +#include +#include + +#include + #include "cwidgetcontrol.hxx" #include "nxwmconfig.hxx" @@ -51,7 +58,7 @@ ********************************************************************************************/ /******************************************************************************************** - * CNxConsole Method Implementations + * CStartWindow Method Implementations ********************************************************************************************/ using namespace NxWM; @@ -70,6 +77,10 @@ CStartWindow::CStartWindow(CTaskbar *taskbar, CApplicationWindow *window) m_taskbar = taskbar; m_window = window; + // The start window task is not running + + m_taskId = -1; + // Add our personalized window label NXWidgets::CNxString myName = getName(); @@ -86,6 +97,11 @@ CStartWindow::CStartWindow(CTaskbar *taskbar, CApplicationWindow *window) CStartWindow::~CStartWindow(void) { + // There would be a problem if we were stopped with the start window task + // running... that should never happen but we'll check anyway: + + stop(); + // Although we didn't create it, we are responsible for deleting the // application window @@ -96,7 +112,7 @@ CStartWindow::~CStartWindow(void) // Then stop and delete all applications - stopAllApplications(); + removeAllApplications(); } /** @@ -144,9 +160,24 @@ NXWidgets::CNxString CStartWindow::getName(void) bool CStartWindow::run(void) { - // We don't have a thread of execution. We only respond to button presses + // Some sanity checking - return true; + if (m_taskId >= 0) + { + // The start window task is already running??? + + return false; + } + + // Start the start window task + + m_taskId = TASK_CREATE("StartWindow", CONFIG_NXWM_STARTWINDOW_PRIO, + CONFIG_NXWM_STARTWINDOW_STACKSIZE, startWindow, + (FAR const char **)0); + + // Did we successfully start the NxConsole task? + + return m_taskId >= 0; } /** @@ -155,7 +186,20 @@ bool CStartWindow::run(void) void CStartWindow::stop(void) { - // We don't have a thread of execution. We only respond to button presses + // Delete the start window task --- what are we doing? This should never + // happen because the start window task is persistent! + + if (m_taskId >= 0) + { + // Call task_delete(), possibly stranding resources + + pid_t pid = m_taskId; + m_taskId = -1; + + // Then delete the NSH task + + task_delete(pid); + } } /** @@ -293,21 +337,17 @@ bool CStartWindow::isFullScreen(void) const } /** - * Add the application to the start window. The general sequence for - * setting up the start window is: + * Add the application to the start window. The general sequence is: * - * 1. Call CTaskBar::openApplicationWindow to create a window for the start window, - * 2. Use the window to instantiate CStartWindow - * 3. Call CStartWindow::addApplication numerous times to install applications - * in the start window. - * 4. Call CTaskBar::startApplication (initially minimized) to start the start - * window application. + * 1. Call IAppicationFactory::create to a new instance of the application + * 2. Call CStartWindow::addApplication to add the application to the + * start window. * * @param app. The new application to add to the start window * @return true on success */ -bool CStartWindow::addApplication(IApplication *app) +bool CStartWindow::addApplication(IApplicationFactory *app) { // Recover the NXTK window instance contained in the application window @@ -418,18 +458,17 @@ void CStartWindow::getIconBounds(void) * Stop all applications */ -void CStartWindow::stopAllApplications(void) +void CStartWindow::removeAllApplications(void) { - // Stop all applications and remove them from the task bar. Clearly, there + // Stop all applications and remove them from the start window. Clearly, there // are some ordering issues here... On an orderly system shutdown, disconnection // should really occur priority to deleting instances while (!m_slots.empty()) { - // Stop the application (and remove it from the task bar) + // Remove the application factory from the start menu - IApplication *app = m_slots.at(0).app; - m_taskbar->stopApplication(app); + IApplicationFactory *app = m_slots.at(0).app; // Now, delete the image and the application @@ -459,12 +498,125 @@ void CStartWindow::handleActionEvent(const NXWidgets::CWidgetEventArgs &e) NXWidgets::CImage *image = m_slots.at(i).image; if (image->isClicked()) { - // Start a new copy of the application + // Create a new copy of the application - m_taskbar->startApplication(m_slots.at(i).app, false); + IApplication *app = m_slots.at(i).app->create(); + if (app) + { + // Start the new copy of the application + + if (m_taskbar->startApplication(app, false)) + { + // Then break out of the loop + + break; + } + else + { + // If we cannot start the app. Destroy the + // instance we created and see what happens next. + + CWindowControl *control = app->getWindowControl(); + control->destroy(app); + } + } + } + } +} - // Then break out of the loop +/** + * This is the start window task. This function receives window events from + * the NX listener threads indirectly through this sequence: + * + * 1. NX listener thread receives a windows event. This may be a + * positional change notification, a redraw request, or mouse or + * keyboard input. + * 2. The NX listener thread performs the callback by calling a + * NXWidgets::CCallback method associated with the window. + * 3. NXWidgets::CCallback calls into NXWidgets::CWidgetControl to process + * the event. + * 4. NXWidgets::CWidgetControl records the new state data and raises a + * window event. + * 5. NXWidgets::CWindowEventHandlerList will give the event to + * NxWM::CWindowControl. + * 6. NxWM::CWindowControl will send the a message on a well-known message + * queue. + * 7. This CStartWindow::startWindow task will receive and process that + * message. + */ + +int CStartWindow::startWindow(int argc, char *argv[]) +{ + /* Open a well-known message queue for reading */ + + struct mq_attr attr; + attr.mq_maxmsg = CONFIG_NXWM_STARTWINDOW_MXMSGS; + attr.mq_msgsize = sizeof(struct SStartWindowMessage); + attr.mq_flags = 0; + + mqd_t mqd = mq_open(CONFIG_NXWM_STARTWINDOW_MQNAME, O_RDONLY|O_CREAT, 0666, &attr); + if (mqd == (mqd_t)-1) + { + gdbg("ERROR: mq_open(%s) failed: %d\n", CONFIG_NXWM_STARTWINDOW_MQNAME, errno); + return EXIT_FAILURE; + } + + // Now loop forever, receiving and processing messages. Ultimately, all + // widget driven events (button presses, etc.) are driven by this logic + // on this thread. + + for (;;) + { + // Receive the next message + + struct SStartWindowMessage msg; + ssize_t nbytes = mq_receive(mqd, &msg, sizeof(struct SStartWindowMessage), 0); + if (nbytes < 0) + { + // EINTR is not an error. The wait was interrupted by a signal and + // we just need to try reading again. + + if (errno != EINTR) + { + gdbg("ERROR: mq_receive failed: %d\n", errno); + } + } + while (nbytes < 0); + + gvdbg("Received msgid=%d nbytes=%d\n", msg.msgId, nbytes); + DEBUGASSERT(nbytes = sizeof(struct SStartWindowMessage) && msg.instance); + + // Dispatch the message to the appropriate CWidgetControl and to the + // appropriate CWidgetControl method + + switch (msg.msgId) + { + break; + + case MSGID_MOUSE_INPUT: // New mouse input is available + case MSGID_KEYBOARD_INPUT: // New keyboard input is available + { + // Handle all new window input events by calling the CWidgetControl::pollEvents() method + + NXWidgets::CWidgetControl *control = (NXWidgets::CWidgetControl *)msg.instance; + control->pollEvents(); + } + break; + + case MSGID_DESTROY_APP: // Destroy the application + { + // Handle all destroy application events + + gdbg("Deleting app=%p\n", msg.instance); + IApplication *app = (IApplication *)msg.instance; + delete app; + } + break; + case MSGID_POSITIONAL_CHANGE: // Change in window positional data (not used) + case MSGID_REDRAW_REQUEST: // Request to redraw a portion of the window (not used) + default: + gdbg("ERROR: Unrecognized or unsupported msgId: %d\n", (int)msg.msgId); break; } } diff --git a/NxWidgets/nxwm/src/ctaskbar.cxx b/NxWidgets/nxwm/src/ctaskbar.cxx index ec3d8460b..ab686f81c 100644 --- a/NxWidgets/nxwm/src/ctaskbar.cxx +++ b/NxWidgets/nxwm/src/ctaskbar.cxx @@ -609,7 +609,9 @@ bool CTaskbar::stopApplication(IApplication *app) hideApplicationWindow(app); - // Stop the application (whatever this means to the application) + // Stop the application (whatever this means to the application). We + // separate stopping from destroying to get the application a chance + // to put things in order before being destroyed. app->stop(); @@ -631,6 +633,11 @@ bool CTaskbar::stopApplication(IApplication *app) } } + // destroy the application + + CWindowControl *control = app->getWindowControl(); + control->destroy(app); + // Re-draw the new top, non-minimized application bool ret = redrawTopWindow(); diff --git a/NxWidgets/nxwm/src/cwindowcontrol.cxx b/NxWidgets/nxwm/src/cwindowcontrol.cxx index 841397a14..2c575d35b 100644 --- a/NxWidgets/nxwm/src/cwindowcontrol.cxx +++ b/NxWidgets/nxwm/src/cwindowcontrol.cxx @@ -36,9 +36,16 @@ /******************************************************************************************** * Included Files ********************************************************************************************/ - + #include +#include +#include + +#include + +#include "nxwmconfig.hxx" +#include "cstartwindow.hxx" #include "cwindowcontrol.hxx" /******************************************************************************************** @@ -62,6 +69,20 @@ using namespace NxWM; CWindowControl::CWindowControl(FAR const NXWidgets::CWidgetStyle *style) : NXWidgets::CWidgetControl(style) { + // Open a message queue to communicate with the start window task. We need to create + // the message queue if it does not exist. + + struct mq_attr attr; + attr.mq_maxmsg = CONFIG_NXWM_STARTWINDOW_MXMSGS; + attr.mq_msgsize = sizeof(struct SStartWindowMessage); + attr.mq_flags = 0; + + m_mqd = mq_open(CONFIG_NXWM_STARTWINDOW_MQNAME, O_WRONLY|O_CREAT, 0666, &attr); + if (m_mqd == (mqd_t)-1) + { + gdbg("ERROR: mq_open(%s) failed: %d\n", CONFIG_NXWM_STARTWINDOW_MQNAME, errno); + } + // Add ourself as the window callback addWindowEventHandler(this); @@ -73,11 +94,41 @@ CWindowControl::CWindowControl(FAR const NXWidgets::CWidgetStyle *style) CWindowControl::~CWindowControl(void) { + // Close the message queue + + (void)mq_close(m_mqd); + // Remove ourself from the window callback removeWindowEventHandler(this); } +/** + * Destroy the application window and everything in it. This is + * handled by CWindowControl (vs just calling the destructors) because + * in the case where an application destroys itself (because of pressing + * the stop button), then we need to unwind and get out of the application + * logic before destroying all of its objects. + */ + +void CWindowControl::destroy(IApplication *app) +{ + // Send a message to destroy the window isntance at a later time + + struct SStartWindowMessage outmsg; + outmsg.msgId = MSGID_DESTROY_APP; + outmsg.instance = (FAR void *)app; + + gdbg("Sending MSGID_DESTROY_APP with instance=%p\n", app); + int ret = mq_send(m_mqd, &outmsg, sizeof(struct SStartWindowMessage), + CONFIG_NXWM_STARTWINDOW_MXMPRIO); + if (ret < 0) + { + gdbg("ERROR: mq_send failed: %d\n", errno); + } + +} + /** * Handle an NX window mouse input event. * @@ -89,24 +140,40 @@ void CWindowControl::handleMouseEvent(void) { // The logic path here is tortuous but flexible: // - // 1. A listener thread receives mouse input and injects that into NX - // 2. In the multi-user mode, this will send a message to the NX server - // 3. The NX server will determine which window gets the mouse input - // and send a message to the listener. - // 4. The listener will call the NX message dispatcher will will do the - // message callback. - // 5. The callback goes into an instance of NXWidgets::CCallback that is - // part of the CWidget control. - // 6. That callback will update mouse information then raise the - // mouse event, - // 7. Which will finally call this function -- still running deep on the - // stack in the listener thread. - // 8. This function will then call back into the widget control to process - // the mouse input. - - // Perform the poll - - pollEvents(); + // 1. A listener thread receives mouse or touchscreen input and injects + // that into NX via nx_mousein + // 2. In the multi-user mode, this will send a message to the NX server + // 3. The NX server will determine which window gets the mouse input + // and send a window event message to the NX listener thread. + // 4. The NX listener thread receives a windows event. The NX listener thread + // which is part of CTaskBar and was created when NX server connection was + // established). This event may be a positional change notification, a + // redraw request, or mouse or keyboard input. In this case, mouse input. + // 5. The NX listener thread handles the message by calling nx_eventhandler(). + // nx_eventhandler() dispatches the message by calling a method in the + // NXWidgets::CCallback instance associated with the window. + // NXWidgets::CCallback is a part of the CWidgetControl. + // 6. NXWidgets::CCallback calls into NXWidgets::CWidgetControl to process + // the event. + // 7. NXWidgets::CWidgetControl records the new state data and raises a + // window event. + // 8. NXWidgets::CWindowEventHandlerList will give the event to this method + // NxWM::CWindowControl. + // 9. This NxWM::CWindowControl method will send the a message on a well- + // known message queue. + // 10. This CStartWindow::startWindow task will receive and process that + // message by calling CWidgetControl::pollEvents() + + struct SStartWindowMessage outmsg; + outmsg.msgId = MSGID_MOUSE_INPUT; + outmsg.instance = (FAR void *)static_cast(this); + + int ret = mq_send(m_mqd, &outmsg, sizeof(struct SStartWindowMessage), + CONFIG_NXWM_STARTWINDOW_MXMPRIO); + if (ret < 0) + { + gdbg("ERROR: mq_send failed: %d\n", errno); + } } #endif @@ -119,25 +186,39 @@ void CWindowControl::handleKeyboardEvent(void) { // The logic path here is tortuous but flexible: // - // 1. A listener thread receives keyboard input and injects that into NX - // 2. In the multi-user mode, this will send a message to the NX server - // 3. The NX server will determine which window gets the keyboard input - // and send a message to the listener. - // 4. The listener will call the NX message dispatcher will will do the - // message callback. - // 5. The callback goes into an instance of NXWidgets::CCallback that is - // part of the CWidget control. - // 6. That callback will update keyboard information then raise the - // keyboard event, - // 7. Which will finally call this function -- still running deep on the - // stack in the listener thread. - // 8. This function will then call back into the widget control to process - // the keyboard input. - - // Perform the poll - - pollEvents(); + // 1. A listener thread receives keyboard input and injects that into NX + // via nx_kbdin. + // 2. In the multi-user mode, this will send a message to the NX server + // 3. The NX server will determine which window gets the keyboard input + // and send a window event message to the NX listener thread. + // 4. The NX listener thread receives a windows event. The NX listener thread + // which is part of CTaskBar and was created when NX server connection was + // established). This event may be a positional change notification, a + // redraw request, or mouse or keyboard input. In this case, keyboard input. + // 5. The NX listener thread handles the message by calling nx_eventhandler(). + // nx_eventhandler() dispatches the message by calling a method in the + // NXWidgets::CCallback instance associated with the window. + // NXWidgets::CCallback is a part of the CWidgetControl. + // 6. NXWidgets::CCallback calls into NXWidgets::CWidgetControl to process + // the event. + // 7. NXWidgets::CWidgetControl records the new state data and raises a + // window event. + // 8. NXWidgets::CWindowEventHandlerList will give the event to this method + // NxWM::CWindowControl. + // 9. This NxWM::CWindowControl method will send the a message on a well- + // known message queue. + // 10. This CStartWindow::startWindow task will receive and process that + // message by calling CWidgetControl::pollEvents() + + struct SStartWindowMessage outmsg; + outmsg.msgId = MSGID_KEYBOARD_INPUT; + outmsg.instance = (FAR void *)static_cast(this); + + int ret = mq_send(m_mqd, &outmsg, sizeof(struct SStartWindowMessage), + CONFIG_NXWM_STARTWINDOW_MXMPRIO); + if (ret < 0) + { + gdbg("ERROR: mq_send failed: %d\n", errno); + } } #endif - - -- cgit v1.2.3