kevin@stl.stc.co.uk (Kevin Lewis) (06/28/89)
Here is a summary of the replies which I received about how to determine whether a monitor attached to a Sun-3 is colour or not. They divide into several types: 1) Screendump into a file/stdout and check how many bits deep it is 2) Use some C to find how deep the screen is by using an ioctl call 3) Using /usr/etc/eeprom console 4) Trapping the names of the workstations being used 4) is a not a portable solution to the problem, but if you are always going to work on the same set of workstations, it's pretty safe. 3) doesn't work on our system. eeprom console actually returns "color" for a black-and-white console! I don't think that this entry is used anywhere crucial in OS, as we don't get any problems with it set wrongly. 2) is a very good way of doing it. See the examples later for more info. 1) can be a very self contained method. My application requires that I can perform a screendump to a printer from a _prolog_ program. I did not want to include any foreign functions, although this is a possible way to call the functions in 2), so I decided on 1). Here's the fragment of prolog I ended up writing... %% screendump.pl screendump :- unix(system('#!/bin/sh if (`/bin/screendump -X 0 -Y 0 | \ /bin/od -Dvw4 | \ /bin/fgrep -s "0000014 0000000001"` ) then # b&w /bin/screendump | /usr/ucb/lpr -v else # colour /bin/screendump | /bin/rasfilter8to1 | /usr/ucb/lpr -v fi' )). %% end of screendump.pl I'm sure that all of you can manage to identify what's needed in a simple UNIX shell script... :-) My thanks go out to everyone who replied, I'm sorry I haven't had enough time to reply to everyone individually, but I am very grateful. Kevin Lewis Here goes with the list of replies. There's code in here too..... **************************************************************************** >From: "``Bob'' is the gun and YOU are the bullet..." <david@sun.com> The simplest way is to screendump to a file, then use the "file" command. **************************************************************************** >From: mmm@inf.rl.ac.uk You could rely on the existence of various devices in /dev, eg cgtwo0 etc. Or you could look at the data coming out of screendump. I enclose below a shell script to dump raster info. You could do something like if screendump -X 10 -Y 10 | rasinfo - | fgrep -s 'depth 1,' then it is mono else it is color fi or if you prefer something tighter and self-contained if screendump -X 10 -Y 10 | od -Dvw4 | fgrep -s '0000014 0000000001' etc... -------------rasinfo------- #!/bin/sh # dump rasterfile info. Mark M Martin 1988 Feb printmap=false checklength=true checkgrey=true while [ $# -gt 0 ] do case "$1" in -c) printmap=true shift;; -f) checklength=false shift;; -g) checkgrey=false shift;; -) break;; -*) echo "$0: usage: [-c] [-f] rasterfiles ... files may be compressed. use - for stdin -c print colourmap -f fast dont check length -g dont check for greyscale" exit 1;; *) break;; esac done for file do case $file in -.Z) zcat ;; *.Z) zcat $file ;; *) cat $file ;; esac | { set `dd bs=4 count=8 2>/dev/null | od -Dvw4 | sed 's/^[0-9]* *0*\(.\)/\1/'` case $1 in 1504078485) ;; *) echo "$file: bad magic number" break;; esac case $6 in 0) t='old type bitmap';; 1) t='standard type bitmap';; 2) t='run length encoded';; *) t="bitmap type $6";; esac case $7 in 0) c='no colormap';; 1) c='colourmap ordered all reds first, etc.';; 2) c='raw colourmap';; *) c='unknown colourmap format';; esac len=`expr $8 / 3` echo "$file: magic number ok" echo " width $2, height $3, depth $4, $5 byte $t" echo " $c $len entries ($8 bytes)" # --- dd count=0 reads till eof! # --- awk collects all r's then g's then b's and writes out in rgb triples # --- checking if r=g=b for all, implies grey colourmap. # --- ok[i] set if r or g or b !=0. set to 999+r until r!=g or g!=b. { $checkgrey || $printmap || $checklength } && case $8_$7 in 0_*) ;; *_1) for i in r g b do dd bs=1 count=$len 2>/dev/null | od -bvw1 done | awk ' $2 ~ /.*[1-9].*/{ i=$1+0; c[i] = c[i] " " $2 if(ok[i]==0)ok[i] = $2+999 else if($2+999!=ok[i])colour = 1 next } { i=$1+0; c[i] = c[i] " 0" if(ok[i]==0)ok[i] = 999 else if(999!=ok[i])colour = 1 } END { if(colour==0)print " greyscale colourmap" if("'$printmap'"=="true"){ print "index r g b" for(i=0;i<'"$8"';i++) if(ok[i]>999)printf "%03d %s\n",i,c[i] } }' ;; *) dd bs=1 count=$8 2>/dev/null | od -bvw1 | sed -n '/ 0*$/!p';; esac if $checklength then case `expr \`wc -c\` - $5` in 0) e='data length correct';; -*) e='data short';; *) e='too much data';; esac echo " $e" fi } done **************************************************************************** >From: Martyn Shortley <martyn@med-image.compsci.bristol.ac.uk> 1 way of doing this is to write a sunview program which opens up a pixwin. The depth of this pixwin is then tested. If the depth of the pixwin is 1 bit --> B & W workstation If depth = 8 --> Colour workstation. I also think there might be an easier way based on looking for the framebuffer file. I believe the name of the framebuffer is different depending on the workstation type. **************************************************************************** >From: Andrew Arensburger <arensb@cvl.uucp> If you're trying to write a shell script, then the simplest way, of course, is to have a switch statement, with a case for each machine at your site. In my case, it would be something like: switch (`/bin/hostname`) case valhalla: $color_sun=true breaksw case hvergel: $color_sun=false breaksw default: echo "Zounds! Que pasa, hombre?" breaksw endsw However, if you're looking for something more general (or just some- thing to put in the 'default' case), you can use the following (assuming you're under SunView: #define get_screen_depth(pw) (pw->pw_pixrect->pr_dept) Which returns the depth of the piwin 'pw', in bits per pixel. I assume you can somehow prevent the pixwin from actually appearing on the screen. Alternately, if it seems you cannot, then I suggest that you display a cute little animation of a cartoon character dipping a weighted rope from a boat who looks up and says "Never mind me, I'm just measuring the depth." **************************************************************************** >From: Bob Johnson {x6152} <rjohnson%RELAY.CS.NET%mcvax@aecmail.prime.com> The following is what we have in our ~/../.login file (which is sourced by everyone's ~/.login file) to figure out the color (or colour) capabilities of a sun. The trick is to look at the device names from record of bootups. This can be done at boot-up time as well, and the info put into a file (like /etc/display) so time is not wasted every time a login is done. # Set up display parameters if ( -f /etc/display ) then # If this was figured at bootup time, set them directly source /etc/display else # otherwise ... try to guess them now. set boot = /tmp/sinceboot_$$ onintr - tail -r /var/adm/messages | \ sed -n -e '/^Copyright/q' -e 's/ at.*//p' >! $boot if { grep -s "^bw" $boot } then setenv DISPLAY_TYPE mono setenv DISPLAY_DEPTH 1 else if { grep -s "^cg" $boot } then setenv DISPLAY_TYPE color setenv DISPLAY_DEPTH 8 else if { grep -s "^qfb" $boot } then setenv DISPLAY_TYPE color setenv DISPLAY_DEPTH 4 else setenv DISPLAY_TYPE none setenv DISPLAY_DEPTH 0 endif rm $boot onintr unset boot endif **************************************************************************** >From: "Anthony A. Datri" <datri@convex.uucp> If /dev/cgfour0 exists, it's color. **************************************************************************** >From: Richard Tobin <richard@aiai.ed.ac.uk> You could test for the existence of the various screen devices, eg /dev/cgfour0. ******************************************************************** >From: Guy Harris <guy@auspex.com> Check out FBIO(4S), which mentions an "ioctl" you can use to get information about a frame buffer. You'd presumably open "/dev/fb" (which is an indirect device that gives you the "default" frame buffer) and do the "ioctl" on it. **************************************************************************** >From: Doug Moran <moran@warbucks.ai.sri.com> Here is a function I use in a variety of programs to identify what monitors are on the local system. The decode_fb structure does NOT include entries for the 3 or 4 color monitors that Sun announced on April 12 -- I am waiting for 4.0.3 to confirm the encoding. =================================================================== #include <sys/ioctl.h> #include <sys/file.h> #include <sun/fbio.h> /* decoding as of Release 3.4 : fbio.h 1.3 87/01/09 SMI */ /* the convention for entries in this table is to translate the * macros for frame buffer codes (in <sun/fbio.h>) to short names * thus: * FBTYPE_SUNxBW becomes bwx * FBTYPE_SUNxCOLOR becomes cgx * FBTYPE_SUNxGP becomes gpx * FBTYPE_NOTSUN[1-9] becomes ns[A-J] */ static char *decode_fb[FBTYPE_LASTPLUSONE] = { "bw1", "cg1", "bw2", "cg2", "gp2", "bw3", "cg3", "bw4", "cg4", "nsA", "nsB", "nsC" /* Not Sun */ }; char * wu_fbid(fbname) char *fbname; { struct fbgattr fbattr; int fd, ioctl_ret; if ( (fd = open(fbname, O_RDWR, 0)) == -1 ) return(0); /* FBIOGATTR fails for earlier frame buffer types */ if (ioctl_ret = ioctl(fd,FBIOGATTR,&fbattr)) { /*success=>0(false)*/ ioctl_ret = ioctl(fd, FBIOGTYPE, &fbattr.fbtype); } close(fd); if ( ioctl_ret == -1 ) return(0); /* The binary is obsolete and needs to be re-compiled: * the ioctl returned a value beyond what was possible * when the program was compiled */ if (fbattr.fbtype.fb_type>=FBTYPE_LASTPLUSONE) return("unk"); /* The source is obsolete. The table "decode_fb" does not * have entries for some of the values returned by the ioctl. * Compare <sun/fbio.h> to the entries in "decode_fb" */ if ( decode_fb[fbattr.fbtype.fb_type] == 0 ) return("unk"); if ( fbattr.fbtype.fb_type == FBTYPE_SUN2BW && fbattr.fbtype.fb_width >= 1600 ) return("bw2hm"); return(decode_fb[fbattr.fbtype.fb_type]); } =================================================================== Load it with the standard set of libraries: -lsuntool -lsunwindow -lpixrect Example program that I use in my .login file to determine which .suntools files to use to start up suntools: =================================================================== main() { char *wu_fbid(); char *consoleid = wu_fbid("/dev/fb"); if ( consoleid == 0 ) write(1, "tty", 3); else write(1, consoleid, strlen(consoleid)); write(1, "\n", 1); } =================================================================== **************************************************************************** >From: Mike Khaw <khaw@parcplace.com> You need a C program that examines the frame buffer to see how many bits deep it is (an additional wrinkle is that cgfour frame buffers allow you to run in b&w, 8-bit color, or use all 10 bits). Here's my hack to test the frame buffer; it returns a string -- "monochrome", "color", "prism" (the code name for a cgfour), or "unknown": <--- CUT HERE ---> #include <stdio.h> #include <errno.h> #include <sys/types.h> #include <sys/ioctl.h> #include <sys/file.h> #include <sun/fbio.h> #include <sunwindow/window_hs.h> main() { int fd; char windevname[12]; struct fbgattr attr_buff; errno = 0; if ((fd = open("/dev/fb", O_RDONLY)) < 0) exit(errno); errno = 0; if (ioctl(fd, FBIOGATTR, &attr_buff) < 0) if (ioctl(fd, FBIOGTYPE, &attr_buff.fbtype) < 0) exit(errno); (void) close(fd); if (attr_buff.fbtype.fb_type != FBTYPE_SUN4COLOR) /* not a cgfour, just get the fb's depth */ switch (attr_buff.fbtype.fb_depth) { case 1: printf("monochrome\n"); break; case 8: printf("color\n"); break; default: printf("unknown\n"); break; } else if (we_getparentwindow(windevname)) /* cgfour, but not running suntools/sunview */ printf("prism\n"); else { /* cgfour running suntools/sunview */ struct screen screen; errno = 0; if ((fd = open(windevname)) < 0) exit(errno); win_screenget(fd, &screen); (void) close(fd); if (screen.scr_flags & SCR_8BITCOLORONLY) printf("color\n"); else if (strncmp("/dev/bw", screen.scr_fbname, 7) == 0 || screen.scr_flags & SCR_OVERLAYONLY) printf("monochrome\n"); else /* using all 10 bits */ printf("prism\n"); } exit(0); } <--- CUT HERE ---> **************************************************************************** >From: Rand Huntzinger <randy@sun1.nlm.nih.gov> You could write a special purpose program to look at the depth of the frame buffer (see fbio(4) manual page); however, if you don't mind creating a temporary file you could do the following: 1. Write screendump output to the file... 2. Use the file command on that file, you should get something like... 'file: rasterfile, 1152x900x1 standard format image' (MONO) or 'einstein: rasterfile, 600x600x8 standard format image' (COLOR) 3. Use whatever means you like to get the 1 or 8 bit depth and from the rasterfile description and use the appropriate filter. The nice thing about the above is you could factor out the screendump and use it for raster files generated in other ways. **************************************************************************** >From: Doug Arnold <dna@emmy.umd.edu> This simple C program queries the frame buffer and reports the monitor type. It compiles without any options, e.g., cc -o displaytype displayttype.c Then typing displaytype will print out an informative message such as: % displaytype Sun 2 or 3 color 900 x 1152 x 8 pixels **************************************************************************** >From: Karl Anderson <karl@spruce.gsfc.nasa.gov> A solution might be based on this program, which I did not write and claim no responsibility for: /* * displaytype -- identify type of display connected to Sun workstation * compile with "cc -o displaytype displaytype.c" */ #include <stdio.h> #include <errno.h> #include <sys/file.h> #include <sys/ioctl.h> #include <sun/fbio.h> extern int errno; char *displaytype[] = { "Sun 1 monochrome", "Sun 1 color", "Sun 2 or 3 monochrome", "Sun 2 or 3 color", "Sun 2 or 3 graphics processor", "type unknown", "type unknown", "Sun 4 monochrome", "Sun 4 color", "" }; main() { int fd; struct fbtype fbinfo; /* struct for frame buffer info */ fd = open("/dev/fb", O_RDONLY); if (fd < 0) { printf("Error opening /dev/fb, error #%d\n", errno); exit(2); } if (ioctl(fd, FBIOGTYPE, &fbinfo) == -1) { printf("Ioctl error on /dev/fb, error #%d\n", errno); exit(3); } printf("%s %d x %d x %d pixels\n", displaytype[fbinfo.fb_type], fbinfo.fb_height, fbinfo.fb_width, fbinfo.fb_depth); exit(0); } Unfortunately, displaytype doesn't seem to work with color Sun 4/110s or 3/60s. Good luck. **************************************************************************** >From: ps@tut.fi Pertti Suomela Run `eeprom` and have a look at the `console` row. **************************************************************************** >From: Skip Montanaro <montnaro@sprite.crd.ge.com> You might try eeprom -i console It should spit out something like console=b&w for a black-and-white monitor. For color and gray-scale monitors something else will turn up; I'm not sure what. Note that you may get checksum errors from eeprom. The man page tells you how to fix them, I believe. **************************************************************************** >From: "Lawrence T. LeMay" <lemay@umn-cs.cs.umn.edu> Try these commands: eeprom console arch 'arch' returns the architecture, such as "sun3" or "386i" 'eeprom console' only workson a sun 3 as far as i know. It returns "b&w" or "color" or "ttya" or "ttyb". So, try something like: if (`arch` == "sun3") then if (`eeprom console` == "color") then * color stuff else * b&w stuff endif endif You should probably check to see if you are logged on to the console, but thats fairly easy to do. Its so easy i can't recall the exact command offhand... Kevin Lewis STC Technology Ltd +44 279 29531 ext 2579 London Rd, Harlow kevin@stl.stc.co.uk CM17 9NA (JANET) kevin@uk.co.stc.stl (UUCP) ...uunet!mcvax!ukc!stl!kevin