wxMicroWindows port
===================
-Julian Smart 2001-07-02
+Julian Smart 2001-12-08
This is a port of wxWindows to MicroWindows, under Linux.
Widgets are supplied by the wxUniversal project, while the
MicroWindows:
-- unarchive MicroWindows 0.89pre7
+- unarchive MicroWindows 0.89pre8
- change 'config' to use X11 and any other options you feel fit.
Suggestions for changes to the defaults:
DEBUG=Y
VERBOSE=Y
+ Note: these are already applied by the patch below.
+
- apply microwindows.patches (from wxWindows:
docs/microwin/microwindows.patches) to fix PeekMessage
- and other issues
+ and other issues. If the patch doesn't apply automatically,
+ you may need to apply it by hand, and the relevant changed
+ functions are given at the end of this file for convenience.
+
+ Example patch command:
+
+ % cd microwindows-0.89pre8.orig
+ % patch -p0 < ~/wx2/docs/microwin/microwindows.patches
- compile by typing 'make' from within the MicroWindows src directory
wxMicroWindows:
-- untar the wxMicroWindows port/download from CVS
+- Download wxMSW 2.3.2 or greater, or get it from CVS
+
+- Copy include/wx/msw/setup_microwin.h to include/wx/setup.h if
+ include/wx/setup.h doesn't exist
+
+- EITHER:
+
+ o set the MICROWINDOWS environment variable, e.g.:
+
+ % export MICROWINDOWS=/home/julians/local/microwindows/microwindows-0.89pre8/src
-- change the TOP variable at the top of src/msw/makefile.mic
- to reflect where MicroWindows is installed
+ OR:
-- type 'make all' from src/msw. To clean, use cleanwx and NOT clean
- since that will clean MicroWindows itself
+ o change the TOP variable at the top of src/msw/makefile.mic
+ to reflect where MicroWindows is installed
-- to make the sample, cd into samples/minimal, edit the TOP variable,
- and type 'make all'
+- type 'make -f makefile.mic all' from src/msw. To clean, use
+ cleanwx and NOT clean since that will clean MicroWindows itself
+
+- to make the sample, cd into samples/minimal, edit the TOP variable
+ (or set MICROWINDOWS) as before, and type 'make -f makefile.mic all'
Running 'minimal' runs the virtual MicroWindows desktop
and the minimal sample, since in a MicroWindows WIN32 application
Status
======
-The minimal sample is almost fully-functional, apart from minor
-menu presentation issues (no borders, for example).
+The minimal sample is almost fully-functional, apart from some
+presentation issues (no menu borders and status bar in the wrong
+place.
+
+The widgets sample is crashing in DeleteObject (see notes below).
+
Implementation Notes
====================
is preferably to proliferating many #ifdefs in the
wxMSW/wxMicroWindows port itself.
+
+Errors/warnings
+===============
+
+In file ../../src/msw/window.cpp at line 1294: 'UpdateWindow' failed with error 0x00000000 (Success).
+
+ - caused because there are no paint messages pending. Presumed
+ harmless.
+
+In file ../../src/msw/dc.cpp at line 1838: 'BitBlt' failed with error 0x00000000 (Success).
+
+ - caused because the window isn't mapped, and MwPrepareDC in wingdi.c
+ fails (hwnd->unmapcount is non-zero). Presumed harmless.
+
+Recursive paint problem, e.g. when clicking the 'Press Me!'
+button in the widgets sample a few times, until the text control
+is full.
+
+ - possibly the scrollbar is causing the text control to be
+ updated, which somehow effects the scrollbar, which causes
+ a window update, etc.
+
+Sluggish updates.
+
+ - probably because many image to bitmap conversions are being
+ done on update, and bitmaps should probably be cached.
+
+
Things missing from MicroWindows that need to be worked around
==============================================================
+wxImage/inline XPM/::CreateBitmap support
+-----------------------------------------
+
+This is the main obstacle to getting a good range
+of widgets working, since wxUniversal uses inline XPMs
+to implement most of the widgets.
+
+See src/engine/devimage.c for routines for loading JPEGs,
+XPMs etc. Unfortunately the XPM routines are also #ifdefed
+for FILE_IO, even though for inline XPMs we don't need file I/O.
+(Embedded systems tend not to have file I/O, anyway.)
+
+Now, wxWindows has its own XPM decoder, src/common/xpmdecod.cpp,
+so in theory we don't need to use MicroWindows' code there.
+wxImage can load an inline XPM, _but_ we need to convert to
+a wxBitmap since this is what the widgets need.
+
+There is no ::CreateBitmap or BITMAPINFO. (BMPs can be converted
+to C using convbmp, then need to use Gr... functions.)
+
+So how can we convert from wxImage to wxBitmap in MicroWindows?
+
+Well, a simple-minded way would be to use CreateCompatibleBitmap
+which returns an HBITMAP, select it into an HDC, and draw
+the pixels from the wxImage to the HDC one by one with SetPixel.
+This is now implemented, but there are problems with masks.
+(a) masks have to be created at screen depth because BitBlt/GrDraw
+can't cope with differing depths, and (b) masked blitting
+is still not working (try enabling mask creation in
+wxBitmap::CreateFromImage by setting USE_MASKS to 1).
+
+
+Other missing features
+----------------------
+
No ::GetKeyState (see include/wx/msw/private.h). Should probably use
GdOpenKeyboard/GdCloseKeyboard/GdReadKeyboard. Could perhaps emulate
GetKeyState this way.
-No ::CreateBitmap or BITMAPINFO. But BMPs can be converted
-to C using convbmp, then need to use Gr... functions.
-We MUST implement creation from XPMs, since wxUniversal
-makes use of XPMs, or else create our own bitmaps for
-drawing radioboxes, checkboxes etc.: see renderers
-in src/univ.
-
No ::DestroyIcon, ::DestroyCursor - use ::DestroyObject instead?
Also no LoadCursor, LoadImage. So how do we make cursors? No ::SetCursor.
in wxSystemSettings (worked around by passing HFONT to
the wxFont constructor).
+
+Applying patches by hand
+========================
+
+The full altered functions are given below in case you have
+to apply them by hand.
+
+src/mwin/winevent.c
+-------------------
+
+A second test has been added to this line:
+
+ if(hittest == HTCLIENT || hwnd == GetCapture()) {
+
+in MwTranslateMouseMessage below. This corrects a mouse message
+bug.
+
+/*
+ * Translate and deliver hardware mouse message to proper window.
+ */
+void
+MwTranslateMouseMessage(HWND hwnd,UINT msg,int hittest)
+{
+ POINT pt;
+ DWORD tick;
+ static UINT lastmsg = 0;
+ static HWND lasthwnd;
+ static DWORD lasttick;
+ static int lastx, lasty;
+
+ /* determine double click eligibility*/
+ if(msg == WM_LBUTTONDOWN || msg == WM_RBUTTONDOWN) {
+ tick = GetTickCount();
+ if((hwnd->pClass->style & CS_DBLCLKS) &&
+ msg == lastmsg && hwnd == lasthwnd &&
+ tick - lasttick < DBLCLICKSPEED &&
+ abs(cursorx-lastx) < mwSYSMETRICS_CXDOUBLECLK &&
+ abs(cursory-lasty) < mwSYSMETRICS_CYDOUBLECLK)
+ msg += (WM_LBUTTONDBLCLK - WM_LBUTTONDOWN);
+ lastmsg = msg;
+ lasthwnd = hwnd;
+ lasttick = tick;
+ lastx = cursorx;
+ lasty = cursory;
+ }
+
+ /*
+ * We always send nc mouse message
+ * unlike Windows, for HTCLIENT default processing
+ */
+ PostMessage(hwnd, msg + (WM_NCMOUSEMOVE-WM_MOUSEMOVE), hittest,
+ MAKELONG(cursorx, cursory));
+
+ /* then possibly send user mouse message*/
+ if(hittest == HTCLIENT || hwnd == GetCapture()) {
+ pt.x = cursorx;
+ pt.y = cursory;
+ ScreenToClient(hwnd, &pt);
+ PostMessage(hwnd, msg, 0, MAKELONG(pt.x, pt.y));
+ }
+}
+
+winuser.c
+---------
+
+Part of PeekMessage has been factored out into PeekMessageHelper,
+and used in PeekMessage and GetMessage. The three relevant functions
+are:
+
+/*
+ * A helper function for sharing code between PeekMessage and GetMessage
+ */
+
+BOOL WINAPI
+PeekMessageHelper(LPMSG lpMsg, HWND hwnd, UINT uMsgFilterMin, UINT uMsgFilterMax,
+ UINT wRemoveMsg, BOOL returnIfEmptyQueue)
+{
+ HWND wp;
+ PMSG pNxtMsg;
+
+ /* check if no messages in queue*/
+ if(mwMsgHead.head == NULL) {
+ /* Added by JACS so it doesn't reach MwSelect */
+ if (returnIfEmptyQueue)
+ return FALSE;
+
+#if PAINTONCE
+ /* check all windows for pending paint messages*/
+ for(wp=listwp; wp; wp=wp->next) {
+ if(!(wp->style & WS_CHILD)) {
+ if(chkPaintMsg(wp, lpMsg))
+ return TRUE;
+ }
+ }
+ for(wp=listwp; wp; wp=wp->next) {
+ if(wp->style & WS_CHILD) {
+ if(chkPaintMsg(wp, lpMsg))
+ return TRUE;
+ }
+ }
+#endif
+ MwSelect();
+ }
+
+ if(mwMsgHead.head == NULL)
+ return FALSE;
+
+ pNxtMsg = (PMSG)mwMsgHead.head;
+ if(wRemoveMsg & PM_REMOVE)
+ GdListRemove(&mwMsgHead, &pNxtMsg->link);
+ *lpMsg = *pNxtMsg;
+ if(wRemoveMsg & PM_REMOVE)
+ GdItemFree(pNxtMsg);
+ return TRUE;
+}
+
+BOOL WINAPI
+PeekMessage(LPMSG lpMsg, HWND hwnd, UINT uMsgFilterMin, UINT uMsgFilterMax,
+ UINT wRemoveMsg)
+{
+ /* Never wait in MwSelect: pass TRUE */
+ return PeekMessageHelper(lpMsg, hwnd, uMsgFilterMin, uMsgFilterMax, wRemoveMsg, TRUE);
+}
+
+BOOL WINAPI
+GetMessage(LPMSG lpMsg,HWND hwnd,UINT wMsgFilterMin,UINT wMsgFilterMax)
+{
+ /*
+ * currently MwSelect() must poll for VT switch reasons,
+ * so this code will work
+ */
+ /* Always wait in MwSelect if there are messages: pass FALSE */
+ while(!PeekMessageHelper(lpMsg, hwnd, wMsgFilterMin, wMsgFilterMax,PM_REMOVE, FALSE))
+ continue;
+ return lpMsg->message != WM_QUIT;
+}