| 1 | wxMicroWindows port |
| 2 | =================== |
| 3 | |
| 4 | Warning: As of 2007-07-17 this port probably doesn't build any more. |
| 5 | Please don't expect it to work out of the box currently. |
| 6 | |
| 7 | |
| 8 | Julian Smart 2001-12-08 |
| 9 | |
| 10 | This is a port of wxWidgets to MicroWindows, under Linux. |
| 11 | Widgets are supplied by the wxUniversal project, while the |
| 12 | underlying port uses the Windows ports with small modifications |
| 13 | for the MicroWindows API. |
| 14 | |
| 15 | === NOTE: === |
| 16 | |
| 17 | Current efforts are being concentrated on a port to Nano-X, |
| 18 | which potentially offers greater flexibility than the WIN32 |
| 19 | API of MicroWindows, such as the ability to run multiple |
| 20 | Nano-X processes simultaneously. Please see |
| 21 | ../docs/x11/readme-nanox.txt for information. |
| 22 | |
| 23 | There are many things missing from MicroWindows that will |
| 24 | make the port quite limited for the time being. |
| 25 | In particular, only one WIN32 app may be run at a time. |
| 26 | |
| 27 | Note that you can gain confidence in the WIN32/wxUniversal |
| 28 | combination by compiling wxUniversal under Windows using VC++, |
| 29 | using src/wxUniv.dsp. You can compile the minimal |
| 30 | and widgets samples in wxUniversal mode using the |
| 31 | UnivDebug and UnivRelease targets. Most of the code is shared |
| 32 | between this combination, and the wxMicroWindows port. |
| 33 | |
| 34 | Installation |
| 35 | ============ |
| 36 | |
| 37 | MicroWindows: |
| 38 | |
| 39 | - unarchive MicroWindows 0.89pre8 |
| 40 | |
| 41 | - change 'config' to use X11 and any other options you feel fit. |
| 42 | Suggestions for changes to the defaults: |
| 43 | |
| 44 | ERASEMOVE=N (otherwise moving windows will look messy) |
| 45 | X11=Y |
| 46 | OPTIMIZE=N |
| 47 | DEBUG=Y |
| 48 | VERBOSE=Y |
| 49 | |
| 50 | Note: these are already applied by the patch below. |
| 51 | |
| 52 | - apply microwindows.patches (from wxWidgets: |
| 53 | docs/microwin/microwindows.patches) to fix PeekMessage |
| 54 | and other issues. If the patch doesn't apply automatically, |
| 55 | you may need to apply it by hand, and the relevant changed |
| 56 | functions are given at the end of this file for convenience. |
| 57 | |
| 58 | Example patch command: |
| 59 | |
| 60 | % cd microwindows-0.89pre8.orig |
| 61 | % patch -p0 < ~/wx2/docs/microwin/microwindows.patches |
| 62 | |
| 63 | - compile by typing 'make' from within the MicroWindows src directory |
| 64 | |
| 65 | wxMicroWindows: |
| 66 | |
| 67 | - Download wxMSW 2.3.4 or greater, or get it from CVS |
| 68 | |
| 69 | - Many settings in include/wx/setup.h have to be disabled. As contents |
| 70 | of this file keeps changing, it's impossible to say what exactly should be |
| 71 | disabled but it probably makes sense to disable as much as possible |
| 72 | initially, make sure that the build works and then add features as needed. |
| 73 | |
| 74 | - EITHER: |
| 75 | |
| 76 | o set the MICROWINDOWS environment variable, e.g.: |
| 77 | |
| 78 | % export MICROWINDOWS=/home/julians/local/microwindows/microwindows-0.89pre8/src |
| 79 | |
| 80 | OR: |
| 81 | |
| 82 | o change the TOP variable at the top of src/msw/makefile.mic |
| 83 | to reflect where MicroWindows is installed |
| 84 | |
| 85 | - type 'make -f makefile.mic all' from src/msw. To clean, use |
| 86 | cleanwx and NOT clean since that will clean MicroWindows itself |
| 87 | |
| 88 | - to make the sample, cd into samples/minimal, edit the TOP variable |
| 89 | (or set MICROWINDOWS) as before, and type 'make -f makefile.mic all' |
| 90 | |
| 91 | Running 'minimal' runs the virtual MicroWindows desktop |
| 92 | and the minimal sample, since in a MicroWindows WIN32 application |
| 93 | they are one and the same binary. |
| 94 | |
| 95 | Status |
| 96 | ====== |
| 97 | |
| 98 | The minimal sample is almost fully-functional, apart from some |
| 99 | presentation issues (no menu borders and status bar in the wrong |
| 100 | place. |
| 101 | |
| 102 | The widgets sample is crashing in DeleteObject (see notes below). |
| 103 | |
| 104 | |
| 105 | Implementation Notes |
| 106 | ==================== |
| 107 | |
| 108 | wxMicroWindows is essentially the wxMSW port + wxUniversal |
| 109 | widgets. Lots of things in include/wx/univ/setup.h are switched |
| 110 | off to allow the port to compile. There are also #ifdefs |
| 111 | switching off further functionality, such as most wxBitmap |
| 112 | functions, pending proper implementation. |
| 113 | |
| 114 | There are some WIN32 API functions not implemented by MicroWindows |
| 115 | that are instead stubbed out in include/wx/msw/microwin.c, |
| 116 | and 'implemented' in src/msw/microwin.c. Some of these functions |
| 117 | are important, some less so. They will need to be implemented |
| 118 | in due course. But implementing missing functionality in this way |
| 119 | is preferably to proliferating many #ifdefs in the |
| 120 | wxMSW/wxMicroWindows port itself. |
| 121 | |
| 122 | |
| 123 | Errors/warnings |
| 124 | =============== |
| 125 | |
| 126 | In file ../../src/msw/window.cpp at line 1294: 'UpdateWindow' failed with error 0x00000000 (Success). |
| 127 | |
| 128 | - caused because there are no paint messages pending. Presumed |
| 129 | harmless. |
| 130 | |
| 131 | In file ../../src/msw/dc.cpp at line 1838: 'BitBlt' failed with error 0x00000000 (Success). |
| 132 | |
| 133 | - caused because the window isn't mapped, and MwPrepareDC in wingdi.c |
| 134 | fails (hwnd->unmapcount is non-zero). Presumed harmless. |
| 135 | |
| 136 | Recursive paint problem, e.g. when clicking the 'Press Me!' |
| 137 | button in the widgets sample a few times, until the text control |
| 138 | is full. |
| 139 | |
| 140 | - possibly the scrollbar is causing the text control to be |
| 141 | updated, which somehow effects the scrollbar, which causes |
| 142 | a window update, etc. |
| 143 | |
| 144 | Sluggish updates. |
| 145 | |
| 146 | - probably because many image to bitmap conversions are being |
| 147 | done on update, and bitmaps should probably be cached. |
| 148 | |
| 149 | |
| 150 | Things missing from MicroWindows that need to be worked around |
| 151 | ============================================================== |
| 152 | |
| 153 | wxImage/inline XPM/::CreateBitmap support |
| 154 | ----------------------------------------- |
| 155 | |
| 156 | This is the main obstacle to getting a good range |
| 157 | of widgets working, since wxUniversal uses inline XPMs |
| 158 | to implement most of the widgets. |
| 159 | |
| 160 | See src/engine/devimage.c for routines for loading JPEGs, |
| 161 | XPMs etc. Unfortunately the XPM routines are also #ifdefed |
| 162 | for FILE_IO, even though for inline XPMs we don't need file I/O. |
| 163 | (Embedded systems tend not to have file I/O, anyway.) |
| 164 | |
| 165 | Now, wxWidgets has its own XPM decoder, src/common/xpmdecod.cpp, |
| 166 | so in theory we don't need to use MicroWindows' code there. |
| 167 | wxImage can load an inline XPM, _but_ we need to convert to |
| 168 | a wxBitmap since this is what the widgets need. |
| 169 | |
| 170 | There is no ::CreateBitmap or BITMAPINFO. (BMPs can be converted |
| 171 | to C using convbmp, then need to use Gr... functions.) |
| 172 | |
| 173 | So how can we convert from wxImage to wxBitmap in MicroWindows? |
| 174 | |
| 175 | Well, a simple-minded way would be to use CreateCompatibleBitmap |
| 176 | which returns an HBITMAP, select it into an HDC, and draw |
| 177 | the pixels from the wxImage to the HDC one by one with SetPixel. |
| 178 | This is now implemented, but there are problems with masks. |
| 179 | (a) masks have to be created at screen depth because BitBlt/GrDraw |
| 180 | can't cope with differing depths, and (b) masked blitting |
| 181 | is still not working (try enabling mask creation in |
| 182 | wxBitmap::CreateFromImage by setting USE_MASKS to 1). |
| 183 | |
| 184 | |
| 185 | Other missing features |
| 186 | ---------------------- |
| 187 | |
| 188 | No ::GetKeyState (see include/wx/msw/private.h). Should probably use |
| 189 | GdOpenKeyboard/GdCloseKeyboard/GdReadKeyboard. Could perhaps emulate |
| 190 | GetKeyState this way. |
| 191 | |
| 192 | No ::DestroyIcon, ::DestroyCursor - use ::DestroyObject instead? |
| 193 | Also no LoadCursor, LoadImage. So how do we make cursors? No ::SetCursor. |
| 194 | |
| 195 | wxDC: no ::GetTextColor, ::GetBkColor, ::IntersectClipRect, |
| 196 | ::GetClipBox |
| 197 | |
| 198 | No ::SetMenu, so no menus or menubars (now implemented by |
| 199 | wxUniversal). |
| 200 | |
| 201 | No ::GetObject so we can't get LOGFONT from an HFONT |
| 202 | in wxSystemSettings (worked around by passing HFONT to |
| 203 | the wxFont constructor). |
| 204 | |
| 205 | |
| 206 | Applying patches by hand |
| 207 | ======================== |
| 208 | |
| 209 | The full altered functions are given below in case you have |
| 210 | to apply them by hand. |
| 211 | |
| 212 | src/mwin/winevent.c |
| 213 | ------------------- |
| 214 | |
| 215 | A second test has been added to this line: |
| 216 | |
| 217 | if(hittest == HTCLIENT || hwnd == GetCapture()) { |
| 218 | |
| 219 | in MwTranslateMouseMessage below. This corrects a mouse message |
| 220 | bug. |
| 221 | |
| 222 | /* |
| 223 | * Translate and deliver hardware mouse message to proper window. |
| 224 | */ |
| 225 | void |
| 226 | MwTranslateMouseMessage(HWND hwnd,UINT msg,int hittest) |
| 227 | { |
| 228 | POINT pt; |
| 229 | DWORD tick; |
| 230 | static UINT lastmsg = 0; |
| 231 | static HWND lasthwnd; |
| 232 | static DWORD lasttick; |
| 233 | static int lastx, lasty; |
| 234 | |
| 235 | /* determine double click eligibility*/ |
| 236 | if(msg == WM_LBUTTONDOWN || msg == WM_RBUTTONDOWN) { |
| 237 | tick = GetTickCount(); |
| 238 | if((hwnd->pClass->style & CS_DBLCLKS) && |
| 239 | msg == lastmsg && hwnd == lasthwnd && |
| 240 | tick - lasttick < DBLCLICKSPEED && |
| 241 | abs(cursorx-lastx) < mwSYSMETRICS_CXDOUBLECLK && |
| 242 | abs(cursory-lasty) < mwSYSMETRICS_CYDOUBLECLK) |
| 243 | msg += (WM_LBUTTONDBLCLK - WM_LBUTTONDOWN); |
| 244 | lastmsg = msg; |
| 245 | lasthwnd = hwnd; |
| 246 | lasttick = tick; |
| 247 | lastx = cursorx; |
| 248 | lasty = cursory; |
| 249 | } |
| 250 | |
| 251 | /* |
| 252 | * We always send nc mouse message |
| 253 | * unlike Windows, for HTCLIENT default processing |
| 254 | */ |
| 255 | PostMessage(hwnd, msg + (WM_NCMOUSEMOVE-WM_MOUSEMOVE), hittest, |
| 256 | MAKELONG(cursorx, cursory)); |
| 257 | |
| 258 | /* then possibly send user mouse message*/ |
| 259 | if(hittest == HTCLIENT || hwnd == GetCapture()) { |
| 260 | pt.x = cursorx; |
| 261 | pt.y = cursory; |
| 262 | ScreenToClient(hwnd, &pt); |
| 263 | PostMessage(hwnd, msg, 0, MAKELONG(pt.x, pt.y)); |
| 264 | } |
| 265 | } |
| 266 | |
| 267 | winuser.c |
| 268 | --------- |
| 269 | |
| 270 | Part of PeekMessage has been factored out into PeekMessageHelper, |
| 271 | and used in PeekMessage and GetMessage. The three relevant functions |
| 272 | are: |
| 273 | |
| 274 | /* |
| 275 | * A helper function for sharing code between PeekMessage and GetMessage |
| 276 | */ |
| 277 | |
| 278 | BOOL WINAPI |
| 279 | PeekMessageHelper(LPMSG lpMsg, HWND hwnd, UINT uMsgFilterMin, UINT uMsgFilterMax, |
| 280 | UINT wRemoveMsg, BOOL returnIfEmptyQueue) |
| 281 | { |
| 282 | HWND wp; |
| 283 | PMSG pNxtMsg; |
| 284 | |
| 285 | /* check if no messages in queue*/ |
| 286 | if(mwMsgHead.head == NULL) { |
| 287 | /* Added by JACS so it doesn't reach MwSelect */ |
| 288 | if (returnIfEmptyQueue) |
| 289 | return FALSE; |
| 290 | |
| 291 | #if PAINTONCE |
| 292 | /* check all windows for pending paint messages*/ |
| 293 | for(wp=listwp; wp; wp=wp->next) { |
| 294 | if(!(wp->style & WS_CHILD)) { |
| 295 | if(chkPaintMsg(wp, lpMsg)) |
| 296 | return TRUE; |
| 297 | } |
| 298 | } |
| 299 | for(wp=listwp; wp; wp=wp->next) { |
| 300 | if(wp->style & WS_CHILD) { |
| 301 | if(chkPaintMsg(wp, lpMsg)) |
| 302 | return TRUE; |
| 303 | } |
| 304 | } |
| 305 | #endif |
| 306 | MwSelect(); |
| 307 | } |
| 308 | |
| 309 | if(mwMsgHead.head == NULL) |
| 310 | return FALSE; |
| 311 | |
| 312 | pNxtMsg = (PMSG)mwMsgHead.head; |
| 313 | if(wRemoveMsg & PM_REMOVE) |
| 314 | GdListRemove(&mwMsgHead, &pNxtMsg->link); |
| 315 | *lpMsg = *pNxtMsg; |
| 316 | if(wRemoveMsg & PM_REMOVE) |
| 317 | GdItemFree(pNxtMsg); |
| 318 | return TRUE; |
| 319 | } |
| 320 | |
| 321 | BOOL WINAPI |
| 322 | PeekMessage(LPMSG lpMsg, HWND hwnd, UINT uMsgFilterMin, UINT uMsgFilterMax, |
| 323 | UINT wRemoveMsg) |
| 324 | { |
| 325 | /* Never wait in MwSelect: pass TRUE */ |
| 326 | return PeekMessageHelper(lpMsg, hwnd, uMsgFilterMin, uMsgFilterMax, wRemoveMsg, TRUE); |
| 327 | } |
| 328 | |
| 329 | BOOL WINAPI |
| 330 | GetMessage(LPMSG lpMsg,HWND hwnd,UINT wMsgFilterMin,UINT wMsgFilterMax) |
| 331 | { |
| 332 | /* |
| 333 | * currently MwSelect() must poll for VT switch reasons, |
| 334 | * so this code will work |
| 335 | */ |
| 336 | /* Always wait in MwSelect if there are messages: pass FALSE */ |
| 337 | while(!PeekMessageHelper(lpMsg, hwnd, wMsgFilterMin, wMsgFilterMax,PM_REMOVE, FALSE)) |
| 338 | continue; |
| 339 | return lpMsg->message != WM_QUIT; |
| 340 | } |