
                ShapeWin - non-rectangular window support

        Copyright (C) 1998-2001 Software Research Associates, Inc.

                    akira@sra.co.jp

1. Introduction

    It is bit hard for OS/2 PM to display images on desktop without 
    window rectangle.

        Once, I tried such program and failed.  Copying some area of
        desktop and write images over it, it seems as drawing desktop
        direct, but if background was changed, unmatched background
        appears.

    Then, I read Shape Extension code of X server, and astonished at its
    simple implementation, and thought it may be implemented on PM. 
    Now, I implemented shape extension look-alike on PM, and release to
    public.

2. Creating Shape Window

2.1. Registering Window Class

    Shape Window was implemented as custom control (widget). To use it,
    you need to register window class with 'WinRegisterClass'.
    
        WinRegisterClass(
	    hab,                Anchor Block Handle
	    ShapeWinName,       Class Name
	    ShapeWinProc,       Window Procedure
	    0L,                 Default Window Style
	    sizeof(PVOID)) ;    Class Data Size
        
    Class name and window procedure is defined in 'shapewin.h'.  But
    class name may be another name.  Class data size should be above
    size.

2.2. Create Shape Window

    You can create Shape Window with 'WinCreateWindow' as normal windows.
    But you should note followings.

    o To display shape (non-rectangular) window on your desktop, parent
      window should be DESKTOP.  Otherwise, shape window will displayed
      in another normal (rectanglar) window.

    o For normal PM programs, top level window is frame window (or sub-
      classed frame window).  Shape window itself don't have function
      corresponds to frame window.  So using shape window as top level
      window is danger.

    o According to above two, you should use frame window as top level
      window, and create shape window with frame window as owner window.
      But in this method, you should sub-class frame window and append
      some message processing (described later).

    o Control Data is required to create shape window (cannot omit). 
      Detail of control data will describe later.

    o Size of shape window is defined by control data and you cannot
      change it size later.  Also, size parameters in WinCreateWindow
      is ignored.

2.3. Shape Control Data

    Size, shape and contents of shape window is defined with control
    data.

        You can change contents of shape window after, but you cannot
	change shape and size of shape window.

    Control data for shape window is defined below (shapewin.h).
    
    typedef struct _SHAPEWIN {
        SHORT   cx, cy  ;       Size of Shape
        HPS     hpsMask ;       Mask Pattern (as Shape)
        HPS     hpsDraw ;       Source of Drawing Data
    } SHAPEWIN, *PSHAPEWIN ;

    cx * cy image in a presentation space 'hpsMask' determines shape of
    shape window (as mask pattern).  And image in a presentation space 
    'hpsDraw' will  written to shape window (drawing data).

2.4. Mask Pattern

    Shape window uses image in 'hpsMask' as mask pattern.  It assumes
    color at pixel (0, 0) as background color, and area of another color
    as shape of drawing area.
    
    Usually, fill memory PS with background color and draw any image
    over it.  If background color is not in drawing area, you may use
    same memory PS as both mask pattern and drawing data.

        Samples programs all uses this method.
    
    There is no limit for size of mask pattern.  But using large image,
    or complicated image eat up lot CPU.
    
2.5. Update Drawing Data

    Via presentaion space 'hpsDraw', you can update contents of shape
    window.

    You can draw anything on presetation space 'hpsDraw'. To update
    new images on 'hpsDraw' to shape window, send following message to
    shape window.

    SHAPEWIN_MSG_UPDATE     Request to update window contents
    
        param1          PRECTL      update region
	param2          NULL

    Only a part of 'hpsDraw' was changed, and want to avoid unneccesary
    drawing, specify update region to restrict window updates. Update
    region may NULL, in this case, shape window redraw entire area.
    Redraw on shape window is quite a heavy processing, your should
    specify update region.

        But if your CPU & Video board fast enough, redrawing entire
        region  may be faster.

3. Combination with Frame Window
    
    Contents of this section is so called 'VooDoo'.  Following methods
    works for my environment (Warp3/Connect), but I am not sure they
    works other environments.  If these methods bot worked on your
    environments, or if you know more good methods, let me know.

    If you use shape window, you want to draw some images on desktop
    direct (not in another window).  For this, you should create shape
    window as child of desktop window.  But shape window does not have
    frame functions, use shape window as top level window is dangerous.
    So you should create shape window with

        Parent Window       DESKTOP (HWND_DESKTOP)
        Owner Window        frame window
    
    If you create frame & shape window as above, there is no parent/
    child releation between frame and shape.  In this case, some
    controls usually worked between frame and client does not works.
    To enable such controls, you should customize (sub-class) frame
    window processing.
    
    Also, if you create frame & shape as above, both frame and shape
    window appear on desktop.  To hide frame window (to use non-
    rectangular drawing are on desktop), you should customize frame
    window, too.

3.1. Relay Frame Control Messages

    If size, position, or Z-order of frame window was changed, following
    frame window procedure receives following messages.
    
        WM_ADJUSTWINDOWPOS      before change
	WM_WINDOWPOSCHANGED     after  change

    To follow shape window's position, Z-order to frame window, hook
    these messages and control shape window's position / Z-order, such
    as

        case WM_ADJUSTWINDOWPOS :
	    pswp = (PSWP) PVOIDFROMMP(mp1) ;
	    WinSetWindowPos(hwndShape, pswp->hwndInsetBehind,
	            pswp->x, pswp->y, pswp->cx, pswp->cy, pswp->fl) ;
            return defaultFrameProc(...) ;

    or
    
        case WM_WINDOWPOSCHANGED :
	    pswp = (PSWP) PVOIDFROMMP(mp1) ;
	    WinSetWindowPos(hwndShape, pswp->hwndInsetBehind,
	            pswp->x, pswp->y, pswp->cx, pswp->cy, pswp->fl) ;
            return defaultFrameProc(...) ;

    But WM_WINDOWPOSCHANGED will never happen if you make frame window
    invisible (describe in next section).

    See sample codes for more deatils.

3.2. Invisible Frame Window

    Create frame and shape window, but not to show frame window, you can
    make frame window invisible.
    
    To do this, hook 'WM_ADJUSTWINDOWPOS' message and modify SWP data.

        case WM_ADJUSTWINDOWPOS :
	    pswp = (PSWP) PVOIDFROMMP(mp1) ;
	    WinSetWindowPos(hwndShape, pswp->hwndInsetBehind,
	            pswp->x, pswp->y, pswp->cx, pswp->cy, pswp->fl) ;
            pswp->fl &= ~SWP_SHOW ;
            return defaultFrameProc(...) ;

    Also you can make frame window to fixed size as

        case WM_ADJUSTWINDOWPOS :
	    pswp = (PSWP) PVOIDFROMMP(mp1) ;
	    WinSetWindowPos(hwndShape, pswp->hwndInsetBehind,
	            pswp->x, pswp->y, pswp->cx, pswp->cy, pswp->fl) ;
            pswp->cx = fixed_width  ;
            pswp->cy = fixed_height ;
            pswp->fl &= ~SWP_SHOW ;
            return defaultFrameProc(...) ;

    See sample codes (trbitmap.c, tranime.c) for more deatils.

3.3. Notify Key & Mouse Events

    Key and mouse events in shape window will send to it's owner (frame
    window).  So if you want to control on such event, you should
    implement such code on (customized) frame window procedure.

    For mouse related messages, mouse position is set in their parameter.
    But if they are transferred from shape window, those positions are
    relative to small windows wich contruct shape window itself, and not
    adjusted to frame window relative.

    If you need mouse positions, use 'WinQueryPointerPos' to acquire
    correct mouse locations.

    See sample codes (trbitmap.c, treyes.c) for more details.
