v08i056: wscrawl, Part04/05

Brian Wilson brianw at hpcvlx.cv.hp.com
Mon Jul 16 04:57:31 AEST 1990


Submitted-by: Brian Wilson <brianw at hpcvlx.cv.hp.com>
Posting-number: Volume 8, Issue 56
Archive-name: wscrawl/part04

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then feed it
# into a shell via "sh file" or similar.  To overwrite existing files,
# type "sh file -c".
# The tool that generated this appeared in the comp.sources.unix newsgroup;
# send mail to comp-sources-unix at uunet.uu.net if you want that tool.
# If this archive is complete, you will see the following message at the end:
#		"End of archive 4 (of 5)."
# Contents:  wscrawl/xaa
# Wrapped by argv at turnpike on Sun Jul 15 11:47:12 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'wscrawl/xaa' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'wscrawl/xaa'\"
else
echo shar: Extracting \"'wscrawl/xaa'\" \(35046 characters\)
sed "s/^X//" >'wscrawl/xaa' <<'END_OF_FILE'
X/*
X *                                WSCRAWL
X *
X *  This file is: wscrawl.c 
X *         ("image_f_io.c" and "pause_curs.h" are also part of this program)
X *
X *  This is the source code to the program "wscrawl".  The word "wscrawl"
X *  stands for "window-scrawl", reflecting the history of wscrawl.  The user
X *  may think of wscrawl as a paint program shared by any number of people
X *  at the same time.  When wscrawl is run, it opens a separate window on 
X *  each participant's display.  From that point, each participant may draw
X *  in his or her window.  All participants see everything drawn by the other
X *  participants instantly.
X * 
X *  NOTES OF PORTABILITY: The routine "block_until_input()" uses a "select"
X *  system call.  Some systems do not have this call.  To patch for this
X *  problem, simply comment out all source inside that routine.  The other
X *  potential problem is with the "rand" function.  If the airbrush is not
X *  "scattering" properly, then take a look at the function "my_rand" and
X *  try to get it to return a random decimal between 0 and 1.
X *
X *  Feel free to use/change/modify/erase/whatever this source code.  Comments
X *  requests, hacked up versions of wscrawl should go to: brianw at cv.hp.com
X *
X *  This program was written by Brian Wilson of Hewlett Packard Co.
X *  Email: brianw at cv.hp.com
X *  
X *  To compile: "cc -o wscrawl wscrawl.c image_f_io.c -lX11"
X *  To invoke: "wscrawl -d displayname1 -d displayname2 . . ."
X *  For a complete usage message, just do a: "wscrawl -help"
X */
X
X#define INTERESTING_EVENTS ButtonPressMask | ButtonReleaseMask | KeyPressMask \
X			   | StructureNotifyMask | ExposureMask
X
X#define WSCRAWL_WIN_WIDTH   	760     /*initial window dimensions*/
X#define WSCRAWL_WIN_HEIGHT   	550
X#define DIALOG_WIN_WIDTH   	300 
X#define DIALOG_WIN_HEIGHT   	50
X
X#define MAX_NUM_DISPS   	10      /*general global variables*/
X#define NUM_OF_MENUS    	7
X#define FIXED_CHAR_WIDTH	7
X#define TRUE			1
X#define FALSE	 		0
X
X#define STRAIGHT_LINE		0       /*types of shapes*/
X#define OUTLINE_RECT		1
X#define FILLED_RECT		2
X#define OUTLINE_OVAL		3
X#define FILLED_OVAL		4
X
X#define NOT_PRESSED     	0       /*Pointer States*/
X#define PRESSED			1
X#define IN_MENU			2
X#define BETWEEN_MENUS           3
X
X#define SCRAWLING		1       /*modes of drawing*/
X#define AIRBRUSHING		2
X#define TYPING			3
X#define ERASING			4
X#define SELECTING_AN_AREA	5
X#define RUBBER_POINTING		6
X#define PLACING_A_BITMAP	7
X#define PLACING_A_TEXTFILE	8
X#define RESPONDING_TO_DIALOG	9
X#define PLACING_AN_IMAGE	10
X
X#define SAVE_BITMAP		1       /*things to do after answering dialog*/
X#define READ_IN_BITMAP		2
X#define ADD_A_DISPLAY		3
X#define READ_TEXTFILE		4
X#define SAVE_IMAGE		5
X#define READ_IN_IMAGE		6
X#define DRAW_SHAPE		7       /*this is a hack to allow me use of the 
X					  rubber select box*/
X
X#define MENU_ITEM_WIDTH	        104     /*menu parameters*/
X#define MENU_ITEM_HEIGHT	25
X#define NO_ITEM_SELECTED	-1
X
X#define MAX_RAND  	((1<<15) - 1)
X
X#include <stdio.h>		/*standard i/o functions*/
X#include <stdlib.h>		/*for the "getenv" command*/
X#include <X11/Xos.h>            /*"time.h" necessary for the "select" stuff */
X#include <X11/Xlib.h>		/*standard x defs*/
X#include <X11/Xutil.h>		/*necessary for the XWMhints stuff*/
X#include <X11/cursorfont.h>	/*we are gonna change the pointer*/
X#include "pause_curs.h"		/*our custom pause cursor*/
X
Xstatic char what[] = "@(#)WSCRAWL - Brian Wilson 7/14/90";
X
Xfloat my_rand();                /*hack, hack, cough, wheez, sputter, hack*/
X
XXSetWindowAttributes menuwinvals =  /*struct for the menu windows*/
X{
X    None,                       /*default background pixmap*/
X    1,                          /*background pixel*/
X    CopyFromParent,             /*border_pixmap*/
X    0, 0, 
X    NorthWestGravity,           /*window gravity*/
X    NotUseful,                  /*backing store*/
X    0, 0, 0, 
X    INTERESTING_EVENTS,         /*events we are interested in*/
X    0, 
X    True,                       /*override redirect flag*/
X    0, 0
X};
X
XXSetWindowAttributes winvals =  /*struct for the window*/
X{
X    None,                       /*default background pixmap*/
X    1,                          /*background pixel*/
X    CopyFromParent,             /*border_pixmap*/
X    0, 0, 
X    NorthWestGravity,           /*window gravity*/
X    Always,                     /*backing store*/
X    0, 0, 0, 
X    INTERESTING_EVENTS,         /*events we are interested in*/
X    0, 
X    False,                      /*override redirect flag*/
X    0, 0
X};
X
XXGCValues menugcvalues =        /*menu graphics context values*/
X{                               /*so we need a gc values structure*/
X    GXxor,                       /*write rule*/
X    0,0,0,0,0,0,
X    0,0,0,0,0,0,0,0,0,          /*bunch of placeholders*/
X    None,			/*subwindow_mode*/
X    0,0,0,0,0,0
X};
X
XXGCValues gcvalues =            /*We want to "include inferiors"*/
X{                               /*so we need a gc values structure*/
X    0,0,
X    0,                          /*foreground color*/
X    0,
X    8,                          /*width of the line*/
X    0,
X    CapRound,                   /*CapRound looks good, but is VERY SLOW*/
X    0,0,0,0,0,0,0,0,0,          /*bunch of placeholders*/
X    None,			/*subwindow_mode*/
X    0,0,0,0,0,0
X};
X
XXGCValues cursor_gc_values =    /*We want the cursor to have XOR */
X{                               /*so we need a gc values structure*/
X    GXor, 
X    0,0,0,
X    4,                          /*Line width*/
X    0,0,0,0,0,0,0,0,0,0,0,      /*bunch of placeholders*/
X    0,0,0,0,0,0,0
X};
X
X/*
X * The following text definitions deserve some explanation.  If you want a new
X * color, or font, or pen_width, simply add the desired value to these lists.
X * The routines automatically incorporate these new values and change menu
X * lengths.  If you want to add a brand new menu, then I recommend
X * you add create a menu_text5 list, then link it appropriately in 
X * "initialize_displays()", change the "#define NUM_OF_MENUS   7" to 8,
X * and add the new functionality to the "menu_selection()" routine.  Good
X * luck, as their are lots of little special cases to worry about, depending
X * on your particular functionality.  Remember to mail interesting versions 
X * to the above address.  :-)
X */
Xstatic char *menu_text0[] = {"Control", 
X			     "Scrawl", 
X			     "Airbrush", 
X			     "Type", 
X			     "Eraser",
X			     "Draw Shapes",
X			     "Rubber Pointer",
X			     "Clear Windows", 
X			     "--------------", 
X			     "Add Display",
X			     "Close Window", "****"};
Xstatic char *menu_text1[] = {"PenColor", "white", "magenta", "red", "blue",
X			     "cyan", "LightSteelBlue", "navy blue", "green",
X			     "coral", "light grey", "orange", "plum", "yellow",
X			     "black", "****"};
Xstatic char *menu_text2[] = {"PenWidth", "1", "2", "4", "8", "15", "25", "30",
X			     "45", "60", "100", "150", "500", "****"};
Xstatic char *menu_text3[] = {"PenCapStyle", "CapRound", "CapButt", 
X			     "CapNotLast", "CapProjecting", "****"};
Xstatic char *menu_text4[] = {"Font", "fixed", "variable", 
X			     "timR12", "helvO12", "courR12", "courR14",
X			     "timBI18", "courR24", "timR24", "timBI24",
X			     "ncenR24", "vbee-36", "vr-40", "vgl-40", 
X			     "vsgn-57", "****"};
Xstatic char *menu_text5[] = {"Shapes", "Straight Line", "Outline Rect", 
X			     "Filled Rect", "Outline Oval", "Filled Oval", 
X			     "****"};
Xstatic char *menu_text6[] = {"File I/O", "Save Bitmap", "Read In Bitmap", 
X			     "Read Text File", "Save Image", 
X			     "Read In Image", "****"};
Xchar **menu_text[NUM_OF_MENUS];
X
Xint num_of_disps = 1;               /*start with your home display*/
Xchar disp_args[MAX_NUM_DISPS][50];  /*No more than 50 letters in display name*/
Xchar PEN_COLOR[42];
Xchar BACKGROUND_COLOR[42];
Xchar MENU_HIGHLIGHT_COLOR[42];
Xchar MENU_FOREGROUND_COLOR[42];
Xchar MENU_BACKGROUND_COLOR[42];
Xchar PEN_STYLE[42];
Xchar FONT[256];
Xint NUM_DOTS;
Xint PEN_WIDTH;
Xint CAP_STYLE;
Xint NOTHING_DRAWN_YET;       /*I am so, so ashamed of this variable*/
Xint TYPE_NOT_DRAW;
X
Xextern XImage *read_image_from_disk();
X
Xstruct char_node	     /*for the history of typing (for backspacing)*/
X{
X    char the_char;
X    int x, y;                /*where this letter was typed (only for <CR>)*/
X    struct char_node *next;  /*pointer to the next character*/
X};
X
Xstruct a_menu	             /*one of these for every menu*/
X{
X    Window win_id;	     /*the window which IS the menu*/
X    int num_items;           /*the number of items in this menu*/
X    int item_selected;	     /*the current item which is selected*/
X    int checked_item;	     /*the current item which is checked*/
X};
X
Xstruct penwidthstruct        /*keeps track of all the current penwidths*/
X{
X    int scrawl;              /*the scrawl penwidth*/
X    int airbrush;	     /*the airbrush penwidth*/
X    int eraser;	             /*the eraser penwidth*/
X    int shape;	             /*the shape penwidth*/
X};
X
Xstruct rubberpointstruct     /*this holds the rubberband cursor pixmap and dim*/
X{
X    Pixmap rubber_pointer_pix[MAX_NUM_DISPS]; /*a rubber pointer for each disp*/
X    int width;               /*the width of the pointer*/
X    int height;	             /*the height of the pointer*/
X    int is_mapped_bool;	     /*TRUE when this person's pointer is mapped*/
X};
X
Xstruct disp_info_struct      /*one of these exists for every "wscrawl" window*/
X{
X    Display *disp;           /*the display variable for this scrawl window*/
X    Window win_id;           /*the window id of this scrawl window*/
X    Window status_win_id;    /*the status window id for this scrawl window*/
X    Window eraser_win_id;    /*the eraser window id for this scrawl window*/
X    Window dialog_win_id;    /*the dialog window id for this scrawl window*/
X    GC *win_gc;              /*one graphics context for every scrawl window*/
X    GC rubber_band_gc;       /*the graphics context for rubber band boxes*/
X    GC fg_menu_gc;	     /*the graphics context for the menu foreground*/
X    GC hi_menu_gc;           /*the graphics context for highlighting of menus*/
X    GC bg_menu_gc;	     /*the graphics context for unhighlighting of mens*/
X    int current_menu;	     /*the current menu that is pulled down(if one is)*/
X    struct a_menu menu[NUM_OF_MENUS]; /*each menu in a scrawl window*/
X    int in_session_bool;     /*whether this win is still in the session or not*/
X    int connection_num;      /*socket that this window is on*/
X    int pointer_state;       /*choices include: NOT_PRESSED, PRESSED, IN_MENU*/
X    int scrawl_mode;	     /*choices include: SCRAWLING, AIRBRUSHING, TYPING*/
X    int previous_scrawl_mode;/*choices include: SCRAWLING, AIRBRUSHING, TYPING*/
X    int first_point_bool;    /*boolean: is this first point drawn in this win?*/
X    int just_placed_something_bool; /*boolean: set if person placed bitmap,etc*/
X    int dialog_what;	     /*the thing we will do after user answers dialog*/
X    char *dialog_text_prompt;/*the prompt that goes in the dialog box*/
X    char dialog_text_return[256];/*text that the user has typed in dialog box*/
X    int dialog_reply_index;  /*current location of the text in dialog_text_ret*/
X    int capstyle;	     /*pen width of this display*/
X    int pen_width;	     /*pen width of this display*/
X    char pen_color_str[42];  /*pen color that this display is scrawling with*/
X    char font_str[256];      /*font that this display is typing with*/
X    int current_shape;	     /*the current shape to be drawn (if one is)*/
X    struct penwidthstruct pen_widths; /*all the various penwidths*/
X    XFontStruct *the_font_struct;
X    struct char_node *type_history; /*history of all typed characters*/
X    GC cursor_gc;            /*graphics context for the typing cursor*/
X    Cursor pause_cursor;     /*the pause cursor for this display*/
X    struct rubberpointstruct rubber_pointer; /*the rubber pointer*/
X    int prompt_width;	     /*width of the typing cursor*/
X    int orig_x, char_height; /*x origin and height of current font*/
X    int cursor_on;	     /*boolean indication of whether cursor is shown*/
X    unsigned long background;/*planes mask of the background color*/
X    XPoint select_start_pos; /*x,y of first click position of select area*/
X    XPoint cur_pos;          /*current position of the typing cursor*/
X    int rubber_band_width;   /*width of rubber band box for placing bitmap*/
X    int rubber_band_height;  /*height of rubber band box for placing bitmap*/
X    int win_width;           /*current width of this window*/
X    int win_height;          /*current height of this window*/
X    XPoint last_point;       /*the last point drawn in this window*/
X    Atom xa_WM_DELETE_WINDOW;/*for communication with the window manager*/
X    Atom xa_WM_PROTOCOLS;    /*for communication with the window manager*/
X};
X
Xstruct disp_info_struct disp_info[MAX_NUM_DISPS];
Xint num_people_drawing = 0;
X
X
Xmain (argc, argv)
Xint argc;
Xchar *argv[];
X{
X    int i;
X
X    parse_command_line(argv, argc);
X    initialize_displays(&num_people_drawing);  /*open displays, windows, etc*/
X
X    while (1)
X    {      
X	block_until_input();
X
X	do
X	{
X	    for (i=0; i<num_of_disps; i++)
X		 if (disp_info[i].in_session_bool)
X		 {
X                     XFlush(disp_info[i].disp);
X	             process_event(i, &num_people_drawing);
X		     if (disp_info[i].in_session_bool == FALSE)
X			 break;
X		     switch (disp_info[i].pointer_state)
X		     {
X		         case PRESSED:
X			    switch(disp_info[i].scrawl_mode)
X			    {
X				case SELECTING_AN_AREA:
X				    update_select_area(i);
X				    break;
X				case SCRAWLING:
X				case AIRBRUSHING:
X				case ERASING:
X				case RUBBER_POINTING:
X		                    draw_on_screens(i); /*draw on ALL displays*/
X				    break;
X				default:
X				    break;
X			    }
X			    break;
X			 case IN_MENU:
X			    update_menu_highlights(i);
X			    break;
X			 case NOT_PRESSED:
X			    switch (disp_info[i].scrawl_mode)
X			    {
X				case TYPING:
X			            type_on_screens(i);/*type on ALL displays*/
X				    break;
X			        case PLACING_A_TEXTFILE:
X			        case PLACING_A_BITMAP:
X			        case PLACING_AN_IMAGE:
X			            slide_rubberband_box(i,&num_people_drawing);
X				    break;
X			        case RESPONDING_TO_DIALOG:
X			            type_on_dialog(i);  /*type in dialog box*/ 
X				    break;
X				default:
X				    break;
X			    }
X			    break;
X			 default:
X			    break;
X		     }
X		 }
X	} while (num_people_drawing);    /*while someone is still drawing*/
X    }
X}
X
X
X/*
X * set_paused_cursors - this function sets all cursors on all displays to be
X *            "Pause" cursors.  This function is called when some action is
X *            done that totally sucks all cycles for a minute or two, like
X *            reading an image in.
X *             
X */
Xset_paused_cursors()
X{
X    int i, j;
X
X    for (i=0; i<num_of_disps; i++)
X    {
X        if (disp_info[i].in_session_bool) /*if window is alive*/
X        {
X            XDefineCursor(disp_info[i].disp, disp_info[i].win_id,
X                         disp_info[i].pause_cursor);
X            XDefineCursor(disp_info[i].disp, disp_info[i].status_win_id,
X                         disp_info[i].pause_cursor);
X            XDefineCursor(disp_info[i].disp, disp_info[i].eraser_win_id,
X                         disp_info[i].pause_cursor);
X            XDefineCursor(disp_info[i].disp, disp_info[i].dialog_win_id,
X                         disp_info[i].pause_cursor);
X            for (j=0; j<NUM_OF_MENUS; j++)
X                XDefineCursor(disp_info[i].disp, disp_info[i].menu[j].win_id,
X                         disp_info[i].pause_cursor);
X            XFlush(disp_info[i].disp);
X        }
X    }
X}
X
X
X/*
X * unset_paused_cursors - this function sets all cursors on all displays to be
X *            the cursors they were before the "Pause" occured.  
X */
Xunset_paused_cursors()
X{
X    int i, j, the_cursor;
X
X    for (i=0; i< num_of_disps; i++)
X    {
X        if (disp_info[i].in_session_bool) /*if window is alive*/
X        {
X	    switch (disp_info[i].scrawl_mode)
X	    { 
X		case SCRAWLING:
X		    the_cursor = XC_dot;
X		    break;
X		case AIRBRUSHING:
X		    the_cursor = XC_spraycan;
X		    break;
X		case TYPING:
X		    the_cursor = XC_xterm;
X		    break;
X		case ERASING:
X		    the_cursor = XC_draped_box;
X		    break;
X		case RUBBER_POINTING:
X		    the_cursor = XC_target;
X		    break;
X		case SELECTING_AN_AREA:
X		    the_cursor = XC_crosshair;
X		    break;
X		case PLACING_A_BITMAP:
X		case PLACING_A_TEXTFILE:
X		case RESPONDING_TO_DIALOG:
X		case PLACING_AN_IMAGE:
X		    the_cursor = XC_cross;
X		    break;
X		default:
X		    break;
X	    }
X		
X	    XDefineCursor(disp_info[i].disp, disp_info[i].win_id,
X	             XCreateFontCursor(disp_info[i].disp, the_cursor));
X	    XDefineCursor(disp_info[i].disp, disp_info[i].status_win_id,
X	             XCreateFontCursor(disp_info[i].disp, XC_star));
X	    XDefineCursor(disp_info[i].disp, disp_info[i].dialog_win_id,
X	             XCreateFontCursor(disp_info[i].disp, XC_xterm));
X	    XDefineCursor(disp_info[i].disp, disp_info[i].eraser_win_id,
X	             XCreateFontCursor(disp_info[i].disp, XC_draped_box));
X            for (j=0; j<NUM_OF_MENUS; j++)
X	        XDefineCursor(disp_info[i].disp, disp_info[i].menu[j].win_id,
X	             XCreateFontCursor(disp_info[i].disp, XC_right_ptr));
X            XFlush(disp_info[i].disp);
X        }
X    }
X}
X
X
X/*
X * place_a_textfile - this function places a text file onto the wscrawl
X *               windows in the current font and color, at the location
X *               this individual has just clicked.
X */
Xplace_a_textfile(disp_num, the_event)
Xint disp_num;
XXButtonPressedEvent *the_event;
X{
X    int i, c, length, top, left, width, height;
X    FILE *text_file_ptr;
X    char current_line[512];
X
X    (num_people_drawing)--;         /*done drawing now*/
X
X    /*
X     * erase rubber band box
X     */
X    top = disp_info[disp_num].cur_pos.y - 
X    disp_info[disp_num].rubber_band_height/2;
X    left = disp_info[disp_num].cur_pos.x - 
X                disp_info[disp_num].rubber_band_width/2;
X    width = disp_info[disp_num].rubber_band_width;
X    height = disp_info[disp_num].rubber_band_height;
X    XDrawRectangle(disp_info[disp_num].disp, 
X	           disp_info[disp_num].win_id,
X                   disp_info[disp_num].rubber_band_gc,
X                   left, top, width, height);
X    /*
X     * place the text file at the current pointer location
X     */
X    if ((text_file_ptr = fopen(disp_info[disp_num].dialog_text_return,"r")) == 
X	NULL)
X    {
X        printf("ERROR: Could not open text file %s.\n", 
X			disp_info[disp_num].dialog_text_return);
X    }
X    else
X    {
X        set_paused_cursors();                     /*this may take a while*/
X
X	disp_info[disp_num].orig_x = left;
X        disp_info[disp_num].char_height =
X	       (disp_info[disp_num].the_font_struct)->max_bounds.ascent +
X               (disp_info[disp_num].the_font_struct)->max_bounds.descent;
X
X	while ((c = getc(text_file_ptr)) != EOF)
X	{
X	    ungetc(c, text_file_ptr);
X	    fgets(current_line, 510, text_file_ptr);       /*get the line*/
X            for (length=0; current_line[length] != '\n'; length++)
X		;
X    
X	    /*draw this line to all the displays*/
X            for (i=0; i< num_of_disps; i++)
X            {
X                if (disp_info[i].in_session_bool) /*if window is alive*/
X                {
X	            XDrawString(disp_info[i].disp, disp_info[i].win_id,
X		                disp_info[disp_num].win_gc[i], 
X			        left, top, current_line, length);
X                }
X            }
X            left = disp_info[disp_num].orig_x;
X            top += disp_info[disp_num].char_height;
X
X        }
X	fclose(text_file_ptr);
X        for (i=0; i< num_of_disps; i++)
X            if (disp_info[i].in_session_bool) /*if window is alive*/
X                XFlush(disp_info[i].disp);
X
X        unset_paused_cursors();                   /*done with long action*/
X        /*go back to appropriate drawing tool*/ 
X        menu_selection(disp_num, 0, &num_people_drawing, 
X		       disp_info[disp_num].previous_scrawl_mode);
X    }
X}
X
X
X/*
X * place_an_image - this routine places an image at the current location
X */
Xplace_an_image(disp_num, the_event)
Xint disp_num;
XXButtonPressedEvent *the_event;
X{
X    int i, top, left, width, height, depth;
X    XImage *the_image;
X    char *mesg;
X
X    (num_people_drawing)--;         /*done drawing now*/
X    /*
X     * erase rubber band box
X     */
X    top = disp_info[disp_num].cur_pos.y - 
X    disp_info[disp_num].rubber_band_height/2;
X    left = disp_info[disp_num].cur_pos.x - 
X                disp_info[disp_num].rubber_band_width/2;
X    width = disp_info[disp_num].rubber_band_width;
X    height = disp_info[disp_num].rubber_band_height;
X    XDrawRectangle(disp_info[disp_num].disp, 
X	           disp_info[disp_num].win_id,
X                   disp_info[disp_num].rubber_band_gc,
X                   left, top, width, height);
X
X    set_paused_cursors();     /*this will take a while*/
X
X    for (i=0; i<num_of_disps; i++)
X    {
X	if (disp_info[i].in_session_bool)
X	{
X            if ((the_image = read_image_from_disk(disp_info[i].disp, 
X			   disp_info[i].win_id,
X	                   disp_info[disp_num].dialog_text_return, &width, 
X			   &height, &depth)) == NULL)
X	    {
X		printf("WARNING: image not displayed on display %s.\n",
X		       disp_args[i]);
X		XClearArea(disp_info[i].disp, disp_info[i].win_id, 
X			   left, top, width, height, False);
X
X		XSetLineAttributes(disp_info[i].disp, 
X                               disp_info[i].rubber_band_gc, 3, LineSolid,
X			       CapButt, JoinBevel);
X		if ((width > 4) && (height > 4))
X		{
X                    XDrawRectangle(disp_info[i].disp, 
X	                       disp_info[i].win_id,
X                               disp_info[i].rubber_band_gc,
X                               left + 2, top + 2, width - 4, height - 4);
X		}
X		XSetLineAttributes(disp_info[i].disp, 
X                               disp_info[i].rubber_band_gc, 0, LineSolid,
X			       CapButt, JoinBevel);
X
X		mesg = "You are missing an image here.";
X		XDrawString(disp_info[i].disp, disp_info[i].win_id,
X		            disp_info[i].fg_menu_gc, 
X			    (left + (width/2) - 88), (top + (height/2) + 5),
X			     mesg, strlen(mesg));
X	    }
X	    else if (DefaultDepth(disp_info[i].disp, 
X			     DefaultScreen(disp_info[i].disp)) != depth)
X	    {
X		printf("WARNING: image not displayed on display %s. ",
X		       disp_args[i]);
X		printf("(Inconsistent depths.)\n");
X	        XDestroyImage(the_image);       /*free the image memory*/
X	    }
X	    else
X	    {
X                XPutImage(disp_info[i].disp, disp_info[i].win_id,
X		      disp_info[disp_num].win_gc[i], the_image, 
X		      0, 0, left, top, width, height);
X                XFlush(disp_info[i].disp);
X	        XDestroyImage(the_image);
X	    }
X	}
X    }
X    unset_paused_cursors();     /*done*/
X
X    /*go back to appropriate drawing tool*/ 
X    menu_selection(disp_num, 0, &num_people_drawing, 
X		       disp_info[disp_num].previous_scrawl_mode);
X}
X
X
X/*
X * place_a_bitmap - this routine places a bitmap at the current location
X */
Xplace_a_bitmap(disp_num, the_event)
Xint disp_num;
XXButtonPressedEvent *the_event;
X{
X    int top, left, width, height;
X
X    (num_people_drawing)--;       /*stop this dude's talley*/
X
X    /*
X     * erase rubber band box
X     */
X    top = disp_info[disp_num].cur_pos.y - 
X    disp_info[disp_num].rubber_band_height/2;
X    left = disp_info[disp_num].cur_pos.x - 
X                disp_info[disp_num].rubber_band_width/2;
X    width = disp_info[disp_num].rubber_band_width;
X    height = disp_info[disp_num].rubber_band_height;
X    XDrawRectangle(disp_info[disp_num].disp, 
X	           disp_info[disp_num].win_id,
X                   disp_info[disp_num].rubber_band_gc,
X                   left, top, width, height);
X    read_in_and_place_bitmap(disp_num,
X		              disp_info[disp_num].dialog_text_return, 
X		              the_event->x - width/2, the_event->y - height/2);
X}
X
X
X/*
X * update_select_area - this function updates the rubber-band box that this
X *             user is selecting an area with.  This function has no effect
X *             other than visual.
X */
Xupdate_select_area(disp_num)
Xint disp_num;
X{
X    Window rr, cr;                 /* <-- Some strange ass variables, dude.*/
X    unsigned int mskr;
X    int temp, rxr, ryr, win_x, win_y;
X    int start_x, start_y, last_x, last_y;
X
X    if (disp_info[disp_num].first_point_bool)
X    { 
X        XQueryPointer(disp_info[disp_num].disp, 
X			  disp_info[disp_num].win_id, &rr, &cr, &rxr, 
X			  &ryr, &win_x, &win_y,&mskr);
X	disp_info[disp_num].select_start_pos.x = win_x;
X	disp_info[disp_num].select_start_pos.y = win_y;
X        disp_info[disp_num].cur_pos.x = win_x;
X        disp_info[disp_num].cur_pos.y = win_y;
X        disp_info[disp_num].first_point_bool = FALSE;
X    } 
X
X    XQueryPointer(disp_info[disp_num].disp,
X	          disp_info[disp_num].win_id, &rr, &cr, &rxr,
X		  &ryr, &win_x, &win_y,&mskr);
X    /*
X     * if the user has changed the x and y position of the pointer, change
X     * the rubberband box.
X     */
X    if ((win_x != disp_info[disp_num].cur_pos.x) ||
X        (win_y != disp_info[disp_num].cur_pos.y))
X    {
X	start_x = disp_info[disp_num].select_start_pos.x;
X	start_y = disp_info[disp_num].select_start_pos.y;
X	last_x = disp_info[disp_num].cur_pos.x;
X	last_y = disp_info[disp_num].cur_pos.y;
X
X        if (start_x > last_x)  /*switch so lesser coordinate is first*/
X        {
X            temp = start_x;
X	    start_x = last_x;
X	    last_x = temp;
X	}
X	if (start_y > last_y)  /*switch so lesser coordinate is first*/
X	{
X            temp = start_y;
X	    start_y = last_y;
X	    last_y = temp;
X	}
X
X	/*erase old one*/
X        XDrawRectangle(disp_info[disp_num].disp, disp_info[disp_num].win_id,
X	               disp_info[disp_num].rubber_band_gc,
X		       start_x, start_y, last_x - start_x,  last_y - start_y);
X
X	disp_info[disp_num].cur_pos.x = win_x;
X	disp_info[disp_num].cur_pos.y = win_y;
X	start_x = disp_info[disp_num].select_start_pos.x;
X	start_y = disp_info[disp_num].select_start_pos.y;
X	last_x = disp_info[disp_num].cur_pos.x;
X	last_y = disp_info[disp_num].cur_pos.y;
X
X        if (start_x > last_x)  /*switch so lesser coordinate is first*/
X        {
X            temp = start_x;
X	    start_x = last_x;
X	    last_x = temp;
X	}
X	if (start_y > last_y)  /*switch so lesser coordinate is first*/
X	{
X            temp = start_y;
X	    start_y = last_y;
X	    last_y = temp;
X	}
X
X        /* draw the new one */
X        XDrawRectangle(disp_info[disp_num].disp, disp_info[disp_num].win_id,
X	               disp_info[disp_num].rubber_band_gc,
X		       start_x, start_y, last_x - start_x,  last_y - start_y);
X	XFlush(disp_info[disp_num].disp);
X    }
X}
X
X
X/* 
X * update_menu_highlights - this function highlights the proper menu selection.
X *             It does not have any affect except visual upon any operations.
X *             However, it could entail switching between menus on the menu
X *             bar if the user has moved the mouse too far off the menu.
X *             It also is responsible for updating the "item_selected" field
X *             of the disp_info structure.
X */
Xupdate_menu_highlights(disp_num)
X{
X    int new_item_num, num_items, menu_num;
X    Window rr, cr;
X    unsigned int mskr;
X    int rxr, ryr, win_x, win_y, oldy, old_item_selected;
X
X
X    menu_num = disp_info[disp_num].current_menu;
X    old_item_selected = disp_info[disp_num].menu[menu_num].item_selected;
X    num_items = disp_info[disp_num].menu[menu_num].num_items;
X    XQueryPointer(disp_info[disp_num].disp, 
X		  disp_info[disp_num].menu[menu_num].win_id,
X	          &rr, &cr, &rxr, &ryr, &win_x, &win_y,&mskr);
X    
X    /*first figure out what item the pointer is pointing at*/
X    for (new_item_num=0; new_item_num < num_items; new_item_num++)
X    {
X        if (win_y < (new_item_num * MENU_ITEM_HEIGHT)+ MENU_ITEM_HEIGHT)
X	    break;
X    }
X
X    /*only draw highlight if not the menu title, and not already selected*/
X    if ((new_item_num != 0) && (new_item_num != old_item_selected))
X    {
X	disp_info[disp_num].menu[menu_num].item_selected = new_item_num;
X	/*erase old highlight*/
X	oldy = (old_item_selected * MENU_ITEM_HEIGHT) + 4;
X        XDrawRectangle(disp_info[disp_num].disp, 
X		   disp_info[disp_num].menu[menu_num].win_id, 
X		   disp_info[disp_num].bg_menu_gc, 2, oldy,
X		   MENU_ITEM_WIDTH - 4, MENU_ITEM_HEIGHT - 6);
X
X	/*draw new highlight*/
X        XDrawRectangle(disp_info[disp_num].disp, 
X		   disp_info[disp_num].menu[menu_num].win_id, 
X		   disp_info[disp_num].hi_menu_gc, 2, 
X		   4 + (MENU_ITEM_HEIGHT * new_item_num),
X		   MENU_ITEM_WIDTH - 4, MENU_ITEM_HEIGHT - 6);
X    }
X    else if ((new_item_num == 0) && (new_item_num != old_item_selected))
X    {
X	disp_info[disp_num].menu[menu_num].item_selected = new_item_num;
X	/*erase old highlight*/
X	oldy = (old_item_selected * MENU_ITEM_HEIGHT) + 4;
X        XDrawRectangle(disp_info[disp_num].disp, 
X		   disp_info[disp_num].menu[menu_num].win_id, 
X		   disp_info[disp_num].bg_menu_gc, 2, oldy,
X		   MENU_ITEM_WIDTH - 4, MENU_ITEM_HEIGHT - 6);
X    }
X    else if ((new_item_num == 0) && (new_item_num == old_item_selected))
X    {
X        /*
X	 * The following code decides if it is necessary to release a menu,
X	 * and if so, it releases the old menu and pulls down a new one.
X	 */
X        if ((win_x < 0) && (menu_num != 0))   /*move to the left one menu*/
X	{
X            disp_info[disp_num].pointer_state = BETWEEN_MENUS;
X	    draw_menu(disp_num);          /*retract the old menu*/
X
X            disp_info[disp_num].current_menu = menu_num-1;
X            disp_info[disp_num].pointer_state = IN_MENU;
X	    disp_info[disp_num].menu[menu_num].item_selected = 0;
X	    draw_menu(disp_num);          /*draw the menus with this new info*/
X	}
X        else if ((win_x>(MENU_ITEM_WIDTH+1)) && (menu_num!=(NUM_OF_MENUS-1))) 
X	{   /*move to the right one menu*/
X            disp_info[disp_num].pointer_state = BETWEEN_MENUS;
X	    draw_menu(disp_num);          /*retract the old menu*/
X
X            disp_info[disp_num].current_menu = menu_num + 1;
X            disp_info[disp_num].pointer_state = IN_MENU;
X	    disp_info[disp_num].menu[menu_num].item_selected = 0;
X	    draw_menu(disp_num);          /*draw the menus with this new info*/
X	}
X    }
X}
X
X
X/*
X * block_until_input - this function blocks using a "select" until someone
X *             inputs on one of the windows involved with the "wscrawling" 
X *             session.  this function returns nothing.  the rest of the 
X *             program looks at the input queues to decide whether or not
X *             to scrawl and on which windows.
X */
Xblock_until_input()
X{
X    int i, read_mask, top_con_num;
X    struct timeval timeout;
X
X    timeout.tv_sec = 5;
X    timeout.tv_usec = 0;
X
X    for (i = read_mask = top_con_num = 0; i<num_of_disps; i++)
X    {
X        if (disp_info[i].in_session_bool == TRUE)
X	{
X            if (XPending(disp_info[i].disp))
X	        return(1); /*an event is pending on live display; don't block*/
X
X            read_mask |= 1 << disp_info[i].connection_num;
X            if (disp_info[i].connection_num > top_con_num)
X            top_con_num = disp_info[i].connection_num;
X	}
X    }
X
X    select(top_con_num+1, &read_mask, (int *) 0, (int *) 0, &timeout);
X    return(1);      /*either an event has occured, or a timeout*/
X}
X
X
X/*
X * process_event - this function takes an event off the event queue and
X *             calls the appropriate routine to handle this type of event.
X */
Xprocess_event(disp_num, num_people_drawing)
Xint disp_num;
Xint *num_people_drawing;
X{
X    XEvent the_event;
X    
X    if (XPending(disp_info[disp_num].disp))
X    {
X        XNextEvent(disp_info[disp_num].disp, &the_event);
X        switch (the_event.type)
X	{
X	    case ButtonPress:
X		handle_ButtonPress_event(&the_event, disp_num, 
X					 num_people_drawing);
X		break;
X	    case ButtonRelease:
X		handle_ButtonRelease_event(&the_event, disp_num, 
X					   num_people_drawing);
X		break;
X	    case KeyPress:
X		handle_KeyPress_event(&the_event, disp_num);
X		break;
X	    case Expose:
X		handle_Expose_event(&the_event, disp_num);
X		break;
X	    case ConfigureNotify:
X		handle_ConfigureNotify_event(&the_event, disp_num);
X		break;
X	    case ClientMessage:
X		handle_ClientMessage_event(&the_event, disp_num);
X		break;
X	    case SelectionNotify:
X		handle_SelectionNotify_event(&the_event, disp_num);
X		break;
X	    default:
X		break;
X	}
X    }
X}
X
X
X/*
X * handle_ButtonPress_event - this function handles a ButtonPress event in
X *                   this particular scrawler's window.  It is probably a
X *                   scrawler starting to draw, but it could be a menu selection
X *                   so that is checked for also.
X */
Xhandle_ButtonPress_event(our_event, disp_num, num_people_drawing)
XXEvent *our_event;
Xint disp_num, *num_people_drawing;
X{
X    XButtonPressedEvent *the_event;
X    int menu_num, i;
X
X    the_event = (XButtonPressedEvent *) our_event;
X
X    if (disp_info[disp_num].scrawl_mode == RESPONDING_TO_DIALOG)
X	return(0);	/*not allowed to do anything else*/
X
X    if (the_event->button == Button1)
X    {
X	if (the_event->window == disp_info[disp_num].win_id)
X	{
X            if (NOTHING_DRAWN_YET == TRUE)   /*global variable*/
X                NOTHING_DRAWN_YET = FALSE;
X		
X            disp_info[disp_num].first_point_bool = TRUE; 
X
X	    switch(disp_info[disp_num].scrawl_mode)
X	    {
X		case PLACING_A_BITMAP:
X	            place_a_bitmap(disp_num, the_event);
X		    disp_info[disp_num].just_placed_something_bool = TRUE;
X		    break;
X		case PLACING_AN_IMAGE:
X	            place_an_image(disp_num, the_event);
X		    disp_info[disp_num].just_placed_something_bool = TRUE;
X		    break;
X		case PLACING_A_TEXTFILE:
X	            place_a_textfile(disp_num, the_event);
X		    disp_info[disp_num].just_placed_something_bool = TRUE;
X		    break;
X	        case TYPING:
X                    disp_info[disp_num].pointer_state = NOT_PRESSED;
X		    break;
X		default:
X                    disp_info[disp_num].pointer_state = PRESSED;
X		    break;
X            }
X
X	    if (disp_info[disp_num].scrawl_mode == ERASING)
X	    {
X		if (disp_info[disp_num].pen_width - 4 > 0)
X		{
X                    XMoveResizeWindow(disp_info[disp_num].disp, 
X			 disp_info[disp_num].eraser_win_id, 
X			 the_event->x - disp_info[disp_num].pen_width/2, 
X			 the_event->y - disp_info[disp_num].pen_width/2,
X			 disp_info[disp_num].pen_width - 4,
X			 disp_info[disp_num].pen_width - 4);
X		}
X		else
X		{
X                    XMoveResizeWindow(disp_info[disp_num].disp, 
X			 disp_info[disp_num].eraser_win_id, 
X			 the_event->x - disp_info[disp_num].pen_width/2, 
X			 the_event->y - disp_info[disp_num].pen_width/2,
X			 1, 1);
X		}
X                XMapWindow(disp_info[disp_num].disp, 
X		       disp_info[disp_num].eraser_win_id);
X            }
X
X	    if (disp_info[disp_num].cursor_on == TRUE) /*erase the cursor*/
X	    {
X         	XDrawLine(disp_info[disp_num].disp, 
X		  disp_info[disp_num].win_id,
X		  disp_info[disp_num].cursor_gc, 
X		  disp_info[disp_num].cur_pos.x, 
X		  disp_info[disp_num].cur_pos.y, 
X		  disp_info[disp_num].cur_pos.x + 
X		  disp_info[disp_num].prompt_width, 
X		  disp_info[disp_num].cur_pos.y);
X            }
X
X	    if (disp_info[disp_num].scrawl_mode != TYPING)
END_OF_FILE
if test 35046 -ne `wc -c <'wscrawl/xaa'`; then
    echo shar: \"'wscrawl/xaa'\" unpacked with wrong size!
fi
# end of 'wscrawl/xaa'
fi
echo shar: End of archive 4 \(of 5\).
cp /dev/null ark4isdone
MISSING=""
for I in 1 2 3 4 5 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 5 archives.
    rm -f ark[1-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0
dan
----------------------------------------------------
O'Reilly && Associates   argv at sun.com / argv at ora.com
Opinions expressed reflect those of the author only.



More information about the Comp.sources.x mailing list