|  | KERNEL MODULE | 
|  | ============= | 
|  |  | 
|  | ... | 
|  |  | 
|  | GDI MODULE | 
|  | ========== | 
|  |  | 
|  | 1. X Windows System interface | 
|  | ----------------------------- | 
|  |  | 
|  | The X libraries used to implement X clients (such as Wine) do not work | 
|  | properly if multiple threads access the same display concurrently. It is | 
|  | possible to compile the X libraries to perform their own synchronization | 
|  | (initiated by calling XInitThreads()). However, Wine does not use this | 
|  | approach. Instead Wine performs its own synchronization py putting a | 
|  | wrapper around every X call that is used. This wrapper protects library | 
|  | access with a critical section, and also arranges things so that X | 
|  | libraries compiled without -D_REENTRANT (eg. with global errno variable) | 
|  | will work with Wine. | 
|  |  | 
|  | To make this scheme work, all calls to X must use the proper wrapper | 
|  | functions (or do their own synchronization that is compatible with the | 
|  | wrappers). The wrapper for a function X...() is calles TSX...() (for | 
|  | "Thread Safe X ..."). So for example, instead of calling XOpenDisplay() | 
|  | in the code, TSXOpenDisplay() must be used. Likewise, X include files | 
|  | that contain function prototypes are wrapped, so that eg. "ts_xutil.h" | 
|  | must be included rather than <X11/Xutil.h>. It is important that this | 
|  | scheme is used everywhere to avoid the introduction of nondeterministic | 
|  | and hard-to-find errors in Wine. | 
|  |  | 
|  | The code for the thread safe X wrappers is contained in the tsx11/ | 
|  | directory and in include/ts*.h. To use a new (ie. not previously used) X | 
|  | function in Wine, a new wrapper must be created. The wrappers are | 
|  | generated (semi-)automatically from the X11R6 includes using the | 
|  | tools/make_X11wrappers perl script. In simple cases it should be enough | 
|  | to add the name of the new function to the list in tsx11/X11_calls; if | 
|  | this does not work the wrapper must be added manually to the | 
|  | make_X11wrappers script. See comments in tsx11/X11_calls and | 
|  | tools/make_X11wrappers for further details. | 
|  |  | 
|  |  | 
|  | USER MODULE | 
|  | =========== | 
|  |  | 
|  | USER implements windowing and messaging subsystems. It also | 
|  | contains code for common controls and for other miscellaneous | 
|  | stuff (rectangles, clipboard, WNet, etc). Wine USER code is | 
|  | located in windows/, controls/, and misc/ directories. | 
|  |  | 
|  | 1. Windowing subsystem | 
|  | ---------------------- | 
|  |  | 
|  | windows/win.c | 
|  | windows/winpos.c | 
|  |  | 
|  | Windows are arranged into parent/child hierarchy with one | 
|  | common ancestor for all windows (desktop window). Each window | 
|  | structure contains a pointer to the immediate ancestor (parent | 
|  | window if WS_CHILD style bit is set), a pointer to the sibling | 
|  | (returned by GetWindow(..., GW_NEXT)), a pointer to the owner | 
|  | window (set only for popup window if it was created with valid | 
|  | hwndParent parameter), and a pointer to the first child | 
|  | window (GetWindow(.., GW_CHILD)). All popup and non-child windows | 
|  | are therefore placed in the first level of this hierarchy and their | 
|  | ancestor link (wnd->parent) points to the desktop window. | 
|  |  | 
|  | Desktop window			- root window | 
|  | |     \      `-. | 
|  | |      \        `-. | 
|  | popup -> wnd1  ->  wnd2		- top level windows | 
|  | |       \   `-.      `-. | 
|  | |        \     `-.      `-. | 
|  | child1  child2 -> child3  child4     - child windows | 
|  |  | 
|  | Horizontal arrows denote sibling relationship, vertical lines | 
|  | - ancestor/child. To summarize, all windows with the same immediate | 
|  | ancestor are sibling windows, all windows which do not have desktop | 
|  | as their immediate ancestor are child windows. Popup windows behave | 
|  | as topmost top-level windows unless they are owned. In this case the | 
|  | only requirement is that they must precede their owners in the top-level | 
|  | sibling list (they are not topmost). Child windows are confined to the | 
|  | client area of their parent windows (client area is where window gets | 
|  | to do its own drawing, non-client area consists of caption, menu, borders, | 
|  | intrinsic scrollbars, and minimize/maximize/close/help buttons). | 
|  |  | 
|  | Another fairly important concept is "z-order". It is derived from | 
|  | the ancestor/child hierarchy and is used to determine "above/below" | 
|  | relationship. For instance, in the example above, z-order is | 
|  | child1->popup->child2->child3->wnd1->child4->wnd2->desktop. Current | 
|  | active window ("foreground window" in Win32) is moved to the front | 
|  | of z-order unless its top-level ancestor owns popup windows. | 
|  |  | 
|  | All these issues are dealt with (or supposed to be) in windows/winpos.c | 
|  | with SetWindowPos() being the primary interface to the window manager. | 
|  |  | 
|  | Wine specifics: in default and managed mode each top-level window | 
|  | gets its own X counterpart with desktop window being basically a | 
|  | fake stub. In desktop mode, however, only desktop window has an X | 
|  | window associated with it. Also, SetWindowPos() should eventually be | 
|  | implemented via Begin/End/DeferWindowPos() calls and not the other way | 
|  | around. | 
|  |  | 
|  | 1.1 Visible region, clipping region and update region | 
|  |  | 
|  | windows/dce.c | 
|  | windows/winpos.c | 
|  | windows/painting.c | 
|  |  | 
|  | ________________________ | 
|  | |_________               |  A and B are child windows of C | 
|  | |    A    |______        | | 
|  | |         |      |       | | 
|  | |---------'      |       | | 
|  | |   |      B     |       | | 
|  | |   |            |       | | 
|  | |   `------------'       | | 
|  | |                   C    | | 
|  | `------------------------' | 
|  |  | 
|  | Visible region determines which part of the window is not obscured | 
|  | by other windows. If a window has the WS_CLIPCHILDREN style then all | 
|  | areas below its children are considered invisible. Similarily, if | 
|  | the WS_CLIPSIBLINGS bit is in effect then all areas obscured by its | 
|  | siblings are invisible. Child windows are always clipped by the | 
|  | boundaries of their parent windows. | 
|  |  | 
|  | B has a WS_CLIPSIBLINGS style: | 
|  | .          ______ | 
|  | :         |      | | 
|  | |   ,-----'      | | 
|  | |   |      B     | - visible region of B | 
|  | |   |            | | 
|  | :   `------------' | 
|  |  | 
|  | When the program requests a display context (DC) for a window it | 
|  | can specify an optional clipping region that further restricts the | 
|  | area where the graphics output can appear. This area is calculated | 
|  | as an intersection of the visible region and a clipping region. | 
|  |  | 
|  | Program asked for a DC with a clipping region: | 
|  | ______ | 
|  | ,--|--.   |     .    ,--. | 
|  | ,--+--'  |   |     :   _:  | | 
|  | |  |   B |   |  => |  |    | - DC region where the painting will | 
|  | |  |     |   |     |  |    |   be visible | 
|  | `--|-----|---'     :  `----' | 
|  | `-----' | 
|  |  | 
|  | When the window manager detects that some part of the window | 
|  | became visible it adds this area to the update region of this | 
|  | window and then generates WM_ERASEBKGND and WM_PAINT messages. | 
|  | In addition, WM_NCPAINT message is sent when the uncovered area | 
|  | intersects a nonclient part of the window. Application must reply | 
|  | to the WM_PAINT message by calling BeginPaint()/EndPaint() pair of | 
|  | functions. BeginPaint() returns a DC that uses accumulated update | 
|  | region as a clipping region. This operation cleans up invalidated | 
|  | area and the window will not receive another WM_PAINT until the | 
|  | window manager creates a new update region. | 
|  |  | 
|  | A was moved to the left: | 
|  | ________________________       ...          / C update region | 
|  | |______                  |     :      .___ / | 
|  | | A    |_________        |  => |   ...|___|.. | 
|  | |      |         |       |     |   :  |   | | 
|  | |------'         |       |     |   :  '---' | 
|  | |   |      B     |       |     |   :      \ | 
|  | |   |            |       |     :            \ | 
|  | |   `------------'       |                    B update region | 
|  | |                   C    | | 
|  | `------------------------' | 
|  |  | 
|  |  | 
|  | Windows maintains a display context cache consisting of entries that | 
|  | include DC itself, window to which it belongs, and an optional clipping | 
|  | region (visible region is stored in the DC itself). When an API call | 
|  | changes the state of the window tree, window manager has to go through | 
|  | the DC cache to recalculate visible regions for entries whose windows | 
|  | were involved in the operation. DC entries (DCE) can be either private | 
|  | to the window, or private to the window class, or shared between all | 
|  | windows (Windows 3.1 limits the number of shared DCEs to 5). | 
|  |  | 
|  | 1.2 | 
|  |  | 
|  | 2. Messaging subsystem | 
|  | ---------------------- | 
|  |  | 
|  | windows/queue.c | 
|  | windows/message.c | 
|  |  | 
|  | Each Windows task/thread has its own message queue - this is where | 
|  | it gets messages from. Messages can be generated on the fly | 
|  | (WM_PAINT, WM_NCPAINT, WM_TIMER), they can be created by the system | 
|  | (hardware messages), they can be posted by other tasks/threads | 
|  | (PostMessage), or they can be sent by other tasks/threads (SendMessage). | 
|  |  | 
|  | Message priority: | 
|  |  | 
|  | First the system looks for sent messages, then for posted messages, | 
|  | then for hardware messages, then it checks if the queue has the | 
|  | "dirty window" bit set, and, finally, it checks for expired | 
|  | timers. See windows/message.c. | 
|  |  | 
|  | From all these different types of messages, only posted messages go | 
|  | directly into the private message queue. System messages (even in | 
|  | Win95) are first collected in the system message queue and then | 
|  | they either sit there until Get/PeekMessage gets to process them | 
|  | or, as in Win95, if system queue is getting clobbered, a special | 
|  | thread ("raw input thread") assigns them to the private | 
|  | queues. Sent messages are queued separately and the sender sleeps | 
|  | until it gets a reply. Special messages are generated on the fly | 
|  | depending on the window/queue state. If the window update region is | 
|  | not empty, the system sets the QS_PAINT bit in the owning queue and | 
|  | eventually this window receives a WM_PAINT message (WM_NCPAINT too | 
|  | if the update region intersects with the non-client area). A timer | 
|  | event is raised when one of the queue timers expire. Depending on | 
|  | the timer parameters DispatchMessage either calls the callback | 
|  | function or the window procedure. If there are no messages pending | 
|  | the task/thread sleeps until messages appear. | 
|  |  | 
|  | There are several tricky moments (open for discussion) - | 
|  |  | 
|  | a) System message order has to be honored and messages should be | 
|  | processed within correct task/thread context. Therefore when | 
|  | Get/PeekMessage encounters unassigned system message and this | 
|  | message appears not to be for the current task/thread it should | 
|  | either skip it (or get rid of it by moving it into the private | 
|  | message queue of the target task/thread - Win95, AFAIK) and | 
|  | look further or roll back and then yield until this message | 
|  | gets processed when system switches to the correct context | 
|  | (Win16). In the first case we lose correct message ordering, in | 
|  | the second case we have the infamous synchronous system message | 
|  | queue. Here is a post to one of the OS/2 newsgroup I found to | 
|  | be relevant: | 
|  |  | 
|  | " Here's the problem in a nutshell, and there is no good solution. | 
|  | Every possible solution creates a different problem. | 
|  |  | 
|  | With a windowing system, events can go to many different windows. | 
|  | Most are sent by applications or by the OS when things relating to | 
|  | that window happen (like repainting, timers, etc.) | 
|  |  | 
|  | Mouse input events go to the window you click on (unless some window | 
|  | captures the mouse). | 
|  |  | 
|  | So far, no problem.  Whenever an event happens, you put a message on | 
|  | the target window's message queue.  Every process has a message | 
|  | queue.  If the process queue fills up, the messages back up onto the | 
|  | system queue. | 
|  |  | 
|  | This is the first cause of apps hanging the GUI.  If an app doesn't | 
|  | handle messages and they back up into the system queue, other apps | 
|  | can't get any more messages.  The reason is that the next message in | 
|  | line can't go anywhere, and the system won't skip over it. | 
|  |  | 
|  | This can be fixed by making apps have bigger private message queues. | 
|  | The SIQ fix does this.  PMQSIZE does this for systems without the SIQ | 
|  | fix.  Applications can also request large queues on their own. | 
|  |  | 
|  | Another source of the problem, however, happens when you include | 
|  | keyboard events.  When you press a key, there's no easy way to know | 
|  | what window the keystroke message should be delivered to. | 
|  |  | 
|  | Most windowing systems use a concept known as "focus".  The window | 
|  | with focus gets all incoming keyboard messages.  Focus can be changed | 
|  | from window to window by apps or by users clicking on winodws. | 
|  |  | 
|  | This is the second source of the problem.  Suppose window A has focus. | 
|  | You click on window B and start typing before the window gets focus. | 
|  | Where should the keystrokes go?  On the one hand, they should go to A | 
|  | until the focus actually changes to B.  On the other hand, you | 
|  | probably want the keystrokes to go to B, since you clicked there | 
|  | first. | 
|  |  | 
|  | OS/2's solution is that when a focus-changing event happens (like | 
|  | clicking on a window), OS/2 holds all messages in the system queue | 
|  | until the focus change actually happens.  This way, subsequent | 
|  | keystrokes go to the window you clicked on, even if it takes a while | 
|  | for that window to get focus. | 
|  |  | 
|  | The downside is that if the window takes a real long time to get focus | 
|  | (maybe it's not handling events, or maybe the window losing focus | 
|  | isn't handling events), everything backs up in the system queue and | 
|  | the system appears hung. | 
|  |  | 
|  | There are a few solutions to this problem. | 
|  |  | 
|  | One is to make focus policy asynchronous.  That is, focus changing has | 
|  | absolutely nothing to do with the keyboard.  If you click on a window | 
|  | and start typing before the focus actually changes, the keystrokes go | 
|  | to the first window until focus changes, then they go to the second. | 
|  | This is what X-windows does. | 
|  |  | 
|  | Another is what NT does.  When focus changes, keyboard events are held | 
|  | in the system message queue, but other events are allowed through. | 
|  | This is "asynchronous" because the messages in the system queue are | 
|  | delivered to the application queues in a different order from that | 
|  | with which they were posted.  If a bad app won't handle the "lose | 
|  | focus" message, it's of no consequence - the app receiving focus will | 
|  | get its "gain focus" message, and the keystrokes will go to it. | 
|  |  | 
|  | The NT solution also takes care of the application queue filling up | 
|  | problem.  Since the system delivers messages asynchronously, messages | 
|  | waiting in the system queue will just sit there and the rest of the | 
|  | messages will be delivered to their apps. | 
|  |  | 
|  | The OS/2 SIQ solution is this:  When a focus-changing event happens, | 
|  | in addition to blocking further messages from the application queues, | 
|  | a timer is started.  When the timer goes off, if the focus change has | 
|  | not yet happened, the bad app has its focus taken away and all | 
|  | messages targetted at that window are skipped.  When the bad app | 
|  | finally handles the focus change message, OS/2 will detect this and | 
|  | stop skipping its messages. | 
|  |  | 
|  |  | 
|  | As for the pros and cons: | 
|  |  | 
|  | The X-windows solution is probably the easiest.  The problem is that | 
|  | users generally don't like having to wait for the focus to change | 
|  | before they start typing.  On many occasions, you can type and the | 
|  | characters end up in the wrong window because something (usually heavy | 
|  | system load) is preventing the focus change from happening in a timely | 
|  | manner. | 
|  |  | 
|  | The NT solution seems pretty nice, but making the system message queue | 
|  | asynchronous can cause similar problems to the X-windows problem. | 
|  | Since messages can be delivered out of order, programs must not assume | 
|  | that two messages posted in a particular order will be delivered in | 
|  | that same order.  This can break legacy apps, but since Win32 always | 
|  | had an asynchronous queue, it is fair to simply tell app designers | 
|  | "don't do that".  It's harder to tell app designers something like | 
|  | that on OS/2 - they'll complain "you changed the rules and our apps | 
|  | are breaking." | 
|  |  | 
|  | The OS/2 solution's problem is that nothing happens until you try to | 
|  | change window focus, and then wait for the timeout.  Until then, the | 
|  | bad app is not detected and nothing is done." (by David Charlap) | 
|  |  | 
|  |  | 
|  | b) Intertask/interthread SendMessage. The system has to inform the | 
|  | target queue about the forthcoming message, then it has to carry | 
|  | out the context switch and wait until the result is available. | 
|  | Win16 stores necessary parameters in the queue structure and then | 
|  | calls DirectedYield() function.  However, in Win32 there could be | 
|  | several messages pending sent by preemptively executing threads, | 
|  | and in this case SendMessage has to build some sort of message | 
|  | queue for sent messages. Another issue is what to do with messages | 
|  | sent to the sender when it is blocked inside its own SendMessage. | 
|  |  | 
|  |  |