Device Contexts


A device context is a device independent means of specifying graphics. A device context may be associated with a video display or a printer or other device. The functions that may be used for creating a new device context are shown in the table below.

begin_paint Creates a device context suitable for painting a window.
get_device_context Creates a display device context.
get_window_device_context Creates a display device context for the entire window.
get_device_context_extended Creates a display device context with clipping control.
create_device_context Creates a device context suitable for printing.
create_memory_device_context Creates a memory device context.
create_informational_device_context Creates an information only device context.
create_metafile Creates a metafile device context.

The first of these functions: begin_paint is usually called in response to the message message::paint. When the application is finished with such a device context, it should call end_paint to release the device context. This sequence creates a device context with attributes suitable for immediate drawing and validates the entire window (the invalid region of a window is the area marked as requiring painting). Drawing in a device context of this type implies that such drawing is clipped to the invalid region of the window. The rectangle found in the paint structure indicates the area to which drawing is restricted. Such a mechanism creates and destroys the device context within the body of the paint message.

The function get_device_context also creates a type of device context that is suitable for drawing in a window. Drawing is not clipped to the invalid region of the window, nor is any portion of the window validated for device contexts of this type. This type of device context is useful for drawing in a window in situations other than receiving a paint message. When finished with a device context of this type, the function release_device_context should be called.

The function get_device_context_extended creates a device context type that allows for clipping control. An application should use release_device_context to destroy device contexts of this type.

The function get_window_device_context creates a device context type that allows for drawing in the entire window - non-client areas included. Applications generally use this type of device context rarely. Such a device context may be released via the function release_device_context.

The function create_device_context is the most general function that may be used to create a device context. It allows for the creation of device contexts associated with any device type, including screens and printers. For example, this function may be used to create a screen device context as shown below.

handle device_context = create_device_context("DISPLAY",0,0,0);

Device contexts of this type are destroyed via the function delete_device_context.

The function create_informational_device_context creates a device context whose sole function is to query attributes of the associated device. Device contexts of this type should be destroyed via a call to the function delete_device_context. An information device for the display may be created via the following call.

handle device_context = create_informational_device_context("DISPLAY",0,0,0);

A device context of type created via the function create_memory_device_context is used for storing bitmaps. When an application no longer requires a device context of this type, it should call the function delete_device_context.

A device context created via the function create_metafile is a metafile device context. This type of device context is destroyed via a call to the function close_metafile. Upon closing such a device context, a handle of the newly created metafile is returned.

Device Capabilities

The program of this section displays device capabilities. The output of the program is shown below.

The program consists of a source code file. The program resembles the programs of the previous chapter (a 3 column textual display) but the information is provided to display the capabilities of a device context. The table includes the indices of the values to be queried and displayed.

The function get_device_capabilities is used to query the actual value of an index. The code sequence (that is part of the paint routine) that performs the query is shown below.

text_out(device_context,
         width_of_character + column1*width_of_capitals + column2*width_of_character,
         height_of_character * (i+1),
          buffer,
         print_string(buffer,"%5d",
                      get_device_capabilities(device_context,capabilities[i].index)));

The remaining portions of the program are taken up with displaying the information so gained via this method.

Colors

The function that queries device capabilities yields detailed information about the color capabilities of the device associated with a device context. Color displays use more than 1 bit/pixel. In particular, the number of colors that may be displayed is 2bits/pixel. Sixteen color devices have 4 bits/pixel and are arranged in color planes. Such devices (VGA) have four color planes - a red plane, a green plane, a blue plane and an intensity plane. VGA devices are somewhat dated. Adapters with 8, 16 or 24 bits per pixel have a single color plane in which a number of adjacent bits are used to represent the color of each pixel.

The function get_device_capabilities allows for the determination of the organisation of memory in the video adapter and the number of colors that may be represented. The number of color planes may be queried using index capability::planes; whereas, the number of bits per pixel may be queried via the index capability::bits_pixel. The number of supported colors may be directly queried via the index capability::colors.

An unsigned integer is used to represent colors within a program. The data type that is used is shown below.

    export struct color
    {
        color()
        {
            argb = (uint)color::black;
        }

        color(byte r,
              byte g,
              byte b)
        {
            argb = make_red_green_blue(255, r, g, b);
        }

        color(byte a,
              byte r,
              byte g,
              byte b)
        {
            argb = make_red_green_blue(a, r, g, b);
        }

        color(uint argb)
        {
            argb = argb;
        }


        uint get_value() const
        {
            return argb;
        }

        void set_value(uint argb)
        {
            argb = argb;
        }

        // common color constants

        enum
        {
            alice_blue = 0xfff0f8ff,
            antique_white = 0xfffaebd7,
            aqua = 0xff00ffff,
            aquamarine = 0xff7fffd4,
            azure = 0xfff0ffff,
            beige = 0xfff5f5dc,
            bisque = 0xffffe4c4,
            black = 0xff000000,
            blanched_almond = 0xffffebcd,
            blue = 0xff0000ff,
            blue_violet = 0xff8a2be2,
            brown = 0xffa52a2a,
            burly_wood = 0xffdeb887,
            cadet_blue = 0xff5f9ea0,
            chartreuse = 0xff7fff00,
            chocolate = 0xffd2691e,
            coral = 0xffff7f50,
            corn_flower_blue = 0xff6495ed,
            corn_silk = 0xfffff8dc,
            crimson = 0xffdc143c,
            cyan = 0xff00ffff,
            dark_blue = 0xff00008b,
            dark_cyan = 0xff008b8b,
            dark_golden_rod = 0xffb8860b,
            dark_gray = 0xffa9a9a9,
            dark_green = 0xff006400,
            dark_khaki = 0xffbdb76b,
            dark_magenta = 0xff8b008b,
            dark_olive_green = 0xff556b2f,
            dark_orange = 0xffff8c00,
            dark_orchid = 0xff9932cc,
            dark_red = 0xff8b0000,
            dark_salmon = 0xffe9967a,
            dark_seagreen = 0xff8fbc8b,
            dark_slate_blue = 0xff483d8b,
            dark_slate_gray = 0xff2f4f4f,
            dark_turquoise = 0xff00ced1,
            dark_violet = 0xff9400d3,
            deep_pink = 0xffff1493,
            deep_sky_blue = 0xff00bfff,
            dim_gray = 0xff696969,
            dodger_blue = 0xff1e90ff,
            firebrick = 0xffb22222,
            floral_white = 0xfffffaf0,
            forest_green = 0xff228b22,
            fuchsia = 0xffff00ff,
            gainsboro = 0xffdcdcdc,
            ghost_white = 0xfff8f8ff,
            gold = 0xffffd700,
            goldenrod = 0xffdaa520,
            gray = 0xff808080,
            green = 0xff008000,
            green_yellow = 0xffadff2f,
            honeydew = 0xfff0fff0,
            hot_pink = 0xffff69b4,
            indian_red = 0xffcd5c5c,
            indigo = 0xff4b0082,
            ivory = 0xfffffff0,
            khaki = 0xfff0e68c,
            lavender = 0xffe6e6fa,
            lavender_blush = 0xfffff0f5,
            lawn_green = 0xff7cfc00,
            lemon_chiffon = 0xfffffacd,
            light_blue = 0xffadd8e6,
            light_coral = 0xfff08080,
            light_cyan = 0xffe0ffff,
            light_golden_rod_yellow = 0xfffafad2,
            light_gray = 0xffd3d3d3,
            light_green = 0xff90ee90,
            light_pink = 0xffffb6c1,
            light_salmon = 0xffffa07a,
            light_sea_green = 0xff20b2aa,
            light_sky_blue = 0xff87cefa,
            light_slate_gray = 0xff778899,
            light_steel_blue = 0xffb0c4de,
            light_yellow = 0xffffffe0,
            lime = 0xff00ff00,
            lime_green = 0xff32cd32,
            linen = 0xfffaf0e6,
            magenta = 0xffff00ff,
            maroon = 0xff800000,
            medium_aquamarine = 0xff66cdaa,
            medium_blue = 0xff0000cd,
            medium_orchid = 0xffba55d3,
            medium_purple = 0xff9370db,
            medium_sea_green = 0xff3cb371,
            medium_slate_blue = 0xff7b68ee,
            medium_spring_green = 0xff00fa9a,
            medium_turquoise = 0xff48d1cc,
            medium_violet_red = 0xffc71585,
            midnight_blue = 0xff191970,
            mint_cream = 0xfff5fffa,
            misty_rose = 0xffffe4e1,
            moccasin = 0xffffe4b5,
            navajo_white = 0xffffdead,
            navy = 0xff000080,
            old_lace = 0xfffdf5e6,
            olive = 0xff808000,
            olive_drab = 0xff6b8e23,
            orange = 0xffffa500,
            orange_red = 0xffff4500,
            orchid = 0xffda70d6,
            pale_golden_rod = 0xffeee8aa,
            pale_green = 0xff98fb98,
            pale_turquoise = 0xffafeeee,
            pale_violet_red = 0xffdb7093,
            papaya_whip = 0xffffefd5,
            peach_puff = 0xffffdab9,
            peru = 0xffcd853f,
            pink = 0xffffc0cb,
            plum = 0xffdda0dd,
            powder_blue = 0xffb0e0e6,
            purple = 0xff800080,
            red = 0xffff0000,
            rosy_brown = 0xffbc8f8f,
            royal_blue = 0xff4169e1,
            saddle_brown = 0xff8b4513,
            salmon = 0xfffa8072,
            sandy_brown = 0xfff4a460,
            sea_green = 0xff2e8b57,
            sea_shell = 0xfffff5ee,
            sienna = 0xffa0522d,
            silver = 0xffc0c0c0,
            sky_blue = 0xff87ceeb,
            slate_blue = 0xff6a5acd,
            slate_gray = 0xff708090,
            snow = 0xfffffafa,
            spring_green = 0xff00ff7f,
            steel_blue = 0xff4682b4,
            tan = 0xffd2b48c,
            teal = 0xff008080,
            thistle = 0xffd8bfd8,
            tomato = 0xffff6347,
            transparent = 0x00ffffff,
            turquoise = 0xff40e0d0,
            violet = 0xffee82ee,
            wheat = 0xfff5deb3,
            white = 0xffffffff,
            white_smoke = 0xfff5f5f5,
            yellow = 0xffffff00,
            yellow_green = 0xff9acd32
        };

        // shift count and bit mask for a, r, g, b components

        enum
        {
            shift_alpha = 24,
            shift_red = 16,
            shift_green = 8,
            shift_blue = 0
        };

        enum
        {
            mask_alpha = 0xff000000,
            mask_red = 0x00ff0000,
            mask_green = 0x0000ff00,
            mask_blue = 0x000000ff
        };

        // assemble a, r, g, b values into a 32-bit integer

        static uint make_red_green_blue(byte a,
            byte r,
            byte g,
            byte b)
        {
            return (((uint)(b) << shift_blue) |
                ((uint)(g) << shift_green) |
                ((uint)(r) << shift_red) |
                ((uint)(a) << shift_alpha));
        }

        uint argb;
    };

The organisation of bits within the data type is depicted in the table below.

0 blue green red
31 ... 24 23 ... 16 15 ... 8 7 ... 0

An inline function exists to create a color from its parts and is shown below.

inline color red_green_blue(byte r, byte g, byte b)
{return ((color)(((byte)(r)|((unsigned char)((byte)(g))<<8))|(((unsigned)(byte)(b))<<16)));}

For example, the color magenta may be represented as red_green_blue(255,0,255) or more directly as 0xff00ff. The three inline functions that are available for extracting a particular color component from an unsigned integer are shown below.

inline byte red_value(unsigned red_green_blue)   {return ((byte)(red_green_blue));}
inline byte green_balue(unsigned red_green_blue) {return ((byte)(((unsigned char)(red_green_blue)) >> 8));}
inline byte blue_value(unsigned red_green_blue)  {return ((byte)((red_green_blue)>>16));}

The following table shows several individual colors.

Value Color
0x0000ff red
0x00ff00 green
0xff0000 blue
0x000000 Black
0xffffff White

Device Context Attributes

Device contexts have associated attributes. When a device context is first created, default values are applied for attributes. The following table documents device context attributes.

Attribute Default Value function to Set function to Query
unit mode unit::pixel set_mapping_mode get_mapping_mode
window origin (0,0) set_window_origin
offset_window_origin
get_window_origin
viewport origin (0,0) set_viewport_origin
offset_viewport_origin
get_viewport_origin
window extents (1,1) set_window_extent
scale_window_extent
set_mapping_mode
get_window_extent
viewport extents (1,1) set_viewport_extent
scale_viewport_extent
set_mapping_mode
get_viewport_extent
pen standard_pen::black select_object get_current_object
brush standard_brush::white select_object get_current_object
font standard_font::system select_object get_current_object
bitmap none select_object get_current_object
position (0,0) move_to
draw_line_to
draw_lines_to
draw_splines_to
get_current_position
background mode background::opaque set_background_mode get_background_mode
background color white set_background_color get_background_color
text color black set_text_color get_text_color
drawing mode mix::copy_pen set_foreground_mix get_foreground_mix
stretch mode stretch_block_mode::and set_stretch_bit_block_mode get_stretch_bit_block_mode
filling mode fill_mode::alternate set_fill_mode get_fill_mode
extra spacing 0 set_text_character_extra get_text_character_extra
brush origin (0,0) set_brush_origin get_brush_origin
clipping region none select_clipping_region
intersect_clipping_rectangle
offset_clipping_region
exclude_clipping_rectangle
exclude_update_region
select_clipping_path
get_clip_box

Saving and Restoring Device Context Attributes

All of the attributes of a device context may be saved using the function save_device_context. Saved attributes may be later restored using the function restore_device_context.

Apart from this, when registering a window class, the class style class_style::own_device_context may be applied. When this style is applied, each window of the class has its own device context set aside. In this case, when a device context is created, destroyed and later recreated, it retains the most recent device context attributes.