/**************************************************************** * * Name: SNAKES * * Function: display multiple "snakes" each controlled by a * separate task. * * Shows how to: 1. create and terminate subtasks. * 2. use mail to send initial data to a new task. * 3. use a semaphore to control access to a * resource, in this case the window. * 4. read and write the window contents. * ****************************************************************/ #include #include "dvapi.h" /* minimum API version required */ #define required 0x201 /* number of tasks supported and the stack size for each */ #define ntasks 8 #define stksize 256 /* object handles */ ulong win,kbd,sema,menuwin,menukbd,taskhan[ntasks]; /* step sizes in each direction {up,right,down,left} */ int row_offsets[4] = {-1,0,1,0}; int col_offsets[4] = {0,2,0,-2}; /* variables used to read menu data */ char *kbuf,field; int klng; /* other variables */ int next = 0; /* next task number available */ int locked = 0; /* TRUE if snakes are suspended */ int version; /* actual API version */ /* this string defines the menu contents */ char menu1[] = "\ Create a new snake C \ Kill a snake K \ Bury dead snakes B \ Start/Stop all snakes S \ Exit E "; /* this string defines the menu's field table */ char ftab1[] = {ftab(5,FTH_KEYSELECT+FTH_MODIFIED,0,0,9,1), 0,0,0,25,FTE_SELECT,'C',1,0, 1,0,1,25,FTE_SELECT,'K',1,0, 2,0,2,25,FTE_SELECT,'B',1,0, 3,0,3,25,FTE_SELECT,'S',1,0, 4,0,4,25,FTE_SELECT,'E',1,0, }; /* subtask entry point - defined here to allow forward reference */ int snake(); /********************************************************************** * main - check for DESQview present and enable required extensions. ***********************************************************************/ main () { /* initialize C interfaces and get API version number */ version = api_init(); /* if DESQview is not running or version is too low, display a message */ if (version < required) { printf ("This program requires DESQview version %d.02%d or later.\n", required/256,required%256); } /* tell DESQview what extensions to enable and start application */ else { api_level (required); program_body(); } /* disable C interfaces and return from program */ api_exit(); } /********************************************************************** * program_body - create and display menu window. Loop processing * menu input. ***********************************************************************/ program_body () { /* reserve stack space for subtasks on primary stack so that stack bounds checking still works. Define other local variables. */ char stacks[ntasks][stksize]; int i,k,done; /* get default object handles. Allocate semaphore (mailbox). */ win = win_me(); kbd = key_me(); sema = mal_new(); /* set logical attributes and make task window full screen */ win_logattr (win,1); win_attr (win,1); win_erase (win); win_origin (win,0,0); win_move (win,0,0); win_resize (win,25,80); win_redraw (win); /* allocate window and keyboard objects for menu */ menuwin = win_new ("Snakes",6,5,26); menukbd = key_new(); key_open (menukbd,menuwin); key_addto (menukbd,KBF_FIELD); /* write contents and field table to menu. Make topmost in application. */ win_swrite (menuwin,menu1); win_stream (menuwin,ftab1); win_move (menuwin,1,53); win_unhide (menuwin); win_top (menuwin); /* move mouse to first menu field */ fld_point (win,1,0,0); /* loop until done becomes TRUE */ done = 0; while (!done) { /* wait for menu selection, determine field #, reset to deselected */ key_read (menukbd,&kbuf,&klng); field = *kbuf; fld_reset (menuwin); /* lockout access to screen for all snake tasks */ mal_lock (sema); /* dispatch based on selected field number */ switch (field) { case 1: /* Create new snake - beep if no more snakes allowed */ if (next == ntasks) api_sound (2000,5); else { /* create a new task to run the "snake" function. */ taskhan[next] = tsk_new (snake,stacks[next],stksize,NULL,0,0,0); /* tell task what attribute to use by sending a NULL message with the attribute as its status code. */ mal_subfrom (mal_of(taskhan[next]),NULL,0,next+1); /* bump task count */ next += 1; } break; case 2: /* Kill a snake - beep if there are no more snakes to kill */ if (next == 0) api_sound (2000,5); else { /* decrement task count and kill most recent task */ next -= 1; tsk_free (taskhan[next]); } break; case 3: /* Bury dead snakes - erase window to clear all snakes. Live ones redraw themselves. */ win_attr (win,1); win_erase (win); break; case 4: /* Stop/Start snakes - stop snakes by over-locking the semaphore. Unlock to start. */ (locked) ? mal_unlock(sema) : mal_lock(sema); locked = !locked; break; case 5: /* Exit - set the "done" flag */ done = 1; break; } /* unlock snake tasks and loop until "done" */ mal_unlock (sema); } /* stop all snakes and free their tasks */ mal_lock (sema); for (i=0; i 24) || (ncol < 0) || (ncol > 78)); /* return new position */ *row = nrow; *col = ncol; } /********************************************************************** * position_occupied - return TRUE if there is a char at given position ***********************************************************************/ int position_occupied (row,col) int row,col; { char *readptr; int readlng; /* set cursor to position and read a single character */ win_cursor (win,row,col); win_nread (win,1,&readptr,&readlng); /* return TRUE if it isn't a space */ return (!(*readptr == ' ')); } /********************************************************************** * write_segment - write character twice at given position with * given attribute. ***********************************************************************/ write_segment (row,col,chr,atr) int row,col,chr,atr; { win_cursor (win,row,col); win_attr (win,atr); win_repchar (win,2,chr); }