https://git.reactos.org/?p=reactos.git;a=commitdiff;h=e8c7e300300e9bbc76b37b30dff392df12ef5222

commit e8c7e300300e9bbc76b37b30dff392df12ef5222
Author:     Katayama Hirofumi MZ <[email protected]>
AuthorDate: Sat Jun 17 21:15:35 2023 +0900
Commit:     GitHub <[email protected]>
CommitDate: Sat Jun 17 21:15:35 2023 +0900

    [MSPAINT] Establish Undo/Redo management (#5347)
    
    - Painting the canvas is done by overlaying the multiple layers.
    - Drawing each overlay is implemented as polymorphism of OOP.
    - Refine the Undo/Redo mechanism.
    - Some adjustments.
    CORE-17969
---
 base/applications/mspaint/canvas.cpp         | 134 ++++----
 base/applications/mspaint/canvas.h           |   4 +-
 base/applications/mspaint/common.h           |   1 -
 base/applications/mspaint/dialogs.cpp        |  20 +-
 base/applications/mspaint/dib.cpp            |  38 +--
 base/applications/mspaint/drawing.cpp        |   2 +-
 base/applications/mspaint/fullscreen.cpp     |   4 +-
 base/applications/mspaint/globalvar.h        |  22 +-
 base/applications/mspaint/history.cpp        | 135 ++++----
 base/applications/mspaint/history.h          |  17 +-
 base/applications/mspaint/main.cpp           |  28 +-
 base/applications/mspaint/miniature.cpp      |   2 +-
 base/applications/mspaint/mouse.cpp          | 468 ++++++++++++++++++---------
 base/applications/mspaint/palette.cpp        |   8 +-
 base/applications/mspaint/palette.h          |   2 -
 base/applications/mspaint/palettemodel.cpp   |   2 +-
 base/applications/mspaint/selectionmodel.cpp | 119 ++++---
 base/applications/mspaint/selectionmodel.h   |  12 +-
 base/applications/mspaint/textedit.cpp       |   4 +-
 base/applications/mspaint/toolbox.cpp        |  29 +-
 base/applications/mspaint/toolbox.h          |   5 +
 base/applications/mspaint/toolsettings.cpp   |  11 +-
 base/applications/mspaint/toolsmodel.cpp     |  15 +-
 base/applications/mspaint/toolsmodel.h       |  31 +-
 base/applications/mspaint/winproc.cpp        | 108 ++++---
 25 files changed, 719 insertions(+), 502 deletions(-)

diff --git a/base/applications/mspaint/canvas.cpp 
b/base/applications/mspaint/canvas.cpp
index c36bd76faed..68a91b5d250 100644
--- a/base/applications/mspaint/canvas.cpp
+++ b/base/applications/mspaint/canvas.cpp
@@ -17,15 +17,17 @@ CCanvasWindow::CCanvasWindow()
     , m_hitSelection(HIT_NONE)
     , m_whereHit(HIT_NONE)
     , m_ptOrig { -1, -1 }
-    , m_hbmCached(NULL)
 {
+    m_ahbmCached[0] = m_ahbmCached[1] = NULL;
     ::SetRectEmpty(&m_rcNew);
 }
 
 CCanvasWindow::~CCanvasWindow()
 {
-    if (m_hbmCached)
-        ::DeleteObject(m_hbmCached);
+    if (m_ahbmCached[0])
+        ::DeleteObject(m_ahbmCached[0]);
+    if (m_ahbmCached[1])
+        ::DeleteObject(m_ahbmCached[1]);
 }
 
 VOID CCanvasWindow::drawZoomFrame(INT mouseX, INT mouseY)
@@ -101,78 +103,80 @@ CANVAS_HITTEST CCanvasWindow::CanvasHitTest(POINT pt)
 VOID CCanvasWindow::DoDraw(HDC hDC, RECT& rcClient, RECT& rcPaint)
 {
     // We use a memory bitmap to reduce flickering
-    HDC hdcMem = ::CreateCompatibleDC(hDC);
-    m_hbmCached = CachedBufferDIB(m_hbmCached, rcClient.right, 
rcClient.bottom);
-    HGDIOBJ hbmOld = ::SelectObject(hdcMem, m_hbmCached);
+    HDC hdcMem0 = ::CreateCompatibleDC(hDC);
+    m_ahbmCached[0] = CachedBufferDIB(m_ahbmCached[0], rcClient.right, 
rcClient.bottom);
+    HGDIOBJ hbm0Old = ::SelectObject(hdcMem0, m_ahbmCached[0]);
 
-    // Fill the background
-    ::FillRect(hdcMem, &rcPaint, (HBRUSH)(COLOR_APPWORKSPACE + 1));
+    // Fill the background on hdcMem0
+    ::FillRect(hdcMem0, &rcPaint, (HBRUSH)(COLOR_APPWORKSPACE + 1));
 
     // Draw the sizeboxes if necessary
     RECT rcBase = GetBaseRect();
     if (!selectionModel.m_bShow)
-        drawSizeBoxes(hdcMem, &rcBase, FALSE, &rcPaint);
+        drawSizeBoxes(hdcMem0, &rcBase, FALSE, &rcPaint);
 
-    // Draw the image
+    // Calculate image size
     CRect rcImage;
     GetImageRect(rcImage);
-    ImageToCanvas(rcImage);
     SIZE sizeImage = { imageModel.GetWidth(), imageModel.GetHeight() };
-    StretchBlt(hdcMem, rcImage.left, rcImage.top, rcImage.Width(), 
rcImage.Height(),
-               imageModel.GetDC(), 0, 0, sizeImage.cx, sizeImage.cy, SRCCOPY);
 
-    // Draw the grid
-    if (showGrid && toolsModel.GetZoom() >= 4000)
+    // hdcMem1 <-- imageModel
+    HDC hdcMem1 = ::CreateCompatibleDC(hDC);
+    m_ahbmCached[1] = CachedBufferDIB(m_ahbmCached[1], sizeImage.cx, 
sizeImage.cy);
+    HGDIOBJ hbm1Old = ::SelectObject(hdcMem1, m_ahbmCached[1]);
+    BitBlt(hdcMem1, 0, 0, sizeImage.cx, sizeImage.cy, imageModel.GetDC(), 0, 
0, SRCCOPY);
+
+    // Draw overlay #1 on hdcMem1
+    toolsModel.OnDrawOverlayOnImage(hdcMem1);
+
+    // Transfer the bits with stretch (hdcMem0 <-- hdcMem1)
+    ImageToCanvas(rcImage);
+    ::StretchBlt(hdcMem0, rcImage.left, rcImage.top, rcImage.Width(), 
rcImage.Height(),
+                 hdcMem1, 0, 0, sizeImage.cx, sizeImage.cy, SRCCOPY);
+
+    // Clean up hdcMem1
+    ::SelectObject(hdcMem1, hbm1Old);
+    ::DeleteDC(hdcMem1);
+
+    // Draw the grid on hdcMem0
+    if (g_showGrid && toolsModel.GetZoom() >= 4000)
     {
-        HPEN oldPen = (HPEN) SelectObject(hdcMem, CreatePen(PS_SOLID, 1, 
RGB(160, 160, 160)));
+        HPEN oldPen = (HPEN) ::SelectObject(hdcMem0, ::CreatePen(PS_SOLID, 1, 
RGB(160, 160, 160)));
         for (INT counter = 0; counter < sizeImage.cy; counter++)
         {
             POINT pt0 = { 0, counter }, pt1 = { sizeImage.cx, counter };
             ImageToCanvas(pt0);
             ImageToCanvas(pt1);
-            ::MoveToEx(hdcMem, pt0.x, pt0.y, NULL);
-            ::LineTo(hdcMem, pt1.x, pt1.y);
+            ::MoveToEx(hdcMem0, pt0.x, pt0.y, NULL);
+            ::LineTo(hdcMem0, pt1.x, pt1.y);
         }
         for (INT counter = 0; counter < sizeImage.cx; counter++)
         {
             POINT pt0 = { counter, 0 }, pt1 = { counter, sizeImage.cy };
             ImageToCanvas(pt0);
             ImageToCanvas(pt1);
-            ::MoveToEx(hdcMem, pt0.x, pt0.y, NULL);
-            ::LineTo(hdcMem, pt1.x, pt1.y);
+            ::MoveToEx(hdcMem0, pt0.x, pt0.y, NULL);
+            ::LineTo(hdcMem0, pt1.x, pt1.y);
         }
-        ::DeleteObject(::SelectObject(hdcMem, oldPen));
+        ::DeleteObject(::SelectObject(hdcMem0, oldPen));
     }
 
-    // Draw selection
-    if (selectionModel.m_bShow)
-    {
-        RECT rcSelection = selectionModel.m_rc;
-        ImageToCanvas(rcSelection);
-
-        ::InflateRect(&rcSelection, GRIP_SIZE, GRIP_SIZE);
-        drawSizeBoxes(hdcMem, &rcSelection, TRUE, &rcPaint);
-        ::InflateRect(&rcSelection, -GRIP_SIZE, -GRIP_SIZE);
-
-        INT iSaveDC = ::SaveDC(hdcMem);
-        ::IntersectClipRect(hdcMem, rcImage.left, rcImage.top, rcImage.right, 
rcImage.bottom);
-        selectionModel.DrawSelection(hdcMem, &rcSelection, 
paletteModel.GetBgColor(),
-                                     toolsModel.IsBackgroundTransparent());
-        ::RestoreDC(hdcMem, iSaveDC);
-    }
+    // Draw overlay #2 on hdcMem0
+    toolsModel.OnDrawOverlayOnCanvas(hdcMem0);
 
-    // Draw new frame if any
+    // Draw new frame on hdcMem0 if any
     if (m_whereHit != HIT_NONE && !::IsRectEmpty(&m_rcNew))
-        DrawXorRect(hdcMem, &m_rcNew);
+        DrawXorRect(hdcMem0, &m_rcNew);
 
-    // Transfer the bits
+    // Transfer the bits (hDC <-- hdcMem0)
     ::BitBlt(hDC,
              rcPaint.left, rcPaint.top,
              rcPaint.right - rcPaint.left, rcPaint.bottom - rcPaint.top,
-             hdcMem, rcPaint.left, rcPaint.top, SRCCOPY);
+             hdcMem0, rcPaint.left, rcPaint.top, SRCCOPY);
 
-    ::SelectObject(hdcMem, hbmOld);
-    ::DeleteDC(hdcMem);
+    // Clean up hdcMem0
+    ::SelectObject(hdcMem0, hbm0Old);
+    ::DeleteDC(hdcMem0);
 }
 
 VOID CCanvasWindow::Update(HWND hwndFrom)
@@ -383,15 +387,15 @@ LRESULT CCanvasWindow::OnMouseMove(UINT nMsg, WPARAM 
wParam, LPARAM lParam, BOOL
         {
             CString strCoord;
             strCoord.Format(_T("%ld, %ld"), pt.x, pt.y);
-            SendMessage(hStatusBar, SB_SETTEXT, 1, (LPARAM) (LPCTSTR) 
strCoord);
+            ::SendMessage(g_hStatusBar, SB_SETTEXT, 1, (LPARAM) (LPCTSTR) 
strCoord);
         }
     }
 
     if (m_drawing)
     {
         // values displayed in statusbar
-        LONG xRel = pt.x - start.x;
-        LONG yRel = pt.y - start.y;
+        LONG xRel = pt.x - g_ptStart.x;
+        LONG yRel = pt.y - g_ptStart.y;
 
         switch (toolsModel.GetActiveTool())
         {
@@ -400,13 +404,13 @@ LRESULT CCanvasWindow::OnMouseMove(UINT nMsg, WPARAM 
wParam, LPARAM lParam, BOOL
             case TOOL_RECTSEL:
             case TOOL_TEXT:
                 if (xRel < 0)
-                    xRel = (pt.x < 0) ? -start.x : xRel;
+                    xRel = (pt.x < 0) ? -g_ptStart.x : xRel;
                 else if (pt.x > imageModel.GetWidth())
-                    xRel = imageModel.GetWidth() - start.x;
+                    xRel = imageModel.GetWidth() - g_ptStart.x;
                 if (yRel < 0)
-                    yRel = (pt.y < 0) ? -start.y : yRel;
+                    yRel = (pt.y < 0) ? -g_ptStart.y : yRel;
                 else if (pt.y > imageModel.GetHeight())
-                    yRel = imageModel.GetHeight() - start.y;
+                    yRel = imageModel.GetHeight() - g_ptStart.y;
                 break;
 
             // while drawing, update cursor coordinates only for tools 3, 7, 
8, 9, 14
@@ -418,7 +422,7 @@ LRESULT CCanvasWindow::OnMouseMove(UINT nMsg, WPARAM 
wParam, LPARAM lParam, BOOL
             {
                 CString strCoord;
                 strCoord.Format(_T("%ld, %ld"), pt.x, pt.y);
-                SendMessage(hStatusBar, SB_SETTEXT, 1, (LPARAM) (LPCTSTR) 
strCoord);
+                ::SendMessage(g_hStatusBar, SB_SETTEXT, 1, (LPARAM) (LPCTSTR) 
strCoord);
                 break;
             }
             default:
@@ -444,7 +448,7 @@ LRESULT CCanvasWindow::OnMouseMove(UINT nMsg, WPARAM 
wParam, LPARAM lParam, BOOL
                 if ((toolsModel.GetActiveTool() >= TOOL_LINE) && 
(GetAsyncKeyState(VK_SHIFT) < 0))
                     yRel = xRel;
                 strSize.Format(_T("%ld x %ld"), xRel, yRel);
-                SendMessage(hStatusBar, SB_SETTEXT, 2, (LPARAM) (LPCTSTR) 
strSize);
+                ::SendMessage(g_hStatusBar, SB_SETTEXT, 2, (LPARAM) (LPCTSTR) 
strSize);
             }
         }
 
@@ -458,7 +462,7 @@ LRESULT CCanvasWindow::OnMouseMove(UINT nMsg, WPARAM 
wParam, LPARAM lParam, BOOL
                 if ((toolsModel.GetActiveTool() >= TOOL_LINE) && 
(GetAsyncKeyState(VK_SHIFT) < 0))
                     yRel = xRel;
                 strSize.Format(_T("%ld x %ld"), xRel, yRel);
-                SendMessage(hStatusBar, SB_SETTEXT, 2, (LPARAM) (LPCTSTR) 
strSize);
+                ::SendMessage(g_hStatusBar, SB_SETTEXT, 2, (LPARAM) (LPCTSTR) 
strSize);
             }
         }
         return 0;
@@ -514,7 +518,7 @@ LRESULT CCanvasWindow::OnMouseMove(UINT nMsg, WPARAM 
wParam, LPARAM lParam, BOOL
     // Display new size
     CString strSize;
     strSize.Format(_T("%d x %d"), cxImage, cyImage);
-    SendMessage(hStatusBar, SB_SETTEXT, 2, (LPARAM) (LPCTSTR) strSize);
+    ::SendMessage(g_hStatusBar, SB_SETTEXT, 2, (LPARAM) (LPCTSTR) strSize);
 
     CRect rc = { 0, 0, cxImage, cyImage };
     switch (m_whereHit)
@@ -556,7 +560,7 @@ LRESULT CCanvasWindow::OnLRButtonUp(BOOL bLeftButton, UINT 
nMsg, WPARAM wParam,
         m_drawing = FALSE;
         toolsModel.OnButtonUp(bLeftButton, pt.x, pt.y);
         Invalidate(FALSE);
-        SendMessage(hStatusBar, SB_SETTEXT, 2, (LPARAM) "");
+        ::SendMessage(g_hStatusBar, SB_SETTEXT, 2, (LPARAM)_T(""));
         return 0;
     }
     else if (m_hitSelection != HIT_NONE && bLeftButton)
@@ -603,7 +607,7 @@ LRESULT CCanvasWindow::OnLRButtonUp(BOOL bLeftButton, UINT 
nMsg, WPARAM wParam,
     }
     ::SetRectEmpty(&m_rcNew);
 
-    imageSaved = FALSE;
+    g_imageSaved = FALSE;
 
     m_whereHit = HIT_NONE;
     toolsModel.resetTool(); // resets the point-buffer of the polygon and 
bezier functions
@@ -654,19 +658,19 @@ LRESULT CCanvasWindow::OnSetCursor(UINT nMsg, WPARAM 
wParam, LPARAM lParam, BOOL
         switch (toolsModel.GetActiveTool())
         {
             case TOOL_FILL:
-                ::SetCursor(::LoadIcon(hProgInstance, 
MAKEINTRESOURCE(IDC_FILL)));
+                ::SetCursor(::LoadIcon(g_hinstExe, MAKEINTRESOURCE(IDC_FILL)));
                 break;
             case TOOL_COLOR:
-                ::SetCursor(::LoadIcon(hProgInstance, 
MAKEINTRESOURCE(IDC_COLOR)));
+                ::SetCursor(::LoadIcon(g_hinstExe, 
MAKEINTRESOURCE(IDC_COLOR)));
                 break;
             case TOOL_ZOOM:
-                ::SetCursor(::LoadIcon(hProgInstance, 
MAKEINTRESOURCE(IDC_ZOOM)));
+                ::SetCursor(::LoadIcon(g_hinstExe, MAKEINTRESOURCE(IDC_ZOOM)));
                 break;
             case TOOL_PEN:
-                ::SetCursor(::LoadIcon(hProgInstance, 
MAKEINTRESOURCE(IDC_PEN)));
+                ::SetCursor(::LoadIcon(g_hinstExe, MAKEINTRESOURCE(IDC_PEN)));
                 break;
             case TOOL_AIRBRUSH:
-                ::SetCursor(::LoadIcon(hProgInstance, 
MAKEINTRESOURCE(IDC_AIRBRUSH)));
+                ::SetCursor(::LoadIcon(g_hinstExe, 
MAKEINTRESOURCE(IDC_AIRBRUSH)));
                 break;
             default:
                 ::SetCursor(::LoadCursor(NULL, IDC_CROSS));
@@ -710,7 +714,7 @@ LRESULT CCanvasWindow::OnMouseWheel(UINT nMsg, WPARAM 
wParam, LPARAM lParam, BOO
 
 LRESULT CCanvasWindow::OnCaptureChanged(UINT nMsg, WPARAM wParam, LPARAM 
lParam, BOOL& bHandled)
 {
-    SendMessage(hStatusBar, SB_SETTEXT, 2, (LPARAM)_T(""));
+    ::SendMessage(g_hStatusBar, SB_SETTEXT, 2, (LPARAM)_T(""));
     return 0;
 }
 
@@ -800,3 +804,9 @@ LRESULT CCanvasWindow::OnCtlColorEdit(UINT nMsg, WPARAM 
wParam, LPARAM lParam, B
     SetBkMode((HDC)wParam, TRANSPARENT);
     return (LRESULT)GetStockObject(NULL_BRUSH);
 }
+
+LRESULT CCanvasWindow::OnPaletteModelColorChanged(UINT nMsg, WPARAM wParam, 
LPARAM lParam, BOOL& bHandled)
+{
+    imageModel.NotifyImageChanged();
+    return 0;
+}
diff --git a/base/applications/mspaint/canvas.h 
b/base/applications/mspaint/canvas.h
index d76b3761b9c..40c07689acd 100644
--- a/base/applications/mspaint/canvas.h
+++ b/base/applications/mspaint/canvas.h
@@ -33,6 +33,7 @@ public:
         MESSAGE_HANDLER(WM_CANCELMODE, OnCancelMode)
         MESSAGE_HANDLER(WM_CAPTURECHANGED, OnCaptureChanged)
         MESSAGE_HANDLER(WM_CTLCOLOREDIT, OnCtlColorEdit)
+        MESSAGE_HANDLER(WM_PALETTEMODELCOLORCHANGED, 
OnPaletteModelColorChanged)
     END_MSG_MAP()
 
     CCanvasWindow();
@@ -55,7 +56,7 @@ protected:
     CANVAS_HITTEST m_hitSelection;
     CANVAS_HITTEST m_whereHit;
     POINT m_ptOrig; // The origin of drag start
-    HBITMAP m_hbmCached; // The cached buffer bitmap
+    HBITMAP m_ahbmCached[2]; // The cached buffer bitmaps
     CRect m_rcNew;
 
     CANVAS_HITTEST CanvasHitTest(POINT pt);
@@ -87,6 +88,7 @@ protected:
     LRESULT OnCancelMode(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& 
bHandled);
     LRESULT OnCaptureChanged(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& 
bHandled);
     LRESULT OnCtlColorEdit(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& 
bHandled);
+    LRESULT OnPaletteModelColorChanged(UINT nMsg, WPARAM wParam, LPARAM 
lParam, BOOL& bHandled);
 
     LRESULT OnLRButtonDown(BOOL bLeftButton, UINT nMsg, WPARAM wParam, LPARAM 
lParam, BOOL& bHandled);
     LRESULT OnLRButtonDblClk(BOOL bLeftButton, UINT nMsg, WPARAM wParam, 
LPARAM lParam, BOOL& bHandled);
diff --git a/base/applications/mspaint/common.h 
b/base/applications/mspaint/common.h
index 4aefbb2dcff..0c99517c599 100644
--- a/base/applications/mspaint/common.h
+++ b/base/applications/mspaint/common.h
@@ -20,7 +20,6 @@
 #define WM_TOOLSMODELSETTINGSCHANGED     (WM_APP + 1)
 #define WM_TOOLSMODELZOOMCHANGED         (WM_APP + 2)
 #define WM_PALETTEMODELCOLORCHANGED      (WM_APP + 3)
-#define WM_PALETTEMODELPALETTECHANGED    (WM_APP + 4)
 
 /* this simplifies checking and unchecking menu items */
 #define CHECKED_IF(a) ((a) ? (MF_CHECKED | MF_BYCOMMAND) : (MF_UNCHECKED | 
MF_BYCOMMAND))
diff --git a/base/applications/mspaint/dialogs.cpp 
b/base/applications/mspaint/dialogs.cpp
index 7b85b59365e..b08e33974c7 100644
--- a/base/applications/mspaint/dialogs.cpp
+++ b/base/applications/mspaint/dialogs.cpp
@@ -83,16 +83,16 @@ LRESULT CAttributesDialog::OnInitDialog(UINT nMsg, WPARAM 
wParam, LPARAM lParam,
     SetDlgItemInt(IDD_ATTRIBUTESEDIT1, newWidth, FALSE);
     SetDlgItemInt(IDD_ATTRIBUTESEDIT2, newHeight, FALSE);
 
-    if (isAFile)
+    if (g_isAFile)
     {
         TCHAR date[100];
         TCHAR temp[100];
-        GetDateFormat(LOCALE_USER_DEFAULT, 0, &fileTime, NULL, date, 
_countof(date));
-        GetTimeFormat(LOCALE_USER_DEFAULT, 0, &fileTime, NULL, temp, 
_countof(temp));
+        GetDateFormat(LOCALE_USER_DEFAULT, 0, &g_fileTime, NULL, date, 
_countof(date));
+        GetTimeFormat(LOCALE_USER_DEFAULT, 0, &g_fileTime, NULL, temp, 
_countof(temp));
         _tcscat(date, _T(" "));
         _tcscat(date, temp);
         CString strSize;
-        strSize.Format(IDS_FILESIZE, fileSize);
+        strSize.Format(IDS_FILESIZE, g_fileSize);
         SetDlgItemText(IDD_ATTRIBUTESTEXT6, date);
         SetDlgItemText(IDD_ATTRIBUTESTEXT7, strSize);
     }
@@ -240,9 +240,9 @@ LRESULT CStretchSkewDialog::OnOk(WORD wNotifyCode, WORD 
wID, HWND hWndCtl, BOOL&
     CString strrcAngle;
     BOOL tr1, tr2, tr3, tr4;
 
-    strrcIntNumbers.LoadString(hProgInstance, IDS_INTNUMBERS);
-    strrcPercentage.LoadString(hProgInstance, IDS_PERCENTAGE);
-    strrcAngle.LoadString(hProgInstance, IDS_ANGLE);
+    strrcIntNumbers.LoadString(g_hinstExe, IDS_INTNUMBERS);
+    strrcPercentage.LoadString(g_hinstExe, IDS_PERCENTAGE);
+    strrcAngle.LoadString(g_hinstExe, IDS_ANGLE);
 
     percentage.x = GetDlgItemInt(IDD_STRETCHSKEWEDITHSTRETCH, &tr1, FALSE);
     percentage.y = GetDlgItemInt(IDD_STRETCHSKEWEDITVSTRETCH, &tr2, FALSE);
@@ -347,11 +347,11 @@ void CFontsDialog::InitToolbar()
     SendMessage(hwndToolbar, TB_SETBUTTONWIDTH, 0, MAKELPARAM(20, 20));
     
     TBADDBITMAP AddBitmap;
-    AddBitmap.hInst = hProgInstance;
+    AddBitmap.hInst = g_hinstExe;
     AddBitmap.nID = IDB_FONTSTOOLBAR;
     SendMessage(hwndToolbar, TB_ADDBITMAP, 4, (LPARAM)&AddBitmap);
 
-    HIMAGELIST himl = ImageList_LoadImage(hProgInstance, 
MAKEINTRESOURCE(IDB_FONTSTOOLBAR),
+    HIMAGELIST himl = ImageList_LoadImage(g_hinstExe, 
MAKEINTRESOURCE(IDB_FONTSTOOLBAR),
                                           16, 8, RGB(255, 0, 255), 
IMAGE_BITMAP,
                                           LR_CREATEDIBSECTION);
     SendMessage(hwndToolbar, TB_SETIMAGELIST, 0, (LPARAM)himl);
@@ -511,7 +511,7 @@ LRESULT CFontsDialog::OnNotify(UINT nMsg, WPARAM wParam, 
LPARAM lParam, BOOL& bH
     if (pnmhdr->code == TTN_NEEDTEXT)
     {
         LPTOOLTIPTEXT pToolTip = reinterpret_cast<LPTOOLTIPTEXT>(lParam);
-        pToolTip->hinst = hProgInstance;
+        pToolTip->hinst = g_hinstExe;
         switch (pnmhdr->idFrom)
         {
             case IDM_BOLD:      pToolTip->lpszText = 
MAKEINTRESOURCE(IDS_BOLD); break;
diff --git a/base/applications/mspaint/dib.cpp 
b/base/applications/mspaint/dib.cpp
index 1e7477c661e..85472994639 100644
--- a/base/applications/mspaint/dib.cpp
+++ b/base/applications/mspaint/dib.cpp
@@ -9,10 +9,10 @@
 #include "precomp.h"
 #include <math.h>
 
-INT fileSize = 0;
+INT g_fileSize = 0;
 float g_xDpi = 96;
 float g_yDpi = 96;
-SYSTEMTIME fileTime;
+SYSTEMTIME g_fileTime;
 
 /* FUNCTIONS ********************************************************/
 
@@ -114,15 +114,15 @@ BOOL SaveDIBToFile(HBITMAP hBitmap, LPCTSTR FileName, HDC 
hDC)
     // update time and size
     FILETIME ft;
     FileTimeToLocalFileTime(&find.ftLastWriteTime, &ft);
-    FileTimeToSystemTime(&ft, &fileTime);
-    fileSize = find.nFileSizeLow;
+    FileTimeToSystemTime(&ft, &g_fileTime);
+    g_fileSize = find.nFileSizeLow;
 
     // TODO: update hRes and vRes
 
     registrySettings.SetMostRecentFile(FileName);
 
-    isAFile = TRUE;
-    imageSaved = TRUE;
+    g_isAFile = TRUE;
+    g_imageSaved = TRUE;
     return TRUE;
 }
 
@@ -150,33 +150,33 @@ HBITMAP SetBitmapAndInfo(HBITMAP hBitmap, LPCTSTR name, 
DWORD dwFileSize, BOOL i
         g_yDpi = GetDeviceCaps(hScreenDC, LOGPIXELSY);
         ReleaseDC(NULL, hScreenDC);
 
-        ZeroMemory(&fileTime, sizeof(fileTime));
+        ZeroMemory(&g_fileTime, sizeof(g_fileTime));
     }
 
     // update image
     imageModel.PushImageForUndo(hBitmap);
     imageModel.ClearHistory();
 
-    // update fileSize
-    fileSize = dwFileSize;
+    // update g_fileSize
+    g_fileSize = dwFileSize;
 
-    // update filepathname
+    // update g_szFileName
     if (name && name[0])
-        GetFullPathName(name, _countof(filepathname), filepathname, NULL);
+        GetFullPathName(name, _countof(g_szFileName), g_szFileName, NULL);
     else
-        LoadString(hProgInstance, IDS_DEFAULTFILENAME, filepathname, 
_countof(filepathname));
+        LoadString(g_hinstExe, IDS_DEFAULTFILENAME, g_szFileName, 
_countof(g_szFileName));
 
     // set title
     CString strTitle;
-    strTitle.Format(IDS_WINDOWTITLE, PathFindFileName(filepathname));
+    strTitle.Format(IDS_WINDOWTITLE, PathFindFileName(g_szFileName));
     mainWindow.SetWindowText(strTitle);
 
     // update file info and recent
-    isAFile = isFile;
-    if (isAFile)
-        registrySettings.SetMostRecentFile(filepathname);
+    g_isAFile = isFile;
+    if (g_isAFile)
+        registrySettings.SetMostRecentFile(g_szFileName);
 
-    imageSaved = TRUE;
+    g_imageSaved = TRUE;
 
     return hBitmap;
 }
@@ -204,7 +204,7 @@ HBITMAP DoLoadImageFile(HWND hwnd, LPCTSTR name, BOOL 
fIsMainFile)
         {
             FILETIME ft;
             FileTimeToLocalFileTime(&find.ftLastWriteTime, &ft);
-            FileTimeToSystemTime(&ft, &fileTime);
+            FileTimeToSystemTime(&ft, &g_fileTime);
             return SetBitmapAndInfo(NULL, name, dwFileSize, TRUE);
         }
     }
@@ -233,7 +233,7 @@ HBITMAP DoLoadImageFile(HWND hwnd, LPCTSTR name, BOOL 
fIsMainFile)
     {
         FILETIME ft;
         FileTimeToLocalFileTime(&find.ftLastWriteTime, &ft);
-        FileTimeToSystemTime(&ft, &fileTime);
+        FileTimeToSystemTime(&ft, &g_fileTime);
         SetBitmapAndInfo(hBitmap, name, dwFileSize, TRUE);
     }
 
diff --git a/base/applications/mspaint/drawing.cpp 
b/base/applications/mspaint/drawing.cpp
index 7bb0d57da60..5b3d1a24f62 100644
--- a/base/applications/mspaint/drawing.cpp
+++ b/base/applications/mspaint/drawing.cpp
@@ -158,7 +158,7 @@ Airbrush(HDC hdc, LONG x, LONG y, COLORREF color, LONG r)
     {
         for (LONG dx = -r; dx <= r; dx++)
         {
-            if ((dx * dx + dy * dy <= r * r) && (rand() % 4 == 0))
+            if ((dx * dx + dy * dy <= r * r) && (rand() % r == 0))
                 ::SetPixelV(hdc, x + dx, y + dy, color);
         }
     }
diff --git a/base/applications/mspaint/fullscreen.cpp 
b/base/applications/mspaint/fullscreen.cpp
index 63dd070da6d..5baadac6f02 100644
--- a/base/applications/mspaint/fullscreen.cpp
+++ b/base/applications/mspaint/fullscreen.cpp
@@ -23,8 +23,8 @@ HWND CFullscreenWindow::DoCreate()
 
 LRESULT CFullscreenWindow::OnCreate(UINT nMsg, WPARAM wParam, LPARAM lParam, 
BOOL& bHandled)
 {
-    SendMessage(WM_SETICON, ICON_BIG, (LPARAM) LoadIcon(hProgInstance, 
MAKEINTRESOURCE(IDI_APPICON)));
-    SendMessage(WM_SETICON, ICON_SMALL, (LPARAM) LoadIcon(hProgInstance, 
MAKEINTRESOURCE(IDI_APPICON)));
+    SendMessage(WM_SETICON, ICON_BIG, (LPARAM) LoadIcon(g_hinstExe, 
MAKEINTRESOURCE(IDI_APPICON)));
+    SendMessage(WM_SETICON, ICON_SMALL, (LPARAM) LoadIcon(g_hinstExe, 
MAKEINTRESOURCE(IDI_APPICON)));
     return 0;
 }
 
diff --git a/base/applications/mspaint/globalvar.h 
b/base/applications/mspaint/globalvar.h
index 4ed2cfc6a12..b38c82e665a 100644
--- a/base/applications/mspaint/globalvar.h
+++ b/base/applications/mspaint/globalvar.h
@@ -10,18 +10,16 @@
 
 /* VARIABLES declared in main.cpp ***********************************/
 
-extern BOOL askBeforeEnlarging;
+extern BOOL g_askBeforeEnlarging;
 
-extern POINT start;
-extern POINT last;
+extern POINT g_ptStart, g_ptEnd;
 
-extern HINSTANCE hProgInstance;
+extern HINSTANCE g_hinstExe;
 
-extern TCHAR filepathname[MAX_LONG_PATH];
-extern BOOL isAFile;
-extern BOOL imageSaved;
-
-extern BOOL showGrid;
+extern TCHAR g_szFileName[MAX_LONG_PATH];
+extern BOOL g_isAFile;
+extern BOOL g_imageSaved;
+extern BOOL g_showGrid;
 
 extern CMainWindow mainWindow;
 
@@ -40,11 +38,11 @@ extern ToolsModel toolsModel;
 extern SelectionModel selectionModel;
 extern PaletteModel paletteModel;
 
-extern HWND hStatusBar;
+extern HWND g_hStatusBar;
 extern float g_xDpi;
 extern float g_yDpi;
-extern INT fileSize;
-extern SYSTEMTIME fileTime;
+extern INT g_fileSize;
+extern SYSTEMTIME g_fileTime;
 
 extern CFullscreenWindow fullscreenWindow;
 extern CMiniatureWindow miniature;
diff --git a/base/applications/mspaint/history.cpp 
b/base/applications/mspaint/history.cpp
index 92ef896afd0..46a7341ff1c 100644
--- a/base/applications/mspaint/history.cpp
+++ b/base/applications/mspaint/history.cpp
@@ -22,103 +22,103 @@ void ImageModel::NotifyImageChanged()
 }
 
 ImageModel::ImageModel()
-    : hDrawingDC(::CreateCompatibleDC(NULL))
-    , currInd(0)
-    , undoSteps(0)
-    , redoSteps(0)
+    : m_hDrawingDC(::CreateCompatibleDC(NULL))
+    , m_currInd(0)
+    , m_undoSteps(0)
+    , m_redoSteps(0)
 {
-    ZeroMemory(hBms, sizeof(hBms));
+    ZeroMemory(m_hBms, sizeof(m_hBms));
 
-    hBms[0] = CreateDIBWithProperties(1, 1);
-    ::SelectObject(hDrawingDC, hBms[0]);
+    m_hBms[0] = CreateColorDIB(1, 1, RGB(255, 255, 255));
+    m_hbmOld = ::SelectObject(m_hDrawingDC, m_hBms[0]);
 
-    imageSaved = TRUE;
+    g_imageSaved = TRUE;
 }
 
 ImageModel::~ImageModel()
 {
-    ::DeleteDC(hDrawingDC);
+    ::DeleteDC(m_hDrawingDC);
 
     for (size_t i = 0; i < HISTORYSIZE; ++i)
     {
-        if (hBms[i])
-            ::DeleteObject(hBms[i]);
+        if (m_hBms[i])
+            ::DeleteObject(m_hBms[i]);
     }
 }
 
 void ImageModel::Undo(BOOL bClearRedo)
 {
-    ATLTRACE("%s: %d\n", __FUNCTION__, undoSteps);
+    ATLTRACE("%s: %d\n", __FUNCTION__, m_undoSteps);
     if (!CanUndo())
         return;
 
-    selectionModel.m_bShow = FALSE;
+    selectionModel.HideSelection();
 
     // Select previous item
-    currInd = (currInd + HISTORYSIZE - 1) % HISTORYSIZE;
-    ::SelectObject(hDrawingDC, hBms[currInd]);
+    m_currInd = (m_currInd + HISTORYSIZE - 1) % HISTORYSIZE;
+    ::SelectObject(m_hDrawingDC, m_hBms[m_currInd]);
 
-    undoSteps--;
+    m_undoSteps--;
     if (bClearRedo)
-        redoSteps = 0;
-    else if (redoSteps < HISTORYSIZE - 1)
-        redoSteps++;
+        m_redoSteps = 0;
+    else if (m_redoSteps < HISTORYSIZE - 1)
+        m_redoSteps++;
 
     NotifyImageChanged();
 }
 
 void ImageModel::Redo()
 {
-    ATLTRACE("%s: %d\n", __FUNCTION__, redoSteps);
+    ATLTRACE("%s: %d\n", __FUNCTION__, m_redoSteps);
     if (!CanRedo())
         return;
 
-    selectionModel.m_bShow = FALSE;
+    selectionModel.HideSelection();
 
     // Select next item
-    currInd = (currInd + 1) % HISTORYSIZE;
-    ::SelectObject(hDrawingDC, hBms[currInd]);
+    m_currInd = (m_currInd + 1) % HISTORYSIZE;
+    ::SelectObject(m_hDrawingDC, m_hBms[m_currInd]);
 
-    redoSteps--;
-    if (undoSteps < HISTORYSIZE - 1)
-        undoSteps++;
+    m_redoSteps--;
+    if (m_undoSteps < HISTORYSIZE - 1)
+        m_undoSteps++;
 
     NotifyImageChanged();
 }
 
 void ImageModel::ResetToPrevious()
 {
-    ATLTRACE("%s: %d\n", __FUNCTION__, currInd);
+    ATLTRACE("%s: %d\n", __FUNCTION__, m_currInd);
 
     // Revert current item with previous item
-    ::DeleteObject(hBms[currInd]);
-    hBms[currInd] = CopyDIBImage(hBms[(currInd + HISTORYSIZE - 1) % 
HISTORYSIZE]);
-    ::SelectObject(hDrawingDC, hBms[currInd]);
+    ::DeleteObject(m_hBms[m_currInd]);
+    m_hBms[m_currInd] = CopyDIBImage(m_hBms[(m_currInd + HISTORYSIZE - 1) % 
HISTORYSIZE]);
+    ::SelectObject(m_hDrawingDC, m_hBms[m_currInd]);
 
     NotifyImageChanged();
 }
 
 void ImageModel::ClearHistory()
 {
-    undoSteps = 0;
-    redoSteps = 0;
+    m_undoSteps = 0;
+    m_redoSteps = 0;
 }
 
 void ImageModel::PushImageForUndo(HBITMAP hbm)
 {
-    ATLTRACE("%s: %d\n", __FUNCTION__, currInd);
+    ATLTRACE("%s: %d\n", __FUNCTION__, m_currInd);
 
     // Go to the next item with an HBITMAP or current item
-    ::DeleteObject(hBms[(currInd + 1) % HISTORYSIZE]);
-    hBms[(currInd + 1) % HISTORYSIZE] = (hbm ? hbm : 
CopyDIBImage(hBms[currInd]));
-    currInd = (currInd + 1) % HISTORYSIZE;
-    ::SelectObject(hDrawingDC, hBms[currInd]);
+    ::DeleteObject(m_hBms[(m_currInd + 1) % HISTORYSIZE]);
+    m_hBms[(m_currInd + 1) % HISTORYSIZE] = (hbm ? hbm : 
CopyDIBImage(m_hBms[m_currInd]));
+    m_currInd = (m_currInd + 1) % HISTORYSIZE;
+    ::SelectObject(m_hDrawingDC, m_hBms[m_currInd]);
 
-    if (undoSteps < HISTORYSIZE - 1)
-        undoSteps++;
-    redoSteps = 0;
+    if (m_undoSteps < HISTORYSIZE - 1)
+        m_undoSteps++;
+    m_redoSteps = 0;
 
-    imageSaved = FALSE;
+    g_imageSaved = FALSE;
     NotifyImageChanged();
 }
 
@@ -136,7 +136,7 @@ void ImageModel::Crop(int nWidth, int nHeight, int 
nOffsetX, int nOffsetY)
         return;
 
     // Select the HBITMAP by memory DC
-    HDC hdcMem = ::CreateCompatibleDC(hDrawingDC);
+    HDC hdcMem = ::CreateCompatibleDC(m_hDrawingDC);
     HGDIOBJ hbmOld = ::SelectObject(hdcMem, hbmCropped);
 
     // Fill background of the HBITMAP
@@ -146,7 +146,7 @@ void ImageModel::Crop(int nWidth, int nHeight, int 
nOffsetX, int nOffsetY)
     ::DeleteObject(hbrBack);
 
     // Copy the old content
-    ::BitBlt(hdcMem, -nOffsetX, -nOffsetY, GetWidth(), GetHeight(), 
hDrawingDC, 0, 0, SRCCOPY);
+    ::BitBlt(hdcMem, -nOffsetX, -nOffsetY, GetWidth(), GetHeight(), 
m_hDrawingDC, 0, 0, SRCCOPY);
 
     // Clean up
     ::SelectObject(hdcMem, hbmOld);
@@ -160,12 +160,12 @@ void ImageModel::Crop(int nWidth, int nHeight, int 
nOffsetX, int nOffsetY)
 
 void ImageModel::SaveImage(LPCTSTR lpFileName)
 {
-    SaveDIBToFile(hBms[currInd], lpFileName, hDrawingDC);
+    SaveDIBToFile(m_hBms[m_currInd], lpFileName, m_hDrawingDC);
 }
 
 BOOL ImageModel::IsImageSaved() const
 {
-    return imageSaved;
+    return g_imageSaved;
 }
 
 void ImageModel::StretchSkew(int nStretchPercentX, int nStretchPercentY, int 
nSkewDegX, int nSkewDegY)
@@ -176,17 +176,17 @@ void ImageModel::StretchSkew(int nStretchPercentX, int 
nStretchPercentY, int nSk
     INT newHeight = oldHeight * nStretchPercentY / 100;
     if (oldWidth != newWidth || oldHeight != newHeight)
     {
-        HBITMAP hbm0 = CopyDIBImage(hBms[currInd], newWidth, newHeight);
+        HBITMAP hbm0 = CopyDIBImage(m_hBms[m_currInd], newWidth, newHeight);
         PushImageForUndo(hbm0);
     }
     if (nSkewDegX)
     {
-        HBITMAP hbm1 = SkewDIB(hDrawingDC, hBms[currInd], nSkewDegX, FALSE);
+        HBITMAP hbm1 = SkewDIB(m_hDrawingDC, m_hBms[m_currInd], nSkewDegX, 
FALSE);
         PushImageForUndo(hbm1);
     }
     if (nSkewDegY)
     {
-        HBITMAP hbm2 = SkewDIB(hDrawingDC, hBms[currInd], nSkewDegY, TRUE);
+        HBITMAP hbm2 = SkewDIB(m_hDrawingDC, m_hBms[m_currInd], nSkewDegY, 
TRUE);
         PushImageForUndo(hbm2);
     }
     NotifyImageChanged();
@@ -194,31 +194,31 @@ void ImageModel::StretchSkew(int nStretchPercentX, int 
nStretchPercentY, int nSk
 
 int ImageModel::GetWidth() const
 {
-    return GetDIBWidth(hBms[currInd]);
+    return GetDIBWidth(m_hBms[m_currInd]);
 }
 
 int ImageModel::GetHeight() const
 {
-    return GetDIBHeight(hBms[currInd]);
+    return GetDIBHeight(m_hBms[m_currInd]);
 }
 
 void ImageModel::InvertColors()
 {
     RECT rect = {0, 0, GetWidth(), GetHeight()};
     PushImageForUndo();
-    InvertRect(hDrawingDC, &rect);
+    InvertRect(m_hDrawingDC, &rect);
     NotifyImageChanged();
 }
 
 HDC ImageModel::GetDC()
 {
-    return hDrawingDC;
+    return m_hDrawingDC;
 }
 
 void ImageModel::FlipHorizontally()
 {
     PushImageForUndo();
-    StretchBlt(hDrawingDC, GetWidth() - 1, 0, -GetWidth(), GetHeight(), 
GetDC(), 0, 0,
+    StretchBlt(m_hDrawingDC, GetWidth() - 1, 0, -GetWidth(), GetHeight(), 
GetDC(), 0, 0,
                GetWidth(), GetHeight(), SRCCOPY);
     NotifyImageChanged();
 }
@@ -226,7 +226,7 @@ void ImageModel::FlipHorizontally()
 void ImageModel::FlipVertically()
 {
     PushImageForUndo();
-    StretchBlt(hDrawingDC, 0, GetHeight() - 1, GetWidth(), -GetHeight(), 
GetDC(), 0, 0,
+    StretchBlt(m_hDrawingDC, 0, GetHeight() - 1, GetWidth(), -GetHeight(), 
GetDC(), 0, 0,
                GetWidth(), GetHeight(), SRCCOPY);
     NotifyImageChanged();
 }
@@ -238,7 +238,7 @@ void ImageModel::RotateNTimes90Degrees(int iN)
         case 1:
         case 3:
         {
-            HBITMAP hbm = Rotate90DegreeBlt(hDrawingDC, GetWidth(), 
GetHeight(), iN == 1, FALSE);
+            HBITMAP hbm = Rotate90DegreeBlt(m_hDrawingDC, GetWidth(), 
GetHeight(), iN == 1, FALSE);
             if (hbm)
                 PushImageForUndo(hbm);
             break;
@@ -246,28 +246,25 @@ void ImageModel::RotateNTimes90Degrees(int iN)
         case 2:
         {
             PushImageForUndo();
-            StretchBlt(hDrawingDC, GetWidth() - 1, GetHeight() - 1, 
-GetWidth(), -GetHeight(),
-                       hDrawingDC, 0, 0, GetWidth(), GetHeight(), SRCCOPY);
+            StretchBlt(m_hDrawingDC, GetWidth() - 1, GetHeight() - 1, 
-GetWidth(), -GetHeight(),
+                       m_hDrawingDC, 0, 0, GetWidth(), GetHeight(), SRCCOPY);
             break;
         }
     }
     NotifyImageChanged();
 }
 
-void ImageModel::DeleteSelection()
-{
-    if (!selectionModel.m_bShow)
-        return;
-
-    selectionModel.TakeOff();
-    selectionModel.m_bShow = FALSE;
-    selectionModel.ClearColor();
-    selectionModel.ClearMask();
-    NotifyImageChanged();
-}
-
 void ImageModel::Bound(POINT& pt) const
 {
     pt.x = max(0, min(pt.x, GetWidth()));
     pt.y = max(0, min(pt.y, GetHeight()));
 }
+
+HBITMAP ImageModel::CopyBitmap()
+{
+    // NOTE: An app cannot select a bitmap into more than one device context 
at a time.
+    ::SelectObject(m_hDrawingDC, m_hbmOld); // De-select
+    HBITMAP ret = CopyDIBImage(m_hBms[m_currInd]);
+    m_hbmOld = ::SelectObject(m_hDrawingDC, m_hBms[m_currInd]); // Re-select
+    return ret;
+}
diff --git a/base/applications/mspaint/history.h 
b/base/applications/mspaint/history.h
index 00e66950425..2b74f306248 100644
--- a/base/applications/mspaint/history.h
+++ b/base/applications/mspaint/history.h
@@ -18,8 +18,8 @@ public:
     virtual ~ImageModel();
 
     HDC GetDC();
-    BOOL CanUndo() const { return undoSteps > 0; }
-    BOOL CanRedo() const { return redoSteps > 0; }
+    BOOL CanUndo() const { return m_undoSteps > 0; }
+    BOOL CanRedo() const { return m_redoSteps > 0; }
     void PushImageForUndo(HBITMAP hbm = NULL);
     void ResetToPrevious(void);
     void Undo(BOOL bClearRedo = FALSE);
@@ -31,18 +31,19 @@ public:
     void StretchSkew(int nStretchPercentX, int nStretchPercentY, int nSkewDegX 
= 0, int nSkewDegY = 0);
     int GetWidth() const;
     int GetHeight() const;
+    HBITMAP CopyBitmap();
     void InvertColors();
     void FlipHorizontally();
     void FlipVertically();
     void RotateNTimes90Degrees(int iN);
-    void DeleteSelection();
     void Bound(POINT& pt) const;
     void NotifyImageChanged();
 
 protected:
-    HDC hDrawingDC; // The device context for this class
-    int currInd; // The current index
-    int undoSteps; // The undo-able count
-    int redoSteps; // The redo-able count
-    HBITMAP hBms[HISTORYSIZE]; // A rotation buffer of HBITMAPs
+    HDC m_hDrawingDC; // The device context for this class
+    int m_currInd; // The current index in m_hBms
+    int m_undoSteps; // The undo-able count
+    int m_redoSteps; // The redo-able count
+    HBITMAP m_hBms[HISTORYSIZE]; // A rotation buffer of HBITMAPs
+    HGDIOBJ m_hbmOld;
 };
diff --git a/base/applications/mspaint/main.cpp 
b/base/applications/mspaint/main.cpp
index 8d328de1e84..b3b6728fd94 100644
--- a/base/applications/mspaint/main.cpp
+++ b/base/applications/mspaint/main.cpp
@@ -8,15 +8,13 @@
 
 #include "precomp.h"
 
-POINT start;
-POINT last;
-
-BOOL askBeforeEnlarging = FALSE;  // TODO: initialize from registry
-HINSTANCE hProgInstance = NULL;
-TCHAR filepathname[MAX_LONG_PATH] = { 0 };
-BOOL isAFile = FALSE;
-BOOL imageSaved = FALSE;
-BOOL showGrid = FALSE;
+POINT g_ptStart, g_ptEnd;
+BOOL g_askBeforeEnlarging = FALSE;  // TODO: initialize from registry
+HINSTANCE g_hinstExe = NULL;
+TCHAR g_szFileName[MAX_LONG_PATH] = { 0 };
+BOOL g_isAFile = FALSE;
+BOOL g_imageSaved = FALSE;
+BOOL g_showGrid = FALSE;
 
 CMainWindow mainWindow;
 
@@ -81,7 +79,7 @@ BOOL CMainWindow::GetOpenFileName(IN OUT LPTSTR pszFile, INT 
cchMaxFile)
     {
         // The "All Files" item text
         CString strAllPictureFiles;
-        strAllPictureFiles.LoadString(hProgInstance, IDS_ALLPICTUREFILES);
+        strAllPictureFiles.LoadString(g_hinstExe, IDS_ALLPICTUREFILES);
 
         // Get the import filter
         CSimpleArray<GUID> aguidFileTypesI;
@@ -92,7 +90,7 @@ BOOL CMainWindow::GetOpenFileName(IN OUT LPTSTR pszFile, INT 
cchMaxFile)
         ZeroMemory(&ofn, sizeof(ofn));
         ofn.lStructSize = sizeof(ofn);
         ofn.hwndOwner   = m_hWnd;
-        ofn.hInstance   = hProgInstance;
+        ofn.hInstance   = g_hinstExe;
         ofn.lpstrFilter = strFilter;
         ofn.Flags       = OFN_EXPLORER | OFN_HIDEREADONLY;
         ofn.lpstrDefExt = L"png";
@@ -119,7 +117,7 @@ BOOL CMainWindow::GetSaveFileName(IN OUT LPTSTR pszFile, 
INT cchMaxFile)
         ZeroMemory(&sfn, sizeof(sfn));
         sfn.lStructSize = sizeof(sfn);
         sfn.hwndOwner   = m_hWnd;
-        sfn.hInstance   = hProgInstance;
+        sfn.hInstance   = g_hinstExe;
         sfn.lpstrFilter = strFilter;
         sfn.Flags       = OFN_EXPLORER | OFN_OVERWRITEPROMPT | OFN_ENABLEHOOK;
         sfn.lpfnHook    = OFNHookProc;
@@ -170,10 +168,10 @@ BOOL CMainWindow::ChooseColor(IN OUT COLORREF *prgbColor)
 
 HWND CMainWindow::DoCreate()
 {
-    ::LoadString(hProgInstance, IDS_DEFAULTFILENAME, filepathname, 
_countof(filepathname));
+    ::LoadString(g_hinstExe, IDS_DEFAULTFILENAME, g_szFileName, 
_countof(g_szFileName));
 
     CString strTitle;
-    strTitle.Format(IDS_WINDOWTITLE, PathFindFileName(filepathname));
+    strTitle.Format(IDS_WINDOWTITLE, PathFindFileName(g_szFileName));
 
     RECT& rc = registrySettings.WindowPlacement.rcNormalPosition;
     return Create(HWND_DESKTOP, rc, strTitle, WS_OVERLAPPEDWINDOW, 
WS_EX_ACCEPTFILES);
@@ -188,7 +186,7 @@ _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, 
LPTSTR lpCmdLine, INT nC
     _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
 #endif
 
-    hProgInstance = hInstance;
+    g_hinstExe = hInstance;
 
     // Initialize common controls library
     INITCOMMONCONTROLSEX iccx;
diff --git a/base/applications/mspaint/miniature.cpp 
b/base/applications/mspaint/miniature.cpp
index b354de983b1..ab10814e5bf 100644
--- a/base/applications/mspaint/miniature.cpp
+++ b/base/applications/mspaint/miniature.cpp
@@ -38,7 +38,7 @@ HWND CMiniatureWindow::DoCreate(HWND hwndParent)
     };
 
     TCHAR strTitle[100];
-    ::LoadString(hProgInstance, IDS_MINIATURETITLE, strTitle, 
_countof(strTitle));
+    ::LoadString(g_hinstExe, IDS_MINIATURETITLE, strTitle, _countof(strTitle));
 
     DWORD style = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME;
     return Create(hwndParent, rc, strTitle, style, WS_EX_PALETTEWINDOW);
diff --git a/base/applications/mspaint/mouse.cpp 
b/base/applications/mspaint/mouse.cpp
index 3c0923bec58..97359f0ce68 100644
--- a/base/applications/mspaint/mouse.cpp
+++ b/base/applications/mspaint/mouse.cpp
@@ -53,25 +53,25 @@ BOOL nearlyEqualPoints(INT x0, INT y0, INT x1, INT y1)
 
 void updateStartAndLast(LONG x, LONG y)
 {
-    start.x = last.x = x;
-    start.y = last.y = y;
+    g_ptStart.x = g_ptEnd.x = x;
+    g_ptStart.y = g_ptEnd.y = y;
 }
 
 void updateLast(LONG x, LONG y)
 {
-    last.x = x;
-    last.y = y;
+    g_ptEnd.x = x;
+    g_ptEnd.y = y;
 }
 
 void ToolBase::reset()
 {
     pointSP = 0;
-    start.x = start.y = last.x = last.y = -1;
+    g_ptStart.x = g_ptStart.y = g_ptEnd.x = g_ptEnd.y = -1;
     selectionModel.ResetPtStack();
     if (selectionModel.m_bShow)
     {
         selectionModel.Landing();
-        selectionModel.m_bShow = FALSE;
+        selectionModel.HideSelection();
     }
 }
 
@@ -99,15 +99,46 @@ void ToolBase::endEvent()
     m_hdc = NULL;
 }
 
+void ToolBase::OnDrawSelectionOnCanvas(HDC hdc)
+{
+    if (!selectionModel.m_bShow)
+        return;
+
+    RECT rcSelection = selectionModel.m_rc;
+    canvasWindow.ImageToCanvas(rcSelection);
+
+    ::InflateRect(&rcSelection, GRIP_SIZE, GRIP_SIZE);
+    drawSizeBoxes(hdc, &rcSelection, TRUE);
+}
+
 /* TOOLS ********************************************************/
 
 // TOOL_FREESEL
 struct FreeSelTool : ToolBase
 {
-    BOOL m_bLeftButton;
+    BOOL m_bLeftButton = FALSE;
+
+    FreeSelTool() : ToolBase(TOOL_FREESEL)
+    {
+    }
+
+    void OnDrawOverlayOnImage(HDC hdc) override
+    {
+        if (!selectionModel.IsLanded())
+        {
+            selectionModel.DrawBackgroundPoly(hdc, selectionModel.m_rgbBack);
+            selectionModel.DrawSelection(hdc, paletteModel.GetBgColor(), 
toolsModel.IsBackgroundTransparent());
+        }
+
+        if (canvasWindow.m_drawing)
+        {
+            selectionModel.DrawFramePoly(hdc);
+        }
+    }
 
-    FreeSelTool() : ToolBase(TOOL_FREESEL), m_bLeftButton(FALSE)
+    void OnDrawOverlayOnCanvas(HDC hdc) override
     {
+        OnDrawSelectionOnCanvas(hdc);
     }
 
     void OnButtonDown(BOOL bLeftButton, LONG x, LONG y, BOOL bDoubleClick) 
override
@@ -115,8 +146,7 @@ struct FreeSelTool : ToolBase
         selectionModel.Landing();
         if (bLeftButton)
         {
-            imageModel.PushImageForUndo();
-            selectionModel.m_bShow = FALSE;
+            selectionModel.HideSelection();
             selectionModel.ResetPtStack();
             POINT pt = { x, y };
             selectionModel.PushToPtStack(pt);
@@ -131,8 +161,7 @@ struct FreeSelTool : ToolBase
             POINT pt = { x, y };
             imageModel.Bound(pt);
             selectionModel.PushToPtStack(pt);
-            imageModel.ResetToPrevious();
-            selectionModel.DrawFramePoly(m_hdc);
+            imageModel.NotifyImageChanged();
         }
     }
 
@@ -140,16 +169,13 @@ struct FreeSelTool : ToolBase
     {
         if (bLeftButton)
         {
-            imageModel.ResetToPrevious();
             if (selectionModel.PtStackSize() > 2)
             {
                 selectionModel.BuildMaskFromPtStack();
-                selectionModel.TakeOff();
                 selectionModel.m_bShow = TRUE;
             }
             else
             {
-                imageModel.Undo(TRUE);
                 selectionModel.ResetPtStack();
                 selectionModel.m_bShow = FALSE;
             }
@@ -159,15 +185,13 @@ struct FreeSelTool : ToolBase
 
     void OnFinishDraw() override
     {
-        m_bLeftButton = FALSE;
+        selectionModel.Landing();
         ToolBase::OnFinishDraw();
     }
 
     void OnCancelDraw() override
     {
-        if (m_bLeftButton)
-            imageModel.Undo(TRUE);
-        m_bLeftButton = FALSE;
+        selectionModel.HideSelection();
         ToolBase::OnCancelDraw();
     }
 };
@@ -175,10 +199,31 @@ struct FreeSelTool : ToolBase
 // TOOL_RECTSEL
 struct RectSelTool : ToolBase
 {
-    BOOL m_bLeftButton;
+    BOOL m_bLeftButton = FALSE;
+
+    RectSelTool() : ToolBase(TOOL_RECTSEL)
+    {
+    }
 
-    RectSelTool() : ToolBase(TOOL_RECTSEL), m_bLeftButton(FALSE)
+    void OnDrawOverlayOnImage(HDC hdc) override
     {
+        if (!selectionModel.IsLanded())
+        {
+            selectionModel.DrawBackgroundRect(hdc, selectionModel.m_rgbBack);
+            selectionModel.DrawSelection(hdc, paletteModel.GetBgColor(), 
toolsModel.IsBackgroundTransparent());
+        }
+
+        if (canvasWindow.m_drawing)
+        {
+            RECT rc = selectionModel.m_rc;
+            if (!::IsRectEmpty(&rc))
+                RectSel(hdc, rc.left, rc.top, rc.right, rc.bottom);
+        }
+    }
+
+    void OnDrawOverlayOnCanvas(HDC hdc) override
+    {
+        OnDrawSelectionOnCanvas(hdc);
     }
 
     void OnButtonDown(BOOL bLeftButton, LONG x, LONG y, BOOL bDoubleClick) 
override
@@ -186,9 +231,7 @@ struct RectSelTool : ToolBase
         selectionModel.Landing();
         if (bLeftButton)
         {
-            imageModel.PushImageForUndo();
-            selectionModel.m_bShow = FALSE;
-            ::SetRectEmpty(&selectionModel.m_rc);
+            selectionModel.HideSelection();
         }
         m_bLeftButton = bLeftButton;
     }
@@ -197,11 +240,10 @@ struct RectSelTool : ToolBase
     {
         if (bLeftButton)
         {
-            imageModel.ResetToPrevious();
             POINT pt = { x, y };
             imageModel.Bound(pt);
-            selectionModel.SetRectFromPoints(start, pt);
-            RectSel(m_hdc, start.x, start.y, pt.x, pt.y);
+            selectionModel.SetRectFromPoints(g_ptStart, pt);
+            imageModel.NotifyImageChanged();
         }
     }
 
@@ -209,9 +251,9 @@ struct RectSelTool : ToolBase
     {
         if (bLeftButton)
         {
-            imageModel.ResetToPrevious();
-            if (start.x == x && start.y == y)
-                imageModel.Undo(TRUE);
+            POINT pt = { x, y };
+            imageModel.Bound(pt);
+            selectionModel.SetRectFromPoints(g_ptStart, pt);
             selectionModel.m_bShow = !selectionModel.m_rc.IsRectEmpty();
             imageModel.NotifyImageChanged();
         }
@@ -219,22 +261,68 @@ struct RectSelTool : ToolBase
 
     void OnFinishDraw() override
     {
-        m_bLeftButton = FALSE;
+        selectionModel.Landing();
         ToolBase::OnFinishDraw();
     }
 
     void OnCancelDraw() override
     {
-        if (m_bLeftButton)
-            imageModel.Undo(TRUE);
-        m_bLeftButton = FALSE;
+        selectionModel.HideSelection();
         ToolBase::OnCancelDraw();
     }
 };
 
-struct GenericDrawTool : ToolBase
+struct TwoPointDrawTool : ToolBase
 {
-    GenericDrawTool(TOOLTYPE type) : ToolBase(type)
+    BOOL m_bLeftButton = FALSE;
+    BOOL m_bDrawing = FALSE;
+
+    TwoPointDrawTool(TOOLTYPE type) : ToolBase(type)
+    {
+    }
+
+    void OnButtonDown(BOOL bLeftButton, LONG x, LONG y, BOOL bDoubleClick) 
override
+    {
+        m_bLeftButton = bLeftButton;
+        m_bDrawing = TRUE;
+        g_ptStart.x = g_ptEnd.x = x;
+        g_ptStart.y = g_ptEnd.y = y;
+        imageModel.NotifyImageChanged();
+    }
+
+    void OnMouseMove(BOOL bLeftButton, LONG x, LONG y) override
+    {
+        g_ptEnd.x = x;
+        g_ptEnd.y = y;
+        imageModel.NotifyImageChanged();
+    }
+
+    void OnButtonUp(BOOL bLeftButton, LONG x, LONG y) override
+    {
+        g_ptEnd.x = x;
+        g_ptEnd.y = y;
+        imageModel.PushImageForUndo();
+        OnDrawOverlayOnImage(m_hdc);
+        m_bDrawing = FALSE;
+        imageModel.NotifyImageChanged();
+    }
+
+    void OnFinishDraw() override
+    {
+        m_bDrawing = FALSE;
+        ToolBase::OnFinishDraw();
+    }
+
+    void OnCancelDraw() override
+    {
+        m_bDrawing = FALSE;
+        ToolBase::OnCancelDraw();
+    }
+};
+
+struct SmoothDrawTool : ToolBase
+{
+    SmoothDrawTool(TOOLTYPE type) : ToolBase(type)
     {
     }
 
@@ -243,7 +331,9 @@ struct GenericDrawTool : ToolBase
     void OnButtonDown(BOOL bLeftButton, LONG x, LONG y, BOOL bDoubleClick) 
override
     {
         imageModel.PushImageForUndo();
-        draw(bLeftButton, x, y);
+        g_ptStart.x = g_ptEnd.x = x;
+        g_ptStart.y = g_ptEnd.y = y;
+        imageModel.NotifyImageChanged();
     }
 
     void OnMouseMove(BOOL bLeftButton, LONG x, LONG y) override
@@ -255,7 +345,12 @@ struct GenericDrawTool : ToolBase
     void OnButtonUp(BOOL bLeftButton, LONG x, LONG y) override
     {
         draw(bLeftButton, x, y);
-        imageModel.NotifyImageChanged();
+        OnFinishDraw();
+    }
+
+    void OnFinishDraw() override
+    {
+        ToolBase::OnFinishDraw();
     }
 
     void OnCancelDraw() override
@@ -267,18 +362,20 @@ struct GenericDrawTool : ToolBase
 };
 
 // TOOL_RUBBER
-struct RubberTool : GenericDrawTool
+struct RubberTool : SmoothDrawTool
 {
-    RubberTool() : GenericDrawTool(TOOL_RUBBER)
+    RubberTool() : SmoothDrawTool(TOOL_RUBBER)
     {
     }
 
     void draw(BOOL bLeftButton, LONG x, LONG y) override
     {
         if (bLeftButton)
-            Erase(m_hdc, last.x, last.y, x, y, m_bg, 
toolsModel.GetRubberRadius());
+            Erase(m_hdc, g_ptEnd.x, g_ptEnd.y, x, y, m_bg, 
toolsModel.GetRubberRadius());
         else
-            Replace(m_hdc, last.x, last.y, x, y, m_fg, m_bg, 
toolsModel.GetRubberRadius());
+            Replace(m_hdc, g_ptEnd.x, g_ptEnd.y, x, y, m_fg, m_bg, 
toolsModel.GetRubberRadius());
+        g_ptEnd.x = x;
+        g_ptEnd.y = y;
     }
 };
 
@@ -354,38 +451,42 @@ struct ZoomTool : ToolBase
 };
 
 // TOOL_PEN
-struct PenTool : GenericDrawTool
+struct PenTool : SmoothDrawTool
 {
-    PenTool() : GenericDrawTool(TOOL_PEN)
+    PenTool() : SmoothDrawTool(TOOL_PEN)
     {
     }
 
     void draw(BOOL bLeftButton, LONG x, LONG y) override
     {
         COLORREF rgb = bLeftButton ? m_fg : m_bg;
-        Line(m_hdc, last.x, last.y, x, y, rgb, 1);
+        Line(m_hdc, g_ptEnd.x, g_ptEnd.y, x, y, rgb, 1);
         ::SetPixelV(m_hdc, x, y, rgb);
+        g_ptEnd.x = x;
+        g_ptEnd.y = y;
     }
 };
 
 // TOOL_BRUSH
-struct BrushTool : GenericDrawTool
+struct BrushTool : SmoothDrawTool
 {
-    BrushTool() : GenericDrawTool(TOOL_BRUSH)
+    BrushTool() : SmoothDrawTool(TOOL_BRUSH)
     {
     }
 
     void draw(BOOL bLeftButton, LONG x, LONG y) override
     {
         COLORREF rgb = bLeftButton ? m_fg : m_bg;
-        Brush(m_hdc, last.x, last.y, x, y, rgb, toolsModel.GetBrushStyle());
+        Brush(m_hdc, g_ptEnd.x, g_ptEnd.y, x, y, rgb, 
toolsModel.GetBrushStyle());
+        g_ptEnd.x = x;
+        g_ptEnd.y = y;
     }
 };
 
 // TOOL_AIRBRUSH
-struct AirBrushTool : GenericDrawTool
+struct AirBrushTool : SmoothDrawTool
 {
-    AirBrushTool() : GenericDrawTool(TOOL_AIRBRUSH)
+    AirBrushTool() : SmoothDrawTool(TOOL_AIRBRUSH)
     {
     }
 
@@ -403,13 +504,22 @@ struct TextTool : ToolBase
     {
     }
 
+    void OnDrawOverlayOnImage(HDC hdc) override
+    {
+        if (canvasWindow.m_drawing)
+        {
+            RECT rc = selectionModel.m_rc;
+            if (!::IsRectEmpty(&rc))
+                RectSel(hdc, rc.left, rc.top, rc.right, rc.bottom);
+        }
+    }
+
     void UpdatePoint(LONG x, LONG y)
     {
-        imageModel.ResetToPrevious();
         POINT pt = { x, y };
         imageModel.Bound(pt);
-        selectionModel.SetRectFromPoints(start, pt);
-        RectSel(m_hdc, start.x, start.y, pt.x, pt.y);
+        selectionModel.SetRectFromPoints(g_ptStart, pt);
+        imageModel.NotifyImageChanged();
     }
 
     void OnButtonDown(BOOL bLeftButton, LONG x, LONG y, BOOL bDoubleClick) 
override
@@ -417,7 +527,6 @@ struct TextTool : ToolBase
         if (!textEditWindow.IsWindow())
             textEditWindow.Create(canvasWindow);
 
-        imageModel.PushImageForUndo();
         UpdatePoint(x, y);
     }
 
@@ -426,30 +535,40 @@ struct TextTool : ToolBase
         UpdatePoint(x, y);
     }
 
-    void OnButtonUp(BOOL bLeftButton, LONG x, LONG y) override
+    void draw(HDC hdc)
     {
-        imageModel.Undo(TRUE);
+        CString szText;
+        textEditWindow.GetWindowText(szText);
 
+        RECT rc;
+        textEditWindow.InvalidateEditRect();
+        textEditWindow.GetEditRect(&rc);
+        ::InflateRect(&rc, -GRIP_SIZE / 2, -GRIP_SIZE / 2);
+
+        // Draw the text
+        INT style = (toolsModel.IsBackgroundTransparent() ? 0 : 1);
+        imageModel.PushImageForUndo();
+        Text(hdc, rc.left, rc.top, rc.right, rc.bottom, m_fg, m_bg, szText,
+             textEditWindow.GetFont(), style);
+    }
+
+    void quit()
+    {
+        if (textEditWindow.IsWindow())
+            textEditWindow.ShowWindow(SW_HIDE);
+        selectionModel.HideSelection();
+    }
+
+    void OnButtonUp(BOOL bLeftButton, LONG x, LONG y) override
+    {
         POINT pt = { x, y };
         imageModel.Bound(pt);
-        selectionModel.SetRectFromPoints(start, pt);
+        selectionModel.SetRectFromPoints(g_ptStart, pt);
 
         BOOL bTextBoxShown = ::IsWindowVisible(textEditWindow);
         if (bTextBoxShown && textEditWindow.GetWindowTextLength() > 0)
         {
-            CString szText;
-            textEditWindow.GetWindowText(szText);
-
-            RECT rc;
-            textEditWindow.InvalidateEditRect();
-            textEditWindow.GetEditRect(&rc);
-            ::InflateRect(&rc, -GRIP_SIZE / 2, -GRIP_SIZE / 2);
-
-            // Draw the text
-            INT style = (toolsModel.IsBackgroundTransparent() ? 0 : 1);
-            imageModel.PushImageForUndo();
-            Text(m_hdc, rc.left, rc.top, rc.right, rc.bottom, m_fg, m_bg, 
szText,
-                 textEditWindow.GetFont(), style);
+            draw(m_hdc);
 
             if (selectionModel.m_rc.IsRectEmpty())
             {
@@ -494,201 +613,224 @@ struct TextTool : ToolBase
 
     void OnFinishDraw() override
     {
-        toolsModel.OnButtonDown(TRUE, -1, -1, TRUE);
-        toolsModel.OnButtonUp(TRUE, -1, -1);
+        draw(m_hdc);
+        quit();
         ToolBase::OnFinishDraw();
     }
+
+    void OnCancelDraw() override
+    {
+        quit();
+        ToolBase::OnCancelDraw();
+    }
 };
 
 // TOOL_LINE
-struct LineTool : GenericDrawTool
+struct LineTool : TwoPointDrawTool
 {
-    LineTool() : GenericDrawTool(TOOL_LINE)
+    LineTool() : TwoPointDrawTool(TOOL_LINE)
     {
     }
 
-    void draw(BOOL bLeftButton, LONG x, LONG y) override
+    void OnDrawOverlayOnImage(HDC hdc) override
     {
-        imageModel.ResetToPrevious();
+        if (!m_bDrawing)
+            return;
         if (GetAsyncKeyState(VK_SHIFT) < 0)
-            roundTo8Directions(start.x, start.y, x, y);
-        COLORREF rgb = bLeftButton ? m_fg : m_bg;
-        Line(m_hdc, start.x, start.y, x, y, rgb, toolsModel.GetLineWidth());
+            roundTo8Directions(g_ptStart.x, g_ptStart.y, g_ptEnd.x, g_ptEnd.y);
+        COLORREF rgb = m_bLeftButton ? m_fg : m_bg;
+        Line(hdc, g_ptStart.x, g_ptStart.y, g_ptEnd.x, g_ptEnd.y, rgb, 
toolsModel.GetLineWidth());
     }
 };
 
 // TOOL_BEZIER
 struct BezierTool : ToolBase
 {
-    BOOL m_bLeftButton;
+    BOOL m_bLeftButton = FALSE;
+    BOOL m_bDrawing = FALSE;
 
-    BezierTool() : ToolBase(TOOL_BEZIER), m_bLeftButton(FALSE)
+    BezierTool() : ToolBase(TOOL_BEZIER)
     {
     }
 
-    void draw(BOOL bLeftButton)
+    void OnDrawOverlayOnImage(HDC hdc)
     {
-        COLORREF rgb = (bLeftButton ? m_fg : m_bg);
+        if (!m_bDrawing)
+            return;
+
+        COLORREF rgb = (m_bLeftButton ? m_fg : m_bg);
         switch (pointSP)
         {
             case 1:
-                Line(m_hdc, pointStack[0].x, pointStack[0].y, pointStack[1].x, 
pointStack[1].y, rgb,
+                Line(hdc, pointStack[0].x, pointStack[0].y, pointStack[1].x, 
pointStack[1].y, rgb,
                      toolsModel.GetLineWidth());
                 break;
             case 2:
-                Bezier(m_hdc, pointStack[0], pointStack[2], pointStack[2], 
pointStack[1], rgb, toolsModel.GetLineWidth());
+                Bezier(hdc, pointStack[0], pointStack[2], pointStack[2], 
pointStack[1], rgb, toolsModel.GetLineWidth());
                 break;
             case 3:
-                Bezier(m_hdc, pointStack[0], pointStack[2], pointStack[3], 
pointStack[1], rgb, toolsModel.GetLineWidth());
+                Bezier(hdc, pointStack[0], pointStack[2], pointStack[3], 
pointStack[1], rgb, toolsModel.GetLineWidth());
                 break;
         }
-        m_bLeftButton = bLeftButton;
     }
 
     void OnButtonDown(BOOL bLeftButton, LONG x, LONG y, BOOL bDoubleClick) 
override
     {
-        pointStack[pointSP].x = x;
-        pointStack[pointSP].y = y;
+        m_bLeftButton = bLeftButton;
 
-        if (pointSP == 0)
+        if (!m_bDrawing)
         {
-            imageModel.PushImageForUndo();
-            pointSP++;
+            m_bDrawing = TRUE;
+            pointStack[pointSP].x = pointStack[pointSP + 1].x = x;
+            pointStack[pointSP].y = pointStack[pointSP + 1].y = y;
+            ++pointSP;
         }
+        else
+        {
+            ++pointSP;
+            pointStack[pointSP].x = x;
+            pointStack[pointSP].y = y;
+        }
+
+        imageModel.NotifyImageChanged();
     }
 
     void OnMouseMove(BOOL bLeftButton, LONG x, LONG y) override
     {
-        imageModel.ResetToPrevious();
         pointStack[pointSP].x = x;
         pointStack[pointSP].y = y;
-        draw(bLeftButton);
+        imageModel.NotifyImageChanged();
     }
 
     void OnButtonUp(BOOL bLeftButton, LONG x, LONG y) override
     {
-        imageModel.ResetToPrevious();
-        draw(bLeftButton);
-        pointSP++;
-        if (pointSP == 4)
-            pointSP = 0;
+        pointStack[pointSP].x = x;
+        pointStack[pointSP].y = y;
+        if (pointSP >= 3)
+        {
+            OnFinishDraw();
+            return;
+        }
         imageModel.NotifyImageChanged();
     }
 
     void OnCancelDraw() override
     {
-        OnButtonUp(FALSE, 0, 0);
-        imageModel.Undo(TRUE);
+        m_bDrawing = FALSE;
         ToolBase::OnCancelDraw();
     }
 
     void OnFinishDraw() override
     {
-        if (pointSP)
-        {
-            imageModel.ResetToPrevious();
-            --pointSP;
-            draw(m_bLeftButton);
-        }
+        imageModel.PushImageForUndo();
+        OnDrawOverlayOnImage(m_hdc);
+        m_bDrawing = FALSE;
         ToolBase::OnFinishDraw();
     }
 };
 
 // TOOL_RECT
-struct RectTool : GenericDrawTool
+struct RectTool : TwoPointDrawTool
 {
-    RectTool() : GenericDrawTool(TOOL_RECT)
+    RectTool() : TwoPointDrawTool(TOOL_RECT)
     {
     }
 
-    void draw(BOOL bLeftButton, LONG x, LONG y) override
+    void OnDrawOverlayOnImage(HDC hdc) override
     {
-        imageModel.ResetToPrevious();
+        if (!m_bDrawing)
+            return;
         if (GetAsyncKeyState(VK_SHIFT) < 0)
-            regularize(start.x, start.y, x, y);
-        if (bLeftButton)
-            Rect(m_hdc, start.x, start.y, x, y, m_fg, m_bg, 
toolsModel.GetLineWidth(), toolsModel.GetShapeStyle());
+            regularize(g_ptStart.x, g_ptStart.y, g_ptEnd.x, g_ptEnd.y);
+        if (m_bLeftButton)
+            Rect(hdc, g_ptStart.x, g_ptStart.y, g_ptEnd.x, g_ptEnd.y, m_fg, 
m_bg, toolsModel.GetLineWidth(), toolsModel.GetShapeStyle());
         else
-            Rect(m_hdc, start.x, start.y, x, y, m_bg, m_fg, 
toolsModel.GetLineWidth(), toolsModel.GetShapeStyle());
+            Rect(hdc, g_ptStart.x, g_ptStart.y, g_ptEnd.x, g_ptEnd.y, m_bg, 
m_fg, toolsModel.GetLineWidth(), toolsModel.GetShapeStyle());
     }
 };
 
 // TOOL_SHAPE
 struct ShapeTool : ToolBase
 {
-    BOOL m_bLeftButton;
+    BOOL m_bLeftButton = FALSE;
+    BOOL m_bClosed = FALSE;
 
-    ShapeTool() : ToolBase(TOOL_SHAPE), m_bLeftButton(FALSE)
+    ShapeTool() : ToolBase(TOOL_SHAPE)
     {
     }
 
-    void draw(BOOL bLeftButton, LONG x, LONG y, BOOL bClosed = FALSE)
+    void OnDrawOverlayOnImage(HDC hdc)
     {
-        if (pointSP + 1 >= 2)
-        {
-            if (bLeftButton)
-                Poly(m_hdc, pointStack, pointSP + 1, m_fg, m_bg, 
toolsModel.GetLineWidth(), toolsModel.GetShapeStyle(), bClosed, FALSE);
-            else
-                Poly(m_hdc, pointStack, pointSP + 1, m_bg, m_fg, 
toolsModel.GetLineWidth(), toolsModel.GetShapeStyle(), bClosed, FALSE);
-        }
-        m_bLeftButton = bLeftButton;
+        if (pointSP <= 0)
+            return;
+
+        if (m_bLeftButton)
+            Poly(hdc, pointStack, pointSP + 1, m_fg, m_bg, 
toolsModel.GetLineWidth(), toolsModel.GetShapeStyle(), m_bClosed, FALSE);
+        else
+            Poly(hdc, pointStack, pointSP + 1, m_bg, m_fg, 
toolsModel.GetLineWidth(), toolsModel.GetShapeStyle(), m_bClosed, FALSE);
     }
 
     void OnButtonDown(BOOL bLeftButton, LONG x, LONG y, BOOL bDoubleClick) 
override
     {
+        m_bLeftButton = bLeftButton;
+        m_bClosed = FALSE;
+
         pointStack[pointSP].x = x;
         pointStack[pointSP].y = y;
 
-        if (pointSP == 0 && !bDoubleClick)
+        if (pointSP && bDoubleClick)
         {
-            imageModel.PushImageForUndo();
-            draw(bLeftButton, x, y);
-            pointSP++;
+            OnFinishDraw();
+            return;
         }
-        else
+
+        if (pointSP == 0)
         {
-            draw(bLeftButton, x, y, bDoubleClick);
-            imageModel.NotifyImageChanged();
+            pointSP++;
+            pointStack[pointSP].x = x;
+            pointStack[pointSP].y = y;
         }
+
+        imageModel.NotifyImageChanged();
     }
 
     void OnMouseMove(BOOL bLeftButton, LONG x, LONG y) override
     {
-        imageModel.ResetToPrevious();
         pointStack[pointSP].x = x;
         pointStack[pointSP].y = y;
+
         if ((pointSP > 0) && (GetAsyncKeyState(VK_SHIFT) < 0))
             roundTo8Directions(pointStack[pointSP - 1].x, pointStack[pointSP - 
1].y, x, y);
-        draw(bLeftButton, x, y, FALSE);
+
+        imageModel.NotifyImageChanged();
     }
 
     void OnButtonUp(BOOL bLeftButton, LONG x, LONG y) override
     {
-        imageModel.ResetToPrevious();
         if ((pointSP > 0) && (GetAsyncKeyState(VK_SHIFT) < 0))
             roundTo8Directions(pointStack[pointSP - 1].x, pointStack[pointSP - 
1].y, x, y);
 
+        m_bClosed = FALSE;
         if (nearlyEqualPoints(x, y, pointStack[0].x, pointStack[0].y))
         {
-            pointSP--;
-            draw(bLeftButton, x, y, TRUE);
-            pointSP = 0;
+            OnFinishDraw();
+            return;
         }
         else
         {
             pointSP++;
             pointStack[pointSP].x = x;
             pointStack[pointSP].y = y;
-            draw(bLeftButton, x, y, FALSE);
         }
 
         if (pointSP == _countof(pointStack))
             pointSP--;
+
+        imageModel.NotifyImageChanged();
     }
 
     void OnCancelDraw() override
     {
-        imageModel.Undo(TRUE);
         ToolBase::OnCancelDraw();
     }
 
@@ -696,49 +838,57 @@ struct ShapeTool : ToolBase
     {
         if (pointSP)
         {
-            imageModel.ResetToPrevious();
             --pointSP;
-            draw(m_bLeftButton, -1, -1, TRUE);
+            m_bClosed = TRUE;
+
+            imageModel.PushImageForUndo();
+            OnDrawOverlayOnImage(m_hdc);
         }
+
+        m_bClosed = FALSE;
+        pointSP = 0;
+
         ToolBase::OnFinishDraw();
     }
 };
 
 // TOOL_ELLIPSE
-struct EllipseTool : GenericDrawTool
+struct EllipseTool : TwoPointDrawTool
 {
-    EllipseTool() : GenericDrawTool(TOOL_ELLIPSE)
+    EllipseTool() : TwoPointDrawTool(TOOL_ELLIPSE)
     {
     }
 
-    void draw(BOOL bLeftButton, LONG x, LONG y) override
+    void OnDrawOverlayOnImage(HDC hdc) override
     {
-        imageModel.ResetToPrevious();
+        if (!m_bDrawing)
+            return;
         if (GetAsyncKeyState(VK_SHIFT) < 0)
-            regularize(start.x, start.y, x, y);
-        if (bLeftButton)
-            Ellp(m_hdc, start.x, start.y, x, y, m_fg, m_bg, 
toolsModel.GetLineWidth(), toolsModel.GetShapeStyle());
+            regularize(g_ptStart.x, g_ptStart.y, g_ptEnd.x, g_ptEnd.y);
+        if (m_bLeftButton)
+            Ellp(hdc, g_ptStart.x, g_ptStart.y, g_ptEnd.x, g_ptEnd.y, m_fg, 
m_bg, toolsModel.GetLineWidth(), toolsModel.GetShapeStyle());
         else
-            Ellp(m_hdc, start.x, start.y, x, y, m_bg, m_fg, 
toolsModel.GetLineWidth(), toolsModel.GetShapeStyle());
+            Ellp(hdc, g_ptStart.x, g_ptStart.y, g_ptEnd.x, g_ptEnd.y, m_bg, 
m_fg, toolsModel.GetLineWidth(), toolsModel.GetShapeStyle());
     }
 };
 
 // TOOL_RRECT
-struct RRectTool : GenericDrawTool
+struct RRectTool : TwoPointDrawTool
 {
-    RRectTool() : GenericDrawTool(TOOL_RRECT)
+    RRectTool() : TwoPointDrawTool(TOOL_RRECT)
     {
     }
 
-    void draw(BOOL bLeftButton, LONG x, LONG y) override
+    void OnDrawOverlayOnImage(HDC hdc) override
     {
-        imageModel.ResetToPrevious();
+        if (!m_bDrawing)
+            return;
         if (GetAsyncKeyState(VK_SHIFT) < 0)
-            regularize(start.x, start.y, x, y);
-        if (bLeftButton)
-            RRect(m_hdc, start.x, start.y, x, y, m_fg, m_bg, 
toolsModel.GetLineWidth(), toolsModel.GetShapeStyle());
+            regularize(g_ptStart.x, g_ptStart.y, g_ptEnd.x, g_ptEnd.y);
+        if (m_bLeftButton)
+            RRect(hdc, g_ptStart.x, g_ptStart.y, g_ptEnd.x, g_ptEnd.y, m_fg, 
m_bg, toolsModel.GetLineWidth(), toolsModel.GetShapeStyle());
         else
-            RRect(m_hdc, start.x, start.y, x, y, m_bg, m_fg, 
toolsModel.GetLineWidth(), toolsModel.GetShapeStyle());
+            RRect(hdc, g_ptStart.x, g_ptStart.y, g_ptEnd.x, g_ptEnd.y, m_bg, 
m_fg, toolsModel.GetLineWidth(), toolsModel.GetShapeStyle());
     }
 };
 
diff --git a/base/applications/mspaint/palette.cpp 
b/base/applications/mspaint/palette.cpp
index f268a982f49..39346fd5e8a 100644
--- a/base/applications/mspaint/palette.cpp
+++ b/base/applications/mspaint/palette.cpp
@@ -181,13 +181,7 @@ LRESULT CPaletteWindow::OnRButtonDblClk(UINT nMsg, WPARAM 
wParam, LPARAM lParam,
 
 LRESULT CPaletteWindow::OnPaletteModelColorChanged(UINT nMsg, WPARAM wParam, 
LPARAM lParam, BOOL& bHandled)
 {
-    InvalidateRect(NULL, FALSE);
-    return 0;
-}
-
-LRESULT CPaletteWindow::OnPaletteModelPaletteChanged(UINT nMsg, WPARAM wParam, 
LPARAM lParam, BOOL& bHandled)
-{
-    InvalidateRect(NULL, FALSE);
+    Invalidate(FALSE);
     return 0;
 }
 
diff --git a/base/applications/mspaint/palette.h 
b/base/applications/mspaint/palette.h
index fe23edda53f..63f3c4caf2b 100644
--- a/base/applications/mspaint/palette.h
+++ b/base/applications/mspaint/palette.h
@@ -27,7 +27,6 @@ public:
         MESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseMove)
         MESSAGE_HANDLER(WM_LBUTTONUP, OnLButtonUp)
         MESSAGE_HANDLER(WM_PALETTEMODELCOLORCHANGED, 
OnPaletteModelColorChanged)
-        MESSAGE_HANDLER(WM_PALETTEMODELPALETTECHANGED, 
OnPaletteModelPaletteChanged)
     END_MSG_MAP()
 
     CPaletteWindow();
@@ -45,7 +44,6 @@ protected:
     LRESULT OnMouseMove(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& 
bHandled);
     LRESULT OnLButtonUp(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& 
bHandled);
     LRESULT OnPaletteModelColorChanged(UINT nMsg, WPARAM wParam, LPARAM 
lParam, BOOL& bHandled);
-    LRESULT OnPaletteModelPaletteChanged(UINT nMsg, WPARAM wParam, LPARAM 
lParam, BOOL& bHandled);
 
 protected:
     INT DoHitTest(INT xPos, INT yPos) const;
diff --git a/base/applications/mspaint/palettemodel.cpp 
b/base/applications/mspaint/palettemodel.cpp
index 8d18449fbee..a07825e4762 100644
--- a/base/applications/mspaint/palettemodel.cpp
+++ b/base/applications/mspaint/palettemodel.cpp
@@ -106,5 +106,5 @@ void PaletteModel::NotifyColorChanged()
 void PaletteModel::NotifyPaletteChanged()
 {
     if (paletteWindow.IsWindow())
-        paletteWindow.SendMessage(WM_PALETTEMODELPALETTECHANGED);
+        paletteWindow.Invalidate(FALSE);
 }
diff --git a/base/applications/mspaint/selectionmodel.cpp 
b/base/applications/mspaint/selectionmodel.cpp
index d70f324d805..9497cef153f 100644
--- a/base/applications/mspaint/selectionmodel.cpp
+++ b/base/applications/mspaint/selectionmodel.cpp
@@ -21,6 +21,7 @@ SelectionModel::SelectionModel()
     , m_bShow(FALSE)
 {
     ::SetRectEmpty(&m_rc);
+    ::SetRectEmpty(&m_rcOld);
     m_ptHit.x = m_ptHit.y = -1;
 }
 
@@ -57,25 +58,13 @@ void SelectionModel::PushToPtStack(POINT pt)
 #undef GROW_COUNT
 }
 
-void SelectionModel::ShiftPtStack(BOOL bPlus)
+void SelectionModel::ShiftPtStack(INT dx, INT dy)
 {
-    if (bPlus)
-    {
-        for (INT i = 0; i < m_iPtSP; ++i)
-        {
-            POINT& pt = m_ptStack[i];
-            pt.x += m_rc.left;
-            pt.y += m_rc.top;
-        }
-    }
-    else
+    for (INT i = 0; i < m_iPtSP; ++i)
     {
-        for (INT i = 0; i < m_iPtSP; ++i)
-        {
-            POINT& pt = m_ptStack[i];
-            pt.x -= m_rc.left;
-            pt.y -= m_rc.top;
-        }
+        POINT& pt = m_ptStack[i];
+        pt.x += dx;
+        pt.y += dy;
     }
 }
 
@@ -93,16 +82,16 @@ void SelectionModel::BuildMaskFromPtStack()
     rc.right += 1;
     rc.bottom += 1;
 
-    m_rc = rc;
-
-    ShiftPtStack(FALSE);
+    m_rc = m_rcOld = rc;
 
     ClearMask();
 
+    ShiftPtStack(-m_rcOld.left, -m_rcOld.top);
+
     HDC hdcMem = ::CreateCompatibleDC(NULL);
     m_hbmMask = ::CreateBitmap(rc.Width(), rc.Height(), 1, 1, NULL);
     HGDIOBJ hbmOld = ::SelectObject(hdcMem, m_hbmMask);
-    FillRect(hdcMem, &rc, (HBRUSH)::GetStockObject(BLACK_BRUSH));
+    ::FillRect(hdcMem, &rc, (HBRUSH)::GetStockObject(BLACK_BRUSH));
     HGDIOBJ hPenOld = ::SelectObject(hdcMem, GetStockObject(NULL_PEN));
     HGDIOBJ hbrOld = ::SelectObject(hdcMem, GetStockObject(WHITE_BRUSH));
     ::Polygon(hdcMem, m_ptStack, m_iPtSP);
@@ -110,34 +99,39 @@ void SelectionModel::BuildMaskFromPtStack()
     ::SelectObject(hdcMem, hPenOld);
     ::SelectObject(hdcMem, hbmOld);
     ::DeleteDC(hdcMem);
+
+    ShiftPtStack(+m_rcOld.left, +m_rcOld.top);
 }
 
 void SelectionModel::DrawBackgroundPoly(HDC hDCImage, COLORREF crBg)
 {
-    ShiftPtStack(TRUE);
+    if (::IsRectEmpty(&m_rcOld))
+        return;
 
     HGDIOBJ hPenOld = ::SelectObject(hDCImage, ::GetStockObject(NULL_PEN));
     HGDIOBJ hbrOld = ::SelectObject(hDCImage, ::CreateSolidBrush(crBg));
     ::Polygon(hDCImage, m_ptStack, m_iPtSP);
     ::DeleteObject(::SelectObject(hDCImage, hbrOld));
     ::SelectObject(hDCImage, hPenOld);
-
-    ShiftPtStack(FALSE);
 }
 
 void SelectionModel::DrawBackgroundRect(HDC hDCImage, COLORREF crBg)
 {
-    Rect(hDCImage, m_rc.left, m_rc.top, m_rc.right, m_rc.bottom, crBg, crBg, 
0, 1);
+    if (::IsRectEmpty(&m_rcOld))
+        return;
+
+    Rect(hDCImage, m_rcOld.left, m_rcOld.top, m_rcOld.right, m_rcOld.bottom, 
crBg, crBg, 0, 1);
 }
 
-void SelectionModel::DrawSelection(HDC hDCImage, LPCRECT prc, COLORREF crBg, 
BOOL bBgTransparent)
+void SelectionModel::DrawSelection(HDC hDCImage, COLORREF crBg, BOOL 
bBgTransparent)
 {
-    CRect rc = *prc;
+    CRect rc = m_rc;
     if (::IsRectEmpty(&rc))
         return;
 
     BITMAP bm;
-    GetObject(m_hbmColor, sizeof(BITMAP), &bm);
+    if (!GetObject(m_hbmColor, sizeof(BITMAP), &bm))
+        return;
 
     COLORREF keyColor = (bBgTransparent ? crBg : CLR_INVALID);
 
@@ -161,23 +155,23 @@ void SelectionModel::GetSelectionContents(HDC hDCImage)
     ::DeleteDC(hMemDC);
 }
 
+BOOL SelectionModel::IsLanded() const
+{
+    return !m_hbmColor;
+}
+
 BOOL SelectionModel::TakeOff()
 {
-    if (m_hbmColor || ::IsRectEmpty(&m_rc))
+    if (!IsLanded() || ::IsRectEmpty(&m_rc))
         return FALSE;
 
-    HDC hDCImage = imageModel.GetDC();
-    GetSelectionContents(hDCImage);
+    m_rgbBack = paletteModel.GetBgColor();
+    GetSelectionContents(imageModel.GetDC());
 
-    if (toolsModel.GetActiveTool() == TOOL_FREESEL)
-    {
-        DrawBackgroundPoly(hDCImage, paletteModel.GetBgColor());
-    }
-    else
-    {
+    if (toolsModel.GetActiveTool() == TOOL_RECTSEL)
         ClearMask();
-        DrawBackgroundRect(hDCImage, paletteModel.GetBgColor());
-    }
+
+    m_rcOld = m_rc;
 
     imageModel.NotifyImageChanged();
     return TRUE;
@@ -185,16 +179,23 @@ BOOL SelectionModel::TakeOff()
 
 void SelectionModel::Landing()
 {
-    if (!m_hbmColor)
+    if (IsLanded() && !m_bShow)
+    {
+        imageModel.NotifyImageChanged();
         return;
+    }
 
-    DrawSelection(imageModel.GetDC(), &m_rc, paletteModel.GetBgColor(), 
toolsModel.IsBackgroundTransparent());
+    m_bShow = FALSE;
 
-    ::SetRectEmpty(&m_rc);
-    ClearMask();
-    ClearColor();
+    if (!::EqualRect(m_rc, m_rcOld) && !::IsRectEmpty(m_rc) && 
!::IsRectEmpty(m_rcOld))
+    {
+        imageModel.PushImageForUndo();
 
-    imageModel.PushImageForUndo();
+        canvasWindow.m_drawing = FALSE;
+        toolsModel.OnDrawOverlayOnImage(imageModel.GetDC());
+    }
+
+    HideSelection();
 }
 
 void SelectionModel::InsertFromHBITMAP(HBITMAP hBm, INT x, INT y)
@@ -349,11 +350,11 @@ void SelectionModel::StretchSkew(int nStretchPercentX, 
int nStretchPercentY, int
     imageModel.NotifyImageChanged();
 }
 
-HBITMAP SelectionModel::GetBitmap()
+HBITMAP SelectionModel::CopyBitmap()
 {
     if (m_hbmColor == NULL)
         GetSelectionContents(imageModel.GetDC());
-    return m_hbmColor;
+    return CopyDIBImage(m_hbmColor);
 }
 
 int SelectionModel::PtStackSize() const
@@ -435,15 +436,29 @@ void SelectionModel::ClearColor()
     }
 }
 
-void SelectionModel::CancelSelection()
+void SelectionModel::HideSelection()
+{
+    m_bShow = FALSE;
+    ClearColor();
+    ClearMask();
+    ::SetRectEmpty(&m_rc);
+    ::SetRectEmpty(&m_rcOld);
+
+    imageModel.NotifyImageChanged();
+}
+
+void SelectionModel::DeleteSelection()
 {
     if (!m_bShow)
         return;
 
+    TakeOff();
+
     imageModel.PushImageForUndo();
-    if (m_bShow)
-        imageModel.Undo(TRUE);
+    if (toolsModel.GetActiveTool() == TOOL_FREESEL)
+        DrawBackgroundPoly(imageModel.GetDC(), paletteModel.GetBgColor());
+    else
+        DrawBackgroundRect(imageModel.GetDC(), paletteModel.GetBgColor());
 
-    m_bShow = FALSE;
-    imageModel.NotifyImageChanged();
+    HideSelection();
 }
diff --git a/base/applications/mspaint/selectionmodel.h 
b/base/applications/mspaint/selectionmodel.h
index 01a21c7bc62..f68a740d18f 100644
--- a/base/applications/mspaint/selectionmodel.h
+++ b/base/applications/mspaint/selectionmodel.h
@@ -18,9 +18,11 @@ private:
     int m_iPtSP;
 
 public:
+    COLORREF m_rgbBack = RGB(255, 255, 255);
     BOOL m_bShow;
     CRect m_rc;    // in image pixel coordinates
     POINT m_ptHit; // in image pixel coordinates
+    CRect m_rcOld; // in image pixel coordinates
 
     SelectionModel();
     ~SelectionModel();
@@ -33,13 +35,16 @@ public:
 
     BOOL TakeOff();
     void Landing();
+    BOOL IsLanded() const;
+    void HideSelection();
+    void DeleteSelection();
 
-    HBITMAP GetBitmap();
+    HBITMAP CopyBitmap();
     void GetSelectionContents(HDC hDCImage);
     void DrawFramePoly(HDC hDCImage);
     void DrawBackgroundPoly(HDC hDCImage, COLORREF crBg);
     void DrawBackgroundRect(HDC hDCImage, COLORREF crBg);
-    void DrawSelection(HDC hDCImage, LPCRECT prc, COLORREF crBg = 0, BOOL 
bBgTransparent = FALSE);
+    void DrawSelection(HDC hDCImage, COLORREF crBg = 0, BOOL bBgTransparent = 
FALSE);
     void InsertFromHBITMAP(HBITMAP hBm, INT x = 0, INT y = 0);
 
     // operation
@@ -48,7 +53,6 @@ public:
     void RotateNTimes90Degrees(int iN);
     void StretchSkew(int nStretchPercentX, int nStretchPercentY, int 
nSkewDegX, int nSkewDegY);
 
-    void CancelSelection();
     void Dragging(CANVAS_HITTEST hit, POINT pt);
     void ClearMask();
     void ClearColor();
@@ -57,5 +61,5 @@ private:
     SelectionModel(const SelectionModel&);
     SelectionModel& operator=(const SelectionModel&);
 
-    void ShiftPtStack(BOOL bPlus);
+    void ShiftPtStack(INT dx, INT dy);
 };
diff --git a/base/applications/mspaint/textedit.cpp 
b/base/applications/mspaint/textedit.cpp
index 3b679c61272..bf0ab2ce4fb 100644
--- a/base/applications/mspaint/textedit.cpp
+++ b/base/applications/mspaint/textedit.cpp
@@ -61,7 +61,7 @@ void CTextEditWindow::FixEditPos(LPCTSTR pszOldText)
         SelectObject(hDC, m_hFontZoomed);
         TEXTMETRIC tm;
         GetTextMetrics(hDC, &tm);
-        szText += TEXT("x"); // This is a trick to enable the last newlines
+        szText += TEXT("x"); // This is a trick to enable the g_ptEnd newlines
         const UINT uFormat = DT_LEFT | DT_TOP | DT_EDITCONTROL | DT_NOPREFIX | 
DT_NOCLIP |
                              DT_EXPANDTABS | DT_WORDBREAK;
         DrawText(hDC, szText, -1, &rcText, uFormat | DT_CALCRECT);
@@ -235,7 +235,7 @@ HWND CTextEditWindow::Create(HWND hwndParent)
     const DWORD style = ES_LEFT | ES_MULTILINE | ES_WANTRETURN | 
ES_AUTOVSCROLL |
                         WS_CHILD | WS_THICKFRAME;
     HWND hwnd = ::CreateWindowEx(0, WC_EDIT, NULL, style, 0, 0, 0, 0,
-                                 hwndParent, NULL, hProgInstance, NULL);
+                                 hwndParent, NULL, g_hinstExe, NULL);
     if (hwnd)
     {
 #undef SubclassWindow // Don't use this macro
diff --git a/base/applications/mspaint/toolbox.cpp 
b/base/applications/mspaint/toolbox.cpp
index 7e772a5bb6c..236ab9a4ba5 100644
--- a/base/applications/mspaint/toolbox.cpp
+++ b/base/applications/mspaint/toolbox.cpp
@@ -13,6 +13,20 @@ CToolBox toolBoxContainer;
 
 /* FUNCTIONS ********************************************************/
 
+LRESULT CALLBACK
+CPaintToolBar::ToolBarWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM 
lParam)
+{
+    WNDPROC oldWndProc = (WNDPROC)::GetWindowLongPtr(hwnd, GWLP_USERDATA);
+    if (uMsg == WM_LBUTTONUP)
+    {
+        // We have to detect clicking on toolbar even if no change of pressed 
button
+        POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
+        INT id = (INT)SendMessage(hwnd, TB_HITTEST, 0, (LPARAM)&pt);
+        ::PostMessage(::GetParent(hwnd), WM_TOOLBARHIT, id, 0);
+    }
+    return ::CallWindowProc(oldWndProc, hwnd, uMsg, wParam, lParam);
+}
+
 BOOL CPaintToolBar::DoCreate(HWND hwndParent)
 {
     // NOTE: The horizontal line above the toolbar is hidden by CCS_NODIVIDER 
style.
@@ -25,7 +39,7 @@ BOOL CPaintToolBar::DoCreate(HWND hwndParent)
     HIMAGELIST hImageList = ImageList_Create(16, 16, ILC_COLOR24 | ILC_MASK, 
16, 0);
     SendMessage(TB_SETIMAGELIST, 0, (LPARAM)hImageList);
 
-    HBITMAP hbmIcons = (HBITMAP)::LoadImage(hProgInstance, 
MAKEINTRESOURCE(IDB_TOOLBARICONS),
+    HBITMAP hbmIcons = (HBITMAP)::LoadImage(g_hinstExe, 
MAKEINTRESOURCE(IDB_TOOLBARICONS),
                                             IMAGE_BITMAP, 256, 16, 0);
     ImageList_AddMasked(hImageList, hbmIcons, RGB(255, 0, 255));
     ::DeleteObject(hbmIcons);
@@ -38,7 +52,7 @@ BOOL CPaintToolBar::DoCreate(HWND hwndParent)
     tbbutton.fsStyle = TBSTYLE_CHECKGROUP;
     for (INT i = 0; i < NUM_TOOLS; i++)
     {
-        ::LoadString(hProgInstance, IDS_TOOLTIP1 + i, szToolTip, 
_countof(szToolTip));
+        ::LoadString(g_hinstExe, IDS_TOOLTIP1 + i, szToolTip, 
_countof(szToolTip));
         tbbutton.iString   = (INT_PTR)szToolTip;
         tbbutton.fsState   = TBSTATE_ENABLED | ((i % 2 == 1) ? TBSTATE_WRAP : 
0);
         tbbutton.idCommand = ID_FREESEL + i;
@@ -49,6 +63,8 @@ BOOL CPaintToolBar::DoCreate(HWND hwndParent)
     SendMessage(TB_CHECKBUTTON, ID_PEN, MAKELPARAM(TRUE, 0));
     SendMessage(TB_SETMAXTEXTROWS, 0, 0);
     SendMessage(TB_SETBUTTONSIZE, 0, MAKELPARAM(CXY_TB_BUTTON, CXY_TB_BUTTON));
+
+    SetWindowLongPtr(GWLP_USERDATA, SetWindowLongPtr(GWLP_WNDPROC, 
(LONG_PTR)ToolBarWndProc));
     return TRUE;
 }
 
@@ -114,7 +130,7 @@ LRESULT CToolBox::OnCommand(UINT nMsg, WPARAM wParam, 
LPARAM lParam, BOOL& bHand
 
 LRESULT CToolBox::OnToolsModelToolChanged(UINT nMsg, WPARAM wParam, LPARAM 
lParam, BOOL& bHandled)
 {
-    selectionModel.m_bShow = FALSE;
+    selectionModel.HideSelection();
     toolsModel.resetTool(); // resets the point-buffer of the polygon and 
bezier functions
 
     // Check the toolbar button
@@ -168,3 +184,10 @@ LRESULT CToolBox::OnLButtonUp(UINT nMsg, WPARAM wParam, 
LPARAM lParam, BOOL& bHa
     ::ReleaseCapture();
     return 0;
 }
+
+LRESULT CToolBox::OnToolBarHit(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& 
bHandled)
+{
+    // See also: CPaintToolBar::ToolBarWndProc
+    selectionModel.Landing();
+    return 0;
+}
diff --git a/base/applications/mspaint/toolbox.h 
b/base/applications/mspaint/toolbox.h
index bd0a635636a..33cfe5eb702 100644
--- a/base/applications/mspaint/toolbox.h
+++ b/base/applications/mspaint/toolbox.h
@@ -15,10 +15,13 @@
 #define CX_TOOLBAR          (TOOLBAR_COLUMNS * CXY_TB_BUTTON)
 #define CY_TOOLBAR          (TOOLBAR_ROWS * CXY_TB_BUTTON)
 
+#define WM_TOOLBARHIT   (WM_APP + 1)
+
 class CPaintToolBar : public CWindow
 {
 public:
     BOOL DoCreate(HWND hwndParent);
+    static LRESULT CALLBACK ToolBarWndProc(HWND hwnd, UINT uMsg, WPARAM 
wParam, LPARAM lParam);
 };
 
 class CToolBox : public CWindowImpl<CToolBox>
@@ -34,6 +37,7 @@ public:
         MESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseMove)
         MESSAGE_HANDLER(WM_LBUTTONUP, OnLButtonUp)
         MESSAGE_HANDLER(WM_TOOLSMODELTOOLCHANGED, OnToolsModelToolChanged)
+        MESSAGE_HANDLER(WM_TOOLBARHIT, OnToolBarHit)
     END_MSG_MAP()
 
     BOOL DoCreate(HWND hwndParent);
@@ -48,4 +52,5 @@ private:
     LRESULT OnMouseMove(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& 
bHandled);
     LRESULT OnLButtonUp(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& 
bHandled);
     LRESULT OnToolsModelToolChanged(UINT nMsg, WPARAM wParam, LPARAM lParam, 
BOOL& bHandled);
+    LRESULT OnToolBarHit(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& 
bHandled);
 };
diff --git a/base/applications/mspaint/toolsettings.cpp 
b/base/applications/mspaint/toolsettings.cpp
index 323956ba7ca..97008c07563 100644
--- a/base/applications/mspaint/toolsettings.cpp
+++ b/base/applications/mspaint/toolsettings.cpp
@@ -200,11 +200,14 @@ VOID CToolSettingsWindow::drawAirBrush(HDC hdc, LPCRECT 
prc)
         if (bHigh)
         {
             ::FillRect(hdc, &rc, ::GetSysColorBrush(COLOR_HIGHLIGHT));
-            Airbrush(hdc, x, y, ::GetSysColor(COLOR_HIGHLIGHTTEXT), 
s_AirRadius[i]);
+
+            for (int k = 0; k < 3; ++k)
+                Airbrush(hdc, x, y, ::GetSysColor(COLOR_HIGHLIGHTTEXT), 
s_AirRadius[i]);
         }
         else
         {
-            Airbrush(hdc, x, y, ::GetSysColor(COLOR_WINDOWTEXT), 
s_AirRadius[i]);
+            for (int k = 0; k < 3; ++k)
+                Airbrush(hdc, x, y, ::GetSysColor(COLOR_WINDOWTEXT), 
s_AirRadius[i]);
         }
     }
 }
@@ -258,9 +261,9 @@ VOID CToolSettingsWindow::drawBox(HDC hdc, LPCRECT prc)
 LRESULT CToolSettingsWindow::OnCreate(UINT nMsg, WPARAM wParam, LPARAM lParam, 
WINBOOL& bHandled)
 {
     /* preloading the draw transparent/nontransparent icons for later use */
-    m_hNontranspIcon = (HICON)LoadImage(hProgInstance, 
MAKEINTRESOURCE(IDI_NONTRANSPARENT),
+    m_hNontranspIcon = (HICON)LoadImage(g_hinstExe, 
MAKEINTRESOURCE(IDI_NONTRANSPARENT),
                                         IMAGE_ICON, CX_TRANS_ICON, 
CY_TRANS_ICON, LR_DEFAULTCOLOR);
-    m_hTranspIcon = (HICON)LoadImage(hProgInstance, 
MAKEINTRESOURCE(IDI_TRANSPARENT),
+    m_hTranspIcon = (HICON)LoadImage(g_hinstExe, 
MAKEINTRESOURCE(IDI_TRANSPARENT),
                                      IMAGE_ICON, CX_TRANS_ICON, CY_TRANS_ICON, 
LR_DEFAULTCOLOR);
 
     RECT trackbarZoomPos = {1, 1, 1 + 40, 1 + 64};
diff --git a/base/applications/mspaint/toolsmodel.cpp 
b/base/applications/mspaint/toolsmodel.cpp
index 822547048f7..76a123513b5 100644
--- a/base/applications/mspaint/toolsmodel.cpp
+++ b/base/applications/mspaint/toolsmodel.cpp
@@ -28,7 +28,7 @@ ToolsModel::ToolsModel()
 
 ToolsModel::~ToolsModel()
 {
-    for (size_t i = 0; i < TOOL_MAX + 1; ++i)
+    for (size_t i = 0; i < _countof(m_tools); ++i)
         delete m_tools[i];
 }
 
@@ -87,9 +87,6 @@ void ToolsModel::SetActiveTool(TOOLTYPE nActiveTool)
 {
     OnFinishDraw();
 
-    if (m_activeTool == nActiveTool)
-        return;
-
     switch (m_activeTool)
     {
         case TOOL_FREESEL:
@@ -225,6 +222,16 @@ void ToolsModel::OnFinishDraw()
     m_pToolObject->endEvent();
 }
 
+void ToolsModel::OnDrawOverlayOnImage(HDC hdc)
+{
+    m_pToolObject->OnDrawOverlayOnImage(hdc);
+}
+
+void ToolsModel::OnDrawOverlayOnCanvas(HDC hdc)
+{
+    m_pToolObject->OnDrawOverlayOnCanvas(hdc);
+}
+
 void ToolsModel::resetTool()
 {
     m_pToolObject->reset();
diff --git a/base/applications/mspaint/toolsmodel.h 
b/base/applications/mspaint/toolsmodel.h
index da0e06cfa2f..b8c819590a7 100644
--- a/base/applications/mspaint/toolsmodel.h
+++ b/base/applications/mspaint/toolsmodel.h
@@ -39,34 +39,27 @@ struct ToolBase
     static INT pointSP;
     static POINT pointStack[256];
 
-    ToolBase(TOOLTYPE tool) : m_tool(tool), m_hdc(NULL)
-    {
-    }
+    ToolBase(TOOLTYPE tool) : m_tool(tool), m_hdc(NULL) { }
+    virtual ~ToolBase() { }
 
-    virtual ~ToolBase()
-    {
-    }
-
-    virtual void OnButtonDown(BOOL bLeftButton, LONG x, LONG y, BOOL 
bDoubleClick)
-    {
-    }
-
-    virtual void OnMouseMove(BOOL bLeftButton, LONG x, LONG y)
-    {
-    }
-
-    virtual void OnButtonUp(BOOL bLeftButton, LONG x, LONG y)
-    {
-    }
+    virtual void OnButtonDown(BOOL bLeftButton, LONG x, LONG y, BOOL 
bDoubleClick) { }
+    virtual void OnMouseMove(BOOL bLeftButton, LONG x, LONG y) { }
+    virtual void OnButtonUp(BOOL bLeftButton, LONG x, LONG y) { }
 
     virtual void OnCancelDraw();
     virtual void OnFinishDraw();
 
+    virtual void OnDrawOverlayOnImage(HDC hdc) { }
+    virtual void OnDrawOverlayOnCanvas(HDC hdc) { }
+
     void beginEvent();
     void endEvent();
     void reset();
 
     static ToolBase* createToolObject(TOOLTYPE type);
+
+protected:
+    void OnDrawSelectionOnCanvas(HDC hdc);
 };
 
 class ToolsModel
@@ -112,6 +105,8 @@ public:
     void OnButtonUp(BOOL bLeftButton, LONG x, LONG y);
     void OnCancelDraw();
     void OnFinishDraw();
+    void OnDrawOverlayOnImage(HDC hdc);
+    void OnDrawOverlayOnCanvas(HDC hdc);
 
     void resetTool();
     void selectAll();
diff --git a/base/applications/mspaint/winproc.cpp 
b/base/applications/mspaint/winproc.cpp
index c3cc041ebe8..29bc32b9327 100644
--- a/base/applications/mspaint/winproc.cpp
+++ b/base/applications/mspaint/winproc.cpp
@@ -17,7 +17,7 @@ typedef HWND (WINAPI *FN_HtmlHelpW)(HWND, LPCWSTR, UINT, 
DWORD_PTR);
 static HINSTANCE s_hHHCTRL_OCX = NULL; // HtmlHelpW needs "hhctrl.ocx"
 static FN_HtmlHelpW s_pHtmlHelpW = NULL;
 
-HWND hStatusBar = NULL;
+HWND g_hStatusBar = NULL;
 
 /* FUNCTIONS ********************************************************/
 
@@ -79,9 +79,9 @@ void CMainWindow::alignChildrenToMainWindow()
     GetClientRect(&clientRect);
     RECT rcSpace = clientRect;
 
-    if (::IsWindowVisible(hStatusBar))
+    if (::IsWindowVisible(g_hStatusBar))
     {
-        ::GetWindowRect(hStatusBar, &rc);
+        ::GetWindowRect(g_hStatusBar, &rc);
         rcSpace.bottom -= rc.bottom - rc.top;
     }
 
@@ -142,18 +142,18 @@ void CMainWindow::saveImage(BOOL overwrite)
 {
     canvasWindow.finishDrawing();
 
-    if (isAFile && overwrite)
+    if (g_isAFile && overwrite)
     {
-        imageModel.SaveImage(filepathname);
+        imageModel.SaveImage(g_szFileName);
     }
-    else if (GetSaveFileName(filepathname, _countof(filepathname)))
+    else if (GetSaveFileName(g_szFileName, _countof(g_szFileName)))
     {
-        imageModel.SaveImage(filepathname);
+        imageModel.SaveImage(g_szFileName);
 
         CString strTitle;
-        strTitle.Format(IDS_WINDOWTITLE, PathFindFileName(filepathname));
+        strTitle.Format(IDS_WINDOWTITLE, PathFindFileName(g_szFileName));
         SetWindowText(strTitle);
-        isAFile = TRUE;
+        g_isAFile = TRUE;
     }
 }
 
@@ -168,13 +168,13 @@ void CMainWindow::InsertSelectionFromHBITMAP(HBITMAP 
bitmap, HWND window)
     {
         BOOL shouldEnlarge = TRUE;
 
-        if (askBeforeEnlarging)
+        if (g_askBeforeEnlarging)
         {
             TCHAR programname[20];
             TCHAR shouldEnlargePromptText[100];
 
-            LoadString(hProgInstance, IDS_PROGRAMNAME, programname, 
_countof(programname));
-            LoadString(hProgInstance, IDS_ENLARGEPROMPTTEXT, 
shouldEnlargePromptText, _countof(shouldEnlargePromptText));
+            LoadString(g_hinstExe, IDS_PROGRAMNAME, programname, 
_countof(programname));
+            LoadString(g_hinstExe, IDS_ENLARGEPROMPTTEXT, 
shouldEnlargePromptText, _countof(shouldEnlargePromptText));
 
             switch (MessageBox(shouldEnlargePromptText, programname, 
MB_YESNOCANCEL | MB_ICONQUESTION))
             {
@@ -276,14 +276,14 @@ LRESULT CMainWindow::OnDropFiles(UINT nMsg, WPARAM 
wParam, LPARAM lParam, BOOL&
 LRESULT CMainWindow::OnCreate(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& 
bHandled)
 {
     // Loading and setting the window menu from resource
-    m_hMenu = ::LoadMenu(hProgInstance, MAKEINTRESOURCE(ID_MENU));
+    m_hMenu = ::LoadMenu(g_hinstExe, MAKEINTRESOURCE(ID_MENU));
     SetMenu(m_hMenu);
 
     // Create the status bar
     DWORD style = SBARS_SIZEGRIP | WS_CHILD | (registrySettings.ShowStatusBar 
? WS_VISIBLE : 0);
-    hStatusBar = ::CreateWindowEx(0, STATUSCLASSNAME, NULL, style, 0, 0, 0, 0, 
m_hWnd,
-                                  NULL, hProgInstance, NULL);
-    ::SendMessage(hStatusBar, SB_SETMINHEIGHT, 21, 0);
+    g_hStatusBar = ::CreateWindowEx(0, STATUSCLASSNAME, NULL, style, 0, 0, 0, 
0, m_hWnd,
+                                  NULL, g_hinstExe, NULL);
+    ::SendMessage(g_hStatusBar, SB_SETMINHEIGHT, 21, 0);
 
     // Create the tool box
     toolBoxContainer.DoCreate(m_hWnd);
@@ -305,8 +305,8 @@ LRESULT CMainWindow::OnCreate(UINT nMsg, WPARAM wParam, 
LPARAM lParam, BOOL& bHa
     }
 
     // Set icon
-    SendMessage(WM_SETICON, ICON_BIG, (LPARAM) LoadIcon(hProgInstance, 
MAKEINTRESOURCE(IDI_APPICON)));
-    SendMessage(WM_SETICON, ICON_SMALL, (LPARAM) LoadIcon(hProgInstance, 
MAKEINTRESOURCE(IDI_APPICON)));
+    SendMessage(WM_SETICON, ICON_BIG, (LPARAM) LoadIcon(g_hinstExe, 
MAKEINTRESOURCE(IDI_APPICON)));
+    SendMessage(WM_SETICON, ICON_SMALL, (LPARAM) LoadIcon(g_hinstExe, 
MAKEINTRESOURCE(IDI_APPICON)));
 
     return 0;
 }
@@ -347,7 +347,7 @@ BOOL CMainWindow::ConfirmSave()
     strProgramName.LoadString(IDS_PROGRAMNAME);
 
     CString strSavePromptText;
-    strSavePromptText.Format(IDS_SAVEPROMPTTEXT, 
PathFindFileName(filepathname));
+    strSavePromptText.Format(IDS_SAVEPROMPTTEXT, 
PathFindFileName(g_szFileName));
 
     switch (MessageBox(strSavePromptText, strProgramName, MB_YESNOCANCEL | 
MB_ICONQUESTION))
     {
@@ -374,7 +374,7 @@ LRESULT CMainWindow::OnClose(UINT nMsg, WPARAM wParam, 
LPARAM lParam, BOOL& bHan
 
 void CMainWindow::ProcessFileMenu(HMENU hPopupMenu)
 {
-    LPCTSTR dotext = PathFindExtensionW(filepathname);
+    LPCTSTR dotext = PathFindExtensionW(g_szFileName);
     BOOL isBMP = FALSE;
     if (_tcsicmp(dotext, _T(".bmp")) == 0 ||
         _tcsicmp(dotext, _T(".dib")) == 0 ||
@@ -383,9 +383,9 @@ void CMainWindow::ProcessFileMenu(HMENU hPopupMenu)
         isBMP = TRUE;
     }
 
-    EnableMenuItem(hPopupMenu, IDM_FILEASWALLPAPERPLANE,     
ENABLED_IF(isAFile && isBMP));
-    EnableMenuItem(hPopupMenu, IDM_FILEASWALLPAPERCENTERED,  
ENABLED_IF(isAFile && isBMP));
-    EnableMenuItem(hPopupMenu, IDM_FILEASWALLPAPERSTRETCHED, 
ENABLED_IF(isAFile && isBMP));
+    EnableMenuItem(hPopupMenu, IDM_FILEASWALLPAPERPLANE,     
ENABLED_IF(g_isAFile && isBMP));
+    EnableMenuItem(hPopupMenu, IDM_FILEASWALLPAPERCENTERED,  
ENABLED_IF(g_isAFile && isBMP));
+    EnableMenuItem(hPopupMenu, IDM_FILEASWALLPAPERSTRETCHED, 
ENABLED_IF(g_isAFile && isBMP));
 
     for (INT iItem = 0; iItem < MAX_RECENT_FILES; ++iItem)
         RemoveMenu(hPopupMenu, IDM_FILE1 + iItem, MF_BYCOMMAND);
@@ -445,11 +445,11 @@ LRESULT CMainWindow::OnInitMenuPopup(UINT nMsg, WPARAM 
wParam, LPARAM lParam, BO
         case 2: /* View menu */
             CheckMenuItem(menu, IDM_VIEWTOOLBOX, 
CHECKED_IF(::IsWindowVisible(toolBoxContainer)));
             CheckMenuItem(menu, IDM_VIEWCOLORPALETTE, 
CHECKED_IF(::IsWindowVisible(paletteWindow)));
-            CheckMenuItem(menu, IDM_VIEWSTATUSBAR,    
CHECKED_IF(::IsWindowVisible(hStatusBar)));
+            CheckMenuItem(menu, IDM_VIEWSTATUSBAR,    
CHECKED_IF(::IsWindowVisible(g_hStatusBar)));
             CheckMenuItem(menu, IDM_FORMATICONBAR, 
CHECKED_IF(::IsWindowVisible(fontsDialog)));
             EnableMenuItem(menu, IDM_FORMATICONBAR, 
ENABLED_IF(toolsModel.GetActiveTool() == TOOL_TEXT));
 
-            CheckMenuItem(menu, IDM_VIEWSHOWGRID,      CHECKED_IF(showGrid));
+            CheckMenuItem(menu, IDM_VIEWSHOWGRID,      CHECKED_IF(g_showGrid));
             CheckMenuItem(menu, IDM_VIEWSHOWMINIATURE, 
CHECKED_IF(registrySettings.ShowThumbnail));
             break;
         case 3: /* Image menu */
@@ -474,10 +474,10 @@ LRESULT CMainWindow::OnInitMenuPopup(UINT nMsg, WPARAM 
wParam, LPARAM lParam, BO
 LRESULT CMainWindow::OnSize(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& 
bHandled)
 {
     int test[] = { LOWORD(lParam) - 260, LOWORD(lParam) - 140, LOWORD(lParam) 
- 20 };
-    if (::IsWindow(hStatusBar))
+    if (::IsWindow(g_hStatusBar))
     {
-        ::SendMessage(hStatusBar, WM_SIZE, 0, 0);
-        ::SendMessage(hStatusBar, SB_SETPARTS, 3, (LPARAM)&test);
+        ::SendMessage(g_hStatusBar, WM_SIZE, 0, 0);
+        ::SendMessage(g_hStatusBar, SB_SETPARTS, 3, (LPARAM)&test);
     }
     alignChildrenToMainWindow();
     return 0;
@@ -508,9 +508,11 @@ LRESULT CMainWindow::OnKeyDown(UINT nMsg, WPARAM wParam, 
LPARAM lParam, BOOL& bH
             }
             else if (selectionModel.m_bShow)
             {
-                selectionModel.Landing();
-                selectionModel.m_bShow = FALSE;
-                imageModel.NotifyImageChanged();
+                selectionModel.HideSelection();
+            }
+            else
+            {
+                canvasWindow.cancelDrawing();
             }
             break;
 
@@ -551,11 +553,11 @@ LRESULT CMainWindow::OnCommand(UINT nMsg, WPARAM wParam, 
LPARAM lParam, BOOL& bH
     {
         case IDM_HELPINFO:
         {
-            HICON paintIcon = LoadIcon(hProgInstance, 
MAKEINTRESOURCE(IDI_APPICON));
+            HICON paintIcon = LoadIcon(g_hinstExe, 
MAKEINTRESOURCE(IDI_APPICON));
             TCHAR infotitle[100];
             TCHAR infotext[200];
-            LoadString(hProgInstance, IDS_INFOTITLE, infotitle, 
_countof(infotitle));
-            LoadString(hProgInstance, IDS_INFOTEXT, infotext, 
_countof(infotext));
+            LoadString(g_hinstExe, IDS_INFOTITLE, infotitle, 
_countof(infotitle));
+            LoadString(g_hinstExe, IDS_INFOTEXT, infotext, _countof(infotext));
             ShellAbout(m_hWnd, infotitle, infotext, paintIcon);
             DeleteObject(paintIcon);
             break;
@@ -620,13 +622,13 @@ LRESULT CMainWindow::OnCommand(UINT nMsg, WPARAM wParam, 
LPARAM lParam, BOOL& bH
                 GlobalFree(pd.hDevNames);
             break;
         case IDM_FILEASWALLPAPERPLANE:
-            RegistrySettings::SetWallpaper(filepathname, 
RegistrySettings::TILED);
+            RegistrySettings::SetWallpaper(g_szFileName, 
RegistrySettings::TILED);
             break;
         case IDM_FILEASWALLPAPERCENTERED:
-            RegistrySettings::SetWallpaper(filepathname, 
RegistrySettings::CENTERED);
+            RegistrySettings::SetWallpaper(g_szFileName, 
RegistrySettings::CENTERED);
             break;
         case IDM_FILEASWALLPAPERSTRETCHED:
-            RegistrySettings::SetWallpaper(filepathname, 
RegistrySettings::STRETCHED);
+            RegistrySettings::SetWallpaper(g_szFileName, 
RegistrySettings::STRETCHED);
             break;
         case IDM_FILE1:
         case IDM_FILE2:
@@ -640,7 +642,10 @@ LRESULT CMainWindow::OnCommand(UINT nMsg, WPARAM wParam, 
LPARAM lParam, BOOL& bH
         }
         case IDM_EDITUNDO:
             if (toolsModel.GetActiveTool() == TOOL_TEXT && 
::IsWindowVisible(textEditWindow))
+            {
+                textEditWindow.PostMessage(WM_UNDO, 0, 0);
                 break;
+            }
             if (selectionModel.m_bShow)
             {
                 if (toolsModel.GetActiveTool() == TOOL_RECTSEL ||
@@ -668,10 +673,19 @@ LRESULT CMainWindow::OnCommand(UINT nMsg, WPARAM wParam, 
LPARAM lParam, BOOL& bH
             imageModel.Redo();
             break;
         case IDM_EDITCOPY:
+            // FIXME: We should use CF_DIB in the future
             if (OpenClipboard())
             {
                 EmptyClipboard();
-                SetClipboardData(CF_BITMAP, 
CopyDIBImage(selectionModel.GetBitmap()));
+                if (selectionModel.m_bShow)
+                {
+                    selectionModel.TakeOff();
+                    SetClipboardData(CF_BITMAP, selectionModel.CopyBitmap());
+                }
+                else
+                {
+                    SetClipboardData(CF_BITMAP, imageModel.CopyBitmap());
+                }
                 CloseClipboard();
             }
             break;
@@ -695,7 +709,7 @@ LRESULT CMainWindow::OnCommand(UINT nMsg, WPARAM wParam, 
LPARAM lParam, BOOL& bH
             {
                 case TOOL_FREESEL:
                 case TOOL_RECTSEL:
-                    imageModel.DeleteSelection();
+                    selectionModel.DeleteSelection();
                     break;
 
                 case TOOL_TEXT:
@@ -723,7 +737,11 @@ LRESULT CMainWindow::OnCommand(UINT nMsg, WPARAM wParam, 
LPARAM lParam, BOOL& bH
         {
             TCHAR szFileName[MAX_LONG_PATH] = _T("");
             if (GetSaveFileName(szFileName, _countof(szFileName)))
-                SaveDIBToFile(selectionModel.GetBitmap(), szFileName, 
imageModel.GetDC());
+            {
+                HBITMAP hbm = selectionModel.CopyBitmap();
+                SaveDIBToFile(hbm, szFileName, imageModel.GetDC());
+                ::DeleteObject(hbm);
+            }
             break;
         }
         case IDM_EDITPASTEFROM:
@@ -827,8 +845,8 @@ LRESULT CMainWindow::OnCommand(UINT nMsg, WPARAM wParam, 
LPARAM lParam, BOOL& bH
             
toolsModel.SetBackgroundTransparent(!toolsModel.IsBackgroundTransparent());
             break;
         case IDM_IMAGECROP:
-            
imageModel.PushImageForUndo(CopyDIBImage(selectionModel.GetBitmap()));
-            imageModel.DeleteSelection();
+            imageModel.PushImageForUndo(selectionModel.CopyBitmap());
+            selectionModel.HideSelection();
             break;
 
         case IDM_VIEWTOOLBOX:
@@ -842,8 +860,8 @@ LRESULT CMainWindow::OnCommand(UINT nMsg, WPARAM wParam, 
LPARAM lParam, BOOL& bH
             alignChildrenToMainWindow();
             break;
         case IDM_VIEWSTATUSBAR:
-            registrySettings.ShowStatusBar = !::IsWindowVisible(hStatusBar);
-            ::ShowWindow(hStatusBar, (registrySettings.ShowStatusBar ? 
SW_SHOWNOACTIVATE : SW_HIDE));
+            registrySettings.ShowStatusBar = !::IsWindowVisible(g_hStatusBar);
+            ::ShowWindow(g_hStatusBar, (registrySettings.ShowStatusBar ? 
SW_SHOWNOACTIVATE : SW_HIDE));
             alignChildrenToMainWindow();
             break;
         case IDM_FORMATICONBAR:
@@ -859,7 +877,7 @@ LRESULT CMainWindow::OnCommand(UINT nMsg, WPARAM wParam, 
LPARAM lParam, BOOL& bH
             }
             break;
         case IDM_VIEWSHOWGRID:
-            showGrid = !showGrid;
+            g_showGrid = !g_showGrid;
             canvasWindow.Invalidate(FALSE);
             break;
         case IDM_VIEWSHOWMINIATURE:

Reply via email to