[comp.sys.apollo] change the background pattern

lambert@spinifex.eecs.unsw.oz (Timothy Lambert) (03/28/90)

The following program lets you display a bitmap in the background
under the Display Manager.  (Like xsetroot -bitmap).

# This is a shell archive.  Remove anything before this line, then
# unpack it by saving it in a file and typing "sh file".  (Files
# unpacked will be owned by you and have default permissions.)
#
# This archive contains:
# bgc.hlp bgc.ins.pas bgc.pas bgc_rtn.pas makefile

echo x - bgc.hlp
cat > "bgc.hlp" << '//E*O*F bgc.hlp//'
"bgc" lets you use a bitmap as a background pattern.  
If you give bgc more than one bitmap (e.g. "bgc *.bmf" it 
picks one at random to use as background.  If you don't
like that one the AGAIN key makes bgc pick another at
random, and the EXIT key terminates "bgc".
//E*O*F bgc.hlp//

echo x - bgc.ins.pas
cat > "bgc.ins.pas" << '//E*O*F bgc.ins.pas//'
{note that each variable in this file should be declared as EXTERN}
const  name_len = 128;
type    name_t       = varying[name_len] of char;
        pt_name_t    = ^name_t;
        argv_t       = array[0..127] of pt_name_t;
        argv_p_t     = ^argv_t;

var status              : extern status_$t;   {all gpr calls return a status value indicating whether they've succeeded or failed}
    display_bitmap      : extern gpr_$bitmap_desc_t;             {this is the bitmap corresponding to the screen}
    display_size        : extern gpr_$offset_t := [gpr_$max_x_size,gpr_$max_y_size];                  {size of display bitmap}
    display_hi_plane    : extern integer; {highest plane on display}
    fill_bitmap         : extern gpr_$bitmap_desc_t;             {this is the bitmap to fill with}
    pattern             : extern boolean;                               {if true fill_bitmap is 32x32 otherwise we have bitmap the size of the screen}
    pad                 : extern ios_$id_t;       {handle to the window we create for drawing in}
    no_of_args          : extern integer;           {no of arguments to bg (counting argument 0) }
    arg_pointer         : extern pgm_$argv_ptr;     {pointer to the arguments}
    argv_p              : extern argv_p_t;

//E*O*F bgc.ins.pas//

echo x - bgc.pas
cat > "bgc.pas" << '//E*O*F bgc.pas//'
program back_ground(input,output);
{displays bitmaps in "background"}
%nolist;
%include '/sys/ins/base.ins.pas';   {common include file for all system routines}
%include '/sys/ins/vfmt.ins.pas';   {routines for converting strings to real numbers}
%include '/sys/ins/pgm.ins.pas';    {declarations for pgm routines (for getting file arguments)}
%include '/sys/ins/pfm.ins.pas';
%include '/sys/ins/gpr.ins.pas';    {contains the declarations for gpr routines}
%include '/sys/ins/pad.ins.pas';    {contains the declarations for pad routines (for creating windows)}
%include '/sys/ins/ios.ins.pas';
%include '/sys/ins/ec2.ins.pas';
%include '/sys/ins/kbd.ins.pas';
%include '/sys/ins/time.ins.pas';
%include '/sys/ins/name.ins.pas';
function fork:integer32; extern;
function random:integer32; extern;
procedure srandom(seed:integer32);val_param; extern;
procedure unlink(in path: univ string); extern;
%list;

define status,                  {each variable that we declare in bg.ins.pas}
    display_bitmap,             {should be defined here}
    display_size,
    fill_bitmap,
    pattern,
    pad,
    no_of_args,
    arg_pointer,
    argv_p;

%include 'bgc.ins.pas';

define display_hi_plane  := gpr_$highest_plane; {number of highest plane on screen - 7 for 8 plane nodes
                                           1 for monochrome nodes.  we ask for maximum no of planes - gpr reduces this to fit}
const unit = 1;

var cmd                 : name_t;
    window_name         : name_t :=  '/tmp/bgc';


    window              : pad_$window_desc_t;
    disp_chars          : gpr_$disp_char_t;
    disp_len            : static integer16 := sizeof(gpr_$disp_char_t);
    disp_len_ret        : integer16;

    decode_count,junk   : integer;           {vfmt_$decode insists on returning these - we don't use them}

    event_type          : gpr_$event_t;      {type of event returned by gpr_$event_wait - not used}
    event_char          : char;              {character user typed in window - not used}
    event_pos           : gpr_$position_t;   {position where she typed it - not used}
    keys                : gpr_$keyset_t :=  [];  {we wait until one of these keys is pressed}
                      
    time : time_$clock_t;

procedure refresh(in unobscured : boolean;
               in position_change : boolean); extern;

procedure check(in messagex : string); extern;
{if last system call was unsuccesful prints an error message}

procedure pause(in t : real); extern;
{waits for t seconds - you might find this useful for debugging}

function randno(n:integer):integer; extern;
{returns a number in range 1..n}

procedure drawit(in file_name:name_t); extern;
{read in the bitmap in file_name and display it}

function again_pressed (IN f_status : pfm_$fault_rec_t): pfm_$fh_func_val_t; extern;
{this function is called when program gets a dq -c 0 signal}

begin
   pgm_$get_args(no_of_args,arg_pointer);
   if no_of_args<=1 then begin
      writeln('Usage: bgc bitmap-names');
      pgm_$exit;
   end; {if}
   {run in background}
   if fork <> 0 then pgm_$exit;

   {kill previous bg, if any}
   cmd := 'dq ';
   append(cmd,window_name);
   append(cmd,';msg '' ''');  {hide error message if window does not exist}
   pad_$dm_cmd(stream_$stdout,cmd.body,cmd.length,status); check('dm command');

   {initialize random number generator}
   time_$clock(time);
   srandom(time.low32);

   gpr_$inq_disp_characteristics(gpr_$borrow,stream_$stdout, disp_len,disp_chars,disp_len_ret, status);
   {create a window and initialise it for graphics}
   with disp_chars do begin
       window.left := x_window_origin;
       window.top := y_window_origin;
       window.width := x_window_size;
       window.height := y_window_size;
   end;{with}

   pad_$create_window(window_name.body,window_name.length,pad_$transcript,unit,window,pad,status); check('creating window');
   ptoc(window_name); unlink(window_name.body);
   if window.width <> 0 then pad_$set_full_window(pad,1,window,status); check('set full window');
   pad_$set_auto_close(pad,1,true,status);
   pad_$set_border(pad,1,false,status);
   gpr_$init(gpr_$direct, pad, display_size,
             display_hi_plane, display_bitmap, status); check('gpr_init');
   gpr_$inq_bitmap_dimensions(display_bitmap,display_size,display_hi_plane,status);
   gpr_$set_obscured_opt(gpr_$ok_if_obs,status);
   gpr_$set_cursor_active(true,status);
      
   argv_p := argv_p_t(arg_pointer);
   drawit(argv_p^[randno(no_of_args-1)]^);

{establish the refresh procedure.  if window needs to be refreshed as
 the result of a pop, the draw procedure will automatically be called.}
    gpr_$set_refresh_entry (addr(refresh), nil, status);
    check('setting the refresh entry procedure.');

{establish the again_pressed procedure.  if window gets a dq -c 1 signal again_pressed will be called}
    discard(pfm_$establish_fault_handler (1,[pfm_$fh_multi_level],ADDR(again_pressed),status));
    check('establishing fault handler');
    pad_$def_pfk(pad,'R2  ','dq -c 1',7,status); check('defining AGAIN');
    pad_$def_pfk(pad,'R5  ','dq',2,status); check('defining EXIT');
  

    discard(gpr_$event_wait (event_type, event_char, event_pos, status)); 
    {We would have liked to have waited for a keystroke, but we can't do
    input into partly obscured windows we resort to evil thing with signals
    instead}
end.
//E*O*F bgc.pas//

echo x - bgc_rtn.pas
cat > "bgc_rtn.pas" << '//E*O*F bgc_rtn.pas//'
MODULE view;  
{This module contains a procedure that the system automatically }
{calls when a refresh is required.                              }
%include '/sys/ins/base.ins.pas';      {required insert file}
%include '/sys/ins/gpr.ins.pas';       {required insert file}
%include '/sys/ins/pad.ins.pas';       {required insert file}
%include '/sys/ins/error.ins.pas';  {declaraions for error handling routines (see check)}
%include '/sys/ins/pfm.ins.pas';
%include '/sys/ins/pgm.ins.pas';
%include '/sys/ins/time.ins.pas';
function random:integer32; extern;

%include 'bgc.ins.pas';
var fill_size     : gpr_$offset_t;   {x and y size of our fill bitmap}
    fill_hi_plane       : gpr_$rgb_plane_t;  {number of highest plane in fill bitmap}


PROCEDURE check(IN messagex : string);
{if last system call was unsuccesful prints an error message}
BEGIN
   if status.all <> status_$ok then
       begin
           error_$print (status);
           writeln('error occurred while ',messagex);
           pgm_$exit;
       end;
END;

Procedure pause(IN t : real);
{waits for t seconds - you might find this useful for debugging}
VAR
   time : time_$clock_t;
BEGIN
   time.high16 := 0;
   time.low32  := trunc(250000 * t);
   time_$wait (time_$relative, time, status);
   check('In Procedure PAUSE.');
END; 

function randno(n:integer):integer;
{returns a number in range 1..n}
begin randno := 1 + random mod n;
end; {randno}

procedure draw_image(in clip:gpr_$window_t);
var
    window        : static gpr_$window_t := [[0,0],[0,0]];
    dest          : gpr_$position_t;  {destinition point for our bit-blts}
    i,j           : integer;
begin
   gpr_$set_clip_window (clip, status) ;
   discard(gpr_$acquire_display(status));
   window.window_size := display_size;
   if pattern then begin 
      gpr_$set_fill_pattern(fill_bitmap,1,status);
      gpr_$rectangle(window,status); check('rectangle');
   end else begin
      for i := clip.window_base.x_coord div fill_size.x_size to (clip.window_base.x_coord+clip.window_size.x_size) div fill_size.x_size do begin
         dest.x_coord := i*fill_size.x_size;
         for j := clip.window_base.y_coord div fill_size.y_size to (clip.window_base.y_coord+clip.window_size.y_size) div fill_size.y_size do begin
            dest.y_coord := j*fill_size.y_size;
            gpr_$pixel_blt( fill_bitmap, window, dest, status );  check('pixel_blt');  {does a bit_blt from bitmap file to fill}
         end;{for}                                                
      end;{for}
   end; {if}
   gpr_$release_display(status);
end; {draw_image}

PROCEDURE refresh(IN unobscured : boolean;
               IN position_change : boolean);
const max_no_windows = 50;
var vis_list : ARRAY[1..max_no_windows] OF gpr_$window_t;
    i, slots_total : integer;
BEGIN
gpr_$release_display(status);
pad_$pop_push_window(pad,1,false,status); check('push');
discard(gpr_$acquire_display(status));
gpr_$set_cursor_active(false,status);
gpr_$inq_vis_list (max_no_windows, slots_total, vis_list, status);
FOR i := 1 TO slots_total DO BEGIN
      draw_image(vis_list[i]);
END;
gpr_$set_cursor_active(true,status);
END;{draw}


procedure getbitmap(in file_name:name_t;out fill_bitmap:gpr_$bitmap_desc_t);
{gets bitmap from file_name}
var dest          : gpr_$position_t;  {destinition point for our bit-blts}
    file_size     : gpr_$offset_t;   {x and y size of our file bitmap}
    file_hi_plane : gpr_$rgb_plane_t;  {number of highest plane in file bitmap}
    color_map     : gpr_$color_vector_t;
    version       : gpr_$version_t;                {some useless information returned by gpr_$open_bitmap_file}
    groups        : integer;                       {more of the same}
    group_hs      : gpr_$bmf_group_header_array_t; {field pixel_size * field n_sects should give # of planes in bitmap}
    created       : boolean;                       {tells us if the bitmap file was created - should be false}
    attribs       : gpr_$attribute_desc_t;         {the attribute block for the bitmap file}
    window        : static gpr_$window_t := [[0,0],[0,0]];
    file_bitmap   : gpr_$bitmap_desc_t;             {this is the bitmap to fill with}
    i,j                 : integer;           
begin
   gpr_$allocate_attribute_block( attribs, status );                                                                    {our window}
   gpr_$open_bitmap_file( gpr_$readonly, file_name.body, file_name.length, version,         {open the bitmap file}
                     file_size, groups, group_hs, 
                     attribs, file_bitmap, created, status );
   if status.all <> status_$ok then begin
       writeln('Couldn''t open ',file_name); pgm_$exit;
   end; {if}
   file_hi_plane := group_hs[0].pixel_size * group_hs[0].n_sects - 1;  {calculates # of planes in file bitmap }
   fill_hi_plane := min(display_hi_plane,file_hi_plane);
   if fill_hi_plane = 7 then begin
       gpr_$inq_bitmap_file_color_map( file_bitmap, 0, 256, color_map, status );
       discard(gpr_$acquire_display(status));
       gpr_$set_color_map( 16, 240, color_map[16], status ); check('set colour map');
       gpr_$release_display(status);
   end; {if}
   if (file_size.x_size = 32) and (file_size.y_size =32) then begin
      fill_size := file_size;
      pattern := true;
   end else begin
      {make sure fill bitmap is at least 200x200}
      fill_size.x_size := file_size.x_size*(1+ 200 div file_size.x_size);
      fill_size.y_size := file_size.y_size*(1+ 200 div file_size.y_size);
      pattern := false
   end; {if}
   gpr_$deallocate_bitmap(fill_bitmap,status); {deallocate fill_bitmap in case this isn't the first time we've been called}
   gpr_$allocate_bitmap(fill_size,fill_hi_plane,attribs,fill_bitmap,status);  {allocate a memory bitmap for bit-blting to}
   window.window_size := file_size;                                            {bitmap file}
   gpr_$set_bitmap( fill_bitmap, status );     
   for i := 0 to (fill_size.x_size-1) div file_size.x_size do begin
      dest.x_coord := i*file_size.x_size;
      for j := 0 to (fill_size.y_size-1) div file_size.y_size do begin
          dest.y_coord := j*file_size.y_size;
          gpr_$pixel_blt( file_bitmap, window, dest, status );  check('pixel_blt');  {does a bit_blt from bitmap file to fill}
      end;{for}                                                
   end;{for}
   gpr_$deallocate_bitmap(file_bitmap,status);
end;
    
procedure drawit(in file_name:name_t);
{read in the bitmap in file_name and display it}
begin
   getbitmap(file_name,fill_bitmap);

   {draw the picture.}                                       
   discard(gpr_$acquire_display(status));
   gpr_$set_bitmap(display_bitmap, status );     
   refresh(true,false);                                             
   gpr_$release_display(status);
end; {drawit}  

function again_pressed (IN f_status : pfm_$fault_rec_t): pfm_$fh_func_val_t ;
{this function is called when program gets a dq -c 1 signal
 this should happen when AGAIN is pressed}
var lock: static boolean := false; {we ignore further interupts till we're finished}
BEGIN
    if not lock then begin
	lock := true;
        drawit(argv_p^[randno(no_of_args-1)]^);
        lock := false;
    end; {if}
    again_pressed := pfm_$return_to_faulting_code;
END; {again_pressed}

//E*O*F bgc_rtn.pas//

echo x - makefile
cat > "makefile" << '//E*O*F makefile//'
PFLAGS = -cpu 3000
bgc: bgc.bin bgc_rtn.bin
	/bin/ld bgc.bin bgc_rtn.bin -o bgc
bgc.bin: bgc.ins.pas
bgc_rtn.bin: bgc.ins.pas


//E*O*F makefile//

exit 0

lambert@spinifex.eecs.unsw.oz (Timothy Lambert) (03/29/90)

If you are running SR10.2 the following patch to bgc
makes things go more smoothly.

*** bgc.pas	Wed Mar 28 20:17:32 1990
--- bgc.pas.bak	Wed Mar 28 20:18:50 1990
***************
*** 103,109 ****
     if window.width <> 0 then pad_$set_full_window(pad,1,window,status); check('set full window');
     pad_$set_auto_close(pad,1,true,status);
     pad_$set_border(pad,1,false,status);
-    pad_$set_erase(pad,1,false,status);
     gpr_$init(gpr_$direct, pad, display_size,
               display_hi_plane, display_bitmap, status); check('gpr_init');
     gpr_$inq_bitmap_dimensions(display_bitmap,display_size,display_hi_plane,status);
--- 103,108 ----