//*********************************************************************************** //Student Name: Lawrence Salacup //Instructor: Dr. Wahab //Class: CS 476 - Systems Programming //Description: gDraw is a program that allows 2 or more people to collaborate over //a white board. //To execute: gDraw ... //*********************************************************************************** #include #include #include #include #include #include #include #define MAX_USERS 5 #define MAX_LABEL 30 #define BUTTON_HEIGHT 25 #define BUTTON_WIDTH 150 #define BUTTON_INPUTMASK ExposureMask | EnterWindowMask | LeaveWindowMask | ButtonPressMask | ButtonReleaseMask #define BUTTON_COUNT 3 #define LABEL_FREE "FREE" #define LABEL_CLEAR "CLEAR" #define LABEL_QUIT "QUIT" #define BLACK "black" #define WHITE "white" #define GREEN "green" #define YELLOW "yellow" #define RED "red" #define BUFFERSIZE 20 #define MAX(A,B) ((A) > (B) ? (A) : (B)) #define BEGINPOSITIONX 400 #define BEGINPOSITIONY 15 typedef struct { int x; int y; char buttonLabel[MAX_LABEL]; Window buttonWindow; GC draw; XGCValues gcval; long busyColor, freeColor, floorColor; } menuButton; void CreateButton(int displayNumber,int buttonNumber); void UpdateButtonLabel(int displayNumber,int buttonNumber); void CheckButtonEvents(int currentWindow, int noOfDisplays, char *userName); void PutChar(char buffer[],int displayNumber,int noOfDisplays); void DelChar(char buffer[],int displayNumber,int noOfDisplays); void NewLine( int displayNumber ); void BackLine( int displayNumber ); int intLen(int someNum); char digitToChar(int digit); int addIntToStr(char *dest,int value); int placeDigit(int value,int place,int *returnInt); int powerTen(int value); //global variables Display *display[MAX_USERS]; Window root[MAX_USERS], mainWindow[MAX_USERS]; Window drawWindow[MAX_USERS], buttonContainerWindow[MAX_USERS]; int screen; XGCValues gcval[MAX_USERS], eraseGCVAL[MAX_USERS]; GC draw[MAX_USERS], erase[MAX_USERS]; XGCValues BCgcval[MAX_USERS], BCeraseGCVAL[MAX_USERS]; GC BCdraw[MAX_USERS], BCerase[MAX_USERS]; //GC drawButton[MAX_USERS]; int lockStatus[MAX_USERS]; int lockFree; menuButton theButtons[MAX_USERS][BUTTON_COUNT]; //not sure how to update draw window after an expose //I imagine these have something to do with it???? XSetWindowAttributes bsetwinattr[MAX_USERS][BUTTON_COUNT]; XSetWindowAttributes setwinattr[MAX_USERS]; XWindowAttributes winattr; Font theFonts[MAX_USERS]; XFontStruct *theFontsStruc[MAX_USERS]; int validWindows[MAX_USERS]; int validWindowCount; XEvent event; XColor apparant, exact; int currentX, currentY, oldX, oldY; int drawChalk, eraseChalk; int onButton[MAX_USERS][BUTTON_COUNT]; //variables needed for typing char buffer[BUFFERSIZE]; int bufsize=BUFFERSIZE; KeySym keysym; long statinout; int charcount; //monitor when cursor for text needs to be reverted int wasTyping; int ignoreLastMove; //holds the current pointer label char pointerLabel[MAX_LABEL]; main(argc,argv) int argc; char **argv; { int loopCount; int anotherLoopCounter; int noOfDisplays = argc - 1; int eventmask = KeyPressMask|ExposureMask|ButtonPressMask|ButtonMotionMask|ButtonReleaseMask|PointerMotionMask |LeaveWindowMask|EnterWindowMask; long fgcolor, bgcolor; int currentStringLength; //, pointx[MAXUSERS], pointy[MAXUSERS]; int currentWindow, currentButton; char * atPointer; //initially no typing wasTyping = 0; ignoreLastMove; //set lock on screen to free lockFree = 1; //initially set drawingto false drawChalk = 0; eraseChalk = 0; //initially set the last x and y to zero //so the pointerLabel routine will not have a zero on //the first Motion Notify oldX = 0; oldY = 0; //insure noOfDisplays does not go beyond MAX_USERS if ( noOfDisplays >= MAX_USERS ) { printf("gDraw can handle a maximum of %d users.\n",MAX_USERS); printf("Please adjust the number of users and rerun the program!\n"); exit(1); } for (loopCount=0; loopCount < MAX_USERS; loopCount++) validWindows[loopCount] = 0; validWindowCount = 0; for (loopCount=0; loopCount< noOfDisplays; loopCount++) { atPointer = argv[loopCount+1]; currentStringLength = strlen( argv[loopCount+1] ); while( *atPointer != '@' ) { if ( (atPointer == '\0') || (currentStringLength <= 0) ) { printf("The command option %s is a malformed syntax!\n",argv[loopCount+1]); printf("Format is user@host\n"); exit(1); } atPointer++; currentStringLength--; } atPointer++; printf("Opening screen %s\n",atPointer); if ( !(display[loopCount] = XOpenDisplay( atPointer ) ) ) { printf("Could not open display %s\n",atPointer); exit(1); } //will keep track of windows that have not been destroyed validWindows[loopCount] = 1; validWindowCount++; } //printf("All displays were successfully opened.\n"); //now clear all locks on screen for (loopCount=0; loopCount < noOfDisplays; loopCount++) lockStatus[loopCount] = 0; for (loopCount=0; loopCount< noOfDisplays; loopCount++) { //printf("Creating screen objects for %s\n",argv[loopCount+1]); setwinattr[loopCount].backing_store = Always; screen = DefaultScreen(display[loopCount]); root[loopCount] = RootWindow(display[loopCount],screen); XAllocNamedColor(display[loopCount], DefaultColormap(display[loopCount],screen), BLACK,&apparant,&exact); fgcolor = apparant.pixel; XAllocNamedColor(display[loopCount], DefaultColormap(display[loopCount],screen), WHITE,&apparant,&exact); bgcolor = apparant.pixel; mainWindow[loopCount] = XCreateSimpleWindow(display[loopCount],root[loopCount], 0,0,600,400,0,fgcolor,bgcolor); drawWindow[loopCount] = XCreateSimpleWindow(display[loopCount], mainWindow[loopCount],0,0,596,300,2,fgcolor,bgcolor); XChangeWindowAttributes(display[loopCount], drawWindow[loopCount], CWBackingStore, &setwinattr[loopCount]); XDefineCursor( display[loopCount], drawWindow[loopCount], XCreateFontCursor( display[loopCount], XC_X_cursor)); buttonContainerWindow[loopCount] = XCreateSimpleWindow(display[loopCount], mainWindow[loopCount],0,302,596,94,2,fgcolor,bgcolor); //create for draw window gcval[loopCount].foreground = fgcolor; gcval[loopCount].background = bgcolor; gcval[loopCount].line_width = 2; gcval[loopCount].cap_style = CapRound; gcval[loopCount].join_style = JoinRound; draw[loopCount] = XCreateGC(display[loopCount],drawWindow[loopCount], GCForeground|GCBackground|GCLineWidth|GCCapStyle|GCJoinStyle, &gcval[loopCount]); eraseGCVAL[loopCount].foreground = bgcolor; eraseGCVAL[loopCount].background = fgcolor; eraseGCVAL[loopCount].line_width = 2; eraseGCVAL[loopCount].cap_style = CapRound; eraseGCVAL[loopCount].join_style = JoinRound; erase[loopCount] = XCreateGC(display[loopCount],drawWindow[loopCount], GCForeground|GCBackground|GCLineWidth|GCCapStyle|GCJoinStyle, &eraseGCVAL[loopCount]); //create for buttonContainer Window BCgcval[loopCount].foreground = fgcolor; BCgcval[loopCount].background = bgcolor; BCgcval[loopCount].line_width = 2; BCgcval[loopCount].cap_style = CapRound; BCgcval[loopCount].join_style = JoinRound; BCdraw[loopCount] = XCreateGC(display[loopCount],buttonContainerWindow[loopCount], GCForeground|GCBackground|GCLineWidth|GCCapStyle|GCJoinStyle, &BCgcval[loopCount]); BCeraseGCVAL[loopCount].foreground = bgcolor; BCeraseGCVAL[loopCount].background = fgcolor; BCeraseGCVAL[loopCount].line_width = 2; BCeraseGCVAL[loopCount].cap_style = CapRound; BCeraseGCVAL[loopCount].join_style = JoinRound; BCerase[loopCount] = XCreateGC(display[loopCount],buttonContainerWindow[loopCount], GCForeground|GCBackground|GCLineWidth|GCCapStyle|GCJoinStyle, &BCeraseGCVAL[loopCount]); //printf("Before Font Load\n"); theFonts[loopCount] = XLoadFont(display[loopCount],"9x15"); theFontsStruc[loopCount] = XQueryFont(display[loopCount],theFonts[loopCount]); //printf("The charWidth = %d\n",theFontsStruc[loopCount]->max_bounds.width); //printf("After Font Load\n"); XStoreName(display[loopCount],mainWindow[loopCount],"gDraw"); //printf("Creating FREE button for display %s\n", argv[loopCount+1]); XAllocNamedColor(display[loopCount], DefaultColormap(display[loopCount],screen), RED,&apparant,&exact); theButtons[loopCount][0].busyColor = apparant.pixel; XAllocNamedColor(display[loopCount], DefaultColormap(display[loopCount],screen), YELLOW,&apparant,&exact); theButtons[loopCount][0].freeColor = apparant.pixel; XAllocNamedColor(display[loopCount], DefaultColormap(display[loopCount],screen), GREEN,&apparant,&exact); theButtons[loopCount][0].floorColor = apparant.pixel; theButtons[loopCount][0].x = 50; theButtons[loopCount][0].y = 35; strcpy( &theButtons[loopCount][0].buttonLabel[0], LABEL_FREE ); CreateButton(loopCount,0); XSetWindowBackground( display[loopCount], theButtons[loopCount][0].buttonWindow, theButtons[loopCount][0].freeColor); UpdateButtonLabel(loopCount,0); XDefineCursor( display[loopCount], theButtons[loopCount][0].buttonWindow, XCreateFontCursor( display[loopCount], XC_hand1)); //printf("Created FREE button for display %s\n", argv[loopCount+1]); //printf("Creating CLEAR button for display %s\n", argv[loopCount+1]); theButtons[loopCount][1].x = 225; theButtons[loopCount][1].y = 35; strcpy( &theButtons[loopCount][1].buttonLabel[0], LABEL_CLEAR ); CreateButton(loopCount,1); UpdateButtonLabel(loopCount,1); XDefineCursor( display[loopCount], theButtons[loopCount][1].buttonWindow, XCreateFontCursor( display[loopCount], XC_hand1)); //printf("Created CLEAR button for display %s\n", argv[loopCount+1]); //printf("Creating QUIT button for display %s\n", argv[loopCount+1]); theButtons[loopCount][2].x = 400; theButtons[loopCount][2].y = 35; strcpy( &theButtons[loopCount][2].buttonLabel[0], LABEL_QUIT ); CreateButton(loopCount,2); UpdateButtonLabel(loopCount,2); XDefineCursor( display[loopCount], theButtons[loopCount][2].buttonWindow, XCreateFontCursor( display[loopCount], XC_hand1)); //printf("Created QUIT button for display %s\n", argv[loopCount+1]); XMapWindow(display[loopCount],mainWindow[loopCount]); XMapWindow(display[loopCount],drawWindow[loopCount]); XMapWindow(display[loopCount],buttonContainerWindow[loopCount]); XFlush(display[loopCount]); XSelectInput(display[loopCount],drawWindow[loopCount],eventmask); } //printf("All objects were created successfully!\n"); for (;;) { //first switch through displays //then check all buttons for(currentWindow = 0;currentWindow < noOfDisplays; currentWindow++) { if( validWindows[currentWindow] ) { if (XCheckWindowEvent(display[currentWindow],drawWindow[currentWindow],eventmask,&event)) { switch (event.type) { case Expose: for (loopCount=0;loopCount < noOfDisplays; loopCount++) if ( validWindows[loopCount] ) XFlush(display[loopCount]); break; case ButtonPress: if ( lockStatus[currentWindow] && !wasTyping) { /* strcpy(pointerLabel,"Position: ("); addIntToStr(pointerLabel,oldX); strcat(pointerLabel,","); addIntToStr(pointerLabel,oldY); strcat(pointerLabel,")"); XSetFont(display[currentWindow], BCerase[currentWindow],theFonts[currentWindow]); XDrawString(display[currentWindow], buttonContainerWindow[currentWindow], BCerase[currentWindow],BEGINPOSITIONX, BEGINPOSITIONY, pointerLabel,strlen(pointerLabel)); XFlush(display[currentWindow]); //printf("Masking %s\n",pointerLabel);*/ oldX = event.xbutton.x; oldY = event.xbutton.y; if ( event.xbutton.button == Button1 ) drawChalk = 1; else eraseChalk = 1; //printf("Valid Button Press in Draw Window on display %d\n",currentWindow); } else { //printf("Invalid Button Press in Draw Window on display %d\n",currentWindow); } break; case ButtonRelease: if ( lockStatus[currentWindow] ) { drawChalk = 0; eraseChalk = 0; } break; case KeyPress: if ( lockStatus[currentWindow] ) { if( lockStatus[currentWindow] && (!(drawChalk || eraseChalk)) && !wasTyping) { strcpy(pointerLabel,"Position: ("); addIntToStr(pointerLabel,oldX); strcat(pointerLabel,","); addIntToStr(pointerLabel,oldY); strcat(pointerLabel,")"); XSetFont(display[currentWindow], BCerase[currentWindow],theFonts[currentWindow]); XDrawString(display[currentWindow], buttonContainerWindow[currentWindow], BCerase[currentWindow],BEGINPOSITIONX,BEGINPOSITIONY, pointerLabel,strlen(pointerLabel)); XFlush(display[currentWindow]); } if ( !wasTyping ) { wasTyping = 1; XDefineCursor( display[currentWindow], drawWindow[currentWindow], XCreateFontCursor( display[currentWindow], XC_gumby)); } charcount = XLookupString(&event,buffer,bufsize, &keysym, &statinout); buffer[charcount]='\0'; //printf("On display %d, %s was typed.\n",currentWindow,buffer); if (keysym >= XK_space && keysym <= XK_asciitilde) { //printf("Valid Key was hit!\n"); //printf("Current Window: %d\n",currentWindow); PutChar(buffer,currentWindow,noOfDisplays); } else if (keysym == XK_BackSpace || keysym ==XK_Delete) DelChar(buffer,currentWindow,noOfDisplays); else if (keysym == XK_Return) NewLine(currentWindow); } break; case LeaveNotify: if( lockStatus[currentWindow] && (!(drawChalk || eraseChalk)) && !wasTyping) { strcpy(pointerLabel,"Position: ("); addIntToStr(pointerLabel,oldX); strcat(pointerLabel,","); addIntToStr(pointerLabel,oldY); strcat(pointerLabel,")"); XSetFont(display[currentWindow], BCerase[currentWindow],theFonts[currentWindow]); XDrawString(display[currentWindow], buttonContainerWindow[currentWindow], BCerase[currentWindow],BEGINPOSITIONX,BEGINPOSITIONY, pointerLabel,strlen(pointerLabel)); XFlush(display[currentWindow]); } break; case EnterNotify: if( lockStatus[currentWindow] && (!(drawChalk || eraseChalk)) && !wasTyping) { strcpy(pointerLabel,"Position: ("); addIntToStr(pointerLabel,currentX); strcat(pointerLabel,","); addIntToStr(pointerLabel,currentY); strcat(pointerLabel,")"); XSetFont(display[currentWindow], BCdraw[currentWindow],theFonts[currentWindow]); XDrawString(display[currentWindow], buttonContainerWindow[currentWindow], BCdraw[currentWindow],BEGINPOSITIONX,BEGINPOSITIONY, pointerLabel,strlen(pointerLabel)); XFlush(display[currentWindow]); //printf("Updating %s\n",pointerLabel); } break; case MotionNotify: //printf("Moving\n"); currentX=event.xmotion.x; currentY=event.xmotion.y; //if( lockStatus[currentWindow] && (!(drawChalk || eraseChalk)) && !wasTyping) if( lockStatus[currentWindow] && !wasTyping) { strcpy(pointerLabel,"Position: ("); addIntToStr(pointerLabel,oldX); strcat(pointerLabel,","); addIntToStr(pointerLabel,oldY); strcat(pointerLabel,")"); XSetFont(display[currentWindow], BCerase[currentWindow],theFonts[currentWindow]); XDrawString(display[currentWindow], buttonContainerWindow[currentWindow], BCerase[currentWindow],BEGINPOSITIONX,BEGINPOSITIONY, pointerLabel,strlen(pointerLabel)); XFlush(display[currentWindow]); //printf("Masking %s\n",pointerLabel); strcpy(pointerLabel,"Position: ("); addIntToStr(pointerLabel,currentX); strcat(pointerLabel,","); addIntToStr(pointerLabel,currentY); strcat(pointerLabel,")"); XSetFont(display[currentWindow], BCdraw[currentWindow],theFonts[currentWindow]); XDrawString(display[currentWindow], buttonContainerWindow[currentWindow], BCdraw[currentWindow],BEGINPOSITIONX,BEGINPOSITIONY, pointerLabel, strlen(pointerLabel)); XFlush(display[currentWindow]); //printf("Updating %s\n",pointerLabel); } //reset so future cursors will be updated if ( wasTyping && !ignoreLastMove) { wasTyping = 0; //printf("Reseting cursor\n"); XDefineCursor( display[currentWindow], drawWindow[currentWindow], XCreateFontCursor( display[currentWindow], XC_crosshair)); XFlush(display[currentWindow]); } else ignoreLastMove = 0; if( lockStatus[currentWindow] && (drawChalk || eraseChalk)) { for (loopCount=0;loopCount < noOfDisplays; loopCount++) { if ( drawChalk ) { if ( validWindows[loopCount] ) { XDrawLine(display[loopCount], drawWindow[loopCount], draw[loopCount],oldX,oldY, currentX, currentY); } } else { if ( validWindows[loopCount] ) { XDrawLine(display[loopCount], drawWindow[loopCount], erase[loopCount],oldX,oldY, currentX, currentY); } } } //oldX=currentX; //oldY=currentY; for (loopCount=0;loopCount < noOfDisplays; loopCount++) if ( validWindows[loopCount] ) XFlush(display[loopCount]); } oldX=currentX; oldY=currentY; break; default: fprintf(stderr,"Unexpected event: %d Display: %d\n", event.type,currentWindow); } } //if (XCheckWindowEvent(display[currentWindow],drawWindow[currentWindow],eventmask,&event)) //now test for any events by buttons on the current display CheckButtonEvents(currentWindow,noOfDisplays,argv[currentWindow+1]); } //if( validWindows[currentWindow] ) //else // printf("Window %d is an invalid window!\n",currentWindow); } //for(currentWindow = 0;currentWindow < noOfDisplays; currentWindow++) } //for (;;) return 0; } //****************************************************************************************** //Function: CreateButton() //Parameters: displayNumber - display to create button // buttonNumber - number to reference the buttons array //Returns: none //Description: This function creates a window to be used as a button. //****************************************************************************************** void CreateButton(int displayNumber,int buttonNumber) { long fgcolor, bgcolor; //printf("Creating button %d for display %d\n",buttonNumber,displayNumber); bsetwinattr[displayNumber][buttonNumber].backing_store = Always; fgcolor = BlackPixel(display[displayNumber],DefaultScreen(display[displayNumber])); bgcolor = WhitePixel(display[displayNumber],DefaultScreen(display[displayNumber])); theButtons[displayNumber][buttonNumber].buttonWindow = XCreateSimpleWindow( display[displayNumber], buttonContainerWindow[displayNumber], theButtons[displayNumber][buttonNumber].x,theButtons[displayNumber][buttonNumber].y, BUTTON_WIDTH, BUTTON_HEIGHT, 2, fgcolor, bgcolor); theButtons[displayNumber][buttonNumber].gcval.foreground = fgcolor; theButtons[displayNumber][buttonNumber].gcval.background = bgcolor; theButtons[displayNumber][buttonNumber].draw = XCreateGC(display[displayNumber], theButtons[displayNumber][buttonNumber].buttonWindow,GCForeground|GCBackground, &theButtons[displayNumber][buttonNumber].gcval); XSelectInput(display[displayNumber], theButtons[displayNumber][buttonNumber].buttonWindow, BUTTON_INPUTMASK ); XChangeWindowAttributes(display[displayNumber], theButtons[displayNumber][buttonNumber].buttonWindow, CWBackingStore, &bsetwinattr[displayNumber][buttonNumber]); XMapWindow( display[displayNumber], theButtons[displayNumber][buttonNumber].buttonWindow ); } //****************************************************************************************** //Function: UpdateButtonLabel() //Parameters: displayNumber - display to update // buttonNumber - number to reference the buttons array //Returns: none //Description: This function redraws a button label. //****************************************************************************************** void UpdateButtonLabel(int displayNumber,int buttonNumber) { int ascent; int descent; int fontWidth; int width; int center; ascent = theFontsStruc[displayNumber]->max_bounds.ascent; descent = theFontsStruc[displayNumber]->max_bounds.descent; fontWidth = theFontsStruc[displayNumber]->max_bounds.width; width = strlen(&theButtons[displayNumber][buttonNumber].buttonLabel[0])*fontWidth; center = MAX((BUTTON_WIDTH-width)/2,4); XSetFont(display[displayNumber], theButtons[displayNumber][buttonNumber].draw,theFonts[displayNumber]); //first clear all text on the button so the new text will be legible XClearWindow(display[displayNumber],theButtons[displayNumber][buttonNumber].buttonWindow); XFlush(display[displayNumber]); XDrawString(display[displayNumber],theButtons[displayNumber][buttonNumber].buttonWindow, theButtons[displayNumber][buttonNumber].draw,center,((BUTTON_HEIGHT/2) + ((ascent+descent)/2)), &theButtons[displayNumber][buttonNumber].buttonLabel[0], strlen(&theButtons[displayNumber][buttonNumber].buttonLabel[0])); } //****************************************************************************************** //Function: CheckButtonEvents() //Parameters: currentWindow - display to check for events // noOfDisplays - total number of displays // userName - person owning this display //Returns: none //Description: This function probes for button events on a particular display. //If any exist, it performs a particular action. //****************************************************************************************** void CheckButtonEvents(int currentWindow, int noOfDisplays, char *userName) { int currentButton, loopCount; for(currentButton = 0;currentButton < BUTTON_COUNT; currentButton++) { if (XCheckWindowEvent(display[currentWindow], theButtons[currentWindow][currentButton].buttonWindow, BUTTON_INPUTMASK,&event)) { switch( event.type ) { case Expose: UpdateButtonLabel(currentWindow,currentButton); //printf("Button Expose on display %d\n",currentWindow); break; case EnterNotify: onButton[currentWindow][currentButton] = 1; XDrawRectangle( display[currentWindow], theButtons[currentWindow][currentButton].buttonWindow, theButtons[currentWindow][currentButton].draw, 1,1, BUTTON_WIDTH-3, BUTTON_HEIGHT-3 ); //printf("Button Enter Notify on display %d\n",currentWindow); break; case LeaveNotify: onButton[currentWindow][currentButton] = 0; UpdateButtonLabel(currentWindow,currentButton); //printf("Button Leave Notify on display %d\n",currentWindow); break; case ButtonPress: if ( lockFree || lockStatus[currentWindow] || (currentButton == 2)) { if (!(( currentButton == 1 ) && !lockStatus[currentWindow])) { XDrawRectangle( display[currentWindow], theButtons[currentWindow][currentButton].buttonWindow, theButtons[currentWindow][currentButton].draw, 0,0, BUTTON_WIDTH-1, BUTTON_HEIGHT-1 ); } } //printf("Button Press on display %d\n",currentWindow); break; case ButtonRelease: UpdateButtonLabel(currentWindow,currentButton); XDrawRectangle( display[currentWindow], theButtons[currentWindow][currentButton].buttonWindow, theButtons[currentWindow][currentButton].draw, 1,1, BUTTON_WIDTH-3, BUTTON_HEIGHT-3 ); if( (currentButton == 0) && onButton[currentWindow][currentButton] ) { if ( lockFree ) { lockFree = 0; wasTyping = 0; for (loopCount=0; loopCount< noOfDisplays; loopCount++) { if ( validWindows[loopCount] ) { if ( loopCount != currentWindow) { XSetWindowBackground( display[loopCount], theButtons[loopCount][currentButton].buttonWindow, theButtons[loopCount][currentButton].busyColor); XDefineCursor( display[loopCount], drawWindow[loopCount], XCreateFontCursor( display[loopCount], XC_X_cursor)); } else { XDefineCursor( display[loopCount], drawWindow[loopCount], XCreateFontCursor( display[loopCount], XC_crosshair)); XGrabButton(display[loopCount], AnyButton, AnyModifier, drawWindow[loopCount], 1, ButtonPressMask | ButtonMotionMask | ButtonReleaseMask, GrabModeAsync, GrabModeAsync, drawWindow[loopCount], XCreateFontCursor(display[loopCount], XC_pencil)); XSetWindowBackground( display[loopCount], theButtons[loopCount][currentButton].buttonWindow, theButtons[loopCount][currentButton].floorColor); } strcpy( &theButtons[loopCount][currentButton].buttonLabel[0], userName ); UpdateButtonLabel(loopCount,currentButton); } } lockStatus[currentWindow] = 1; } else if ( ( !lockFree ) && lockStatus[currentWindow] ) { lockFree = 1; lockStatus[currentWindow] = 0; for (loopCount=0; loopCount< noOfDisplays; loopCount++) { if ( validWindows[loopCount] ) { XDefineCursor( display[loopCount], drawWindow[loopCount], XCreateFontCursor( display[loopCount], XC_X_cursor)); XSetWindowBackground( display[loopCount], theButtons[loopCount][currentButton].buttonWindow, theButtons[loopCount][currentButton].freeColor); strcpy( &theButtons[loopCount][currentButton].buttonLabel[0], LABEL_FREE ); UpdateButtonLabel(loopCount,currentButton); } } XUngrabButton(display[currentWindow], AnyButton, AnyModifier, drawWindow[currentWindow]); } } else if ( (currentButton == 1) && onButton[currentWindow][currentButton] ) { if ( lockStatus[currentWindow] ) { for (loopCount=0; loopCount< noOfDisplays; loopCount++) { if ( validWindows[loopCount] ) { XClearWindow(display[loopCount],drawWindow[loopCount]); XFlush(display[loopCount]); } } //clear the window } } else if ( (currentButton == 2) && onButton[currentWindow][currentButton] ) { XUnmapSubwindows(display[currentWindow],mainWindow[currentWindow]); XUnmapWindow(display[currentWindow],mainWindow[currentWindow]); for(loopCount=0;loopCount < BUTTON_COUNT;loopCount++) { //printf("Destroying button %d on display %d\n",loopCount,currentWindow); XDestroyWindow(display[currentWindow], theButtons[currentWindow][loopCount].buttonWindow); } //printf("Destroying buttonContainerWindow on display %d\n",currentWindow); XDestroyWindow(display[currentWindow], buttonContainerWindow[currentWindow]); //printf("Destroying drawWindow on display %d\n",currentWindow); XDestroyWindow(display[currentWindow], drawWindow[currentWindow]); //printf("Destroying mainWindow on display %d\n",currentWindow); XDestroyWindow(display[currentWindow], mainWindow[currentWindow]); //printf("All windows destroyed on display %d\n",currentWindow); //should also deallocate fonts and colors here!!!!!! printf("User %s has quit gDraw!\n",userName); validWindows[currentWindow] = 0; validWindowCount--; if( validWindowCount == 0 ) { printf("All users have quit gDraw!\n"); printf("Shuting Down!\n"); exit(0); } if ( ( !lockFree ) && lockStatus[currentWindow] ) { lockFree = 1; lockStatus[currentWindow] = 0; for (loopCount=0; loopCount< noOfDisplays; loopCount++) { if ( validWindows[loopCount] ) { XSetWindowBackground( display[loopCount], theButtons[loopCount][0].buttonWindow, theButtons[loopCount][0].freeColor); strcpy( &theButtons[loopCount][0].buttonLabel[0], LABEL_FREE ); UpdateButtonLabel(loopCount,0); } } } XFlush(display[currentWindow]); } //printf("Button Release on display %d\n",currentWindow); break; default: fprintf(stderr,"Unexpected Button event: %d Display: %d\n", event.type,currentWindow); break; } //switch( event.type ) } // if (XCheckWindowEvent(display[currentWindow], // theButtons[currentWindow][currentButton].buttonWindow, // BUTTON_INPUTMASK,&event)) } //for(currentButton = 0;currentButton < BUTTON_COUNT; currentButton++) } //****************************************************************************************** //Function: PutChar() //Parameters: buffer - stores character to write to screen // displayNumber - display to write the character // noOfDisplays - total number of displays //Returns: none //Description: This function sends a character to all displays running the //whiteboard. //****************************************************************************************** void PutChar(char buffer[],int displayNumber,int noOfDisplays) { int winx, winy; int rwinx, rwiny; unsigned int maskret; Window rootret, childret; int j; int loopCount; int width; int ascent; int descent; ignoreLastMove = 1; width = theFontsStruc[displayNumber]->max_bounds.width; ascent = theFontsStruc[displayNumber]->max_bounds.ascent; descent = theFontsStruc[displayNumber]->max_bounds.descent; XQueryPointer(display[displayNumber], drawWindow[displayNumber], &rootret, &childret, &rwinx, &rwiny, &winx, &winy, &maskret); //printf("In drawWindow, x = %d y = %d\n",winx,winy); //supply enough room so characters do not run off window //printf("Coordinates winx=%d winy=%d\n",winx,winy); if ((winx >= (600 - width*2)) && (winy < (300 - (ascent+descent))) && (winy >= (ascent+descent))) { //printf("Processing a New Line"); NewLine(displayNumber); XQueryPointer(display[displayNumber], drawWindow[displayNumber], &rootret, &childret, &rwinx, &rwiny, &winx, &winy, &maskret); //printf("Coordinates winx=%d winy=%d\n",winx,winy); } if ((winx >= (600 - width*2)) || (winy < (ascent+descent))) { XBell(display[displayNumber],0); //printf("LocationError\n"); return; } //printf("set font successfully\n"); for(loopCount=0;loopCount < noOfDisplays;loopCount++) { if (validWindows[loopCount]) { XSetFont(display[loopCount], draw[loopCount],theFonts[loopCount]); XDrawString(display[loopCount],drawWindow[loopCount], draw[loopCount],winx,winy,buffer,strlen(buffer)); XFlush(display[loopCount]); } } XWarpPointer(display[displayNumber], NULL, NULL, 0,0,0,0,width,0); } //****************************************************************************************** //Function: DelChar() //Parameters: buffer - stores character to write to screen // displayNumber - display to write the character // noOfDisplays - total number of displays //Returns: none //Description: This function sends a backspace to all displays running the //whiteboard. //****************************************************************************************** void DelChar( char buffer[], int displayNumber,int noOfDisplays) { int loopCount; int winx, winy; int rwinx, rwiny; unsigned int maskret; Window rootret, childret; int j; int width; int ascent; int descent; ignoreLastMove = 1; width = theFontsStruc[displayNumber]->max_bounds.width; ascent = theFontsStruc[displayNumber]->max_bounds.ascent; descent = theFontsStruc[displayNumber]->max_bounds.descent; XQueryPointer(display[displayNumber], drawWindow[displayNumber], &rootret, &childret, &rwinx, &rwiny, &winx, &winy, &maskret); //supply enough room so characters do not run off window if ((winx < width*2) || (winy < (ascent+descent))) { if (winx < width*2) BackLine(displayNumber); XBell(display[displayNumber],0); //printf("LocationError\n"); return; } XWarpPointer(display[displayNumber], NULL, NULL, 0,0,0,0,-width,0); for(loopCount=0;loopCount < noOfDisplays;loopCount++) { if (validWindows[loopCount]) { //printf("Deleting character on display %d\n",loopCount); XFillRectangle(display[loopCount],drawWindow[loopCount], erase[loopCount],winx-width, winy-ascent,width, ascent+descent); XFlush(display[loopCount]); } } } //****************************************************************************************** //Function: NewLine() //Parameters: displayNumber - display to write the character //Returns: none //Description: This function sets the pointer on the current display down one line //at the beginning of the line as if enter was pressed. //****************************************************************************************** void NewLine( int displayNumber ) { int loopCount; int winx, winy; int rwinx, rwiny; unsigned int maskret; Window rootret, childret; int j; int width; int ascent; int descent; ignoreLastMove = 1; width = theFontsStruc[displayNumber]->max_bounds.width; ascent = theFontsStruc[displayNumber]->max_bounds.ascent; descent = theFontsStruc[displayNumber]->max_bounds.descent; XQueryPointer(display[displayNumber], drawWindow[displayNumber], &rootret, &childret, &rwinx, &rwiny, &winx, &winy, &maskret); //supply enough room so characters do not run off window if (winy < (ascent+descent)) { XBell(display[displayNumber],0); //printf("LocationError NewLine\n"); return; } XWarpPointer(display[displayNumber], NULL, NULL, 0,0,0,0,(width-winx),(ascent+descent)); } //****************************************************************************************** //Function: BackLine() //Parameters: displayNumber - display to write the character //Returns: none //Description: This function simulates deleting a line by moving up one line //to the end of that line. //****************************************************************************************** void BackLine( int displayNumber ) { int loopCount; int winx, winy; int rwinx, rwiny; unsigned int maskret; Window rootret, childret; int j; int width; int ascent; int descent; ignoreLastMove = 1; width = theFontsStruc[displayNumber]->max_bounds.width; ascent = theFontsStruc[displayNumber]->max_bounds.ascent; descent = theFontsStruc[displayNumber]->max_bounds.descent; XQueryPointer(display[displayNumber], drawWindow[displayNumber], &rootret, &childret, &rwinx, &rwiny, &winx, &winy, &maskret); //supply enough room so characters do not run off window if (winy < ((ascent+descent)*2)) { XBell(display[displayNumber],0); //printf("LocationError\n"); return; } XWarpPointer(display[displayNumber], NULL, NULL, 0,0,0,0,(600-width-winx),-(ascent+descent)); } //****************************************************************************************** //Function: intLen() //Parameters: someNum - a number of which to return the lengthr //Returns: length - the number of digits //Description: This function returns the number of digits in a number. //****************************************************************************************** int intLen(int someNum) { int length = 0; while( someNum != 0) { someNum = someNum / 10; length++; } return length; } //****************************************************************************************** //Function: addIntToStr() //Parameters: dest - string to which the integer will be appended // value - integer to append //Returns: return success of 1 or no success of 0 //Description: This function converts an integer into a string and then //appends it to another string. //****************************************************************************************** int addIntToStr(char *dest,int value) { char addChar[2]; int aDigit; int counter; int integerLength = intLen(value); //printf("Integer Length Initially %d\n",integerLength); addChar[1] = '\0'; for(counter = 0;counter < integerLength;counter++) { if( !placeDigit(value,(counter+1),&aDigit) ) return 0; addChar[0] = digitToChar(aDigit); //printf("Adding %s to %s\n",addChar,dest); strcat(dest,&addChar[0]); } if(value == 0) { strcat(dest,"0"); } return 1; } //****************************************************************************************** //Function: placeDigit() //Parameters: value - the integer to grab the digit // place - the digit to grab // returnInt - placeholder for returned integer //Returns: return success 1 or no success 0 //Description: This function will return a digit from an integer by taking the given //place value and returning the digit at that place. //****************************************************************************************** int placeDigit(int value,int place,int *returnInt) { int n; char testChar; int currentValue = value; int counter; if( ( place < 1 ) || ( place > intLen(value) ) ) { return 0; } //printf("Requested place: %d from number: %d\n",place,value); //897 //place 1 is 8 //place 2 is 9 //place 3 is 7 //now make the requested place the 1's value while( intLen(currentValue) != place ) currentValue = currentValue / 10; //printf("The current Value is: %d Length: %d\n",currentValue,intLen(currentValue)); counter = intLen(currentValue); while ( counter > 1 ) { //n = scanf("%c",&testChar); currentValue = currentValue - powerTen((intLen(currentValue)-1)); counter = intLen(currentValue); //printf("The current Value is: %d Length: %d\n",currentValue,intLen(currentValue)); } *returnInt = currentValue; return 1; } //****************************************************************************************** //Function: digitToChar() //Parameters: digit - digit to convert to char //Returns: returns the character equilavent //Description: This function returns the character equivalent of a digit. //****************************************************************************************** char digitToChar(int digit) { switch(digit) { case 0: return '0'; break; case 1: return '1'; break; case 2: return '2'; break; case 3: return '3'; break; case 4: return '4'; break; case 5: return '5'; break; case 6: return '6'; break; case 7: return '7'; break; case 8: return '8'; break; case 9: return '9'; break; default: //Error //happens for negative values //just return 0 return '0'; break; } } //****************************************************************************************** //Function: powerTen() //Parameters: value - takes ten to the power of this number //Returns: returnValue - returns 10^value //Description: This function returns ten to the power of the passed value. //****************************************************************************************** int powerTen(int value) { int returnValue = 1; int counter; for(counter = 0;counter < value;counter++) returnValue = 10*returnValue; return returnValue; }