[comp.sys.mac.programmer] SUMMARY: Screen depth with colour systems/multiple monitors

iand@mullian.ee.mu.OZ.AU (Ian Robert DOBSON) (01/03/91)

SUMMARY:

> I am programming a window at present which will use colour if
> the machine is equipped with Color QuickDraw.  However, to
> optimise the display for users with a b/w monitor, I want
> to handle redraw specially when the monitor is in 1 or 2
> bit mode.
>
> What I need is a mechanism to detect the screen depth of my
> window.  I thought of examining the window's pixmap, but
> it raises the following questions:

----------------------------------------------------------------------
> 1. What happens to a window's pixmap if, in a multi-monitor
>    environment, the window is moved from a >= 8 bit monitor
>    to a b/w display?

Color Quickdraw (CQD) translates the color pixels of the window
(or your color QD calls on an update) into B&W pixels.  The
window's pixmap still exists at its original depth, so it will
retain colour information even though it is being displayed on a
black & white screen.  When the window is moved back to the colour
display, any colour QD drawing performed when the window was on
the B&W screen will be properly displayed in colour.


----------------------------------------------------------------------
> 2. How is a window straddling a screen boundary (and thus
>    displayed partially on both screens) stored in memory?

Once again CQD does the necessary work for you. The pixmap
still exists at its original depth, but CQD does the final
mapping to B&W on the one monitor, and color display on the
color monitor.


----------------------------------------------------------------------
> 3. What determines a pixmap's original depth?
>    Are all windows created at maximum depth for the system
>    (say 24 bits), in which case a window on the mono display
>    would still use 24 bits per pixel and be grossly memory
>    inefficient.

Close! All color windows and color grafports are created at
the depth of the "current" graphics device. This is normally
the main monitor - the one with the menu bar on it. If the
current device is a 1-bit B&W monitor, then your color windows
will have two colors only - black and white.

The Mac OS always sets the current device to the main monitor,
but the programmer can change the current device with a call
to SetGDevice - be sure to save a reference to the original
device using GetGDevice and to restore the current device
to that reference when you're done.


----------------------------------------------------------------------
> 4. How do I ensure my window update method is consistant
>    in a multi-monitor environment?  I.E. I don't want
>    half my window to be updated one way and half the
>    other.  If the window appears on more than one monitor,
>    should I draw the window contents with a method suited
>    to the monitor with the lowest screen depth?  If so, how
>    do I find this depth?

Most people just let CQD do the work for them. There are times
though were the B&W results are not good enough. In this case,
you need to write code that identifies the environment(s) that
the window exists in, and special case the drawing to each of
those environments.

This is not a trivial piece of work. It means finding out the
bit depth of the various monitors your window overlaps. Then
you must find the regions of your grafport that intersect the
each monitor. Once you have this information, you can then
draw into each of these regions in a manner best suited for
the bit depth of that region.

The routine you want is:
        FUNCTION GetMaxDevice(globalRect: Rect) : GDHandle
which is described in IM V-125.  Basically, you pass it a rectangle
(your portRect) converted to global coordinates (SetPort, 
LocalToGlobal twice) and it finds the deepest GDevice that intersects.
Look in the GDevice for the depth (maxgdh^^.gdPMap^^.pixelSize).

One thing you end up doing a lot on color QD systems is walking the
GDevice list, which is a linked list of handles.  The rectangle in
global coordinates that the GDevice occupies is in gdRect.  You also
need to check if it's a screenDevice.  Look at the GDevice chapter.

If you're using offscreen pixmaps, you'd do best to use the GWorld
stuff (documented in very few places, part of 32-Bit QD) or perhaps
the DTS sample code which does similar things.


-----------
SAMPLE CODE
-----------

----------------------------------------
From: daven@sv.portal.com (David Newman)
----------------------------------------

{ Does the window have a pixmap, and what is the pixmap's depth }
 PROCEDURE WindowInfo (theWindow: WindowPtr; VAR hasColor: Boolean;
           VAR bitDepth: integer);
 BEGIN
     hasColor := BTst(theWindow^.portBits.rowBytes, 15);  {IF bit 15=1 THEN pixMap}
     IF hasColor THEN
         bitDepth := CGrafPtr(theWindow)^.portPixMap^^.pixelSize
     ELSE
         bitDepth := 1;
 END;


{ Returns the bitDepth of the monitor on which theWindow is located.
  If theWindow spans multiple monitors, then the largest depth is returned}

 PROCEDURE MonitorInfo (theWindow: WindowPtr; VAR bitDepth: integer);
 VAR
     tempRect: Rect;
     oldPort: GrafPtr;
     theDevice: GDHandle;
 BEGIN
     GetPort(oldPort);

     SetPort(theWindow);
     tempRect := theWindow^.portRect;
     LocalToGlobal(tempRect.topLeft);
     LocalToGlobal(tempRect.botRight);

     IF theWorld.hasColorQD THEN
         BEGIN
             theDevice := GetMaxDevice(tempRect);
             IF BTst(theDevice^^.gdPMap^^.rowBytes, 15) THEN        {IF bit 15=1 THEN pixMap}
                 bitDepth := theDevice^^.gdPMap^^.pixelSize
             ELSE
                 bitDepth := 1;
         END
     ELSE
         bitDepth:=1;

     SetPort(oldPort);
 END;


{ Returns max bit depth of deepest monitor in the VAR parameter, and TRUE cpu has ColorQD }
 FUNCTION WorldInfo (VAR bitDepth: integer): Boolean;
 VAR
     tempRect: Rect;
     theDevice: GDHandle;
 BEGIN
     WorldInfo := FALSE;
     SetRect(tempRect, -maxint-1,-maxint-1,maxint,maxint);

     IF theWorld.hasColorQD THEN
         BEGIN
             WorldInfo := TRUE;
             theDevice := GetMaxDevice(tempRect);
             IF BTst(theDevice^^.gdPMap^^.rowBytes, 15) THEN        {IF bit 15=1 THEN pixMap}
                 bitDepth := theDevice^^.gdPMap^^.pixelSize
             ELSE
                  bitDepth := 1;
         END
     ELSE
         bitDepth := 1;
 END;


------------------------------------------------
From: well!oster@apple.com (David Phillip Oster)
------------------------------------------------

Use a loop like the following:

if (world.hasColorQD) {
    for (gdh = GetDeviceList();gdh != NIL;gdh = GetNextDevice(gdh)) { /* loop through devices */
        if ( TestDeviceAttribute(gdh, screenActive) &&                          /* is active? */
             TestDeviceAttribute(gdh, screenDevice) &&                           /* and a CRT */
             (rg = (**gdh).gdRect, PtInRect(where, &rg))) {           /* and contains "where" */

                *r = (**gdh).gdRect;
                if (gdh == GetMainDevice()) {
                    r->top += MenuBarSize();   /* trim off menu bar */
                }
                return;                        /* <- found it, exit */
        }
    }
}

to scan the device list, looking for the devices that intersect your
window (copy the portRect to a temp, then use LocalToGlobal on the
topLeft() and botRight() of the temp.)

I call:

/* SetUseColor - use color style hiliting only on machines that handle it
        correctly (i.e, have Color QuickDraw and more than one bit-per pixel
        CRT attached.)
 */
SetUseColor() {
    GDHandle gd;
    Rect desktop;

    useColor = FALSE;
    if (world.hasColorQD) {
        desktop = (**GrayRgn).rgnBBox;
        gd = GetMaxDevice(&desktop);
        useColor = (NIL != gd && (**(**gd).gdPMap).pixelSize > 1);
    }
}

from each activate/update, sicne if the user changes the window depth, the
window will get an update.  This almost works.
If a window straddles more than one screen, and both parts need updating,
you see 1 update update for the whole thing,so you have to split it into
per-device rectangles yourself.


-------------------------------------------------------------------------

Thanks to all who responded to my request.  The help was most appreciated.


' )       ' )  )  ' /~\      /            | Dept. of Electrical Engineering
 / __  _   /--'    /  / ____/____  _____  | University of Melbourne, Australia
/ (_(_/ ) /   \ o /__( (_) /_) _)_(_) / ) | UUCP: iand@mullian.ee.mu.oz.AU