/* $XConsortium: pexutcmapint.c,v 1.0 93/11/22 12:23:48 rws Exp $ */ /******************************************************************************/ /* */ /* (c) Copyright Hewlett-Packard Company, 1992, Fort Collins, Colorado */ /* */ /* All Rights Reserved */ /* */ /* Permission to use, copy, modify, and distribute this software and its */ /* documentation for any purpose and without fee is hereby granted, */ /* provided that the above copyright notices appear in all copies and that */ /* both the copyright notices and this permission notice appear in */ /* supporting documentation, and that the name of Hewlett-Packard not be */ /* used in advertising or publicity pertaining to distribution of the */ /* software without specific, written prior permission. */ /* */ /* HEWLETT-PACKARD MAKES NO WARRANTY OF ANY KIND WITH REGARD TO THIS */ /* SOFTWARE, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF */ /* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Hewlett-Packard */ /* shall not be liable for errors contained herein or direct, indirect, */ /* special, incidental or consequential damages in connection with the */ /* furnishing, performance or use of this software. */ /* */ /******************************************************************************/ /******************************************************************************/ /* */ /* $Source: /net/expo/xsrc/xc/unsupported/./test/suspex/src/pexut_hp/RCS/pexutcmapint.c,v $ */ /* $Date: 93/11/22 12:23:48 $ */ /* $Revision: 1.0 $ */ /* */ /* Description: */ /* Internal routine implementation file for PEXUt colormap/visual utilities.*/ /* */ /* Notes: */ /* */ /******************************************************************************/ #include #include #include #include #include #include #include #include "pexutext.h" #include "pexutcmap.h" #include "pexutcmapint.h" #ifndef MBX_HEADER_FILE_NOT_INSTALLED /* [ */ #include #endif /* !MBX_HEADER_FILE_NOT_INSTALLED ] */ #include "pexutdbint.h" int pexut_get_standard_cmap_property ( display, screen, property_info, property_atom_return, property_count_return, property_data_return ) Display *display; int screen; interop_property_type *property_info; Atom *property_atom_return; int *property_count_return; XStandardColormap **property_data_return; { Atom actual_type; int actual_format; unsigned long item_count; unsigned long item_count_return, bytes_unread; int result; if ( !property_info->is_standard) { if (property_info->have_atom) *property_atom_return = property_info->property_atom; else { /* Get the atom from the X server. If it doesn't exist, neither does the property. This should not be considered a fatal error. */ *property_atom_return = XInternAtom(display, property_info->property_name, True); if (*property_atom_return == None) { *property_count_return = 0; return PEXUtSuccess; } } /* Property atom exists - fetch the property. */ bytes_unread = 0; item_count = sizeof(XStandardColormap)/4; do { item_count += (bytes_unread+3)/4; result = XGetWindowProperty (display, RootWindow(display, screen), *property_atom_return, 0, item_count, False, *property_atom_return, &actual_type, &actual_format, &item_count_return, &bytes_unread, (unsigned char **) property_data_return); } while ((result == Success) && (bytes_unread > 0)); if (result != Success) return PEXUtXFailure; *property_count_return = item_count_return/(sizeof(XStandardColormap)/4); return PEXUtSuccess; } else { /* Note that XGetRGBColormaps returns a zero status even if nothing is wrong but the property doesn't exist. */ *property_atom_return = property_info->property_atom; result = XGetRGBColormaps (display, RootWindow(display, screen), property_data_return, property_count_return, *property_atom_return); if (!result) *property_count_return = 0; return PEXUtSuccess; } } /* pexut_get_standard_cmap_property */ int pexut_get_overlay_visuals_property ( display, screen, property_count_return, property_data_return ) Display *display; int screen; int *property_count_return; overlay_visuals_type **property_data_return; { Atom property_atom; Atom actual_type; int actual_format; unsigned long item_count; unsigned long item_count_return, bytes_unread; int result; /* Get the atom from the X server. If it doesn't exist, neither does the property. */ property_atom = XInternAtom(display, "SERVER_OVERLAY_VISUALS", True); if (property_atom == None) { return PEXUtXFailure; } /* Property atom exists - fetch the property. */ bytes_unread = 0; item_count = sizeof(overlay_visuals_type)/4; do { item_count += (bytes_unread+3)/4; result = XGetWindowProperty (display, RootWindow(display, screen), property_atom, 0, item_count, False, property_atom, &actual_type, &actual_format, &item_count_return, &bytes_unread, (unsigned char **) property_data_return); } while ((result == Success) && (bytes_unread > 0)); if (result != Success) return PEXUtXFailure; *property_count_return = item_count_return/(sizeof(overlay_visuals_type)/4); return PEXUtSuccess; } /* pexut_get_overlay_visuals_property */ int pexut_evaluate_color_criteria ( display, criteria, vis_info, p_info ) Display *display; PEXUtVisualCriteria *criteria; XVisualInfo *vis_info; visual_info_type *p_info; /* Algorithm: Section I: Compute the color resolution numbers. If we have a property entry, use it to do this, otherwise use the Visual description. Section II: Mark the information block as criteria are tested for satisfaction. Also, keep numbers for the degree to which the available colors surpass the specified minima. Section III: Compute an overall color rating based on to what degree the colors exceed the minima. If no color criteria were specified, this rating comes out zero. If sharable_colormap was a criterion, Visuals that are not named in properties lose their color rating. Visuals that were named in a property, but whose ramps do not meet the criteria, also lose. */ { PEXEnumTypeIndex color_approx_type; int avail_reds, avail_greens, avail_blues; int avail_colors; int colors_excess, total_excess, reds_excess, greens_excess, blues_excess; unsigned long temp; XStandardColormap *cmap_info; /* ----------------------------------------------------------------------- Section I: Compute the color resolution numbers. If we have a property entry, use it to do this, otherwise use the Visual description. ----------------------------------------------------------------------- */ if (PEXUtColorApproxType & (criteria->hard_criteria_mask|criteria->soft_criteria_mask)) color_approx_type = criteria->color_approx_type; else color_approx_type = PEXColorSpace; if ((p_info->property_ptr != NULL) && (color_approx_type == PEXColorSpace)) { cmap_info = p_info->property_ptr; avail_reds = cmap_info->red_max + 1; avail_greens = cmap_info->green_max + 1; avail_blues = cmap_info->blue_max + 1; avail_colors = avail_reds * avail_greens * avail_blues; } else { switch (vis_info->class) { case PseudoColor: case StaticColor: case GrayScale: case StaticGray: avail_colors = vis_info->colormap_size; avail_reds = vis_info->colormap_size; avail_greens = vis_info->colormap_size; avail_blues = vis_info->colormap_size; break; case DirectColor: case TrueColor: avail_reds = 1; for (temp = vis_info->red_mask; temp > 0; temp >>= 1) { if (temp & 1) avail_reds *= 2; } avail_greens = 1; for (temp = vis_info->green_mask; temp > 0; temp >>= 1) { if (temp & 1) avail_greens *= 2; } avail_blues = 1; for (temp = vis_info->blue_mask; temp > 0; temp >>= 1) { if (temp & 1) avail_blues *= 2; } avail_colors = avail_reds * avail_greens * avail_blues; break; } } /* ----------------------------------------------------------------------- Section II: Mark the information block as criteria are tested for satisfaction. Also, keep numbers for the degree to which the available colors surpass the specified minima. ----------------------------------------------------------------------- */ if (PEXUtMinColors & (criteria->hard_criteria_mask | criteria->soft_criteria_mask)) { if (avail_colors < criteria->min_colors) { p_info->unmet_hard_criteria |= (criteria->hard_criteria_mask & PEXUtMinColors); p_info->unmet_soft_criteria |= (criteria->soft_criteria_mask & PEXUtMinColors); colors_excess = criteria->min_colors - avail_colors; } else colors_excess = avail_colors - criteria->min_colors; } else colors_excess = avail_colors; if (PEXUtMinRed & (criteria->hard_criteria_mask | criteria->soft_criteria_mask)) { if (avail_reds < criteria->min_red) { p_info->unmet_hard_criteria |= (criteria->hard_criteria_mask & PEXUtMinRed); p_info->unmet_soft_criteria |= (criteria->soft_criteria_mask & PEXUtMinRed); reds_excess = criteria->min_red - avail_reds; } else reds_excess = avail_reds - criteria->min_red; } else reds_excess = 0; if (PEXUtMinGreen & (criteria->hard_criteria_mask | criteria->soft_criteria_mask)) { if (avail_greens < criteria->min_green) { p_info->unmet_hard_criteria |= (criteria->hard_criteria_mask & PEXUtMinGreen); p_info->unmet_soft_criteria |= (criteria->soft_criteria_mask & PEXUtMinGreen); greens_excess = criteria->min_green - avail_greens; } else greens_excess = avail_greens - criteria->min_green; } else greens_excess = 0; if (PEXUtMinBlue & (criteria->hard_criteria_mask | criteria->soft_criteria_mask)) { if (avail_blues < criteria->min_blue) { p_info->unmet_hard_criteria |= (criteria->hard_criteria_mask & PEXUtMinBlue); p_info->unmet_soft_criteria |= (criteria->soft_criteria_mask & PEXUtMinBlue); blues_excess = criteria->min_blue- avail_blues; } else blues_excess = avail_blues - criteria->min_blue; } else blues_excess = 0; /* ----------------------------------------------------------------------- Section III: Compute an overall color rating based on to what degree the colors exceed the minima. If no color criteria were specified, this rating comes out zero. If sharable_colormap was a criterion, Visuals that are not named in properties lose their color rating. Visuals that were named in a property, but whose ramps do not meet the criteria, also lose. ----------------------------------------------------------------------- */ total_excess = colors_excess + reds_excess + greens_excess + blues_excess; if (total_excess >= 0x10000) /* 24 bits */ p_info->color_rating = MAX_COLOR_RATING; else if (total_excess >= 0x1000) /* 16 bits */ p_info->color_rating = MAX_COLOR_RATING - 1; else if (total_excess >= 0x100) /* 12 bits */ p_info->color_rating = MAX_COLOR_RATING - 2; else p_info->color_rating = total_excess; /* If caller asked for colormap to NOT be sharable, criteria are met, since any Visual supports private colormaps. */ if ((PEXUtSharableColormap & (criteria->hard_criteria_mask | criteria->soft_criteria_mask)) && (criteria->sharable_colormap)) { if ((colors_excess < 0) || (reds_excess < 0) || (greens_excess < 0) || (blues_excess < 0) || (p_info->property_ptr == NULL)) { p_info->unmet_hard_criteria |= (criteria->hard_criteria_mask & PEXUtSharableColormap); p_info->unmet_soft_criteria |= (criteria->soft_criteria_mask & PEXUtSharableColormap); p_info->color_rating = 0; } } return PEXUtSuccess; } /* pexut_evaluate_color_criteria */ static Bool pexut_is_pex_db_supported( dpy, win, db_x ) Display *dpy; Window win; int db_x; { PEXExtensionInfo *pexinfo; XWindowAttributes wattrs; unsigned long count; PEXRenderingTarget *target; /* ** Verify the PEX server is major version 5. */ pexinfo = PEXGetExtensionInfo( dpy ); if ( pexinfo == (PEXExtensionInfo *)NULL ) return( False ); if ( pexinfo->major_version != 5 ) return( False ); /* ** Get the window attributes for use in later inquiries. */ if ( ! XGetWindowAttributes( dpy, win, &wattrs ) ) return( False ); /* ** Try MBX. ** ** Verify rendering to MBX buffers is supported. ** Verify the MBX extension is supported and that it is major version 3. ** Verify the MBX extension supports at least 2 buffers for this drawable. */ { int first_event, first_error, num, dc; XmbufBufferInfo *buf_info, *dc_info; if ( ( ( pexinfo->minor_version >= 1 ) && PEXMatchRenderingTargets( dpy, win, wattrs.depth, PEXBufferDrawable, wattrs.visual, 1, &count, &target ) && ( count == 1 ) ) ) { if ( XmbufQueryExtension( dpy, &first_event, &first_error ) ) { if ( XmbufGetScreenInfo( dpy, win, &num, &buf_info, &dc, &dc_info ) ) { if ( buf_info->max_buffers >= 2 ) return( True ); } } } } /* ** MBX not available, so try double-buffer escapes. ** ** The escapes are not usable if db_x; ** the escapes are not available on pre-5.1 servers (unless server is Sun). ** Verify the double-buffer escape is supported. */ if ( ! db_x ) { if ( ( pexinfo->minor_version == 1 ) || (strncmp( pexinfo->vendor_name, "SunPEX 2", 8 ) == 0 ) ) { int enumtypes, i; unsigned long *enum_counts; PEXEnumTypeDesc *enum_info; enumtypes = PEXETEscape; if ( PEXGetEnumTypeInfo( dpy, win, 1, &enumtypes, PEXETIndex, &enum_counts, &enum_info ) ) { for ( i = 0; i < *enum_counts; i++ ) { if ( (short)enum_info[i].index == (short)ES_ESCAPE_ET_DBLBUFFER ) return( True ); /* assume rest of E&S escapes */ } } } } /* ** Pixmaps are not considered support for double-buffering; rather, pixmaps ** are a mechanism for doing smooth animation when double-buffering is not ** supported. ** ** However, return True if rendering to pixmaps is supported ** this is acceptable because the PEXUtDB utilities will double-buffer ** using pixmaps if rendering to pixmaps is supported. */ if ( PEXMatchRenderingTargets( dpy, win, wattrs.depth, PEXPixmapDrawable, wattrs.visual, 1, &count, &target ) && ( count == 1 ) ) { return( True ); } /* ** No double-buffering is supported. */ return( False ); } /* pexut_is_pex_db_supported */ int pexut_evaluate_double_buffering_capability ( display, criteria, vis_info, p_info ) Display *display; PEXUtVisualCriteria *criteria; XVisualInfo *vis_info; visual_info_type *p_info; { int actual_capabilities; Window window; int db_x; int result; if (PEXUtDoubleBufferingCapability & (criteria->hard_criteria_mask | criteria->soft_criteria_mask)) { /* Create a temporary unmapped window in the visual. */ pexut_create_temporary_window (display, vis_info, &window); /* Determine if the window's visual supports the desired capabilities. */ db_x = (criteria->double_buffering_capability == PEXUtDbufferPEXAndX); result = pexut_is_pex_db_supported (display, window, db_x); if (result) actual_capabilities = db_x ? PEXUtDbufferPEXAndX: PEXUtDbufferPEX; else actual_capabilities = PEXUtDbufferNone; /* Destroy the temporary window. */ pexut_destroy_temporary_window (display, vis_info, window); if (actual_capabilities != criteria->double_buffering_capability) { p_info->unmet_hard_criteria |= (criteria->hard_criteria_mask & PEXUtDoubleBufferingCapability); p_info->unmet_soft_criteria |= (criteria->soft_criteria_mask & PEXUtDoubleBufferingCapability); } } return PEXUtSuccess; } /* pexut_evaluate_double_buffering_capability */ int pexut_evaluate_color_approx_type ( display, criteria, vis_info, p_info ) Display *display; PEXUtVisualCriteria *criteria; XVisualInfo *vis_info; visual_info_type *p_info; { Window window; int found; int result; if (PEXUtColorApproxType & (criteria->hard_criteria_mask | criteria->soft_criteria_mask)) { /* Create a temporary unmapped window in the visual. */ pexut_create_temporary_window (display, vis_info, &window); /* Determine support for the color approx type using GetEnumTypeInfo. */ result = pexut_verify_color_approx_type (display, window, criteria->color_approx_type); /* Destroy the temporary window. */ pexut_destroy_temporary_window (display, vis_info, window); if (result == PEXUtSuccess) found = True; else if (result == PEXUtCriteriaFailure) found = False; else return result; if (!found) { p_info->unmet_hard_criteria |= (criteria->hard_criteria_mask & PEXUtColorApproxType); p_info->unmet_soft_criteria |= (criteria->soft_criteria_mask & PEXUtColorApproxType); } } return PEXUtSuccess; } /* pexut_evaluate_color_approx_type */ unsigned int pexut_compute_overall_rating ( p_info ) visual_info_type *p_info; { unsigned int rating; rating = (p_info->order_rating << ORDER_SHIFT) + (p_info->soft_rating << SOFT_SHIFT) + (p_info->class_rating << CLASS_SHIFT) + (p_info->color_rating << COLOR_SHIFT); return rating; } /* pexut_compute_overall_rating */ int pexut_create_temporary_window ( display, vis_info, window_return ) Display *display; XVisualInfo *vis_info; Window *window_return; { unsigned long window_mask; XSetWindowAttributes window_attrs; Colormap cmap_id; /* Create a window using override-redirect. Do not map it. If the visual is the default, use the root window. Otherwise, create a colormap to use. */ if (vis_info->visual == DefaultVisual (display, vis_info->screen)) { *window_return = RootWindow (display, vis_info->screen); return PEXUtSuccess; } else { cmap_id = XCreateColormap (display, RootWindow(display, vis_info->screen), vis_info->visual, AllocNone ); if (cmap_id == None) return PEXUtXFailure; window_attrs.colormap = cmap_id; window_mask = CWColormap; window_attrs.override_redirect = True; window_mask |= CWOverrideRedirect; window_attrs.background_pixel = 0; window_mask |= CWBackPixel; window_attrs.border_pixel = 0; window_mask |= CWBorderPixel; *window_return = XCreateWindow (display, RootWindow (display, vis_info->screen), 10, 10, 1, 1, 0, vis_info->depth, InputOutput, vis_info->visual, window_mask, &(window_attrs)); if (*window_return == None) return PEXUtXFailure; else return PEXUtSuccess; } } /* pexut_create_temporary_window */ int pexut_destroy_temporary_window ( display, vis_info, window ) Display *display; XVisualInfo *vis_info; Window window; { XWindowAttributes window_attrs; /* If this window is not in the default Visual, the Colormap and Window need to be freed. */ if (vis_info->visual != DefaultVisual (display, vis_info->screen)) { if (XGetWindowAttributes (display, window, &window_attrs)) XFreeColormap (display, window_attrs.colormap); XDestroyWindow (display, window); } return PEXUtSuccess; } /* pexut_destroy_temporary_window */ int pexut_verify_color_approx_type #if NeedFunctionPrototypes ( Display *display, Window window, PEXEnumTypeIndex color_approx_type ) #else ( display, window, color_approx_type ) Display *display; Window window; PEXEnumTypeIndex color_approx_type; #endif { int enum_types[1]; unsigned long *count; PEXEnumTypeDesc *enum_data; int enum_index; int found; /* Verify that specified color approx type is supported using PEXGetEnumTypeInfo. If not, return failure. */ enum_types[0] = PEXETColorApproxType; if (!PEXGetEnumTypeInfo (display, window, 1, enum_types, PEXETIndex, &count, &enum_data)) { return PEXUtPEXFailure; } found = False; for (enum_index = 0; enum_index < *count; enum_index++) { if (enum_data[enum_index].index == color_approx_type) { found = True; break; } } PEXFreeEnumInfo (1, count, enum_data); if (found) return PEXUtSuccess; else return PEXUtCriteriaFailure; } /* pexut_verify_color_approx_type */ int pexut_synthesize_cmap_from_visual ( vis_info, cmap_info_return ) XVisualInfo *vis_info; XStandardColormap *cmap_info_return; { int num_reds, red_shift, red_mult; int num_greens, green_shift, green_mult; int num_blues, blue_shift, blue_mult; int base_pixel; unsigned long temp; int depth; int trial_value, overrun; switch (vis_info->class) { case PseudoColor: case StaticColor: /* Divide the number of planes into thirds, and then favor equal numbers of red and green planes at the expense of blue planes. Favor green at the expense of red in tight situations. This yields 121 in depth 4, 332 in depth 8, 444 in depth 12, and 888 in depth 24. */ depth = vis_info->depth; trial_value = depth / 3; overrun = depth % 3; if (overrun) trial_value += 1; num_greens = (1 << trial_value); num_reds = (1 << trial_value); if ((num_reds * num_greens) >= vis_info->colormap_size) num_reds = (1 << (trial_value-1)); num_blues = vis_info->colormap_size / (num_reds * num_greens); red_mult = num_greens * num_blues; green_mult = num_blues; blue_mult = 1; base_pixel = 0; break; case GrayScale: case StaticGray: /* PEXColorRange is advantageous in gray Visuals since it uses less cells to achieve the same effect. Here, use the entire colormap for gray levels. */ num_reds = vis_info->colormap_size; num_greens = vis_info->colormap_size; num_blues = vis_info->colormap_size; red_mult = 1; green_mult = 1; blue_mult = 1; base_pixel = 0; break; case DirectColor: case TrueColor: /* Determine the maximum number of color values for each of red, green, and blue, and the corresponding shifts. */ num_reds = 1; red_shift = 0; for (temp = vis_info->red_mask; temp > 0; temp >>= 1) { if (temp & 1) num_reds *= 2; else red_shift++; } red_mult = 1 << red_shift; num_greens = 1; green_shift = 0; for (temp = vis_info->green_mask; temp > 0; temp >>= 1) { if (temp & 1) num_greens *= 2; else green_shift++; } green_mult = 1 << green_shift; num_blues = 1; blue_shift = 0; for (temp = vis_info->blue_mask; temp > 0; temp >>= 1) { if (temp & 1) num_blues *= 2; else blue_shift++; } blue_mult = 1 << blue_shift; base_pixel = 0; break; } cmap_info_return->colormap = None; cmap_info_return->visualid = vis_info->visualid; cmap_info_return->killid = None; cmap_info_return->red_max = num_reds - 1; cmap_info_return->green_max = num_greens - 1; cmap_info_return->blue_max = num_blues - 1; cmap_info_return->red_mult = red_mult; cmap_info_return->green_mult = green_mult; cmap_info_return->blue_mult = blue_mult; cmap_info_return->base_pixel = base_pixel; return PEXUtSuccess; } /* pexut_synthesize_cmap_from_visual */ int pexut_load_color_approx_from_std_cmap ( color_approx_type, vis_info, cmap_info, capx_info_return ) int color_approx_type; XVisualInfo *vis_info; XStandardColormap *cmap_info; PEXColorApproxEntry *capx_info_return; { /* If color approx type was not specified, decide it based on the Visual class. */ if (color_approx_type == -1) { if ((vis_info->class == GrayScale) || (vis_info->class == StaticGray)) color_approx_type = PEXColorRange; else color_approx_type = PEXColorSpace; } /* Transfer information from the standard colormap property structure into the color approximation entry. */ if (color_approx_type == PEXColorRange) { capx_info_return->type = PEXColorRange; capx_info_return->model = PEXColorApproxRGB; capx_info_return->dither = PEXOn; capx_info_return->base_pixel = 0; capx_info_return->max1 = vis_info->colormap_size-1; capx_info_return->max2 = 0; capx_info_return->max3 = 0; capx_info_return->weight1 = 0.299; capx_info_return->weight2 = 0.587; capx_info_return->weight3 = 0.114; capx_info_return->mult1 = 1; capx_info_return->mult2 = 0; capx_info_return->mult3 = 0; } else { capx_info_return->type = PEXColorSpace; capx_info_return->model = PEXColorApproxRGB; capx_info_return->dither = PEXOn; capx_info_return->base_pixel = cmap_info->base_pixel; capx_info_return->max1 = cmap_info->red_max; capx_info_return->max2 = cmap_info->green_max; capx_info_return->max3 = cmap_info->blue_max; capx_info_return->weight1 = 0.0; capx_info_return->weight2 = 0.0; capx_info_return->weight3 = 0.0; capx_info_return->mult1 = cmap_info->red_mult; capx_info_return->mult2 = cmap_info->green_mult; capx_info_return->mult3 = cmap_info->blue_mult; } return PEXUtSuccess; } /* pexut_load_color_approx_from_std_cmap */ int pexut_match_color_approx_entry ( entry1, entry2 ) PEXColorApproxEntry *entry1; PEXColorApproxEntry *entry2; { int match = 1; match &= (entry1->type == entry2->type); match &= (entry1->model == entry2->model); match &= (entry1->base_pixel == entry2->base_pixel); match &= (entry1->max1 == entry2->max1); if (entry1->type == PEXColorSpace) { match &= (entry1->mult1 == entry2->mult1); match &= (entry1->max2 == entry2->max2); match &= (entry1->mult2 == entry2->mult2); match &= (entry1->max3 == entry2->max3); match &= (entry1->mult3 == entry2->mult3); } else if (entry1->type == PEXColorRange) { /* Issue: how flexible are implementations on the values of mults or of weights? We'll be lax and pass everything. */ ; } if (match) return True; else return False; } /* pexut_match_color_approx_entry */ int pexut_create_one_channel_map ( display, vis_info, capx_info, colormap_id_return ) Display *display; XVisualInfo *vis_info; PEXColorApproxEntry *capx_info; Colormap *colormap_id_return; /* Algorithm: Section I: Create a Colormap and capture the default values. Compute the number of cells in the color approximation region. Section II: Allocate all the cells in the Colormap read-write. Load the color approximation region with the correct colors. */ { Colormap cmap_id; int num_reds, num_greens, num_blues, num_colors; unsigned long *pixels, pixel_value; XColor *colors, *p_color; int i, j, k; int result; /* ----------------------------------------------------------------------- Section I: Create a Colormap and capture the default values. Compute the number of cells in the color approximation region. ----------------------------------------------------------------------- */ /* Create the colormap with AllocNone. */ cmap_id = XCreateColormap ( display, RootWindow (display, vis_info->screen), vis_info->visual, AllocNone ); if (cmap_id == None) return PEXUtXFailure; /* If color approx type is PEXColorRange, compute the number of cells from max1, typical for GrayScale. If color approx type is PEXColorSpace, compute the number of cells from all three maxes, typical for PseudoColor. */ if (capx_info->type == PEXColorRange) { num_colors = capx_info->max1 + 1; } else { /* assume PEXColorSpace */ num_reds = capx_info->max1 + 1; num_greens = capx_info->max2 + 1; num_blues = capx_info->max3 + 1; num_colors = num_reds * num_greens * num_blues; } if (capx_info->base_pixel >= vis_info->colormap_size) { XFreeColormap (display, cmap_id); return PEXUtXFailure; } if (capx_info->base_pixel + num_colors > vis_info->colormap_size) num_colors = vis_info->colormap_size - capx_info->base_pixel; /* Query the default colors, or the default Colormap if we're in that Visual; we will preserve the colors in cells outside the ramp. */ colors = (XColor *) malloc (vis_info->colormap_size * sizeof(XColor)); if (colors == NULL) { XFreeColormap (display, cmap_id); return PEXUtXFailure; } for (pixel_value = 0, p_color = colors; pixel_value < vis_info->colormap_size; pixel_value++, p_color++) { p_color->pixel = pixel_value; } if (vis_info->visualid == XVisualIDFromVisual(DefaultVisual(display, vis_info->screen))) XQueryColors (display, DefaultColormap(display, vis_info->screen), colors, vis_info->colormap_size); else XQueryColors (display, cmap_id, colors, vis_info->colormap_size); /* ----------------------------------------------------------------------- Section II: Allocate all the cells in the Colormap read-write. Load the color approximation region with the correct colors. ----------------------------------------------------------------------- */ /* Allocate all cells read/write using XAllocColorCells. */ pixels = (unsigned long *) malloc (vis_info->colormap_size * sizeof(unsigned long)); if (pixels == NULL) { XFreeColormap (display, cmap_id); return PEXUtXFailure; } result = XAllocColorCells ( display, cmap_id, True, (unsigned long *) NULL, 0, pixels, vis_info->colormap_size); free (pixels); if (! result) { XFreeColormap (display, cmap_id); return PEXUtXFailure; } /* Load the colors into the cells. Even if the visual is PseudoColor, if the color approx type is PEXColorRange, we will load a ramp of gray values (since we have no idea what the colors should be). Similarly, even for GrayScale, PEXColorSpace will load a color space sampling. */ for (pixel_value = 0, p_color = colors; pixel_value < capx_info->base_pixel; pixel_value++, p_color++) { p_color->flags = DoRed | DoGreen | DoBlue; } if (capx_info->type == PEXColorRange) { pixel_value = capx_info->base_pixel; p_color = colors + capx_info->base_pixel; for (i = 0; i < num_colors; i++) { p_color->flags = DoRed | DoGreen | DoBlue; p_color->pixel = pixel_value++; p_color->red = p_color->green = p_color->blue = i * 65535 / (num_colors - 1); p_color++; } } else { /* assume PEXColorSpace */ pixel_value = capx_info->base_pixel; p_color = colors + capx_info->base_pixel; /* The following logic can be coded more generally but hasn't been, yet. */ if (capx_info->mult1 > capx_info->mult3) { if (capx_info->mult2 > capx_info->mult1) { /* Set up GBR ramp, as on Sun. */ for (i = 0; (i < num_greens) && (pixel_value < vis_info->colormap_size); i++) { for (j = 0; (j < num_blues) && (pixel_value < vis_info->colormap_size); j++) { for (k = 0; (k < num_reds) && (pixel_value < vis_info->colormap_size); k++) { p_color->flags = DoRed | DoGreen | DoBlue; p_color->pixel = pixel_value++; p_color->red = (unsigned short)(k * 65535) / capx_info->max1; p_color->green = (unsigned short)(i * 65535) / capx_info->max2; p_color->blue = (unsigned short)(j * 65535) / capx_info->max3; p_color++; if (pixel_value == vis_info->colormap_size) break; } } } } else { /* Set up RGB ramp, as on HP, DEC, Kubota Pacific, Oki, some NCD. */ for (i = 0; (i < num_reds) && (pixel_value < vis_info->colormap_size); i++) { for (j = 0; (j < num_greens) && (pixel_value < vis_info->colormap_size); j++) { for (k = 0; (k < num_blues) && (pixel_value < vis_info->colormap_size); k++) { p_color->flags = DoRed | DoGreen | DoBlue; p_color->pixel = pixel_value++; p_color->red = (unsigned short)(i * 65535) / capx_info->max1; p_color->green = (unsigned short)(j * 65535) / capx_info->max2; p_color->blue = (unsigned short)(k * 65535) / capx_info->max3; p_color++; if (pixel_value == vis_info->colormap_size) break; } } } } } else { /* Set up BGR ramp, as on IBM, SHOgraphics, Tektronix, some NCD. */ for (i = 0; (i < num_blues) && (pixel_value < vis_info->colormap_size); i++) { for (j = 0; (j < num_greens) && (pixel_value < vis_info->colormap_size); j++) { for (k = 0; (k < num_reds) && (pixel_value < vis_info->colormap_size); k++) { p_color->flags = DoRed | DoGreen | DoBlue; p_color->pixel = pixel_value++; p_color->red = (unsigned short)(k * 65535) / capx_info->max1; p_color->green = (unsigned short)(j * 65535) / capx_info->max2; p_color->blue = (unsigned short)(i * 65535) / capx_info->max3; p_color++; if (pixel_value == vis_info->colormap_size) break; } } } } } for (pixel_value = capx_info->base_pixel + num_colors, p_color = colors; pixel_value < vis_info->colormap_size; pixel_value++, p_color++) { p_color->flags = DoRed | DoGreen | DoBlue; } XStoreColors (display, cmap_id, colors, vis_info->colormap_size); free (colors); /* Optional: could free cells outside the ramp at this point, and/or reallocate cells as read-only so XAllocColor might work. At the very least, should make sure that black and white can be found. However, currently leaving implementation of policy to the caller. See PEXUtCopyColormapAsReadOnly(). */ *colormap_id_return = cmap_id; return PEXUtSuccess; } /* pexut_create_one_channel_map */ int pexut_create_three_channel_map ( display, vis_info, capx_info, colormap_id_return ) Display *display; XVisualInfo *vis_info; PEXColorApproxEntry *capx_info; Colormap *colormap_id_return; { Colormap cmap_id; int num_colors; int num_reds, num_greens, num_blues; int red_shift, green_shift, blue_shift; int vis_red_shift, vis_green_shift, vis_blue_shift; unsigned long temp; unsigned long *pixels; XColor *colors, *p_color; int i; int result; /* Create the colormap with AllocNone. */ cmap_id = XCreateColormap ( display, RootWindow (display, vis_info->screen), vis_info->visual, AllocNone ); if (cmap_id == None) return PEXUtXFailure; /* Compute the color shifts for r, g, b. Making an major assumption that the number of levels of each component are all powers of two. Compute the number of cells to write as the maximum count for any of the three channels. */ num_reds = capx_info->max1 + 1; for (red_shift = 0, temp = capx_info->mult1; temp > 1; red_shift++, temp >>= 1); vis_red_shift = 0; temp = vis_info->red_mask; while (!(temp & 0x1)) { vis_red_shift++; temp >>= 1; } num_greens = capx_info->max2 + 1; for (green_shift = 0, temp = capx_info->mult2; temp > 1; green_shift++, temp >>= 1); vis_green_shift = 0; temp = vis_info->green_mask; while (!(temp & 0x1)) { vis_green_shift++; temp >>= 1; } num_blues = capx_info->max3 + 1; for (blue_shift = 0, temp = capx_info->mult3; temp > 1; blue_shift++, temp >>= 1); vis_blue_shift = 0; temp = vis_info->blue_mask; while (!(temp & 0x1)) { vis_blue_shift++; temp >>= 1; } if ((red_shift != vis_red_shift) || (green_shift != vis_green_shift) || (blue_shift != vis_blue_shift)) { XFreeColormap (display, cmap_id); return PEXUtXFailure; } num_colors = num_reds; if (num_greens > num_colors) num_colors = num_greens; if (num_blues > num_colors) num_colors = num_blues; if (capx_info->base_pixel >= vis_info->colormap_size) { XFreeColormap (display, cmap_id); return PEXUtXFailure; } if (capx_info->base_pixel + num_colors > vis_info->colormap_size) num_colors = vis_info->colormap_size - capx_info->base_pixel; /* Allocate all cells read/write using XAllocColorCells. */ pixels = (unsigned long *) malloc (vis_info->colormap_size * sizeof(unsigned long)); if (pixels == NULL) { XFreeColormap (display, cmap_id); return PEXUtXFailure; } result = XAllocColorCells ( display, cmap_id, True, (unsigned long *) NULL, 0, pixels, vis_info->colormap_size); free (pixels); if (! result) { XFreeColormap (display, cmap_id); return PEXUtXFailure; } /* Load the colors into the cells. */ colors = (XColor *) malloc (num_colors * sizeof(XColor)); if (colors == NULL) { XFreeColormap (display, cmap_id); return PEXUtXFailure; } for (i = 0, p_color = colors; i < num_colors; i++, p_color++) { p_color->flags = 0; p_color->pixel = capx_info->base_pixel; if (i < num_reds) { p_color->flags |= DoRed; p_color->pixel |= (i << red_shift); p_color->red = (unsigned short)(i * 65535) / capx_info->max1; } if (i < num_greens) { p_color->flags |= DoGreen; p_color->pixel |= (i << green_shift); p_color->green = (unsigned short)(i * 65535) / capx_info->max2; } if (i < num_blues) { p_color->flags |= DoBlue; p_color->pixel |= (i << blue_shift); p_color->blue = (unsigned short)(i * 65535) / capx_info->max3; } } XStoreColors (display, cmap_id, colors, num_colors); free (colors); /* Optional: could free cells outside the ramp at this point, and/or reallocate cells as read-only so XAllocColor might work. At the very least, should make sure that black and white can be found. However, currently leaving implementation of policy to the caller. See PEXUtCopyColormapAsReadOnly(). */ *colormap_id_return = cmap_id; return PEXUtSuccess; } /* pexut_create_three_channel_map */ int pexut_create_read_only_map ( display, vis_info, capx_info, colormap_id_return ) Display *display; XVisualInfo *vis_info; PEXColorApproxEntry *capx_info; Colormap *colormap_id_return; { /* Create the colormap with AllocNone. */ *colormap_id_return = XCreateColormap ( display, RootWindow (display, vis_info->screen), vis_info->visual, AllocNone ); /* Optional: could verify that the ramp is actually represented in the colormap, and return an error if not. Left as an exercise. */ if (*colormap_id_return == None) return PEXUtXFailure; else return PEXUtSuccess; } /* pexut_create_read_only_map */ int pexut_count_bits_in_mask ( mask ) unsigned int mask; { int count = 0; while (mask) { if (mask & 0x1) count++; mask >>= 1; } return count; } /* pexut_count_bits_in_mask */