blob: 8ccbb6622dcb1db65a72d4f62afa06b350f48c32 [file] [log] [blame]
Alexandre Julliard23946ad1997-06-16 17:43:53 +00001KERNEL MODULE
2=============
3
4...
5
6GDI MODULE
7==========
8
Alexandre Julliard60ce85c1998-02-01 18:33:27 +000091. X Windows System interface
10-----------------------------
11
12The X libraries used to implement X clients (such as Wine) do not work
13properly if multiple threads access the same display concurrently. It is
14possible to compile the X libraries to perform their own synchronization
15(initiated by calling XInitThreads()). However, Wine does not use this
16approach. Instead Wine performs its own synchronization py putting a
17wrapper around every X call that is used. This wrapper protects library
18access with a critical section, and also arranges things so that X
19libraries compiled without -D_REENTRANT (eg. with global errno variable)
20will work with Wine.
21
22To make this scheme work, all calls to X must use the proper wrapper
23functions (or do their own synchronization that is compatible with the
24wrappers). The wrapper for a function X...() is calles TSX...() (for
25"Thread Safe X ..."). So for example, instead of calling XOpenDisplay()
26in the code, TSXOpenDisplay() must be used. Likewise, X include files
Alexandre Julliard03468f71998-02-15 19:40:49 +000027that contain function prototypes are wrapped, so that eg. "ts_xutil.h"
28must be included rather than <X11/Xutil.h>. It is important that this
29scheme is used everywhere to avoid the introduction of nondeterministic
30and hard-to-find errors in Wine.
Alexandre Julliard60ce85c1998-02-01 18:33:27 +000031
32The code for the thread safe X wrappers is contained in the tsx11/
Alexandre Julliard03468f71998-02-15 19:40:49 +000033directory and in include/ts*.h. To use a new (ie. not previously used) X
Alexandre Julliard60ce85c1998-02-01 18:33:27 +000034function in Wine, a new wrapper must be created. The wrappers are
35generated (semi-)automatically from the X11R6 includes using the
36tools/make_X11wrappers perl script. In simple cases it should be enough
37to add the name of the new function to the list in tsx11/X11_calls; if
38this does not work the wrapper must be added manually to the
39make_X11wrappers script. See comments in tsx11/X11_calls and
40tools/make_X11wrappers for further details.
41
Alexandre Julliard23946ad1997-06-16 17:43:53 +000042
Alexandre Julliard8b915631996-06-16 16:16:05 +000043USER MODULE
44===========
45
46USER implements windowing and messaging subsystems. It also
47contains code for common controls and for other miscellaneous
48stuff (rectangles, clipboard, WNet, etc). Wine USER code is
49located in windows/, controls/, and misc/ directories.
50
511. Windowing subsystem
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +000052----------------------
Alexandre Julliard8b915631996-06-16 16:16:05 +000053
Alexandre Julliard491502b1997-11-01 19:08:16 +000054 windows/win.c
55 windows/winpos.c
56
Alexandre Julliard8b915631996-06-16 16:16:05 +000057 Windows are arranged into parent/child hierarchy with one
58 common ancestor for all windows (desktop window). Each window
59 structure contains a pointer to the immediate ancestor (parent
60 window if WS_CHILD style bit is set), a pointer to the sibling
61 (returned by GetWindow(..., GW_NEXT)), a pointer to the owner
62 window (set only for popup window if it was created with valid
63 hwndParent parameter), and a pointer to the first child
64 window (GetWindow(.., GW_CHILD)). All popup and non-child windows
65 are therefore placed in the first level of this hierarchy and their
66 ancestor link (wnd->parent) points to the desktop window.
67
68 Desktop window - root window
Alexandre Julliard23946ad1997-06-16 17:43:53 +000069 | \ `-.
70 | \ `-.
Alexandre Julliard8b915631996-06-16 16:16:05 +000071 popup -> wnd1 -> wnd2 - top level windows
Alexandre Julliard23946ad1997-06-16 17:43:53 +000072 | \ `-. `-.
73 | \ `-. `-.
Alexandre Julliard8b915631996-06-16 16:16:05 +000074 child1 child2 -> child3 child4 - child windows
75
76 Horizontal arrows denote sibling relationship, vertical lines
77 - ancestor/child. To summarize, all windows with the same immediate
78 ancestor are sibling windows, all windows which do not have desktop
79 as their immediate ancestor are child windows. Popup windows behave
80 as topmost top-level windows unless they are owned. In this case the
81 only requirement is that they must precede their owners in the top-level
82 sibling list (they are not topmost). Child windows are confined to the
83 client area of their parent windows (client area is where window gets
84 to do its own drawing, non-client area consists of caption, menu, borders,
Alexandre Julliard23946ad1997-06-16 17:43:53 +000085 intrinsic scrollbars, and minimize/maximize/close/help buttons).
Alexandre Julliard8b915631996-06-16 16:16:05 +000086
87 Another fairly important concept is "z-order". It is derived from
88 the ancestor/child hierarchy and is used to determine "above/below"
89 relationship. For instance, in the example above, z-order is
90 child1->popup->child2->child3->wnd1->child4->wnd2->desktop. Current
91 active window ("foreground window" in Win32) is moved to the front
92 of z-order unless its top-level ancestor owns popup windows.
93
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +000094 All these issues are dealt with (or supposed to be) in windows/winpos.c
95 with SetWindowPos() being the primary interface to the window manager.
Alexandre Julliard8b915631996-06-16 16:16:05 +000096
97 Wine specifics: in default and managed mode each top-level window
98 gets its own X counterpart with desktop window being basically a
Alexandre Julliard23946ad1997-06-16 17:43:53 +000099 fake stub. In desktop mode, however, only desktop window has an X
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000100 window associated with it. Also, SetWindowPos() should eventually be
101 implemented via Begin/End/DeferWindowPos() calls and not the other way
102 around.
Alexandre Julliard8b915631996-06-16 16:16:05 +0000103
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000104 1.1 Visible region, clipping region and update region
Alexandre Julliard491502b1997-11-01 19:08:16 +0000105
106 windows/dce.c
107 windows/winpos.c
108 windows/painting.c
109
110 ________________________
111 |_________ | A and B are child windows of C
112 | A |______ |
113 | | | |
114 |---------' | |
115 | | B | |
116 | | | |
117 | `------------' |
118 | C |
119 `------------------------'
120
121 Visible region determines which part of the window is not obscured
122 by other windows. If a window has the WS_CLIPCHILDREN style then all
123 areas below its children are considered invisible. Similarily, if
124 the WS_CLIPSIBLINGS bit is in effect then all areas obscured by its
125 siblings are invisible. Child windows are always clipped by the
126 boundaries of their parent windows.
127
128 B has a WS_CLIPSIBLINGS style:
129 . ______
130 : | |
131 | ,-----' |
132 | | B | - visible region of B
133 | | |
134 : `------------'
135
136 When the program requests a display context (DC) for a window it
137 can specify an optional clipping region that further restricts the
138 area where the graphics output can appear. This area is calculated
139 as an intersection of the visible region and a clipping region.
140
141 Program asked for a DC with a clipping region:
142 ______
143 ,--|--. | . ,--.
144 ,--+--' | | : _: |
145 | | B | | => | | | - DC region where the painting will
146 | | | | | | | be visible
147 `--|-----|---' : `----'
148 `-----'
149
150 When the window manager detects that some part of the window
151 became visible it adds this area to the update region of this
152 window and then generates WM_ERASEBKGND and WM_PAINT messages.
153 In addition, WM_NCPAINT message is sent when the uncovered area
154 intersects a nonclient part of the window. Application must reply
155 to the WM_PAINT message by calling BeginPaint()/EndPaint() pair of
156 functions. BeginPaint() returns a DC that uses accumulated update
157 region as a clipping region. This operation cleans up invalidated
158 area and the window will not receive another WM_PAINT until the
159 window manager creates a new update region.
160
161 A was moved to the left:
162 ________________________ ... / C update region
163 |______ | : .___ /
164 | A |_________ | => | ...|___|..
165 | | | | | : | |
166 |------' | | | : '---'
167 | | B | | | : \
168 | | | | : \
169 | `------------' | B update region
170 | C |
171 `------------------------'
172
173
174 Windows maintains a display context cache consisting of entries that
175 include DC itself, window to which it belongs, and an optional clipping
176 region (visible region is stored in the DC itself). When an API call
177 changes the state of the window tree, window manager has to go through
178 the DC cache to recalculate visible regions for entries whose windows
179 were involved in the operation. DC entries (DCE) can be either private
180 to the window, or private to the window class, or shared between all
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000181 windows (Windows 3.1 limits the number of shared DCEs to 5).
Alexandre Julliard491502b1997-11-01 19:08:16 +0000182
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000183 1.2
184
1852. Messaging subsystem
186----------------------
Alexandre Julliard491502b1997-11-01 19:08:16 +0000187
188 windows/queue.c
189 windows/message.c
Alexandre Julliard8b915631996-06-16 16:16:05 +0000190
191 Each Windows task/thread has its own message queue - this is where
192 it gets messages from. Messages can be generated on the fly
193 (WM_PAINT, WM_NCPAINT, WM_TIMER), they can be created by the system
194 (hardware messages), they can be posted by other tasks/threads
195 (PostMessage), or they can be sent by other tasks/threads (SendMessage).
196
197 Message priority:
198
199 First the system looks for sent messages, then for posted messages,
200 then for hardware messages, then it checks if the queue has the
201 "dirty window" bit set, and, finally, it checks for expired
202 timers. See windows/message.c.
203
204 From all these different types of messages, only posted messages go
205 directly into the private message queue. System messages (even in
206 Win95) are first collected in the system message queue and then
207 they either sit there until Get/PeekMessage gets to process them
208 or, as in Win95, if system queue is getting clobbered, a special
209 thread ("raw input thread") assigns them to the private
210 queues. Sent messages are queued separately and the sender sleeps
211 until it gets a reply. Special messages are generated on the fly
212 depending on the window/queue state. If the window update region is
213 not empty, the system sets the QS_PAINT bit in the owning queue and
214 eventually this window receives a WM_PAINT message (WM_NCPAINT too
215 if the update region intersects with the non-client area). A timer
216 event is raised when one of the queue timers expire. Depending on
217 the timer parameters DispatchMessage either calls the callback
218 function or the window procedure. If there are no messages pending
219 the task/thread sleeps until messages appear.
220
221 There are several tricky moments (open for discussion) -
222
223 a) System message order has to be honored and messages should be
224 processed within correct task/thread context. Therefore when
225 Get/PeekMessage encounters unassigned system message and this
226 message appears not to be for the current task/thread it should
227 either skip it (or get rid of it by moving it into the private
228 message queue of the target task/thread - Win95, AFAIK) and
229 look further or roll back and then yield until this message
230 gets processed when system switches to the correct context
231 (Win16). In the first case we lose correct message ordering, in
232 the second case we have the infamous synchronous system message
233 queue. Here is a post to one of the OS/2 newsgroup I found to
234 be relevant:
235
236 " Here's the problem in a nutshell, and there is no good solution.
237 Every possible solution creates a different problem.
238
239 With a windowing system, events can go to many different windows.
240 Most are sent by applications or by the OS when things relating to
241 that window happen (like repainting, timers, etc.)
242
243 Mouse input events go to the window you click on (unless some window
244 captures the mouse).
245
246 So far, no problem. Whenever an event happens, you put a message on
247 the target window's message queue. Every process has a message
248 queue. If the process queue fills up, the messages back up onto the
249 system queue.
250
251 This is the first cause of apps hanging the GUI. If an app doesn't
252 handle messages and they back up into the system queue, other apps
253 can't get any more messages. The reason is that the next message in
254 line can't go anywhere, and the system won't skip over it.
255
256 This can be fixed by making apps have bigger private message queues.
257 The SIQ fix does this. PMQSIZE does this for systems without the SIQ
258 fix. Applications can also request large queues on their own.
259
260 Another source of the problem, however, happens when you include
261 keyboard events. When you press a key, there's no easy way to know
262 what window the keystroke message should be delivered to.
263
264 Most windowing systems use a concept known as "focus". The window
265 with focus gets all incoming keyboard messages. Focus can be changed
266 from window to window by apps or by users clicking on winodws.
267
268 This is the second source of the problem. Suppose window A has focus.
269 You click on window B and start typing before the window gets focus.
270 Where should the keystrokes go? On the one hand, they should go to A
271 until the focus actually changes to B. On the other hand, you
272 probably want the keystrokes to go to B, since you clicked there
273 first.
274
275 OS/2's solution is that when a focus-changing event happens (like
276 clicking on a window), OS/2 holds all messages in the system queue
277 until the focus change actually happens. This way, subsequent
278 keystrokes go to the window you clicked on, even if it takes a while
279 for that window to get focus.
280
281 The downside is that if the window takes a real long time to get focus
282 (maybe it's not handling events, or maybe the window losing focus
283 isn't handling events), everything backs up in the system queue and
284 the system appears hung.
285
286 There are a few solutions to this problem.
287
288 One is to make focus policy asynchronous. That is, focus changing has
289 absolutely nothing to do with the keyboard. If you click on a window
290 and start typing before the focus actually changes, the keystrokes go
291 to the first window until focus changes, then they go to the second.
292 This is what X-windows does.
293
294 Another is what NT does. When focus changes, keyboard events are held
295 in the system message queue, but other events are allowed through.
296 This is "asynchronous" because the messages in the system queue are
297 delivered to the application queues in a different order from that
298 with which they were posted. If a bad app won't handle the "lose
299 focus" message, it's of no consequence - the app receiving focus will
300 get its "gain focus" message, and the keystrokes will go to it.
301
302 The NT solution also takes care of the application queue filling up
303 problem. Since the system delivers messages asynchronously, messages
304 waiting in the system queue will just sit there and the rest of the
305 messages will be delivered to their apps.
306
307 The OS/2 SIQ solution is this: When a focus-changing event happens,
308 in addition to blocking further messages from the application queues,
309 a timer is started. When the timer goes off, if the focus change has
310 not yet happened, the bad app has its focus taken away and all
311 messages targetted at that window are skipped. When the bad app
312 finally handles the focus change message, OS/2 will detect this and
313 stop skipping its messages.
314
315
316 As for the pros and cons:
317
318 The X-windows solution is probably the easiest. The problem is that
319 users generally don't like having to wait for the focus to change
320 before they start typing. On many occasions, you can type and the
321 characters end up in the wrong window because something (usually heavy
322 system load) is preventing the focus change from happening in a timely
323 manner.
324
325 The NT solution seems pretty nice, but making the system message queue
326 asynchronous can cause similar problems to the X-windows problem.
327 Since messages can be delivered out of order, programs must not assume
328 that two messages posted in a particular order will be delivered in
329 that same order. This can break legacy apps, but since Win32 always
330 had an asynchronous queue, it is fair to simply tell app designers
331 "don't do that". It's harder to tell app designers something like
332 that on OS/2 - they'll complain "you changed the rules and our apps
333 are breaking."
334
335 The OS/2 solution's problem is that nothing happens until you try to
336 change window focus, and then wait for the timeout. Until then, the
337 bad app is not detected and nothing is done." (by David Charlap)
338
339
340 b) Intertask/interthread SendMessage. The system has to inform the
Alexandre Julliard8cc3a5e1996-08-11 15:49:51 +0000341 target queue about the forthcoming message, then it has to carry
342 out the context switch and wait until the result is available.
343 Win16 stores necessary parameters in the queue structure and then
344 calls DirectedYield() function. However, in Win32 there could be
345 several messages pending sent by preemptively executing threads,
346 and in this case SendMessage has to build some sort of message
347 queue for sent messages. Another issue is what to do with messages
348 sent to the sender when it is blocked inside its own SendMessage.
Alexandre Julliard8cc3a5e1996-08-11 15:49:51 +0000349
Alexandre Julliard23946ad1997-06-16 17:43:53 +0000350