NxWidgets/NxWM updates from Petteri Aimonen (Patches 0007-0013)

git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@5689 42af7a65-404d-4744-a932-0658087f49c3
This commit is contained in:
patacongo 2013-02-28 18:48:11 +00:00
parent a96a12751a
commit 804bd95e05
14 changed files with 286 additions and 285 deletions

View File

@ -280,4 +280,50 @@
it works with indexed input images.
* NxWidgets::CLabel: Fix backward conditional compilation in the
"flicker free" logic.
* NxWidgets::CNxTimer: Previously repeated timers were re-enabled after
the timer action event. Consequently, if the action event handler tried
to stop the timer, the request would be ignored. Changes the order
so that the timer is re-enabled before the callback. There is still
no risk of re-entrancy, because everything executes on the USRWORK work
queue. From Petteri Aimonen.
* NxWidgets::CMultiLineTestBox: Fix text placement error. From Petteri
Aimonen.
* NxWidgets::CWidgetControl: Added another semaphore, boundssem, which
is set as soon as the screen bounds are known. This corrects two
problems:
1) Due to the way nxgl_rectsize computes the size, it will never
be 0,0 like CWidgetControl expects. Therefore the size is considered
valid even though it has not been set yet.
2) After the check is fixed to test for > 1, NxWM window creation will
hang. This is due to the fact that it uses the screen bounds for
determining window size. This was being blocked on geosem, which
is only posted after the size has been set.
From Petteri Aimonen.
* NxWidgets::CImage: Two enhancements:
1) Allow changing the bitmap even after the control has been created.
2) Allow giving 'null' to have the control draw no image at all.
From Petteri Aimonen.
* NxWM::CTaskBar: Allow windows with null icon. This makes sense for e.g.
full screen windows. From Petteri Aimonen.
* NxWM::CApplicationWindow: Add config options to override NxWM
stop/minimize icons. From Petteri Aimonen.
* NwWM::CStartWindow, NxWM::CWindowMessenger: Get rid of the start window
thread. Instead, handle all events through the USRWORK work queue.
For me, this was necessary because I would open some files in button
handlers and close them in NxTimer handlers. If these belonged to
different tasks, the close operation would fail. Further benefits:
+ Gets rid of one task and message queue.
+ Reduces the amount of code required
+ Decouples CStartWindow from everything else - now it is just a window
with application icons, not an integral part of the event logic.
+ All events come from the same thread, which reduces the possibility of
multithreading errors in user code.
+ The user code can also send events to USRWORK, so that everything gets
serialized nicely without having to use so many mutexes.
Drawbacks:
- Currently the work state structure is malloc()ed, causing one allocation
and free per each input event. Could add a memory pool for these later, but
the speed difference doesn't seem noticeable.
- The work queue will add ~50 ms latency to input events. This is however
configurable, and the delay is anyway short enough that it is unnoticeable.
From Petteri Aimonen.

24
Kconfig
View File

@ -463,6 +463,30 @@ config NXWM_BACKGROUND_IMAGE
The name of the image to use in the background window. Default:
NXWidgets::g_nuttxBitmap
comment "Application Window Configuration"
config NXWM_CUSTOM_APPWINDOW_ICONS
bool "Custom Start/Stop Application Window Icons"
default n
---help---
Select to override the default Application Window Stop and Minimize Icons.
if NXWM_CUSTOM_APPWINDOW_ICONS
config NXWM_STOP_BITMAP
string "Stop Icon"
default "NxWM::g_stopBitmap"
---help---
The glyph to use as the Stop icon. Default: NxWM::g_stopBitmap
config NXWM_MINIMIZE_BITMAP
string "Minimize Icon"
default "NxWM::g_minimizeBitmap"
---help---
The glyph to use as the Minimize icon. Default: NxWM::g_minimizeBitmap
endif
comment "Start Window Configuration"
comment "Horizontal and vertical spacing of icons in the task bar"

View File

@ -1,7 +1,7 @@
/****************************************************************************
* NxWidgets/libnxwidgets/include/cimage.hxx
*
* Copyright (C) 2012 Gregory Nutt. All rights reserved.
* Copyright (C) 2012-2013 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@ -207,6 +207,12 @@ namespace NXWidgets
inline FAR IBitmap *getBitmap() const { return m_bitmap; }
/**
* Set the bitmap that this image contains.
*/
inline void setBitmap(FAR IBitmap *bitmap) { m_bitmap = bitmap; }
/**
* Insert the dimensions that this widget wants to have into the rect
* passed in as a parameter. All coordinates are relative to the

View File

@ -1,7 +1,7 @@
/****************************************************************************
* NxWidgets/libnxwidgets/include/cwidgetcontrol.hxx
*
* Copyright (C) 2012 Gregory Nutt. All rights reserved.
* Copyright (C) 2012-2013 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@ -39,11 +39,12 @@
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include <semaphore.h>
#include <time.h>
@ -203,6 +204,7 @@ namespace NXWidgets
struct nxgl_rect_s m_bounds; /**< Size of the display */
#ifdef CONFIG_NX_MULTIUSER
sem_t m_geoSem; /**< Posted when geometry is valid */
sem_t m_boundsSem; /**< Posted when bounds are valid */
#endif
CWindowEventHandlerList m_eventHandlers; /**< List of event handlers. */
@ -228,7 +230,7 @@ namespace NXWidgets
* @param startTime A time in the past from which to compute the elapsed time.
* @return The elapsed time since startTime
*/
uint32_t elapsedTime(FAR const struct timespec *startTime);
/**
@ -256,7 +258,7 @@ namespace NXWidgets
/**
* Delete any widgets in the deletion queue.
*/
void processDeleteQueue(void);
/**
@ -324,6 +326,37 @@ namespace NXWidgets
giveGeoSem();
}
/**
* Take the bounds semaphore (handling signal interruptions)
*/
#ifdef CONFIG_NX_MULTIUSER
void takeBoundsSem(void);
#else
inline void takeBoundsSem(void) {}
#endif
/**
* Give the bounds semaphore
*/
inline void giveBoundsSem(void)
{
#ifdef CONFIG_NX_MULTIUSER
sem_post(&m_boundsSem);
#endif
}
/**
* Wait for bounds data
*/
inline void waitBoundsData(void)
{
takeBoundsSem();
giveBoundsSem();
}
/**
* Clear all mouse events
*/
@ -345,7 +378,7 @@ namespace NXWidgets
/**
* Destructor.
*/
virtual ~CWidgetControl(void);
/**
@ -407,7 +440,7 @@ namespace NXWidgets
* all widgets in the window.
* @return True means some interesting event occurred
*/
bool pollEvents(CNxWidget *widget = (CNxWidget *)NULL);
/**
@ -425,7 +458,7 @@ namespace NXWidgets
*
* @param widget The widget to be controlled.
*/
inline void addControlledWidget(CNxWidget* widget)
{
m_widgets.push_back(widget);
@ -438,7 +471,7 @@ namespace NXWidgets
*/
void removeControlledWidget(CNxWidget* widget);
/**
* Get the number of controlled widgets.
*
@ -456,7 +489,7 @@ namespace NXWidgets
*
* @param widget The widget to add to the delete queue.
*/
void addToDeleteQueue(CNxWidget *widget);
/**
@ -469,7 +502,7 @@ namespace NXWidgets
void setClickedWidget(CNxWidget *widget);
/**
* Get the clicked widget pointer.
* Get the clicked widget pointer.
*
* @return Pointer to the clicked widget.
*/
@ -502,7 +535,7 @@ namespace NXWidgets
}
/**
* Get the focused widget pointer.
* Get the focused widget pointer.
*
* @return Pointer to the focused widget.
*/
@ -513,7 +546,7 @@ namespace NXWidgets
}
/**
* Check for the occurrence of a double click.
* Check for the occurrence of a double click.
*
* @return Pointer to the clicked widget.
*/
@ -582,7 +615,7 @@ namespace NXWidgets
* @param pos The (x,y) position of the mouse.
* @param buttons See NX_MOUSE_* definitions.
*/
void newMouseEvent(FAR const struct nxgl_point_s *pos, uint8_t buttons);
/**
@ -624,7 +657,7 @@ namespace NXWidgets
*
* @param cursorControl The cursor control code received.
*/
void newCursorControlEvent(ECursorControl cursorControl);
/**
@ -639,21 +672,21 @@ namespace NXWidgets
}
/**
* Get the window bounding box in physical display coordinated. This
* method may need to wait until geometry data is available.
* Get the window bounding box in physical display coordinates. This
* method may need to wait until bounds data is available.
*
* @return This function returns the window handle.
*/
inline CRect getWindowBoundingBox(void)
{
waitGeoData();
waitBoundsData();
return CRect(&m_bounds);
}
inline void getWindowBoundingBox(FAR struct nxgl_rect_s *bounds)
{
waitGeoData();
waitBoundsData();
nxgl_rectcopy(bounds, &m_bounds);
}
@ -759,7 +792,7 @@ namespace NXWidgets
inline void removeWindowEventHandler(CWindowEventHandler *eventHandler)
{
m_eventHandlers.removeWindowEventHandler(eventHandler);
m_eventHandlers.removeWindowEventHandler(eventHandler);
}
};
}

View File

@ -1,7 +1,7 @@
/****************************************************************************
* NxWidgets/libnxwidgets/include/cimage.cxx
*
* Copyright (C) 2012 Gregory Nutt. All rights reserved.
* Copyright (C) 2012-2013 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@ -88,7 +88,7 @@
/****************************************************************************
* Pre-Processor Definitions
****************************************************************************/
/****************************************************************************
* Method Implementations
****************************************************************************/
@ -163,6 +163,13 @@ void CImage::getPreferredDimensions(CRect &rect) const
void CImage::drawContents(CGraphicsPort *port)
{
if (!m_bitmap)
{
// No image to draw
return;
}
// Get the the drawable region
CRect rect;
@ -187,11 +194,11 @@ void CImage::drawContents(CGraphicsPort *port)
m_bitmap->setSelected(isClicked() || m_highlighted);
// This is the number of rows that we can draw at the top of the display
nxgl_coord_t nTopRows = m_bitmap->getHeight() - m_origin.y;
if (nTopRows > rect.getHeight())
{
nTopRows = rect.getHeight();
nTopRows = rect.getHeight();
}
else if (nTopRows < 0)
{
@ -214,7 +221,7 @@ void CImage::drawContents(CGraphicsPort *port)
// the display
nxgl_coord_t nLeftPixels = m_bitmap->getWidth() - m_origin.x;
// This is the number of rows that we have to pad on the right if the display
// width is wider than the image width
@ -257,7 +264,7 @@ void CImage::drawContents(CGraphicsPort *port)
// Replace any transparent pixels with the background color.
// Then we can use the faster opaque drawBitmap() function.
ptr = buffer;
for (int i = 0; i < nLeftPixels; i++, ptr++)
{
@ -337,12 +344,12 @@ void CImage::drawBorder(CGraphicsPort *port)
{
return;
}
// Work out which colors to use
nxgl_coord_t color1;
nxgl_coord_t color2;
if (isClicked())
{
// Bevelled into the screen
@ -357,7 +364,7 @@ void CImage::drawBorder(CGraphicsPort *port)
color1 = getShineEdgeColor();
color2 = getShadowEdgeColor();
}
port->drawBevelledRect(getX(), getY(), getWidth(), getHeight(), color1, color2);
}
@ -389,7 +396,7 @@ void CImage::onClick(nxgl_coord_t x, nxgl_coord_t y)
}
/**
* Raises an action.
* Raises an action.
*
* @param x The x coordinate of the mouse.
* @param y The y coordinate of the mouse.

View File

@ -1261,8 +1261,8 @@ void CMultiLineTextBox::drawRow(CGraphicsPort *port, int row)
uint8_t rowLength = m_text->getLineTrimmedLength(row);
struct nxgl_point_s pos;
pos.x = getRowX(row) + m_canvasX;
pos.y = getRowY(row) + m_canvasY;
pos.x = getRowX(row) + m_canvasX + rect.getX();
pos.y = getRowY(row) + m_canvasY + rect.getY();
// Determine the background and text color

View File

@ -193,16 +193,16 @@ void CNxTimer::workQueueCallback(FAR void *arg)
This->m_isRunning = false;
// Raise the action event.
This->m_widgetEventHandlers->raiseActionEvent();
// Restart the timer if this is a repeating timer
if (This->m_isRepeater)
{
This->start();
}
// Raise the action event.
This->m_widgetEventHandlers->raiseActionEvent();
}

View File

@ -1,7 +1,7 @@
/****************************************************************************
* NxWidgets/libnxwidgets/src/cwidgetcontrol.cxx
*
* Copyright (C) 2012 Gregory Nutt. All rights reserved.
* Copyright (C) 2012-2013 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@ -117,6 +117,7 @@ CWidgetControl::CWidgetControl(FAR const CWidgetStyle *style)
sem_init(&m_waitSem, 0, 0);
#endif
#ifdef CONFIG_NX_MULTIUSER
sem_init(&m_boundsSem, 0, 0);
sem_init(&m_geoSem, 0, 0);
#endif
@ -135,12 +136,11 @@ CWidgetControl::CWidgetControl(FAR const CWidgetStyle *style)
copyWidgetStyle(&m_style, style);
}
}
/**
* Destructor.
*/
CWidgetControl::~CWidgetControl(void)
{
// Notify any external waiters... this should not happen because it
@ -235,7 +235,7 @@ void CWidgetControl::postWindowEvent(void)
* all widgets in the window.
* @return True means some interesting event occurred
*/
bool CWidgetControl::pollEvents(CNxWidget *widget)
{
// Delete any queued widgets
@ -299,7 +299,7 @@ void CWidgetControl::removeControlledWidget(CNxWidget *widget)
*
* @param widget The widget to add to the delete queue.
*/
void CWidgetControl::addToDeleteQueue(CNxWidget *widget)
{
// Add the widget to the delete queue
@ -330,7 +330,7 @@ void CWidgetControl::setClickedWidget(CNxWidget *widget)
m_clickedWidget->release(m_clickedWidget->getX() - 10, 0);
}
// Update the pointer
m_clickedWidget = widget;
@ -394,18 +394,19 @@ void CWidgetControl::geometryEvent(NXHANDLE hWindow,
if (!m_hWindow)
{
// Save one-time server specific information
m_hWindow = hWindow;
nxgl_rectcopy(&m_bounds, bounds);
giveBoundsSem();
}
// In the normal start up sequence, the window is created with zero size
// at position 0,0. The safe thing to do is to set the position (still
// with size 0, then then set the size. Assuming that is what is being
// done, we will not report that we have valid geometry until the size
// becomes nonzero.
// becomes nonzero (or actually over 1).
if (!m_haveGeometry && size->h > 0 && size->w > 0)
if (!m_haveGeometry && size->h > 1 && size->w > 1)
{
// Wake up any threads waiting for initial position information.
// REVISIT: If the window is moved or repositioned, then the
@ -619,7 +620,7 @@ void CWidgetControl::newKeyboardEvent(uint8_t nCh, FAR const uint8_t *pStr)
*
* @param cursorControl The cursor control code received.
*/
void CWidgetControl::newCursorControlEvent(ECursorControl cursorControl)
{
// Append the new cursor control
@ -688,7 +689,7 @@ void CWidgetControl::copyWidgetStyle(CWidgetStyle *dest, const CWidgetStyle *src
* @param tp A time in the past from which to compute the elapsed time.
* @return The elapsed time since tp
*/
uint32_t CWidgetControl::elapsedTime(FAR const struct timespec *startTime)
{
struct timespec endTime;
@ -701,7 +702,7 @@ uint32_t CWidgetControl::elapsedTime(FAR const struct timespec *startTime)
uint32_t seconds = endTime.tv_sec - startTime->tv_sec;
// Get the elapsed nanoseconds, borrowing from the seconds if necessary
int32_t endNanoSeconds = endTime.tv_nsec;
if (startTime->tv_nsec > endNanoSeconds)
{
@ -767,7 +768,7 @@ void CWidgetControl::handleLeftClick(nxgl_coord_t x, nxgl_coord_t y, CNxWidget *
/**
* Delete any widgets in the deletion queue.
*/
void CWidgetControl::processDeleteQueue(void)
{
int i = 0;
@ -916,6 +917,25 @@ void CWidgetControl::takeGeoSem(void)
}
#endif
/**
* Take the bounds semaphore (handling signal interruptions)
*/
#ifdef CONFIG_NX_MULTIUSER
void CWidgetControl::takeBoundsSem(void)
{
// Take the bounds semaphore. Retry is an error occurs (only if
// the error is due to a signal interruption).
int ret;
do
{
ret = sem_wait(&m_boundsSem);
}
while (ret < 0 && errno == EINTR);
}
#endif
/**
* Clear all mouse events
*/

View File

@ -119,7 +119,6 @@ namespace NxWM
CApplicationWindow *m_window; /**< Reference to the application window */
TNxArray<struct SStartWindowSlot> 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

View File

@ -1,7 +1,7 @@
/****************************************************************************
* NxWidgets/nxwm/include/cwindowmessenger.hxx
*
* Copyright (C) 2012 Gregory Nutt. All rights reserved.
* Copyright (C) 2012-2013 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@ -39,12 +39,12 @@
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <sys/types.h>
#include <mqueue.h>
#include <nuttx/wqueue.h>
#include <nuttx/nx/nxtk.h>
#include <nuttx/nx/nxconsole.h>
@ -83,9 +83,20 @@ namespace NxWM
public NXWidgets::CWidgetControl
{
private:
mqd_t m_mqd; /**< Message queue descriptor used to commincate with the
** start window thread. */
/** Structure that stores data for the work queue callback. */
struct work_state_t
{
work_s work;
CWindowMessenger *windowMessenger;
void *instance;
};
/** Work queue callback functions */
static void inputWorkCallback(FAR void *arg);
static void destroyWorkCallback(FAR void *arg);
/**
* Handle an NX window mouse input event.
*
@ -109,7 +120,7 @@ namespace NxWM
*
* @param arg - User provided argument (see nx_block or nxtk_block)
*/
void handleBlockedEvent(FAR void *arg);
public:

View File

@ -1,7 +1,7 @@
/********************************************************************************************
* NxWidgets/nxwm/src/capplicationwindow.cxx
*
* Copyright (C) 2012 Gregory Nutt. All rights reserved.
* Copyright (C) 2012-2013 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@ -54,6 +54,18 @@
* Pre-Processor Definitions
********************************************************************************************/
#ifdef CONFIG_NXWM_STOP_BITMAP
extern const struct NXWidgets::SRlePaletteBitmap CONFIG_NXWM_STOP_BITMAP;
#else
# define CONFIG_NXWM_STOP_BITMAP g_stopBitmap
#endif
#ifdef CONFIG_NXWM_MINIMIZE_BITMAP
extern const struct NXWidgets::SRlePaletteBitmap CONFIG_NXWM_MINIMIZE_BITMAP;
#else
# define CONFIG_NXWM_MINIMIZE_BITMAP g_minimizeBitmap
#endif
/********************************************************************************************
* CApplicationWindow Method Implementations
********************************************************************************************/
@ -192,7 +204,7 @@ bool CApplicationWindow::open(void)
{
// Create STOP bitmap container
m_stopBitmap = new NXWidgets::CRlePaletteBitmap(&g_stopBitmap);
m_stopBitmap = new NXWidgets::CRlePaletteBitmap(&CONFIG_NXWM_STOP_BITMAP);
if (!m_stopBitmap)
{
return false;
@ -244,7 +256,7 @@ bool CApplicationWindow::open(void)
#ifndef CONFIG_NXWM_DISABLE_MINIMIZE
// Create MINIMIZE application bitmap container
m_minimizeBitmap = new NXWidgets::CRlePaletteBitmap(&g_minimizeBitmap);
m_minimizeBitmap = new NXWidgets::CRlePaletteBitmap(&CONFIG_NXWM_MINIMIZE_BITMAP);
if (!m_minimizeBitmap)
{
return false;
@ -375,7 +387,7 @@ void CApplicationWindow::redraw(void)
m_minimizeImage->redraw();
m_minimizeImage->setRaisesEvents(true);
}
// And finally draw the window label
m_windowLabel->enableDrawing();
@ -406,7 +418,7 @@ void CApplicationWindow::hide(void)
m_minimizeImage->disableDrawing();
m_minimizeImage->setRaisesEvents(false);
}
// Disable the window label
m_windowLabel->disableDrawing();

View File

@ -1,7 +1,7 @@
/********************************************************************************************
* NxWidgets/nxwm/src/cstartwindow.cxx
*
* Copyright (C) 2012 Gregory Nutt. All rights reserved.
* Copyright (C) 2012-2013 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@ -44,8 +44,6 @@
#include <csched>
#include <cerrno>
#include <mqueue.h>
#include "cwidgetcontrol.hxx"
#include "nxwmconfig.hxx"
@ -66,7 +64,7 @@
*/
FAR const char *NxWM::g_startWindowMqName = CONFIG_NXWM_STARTWINDOW_MQNAME;
/********************************************************************************************
* CStartWindow Method Implementations
********************************************************************************************/
@ -89,10 +87,6 @@ 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();
@ -169,24 +163,7 @@ NXWidgets::CNxString CStartWindow::getName(void)
bool CStartWindow::run(void)
{
// Some sanity checking
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 char * const *)0);
// Did we successfully start the NxConsole task?
return m_taskId >= 0;
return true;
}
/**
@ -195,21 +172,8 @@ bool CStartWindow::run(void)
void CStartWindow::stop(void)
{
// 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);
}
}
/**
* Destroy the application and free all of its resources. This method
* will initiate blocking of messages from the NX server. The server
@ -532,7 +496,7 @@ void CStartWindow::getIconBounds(void)
void CStartWindow::removeAllApplications(void)
{
// Stop all applications and remove them from the start window. 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
@ -543,7 +507,7 @@ void CStartWindow::removeAllApplications(void)
IApplicationFactory *app = m_slots.at(0).app;
// Now, delete the image and the application
delete app;
delete m_slots.at(0).image;
@ -596,108 +560,3 @@ void CStartWindow::handleActionEvent(const NXWidgets::CWidgetEventArgs &e)
}
}
/**
* 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::CWindowMessenger.
* 6. NxWM::CWindowMessenger 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(g_startWindowMqName, O_RDONLY|O_CREAT, 0666, &attr);
if (mqd == (mqd_t)-1)
{
gdbg("ERROR: mq_open(%s) failed: %d\n", g_startWindowMqName, 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)
{
int errval = errno;
// EINTR is not an error. The wait was interrupted by a signal and
// we just need to try reading again.
if (errval != EINTR)
{
gdbg("ERROR: mq_receive failed: %d\n", errval);
}
else
{
gdbg("mq_receive interrupted by signal\n");
}
continue;
}
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;
}
}
}

View File

@ -1,7 +1,7 @@
/********************************************************************************************
* NxWidgets/nxwm/src/ctaskbar.cxx
*
* Copyright (C) 2012 Gregory Nutt. All rights reserved.
* Copyright (C) 2012-2013 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@ -456,11 +456,21 @@ bool CTaskbar::startApplication(IApplication *app, bool minimized)
NXWidgets::IBitmap *bitmap = app->getIcon();
// Create a CImage instance to manage the applications icon
// Create a CImage instance to manage the applications icon. Assume the
// minimum size in case no bitmap is provided (bitmap == NULL)
int w = 1;
int h = 1;
if (bitmap)
{
w = bitmap->getWidth();
h = bitmap->getHeight();
}
NXWidgets::CImage *image =
new NXWidgets::CImage(control, 0, 0, bitmap->getWidth(),
bitmap->getHeight(), bitmap, 0);
new NXWidgets::CImage(control, 0, 0, w, h, bitmap, 0);
if (!image)
{
return false;

View File

@ -1,7 +1,7 @@
/********************************************************************************************
* NxWidgets/nxwm/src/cwindowmessenger.cxx
*
* Copyright (C) 2012 Gregory Nutt. All rights reserved.
* Copyright (C) 2012-2013 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@ -69,20 +69,6 @@ using namespace NxWM;
CWindowMessenger::CWindowMessenger(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(g_startWindowMqName, O_WRONLY|O_CREAT, 0666, &attr);
if (m_mqd == (mqd_t)-1)
{
gdbg("ERROR: mq_open(%s) failed: %d\n", g_startWindowMqName, errno);
}
// Add ourself to the list of window event handlers
addWindowEventHandler(this);
@ -97,10 +83,6 @@ CWindowMessenger::~CWindowMessenger(void)
// Remove ourself from the list of the window event handlers
removeWindowEventHandler(this);
// Close the message queue
(void)mq_close(m_mqd);
}
/**
@ -120,8 +102,8 @@ void CWindowMessenger::handleMouseEvent(void)
// 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
// 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
@ -133,20 +115,18 @@ void CWindowMessenger::handleMouseEvent(void)
// window event.
// 8. NXWidgets::CWindowEventHandlerList will give the event to this method
// NxWM::CWindowMessenger.
// 9. This NxWM::CWindowMessenger 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()
// 9. This NxWM::CWindowMessenger method will schedule an entry on the work
// queue.
// 10. The work queue callback will finally call pollEvents() to execute whatever
// actions the input event should trigger.
struct SStartWindowMessage outmsg;
outmsg.msgId = MSGID_MOUSE_INPUT;
outmsg.instance = (FAR void *)static_cast<CWidgetControl*>(this);
work_state_t *state = new work_state_t;
state->windowMessenger = this;
int ret = mq_send(m_mqd, &outmsg, sizeof(struct SStartWindowMessage),
CONFIG_NXWM_STARTWINDOW_MXMPRIO);
int ret = work_queue(USRWORK, &state->work, &inputWorkCallback, state, 0);
if (ret < 0)
{
gdbg("ERROR: mq_send failed: %d\n", errno);
gdbg("ERROR: work_queue failed: %d\n", ret);
}
}
#endif
@ -158,41 +138,13 @@ void CWindowMessenger::handleMouseEvent(void)
#ifdef CONFIG_NX_KBD
void CWindowMessenger::handleKeyboardEvent(void)
{
// The logic path here is tortuous but flexible:
//
// 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::CWindowMessenger.
// 9. This NxWM::CWindowMessenger 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()
work_state_t *state = new work_state_t;
state->windowMessenger = this;
struct SStartWindowMessage outmsg;
outmsg.msgId = MSGID_KEYBOARD_INPUT;
outmsg.instance = (FAR void *)static_cast<CWidgetControl*>(this);
int ret = mq_send(m_mqd, &outmsg, sizeof(struct SStartWindowMessage),
CONFIG_NXWM_STARTWINDOW_MXMPRIO);
int ret = work_queue(USRWORK, &state->work, &inputWorkCallback, state, 0);
if (ret < 0)
{
gdbg("ERROR: mq_send failed: %d\n", errno);
gdbg("ERROR: work_queue failed: %d\n", ret);
}
}
#endif
@ -213,18 +165,40 @@ void CWindowMessenger::handleKeyboardEvent(void)
void CWindowMessenger::handleBlockedEvent(FAR void *arg)
{
// Send a message to destroy the window isntance at a later time
// Send a message to destroy the window instance.
struct SStartWindowMessage outmsg;
outmsg.msgId = MSGID_DESTROY_APP;
outmsg.instance = arg;
work_state_t *state = new work_state_t;
state->windowMessenger = this;
state->instance = arg;
gdbg("Sending MSGID_DESTROY_APP with instance=%p\n", arg);
int ret = mq_send(m_mqd, &outmsg, sizeof(struct SStartWindowMessage),
CONFIG_NXWM_STARTWINDOW_MXMPRIO);
int ret = work_queue(USRWORK, &state->work, &destroyWorkCallback, state, 0);
if (ret < 0)
{
gdbg("ERROR: mq_send failed: %d\n", errno);
gdbg("ERROR: work_queue failed: %d\n", ret);
}
}
/** Work queue callback functions */
void CWindowMessenger::inputWorkCallback(FAR void *arg)
{
work_state_t *state = (work_state_t*)arg;
state->windowMessenger->pollEvents();
delete state;
}
void CWindowMessenger::destroyWorkCallback(FAR void *arg)
{
work_state_t *state = (work_state_t*)arg;
// First make sure any pending input events have been handled.
state->windowMessenger->pollEvents();
// Then release the memory.
gdbg("Deleting app=%p\n", state->instance);
IApplication *app = (IApplication *)state->instance;
delete app;
delete state;
}