jec@cbnews.att.com (John Collier) (09/27/90)
I've been fiddling around with a "paint mixer" program, mostly just to learn how things work (those of you who've already done this may smile and nod your heads knowingly...:-). This is the "traditional" paint mixer where I show three sliders, one each for red, green, and blue intensities, with the idea that when I move one of the sliders, the background color inside a window will change dynamically. This would be really nice; I just can't seem to make it work. I made a call to XAllocColorCells to allocate one read/write color cell. The call looks like: unsigned long *plane_masks = 0 ; int rtn = XAllocColorCells (dsp, cmap, True, plane_masks, 0, &pixel, 1) ; This seems to yield a valid value for "pixel" usually something "25". I also check the return code and it never comes back "0", so it seems like this part works okay. Later I call XStoreColor to initialize the color cell to "black": XColor xc ; xc.pixel = pixel ; xc.red = 0 ; xc.green = 0 ; xc.blue = 0 ; xc.flags = DoRed | DoGreen | DoBlue ; XStoreColor (dsp, cmap, &xc) ; As far as I can tell, this works. My Xlib Reference Manual doesn't mention a return code, so I don't know if I can check one to see it the call worked. Also, my test area shows black, which may or may not mean anything under the circumstances. Once I've allocated this, I assign the background color of an OpenLook Static Text widget to use the "pixel" I got from the previous call. This looks like: XFreeColors (dsp, cmap, old_pixel_value, 1, 0) ; /* Free previous color */ XColor xc ; xc.pixel = new_pixel ; /* Pixel value obtained from XAllocColorCells */ int rtn = XAllocColor (dsp, cmap, &xc) ; /* Build an Xt Args list with XtNbackground set to "new_pixel" */ /* Use XtSetValues to set the widget background color to "new_pixel" */ I check the return code from "XAllocColor", but it is never zero, so I assume this call worked as well. Later, in the callback function for the slider, I call XStoreColor again to set a new RGB value for the "pixel". It is identical to the one above except only one field is set and "flags" is set correspondingly. I also left-shift the color by 8 (<< 8) before I call XStoreColor. Now, with all of that, when I run the program and move the sliders, the window background never changes color. If someone could tell me what I'm doing wrong or, conversely, a better way to do it right, I would really appreciate it. The explanation can deal with what I want to do on the Xlib level; I can translate it into my "stuff" from there. Any ideas, help, or suggestions would be appreciated. -- ------------------------------------------------------------------------------- Working around here is like going into a swamp | John Collier, AT&T Bell Labs full of alligators...you'll either be eaten | ARPA: jec@cbnea.ATT.COM alive or wind up with some really nice luggage!| uucp/e-mail: att!cbnea!jec
mouse@SHAMASH.MCRCIM.MCGILL.EDU (der Mouse) (09/27/90)
[Code examples edited to compress this posting -dM] > [...] the background color inside a window will change dynamically. > I made a call to XAllocColorCells to allocate one read/write color > cell. The call looks like: > unsigned long *plane_masks = 0 ; > int rtn = XAllocColorCells (dsp, cmap, True, plane_masks, 0, &pixel, 1) ; Well, there's no need to make plane_masks a variable, but that's not a problem (except perhaps in a stylistic sense). > This seems to yield a valid value for "pixel" usually something "25". > I also check the return code and it never comes back "0", so it seems > like this part works okay. Later I call XStoreColor to initialize > the color cell to "black": > XColor xc ; > xc.pixel = pixel ; xc.red = xc.green = xc.blue = 0 ; > xc.flags = DoRed | DoGreen | DoBlue ; > XStoreColor (dsp, cmap, &xc) ; > As far as I can tell, this works. [...] This looks entirely reasonable, assuming cmap is something sensible (you don't say where you get cmap from). > Once I've allocated this, I assign the background color of an > OpenLook Static Text widget to use the "pixel" I got from the > previous call. This looks like: > XFreeColors (dsp, cmap, old_pixel_value, 1, 0) ; /* Free previous color */ > XColor xc ; > xc.pixel = new_pixel ; /* Pixel value obtained from XAllocColorCells */ > int rtn = XAllocColor (dsp, cmap, &xc) ; > /* Build an Xt Args list with XtNbackground set to "new_pixel" */ > /* Use XtSetValues to set the widget background color to "new_pixel" */ This looks most peculiar. Where are you getting old_pixel_value from and why are you freeing it? (Also, shouldn't it be &old_pixel_value? Without a declaration for old_pixel_value I can't be sure.) XAllocColor allocates a read-only color cell. You don't say what you're setting the red/green/blue fields of xc to, so I can't say what sort of color you're allocating. The Xlib documentation I have does not explicitly say what XAllocColor does with the pixel field of the XColor structure passed in; UTSLing tells me that it is completely ignored. However, this shouldn't matter, because you ignore the allocated read-only cell and proceed to use the read-write cell you allocated earlier with XAllocColorCells. > Later, in the callback function for the slider, I call XStoreColor > again to set a new RGB value for the "pixel". It is identical to > the one above except only one field is set and "flags" is set > correspondingly. I also left-shift the color by 8 (<< 8) before I > call XStoreColor. (Presumably the value before the left-shift is [0..255].) I assume the cell you are trying to store into in the callback is the one from XAllocColorCells. The only thing that comes to mind then is, are you sure the widget's window is using the same colormap as the one you allocated your read-write cell in? You don't say where you get the "cmap" you pass to all these functions. It might be informative to start off with something other than black. Pick a color that's not normally present on your screen and set the color to that initially, instead of black. If you then still see black this should tell you something - just what depends on where you see black when you expect the other color. If you still have trouble, I'd be glad to discuss it via email (so as to avoid annoying everyone on xpert with a debugging session :-). der Mouse old: mcgill-vision!mouse new: mouse@larry.mcrcim.mcgill.edu
erc@pai.UUCP (Eric Johnson) (10/03/90)
I tried to email, but it bounced. Since Xlib and colour is a general enough topic, here goes. Regarding: From: jec@cbnews.att.com (John Collier) Newsgroups: comp.windows.x Subject: How do I use a read/write color cell? Keywords: read,write,alloc,SetColor Date: 26 Sep 90 19:09:51 GMT Organization: AT&T Bell Laboratories I've been fiddling around with a "paint mixer" program, mostly just to learn how things work (those of you who've already done this may smile and nod your heads knowingly...:-). This is the "traditional" paint mixer where I show three sliders, one each for red, green, and blue intensities, with the idea that when I move one of the sliders, the background color inside a window will change dynamically. This would be really nice; I just can't seem to make it work. I made a call to XAllocColorCells to allocate one read/write color cell. The call looks like: unsigned long *plane_masks = 0 ; int rtn = XAllocColorCells (dsp, cmap, True, plane_masks, 0, &pixel, 1) ; This seems to yield a valid value for "pixel" usually something "25". I also check the return code and it never comes back "0", so it seems like this part works okay. Later I call XStoreColor to initialize the color cell to "black": XColor xc ; xc.pixel = pixel ; xc.red = 0 ; xc.green = 0 ; xc.blue = 0 ; xc.flags = DoRed | DoGreen | DoBlue ; XStoreColor (dsp, cmap, &xc) ; As far as I can tell, this works. My Xlib Reference Manual doesn't mention a return code, so I don't know if I can check one to see it the call worked. Also, my test area shows black, which may or may not mean anything under the circumstances. Once I've allocated this, I assign the background color of an OpenLook Static Text widget to use the "pixel" I got from the previous call. This looks like: XFreeColors (dsp, cmap, old_pixel_value, 1, 0) ; /* Free previous color */ XColor xc ; xc.pixel = new_pixel ; /* Pixel value obtained from XAllocColorCells */ int rtn = XAllocColor (dsp, cmap, &xc) ; /* Build an Xt Args list with XtNbackground set to "new_pixel" */ /* Use XtSetValues to set the widget background color to "new_pixel" */ I check the return code from "XAllocColor", but it is never zero, so I assume this call worked as well. Later, in the callback function for the slider, I call XStoreColor again to set a new RGB value for the "pixel". It is identical to the one above except only one field is set and "flags" is set correspondingly. I also left-shift the color by 8 (<< 8) before I call XStoreColor. Now, with all of that, when I run the program and move the sliders, the window background never changes color. If someone could tell me what I'm doing wrong or, conversely, a better way to do it right, I would really appreciate it. The explanation can deal with what I want to do on the Xlib level; I can translate it into my "stuff" from there. Any ideas, help, or suggestions would be appreciated. -- ------------------------------------------------------------------------------- Working around here is like going into a swamp | John Collier, AT&T Bell Labs full of alligators...you'll either be eaten | ARPA: jec@cbnea.ATT.COM alive or wind up with some really nice luggage!| uucp/e-mail: att!cbnea!jec - ---- Kevin Reichard and I recently had an article on X Window colour published in _Computer Language_ magazine (the July, 1990 issue). Enclosed below is the source code for the program described in that article. I'm a firm believer that working source code examples do a lot for the learning process (at least for me). The program allocates colours and then changes the colour values on the fly. So, I hope it provides some help. You might also want to look up XSetWindowBackground(), e.g.: XSetWindowBackground( display, window, new_back_pixel ); XClearWindow( display, window ); --- The July, 1990 issue of Computer Language contains an article on writing X programs that use color: "Controlling Colors the Xlib Way" by yours truly and Kevin Reichard. Unfortunately, the accompaning C program was not included due to space. The article makes a lot more sense with the program, so here goes. I'm a firm believer that source code examples really help. (The program is written to Release 4 of X. You can easily convert, though.) ---------------cut here for colorfun.c--------------------------------- /* * colorfun.c * X Window demo program that draws a colored box * in a window. Every second, we change the color. * * To compile and run this program, you * will need to link in the X library * (usually called Xlib), usually done with * a command something like: * * cc -o colorfun colorfun.c -lX11 * * (On UNIX systems.) * * Note that we use some functions found only * in the Release 4 Xlib. These functions are * marked as such, so if you have an R3 or * older system you can easily convert. * * Written for Computer Language magazine * by E F Johnson and K Reichard, 1990. * */ #include <stdio.h> /* * Most X programs will need Xlib.h and Xutil.h */ #include <X11/Xlib.h> #include <X11/Xutil.h> main( argc, argv ) int argc; char *argv[]; { /* -- main */ Display *display; int screen; Window window; GC gc; int done; XColor the_color; Visual *visual; int depth; XFontStruct *font; int status; Colormap colormap; unsigned long black, white; /* * 1) Set up X display connection with the server * named in the user's DISPLAY environment variable. */ display = XOpenDisplay( NULL ); if ( display == (Display *) NULL ) { (void) fprintf( stderr, "Error: Could not open display\n" ); exit( 1 ); } /* * 2) Find a visual that supports color and get its depth. */ screen = DefaultScreen( display ); SetUpVisual( display, screen, &visual, &depth ); /* * 3a) Create Color map and get a black and white * pixel values for the colormap. */ SetUpColormap( display, screen, visual, &colormap, &black, &white ); /* * 3b) Allocate one read-write color cell. */ status = XAllocColorCells( display, colormap, False, NULL, 0, &the_color.pixel, 1 ); if ( status == 0 ) { (void) fprintf( stderr, "Error in allocating color cell.\n" ); XCloseDisplay( display ); exit( 1 ); } /* * Set up some "random" RGB color values. */ the_color.red = ( 1 << 8 ); the_color.green = ( 104 << 8 ); the_color.blue = ( 200 << 8 ); /* * 4) Load a font */ font = XLoadQueryFont( display, "fixed" ); if ( font == (XFontStruct *) NULL ) { (void) fprintf( stderr, "Error loading fixed font\n" ); XCloseDisplay( display ); exit( 1 ); } /* * 5) Create a window and set ICCCM values. */ SetUpWindow( display, visual, depth, colormap, black, white, &window ); /* * 6) Create a graphics context (GC) for our window. */ gc = XCreateGC( display, window, 0x0, (XGCValues *) NULL ); XSetFont( display, gc, font->fid ); XSetBackground( display, gc, white ); /* * 7) "Map" our window, making it appear * on the screen. */ XMapRaised( display, window ); XFlush( display ); /* * 8) Loop on events, exit on a ButtonPress event. */ done = False; while( !done ) { done = CheckForEvents( display, window, gc, &the_color, black ); /* * 9) Sleep for a second, * to space out the color changes. */ sleep( 1 ); /* * 10) Change the color in our window. */ ChangeColor( display, colormap, &the_color ); /* * 11) Redraw with the new color */ Redraw( display, window, gc, &the_color, black ); } /* * 12) Free/Destroy our window, GC, and font. */ XDestroyWindow( display, window ); XFreeGC( display, gc ); XFreeFont( display, font ); /* * 13) Close our X display connection and quit. */ XCloseDisplay( display ); exit( 0 ); } /* -- main */ CheckForEvents( display, window, gc, the_color, black ) Display *display; Window window; GC gc; XColor *the_color; unsigned long black; /* * 8) Loop on events. * CheckForEvents() checks to see if an X event * is pending. If so, CheckForEvents() reads in * that event and then acts on it (perhaps by * doing nothing). We ignore changes to the window's * size (it is assumed the user will be too * dazzled by the program to even think about resizing * the window). */ { /* -- function CheckForEvents */ XEvent event; int done = False; /* * 8a) Do we have an event waiting? */ if ( XPending( display ) > 0 ) { XNextEvent( display, &event ); switch( event.type ) { /* * 8b) Set a flag if a mouse button * is pressed. We will exit later. */ case ButtonPress: done = True; break; /* * 8c) Only redraw our window when * the last Expose event comes in. */ case Expose: if ( event.xexpose.count == 0 ) { Redraw( display, window, gc, the_color, black ); } break; } } return( done ); } /* -- function CheckForEvents */ Redraw( display, window, gc, the_color, black ) Display *display; Window window; GC gc; XColor *the_color; unsigned long black; /* * Redraw() redraws our window. Redraw() * is called whenever the window's contents * need to be refreshed, because the contents * have changed, or because the window system * requests we redraw the window due to "damage". */ { /* -- function Redraw */ char string[ 120 ]; /* * Fill in a rectangle, in the given color. */ XSetForeground( display, gc, the_color->pixel ); XFillRectangle( display, window, gc, 10, 30, 200, 100 ); /* * Draw text in black */ XSetForeground( display, gc, black ); /* * Display current color values as text */ (void) sprintf( string, "R 0x%5.5x G 0x%5.5x B 0x%5.5x", the_color->red, the_color->green, the_color->blue ); XDrawImageString( display, window, gc, 10, 20, string, strlen( string ) ); /* * Send output requests to the X server */ XFlush( display ); } /* -- function Redraw */ SetUpColormap( display, screen, visual, colormap, black, white ) Display *display; int screen; Visual *visual; Colormap *colormap; unsigned long *black, *white; /* * SetUpColormap() creats an X colormap using the * given screen and visual. Color cells (pixels) * for "black" and "white" are also allocated in * our new colormap. */ { /* -- function SetUpColormap */ int status; XColor hardwarecolor, exactcolor; /* * Create a colormap using the * visual found in SetUpVisual(). */ *colormap = XCreateColormap( display, RootWindow( display, screen ), visual, AllocNone ); /* * Check for failure. */ if ( *colormap != None ) { /* -- Set up "white" in the new colormap */ status = XAllocNamedColor( display, *colormap, "white", &hardwarecolor, &exactcolor ); if ( status != 0 ) { *white = hardwarecolor.pixel; /* -- Set up "black" in the new colormap */ status = XAllocNamedColor( display, *colormap, "black", &hardwarecolor, &exactcolor ); *black = hardwarecolor.pixel; } } else { status = 0; } if ( status == 0 ) { (void) fprintf( stderr, "Error in creating colormap\n" ); XCloseDisplay( display ); exit( 1 ); } } /* -- function SetUpColormap */ SetUpVisual( display, screen, visual, depth ) Display *display; int screen; Visual **visual; int *depth; /* * SetUpVisual() finds a PseudoColor visual * on the given screen. If none is to be found, * the program will terminate. *depth is set to * the depth of the found visual. */ { /* -- function SetUpVisual */ int number_visuals; XVisualInfo *visual_array, visual_template; /* * We want a PseudoColor visual on this screen. * XGetVisualInfo() will get a list of all * the PseudoColor visuals supported on * this screen. */ visual_template.class = PseudoColor; visual_template.screen = screen; visual_array = XGetVisualInfo( display, VisualClassMask | VisualScreenMask, &visual_template, &number_visuals ); /* -- Check for success */ if ( ( number_visuals > 0 ) && ( visual_array != NULL ) ) { /* * We're lazy, we just choose the * first PseudoColor visual */ *visual = visual_array[0].visual; *depth = visual_array[0].depth; XFree( visual_array ); } else { (void) fprintf( stderr, "Error in finding visual\n" ); XCloseDisplay( display ); exit( 1 ); } } /* -- function SetUpVisual */ SetUpWindow( display, visual, depth, colormap, fore, back, window ) Display *display; Visual *visual; int depth; Colormap colormap; unsigned long fore, back; Window *window; /* * 5) Create a window. We need to be careful here * to use our visual and colormap. */ { /* -- function SetUpWindow */ int x, y, width, height; XSetWindowAttributes attributes; unsigned long attribute_mask; int screen; XWMHints *wmhints; XSizeHints *sizehints; /* * 5a) Determine x, y, width, height. Normally * in X, the user should be able to specify this * on the UNIX command-line. For simplicity, * we're just using arbitrary values here. */ x = 10; y = 10; width = 220; height = 140; /* * 5b) Fill in a window attributes structure. * fore and back arer the black and white colors * allocated in our new colormap. If we use * the default BlackPixel() and WhitePixel(), * we may get strange values since these * may not have been allocated in our new * colormap. */ attributes.background_pixel = back; attributes.border_pixel = fore; attributes.event_mask = ExposureMask | ButtonPressMask; attributes.colormap = colormap; attribute_mask = CWBackPixel | CWBorderPixel | CWEventMask | CWColormap; /* * 5c) Create window */ screen = DefaultScreen( display ); *window = XCreateWindow( display, RootWindow( display, screen ), /* parent window */ x, y, width, height, 2, /* -- border width */ depth, InputOutput, /* -- window class */ visual, /* -- our visual */ attribute_mask, &attributes ); if ( *window == (Window) None ) { (void) fprintf( stderr, "Error: could not open window\n" ); XCloseDisplay( display ); exit( 1 ); } /* * 5d) Store a name for the window * with the window manager. Note we are * using Latin-1 names, so users in Japan * or Arabia might want to use X's compound * text mechanism. */ XStoreName( display, *window, "ColorFun" ); /* * 5e) Set window manager hints, R4-only functions! */ wmhints = XAllocWMHints(); if ( wmhints != NULL ) { wmhints->initial_state = NormalState; wmhints->input = True; wmhints->flags = StateHint | InputHint; XSetWMHints( display, *window, wmhints ); XFree( wmhints ); } /* * 5f) Set Size hints, again R4-specific! * (This also requires an R4 or ICCCM-compliant * window manager.) */ sizehints = XAllocSizeHints(); if ( sizehints != NULL ) { sizehints->base_width = width; sizehints->base_height = height; sizehints->flags = PBaseSize; XSetWMNormalHints( display, *window, sizehints ); XFree( sizehints ); } } /* -- function SetUpWindow */ ChangeColor( display, colormap, color ) Display *display; Colormap colormap; XColor *color; /* * Every second, ChangeColor() is called to * modify the current color we are displaying. */ { /* -- function ChangeColor */ color->flags = DoRed | DoGreen | DoBlue; color->red = (unsigned short) IncrementValue( color->red, 3 ); color->green = (unsigned short) IncrementValue( color->green, 6 ); color->blue = (unsigned short) IncrementValue( color->blue, 5 ); XStoreColor( display, colormap, color ); } /* -- function ChangeColor */ IncrementValue( value, amount ) short value; int amount; /* -- add this amount to value. */ /* * Some common 8-plane color systems seem to just * use the upper byte of the color values for * Red, Green and Blue (hence all the >> and << * bit-shift operations). If you don't like how * these colors look on your system, change * IncrementValue() and ChangeColor() to do what * you'd like. Play around with them and have fun. */ { /* -- function IncrementValue */ unsigned short new_value; new_value = ( value >> 8 ); new_value += amount; /* * Spend more time with brighter colors. */ if ( new_value > 200 ) { new_value--; } if ( new_value > 250 ) { new_value = 0; } return( new_value << 8 ); } /* -- function IncrementValue */ /* * end of file */ ---------------cut here------------------------------------------------ Have fun, -Eric -- Eric F. Johnson phone: +1 612 894 0313 BTI: Industrial Boulware Technologies, Inc. fax: +1 612 894 0316 automation systems 415 W. Travelers Trail email: erc@pai.mn.org and services Burnsville, MN 55337 USA