From e76bfbb74e0d7870bdbc656c07bc6cf2bfd5c268 Mon Sep 17 00:00:00 2001
From: Gregory Nutt <gnutt@nuttx.org>
Date: Thu, 16 May 2019 13:51:57 -0600
Subject: [PATCH] Squashed commit of the following:

    apps/graphics/twm4nx:  Other toolbar buttons need to be disabled while resizing.  Lots of problems if you decide to iconify or exit while resizing.  CResize now disables all buttons except for the RESIZE button while resizing.

    apps/graphics/twm4nx:  Add an event and logic to support notification of changes in the size of a window to NxTerm.

    Various updates to adapt to change in boardctl() interface.

    apps/graphics/twm4nx:  Correct an error in the NxTerm resize logic

    apps/graphics/twm4nx:  Update debug output when failures to send a message occur.  The returned value of -1 is not interested, need to show the errno value instead.

    apps/graphics/twm4nx:  Correct the maximum size of a message.  Recent changes caused message send failures because a message exceed that previous maximum size.

    apps/graphics/twm4nx:  Fix routing of redraw events.
---
 examples/nxterm/nxterm_wndo.c             |  8 ++-
 graphics/nxwidgets/src/ccallback.cxx      |  8 ++-
 graphics/nxwm/src/cnxterm.cxx             |  8 ++-
 graphics/twm4nx/README.txt                | 61 +++++++++++++++++------
 graphics/twm4nx/src/cbackground.cxx       |  3 +-
 graphics/twm4nx/src/ciconmgr.cxx          |  4 +-
 graphics/twm4nx/src/ciconwidget.cxx       |  6 +--
 graphics/twm4nx/src/cmenus.cxx            |  5 +-
 graphics/twm4nx/src/cnxterm.cxx           | 43 +++++++++++++---
 graphics/twm4nx/src/cresize.cxx           | 19 +++++--
 graphics/twm4nx/src/cwindow.cxx           | 57 ++++++++++++++++++---
 graphics/twm4nx/src/cwindowevent.cxx      | 12 +++--
 include/graphics/twm4nx/cnxterm.hxx       | 11 +++-
 include/graphics/twm4nx/cwindow.hxx       | 24 +++++++++
 include/graphics/twm4nx/cwindowevent.hxx  |  2 +
 include/graphics/twm4nx/nxterm_config.hxx | 10 ++--
 include/graphics/twm4nx/twm4nx_events.hxx | 25 +++++++++-
 17 files changed, 249 insertions(+), 57 deletions(-)

diff --git a/examples/nxterm/nxterm_wndo.c b/examples/nxterm/nxterm_wndo.c
index a8a006b8e..e8962e10d 100644
--- a/examples/nxterm/nxterm_wndo.c
+++ b/examples/nxterm/nxterm_wndo.c
@@ -116,7 +116,8 @@ static void nxwndo_redraw(NXWINDOW hwnd, FAR const struct nxgl_rect_s *rect,
 
   if (g_nxterm_vars.hdrvr)
     {
-      struct boardioc_nxterm_redraw_s redraw;
+      struct boardioc_nxterm_ioctl_s iocargs;
+      struct nxtermioc_redraw_s redraw;
 
       /* Inform the NX console of the redraw request */
 
@@ -124,7 +125,10 @@ static void nxwndo_redraw(NXWINDOW hwnd, FAR const struct nxgl_rect_s *rect,
       redraw.more   = more;
       nxgl_rectcopy(&redraw.rect, rect);
 
-      (void)boardctl(BOARDIOC_NXTERM_REDRAW, (uintptr_t)&redraw);
+      iocargs.cmd = NXTERMIOC_NXTERM_REDRAW;
+      iocargs.arg = (uintptr_t)&redraw;
+
+      (void)boardctl(BOARDIOC_NXTERM_IOCTL, (uintptr_t)&iocargs);
     }
   else
     {
diff --git a/graphics/nxwidgets/src/ccallback.cxx b/graphics/nxwidgets/src/ccallback.cxx
index 182be08e1..9211f645d 100644
--- a/graphics/nxwidgets/src/ccallback.cxx
+++ b/graphics/nxwidgets/src/ccallback.cxx
@@ -276,7 +276,8 @@ void CCallback::newKeyboardEvent(NXHANDLE hwnd, uint8_t nCh,
 
   if (This->m_nxterm)
     {
-      struct boardioc_nxterm_kbdin_s kbdin;
+      struct boardioc_nxterm_ioctl_s iocargs;
+      struct nxtermioc_kbdin_s kbdin;
 
       // Keyboard input is going to an NxTerm
 
@@ -284,7 +285,10 @@ void CCallback::newKeyboardEvent(NXHANDLE hwnd, uint8_t nCh,
       kbdin.buffer = str;
       kbdin.buflen = nCh;
 
-      (void)boardctl(BOARDIOC_NXTERM_KBDIN, (uintptr_t)&kbdin);
+      iocargs.cmd  = NXTERMIOC_NXTERM_KBDIN;
+      iocargs.arg  = (uintptr_t)&kbdin;
+
+      (void)boardctl(BOARDIOC_NXTERM_IOCTL, (uintptr_t)&iocargs);
     }
   else
 #endif
diff --git a/graphics/nxwm/src/cnxterm.cxx b/graphics/nxwm/src/cnxterm.cxx
index e82120d04..11f3ce8e2 100644
--- a/graphics/nxwm/src/cnxterm.cxx
+++ b/graphics/nxwm/src/cnxterm.cxx
@@ -411,7 +411,8 @@ void CNxTerm::redraw(void)
 
   // Redraw the entire NxTerm window
 
-  struct boardioc_nxterm_redraw_s redraw;
+  struct boardioc_nxterm_ioctl_s iocargs;
+  struct nxtermioc_redraw_s redraw;
 
   redraw.handle     = m_nxterm;
   redraw.rect.pt1.x = 0;
@@ -420,7 +421,10 @@ void CNxTerm::redraw(void)
   redraw.rect.pt2.y = windowSize.h - 1;
   redraw.more       = false;
 
-  (void)boardctl(BOARDIOC_NXTERM_KBDIN, (uintptr_t)&redraw);
+  iocargs.cmd       = NXTERMIOC_NXTERM_REDRAW;
+  iocargs.arg       = (uintptr_t)&redraw;
+
+  (void)boardctl(BOARDIOC_NXTERM_IOCTL, (uintptr_t)&iocargs);
 }
 
 /**
diff --git a/graphics/twm4nx/README.txt b/graphics/twm4nx/README.txt
index feca194d4..dc2ae6e91 100644
--- a/graphics/twm4nx/README.txt
+++ b/graphics/twm4nx/README.txt
@@ -29,6 +29,8 @@ within this directory.
 
 STATUS
 ======
+
+Progress:
   2019-04-28:  This port was brutal.  Much TWM logic was removed because it
     depended on X11 features (or just because I could not understand how to
     use it).  The replacement logic is only mostly in place but more
@@ -64,16 +66,49 @@ STATUS
     later is an issue.  The background image image widget needs to be
     removed; it can occlude a dektop icon.  We need to paint the image
     directly on the background without the use of a widget.
-  2019-05-15:  Resizing now seems to work correctly in Twm4Nx.  It is still
-    not usable, however.  When the window size is extended, the newly exposed
-    regions must initialized with meaningul data. This is a problem in NX.
-    Normally, NX generates a redraw callback whenever the application needs
-    to redraw a region the the display.  However, with RAM-backed windows,
-    all callbacks are suppressed.  That is okay in all cases except for a
-    resize.  The missing callback leaves the new window region improperly
-    initialized.
+  2019-05-15:  Resizing now seems to work correctly in Twm4Nx.
+
+How To:
+
+  Move a Window:
+    - Grab the title in the toolbar and move the window to the desired
+      postion.
+
+  Resize a Window:
+    - A window must have the green resize button with the square or it
+      cannot be resized.
+    - Press resize button.  A small window should pop-up in the upper
+      left hand corner showing the current window size.
+    - Touch anywhere in window (not the toolbar) and slide your finger.
+      The resize window will show the new size but there will be no other
+      update to the display.  It is thought that continous size updates
+      would overwhelm lower end MCUs.  Movements support include:
+
+      o Move toward the right increases the width of the window
+      o Move toward the left decreases the width of the window
+      o Move toward the bottom increases the height of the window
+      o Move toward the top decreases the heght of the Window
+      o Other moves will affect both the height and width of the window.
+
+  Main Menu:
+    - A touch/click at any open location on the background (except the
+      image at the center or on another icon) will bring up the Main Menu.
+      Options:
+
+      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
+      o NuttShell.  Start and instance of NSH runnin in an NxTerm.
 
 Issues:
+
+    2019-05-16:
+      Twm4Nx is in a very complete state but only at perhaps "alpha" in its
+      maturity.  You should expect to see some undocumented problems.  If
+      you see such problems and can describe a sequence to actions to
+      reproduce the problem, let me know and I will try to resolve the
+      problems.
+
     Here are all known issues and features that are missing:
 
     TWM Compatibilities Issues:
@@ -88,21 +123,17 @@ Issues:
        been working with a system where the touchscreen naturally matches
        up with the display and no calibration is required.  But the general
        case requires calibration.
-    6. Icon drag movement is fairly smooth, but I think there may be issues
-       with the window drag movement.  it is hard to tell because of
-       limitations in the touchscreen performance on the system that I am
-       working with.
-    7. Icon drag movement includes logic to avoid collisions with other
+    6. 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
        dektop icon.  We need to paint the image directly on the background
        without the use of a widget.
-    8. More issues with the background image:  It absorbs touchscreen
+    7. 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 is the better
        solution.
-    9. The Icon Manager currently used the default window width.  That is
+    8. The Icon Manager currently used the default window width.  That is
        set half of the display width which is okay for the display I am using,
        but it really needs to set a width that is appropriate for the number
        of columns and the size of a generic name string.
diff --git a/graphics/twm4nx/src/cbackground.cxx b/graphics/twm4nx/src/cbackground.cxx
index 0adedd9bf..c14c0fa88 100644
--- a/graphics/twm4nx/src/cbackground.cxx
+++ b/graphics/twm4nx/src/cbackground.cxx
@@ -321,7 +321,7 @@ bool CBackground::event(FAR struct SEventMsg *eventmsg)
                                     sizeof(struct SEventMsg), 100);
                   if (ret < 0)
                     {
-                      twmerr("ERROR: mq_send failed: %d\n", ret);
+                      twmerr("ERROR: mq_send failed: %d\n", errno);
                     }
                }
 
@@ -366,6 +366,7 @@ bool CBackground::createBackgroundWindow(void)
   struct SAppEvents events;
   events.eventObj    = (FAR void *)this;
   events.redrawEvent = EVENT_BACKGROUND_REDRAW;
+  events.resizeEvent = EVENT_SYSTEM_NOP;
   events.mouseEvent  = EVENT_BACKGROUND_XYINPUT;
   events.kbdEvent    = EVENT_SYSTEM_NOP;
   events.closeEvent  = EVENT_SYSTEM_NOP;
diff --git a/graphics/twm4nx/src/ciconmgr.cxx b/graphics/twm4nx/src/ciconmgr.cxx
index d86710820..104b1a4ca 100644
--- a/graphics/twm4nx/src/ciconmgr.cxx
+++ b/graphics/twm4nx/src/ciconmgr.cxx
@@ -48,6 +48,7 @@
 
 #include <cstdio>
 #include <cstring>
+#include <cerrno>
 
 #include "graphics/nxwidgets/cnxwindow.hxx"
 #include "graphics/nxwidgets/cnxfont.hxx"
@@ -533,6 +534,7 @@ bool CIconMgr::createIconManagerWindow(FAR const char *prefix)
   struct SAppEvents events;
   events.eventObj    = (FAR void *)this;
   events.redrawEvent = EVENT_SYSTEM_NOP;
+  events.resizeEvent = EVENT_SYSTEM_NOP;
   events.mouseEvent  = EVENT_ICONMGR_XYINPUT;
   events.kbdEvent    = EVENT_SYSTEM_NOP;
   events.closeEvent  = EVENT_SYSTEM_NOP;
@@ -900,7 +902,7 @@ void CIconMgr::handleActionEvent(const NXWidgets::CWidgetEventArgs &e)
                                 sizeof(struct SEventMsg), 100);
               if (ret < 0)
                 {
-                  twmerr("ERROR: mq_send failed: %d\n", ret);
+                  twmerr("ERROR: mq_send failed: %d\n", errno);
                 }
 
               break;
diff --git a/graphics/twm4nx/src/ciconwidget.cxx b/graphics/twm4nx/src/ciconwidget.cxx
index 0dd9728f2..284d1ad4a 100644
--- a/graphics/twm4nx/src/ciconwidget.cxx
+++ b/graphics/twm4nx/src/ciconwidget.cxx
@@ -481,7 +481,7 @@ void CIconWidget::handleUngrabEvent(const NXWidgets::CWidgetEventArgs &e)
                     sizeof(struct SEventMsg), 100);
   if (ret < 0)
     {
-      twmerr("ERROR: mq_send failed: %d\n", ret);
+      twmerr("ERROR: mq_send failed: %d\n", errno);
     }
 }
 
@@ -519,7 +519,7 @@ void CIconWidget::handleDragEvent(const NXWidgets::CWidgetEventArgs &e)
                         sizeof(struct SEventMsg), 100);
       if (ret < 0)
         {
-          twmerr("ERROR: mq_send failed: %d\n", ret);
+          twmerr("ERROR: mq_send failed: %d\n", errno);
         }
     }
 }
@@ -578,7 +578,7 @@ void CIconWidget::handleClickEvent(const NXWidgets::CWidgetEventArgs &e)
                         sizeof(struct SEventMsg), 100);
       if (ret < 0)
         {
-          twmerr("ERROR: mq_send failed: %d\n", ret);
+          twmerr("ERROR: mq_send failed: %d\n", errno);
         }
     }
 }
diff --git a/graphics/twm4nx/src/cmenus.cxx b/graphics/twm4nx/src/cmenus.cxx
index 225cfb527..22174da8b 100644
--- a/graphics/twm4nx/src/cmenus.cxx
+++ b/graphics/twm4nx/src/cmenus.cxx
@@ -350,7 +350,7 @@ bool CMenus::event(FAR struct SEventMsg *eventmsg)
                              sizeof(struct SEventMsg), 100);
               if (ret < 0)
                 {
-                  twmerr("ERROR: mq_send failed: %d\n", ret);
+                  twmerr("ERROR: mq_send failed: %d\n", errno);
                   success = false;
                 }
             }
@@ -566,6 +566,7 @@ bool CMenus::createMenuWindow(void)
   struct SAppEvents events;
   events.eventObj    = (FAR void *)this;
   events.redrawEvent = EVENT_SYSTEM_NOP;
+  events.resizeEvent = EVENT_SYSTEM_NOP;
   events.mouseEvent  = EVENT_MENU_XYINPUT;
   events.kbdEvent    = EVENT_SYSTEM_NOP;
   events.closeEvent  = EVENT_SYSTEM_NOP;
@@ -849,7 +850,7 @@ void CMenus::handleActionEvent(const NXWidgets::CWidgetEventArgs &e)
                                 sizeof(struct SEventMsg), 100);
               if (ret < 0)
                 {
-                  twmerr("ERROR: mq_send failed: %d\n", ret);
+                  twmerr("ERROR: mq_send failed: %d\n", errno);
                 }
 
               return;
diff --git a/graphics/twm4nx/src/cnxterm.cxx b/graphics/twm4nx/src/cnxterm.cxx
index bb16277b0..b4aca9cef 100644
--- a/graphics/twm4nx/src/cnxterm.cxx
+++ b/graphics/twm4nx/src/cnxterm.cxx
@@ -201,6 +201,7 @@ bool CNxTerm::initialize(void)
   struct SAppEvents events;
   events.eventObj    = (FAR void *)this;
   events.redrawEvent = EVENT_NXTERM_REDRAW;
+  events.resizeEvent = EVENT_NXTERM_RESIZE;
   events.mouseEvent  = EVENT_NXTERM_XYINPUT;
   events.kbdEvent    = EVENT_NXTERM_KBDINPUT;
   events.closeEvent  = EVENT_NXTERM_CLOSE;
@@ -493,10 +494,14 @@ bool CNxTerm::event(FAR struct SEventMsg *eventmsg)
 
   switch (eventmsg->eventID)
     {
-      case EVENT_NXTERM_REDRAW:  // Redraw event (should not happen)
+      case EVENT_NXTERM_REDRAW:  // Redraw event
         redraw();                // Redraw the whole window
         break;
 
+      case EVENT_NXTERM_RESIZE:  // Resize event
+        resize();                // Size the NxTerm window
+        break;
+
       case EVENT_NXTERM_CLOSE:   // Window close event
         stop();                  // Stop the NxTerm thread
         break;
@@ -510,9 +515,9 @@ bool CNxTerm::event(FAR struct SEventMsg *eventmsg)
 }
 
 /**
- * Redraw the entire window.  The application has been maximized or
- * otherwise moved to the top of the hierarchy.  This method is call from
- * CTwm4Nx when the application window must be displayed
+ * Redraw the entire window.  The application has been maximized, resized or
+ * moved to the top of the hierarchy.  This method is call from CTwm4Nx when
+ * the application window must be displayed
  */
 
 void CNxTerm::redraw(void)
@@ -524,7 +529,8 @@ void CNxTerm::redraw(void)
 
   // Redraw the entire NxTerm window
 
-  struct boardioc_nxterm_redraw_s redraw;
+  struct boardioc_nxterm_ioctl_s iocargs;
+  struct nxtermioc_redraw_s redraw;
 
   redraw.handle     = m_NxTerm;
   redraw.rect.pt1.x = 0;
@@ -533,7 +539,32 @@ void CNxTerm::redraw(void)
   redraw.rect.pt2.y = windowSize.h - 1;
   redraw.more       = false;
 
-  (void)boardctl(BOARDIOC_NXTERM_KBDIN, (uintptr_t)&redraw);
+  iocargs.cmd       = NXTERMIOC_NXTERM_REDRAW;
+  iocargs.arg       = (uintptr_t)&redraw;
+
+  (void)boardctl(BOARDIOC_NXTERM_IOCTL, (uintptr_t)&iocargs);
+}
+
+/**
+ * inform NxTerm of a new window size.
+ */
+
+void CNxTerm::resize(void)
+{
+  struct nxtermioc_resize_s resize;
+
+  // Get the size of the window
+
+  resize.handle     = m_NxTerm;
+  (void)m_nxtermWindow->getWindowSize(&resize.size);
+
+  // Inform NxTerm of the new size
+
+  struct boardioc_nxterm_ioctl_s iocargs;
+  iocargs.cmd       = NXTERMIOC_NXTERM_RESIZE;
+  iocargs.arg       = (uintptr_t)&resize;
+
+  (void)boardctl(BOARDIOC_NXTERM_IOCTL, (uintptr_t)&iocargs);
 }
 
 /////////////////////////////////////////////////////////////////////////////
diff --git a/graphics/twm4nx/src/cresize.cxx b/graphics/twm4nx/src/cresize.cxx
index 1301f47ad..784b3785b 100644
--- a/graphics/twm4nx/src/cresize.cxx
+++ b/graphics/twm4nx/src/cresize.cxx
@@ -44,7 +44,8 @@
 // Included Files
 /////////////////////////////////////////////////////////////////////////////
 
-#include <stdio.h>
+#include <cstdio>
+#include <cerrno>
 
 #include <nuttx/nx/nxbe.h>
 
@@ -499,6 +500,12 @@ bool CResize::startResize(FAR struct SEventMsg *eventmsg)
 
   updateSizeLabel(m_lastSize);
 
+  // Disable all other toolbar buttons
+
+  m_resizeWindow->disableToolbarButtons(DISABLE_MENU_BUTTON |
+                                        DISABLE_DELETE_BUTTON |
+                                        DISABLE_MINIMIZE_BUTTON);
+
   // Unhide the size window
 
   m_sizeWindow->show();
@@ -762,6 +769,10 @@ bool CResize::endResize(FAR struct SEventMsg *eventmsg)
 
   m_resizeWindow->installEventTap(m_savedTap, m_savedTapArg);
 
+  // Re-enable toolbar buttons
+
+  m_resizeWindow->disableToolbarButtons(DISABLE_NO_BUTTONS);
+
   // The size window should no longer be modal
 
   m_sizeWindow->modal(false);
@@ -835,7 +846,7 @@ bool CResize::moveEvent(FAR const struct nxgl_point_s &pos,
                     sizeof(struct SEventMsg), 100);
   if (ret < 0)
    {
-     twmerr("ERROR: mq_send failed: %d\n", ret);
+     twmerr("ERROR: mq_send failed: %d\n", errno);
      return false;
    }
 
@@ -877,7 +888,7 @@ bool CResize::dropEvent(FAR const struct nxgl_point_s &pos,
                     sizeof(struct SEventMsg), 100);
   if (ret < 0)
    {
-     twmerr("ERROR: mq_send failed: %d\n", ret);
+     twmerr("ERROR: mq_send failed: %d\n", errno);
      return false;
    }
 
@@ -924,7 +935,7 @@ void CResize::enableMovement(FAR const struct nxgl_point_s &pos,
                         sizeof(struct SEventMsg), 100);
       if (ret < 0)
        {
-         twmerr("ERROR: mq_send failed: %d\n", ret);
+         twmerr("ERROR: mq_send failed: %d\n", errno);
        }
     }
 
diff --git a/graphics/twm4nx/src/cwindow.cxx b/graphics/twm4nx/src/cwindow.cxx
index b4c0067c7..b7d18e858 100644
--- a/graphics/twm4nx/src/cwindow.cxx
+++ b/graphics/twm4nx/src/cwindow.cxx
@@ -388,6 +388,7 @@ bool CWindow::configureEvents(FAR const struct SAppEvents &events)
 {
   m_appEvents.eventObj     = events.eventObj;    // Event object
   m_appEvents.redrawEvent  = events.redrawEvent; // Redraw event ID
+  m_appEvents.resizeEvent  = events.resizeEvent; // Resize event ID
   m_appEvents.mouseEvent   = events.mouseEvent;  // Mouse/touchscreen event ID
   m_appEvents.kbdEvent     = events.kbdEvent;    // Keyboard event ID
   m_appEvents.closeEvent   = events.closeEvent;  // Window event ID
@@ -483,7 +484,40 @@ bool CWindow::resizeFrame(FAR const struct nxgl_size_s *frameSize,
 
   // Then update the toolbar layout (if there is one)
 
-  return updateToolbarLayout();
+  success = updateToolbarLayout();
+  if (!success)
+    {
+      twmerr("ERROR: updateToolbarLayout() failed\n");
+      return false;
+    }
+
+  // Check if the application using this window is interested in resize
+  // events
+
+  if (m_appEvents.resizeEvent != EVENT_SYSTEM_NOP)
+    {
+      twminfo("Close event...\n");
+
+      // Send the application specific [pre-]close event
+
+      struct SEventMsg outmsg;
+      outmsg.eventID  = m_appEvents.resizeEvent;
+      outmsg.obj      = (FAR void *)this;
+      outmsg.pos.x    = 0;
+      outmsg.pos.y    = 0;
+      outmsg.context  = EVENT_CONTEXT_WINDOW;
+      outmsg.handler  = m_appEvents.eventObj;
+
+      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);
+          return false;
+        }
+   }
+
+  return true;
 }
 
 /**
@@ -708,7 +742,7 @@ bool CWindow::event(FAR struct SEventMsg *eventmsg)
                                   sizeof(struct SEventMsg), 100);
                 if (ret < 0)
                   {
-                    twmerr("ERROR: mq_send failed: %d\n", ret);
+                    twmerr("ERROR: mq_send failed: %d\n", errno);
                   }
              }
 
@@ -889,6 +923,7 @@ bool CWindow::createToolbar(void)
   struct SAppEvents events;
   events.eventObj    = (FAR void *)this;
   events.redrawEvent = EVENT_SYSTEM_NOP;
+  events.resizeEvent = EVENT_SYSTEM_NOP;
   events.mouseEvent  = EVENT_TOOLBAR_XYINPUT;
   events.kbdEvent    = EVENT_SYSTEM_NOP;
   events.closeEvent  = EVENT_SYSTEM_NOP;
@@ -1316,7 +1351,7 @@ void CWindow::handleUngrabEvent(nxgl_coord_t x, nxgl_coord_t y)
                     sizeof(struct SEventMsg), 100);
   if (ret < 0)
     {
-      twmerr("ERROR: mq_send failed: %d\n", ret);
+      twmerr("ERROR: mq_send failed: %d\n", errno);
     }
 }
 
@@ -1354,7 +1389,7 @@ void CWindow::handleClickEvent(const NXWidgets::CWidgetEventArgs &e)
                         sizeof(struct SEventMsg), 100);
       if (ret < 0)
         {
-          twmerr("ERROR: mq_send failed: %d\n", ret);
+          twmerr("ERROR: mq_send failed: %d\n", errno);
         }
     }
 }
@@ -1400,6 +1435,15 @@ void CWindow::handleActionEvent(const NXWidgets::CWidgetEventArgs &e)
 
   for (int btindex = 0; btindex < NTOOLBAR_BUTTONS; btindex++)
     {
+      // 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)
+        {
+          continue;
+        }
+
       // Check if the widget is clicked
 
       if (m_tbButtons[btindex] != (FAR NXWidgets::CImage *)0 &&
@@ -1426,7 +1470,7 @@ void CWindow::handleActionEvent(const NXWidgets::CWidgetEventArgs &e)
                             sizeof(struct SEventMsg), 100);
           if (ret < 0)
             {
-              twmerr("ERROR: mq_send failed: %d\n", ret);
+              twmerr("ERROR: mq_send failed: %d\n", errno);
             }
         }
     }
@@ -1482,7 +1526,7 @@ bool CWindow::moveEvent(FAR const struct nxgl_point_s &pos,
                         sizeof(struct SEventMsg), 100);
       if (ret < 0)
         {
-          twmerr("ERROR: mq_send failed: %d\n", ret);
+          twmerr("ERROR: mq_send failed: %d\n", errno);
         }
 
       return true;
@@ -1588,6 +1632,7 @@ bool CWindow::toolbarGrab(FAR struct SEventMsg *eventmsg)
   struct SAppEvents events;
   events.eventObj    = (FAR void *)this;
   events.redrawEvent = EVENT_SYSTEM_NOP;
+  events.resizeEvent = EVENT_SYSTEM_NOP;
   events.mouseEvent  = EVENT_TOOLBAR_XYINPUT;
   events.kbdEvent    = EVENT_SYSTEM_NOP;
   events.closeEvent  = m_appEvents.closeEvent;
diff --git a/graphics/twm4nx/src/cwindowevent.cxx b/graphics/twm4nx/src/cwindowevent.cxx
index 1bb16e84e..ae4157982 100644
--- a/graphics/twm4nx/src/cwindowevent.cxx
+++ b/graphics/twm4nx/src/cwindowevent.cxx
@@ -175,6 +175,8 @@ void CWindowEvent::handleRedrawEvent(FAR const nxgl_rect_s *nxRect,
     {
       struct SRedrawEventMsg msg;
       msg.eventID    = m_appEvents.redrawEvent;
+      msg.obj        = m_appEvents.eventObj;
+      msg.handler    = m_appEvents.eventObj;
       msg.rect.pt1.x = nxRect->pt1.x;
       msg.rect.pt1.y = nxRect->pt1.y;
       msg.rect.pt2.x = nxRect->pt2.x;
@@ -192,7 +194,7 @@ void CWindowEvent::handleRedrawEvent(FAR const nxgl_rect_s *nxRect,
                         sizeof(struct SRedrawEventMsg), 100);
       if (ret < 0)
         {
-          twmerr("ERROR: mq_send failed: %d\n", ret);
+          twmerr("ERROR: mq_send failed: %d\n", errno);
         }
     }
 }
@@ -302,6 +304,7 @@ void CWindowEvent::handleMouseEvent(FAR const struct nxgl_point_s *pos,
       struct SXyInputEventMsg msg;
       msg.eventID = m_appEvents.mouseEvent;
       msg.obj     = m_appEvents.eventObj;
+      msg.handler = m_appEvents.eventObj;
       msg.pos.x   = pos->x;
       msg.pos.y   = pos->y;
       msg.buttons = buttons;
@@ -310,7 +313,7 @@ void CWindowEvent::handleMouseEvent(FAR const struct nxgl_point_s *pos,
                         sizeof(struct SXyInputEventMsg), 100);
       if (ret < 0)
         {
-          twmerr("ERROR: mq_send failed: %d\n", ret);
+          twmerr("ERROR: mq_send failed: %d\n", errno);
         }
     }
 }
@@ -334,13 +337,14 @@ void CWindowEvent::handleKeyboardEvent(void)
       struct SNxEventMsg msg;
       msg.eventID  = m_appEvents.kbdEvent;
       msg.obj      = m_appEvents.eventObj;
+      msg.handler  = m_appEvents.eventObj;
       msg.instance = this;
 
       int ret = mq_send(m_eventq, (FAR const char *)&msg,
                         sizeof(struct SNxEventMsg), 100);
       if (ret < 0)
         {
-          twmerr("ERROR: mq_send failed: %d\n", ret);
+          twmerr("ERROR: mq_send failed: %d\n", errno);
         }
     }
 }
@@ -373,6 +377,6 @@ void CWindowEvent::handleBlockedEvent(FAR void *arg)
                     sizeof(struct SNxEventMsg), 100);
   if (ret < 0)
     {
-      twmerr("ERROR: mq_send failed: %d\n", ret);
+      twmerr("ERROR: mq_send failed: %d\n", errno);
     }
 }
diff --git a/include/graphics/twm4nx/cnxterm.hxx b/include/graphics/twm4nx/cnxterm.hxx
index cc1ca4139..8c4a03597 100644
--- a/include/graphics/twm4nx/cnxterm.hxx
+++ b/include/graphics/twm4nx/cnxterm.hxx
@@ -60,16 +60,17 @@
 // Window Events
 
 #define EVENT_NXTERM_REDRAW   (EVENT_RECIPIENT_APP | 0x0000)
+#define EVENT_NXTERM_RESIZE   (EVENT_RECIPIENT_APP | 0x0001)
 #define EVENT_NXTERM_XYINPUT   EVENT_SYSTEM_NOP
 #define EVENT_NXTERM_KBDINPUT  EVENT_SYSTEM_NOP
 
 // Button Events
 
-#define EVENT_NXTERM_CLOSE    (EVENT_RECIPIENT_APP | 0x0001)
+#define EVENT_NXTERM_CLOSE    (EVENT_RECIPIENT_APP | 0x0002)
 
 // Menu Events
 
-#define EVENT_NXTERM_START    (EVENT_RECIPIENT_APP | 0x0002)
+#define EVENT_NXTERM_START    (EVENT_RECIPIENT_APP | 0x0003)
 
 /////////////////////////////////////////////////////////////////////////////
 // Implementation Classes
@@ -113,6 +114,12 @@ namespace Twm4Nx
 
       void redraw(void);
 
+      /**
+       * inform NxTerm of a new window size.
+       */
+
+      void resize(void);
+
       /**
        * This is the close window event handler.  It will stop the NxTerm
        * application trhead.
diff --git a/include/graphics/twm4nx/cwindow.hxx b/include/graphics/twm4nx/cwindow.hxx
index 734cdd5aa..7ef933124 100644
--- a/include/graphics/twm4nx/cwindow.hxx
+++ b/include/graphics/twm4nx/cwindow.hxx
@@ -110,6 +110,15 @@
 #define WFLAGS_IS_MENU(f)              (((f) & WFLAGS_MENU) != 0)
 #define WFLAGS_IS_HIDDEN(f)            (((f) & WFLAGS_HIDDEN) != 0)
 
+// Buttons can be disabled temporarily while in certain absorbing states
+// (such as resizing the window).
+
+#define DISABLE_NO_BUTTONS        (0)
+#define DISABLE_MENU_BUTTON       (1 << MENU_BUTTON)
+#define DISABLE_DELETE_BUTTON     (1 << DELETE_BUTTON)
+#define DISABLE_RESIZE_BUTTON     (1 << RESIZE_BUTTON)
+#define DISABLE_MINIMIZE_BUTTON   (1 << MINIMIZE_BUTTON)
+
 /////////////////////////////////////////////////////////////////////////////
 // Implementation Classes
 /////////////////////////////////////////////////////////////////////////////
@@ -167,6 +176,7 @@ namespace Twm4Nx
       nxgl_coord_t                m_tbLeftX;     /**< Rightmost position of left buttons */
       nxgl_coord_t                m_tbRightX;    /**< Leftmost position of right buttons */
       uint8_t                     m_tbFlags;     /**< Toolbar button customizations */
+      uint8_t                     m_tbDisables;  /**< Toolbar button disables */
 
       // List of all toolbar button images
 
@@ -849,6 +859,20 @@ namespace Twm4Nx
           }
       }
 
+      /**
+       * Enable/disable toolbar buttons.  Buttons may need to be disabled
+       * temporarily while in certain absorbing states (such as resizing the
+       * window).
+       *
+       * @param disables The set of buttons to enable or disble See
+       *   DISABLE_* definitions.
+       */
+
+      inline void disableToolbarButtons(uint8_t disables)
+      {
+        m_tbDisables = disables;
+      }
+
       /**
        * Check for widget-related toolbar events, typically button presses.
        * This is called by event handling logic for events that require
diff --git a/include/graphics/twm4nx/cwindowevent.hxx b/include/graphics/twm4nx/cwindowevent.hxx
index f2176899d..347157e8b 100644
--- a/include/graphics/twm4nx/cwindowevent.hxx
+++ b/include/graphics/twm4nx/cwindowevent.hxx
@@ -68,6 +68,7 @@ namespace Twm4Nx
     FAR void     *eventObj;     /**< Object reference that accompanies events */
     nxgl_coord_t  minWidth;     /**< The minimum width of the window */
     uint16_t      redrawEvent;  /**< Redraw event ID */
+    uint16_t      resizeEvent;  /**< Resize event ID */
     uint16_t      mouseEvent;   /**< Mouse/touchscreen event ID */
     uint16_t      kbdEvent;     /**< Keyboard event ID */
     uint16_t      closeEvent;   /**< Window close event ID */
@@ -283,6 +284,7 @@ namespace Twm4Nx
       {
         m_appEvents.eventObj    = events.eventObj;    // Event object reference
         m_appEvents.redrawEvent = events.redrawEvent; // Redraw event ID
+        m_appEvents.resizeEvent = events.resizeEvent; // Resize event ID
         m_appEvents.mouseEvent  = events.mouseEvent;  // Mouse/touchscreen event ID
         m_appEvents.kbdEvent    = events.kbdEvent;    // Keyboard event ID
         m_appEvents.closeEvent  = events.closeEvent;  // Window close event ID
diff --git a/include/graphics/twm4nx/nxterm_config.hxx b/include/graphics/twm4nx/nxterm_config.hxx
index 4a33c08a2..3c762705f 100644
--- a/include/graphics/twm4nx/nxterm_config.hxx
+++ b/include/graphics/twm4nx/nxterm_config.hxx
@@ -66,15 +66,15 @@
  */
 
 #ifndef CONFIG_HAVE_CXX
-#  error "C++ support is required (CONFIG_HAVE_CXX)"
+#  error C++ support is required (CONFIG_HAVE_CXX)
 #endif
 
 #ifndef CONFIG_NX
-#  error "NX support is required (CONFIG_NX)"
+#  error NX support is required (CONFIG_NX)
 #endif
 
 #ifndef CONFIG_NXTERM
-#  warning "NxTerm support is required (CONFIG_NXTERM)"
+#  warning NxTerm support is required (CONFIG_NXTERM)
 #endif
 
 // Keyboard input can come from either /dev/console or via Twm4Nx.  If
@@ -84,9 +84,9 @@
 // /dev/console for keyboard input.
 
 #if !defined(CONFIG_TWM4NX_NOKEYBOARD) && !defined(CONFIG_NXTERM_NXKBDIN)
-#  warning "Nxterm needs CONFIG_NXTERM_NXKBDIN for keyboard input"
+#  warning Nxterm needs CONFIG_NXTERM_NXKBDIN for keyboard input
 #elif defined(CONFIG_TWM4NX_NOKEYBOARD) && defined(CONFIG_NXTERM_NXKBDIN)
-#  warning "Nxterm has no keyboard input.  Undefine CONFIG_NXTERM_NXKBDIN
+#  warning Nxterm has no keyboard input.  Undefine CONFIG_NXTERM_NXKBDIN
 #endif
 
 // NxTerm Window /////////////////////////////////////////////////////////////
diff --git a/include/graphics/twm4nx/twm4nx_events.hxx b/include/graphics/twm4nx/twm4nx_events.hxx
index 111932033..c6c329a1a 100644
--- a/include/graphics/twm4nx/twm4nx_events.hxx
+++ b/include/graphics/twm4nx/twm4nx_events.hxx
@@ -52,7 +52,9 @@
 // Preprocessor Definitions
 /////////////////////////////////////////////////////////////////////////////
 
-#define MAX_EVENT_MSGSIZE sizeof(struct SEventMsg)
+// 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))
 
 /////////////////////////////////////////////////////////////////////////////
@@ -197,12 +199,16 @@ namespace Twm4Nx
 
   struct SEventMsg
   {
+    // Common fields
+
     uint16_t eventID;                   /**< Encoded event ID */
     FAR void *obj;                      /**< Context specific reference */
+    FAR void *handler;                  /**< Context specific handler */
+
+    // Event-specific fields
 
     struct nxgl_point_s pos;            /**< X/Y position */
     uint8_t context;                    /**< Button press context */
-    FAR void *handler;                  /**< Context specific handler */
   };
 
   /**
@@ -211,8 +217,13 @@ namespace Twm4Nx
 
   struct SRedrawEventMsg
   {
+    // Common fields
+
     uint16_t eventID;                   /**< Encoded event ID */
     FAR void *obj;                      /**< Context specific reference */
+    FAR void *handler;                  /**< Context specific handler */
+
+    // Event-specific fields
 
     struct nxgl_rect_s rect;            /**< Region to be redrawn */
     bool more;                          /**< True: More redraw requests will follow */
@@ -225,8 +236,13 @@ namespace Twm4Nx
 
   struct SXyInputEventMsg
   {
+    // Common fields
+
     uint16_t eventID;                   /**< Encoded event ID */
     FAR void *obj;                      /**< Context specific reference */
+    FAR void *handler;                  /**< Context specific handler */
+
+    // Event-specific fields
 
     struct nxgl_point_s pos;            /**< X/Y position */
     uint8_t buttons;                    /**< Bit set of button presses */
@@ -239,8 +255,13 @@ namespace Twm4Nx
 
   struct SNxEventMsg
   {
+    // Common fields
+
     uint16_t eventID;                   /**< Encoded event ID */
     FAR void *obj;                      /**< Context specific reference */
+    FAR void *handler;                  /**< Context specific handler */
+
+    // Event-specific fields
 
     FAR CWindowEvent *instance;         /**< X/Y position */
   };