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.