brianw@hpcvlx.cv.hp.com (Brian Wilson) (07/16/90)
Submitted-by: Brian Wilson <brianw@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@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@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@cv.hp.com X * X * This program was written by Brian Wilson of Hewlett Packard Co. X * Email: brianw@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@sun.com / argv@ora.com Opinions expressed reflect those of the author only.