/* Copyright 1991, 1998 The Open Group Permission to use, copy, modify, distribute, and sell this software and its documentation for any purpose is hereby granted without fee, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation. The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Except as contained in this notice, the name of The Open Group shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from The Open Group. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include /* for exit() and abs() */ #include #include #include #include #include #include #include #include #include #include "RootWin.h" #include "Scale.h" #include "CutPaste.h" #define SRCWIDTH 64 #define SRCHEIGHT 64 #ifndef min #define min(a, b) ((a) < (b) ? (a) : (b)) #endif #ifndef max #define max(a, b) ((a) > (b) ? (a) : (b)) #endif /* highlight interval (in milliseconds) */ #define HLINTERVAL 100 /* sleep between draw & erase of highlight * 20 milliseconds - enough for screen refresh - not too long to annoy users * since we hold a server grab during this time */ #define HLSLEEPINTERVAL 20 /* milliseconds */ #ifdef HAVE_NANOSLEEP #include #define HLSLEEP do { \ struct timespec sleeptime = { 0 , HLSLEEPINTERVAL * 1000000 } ; \ nanosleep(&sleeptime, NULL); \ } while(0) #elif defined(HAVE_POLL) #include #define HLSLEEP poll(NULL, 0, HLSLEEPINTERVAL) #elif defined(HAVE_SELECT) #include #define HLSLEEP do { \ struct timeval sleeptime = { 0 , HLSLEEPINTERVAL * 1000 } ; \ select(0, NULL, NULL, NULL, &sleeptime); \ } while(0) #else #define HLSLEEP XSync(dpy, False) #endif /* highlight mode */ typedef enum { drag, resize, done } hlMode; /* highlight data structure */ typedef struct { Boolean newScale; hlMode selectMode; GC gc; XWindowAttributes win_info; XImage *image; Position homeX, homeY, x, y; Dimension width, height; Widget scaleShell, scaleInstance, pixShell, pixLabel, cmapWinList [2]; } hlStruct, *hlPtr; /* global variables */ static XtAppContext app; static Cursor ulAngle, urAngle, lrAngle, llAngle; static Display *dpy; static int scr; static GC selectGC; static XGCValues selectGCV; static Widget toplevel, root; static Atom wm_delete_window; static int numXmags = 0; static int srcStat, srcX, srcY; static unsigned int srcWidth, srcHeight; /* forward declarations */ static int Error(Display *, XErrorEvent *); static void CloseAP(Widget, XEvent *, String *, Cardinal *); static void SetCmapPropsAP(Widget, XEvent *, String *, Cardinal *); static void UnsetCmapPropsAP(Widget, XEvent *, String *, Cardinal *); static void NewAP(Widget, XEvent *, String *, Cardinal *); static void ReplaceAP(Widget, XEvent *, String *, Cardinal *); static void PopupPixelAP(Widget, XEvent *, String *, Cardinal *); static void UpdatePixelAP(Widget, XEvent *, String *, Cardinal *); static void PopdownPixelAP(Widget, XEvent *, String *, Cardinal *); static void SelectRegionAP(Widget, XEvent *, String *, Cardinal *); static void CheckPoints(Position *, Position *, Position *, Position *); static void HighlightTO(XtPointer, XtIntervalId *); static void CloseCB(Widget, XtPointer, XtPointer); static void ReplaceCB(Widget, XtPointer, XtPointer); static void NewCB(Widget, XtPointer, XtPointer); static void SelectCB(Widget, XtPointer, XtPointer); static void PasteCB(Widget, XtPointer, XtPointer); static void SetupGC(void); static Window FindWindow(int, int); static void ResizeEH(Widget, XtPointer, XEvent *, Boolean *); static void DragEH(Widget, XtPointer, XEvent *, Boolean *); static void StartRootPtrGrab(int, hlPtr); static void CreateRoot(void); static void GetImageAndAttributes(Window, int, int, int, int, hlPtr); static int Get_XColors(XWindowAttributes *, XColor **); static Pixel GetMaxIntensity(hlPtr); static Pixel GetMinIntensity(hlPtr); static void PopupNewScale(hlPtr); static void RedoOldScale(hlPtr); static void InitCursors(void); static void ParseSourceGeom(void); /* application resources */ typedef struct { String geometry, source, mag, title; } OptionsRec; static OptionsRec options; #define Offset(field) XtOffsetOf(OptionsRec, field) static XtResource resources[] = { {"geometry", "Geometry", XtRString, sizeof(String), Offset(geometry), XtRString, (XtPointer)NULL}, {"mag", "Mag", XtRString, sizeof(String), Offset(mag), XtRString, (XtPointer)"5.0"}, {"source", "Source", XtRString, sizeof(String), Offset(source), XtRString, (XtPointer)"SRCWIDTHxSRCHEIGHT"}, {"title", XtCString, XtRString, sizeof(char *), Offset(title), XtRString, "xmag"}, }; #undef Offset static XrmOptionDescRec optionDesc[] = { {"-bd", "*borderColor", XrmoptionSepArg, (XtPointer)NULL}, {"-bg", "*background", XrmoptionSepArg, (XtPointer)NULL}, {"-bw", "*borderWidth", XrmoptionSepArg, (XtPointer)NULL}, {"-geometry", "*geometry", XrmoptionSepArg, (XtPointer)NULL}, {"-mag", "*mag", XrmoptionSepArg, (XtPointer)NULL}, {"-source", "*source", XrmoptionSepArg, (XtPointer)NULL}, {"-title", "*title", XrmoptionSepArg, (XtPointer)NULL}, }; /* action table */ static XtActionsRec actions_table[] = { {"close", CloseAP}, {"set-colors", SetCmapPropsAP}, {"unset-colors", UnsetCmapPropsAP}, {"new", NewAP}, {"replace", ReplaceAP}, {"popup-pixel", PopupPixelAP}, {"update-pixel", UpdatePixelAP}, {"popdown-pixel", PopdownPixelAP}, {"select-region", SelectRegionAP} }; /* * Error() -- Error handler: Catch a bad match in magnifying an * area that contains bits of different depths. */ static int Error(Display *display, XErrorEvent *err) { (void) XmuPrintDefaultErrorMessage (display, err, stderr); return 0; } /* * CloseAP() -- Close this dialog. If its the last one exit the program. * */ static void CloseAP(Widget w, XEvent *event, _X_UNUSED String *params, _X_UNUSED Cardinal *num_params) { Arg wargs[2]; int n; hlPtr data; if (!--numXmags) exit(0); if (event->type != ClientMessage) { n = 0; /* get user data */ XtSetArg(wargs[0], XtNuserData, &data); n++; XtGetValues(w, wargs, n); w = data->scaleShell; } XtPopdown(w); XtDestroyWidget(w); } /* * SetCmapPropsAP() -- Put the scale widget first in WM_COLORMAP_WINDOWS * */ static void SetCmapPropsAP(Widget w, _X_UNUSED XEvent *event, _X_UNUSED String *params, _X_UNUSED Cardinal *num_params) { Arg wargs[2]; int n; hlPtr data; n = 0; /* get user data */ XtSetArg(wargs[0], XtNuserData, &data); n++; XtGetValues(w, wargs, n); if (data->win_info.colormap != DefaultColormap(dpy, scr)) { data->cmapWinList[0] = data->scaleInstance; data->cmapWinList[1] = data->scaleShell; XtSetWMColormapWindows(data->scaleShell, data->cmapWinList, 2); } } /* * UnsetCmapPropsAP() -- Put the shell first in WM_COLORMAP_WINDOWS * */ static void UnsetCmapPropsAP(Widget w, _X_UNUSED XEvent *event, _X_UNUSED String *params, _X_UNUSED Cardinal *num_params) { Arg wargs[2]; int n; hlPtr data; n = 0; /* get user data */ XtSetArg(wargs[0], XtNuserData, &data); n++; XtGetValues(w, wargs, n); if (data->win_info.colormap != DefaultColormap(dpy, scr)) { data->cmapWinList[0] = data->scaleShell; data->cmapWinList[1] = data->scaleInstance; XtSetWMColormapWindows(data->scaleShell, data->cmapWinList, 2); } } /* * NewAP() -- Create an additional xmag dialog. THIS IS A COPY OF NewEH * FIND A BETTER WAY.... */ static void NewAP(_X_UNUSED Widget w, _X_UNUSED XEvent *event, _X_UNUSED String *params, _X_UNUSED Cardinal *num_params) { StartRootPtrGrab(True, NULL); } /* * ReplaceAP() -- Replace this particular xmag dialog. */ static void ReplaceAP(Widget w, _X_UNUSED XEvent *event, _X_UNUSED String *params, _X_UNUSED Cardinal *num_params) { Arg wargs[2]; int n; hlPtr data; n = 0; /* get user data */ XtSetArg(wargs[0], XtNuserData, &data); n++; XtGetValues(w, wargs, n); StartRootPtrGrab(False, data); } /* * PopupPixelAP() -- Show pixel information. */ static void PopupPixelAP(Widget w, XEvent *event, _X_UNUSED String *params, _X_UNUSED Cardinal *num_params) { Position scale_x, scale_y; Dimension scale_height; Position label_x, label_y; Dimension label_height; int n; Arg wargs[3]; hlPtr data; n = 0; /* get user data */ XtSetArg(wargs[0], XtNuserData, &data); n++; XtGetValues(w, wargs, n); n = 0; XtSetArg(wargs[n], XtNheight, &scale_height); n++; XtGetValues(w, wargs, n); XtTranslateCoords(w, -1, -1, &scale_x, &scale_y); XtRealizeWidget(data->pixShell); /* to get the right height */ n = 0; XtSetArg(wargs[n], XtNheight, &label_height); n++; XtGetValues(data->pixShell, wargs, n); if ((double) event->xbutton.y / (double) scale_height > 0.5) { label_x = scale_x; label_y = scale_y; } else { label_x = scale_x; label_y = scale_y + scale_height - label_height; } n = 0; XtSetArg(wargs[n], XtNx, label_x); n++; XtSetArg(wargs[n], XtNy, label_y); n++; XtSetValues(data->pixShell, wargs, n); UpdatePixelAP(w, event, NULL, NULL); } /* * UpdatePixelAP() -- Update pixel information. */ static void UpdatePixelAP(Widget w, XEvent *event, _X_UNUSED String *params, _X_UNUSED Cardinal *num_params) { Position x, y; Pixel pixel; XColor color; int n; Arg wargs[3]; char string[80]; hlPtr data; n = 0; XtSetArg(wargs[0], XtNuserData, &data); n++; XtGetValues(w, wargs, n); if (SWGetImagePixel(w, event->xbutton.x, event->xbutton.y, &x, &y, &pixel)) XtPopdown(data->pixShell); else { color.pixel = pixel; XQueryColor(dpy, data->win_info.colormap, &color); snprintf(string, sizeof(string), "Pixel %ld at (%d,%d) colored (%x,%x,%x).", pixel, x + data->x, y + data->y, color.red, color.green, color.blue); n = 0; XtSetArg(wargs[n], XtNlabel, string); n++; XtSetValues(data->pixLabel, wargs, n); XtPopup(data->pixShell, XtGrabNone); } } /* * PopdownPixelAP() -- Remove pixel info. */ static void PopdownPixelAP(Widget w, _X_UNUSED XEvent *event, _X_UNUSED String *params, _X_UNUSED Cardinal *num_params) { int n; Arg wargs[3]; hlPtr data = NULL; n = 0; XtSetArg(wargs[0], XtNuserData, &data); n++; XtGetValues(w, wargs, n); if (data) XtPopdown(data->pixShell); } static void SelectRegionAP(_X_UNUSED Widget w, _X_UNUSED XEvent *event, _X_UNUSED String *params, _X_UNUSED Cardinal *num_params) { /***** NOT SURE WHAT TO DO WITH THIS if (app_resources.unmap) XtUnmapWidget(toplevel); Redisplay(XtDisplay(w), RootWindow(XtDisplay(w), DefaultScreen(XtDisplay(w))), source.width, source.height, app_resources.freq, app_resources.puls, ul_angle, lr_angle, app_resources.grab); if (app_resources.unmap) XtMapWidget(toplevel); ******/ } /* * CheckPoints() -- Change the cursor for the correct quadrant. * Make sure the first point is less than the second * for drawing the selection rectangle. * */ static void CheckPoints(Position *x1, Position *x2, Position *y1, Position *y2) { Position tmp; Boolean above, left; Cursor newC; above = (*y2 < *y1); left = (*x2 < *x1); if (above&&left) newC = ulAngle; else if (above&&!left) newC = urAngle; else if (!above&&!left) newC = lrAngle; else newC = llAngle; XChangeActivePointerGrab (dpy, PointerMotionMask|ButtonPressMask|ButtonReleaseMask, newC, CurrentTime); if (*x2 < *x1) { tmp = *x1; *x1 = *x2; *x2 = tmp; } if (*y2 < *y1) { tmp = *y1; *y1 = *y2; *y2 = tmp; } } /* * HighlightTO() -- Timer to highlight the selection box */ static void HighlightTO(XtPointer closure, _X_UNUSED XtIntervalId *id) { hlPtr data = (hlPtr)closure; XGrabServer(dpy); if (data->selectMode == drag) { XDrawRectangle(dpy, DefaultRootWindow(dpy), data->gc, data->x, data->y, data->width, data->height); XFlush(dpy); HLSLEEP; XDrawRectangle(dpy, DefaultRootWindow(dpy), data->gc, data->x, data->y, data->width, data->height); } else if (data->selectMode == resize) { Position x1 = data->homeX, x2 = data->x, y1 = data->homeY, y2 = data->y; CheckPoints(&x1, &x2, &y1, &y2); XDrawRectangle(dpy, DefaultRootWindow(dpy), data->gc, x1, y1, x2 - x1, y2 - y1); XFlush(dpy); HLSLEEP; XDrawRectangle(dpy, DefaultRootWindow(dpy), data->gc, x1, y1, x2 - x1, y2 - y1); } XUngrabServer(dpy); if (data->selectMode != done) XtAppAddTimeOut(app, HLINTERVAL, HighlightTO, (XtPointer)data); } /* * CloseCB() -- Delete this xmag dialog. If its the only one on the screen * then exit. */ static void CloseCB(_X_UNUSED Widget w, XtPointer clientData, _X_UNUSED XtPointer callData) { Widget shell = (Widget)clientData; if (!--numXmags) exit(0); XtPopdown(shell); XtDestroyWidget(shell); } /* * ReplaceCB() -- Replace this particular xmag dialog. */ static void ReplaceCB(_X_UNUSED Widget w, XtPointer clientData, _X_UNUSED XtPointer callData) { hlPtr data = (hlPtr)clientData; StartRootPtrGrab(False, data); } /* * NewCB() -- Create an additional xmag dialog. */ static void NewCB(_X_UNUSED Widget w, _X_UNUSED XtPointer clientData, _X_UNUSED XtPointer callData) { StartRootPtrGrab(True, NULL); } /* * SelectCB() -- Own the primary selection. */ static void SelectCB(_X_UNUSED Widget w, XtPointer clientData, _X_UNUSED XtPointer callData) { hlPtr data = (hlPtr)clientData; SWGrabSelection(data->scaleInstance, XtLastTimestampProcessed(dpy)); } /* * PasteCB() -- Paste from the primary selection into xmag. */ static void PasteCB(_X_UNUSED Widget w, XtPointer clientData, _X_UNUSED XtPointer callData) { hlPtr data = (hlPtr)clientData; SWRequestSelection(data->scaleInstance, XtLastTimestampProcessed(dpy)); } /* * SetupGC() -- Graphics context for magnification selection. */ static void SetupGC(void) { selectGCV.function = GXxor; selectGCV.foreground = 0xffffffff; selectGCV.subwindow_mode = IncludeInferiors; selectGC = XtGetGC(toplevel, GCFunction|GCForeground|GCSubwindowMode, &selectGCV); } /* * FindWindow() -- Determine window the pointer is over. * */ static Window FindWindow(int x, int y) /* Location of cursor */ { XWindowAttributes wa; Window findW = DefaultRootWindow(dpy), stopW, childW; /* Setup for first window find */ stopW = findW; while (stopW) { XTranslateCoordinates(dpy, findW, stopW, x, y, &x, &y, &childW); findW = stopW; /* If child is not InputOutput (for example, InputOnly) */ /* then don't continue, return the present findW which */ /* can be the root, or a root child of class InputOutput */ if (childW && XGetWindowAttributes(dpy, childW, &wa) && wa.class != InputOutput) break; stopW = childW; } return findW; } /* * ResizeEH() -- Event Handler for resize of selection box. */ static void ResizeEH(Widget w, XtPointer closure, XEvent *event, _X_UNUSED Boolean *continue_to_dispatch) { hlPtr data = (hlPtr)closure; switch (event->type) { case MotionNotify: data->x = event->xmotion.x_root; data->y = event->xmotion.y_root; break; case ButtonRelease: GetImageAndAttributes(FindWindow(event->xmotion.x_root, event->xmotion.y_root), min(data->homeX,event->xbutton.x_root), min(data->homeY,event->xbutton.y_root), abs(data->homeX - event->xbutton.x_root), abs(data->homeY - event->xbutton.y_root), data); if (data->newScale) PopupNewScale(data); else SWSetImage(data->scaleInstance, data->image); XtUngrabPointer(w, CurrentTime); /***** XtRemoveRawEventHandler(w, PointerMotionMask|ButtonReleaseMask, True, ResizeEH, (XtPointer)data); *****/ XtRemoveEventHandler(w, PointerMotionMask|ButtonReleaseMask, True, ResizeEH, (XtPointer)data); data->selectMode = done; break; } } /* * DragEH() -- Event Handler for dragging selection box. */ static void DragEH(Widget w, XtPointer closure, XEvent *event, _X_UNUSED Boolean *continue_to_dispatch) { hlPtr data = (hlPtr)closure; switch (event->type) { case MotionNotify: /* drag mode */ data->x = event->xmotion.x_root; data->y = event->xmotion.y_root; break; case ButtonRelease: /* end drag mode */ if (event->xbutton.button == Button1) { /* get image */ /* Problem: You can't get bits with XGetImage outside of its window. * xmag will only do a GetImage on the actual window in the case * where the depth of the window does not match the depth of * the root window. */ GetImageAndAttributes(FindWindow(event->xmotion.x_root, event->xmotion.y_root), event->xbutton.x_root, event->xbutton.y_root, srcWidth, srcHeight, data); if (data->newScale) PopupNewScale(data); else RedoOldScale(data); XtUngrabPointer(w, CurrentTime); XtRemoveRawEventHandler(w, PointerMotionMask|ButtonPressMask| ButtonReleaseMask, True, DragEH, (XtPointer)data); data->selectMode = done; } break; case ButtonPress: if (event->xbutton.button == Button2) { /* turn on resize mode */ data->homeX = event->xbutton.x_root; data->homeY = event->xbutton.y_root; data->x = event->xbutton.x_root + srcWidth; data->y = event->xbutton.y_root + srcHeight; data->selectMode = resize; XtRemoveRawEventHandler(w, PointerMotionMask|ButtonPressMask| ButtonReleaseMask, True, DragEH, (XtPointer)data); XChangeActivePointerGrab (dpy, PointerMotionMask|ButtonPressMask|ButtonReleaseMask, lrAngle, CurrentTime); XWarpPointer(dpy, None, None, 0, 0, 0, 0, srcWidth, srcHeight); XtAddEventHandler(w, PointerMotionMask|ButtonReleaseMask, True, ResizeEH, (XtPointer)data); } break; } } /* * StartRootPtrGrab() -- Bring up the selection box. * */ static void StartRootPtrGrab(int new, /* do we create a new scale instance? */ hlPtr data) /* highlight data */ { Window rootR, childR; int rootX, rootY, winX, winY; unsigned int mask; hlPtr hlData; XtGrabPointer (root, False, PointerMotionMask|ButtonPressMask|ButtonReleaseMask, GrabModeAsync, GrabModeAsync, None, ulAngle, CurrentTime); XQueryPointer(dpy, DefaultRootWindow(dpy), &rootR, &childR, &rootX, &rootY, &winX, &winY, &mask); if (new) { numXmags++; hlData = (hlPtr)XtMalloc(sizeof(hlStruct)); } else hlData = data; hlData->newScale = new; hlData->selectMode = drag; hlData->x = rootX; hlData->y = rootY; hlData->gc = selectGC; hlData->width = srcWidth; hlData->height = srcHeight; XtAddRawEventHandler (root, PointerMotionMask|ButtonPressMask|ButtonReleaseMask, True, DragEH, (XtPointer)hlData); (void) XtAppAddTimeOut(app, HLINTERVAL, HighlightTO, (XtPointer)hlData); } /* * CreateRoot() -- Create a root window widget. If the user specified x and y * in the source geometry then use this to directly get the * image. */ static void CreateRoot(void) { hlPtr data; root = XtCreateWidget("root", rootWindowWidgetClass, toplevel, NULL, 0); XtRealizeWidget(root); if (XValue & srcStat && YValue &srcStat) { numXmags = 1; data = (hlPtr)XtMalloc(sizeof(hlStruct)); data->newScale = True; data->selectMode = drag; data->x = srcX; data->y = srcY; data->gc = selectGC; data->width = srcWidth; data->height = srcHeight; GetImageAndAttributes(RootWindow(dpy, scr), srcX, srcY, srcWidth, srcHeight, data); PopupNewScale(data); return; } } /* * GetImageAndAttributes() -- Get the image bits from the screen. * We will also determine here the colormap, depth, and * visual to be used for the magnification image. */ static void GetImageAndAttributes(Window w, int x, int y, int width, int height, hlPtr data) { /* get parameters of window being magnified */ XGetWindowAttributes(dpy, w, &data->win_info); if (data->win_info.depth == DefaultDepth(dpy, scr)) { /* avoid off screen pixels */ if (x < 0) x = 0; if (y < 0) y = 0; if (x + width > DisplayWidth(dpy,scr)) x = DisplayWidth(dpy,scr) - width; if (y + height > DisplayHeight(dpy,scr)) y = DisplayHeight(dpy,scr) - height; data->x = x; data->y = y; /* get image pixels */ data->image = XGetImage (dpy, RootWindow(dpy, scr), x, y, width, height, AllPlanes, ZPixmap); } else { int t0, t1; int x0, x1, y0, y1; int xInWin, yInWin; Window childWin; XTranslateCoordinates(dpy, DefaultRootWindow(dpy), w, x, y, &xInWin, &yInWin, &childWin); /* Avoid off screen pixels. Assume this routine is not * called for totally offscreen windows. */ x0 = max(x, 0); y0 = max(y, 0); x1 = min(DisplayWidth(dpy, scr), min(x0 + width, x0 + (data->win_info.width - xInWin))); y1 = min(DisplayHeight(dpy, scr), min(y0 + height, y0 + (data->win_info.height - yInWin))); /* Try to use up to width x height pixels */ if (x1 - x0 < width) { t0 = x0; t1 = max(0, x - xInWin + data->win_info.width - DisplayWidth(dpy, scr)); x0 = max(0, x1 - min(width, data->win_info.width - t1)); xInWin -= t0 - x0; } if (y1 - y0 < height) { t0 = y0; t1 = max(0, y - yInWin + data->win_info.height - DisplayHeight(dpy, scr)); y0 = max(0, y1 - min(height, data->win_info.height - t1)); yInWin -= t0 - y0; } data->x = x0; data->y = y0; data->width = x1 - x0; data->height = y1 - y0; data->image = XGetImage (dpy, w, xInWin, yInWin, data->width, data->height, AllPlanes, ZPixmap); } } /* * Get_XColors() Get the XColors of all pixels in image - returns # of colors * This function was taken from xwd (thanks Bob...) */ #define lowbit(x) ((x) & (~(x) + 1)) static int Get_XColors(XWindowAttributes *win_info, XColor **colors) { int i, ncolors; if (!win_info->colormap) return(0); ncolors = win_info->visual->map_entries; if (!(*colors = (XColor *) XtMalloc (sizeof(XColor) * ncolors))) XtError("Out of memory!"); if (win_info->visual->class == DirectColor || win_info->visual->class == TrueColor) { Pixel red, green, blue, red1, green1, blue1; red = green = blue = 0; red1 = lowbit(win_info->visual->red_mask); green1 = lowbit(win_info->visual->green_mask); blue1 = lowbit(win_info->visual->blue_mask); for (i=0; i win_info->visual->red_mask) red = 0; green += green1; if (green > win_info->visual->green_mask) green = 0; blue += blue1; if (blue > win_info->visual->blue_mask) blue = 0; } } else { for (i=0; icolormap, *colors, ncolors); return(ncolors); } #define Intensity(cptr) (3.0*cptr->red+0.59*cptr->green+0.11*cptr->blue) /* * GetMaxIntensity() -- Find the maximum intensity pixel value for a colormap. */ static Pixel GetMaxIntensity(hlPtr data) { XColor *colors = NULL, *mptr, *tptr; int i, ncolors; if (data->win_info.colormap == DefaultColormap(dpy, scr)) return WhitePixel(dpy, scr); ncolors = Get_XColors(&data->win_info, &colors); mptr = tptr = colors; tptr++; for (i=1; ipixel; else return WhitePixel(dpy, scr); } /* * GetMinIntensity() -- Find the minimum intensity pixel value for a colormap. */ static Pixel GetMinIntensity(hlPtr data) { XColor *colors = NULL, *mptr, *tptr; int i, ncolors; if (data->win_info.colormap == DefaultColormap(dpy, scr)) return BlackPixel(dpy, scr); ncolors = Get_XColors(&data->win_info, &colors); mptr = tptr = colors; tptr++; for (i=1; i (int)Intensity(tptr)) mptr = tptr; tptr++; } /* Null pointer protection */ if(mptr) return mptr->pixel; else return BlackPixel(dpy, scr); } static Widget pane1, pane2, pane3, cclose, replace, new, select_w, paste; /* * PopupNewScale() -- Create and popup a new scale composite. */ static void PopupNewScale(hlPtr data) { Arg warg; data->scaleShell = XtVaCreatePopupShell("xmag", topLevelShellWidgetClass, toplevel, XtNgeometry, (XtArgVal)options.geometry, XtNtitle, (XtArgVal)options.title, NULL); pane1 = XtCreateManagedWidget("pane1", panedWidgetClass, data->scaleShell, (Arg *) NULL, 0); pane2 = XtCreateManagedWidget("pane2", panedWidgetClass, pane1, (Arg *) NULL, 0); cclose = XtCreateManagedWidget("close", commandWidgetClass, pane2, (Arg *) NULL, 0); XtAddCallback(cclose, XtNcallback, CloseCB, (XtPointer)data->scaleShell); replace = XtCreateManagedWidget("replace", commandWidgetClass, pane2, (Arg *) NULL, 0); XtAddCallback(replace, XtNcallback, ReplaceCB, (XtPointer)data); new = XtCreateManagedWidget("new", commandWidgetClass, pane2, (Arg *) NULL, 0); XtAddCallback(new, XtNcallback, NewCB, (XtPointer)NULL); select_w = XtCreateManagedWidget("select", commandWidgetClass, pane2, (Arg *) NULL, 0); XtAddCallback(select_w, XtNcallback, SelectCB, (XtPointer)data); paste = XtCreateManagedWidget("paste", commandWidgetClass, pane2, (Arg *) NULL, 0); XtAddCallback(paste, XtNcallback, PasteCB, (XtPointer)data); (void) XtCreateManagedWidget("helpLabel", labelWidgetClass, pane2, (Arg *) NULL, 0); pane3 = XtCreateManagedWidget("pane2", panedWidgetClass, pane1, (Arg *) NULL, 0); data->scaleInstance = XtVaCreateManagedWidget("scale", scaleWidgetClass, pane3, XtNvisual, (XtArgVal)data->win_info.visual, XtNcolormap, (XtArgVal)data->win_info.colormap, XtNdepth, (XtArgVal)data->win_info.depth, XtNscaleX, (XtArgVal)options.mag, XtNscaleY, (XtArgVal)options.mag, NULL); SWSetImage(data->scaleInstance, data->image); XtOverrideTranslations (data->scaleShell, XtParseTranslationTable ("WM_PROTOCOLS: close()")); XtSetArg(warg, XtNuserData, data); XtSetValues(data->scaleInstance, &warg, 1); data->pixShell = XtVaCreatePopupShell("pixShell", overrideShellWidgetClass, toplevel, XtNvisual, (XtArgVal)data->win_info.visual, XtNcolormap, (XtArgVal)data->win_info.colormap, XtNdepth, (XtArgVal)data->win_info.depth, XtNborderWidth, (XtPointer)0, NULL); data->pixLabel = XtVaCreateManagedWidget("pixLabel", labelWidgetClass, data->pixShell, XtNforeground, (XtPointer)GetMaxIntensity(data), XtNbackground, (XtPointer)GetMinIntensity(data), XtNborderWidth, (XtPointer)0, NULL); XtInstallAllAccelerators(pane1, pane1); /* install accelerators */ if (data->newScale) { XtPopup(data->scaleShell, XtGrabNone); (void) XSetWMProtocols /* ICCCM delete window */ (dpy, XtWindow(data->scaleShell), &wm_delete_window, 1); } if (data->win_info.colormap != DefaultColormap(dpy, scr)) { data->cmapWinList[0] = data->scaleShell; data->cmapWinList[1] = data->scaleInstance; XtSetWMColormapWindows(data->scaleShell, data->cmapWinList, 2); } } /* * RedoOldScale() -- If the visual, depth, or colormap has changed, unrealize * the scale widget and change its colormap/depth/visual. * Then re-realize it. Also do this for the pixel display * widget. */ static void RedoOldScale(hlPtr data) { Arg wargs[3]; int n; Visual *oldVis; int oldDepth; Colormap oldCmap; n=0; XtSetArg(wargs[n], XtNvisual, &oldVis); n++; XtSetArg(wargs[n], XtNdepth, &oldDepth); n++; XtSetArg(wargs[n], XtNcolormap, &oldCmap); n++; XtGetValues(data->scaleInstance, wargs, n); if (oldVis == data->win_info.visual && oldDepth == data->win_info.depth && oldCmap == data->win_info.colormap) { SWSetImage(data->scaleInstance, data->image); return; } /* get width and height, save and reuse them */ XtUnmanageChild(data->scaleInstance); XtUnrealizeWidget(data->scaleInstance); n=0; XtSetArg(wargs[n], XtNcolormap, data->win_info.colormap); n++; XtSetArg(wargs[n], XtNdepth, data->win_info.depth); n++; XtSetArg(wargs[n], XtNvisual, data->win_info.visual); n++; XtSetValues(data->scaleInstance, wargs, n); n=0; XtSetArg(wargs[n], XtNforeground, GetMaxIntensity(data)); n++; XtSetArg(wargs[n], XtNbackground, GetMinIntensity(data)); n++; XtSetValues(data->pixLabel, wargs, n); SWSetImage(data->scaleInstance, data->image); XtRealizeWidget(data->scaleInstance); XtManageChild(data->scaleInstance); } /* * InitCursors() -- Create our cursors for area selection. */ static void InitCursors(void) { ulAngle = XCreateFontCursor(dpy, XC_ul_angle); urAngle = XCreateFontCursor(dpy, XC_ur_angle); lrAngle = XCreateFontCursor(dpy, XC_lr_angle); llAngle = XCreateFontCursor(dpy, XC_ll_angle); } /* * ParseSourceGeom() -- Determine dimensions of area to magnify from resources. */ static void ParseSourceGeom(void) { /* source */ srcStat = XParseGeometry(options.source, &srcX, &srcY, &srcWidth, &srcHeight); if (!srcWidth) srcWidth = SRCWIDTH; if (!srcHeight) srcHeight = SRCHEIGHT; if (XNegative & srcStat) srcX = DisplayWidth(dpy, scr) + srcX - srcWidth; if (YNegative & srcStat) srcY = DisplayHeight(dpy, scr) + srcY - srcHeight; /* mag */ } static void _X_NORETURN usage(const char *progname, int exitval) { fprintf (stderr, "usage: %s [-source geom] [-mag magfactor] [-toolkitoption]\n" " %s [-help|-version]\n", progname, progname); exit (exitval); } /* * Main program. */ int main(int argc, char *argv[]) { /* Handle args that don't require opening a display */ for (int n = 1; n < argc; n++) { const char *argn = argv[n]; /* accept single or double dash for -help & -version */ if (argn[0] == '-' && argn[1] == '-') { argn++; } if (strcmp(argn, "-help") == 0) { usage(argv[0], 0); } if (strcmp(argn, "-version") == 0) { puts(PACKAGE_STRING); exit(0); } } XSetErrorHandler(Error); toplevel = XtAppInitialize(&app, "Xmag", optionDesc, XtNumber(optionDesc), &argc, argv, NULL, NULL, 0); dpy = XtDisplay(toplevel); scr = DefaultScreen(dpy); XtGetApplicationResources(toplevel, (XtPointer) &options, resources, XtNumber(resources), NULL, 0); if (argc != 1) { fputs("Unknown argument(s):", stderr); for (int n = 1; n < argc; n++) { fprintf(stderr, " %s", argv[n]); } fputs("\n\n", stderr); usage(argv[0], 1); } ParseSourceGeom(); XtAppAddActions(app, actions_table, XtNumber(actions_table)); InitCursors(); SetupGC(); CreateRoot(); if (!(XValue & srcStat && YValue & srcStat)) StartRootPtrGrab(True, (hlPtr)NULL); wm_delete_window = XInternAtom(dpy, "WM_DELETE_WINDOW", False); XtAppMainLoop(app); exit(0); }