diff options
author | Matthieu Herrb <matthieu@cvs.openbsd.org> | 2006-11-25 20:52:24 +0000 |
---|---|---|
committer | Matthieu Herrb <matthieu@cvs.openbsd.org> | 2006-11-25 20:52:24 +0000 |
commit | cf87db164aa2401ec33a041d3969d6ccb1ef49d9 (patch) | |
tree | 9b65838d7e1aee39d37defb896a5fd6a3922d5ba /app/xmag/xmag.c | |
parent | 2387c426e6dfc2b0a2d0aa5585dbeb580f5ea91e (diff) |
Importing from X.Org 7.2RC2
Diffstat (limited to 'app/xmag/xmag.c')
-rw-r--r-- | app/xmag/xmag.c | 1075 |
1 files changed, 1075 insertions, 0 deletions
diff --git a/app/xmag/xmag.c b/app/xmag/xmag.c new file mode 100644 index 000000000..c5cc10a0f --- /dev/null +++ b/app/xmag/xmag.c @@ -0,0 +1,1075 @@ +/* $Xorg: xmag.c,v 1.4 2001/02/09 02:05:55 xorgcvs Exp $ */ +/* + +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. + +*/ +/* $XFree86: xmag.c,v 1.13 2003/05/27 22:27:07 tsi Exp $ */ + + +#include <stdlib.h> /* for exit() and abs() */ +#include <stdio.h> + +#include <X11/Intrinsic.h> +#include <X11/StringDefs.h> +#include <X11/Xaw/Paned.h> +#include <X11/Xaw/Command.h> +#include <X11/Xaw/Label.h> +#include <X11/Shell.h> +#include <X11/cursorfont.h> +#include <X11/Xmu/Error.h> +#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 + + + +/* highlight interval */ +#define HLINTERVAL 10 + +/* 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 magnifing an + * area that contains bits of different depths. + */ +static int +Error(Display *dpy, XErrorEvent *err) +{ + (void) XmuPrintDefaultErrorMessage (dpy, err, stderr); + return 0; +} + + +/* + * CloseAP() -- Close this dialog. If its the last one exit the program. + * + */ +static void /* ARGSUSED */ +CloseAP(Widget w, XEvent *event, String *params, 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 /* ARGSUSED */ +SetCmapPropsAP(Widget w, XEvent *event, String *params, 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 /* ARGSUSED */ +UnsetCmapPropsAP(Widget w, XEvent *event, String *params, 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 /* ARGSUSED */ +NewAP(Widget w, XEvent *event, String *params, Cardinal *num_params) +{ + StartRootPtrGrab(True, NULL); +} + + + +/* + * ReplaceAP() -- Replace this particular xmag dialog. + */ +static void /* ARGSUSED */ +ReplaceAP(Widget w, XEvent *event, String *params, 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 /* ARGSUSED */ +PopupPixelAP(Widget w, XEvent *event, String *params, 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, 0, 0); +} + + + +/* + * UpdatePixelAP() -- Update pixel information. + */ +static void /* ARGSUSED */ +UpdatePixelAP(Widget w, XEvent *event, String *params, 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); + sprintf(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 /* ARGSUSED */ +PopdownPixelAP(Widget w, XEvent *event, String *params, 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 /* ARGSUSED */ +SelectRegionAP(Widget w, XEvent *event, String *params, 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, XtIntervalId *id) /* ARGSUSED */ +{ + hlPtr data = (hlPtr)closure; + XGrabServer(dpy); + if (data->selectMode == drag) { + XDrawRectangle(dpy, DefaultRootWindow(dpy), data->gc, + data->x, data->y, data->width, data->height); + 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); + 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 /* ARGSUSED */ +CloseCB(Widget w, XtPointer clientData, XtPointer callData) +{ + Widget shell = (Widget)clientData; + if (!--numXmags) exit(0); + XtPopdown(shell); + XtDestroyWidget(shell); +} + + + +/* + * ReplaceCB() -- Replace this particular xmag dialog. + */ +static void /* ARGSUSED */ +ReplaceCB(Widget w, XtPointer clientData, XtPointer callData) +{ + hlPtr data = (hlPtr)clientData; + StartRootPtrGrab(False, data); +} + + + +/* + * NewCB() -- Create an additional xmag dialog. + */ +static void /* ARGSUSED */ +NewCB(Widget w, XtPointer clientData, XtPointer callData) +{ + StartRootPtrGrab(True, NULL); +} + + + +/* + * SelectCB() -- Own the primary selection. + */ +static void /* ARGSUSED */ +SelectCB(Widget w, XtPointer clientData, XtPointer callData) +{ + hlPtr data = (hlPtr)clientData; + SWGrabSelection(data->scaleInstance, XtLastTimestampProcessed(dpy)); +} + + + +/* + * PasteCB() -- Paste from the primary selectin into xmag. + */ +static void /* ARGSUSED */ +PasteCB(Widget w, XtPointer clientData, 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 = 1L; + selectGCV.subwindow_mode = IncludeInferiors; + selectGC = XtGetGC(toplevel, GCFunction|GCForeground|GCSubwindowMode, + &selectGCV); +} + + + +/* + * FindWindow() -- Determin window the pointer is over. + * + */ +static Window +FindWindow(int x, int y) /* Locatation 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, + Boolean *continue_to_dispatch) /* ARGSUSED */ +{ + 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 draging selection box. + */ +static void +DragEH(Widget w, XtPointer closure, XEvent *event, + Boolean *continue_to_dispatch) /* ARGSUSED */ +{ + 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 cretate a new scale instance? */ + hlPtr data) /* highligh 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 his 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 = data; + 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 determin 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 xInWin, yInWin; Window childWin; + XTranslateCoordinates(dpy, DefaultRootWindow(dpy), w, x, y, + &xInWin, &yInWin, &childWin); + /* avoid off screen pixels */ + if (x + data->win_info.x < 0) x = abs(data->win_info.x); + if (y + data->win_info.y < 0) y = abs(data->win_info.y); + 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; + data->image = XGetImage (dpy, + w, + xInWin, yInWin, + width, 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<ncolors; i++) { + (*colors)[i].pixel = red|green|blue; + (*colors)[i].pad = 0; + red += red1; + if (red > 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; i<ncolors; i++) { + (*colors)[i].pixel = i; + (*colors)[i].pad = 0; + } + } + + XQueryColors(dpy, win_info->colormap, *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; i<ncolors; i++) { + if ((int)Intensity(mptr) < (int)Intensity(tptr)) + mptr = tptr; + tptr++; + } + /* Null pointer protection */ + if(mptr) + return mptr->pixel; + 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<ncolors; i++) { + if ((int)Intensity(mptr) > (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 ("<Message>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() -- Determin 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 */ +} + + + +/* + * Main program. + */ +int +main(int argc, char *argv[]) +{ + XSetErrorHandler(Error); + + /* SUPPRESS 594 */ + 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) { + fprintf (stderr, + "usage: xmag [-source geom] [-mag magfactor] [-toolkitoption]\n"); + exit(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); +} |