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