summaryrefslogtreecommitdiff
path: root/xmag.c
diff options
context:
space:
mode:
authorKaleb Keithley <kaleb@freedesktop.org>2003-11-14 15:54:54 +0000
committerKaleb Keithley <kaleb@freedesktop.org>2003-11-14 15:54:54 +0000
commit31f434e2df14612e3cf18fe45a6c161eb3c225ff (patch)
tree65d53468220245d1fcfa6a593680ea183cf239e3 /xmag.c
R6.6 is the Xorg base-lineXORG-MAIN
Diffstat (limited to 'xmag.c')
-rw-r--r--xmag.c1125
1 files changed, 1125 insertions, 0 deletions
diff --git a/xmag.c b/xmag.c
new file mode 100644
index 0000000..7b77b6a
--- /dev/null
+++ b/xmag.c
@@ -0,0 +1,1125 @@
+/* $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.
+
+*/
+
+
+#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 "RootWin.h"
+#include "Scale.h"
+#include <X11/cursorfont.h>
+
+#include <stdio.h>
+#include <X11/Xmu/Error.h>
+
+#ifndef X_NOT_STDC_ENV
+#include <stdlib.h> /* for exit() and abs() */
+#endif
+
+#define SRCWIDTH 64
+#define SRCHEIGHT 64
+
+#define min(a, b) a < b ? a : b
+
+extern void SWGrabSelection();
+extern void SWRequestSelection();
+extern int SWGetImagePixel();
+
+
+
+/* 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;
+
+static XtIntervalId hlId;
+
+
+
+/* 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 void
+ CloseAP(),
+ SetCmapPropsAP(),
+ UnsetCmapPropsAP(),
+ NewAP(),
+ ReplaceAP(),
+ PopupPixelAP(),
+ UpdatePixelAP(),
+ PopdownPixelAP(),
+ SelectRegionAP(),
+ CheckPoints(),
+ HighlightTO(),
+ CloseCB(),
+ ReplaceCB(),
+ NewCB(),
+ SelectCB(),
+ SetupGC(),
+ ResizeEH(),
+ DragEH(),
+ StartRootPtrGrab(),
+ CreateRoot(),
+ GetImageAndAttributes(),
+ PopupNewScale(),
+ RedoOldScale(),
+ InitCursors(),
+ ParseSourceGeom();
+
+static Window
+ FindWindow();
+
+static int
+ Error(),
+ Get_XColors();
+
+static Pixel
+ GetMaxIntensity(),
+ GetMinIntensity();
+
+
+
+/* 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(dpy, err)
+ 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(w, event, params, num_params)
+ 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(w, event, params, num_params)
+ 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(w, event, params, num_params)
+ 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(w, event, params, num_params)
+ Widget w;
+ XEvent *event;
+ String *params;
+ Cardinal *num_params;
+{
+ StartRootPtrGrab(True, NULL);
+}
+
+
+
+/*
+ * ReplaceAP() -- Replace this particular xmag dialog.
+ */
+static void /* ARGSUSED */
+ReplaceAP(w, event, params, num_params)
+ 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(w, event, params, num_params)
+ 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);
+}
+
+
+
+/*
+ * UpdatePixelAP() -- Update pixel information.
+ */
+static void /* ARGSUSED */
+UpdatePixelAP(w, event, params, num_params)
+ 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 %d 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(w, event, params, num_params)
+ Widget w;
+ XEvent *event;
+ String *params;
+ Cardinal *num_params;
+{
+ int n;
+ Arg wargs[3];
+ hlPtr data;
+
+ n = 0;
+ XtSetArg(wargs[0], XtNuserData, &data); n++;
+ XtGetValues(w, wargs, n);
+ XtPopdown(data->pixShell);
+}
+
+
+
+static void /* ARGSUSED */
+SelectRegionAP(w, event, params, num_params)
+ 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(x1, x2, y1, y2)
+ Position *x1, *x2, *y1, *y2; /* Coordinates */
+{
+ 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(closure, id) /* ARGSUSED */
+ XtPointer closure; 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);
+ 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(w, clientData, callData)
+ Widget w; XtPointer clientData, callData;
+{
+ Widget shell = (Widget)clientData;
+ if (!--numXmags) exit(0);
+ XtPopdown(shell);
+ XtDestroyWidget(shell);
+}
+
+
+
+/*
+ * ReplaceCB() -- Replace this particular xmag dialog.
+ */
+static void /* ARGSUSED */
+ReplaceCB(w, clientData, callData)
+ Widget w; XtPointer clientData, callData;
+{
+ hlPtr data = (hlPtr)clientData;
+ StartRootPtrGrab(False, data);
+}
+
+
+
+/*
+ * NewCB() -- Create an additional xmag dialog.
+ */
+static void /* ARGSUSED */
+NewCB(w, clientData, callData)
+ Widget w; XtPointer clientData, callData;
+{
+ StartRootPtrGrab(True, NULL);
+}
+
+
+
+/*
+ * SelectCB() -- Own the primary selection.
+ */
+static void /* ARGSUSED */
+SelectCB(w, clientData, callData)
+ Widget w; XtPointer clientData, callData;
+{
+ hlPtr data = (hlPtr)clientData;
+ SWGrabSelection(data->scaleInstance, XtLastTimestampProcessed(dpy));
+}
+
+
+
+/*
+ * PasteCB() -- Paste from the primary selectin into xmag.
+ */
+static void /* ARGSUSED */
+PasteCB(w, clientData, callData)
+ Widget w; XtPointer clientData, callData;
+{
+ hlPtr data = (hlPtr)clientData;
+ SWRequestSelection(data->scaleInstance, XtLastTimestampProcessed(dpy));
+}
+
+
+
+/*
+ * SetupGC() -- Graphics context for magnification selection.
+ */
+static void
+SetupGC()
+{
+ 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(x, y)
+ int x, y; /* Locatation of cursor */
+{
+ XWindowAttributes wa;
+ Window findW = DefaultRootWindow(dpy), stopW, childW;
+ XTranslateCoordinates(dpy, findW, findW,
+ x, y, &x, &y, &stopW);
+ while (stopW) {
+ XTranslateCoordinates(dpy, findW, stopW,
+ x, y, &x, &y, &childW);
+ findW = stopW;
+ 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(w, closure, event, continue_to_dispatch) /* ARGSUSED */
+ Widget w; XtPointer closure; XEvent *event; 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 draging selection box.
+ */
+static void
+DragEH(w, closure, event, continue_to_dispatch) /* ARGSUSED */
+ Widget w; XtPointer closure; XEvent *event; 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(new, data)
+ Boolean 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);
+ hlId = 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()
+{
+ 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(w, x, y, width, height, data)
+ Window w; int x, y, width, 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(win_info, colors)
+ 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(data)
+ 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++;
+ }
+ return mptr->pixel;
+}
+
+/*
+ * GetMinIntensity() -- Find the minimum intensity pixel value for a colormap.
+ */
+static Pixel
+GetMinIntensity(data)
+ 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++;
+ }
+ return mptr->pixel;
+}
+
+
+
+
+static Widget pane1, pane2, pane3, cclose, replace, new, select_w, paste, label;
+
+/*
+ * PopupNewScale() -- Create and popup a new scale composite.
+ */
+static void
+PopupNewScale(data)
+ 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);
+ label = 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(data)
+ 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()
+{
+ 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()
+{
+ /* 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.
+ */
+void main(argc, argv)
+ 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);
+}