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