]>
Commit | Line | Data |
---|---|---|
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 | } |