9 1. X Windows System interface
10 -----------------------------
12 The X libraries used to implement X clients (such as Wine) do not work
13 properly if multiple threads access the same display concurrently. It is
14 possible to compile the X libraries to perform their own synchronization
15 (initiated by calling XInitThreads()). However, Wine does not use this
16 approach. Instead Wine performs its own synchronization py putting a
17 wrapper around every X call that is used. This wrapper protects library
18 access with a critical section, and also arranges things so that X
19 libraries compiled without -D_REENTRANT (eg. with global errno variable)
22 To make this scheme work, all calls to X must use the proper wrapper
23 functions (or do their own synchronization that is compatible with the
24 wrappers). The wrapper for a function X...() is calles TSX...() (for
25 "Thread Safe X ..."). So for example, instead of calling XOpenDisplay()
26 in the code, TSXOpenDisplay() must be used. Likewise, X include files
27 that contain function prototypes are wrapped, so that eg. "ts_xutil.h"
28 must be included rather than <X11/Xutil.h>. It is important that this
29 scheme is used everywhere to avoid the introduction of nondeterministic
30 and hard-to-find errors in Wine.
32 The code for the thread safe X wrappers is contained in the tsx11/
33 directory and in include/ts*.h. To use a new (ie. not previously used) X
34 function in Wine, a new wrapper must be created. The wrappers are
35 generated (semi-)automatically from the X11R6 includes using the
36 tools/make_X11wrappers perl script. In simple cases it should be enough
37 to add the name of the new function to the list in tsx11/X11_calls; if
38 this does not work the wrapper must be added manually to the
39 make_X11wrappers script. See comments in tsx11/X11_calls and
40 tools/make_X11wrappers for further details.
46 USER implements windowing and messaging subsystems. It also
47 contains code for common controls and for other miscellaneous
48 stuff (rectangles, clipboard, WNet, etc). Wine USER code is
49 located in windows/, controls/, and misc/ directories.
51 1. Windowing subsystem
52 ----------------------
57 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.
68 Desktop window - root window
71 popup -> wnd1 -> wnd2 - top level windows
74 child1 child2 -> child3 child4 - child windows
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,
85 intrinsic scrollbars, and minimize/maximize/close/help buttons).
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.
94 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.
97 Wine specifics: in default and managed mode each top-level window
98 gets its own X counterpart with desktop window being basically a
99 fake stub. In desktop mode, however, only desktop window has an X
100 window associated with it. Also, SetWindowPos() should eventually be
101 implemented via Begin/End/DeferWindowPos() calls and not the other way
104 1.1 Visible region, clipping region and update region
110 ________________________
111 |_________ | A and B are child windows of C
119 `------------------------'
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.
128 B has a WS_CLIPSIBLINGS style:
132 | | B | - visible region of B
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.
141 Program asked for a DC with a clipping region:
145 | | B | | => | | | - DC region where the painting will
146 | | | | | | | be visible
147 `--|-----|---' : `----'
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.
161 A was moved to the left:
162 ________________________ ... / C update region
164 | A |_________ | => | ...|___|..
166 |------' | | | : '---'
169 | `------------' | B update region
171 `------------------------'
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
181 windows (Windows 3.1 limits the number of shared DCEs to 5).
185 2. Messaging subsystem
186 ----------------------
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).
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.
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.
221 There are several tricky moments (open for discussion) -
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
236 " Here's the problem in a nutshell, and there is no good solution.
237 Every possible solution creates a different problem.
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.)
243 Mouse input events go to the window you click on (unless some window
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
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.
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.
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.
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.
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
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.
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.
286 There are a few solutions to this problem.
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.
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.
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.
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.
316 As for the pros and cons:
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
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
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)
340 b) Intertask/interthread SendMessage. The system has to inform the
341 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.