/* drawz.c -- an interactive drawing program for X-Windows */
/* To Compile:  cc drawz.c -o drawz -lX11 */
/* On bingsuns: cc drawz.c -o drawz -I/usr/openwin/include -lX11 */

#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/keysym.h>
#include <math.h>

void main(int argc, char** argv)
{
Display *display;
int screen;
Window win;
unsigned int width, height;
int x = 0 , y = 0;
unsigned int border_width = 4;
unsigned int display_width, display_height;
char *window_name = "Drawing Program";
char *icon_name = "Draw Pgm";
XSizeHints size_hints;
XEvent report;
GC gc;
unsigned long whitepixel;

/* Event loop variables */
int lx = 0, ly = -1;
int cx,cy,depth;
int button, gfunc = 1;
Pixmap dis_backup;
XWindowAttributes attrib;
KeySym key;
char buffer[20];
int bufsize = 20;
XComposeStatus compose;
int charcount;
int tp;

/* Request display from server */
display=XOpenDisplay("");
screen = DefaultScreen(display);
display_width = DisplayWidth(display,screen);
display_height = DisplayHeight(display,screen);

/* Creating window of width X height*/
width = display_width/2, height = display_height/2;
win = XCreateSimpleWindow(display, RootWindow(display,screen),
                x, y, width, height, border_width,
                BlackPixel(display, screen),
                WhitePixel(display, screen));

/* Set standard properties of application in relation to window */
size_hints.flags = PPosition |  PSize | PMinSize;
size_hints.x = x;
size_hints.y = y;
size_hints.width = width;
size_hints.height = height;
size_hints.min_width = 360;
size_hints.min_height = 240;
XSetStandardProperties(display, win, window_name, icon_name,
                NULL, argv, argc, &size_hints);

/* Flags that are returned if something happens to the window */
XSelectInput(display, win, ExposureMask | KeyPressMask |
                ButtonPressMask | ButtonMotionMask);

/* Load in graphics context */
gc = XCreateGC(display,win,0,0);

/* Map the newly created window to the display */
XMapWindow (display, win);

/* Create copy of screen in memory (for rubber band lines) */
XGetWindowAttributes (display, win, &attrib);

/* Create the pixmap & copy window to it */
dis_backup = XCreatePixmap( display,  win, width, height, attrib.depth);
XClearWindow (display, win);
XCopyArea(display, win, dis_backup,gc,0,0,width,height,0,0);    

/*******************************************************************/
/* All preparation for the window is done so now map the window and
   wait for an EXPOSE event to draw on it */
/*******************************************************************/
while (1)
  {
  XNextEvent(display, &report);
  switch (report.type) 
    {
    case ButtonPress:
      XCopyArea(display, win, dis_backup,gc,0,0,width,height,0,0);
      lx=report.xmotion.x;
      ly=report.xmotion.y;
      button = report.xbutton.button;
    case MotionNotify:
      switch (button)
      {
        case 1 :  /* left button press */
          XDrawLine(display, win, gc, 
                     report.xmotion.x, report.xmotion.y,lx,ly);
          lx = report.xmotion.x;
          ly = report.xmotion.y;
          break;
        case 3: /*right button press */
          XCopyArea(display, dis_backup, win,gc,0,0,width,height,0,0);
          switch (gfunc)
          {
           case 1: /* draw rubberband line */
             XDrawLine(display,win,gc,lx,ly,report.xmotion.x,
                        report.xmotion.y);
             break;
           case 2: /* draw box */
             cx = report.xmotion.x;
             cy = report.xmotion.y;
             XDrawLine(display, win, gc, lx,ly,cx,ly);
             XDrawLine(display, win, gc, lx,ly,lx,cy);
             XDrawLine(display, win, gc, cx,ly,cx,cy);
             XDrawLine(display, win, gc, cx,cy,lx,cy);
             break;
           case 3: /* fill box */
             cx = report.xmotion.x;
             cy = report.xmotion.y;
             if (cx < lx) 
               { tp=cx; cx=lx; lx=tp; }
             if (cy < ly) 
               { tp=cy; cy=ly; ly=tp; }
             cx = cx - lx;
             cy = cy - ly;
             XFillRectangle(display,win,gc,lx,ly,cx,cy);
             break;
           default:
             break;
          } /* end of gfunc switch */
           break;
        default :
          break;
      } /*end button switch */
      break;

    case Expose:
      while (XCheckTypedEvent (display, Expose, &report));
      XCopyArea (display, dis_backup, win, gc, 0,0, width, height,0,0);
      break;

    case KeyPress:
      charcount = XLookupString(&report, buffer, bufsize, &key,
                                 &compose);
      if (key == XK_F9)
      {
        XFreeGC(display, gc);
        XDestroyWindow(display, win);
        XCloseDisplay(display);
        exit (0);
      }
      else if (key == XK_l) gfunc = 1;
      else if (key == XK_f) gfunc = 3;
      else if (key == XK_b) gfunc = 2;
      else if (key == XK_F8) XClearWindow (display, win);
      else if (key == XK_F1)
       XCopyArea(display,dis_backup,win,gc,0,0,width,height,0,0);
      break;

    default:
      break;

    } /* end of report.type switch loop */

  } /* end of while */

} /* end of main */