/* Programmazione II - Helper grafico. File : xhelper.c Author : Francesco Prelz ($Author: prelz $) e-mail : "francesco.prelz@mi.infn.it" Revision history : 14-Jul-2000 Original release Description: Helper routines for drawing on simple, deaf&dumb X-windows. Their main use is to demonstrate graphics programming. They can be engineered way better but that's not my job. */ #include <stdio.h> #include <stdlib.h> #include <math.h> #include <X11/Xlib.h> #include <X11/Xutil.h> #include <X11/cursorfont.h> #ifndef FALSE #define FALSE 0 #endif #ifndef TRUE #define TRUE 1 #endif Display *XHLP_display=NULL; /* X server connection */ Screen *XHLP_screen_id; /* ID of server screen. */ int XHLP_max_windows=0; /* Max Number of defined windows */ /* Window information */ typedef struct XHLP_winfo_t { Window window; /* Window */ GC gc; /* Graphic Context */ } XHLP_winfo; XHLP_winfo **XHLP_window_handles=NULL; /* Window handle array */ /* Amount of pixels to "stagger" the initial position of windows */ #define XHLP_INITIAL_OPEN_STEP 20 #define XHLP_check_window_status() \ /* Is the display open ? */ \ if (XHLP_display == NULL) return(-1); \ /* Is this window a good one ? */ \ if (cur_h < 0 || cur_h >= XHLP_max_windows) return(-1); \ if (XHLP_window_handles[cur_h] == NULL) return(-1); #ifdef TEST_LIBRARY /* This is just a library test main program */ int main(void) { int retcod; int w_1,w_2; float angle = 0; int radius = 50; int centerx, centery; char *display; unsigned int id; char dumb[16]; retcod = XHLP_open_display(NULL); printf("XHLP_open_display returns %d.\n",retcod); retcod = XHLP_open_window(250,200,"Test1"); printf("XHLP_open_window returns %d.\n",retcod); if (retcod >= 0) w_1 = retcod; else exit(1); retcod = XHLP_open_window(150,100,"Test2"); printf("XHLP_open_window returns %d.\n",retcod); if (retcod >= 0) w_2 = retcod; else exit(1); XHLP_print(w_1, 10, 10, "Window # 1"); XHLP_print(w_2, 10, 10, "Window # 2"); XHLP_get_click(w_1, &centerx, &centery); XHLP_set_color(w_1, "#ffc000"); for (angle = 0; angle < 2*M_PI; angle += 0.1) { XHLP_draw_line(w_1, centerx, centery, centerx + (int)(radius*cos(angle)), centery + (int)(radius*sin(angle))); } XHLP_get_click(w_2, &centerx, &centery); XHLP_set_color(w_2, "darkblue"); for (angle = 0; angle < 2*M_PI; angle += 0.1) { XHLP_draw_line(w_2, centerx, centery, centerx + (int)(radius*cos(angle)), centery + (int)(radius*sin(angle))); } sleep(2); XHLP_clear_window(w_2); XHLP_set_color(w_2, "green2"); XHLP_get_click(w_2, &centerx, &centery); for (angle = 0; angle < 2*M_PI; angle += 0.1) { XHLP_draw_line(w_2, centerx, centery, centerx + (int)(radius*cos(angle)), centery + (int)(radius*sin(angle))); } XHLP_get_display_id(w_1, &display, &id); printf("Window 1 is on display <%s>, id=0x%x\n", display, id); printf("Press <Enter> to close windows."); fgets(dumb,sizeof(dumb),stdin); retcod = XHLP_close_window(w_1); printf("XHLP_close_window returns %d.\n",retcod); retcod = XHLP_close_window(w_2); printf("XHLP_close_window returns %d.\n",retcod); XHLP_close_display(); exit(0); } #endif int XHLP_open_display(char *display) { /* Make sure we don't leave another display open */ if (XHLP_display != NULL) XHLP_close_display(); /* Open X display. If display is NULL the DISPLAY env variable will be used. */ XHLP_display = XOpenDisplay(display); if (XHLP_display == NULL) { return(-1); } /* Store screen ID. */ XHLP_screen_id = XDefaultScreenOfDisplay(XHLP_display); return(0); } int XHLP_close_display() { /* Close display if it's open */ if (XHLP_display == NULL) return(-1); XCloseDisplay(XHLP_display); XHLP_display = NULL; return(0); } int XHLP_open_window(int sx, int sy, char *name) { XSetWindowAttributes xswda; /* Window attributes */ XSizeHints xszhn; /* WM hints about window size */ XWMHints xwmhn; /* WM hints about input & startup */ XGCValues xgcvl; /* Graphic Context init parameters */ unsigned long amask=0; /* Mask for defined fields in xswda */ int screen_width, screen_height; /* Size of screen in pixels */ unsigned int req_sx, req_sy; /* Requested Window size */ int init_x, init_y; /* Initial window position */ int cur_h; /* Current window handle */ /* Is the display open ? */ if (XHLP_display == NULL) return(-1); /* Check requested size against screen size. */ screen_width = XWidthOfScreen(XHLP_screen_id); screen_height = XHeightOfScreen(XHLP_screen_id); req_sx = sx; if (sx <= 0 || sx > screen_width) { req_sx = screen_width; } req_sy = sy; if (sy <= 0 || sy > screen_height) { req_sy = screen_height; } /* Set window attributes (background, colormap, bit gravity, backing store) */ xswda.background_pixel = XWhitePixelOfScreen(XHLP_screen_id); amask |= CWBackPixel; xswda.bit_gravity = StaticGravity; amask |= CWBitGravity; xswda.backing_store = XDoesBackingStore(XHLP_screen_id); if (xswda.backing_store != NotUseful) /* Use it */ { amask |= CWBackingStore; xswda.save_under = TRUE; amask |= CWSaveUnder; } xswda.colormap = XDefaultColormapOfScreen(XHLP_screen_id); amask |= CWColormap; /* Create window */ /* Find an empty window slot or create it*/ for (cur_h = 0; cur_h < XHLP_max_windows; cur_h ++) { if (XHLP_window_handles[cur_h] == NULL) break; } if (cur_h == XHLP_max_windows) { XHLP_max_windows++; XHLP_window_handles = (XHLP_winfo **)realloc(XHLP_window_handles, XHLP_max_windows * sizeof(XHLP_winfo *)); if (XHLP_window_handles == NULL) { fprintf(stderr,"XHLP: Out of memory\n"); return(-1); } } init_x = init_y = (cur_h+1)*XHLP_INITIAL_OPEN_STEP; XHLP_window_handles[cur_h] = (XHLP_winfo *) malloc(sizeof(XHLP_winfo)); if (XHLP_window_handles[cur_h] == NULL) { fprintf(stderr,"XHLP: Out of memory\n"); free(XHLP_window_handles); XHLP_max_windows = 0; return(-1); } XHLP_window_handles[cur_h]->window = XCreateWindow(XHLP_display, XRootWindowOfScreen(XHLP_screen_id), init_x, init_y, req_sx,req_sy, 0, XDefaultDepthOfScreen(XHLP_screen_id), InputOutput, XDefaultVisualOfScreen(XHLP_screen_id), amask, &xswda); /* Set window manager size hints on the window (WM_NORMAL_HINTS) */ xszhn.x = init_x; xszhn.y = init_y; xszhn.width = req_sx; xszhn.height = req_sy; xszhn.flags = (PPosition | PSize); XSetNormalHints(XHLP_display, XHLP_window_handles[cur_h]->window, &xszhn); /* Set WM hints about keyboard input focus and initial state (WM_HINTS) */ xwmhn.input = FALSE; /* WM should never give us input focus */ xwmhn.initial_state = NormalState; xwmhn.flags = (InputHint | StateHint); XSetWMHints(XHLP_display, XHLP_window_handles[cur_h]->window, &xwmhn); /* Set WM hints about titles of window and icon (WM_NAME, WM_ICON_NAME), */ if (name != NULL) { XStoreName(XHLP_display, XHLP_window_handles[cur_h]->window, name); XSetIconName(XHLP_display, XHLP_window_handles[cur_h]->window, name); } /* Create graphics context */ xgcvl.background = xswda.background_pixel; XHLP_window_handles[cur_h]->gc = XCreateGC (XHLP_display, XHLP_window_handles[cur_h]->window, GCBackground, &xgcvl); /* Initialize event mask for window */ XSelectInput (XHLP_display, XHLP_window_handles[cur_h]->window, StructureNotifyMask); /* Set Black foreground, just for starters */ XSetForeground(XHLP_display, XHLP_window_handles[cur_h]->gc, BlackPixelOfScreen(XHLP_screen_id)); XMapWindow(XHLP_display, XHLP_window_handles[cur_h]->window); XSync (XHLP_display, FALSE); return(cur_h); } int XHLP_close_window(int cur_h) { int i; XHLP_check_window_status(); XUnmapWindow(XHLP_display, XHLP_window_handles[cur_h]->window); XDestroyWindow(XHLP_display, XHLP_window_handles[cur_h]->window); /* Free the window structure and mark the slot as empty */ free (XHLP_window_handles[cur_h]); XHLP_window_handles[cur_h] = NULL; XSync (XHLP_display, FALSE); return(0); } int XHLP_draw_line(int cur_h,int x1,int y1,int x2,int y2) { Status result; XHLP_check_window_status(); XDrawLine(XHLP_display, XHLP_window_handles[cur_h]->window, XHLP_window_handles[cur_h]->gc, x1, y1, x2, y2); XSync (XHLP_display, FALSE); return(0); } int XHLP_clear_window(int cur_h) { Status result; /* X call status */ XWindowAttributes xwda; /* Window attributes */ XHLP_check_window_status(); /* Need to access the window colormap */ result=XGetWindowAttributes(XHLP_display, XHLP_window_handles[cur_h]->window, &xwda); if (result == 0) return (-1); /* 0 is failure in X-Windows */ XClearArea (XHLP_display, XHLP_window_handles[cur_h]->window, 0, 0, xwda.width, xwda.height, FALSE); } int XHLP_plot(int cur_h,int x,int y) { Status result; XHLP_check_window_status(); XDrawPoint(XHLP_display, XHLP_window_handles[cur_h]->window, XHLP_window_handles[cur_h]->gc, x, y); XSync (XHLP_display, FALSE); return(0); } int XHLP_print(int cur_h,int x,int y,char *text) { Status result; XHLP_check_window_status(); if (text == NULL) return(-1); XDrawString(XHLP_display, XHLP_window_handles[cur_h]->window, XHLP_window_handles[cur_h]->gc, x, y, text, strlen(text)); XSync (XHLP_display, FALSE); return(0); } int XHLP_set_color(int cur_h, char *colorname) { Status result; /* X call status */ XColor color; /* Requested color structure */ XWindowAttributes xwda; /* Window attributes */ XHLP_check_window_status(); /* Need to access the window colormap */ result=XGetWindowAttributes(XHLP_display, XHLP_window_handles[cur_h]->window, &xwda); if (result == 0) return (-1); /* 0 is failure in X-Windows */ result = XParseColor(XHLP_display, xwda.colormap, colorname, &color); if (result == 0) return (-1); /* 0 is failure in X-Windows */ XAllocColor(XHLP_display, xwda.colormap, &color); XSetForeground(XHLP_display, XHLP_window_handles[cur_h]->gc, color.pixel); XSync (XHLP_display, FALSE); return(0); } int XHLP_get_click(int cur_h, int *rx, int *ry) { int retcod = -1; XEvent event; /* Next button event */ Cursor crosshair; XHLP_check_window_status(); /* Change the cursor inside the selected window to a crosshair */ crosshair = XCreateFontCursor(XHLP_display, XC_crosshair); XDefineCursor(XHLP_display, XHLP_window_handles[cur_h]->window, crosshair); /* Allow button clicks to be detected in the selected window */ XSelectInput(XHLP_display, XHLP_window_handles[cur_h]->window, StructureNotifyMask|ButtonPressMask); /* Wait for a button click */ while (XWindowEvent(XHLP_display, XHLP_window_handles[cur_h]->window, ButtonPressMask, &event) >=0 ) { if (event.type==ButtonPress) { *rx = event.xbutton.x; *ry = event.xbutton.y; retcod = 0; break; } } /* Restore the original cursor */ XUndefineCursor(XHLP_display, XHLP_window_handles[cur_h]->window); XFreeCursor(XHLP_display, crosshair); /* Remove button click detection */ XSelectInput(XHLP_display, XHLP_window_handles[cur_h]->window, StructureNotifyMask); return(retcod); } int XHLP_get_display_id(int cur_h, char **display, unsigned int *id) { XHLP_check_window_status(); *display = XDisplayString(XHLP_display); *id = (unsigned int)XHLP_window_handles[cur_h]->window; return(0); }