Squashed commit of the following:

apps/graphics/twm4nx:  Revise logic to detect clicks on the background image.  The original implementation had some side effects.

    apps/graphics/twm4nx:  Remove some remaining, unused stuff from TWM that was never used.  Menus need to close after the 'terminal' selection is made.  Otherwise, the menu can become buried under a newly open menu and not easily recovered.

    apps/graphics/twm4ndx:  Add a 'critical' bit to the eventID.  While resizing, all events will be ignore except those marked critical.

    apps/graphics/twm4nx:  CBackground now brings up the main menu if the background image is click.  This makes the behavior the same across all of the background except when an icon is clicked.
This commit is contained in:
Gregory Nutt 2019-05-23 10:20:12 -06:00
parent 7409dd57bb
commit 636e3e2278
12 changed files with 174 additions and 258 deletions

View File

@ -88,9 +88,12 @@ How To:
o Desktop. Iconify all windows and show the desktop
o Twm4Nx Icom Manager. De-iconify and/or raise the Icon Manager to
the top of the display
the top of the display.
o Calibration. Perform touchscreen re-calibration.
o NuttShell. Start and instance of NSH running in an NxTerm.
- All windows close after the terminal menu option is selected.
Window Toolbar
- Most windows have a toolbar at the top. It is optional but used
in most windows.
@ -126,6 +129,9 @@ How To:
o Move toward the top decreases the height of the Window
o Other moves will affect both the height and width of the window.
- NOTE: While resizing, non-critical events from all other windows
are ignored.
Themes
- There are two themes support by the configuration system:
o CONFIG_TWM4NX_CLASSIC. Strong bordered windows with dark primary
@ -153,27 +159,18 @@ Issues:
Other issues/bugs
5. Icon drag movement includes logic to avoid collisions with other
icons and with the background image. That later is an issue. The
background image image widget needs to be removed; it can occlude a
desktop icon. We need to paint the image directly on the background
without the use of a widget.
6. More issues with the background image: It absorbs touchscreen
presses without doing anything. It should bring-up the main menu
menu just as any other region of the background. This would be easy
to fix, but just replacing the background image widget and drawing
directly on the background which is the better solution anyway.
NOTE: There is a configuration option that will eliminate the background
image. The CONTEMPORARY theme, for example, has no background image.
7. There are a few color artifacts in the toolbar of the CONTEMPORARY
icons and with the background image. That later is an issue. We
need to paint the image directly on the background without the
use of a widget.
6. There are a few color artifacts in the toolbar of the CONTEMPORARY
theme. These look like borders are being drawn around the toolbar
widgets (even though the are configured to be borderless).
8. Most Twm4Nx configuration settings are hard-coded in *_config.hxx header
7. Most Twm4Nx configuration settings are hard-coded in *_config.hxx header
files. These all need to be brought out and made accessible via Kconfig
files
9. If you create a window and resize it while the Main Menu is up, you can
force things into a bad state by interacting with the Main Menu while
resize is in operation.
10. Things become buggy after perhaps 10 shell windows have been opened.
8. Things become buggy after perhaps 10 shell windows have been opened.
Most likely, some resource allocation is failing silently and leaving
things in a bad state. The board I am using has 128Mb of SDRAM so I
can't believe that memory is limiting factor.
can't believe that memory is the limiting factor. These are, however,
RAM-backed windows and will use significant amounts of memory.

View File

@ -548,7 +548,7 @@ void CNxTerm::redraw(void)
}
/**
* inform NxTerm of a new window size.
* Inform NxTerm of a new window size.
*/
void CNxTerm::resize(void)

View File

@ -295,6 +295,9 @@ bool CBackground::event(FAR struct SEventMsg *eventmsg)
NXWidgets::CWidgetControl *control =
m_backWindow->getWidgetControl();
FAR struct SXyInputEventMsg *xymsg =
(FAR struct SXyInputEventMsg *)eventmsg;
// pollEvents() returns true if any interesting event occurred
// within a widget that is associated with the background window.
// false is not a failure.
@ -305,35 +308,24 @@ bool CBackground::event(FAR struct SEventMsg *eventmsg)
// a background click. In that case, we should bring up the
// main menu (if it is not already up).
// Is the main menu already up? Was the mouse left button
// pressed?
FAR struct SXyInputEventMsg *xymsg =
(FAR struct SXyInputEventMsg *)eventmsg;
FAR CMainMenu *cmain = m_twm4nx->getMainMenu();
if (!cmain->isVisible() &&
(xymsg->buttons & MOUSE_BUTTON_1) != 0)
{
// Bring up the main menu
struct SEventMsg outmsg;
outmsg.eventID = EVENT_MAINMENU_SELECT;
outmsg.pos.x = eventmsg->pos.x;
outmsg.pos.y = eventmsg->pos.y;
outmsg.context = EVENT_CONTEXT_BACKGROUND;
outmsg.handler = (FAR void *)0;
outmsg.obj = (FAR void *)this;
int ret = mq_send(m_eventq, (FAR const char *)&outmsg,
sizeof(struct SEventMsg), 100);
if (ret < 0)
{
twmerr("ERROR: mq_send failed: %d\n", errno);
}
}
showMainMenu(xymsg->pos, xymsg->buttons);
}
#ifdef CONFIG_TWM4NX_BACKGROUND_HASIMAGE
// If there is a background image, then clicking the background
// image is equivalent to clicking the background. We need to
// handle this case because the image widget occludes the
// background
else if (m_backImage != (NXWidgets::CImage *)0 &&
m_backImage->isClicked())
{
// Treat the image click like background click: Bring up the
// main menu (if it is not already up).
showMainMenu(xymsg->pos, xymsg->buttons);
}
#endif
}
break;
@ -496,10 +488,13 @@ bool CBackground::
return false;
}
// Configure and draw the background image
// Configure and draw the background image.
// NOTE that we need to get events from the background image. That is
// because the image occludes the background and we have to treat image
// clicks just as background clicks.
m_backImage->setBorderless(true);
m_backImage->setRaisesEvents(false);
m_backImage->setRaisesEvents(true);
m_backImage->enable();
m_backImage->enableDrawing();
@ -508,6 +503,40 @@ bool CBackground::
}
#endif
/**
* Bring up the main menu (if it is not already up).
*
* @param pos The window click position.
* @param buttons The set of mouse button presses.
*/
void CBackground::showMainMenu(FAR struct nxgl_point_s &pos,
uint8_t buttons)
{
// Is the main menu already up? Was the mouse left button pressed?
FAR CMainMenu *cmain = m_twm4nx->getMainMenu();
if (!cmain->isVisible() && (buttons & MOUSE_BUTTON_1) != 0)
{
// Bring up the main menu
struct SEventMsg outmsg;
outmsg.eventID = EVENT_MAINMENU_SELECT;
outmsg.pos.x = pos.x;
outmsg.pos.y = pos.y;
outmsg.context = EVENT_CONTEXT_BACKGROUND;
outmsg.handler = (FAR void *)0;
outmsg.obj = (FAR void *)this;
int ret = mq_send(m_eventq, (FAR const char *)&outmsg,
sizeof(struct SEventMsg), 100);
if (ret < 0)
{
twmerr("ERROR: mq_send failed: %d\n", errno);
}
}
}
/**
* Release resources held by the background.
*/

View File

@ -300,61 +300,11 @@ bool CMenus::event(FAR struct SEventMsg *eventmsg)
}
break;
case EVENT_MENU_IDENTIFY: // Describe the window
case EVENT_MENU_COMPLETE: // Menu selection complete
{
identify((FAR CWindow *)eventmsg->obj);
}
break;
case EVENT_MENU_VERSION: // Show the Twm4Nx version
identify((FAR CWindow *) NULL);
break;
case EVENT_MENU_DEICONIFY: // Window icon pressed
case EVENT_MENU_ICONIFY: // Tool bar minimize button pressed
{
FAR CWindow *cwin = (FAR CWindow *)eventmsg->obj;
if (cwin->isIconified())
if (!m_menuWindow->isIconified())
{
cwin->deIconify();
}
else if (eventmsg->eventID == EVENT_MENU_ICONIFY)
{
cwin->iconify();
}
}
break;
case EVENT_MENU_FUNCTION: // Perform function on unknown menu
{
FAR struct SMenuItem *item;
for (item = m_menuHead; item != NULL; item = item->flink)
{
// Send another event message to the session manager
struct SEventMsg newmsg;
newmsg.eventID = item->event;
newmsg.obj = eventmsg->obj;
newmsg.pos.x = eventmsg->pos.x;
newmsg.pos.y = eventmsg->pos.y;
newmsg.context = eventmsg->context;
newmsg.handler = (FAR void *)item->handler;
// NOTE that we cannot block because we are on the same thread
// as the message reader. If the event queue becomes full then
// we have no other option but to lose events.
//
// I suppose we could recurse and call Twm4Nx::dispatchEvent at
// the risk of runaway stack usage.
int ret = mq_send(m_eventq, (FAR const char *)&newmsg,
sizeof(struct SEventMsg), 100);
if (ret < 0)
{
twmerr("ERROR: mq_send failed: %d\n", errno);
success = false;
}
m_menuWindow->iconify();
}
}
break;
@ -376,117 +326,6 @@ bool CMenus::event(FAR struct SEventMsg *eventmsg)
return success;
}
void CMenus::identify(FAR CWindow *cwin)
{
int n = 0;
#if CONFIG_VERSION_MAJOR != 0 || CONFIG_VERSION_MINOR != 0
std::snprintf(m_info[n], INFO_SIZE, "Twm4Nx: NuttX-" CONFIG_VERSION_STRING);
#else
std::snprintf(m_info[n], INFO_SIZE, "Twm4Nx:");
#endif
m_info[n++][0] = '\0';
if (cwin != (FAR CWindow *)0)
{
// Get the size of the window
struct nxgl_size_s windowSize;
if (!cwin->getFrameSize(&windowSize))
{
return;
}
struct nxgl_point_s windowPos;
if (!cwin->getFramePosition(&windowPos))
{
return;
}
std::snprintf(m_info[n++], INFO_SIZE, "Name = \"%s\"",
cwin->getWindowName());
m_info[n++][0] = '\0';
std::snprintf(m_info[n++], INFO_SIZE, "Geometry/root = %dx%d+%d+%d",
windowSize.w, windowSize.h, windowPos.x, windowPos.y);
}
m_info[n++][0] = '\0';
std::snprintf(m_info[n++], INFO_SIZE, "Click to dismiss....");
// Figure out the width and height of the info window
FAR CFonts *fonts = m_twm4nx->getFonts();
FAR NXWidgets::CNxFont *defaultFont = fonts->getDefaultFont();
struct nxgl_size_s menuSize;
menuSize.h = n * (defaultFont->getHeight() + 2);
menuSize.w = 1;
for (int i = 0; i < n; i++)
{
int twidth = defaultFont->getStringWidth(m_info[i]);
if (twidth > menuSize.w)
{
menuSize.w = twidth;
}
}
menuSize.w += 10; // some padding
// Make sure that the window is on the display
struct nxgl_point_s menuPos;
if (m_menuWindow->getWindowPosition(&menuPos))
{
menuPos.x -= (menuSize.w / 2);
menuPos.y -= (menuSize.h / 3);
struct nxgl_size_s displaySize;
m_twm4nx->getDisplaySize(&displaySize);
struct nxgl_size_s frameSize;
menuToFrameSize(&menuSize, &frameSize);
if (menuPos.x + frameSize.w >= displaySize.w)
{
menuPos.x = displaySize.w - frameSize.w;
}
if (menuPos.y + frameSize.h >= displaySize.h)
{
menuPos.y = displaySize.h - frameSize.h;
}
if (menuPos.x < 0)
{
menuPos.x = 0;
}
if (menuPos.y < 0)
{
menuPos.y = 0;
}
frameToMenuSize(&frameSize, &menuSize);
}
else
{
menuPos.x = 0;
menuPos.y = 0;
}
// Set the new window size and position
if (!m_menuWindow->setWindowPosition(&menuPos) ||
!m_menuWindow->setWindowSize(&menuSize))
{
return;
}
// Raise it to the top of the hiearchy
m_menuWindow->raiseWindow();
}
/**
* Convert the position of a menu window to the position of
* the containing frame.
@ -787,7 +626,7 @@ void CMenus::handleActionEvent(const NXWidgets::CWidgetEventArgs &e)
if (m_buttons->isButtonClicked(column, row) && column == 0)
{
// The row number is sufficent to locate the menu entry info
// The row number is sufficient to locate the menu entry info
// But we have to search through the menu items to find the
// at this row.
@ -817,8 +656,11 @@ void CMenus::handleActionEvent(const NXWidgets::CWidgetEventArgs &e)
// 2. Sub-menu
// 3. Event with other recipients
if ((item->event & EVENT_RECIPIENT_MASK) != EVENT_RECIPIENT_APP &&
item->subMenu != (FAR CMenus *)0)
bool subMenu =
((item->event & EVENT_RECIPIENT_MASK) != EVENT_RECIPIENT_APP &&
item->subMenu != (FAR CMenus *)0);
if (subMenu)
{
msg.eventID = EVENT_MENU_SUBMENU;
msg.obj = (FAR void *)item->subMenu;
@ -856,7 +698,27 @@ void CMenus::handleActionEvent(const NXWidgets::CWidgetEventArgs &e)
twmerr("ERROR: mq_send failed: %d\n", errno);
}
return;
// If this is a terminal option (i.e., not a submenu) then
// make the menu inaccessible
if (!subMenu)
{
msg.eventID = EVENT_MENU_COMPLETE;
msg.obj = (FAR void *)this;
msg.handler = (FAR void *)0;
msg.pos.x = e.getX();
msg.pos.y = e.getY();
msg.context = EVENT_CONTEXT_MENU;
ret = mq_send(m_eventq, (FAR const char *)&msg,
sizeof(struct SEventMsg), 100);
if (ret < 0)
{
twmerr("ERROR: mq_send failed: %d\n", errno);
}
return;
}
}
}

View File

@ -504,7 +504,10 @@ bool CResize::startResize(FAR struct SEventMsg *eventmsg)
updateSizeLabel(m_lastSize);
// Disable all other toolbar buttons
// Disable all toolbar buttons except for the RESIZE button which is
// needed to exit the resize mode.
// NOTE: This is really unnecessary since all non-critical events are
// ignored during resizing.
m_resizeWindow->disableToolbarButtons(DISABLE_MENU_BUTTON |
DISABLE_DELETE_BUTTON |

View File

@ -338,14 +338,20 @@ bool CTwm4Nx::eventLoop(void)
return false;
}
// Dispatch the new event
// If we are resizing, then drop all non-critical events (of course,
// all resizing events must be critical)
if (!dispatchEvent(&u.eventmsg))
if (!m_resize->resizing() || EVENT_ISCRITICAL(u.eventmsg.eventID))
{
twmerr("ERROR: dispatchEvent() failed, eventID=%u\n",
u.eventmsg.eventID);
cleanup();
return false;
// Dispatch the new event
if (!dispatchEvent(&u.eventmsg))
{
twmerr("ERROR: dispatchEvent() failed, eventID=%u\n",
u.eventmsg.eventID);
cleanup();
return false;
}
}
}

View File

@ -592,7 +592,7 @@ bool CWindow::iconify(void)
{
if (!isIconified())
{
// Make sure to exit any modal state before minimizing
// Make sure to exit any modal state before minimizing
m_modal = false;
m_nxWin->modal(false);
@ -1472,8 +1472,7 @@ void CWindow::handleActionEvent(const NXWidgets::CWidgetEventArgs &e)
// Check if this button is omitted by toolbar customizations or if the
// button is temporarily disabled.
if ((m_tbFlags & (1 << btindex)) != 0 ||
(m_tbDisables & (1 << btindex)) != 0)
if (((m_tbFlags | m_tbDisables) & (1 << btindex)) != 0)
{
continue;
}
@ -1533,7 +1532,7 @@ bool CWindow::moveEvent(FAR const struct nxgl_point_s &pos,
if (m_dragging)
{
// arg == 0 means that this a tooolbar event vs s main window event.
// arg == 0 means that this a toolbar event vs s main window event.
// Since the position is relative in both cases, we need a fix-up in
// the height to keep the same toolbar relative position in all cases.
@ -1571,7 +1570,7 @@ bool CWindow::moveEvent(FAR const struct nxgl_point_s &pos,
/**
* This function is called if the mouse left button is released or
* if the touchscrreen touch is lost. This indicates that the
* if the touchscreen touch is lost. This indicates that the
* dragging sequence is complete.
*
* This function overrides the virtual IEventTap::dropEvent method.

View File

@ -59,8 +59,8 @@
// CNxTerm application events
// Window Events
#define EVENT_NXTERM_REDRAW (EVENT_RECIPIENT_APP | 0x0000)
#define EVENT_NXTERM_RESIZE (EVENT_RECIPIENT_APP | 0x0001)
#define EVENT_NXTERM_REDRAW (EVENT_RECIPIENT_APP | EVENT_CRITICAL | 0x0000)
#define EVENT_NXTERM_RESIZE (EVENT_RECIPIENT_APP | EVENT_CRITICAL | 0x0001)
#define EVENT_NXTERM_XYINPUT EVENT_SYSTEM_NOP
#define EVENT_NXTERM_KBDINPUT EVENT_SYSTEM_NOP
#define EVENT_NXTERM_DELETE EVENT_WINDOW_DELETE

View File

@ -109,6 +109,15 @@ namespace Twm4Nx
bool createBackgroundImage(FAR const struct NXWidgets::SRlePaletteBitmap *sbitmap);
#endif
/**
* Bring up the main menu (if it is not already up).
*
* @param pos The window click position.
* @param buttons The set of mouse button presses.
*/
void showMainMenu(FAR struct nxgl_point_s &pos, uint8_t buttons);
/**
* Release resources held by the background.
*/

View File

@ -124,8 +124,6 @@ namespace Twm4Nx
uint8_t m_nrows; /**< Number of rows in the button array */
char m_info[INFO_LINES][INFO_SIZE];
void identify(FAR CWindow *cwin);
/**
* Convert the position of a menu window to the position of
* the containing frame.

View File

@ -76,8 +76,8 @@ namespace Twm4Nx
// separately only to minimize the complexity of CWindows (and because it
// matches the original partitioning of TWM). The downside is that (1) CWindow
// instances have to be passed un-necessarily, and (2) the precludes the
// possibiity of resizing two window simultaneous. That latter is not
// currenlty supported anyway.
// possibility of resizing two window simultaneous. That latter is not
// currently supported anyway.
class CResize : protected NXWidgets::CWidgetEventHandler,
protected IEventTap,

View File

@ -54,8 +54,12 @@
// struct SRedrawEventMsg is the largest message as of this writing
#define MAX_EVENT_MSGSIZE sizeof(struct SRedrawEventMsg)
#define MAX_EVENT_PAYLOAD (MAX_EVENT_MSGSIZE - sizeof(uint16_t))
#define MAX_EVENT_MSGSIZE sizeof(struct SRedrawEventMsg)
#define MAX_EVENT_PAYLOAD (MAX_EVENT_MSGSIZE - sizeof(uint16_t))
#define EVENT_CRITICAL 0x0800
#define EVENT_RECIPIENT(id) ((id) & EVENT_RECIPIENT_MASK)
#define EVENT_ISCRITICAL(id) (((id) & EVENT_CRITICAL) != 0)
/////////////////////////////////////////////////////////////////////////////
// WidgetEvent
@ -77,6 +81,19 @@ namespace Twm4Nx
// Public Types
///////////////////////////////////////////////////////////////////////////
/**
* Event ID format:
*
* rrrr nooo oooo oooo
*
* Bits 0-10: Opcode
* Bit 11: Critical event (cannot be discarded*)
* Bits 12-15: Recipient of the event
*
* * During a window resize operation, all events are ignored except for
* those that are marked critical.
*/
/**
* This enumeration identifies the recipient of the event
*/
@ -106,14 +123,14 @@ namespace Twm4Nx
// Recipient == SYSTEM
EVENT_SYSTEM_NOP = 0x0000, /**< Null event */
EVENT_SYSTEM_ERROR = 0x0001, /**< Report system error */
EVENT_SYSTEM_EXIT = 0x0002, /**< Terminate the Twm4Nx session */
EVENT_SYSTEM_ERROR = 0x0801, /**< Report system error */
EVENT_SYSTEM_EXIT = 0x0802, /**< Terminate the Twm4Nx session */
EVENT_SYSTEM_STARTUP = 0x0003, /**< Start an application */
// Recipient == BACKGOUND
EVENT_BACKGROUND_XYINPUT = 0x1000, /**< Poll for widget mouse/touch events */
EVENT_BACKGROUND_REDRAW = 0x1001, /**< Redraw the background */
EVENT_BACKGROUND_REDRAW = 0x1801, /**< Redraw the background */
// Recipient == ICONWIDGET
@ -129,12 +146,8 @@ namespace Twm4Nx
// Recipient == MENU
EVENT_MENU_XYINPUT = 0x4000, /**< Poll for widget mouse/touch events */
EVENT_MENU_IDENTIFY = 0x4001, /**< Describe the window */
EVENT_MENU_VERSION = 0x4002, /**< Show the Twm4Nx version */
EVENT_MENU_ICONIFY = 0x4003, /**< Tool bar minimize button pressed */
EVENT_MENU_DEICONIFY = 0x4004, /**< Window icon pressed */
EVENT_MENU_SUBMENU = 0x4005, /**< Sub-menu selected */
EVENT_MENU_FUNCTION = 0x4006, /**< Perform function on unknown menu */
EVENT_MENU_COMPLETE = 0x4001, /**< Menu selection complete */
EVENT_MENU_SUBMENU = 0x4002, /**< Sub-menu selected */
// Recipient == MAINMENU
@ -142,16 +155,16 @@ namespace Twm4Nx
// Recipient == WINDOW
EVENT_WINDOW_RAISE = 0x6000, /**< Raise window to the top of the heirarchy */
EVENT_WINDOW_LOWER = 0x6001, /**< Lower window to the bottom of the heirarchy */
EVENT_WINDOW_RAISE = 0x6000, /**< Raise window to the top of the hierarchy */
EVENT_WINDOW_LOWER = 0x6001, /**< Lower window to the bottom of the hierarchy */
EVENT_WINDOW_DEICONIFY = 0x6002, /**< De-iconify and raise window */
EVENT_WINDOW_DRAG = 0x6003, /**< Drag window */
EVENT_WINDOW_DELETE = 0x6004, /**< Delete window */
EVENT_WINDOW_DELETE = 0x6804, /**< Delete window */
EVENT_WINDOW_DESKTOP = 0x6005, /**< Show the desktop */
// Recipient == TOOLBAR
EVENT_TOOLBAR_XYINPUT = 0x7000, /**< Poll for widget mouse/touch events */
EVENT_TOOLBAR_XYINPUT = 0x7800, /**< Poll for widget mouse/touch events */
EVENT_TOOLBAR_GRAB = 0x7001, /**< Click on title widget */
EVENT_TOOLBAR_UNGRAB = 0x7002, /**< Release click on title widget */
EVENT_TOOLBAR_MENU = 0x7003, /**< Toolbar menu button released */
@ -162,15 +175,15 @@ namespace Twm4Nx
// Recipient == RESIZE
EVENT_RESIZE_XYINPUT = 0x9000, /**< Poll for widget mouse/touch events */
EVENT_RESIZE_BUTTON = 0x9001, /**< Start or stop a resize sequence */
EVENT_RESIZE_MOVE = 0x9002, /**< Mouse movement during a resize sequence */
EVENT_RESIZE_PAUSE = 0x9003, /**< Pause resize operation when unclicked */
EVENT_RESIZE_RESUME = 0x9004, /**< Resume resize operation when re-clicked */
EVENT_RESIZE_STOP = 0x9005, /**< End a resize sequence on second press */
EVENT_RESIZE_XYINPUT = 0x9800, /**< Poll for widget mouse/touch events */
EVENT_RESIZE_BUTTON = 0x9801, /**< Start or stop a resize sequence */
EVENT_RESIZE_MOVE = 0x9802, /**< Mouse movement during a resize sequence */
EVENT_RESIZE_PAUSE = 0x9803, /**< Pause resize operation when unclicked */
EVENT_RESIZE_RESUME = 0x9804, /**< Resume resize operation when re-clicked */
EVENT_RESIZE_STOP = 0x9805, /**< End a resize sequence on second press */
// Recipient == APP
// All application defined events must (1) use recepient == EVENT_RECIPIENT_APP,
// All application defined events must (1) use recipient == EVENT_RECIPIENT_APP,
// and (2) provide an instance of CTwm4NxEvent in the SEventMsg structure.
};