19aa228fdSmrg/*
29aa228fdSmrg
39aa228fdSmrgCopyright 1991, 1998  The Open Group
49aa228fdSmrg
59aa228fdSmrgPermission to use, copy, modify, distribute, and sell this software and its
69aa228fdSmrgdocumentation for any purpose is hereby granted without fee, provided that
79aa228fdSmrgthe above copyright notice appear in all copies and that both that
89aa228fdSmrgcopyright notice and this permission notice appear in supporting
99aa228fdSmrgdocumentation.
109aa228fdSmrg
119aa228fdSmrgThe above copyright notice and this permission notice shall be included
129aa228fdSmrgin all copies or substantial portions of the Software.
139aa228fdSmrg
149aa228fdSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
159aa228fdSmrgOR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
169aa228fdSmrgMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
179aa228fdSmrgIN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
189aa228fdSmrgOTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
199aa228fdSmrgARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
209aa228fdSmrgOTHER DEALINGS IN THE SOFTWARE.
219aa228fdSmrg
229aa228fdSmrgExcept as contained in this notice, the name of The Open Group shall
239aa228fdSmrgnot be used in advertising or otherwise to promote the sale, use or
249aa228fdSmrgother dealings in this Software without prior written authorization
259aa228fdSmrgfrom The Open Group.
269aa228fdSmrg
279aa228fdSmrg*/
289aa228fdSmrg
2915106172Smrg#ifdef HAVE_CONFIG_H
309aa228fdSmrg#include "config.h"
3115106172Smrg#endif
329aa228fdSmrg
339aa228fdSmrg#include <stdlib.h>		/* for exit() and abs() */
349aa228fdSmrg#include <stdio.h>
359aa228fdSmrg
369aa228fdSmrg#include <X11/Intrinsic.h>
379aa228fdSmrg#include <X11/StringDefs.h>
389aa228fdSmrg#include <X11/Xaw/Paned.h>
399aa228fdSmrg#include <X11/Xaw/Command.h>
409aa228fdSmrg#include <X11/Xaw/Label.h>
419aa228fdSmrg#include <X11/Shell.h>
429aa228fdSmrg#include <X11/cursorfont.h>
439aa228fdSmrg#include <X11/Xmu/Error.h>
449aa228fdSmrg#include "RootWin.h"
459aa228fdSmrg#include "Scale.h"
469aa228fdSmrg#include "CutPaste.h"
479aa228fdSmrg
489aa228fdSmrg#define SRCWIDTH  64
499aa228fdSmrg#define SRCHEIGHT 64
509aa228fdSmrg
519aa228fdSmrg#ifndef min
529aa228fdSmrg#define min(a, b) ((a) < (b) ? (a) : (b))
539aa228fdSmrg#endif
549aa228fdSmrg
5583d7c197Smrg#ifndef max
5683d7c197Smrg#define max(a, b) ((a) > (b) ? (a) : (b))
5783d7c197Smrg#endif
5883d7c197Smrg
599aa228fdSmrg
609aa228fdSmrg
619aa228fdSmrg/* highlight interval (in milliseconds) */
629aa228fdSmrg#define HLINTERVAL  100
639aa228fdSmrg
649aa228fdSmrg/* sleep between draw & erase of highlight
659aa228fdSmrg * 20 milliseconds - enough for screen refresh - not too long to annoy users
669aa228fdSmrg *  since we hold a server grab during this time
679aa228fdSmrg */
689aa228fdSmrg#define HLSLEEPINTERVAL 20 /* milliseconds */
699aa228fdSmrg
709aa228fdSmrg#ifdef HAVE_NANOSLEEP
719aa228fdSmrg#include <time.h>
729aa228fdSmrg#define HLSLEEP	    do { \
739aa228fdSmrg	struct timespec sleeptime = { 0 , HLSLEEPINTERVAL * 1000000 } ;	\
749aa228fdSmrg	nanosleep(&sleeptime, NULL); \
759aa228fdSmrg    } while(0)
769aa228fdSmrg#elif defined(HAVE_POLL)
779aa228fdSmrg#include <poll.h>
789aa228fdSmrg#define HLSLEEP	    poll(NULL, 0, HLSLEEPINTERVAL)
799aa228fdSmrg#elif defined(HAVE_SELECT)
809aa228fdSmrg#include <X11/Xpoll.h>
819aa228fdSmrg#define HLSLEEP	    do { \
829aa228fdSmrg	struct timeval sleeptime = { 0 , HLSLEEPINTERVAL * 1000 } ;	\
839aa228fdSmrg	select(0, NULL, NULL, NULL, &sleeptime); \
849aa228fdSmrg    } while(0)
859aa228fdSmrg#else
869aa228fdSmrg#define HLSLEEP	XSync(dpy, False)
879aa228fdSmrg#endif
889aa228fdSmrg
899aa228fdSmrg/* highlight mode */
900c7e83b2Smrgtypedef enum { drag, resize, done } hlMode;
919aa228fdSmrg
929aa228fdSmrg/* highlight data structure */
930c7e83b2Smrgtypedef struct {
949aa228fdSmrg  Boolean   newScale;
959aa228fdSmrg  hlMode    selectMode;
969aa228fdSmrg  GC        gc;
970c7e83b2Smrg  XWindowAttributes win_info;
989aa228fdSmrg  XImage     *image;
999aa228fdSmrg  Position  homeX, homeY, x, y;
1009aa228fdSmrg  Dimension width, height;
1019aa228fdSmrg  Widget    scaleShell, scaleInstance, pixShell, pixLabel, cmapWinList [2];
1029aa228fdSmrg  } hlStruct, *hlPtr;
1039aa228fdSmrg
1049aa228fdSmrg
1059aa228fdSmrg
1069aa228fdSmrg/* global variables */
1079aa228fdSmrgstatic XtAppContext app;
1089aa228fdSmrgstatic Cursor ulAngle, urAngle, lrAngle, llAngle;
1099aa228fdSmrgstatic Display *dpy;
1109aa228fdSmrgstatic int scr;
1110c7e83b2Smrgstatic GC selectGC;
1129aa228fdSmrgstatic XGCValues selectGCV;
1139aa228fdSmrgstatic Widget toplevel, root;
1149aa228fdSmrgstatic Atom wm_delete_window;
1159aa228fdSmrgstatic int numXmags = 0;
1169aa228fdSmrgstatic int srcStat, srcX, srcY;
1179aa228fdSmrgstatic unsigned int srcWidth, srcHeight;
1189aa228fdSmrg
1199aa228fdSmrg/* forward declarations */
1209aa228fdSmrg
1219aa228fdSmrgstatic int Error(Display *, XErrorEvent *);
1229aa228fdSmrgstatic void CloseAP(Widget, XEvent *, String *, Cardinal *);
1239aa228fdSmrgstatic void SetCmapPropsAP(Widget, XEvent *, String *, Cardinal *);
1249aa228fdSmrgstatic void UnsetCmapPropsAP(Widget, XEvent *, String *, Cardinal *);
1259aa228fdSmrgstatic void NewAP(Widget, XEvent *, String *, Cardinal *);
1269aa228fdSmrgstatic void ReplaceAP(Widget, XEvent *, String *, Cardinal *);
1279aa228fdSmrgstatic void PopupPixelAP(Widget, XEvent *, String *, Cardinal *);
1289aa228fdSmrgstatic void UpdatePixelAP(Widget, XEvent *, String *, Cardinal *);
1299aa228fdSmrgstatic void PopdownPixelAP(Widget, XEvent *, String *, Cardinal *);
1309aa228fdSmrgstatic void SelectRegionAP(Widget, XEvent *, String *, Cardinal *);
1319aa228fdSmrgstatic void CheckPoints(Position *, Position *, Position *, Position *);
1329aa228fdSmrgstatic void HighlightTO(XtPointer, XtIntervalId *);
1339aa228fdSmrgstatic void CloseCB(Widget, XtPointer, XtPointer);
1349aa228fdSmrgstatic void ReplaceCB(Widget, XtPointer, XtPointer);
1359aa228fdSmrgstatic void NewCB(Widget, XtPointer, XtPointer);
1369aa228fdSmrgstatic void SelectCB(Widget, XtPointer, XtPointer);
1379aa228fdSmrgstatic void PasteCB(Widget, XtPointer, XtPointer);
1389aa228fdSmrgstatic void SetupGC(void);
1399aa228fdSmrgstatic Window FindWindow(int, int);
1409aa228fdSmrgstatic void ResizeEH(Widget, XtPointer, XEvent *, Boolean *);
1419aa228fdSmrgstatic void DragEH(Widget, XtPointer, XEvent *, Boolean *);
1429aa228fdSmrgstatic void StartRootPtrGrab(int, hlPtr);
1439aa228fdSmrgstatic void CreateRoot(void);
1449aa228fdSmrgstatic void GetImageAndAttributes(Window, int, int, int, int, hlPtr);
1459aa228fdSmrgstatic int Get_XColors(XWindowAttributes *, XColor **);
1469aa228fdSmrgstatic Pixel GetMaxIntensity(hlPtr);
1479aa228fdSmrgstatic Pixel GetMinIntensity(hlPtr);
1489aa228fdSmrgstatic void PopupNewScale(hlPtr);
1499aa228fdSmrgstatic void RedoOldScale(hlPtr);
1509aa228fdSmrgstatic void InitCursors(void);
1519aa228fdSmrgstatic void ParseSourceGeom(void);
1529aa228fdSmrg
1539aa228fdSmrg/* application resources */
1549aa228fdSmrg
1559aa228fdSmrgtypedef struct { String geometry, source, mag, title; } OptionsRec;
1569aa228fdSmrgstatic OptionsRec options;
1579aa228fdSmrg
1589aa228fdSmrg#define Offset(field) XtOffsetOf(OptionsRec, field)
1599aa228fdSmrgstatic XtResource resources[] = {
1609aa228fdSmrg  {"geometry", "Geometry", XtRString, sizeof(String),
1619aa228fdSmrg     Offset(geometry), XtRString, (XtPointer)NULL},
1629aa228fdSmrg  {"mag", "Mag", XtRString, sizeof(String),
1639aa228fdSmrg     Offset(mag), XtRString, (XtPointer)"5.0"},
1649aa228fdSmrg  {"source", "Source", XtRString, sizeof(String),
1659aa228fdSmrg     Offset(source), XtRString, (XtPointer)"SRCWIDTHxSRCHEIGHT"},
1669aa228fdSmrg  {"title", XtCString, XtRString, sizeof(char *),
1679aa228fdSmrg     Offset(title), XtRString, "xmag"},
1689aa228fdSmrg};
1699aa228fdSmrg#undef Offset
1709aa228fdSmrg
1719aa228fdSmrgstatic XrmOptionDescRec optionDesc[] = {
1729aa228fdSmrg  {"-bd",         "*borderColor", XrmoptionSepArg, (XtPointer)NULL},
1739aa228fdSmrg  {"-bg",         "*background",   XrmoptionSepArg, (XtPointer)NULL},
1749aa228fdSmrg  {"-bw",         "*borderWidth", XrmoptionSepArg, (XtPointer)NULL},
1750c7e83b2Smrg
1769aa228fdSmrg  {"-geometry", "*geometry", XrmoptionSepArg, (XtPointer)NULL},
1779aa228fdSmrg  {"-mag",      "*mag",                XrmoptionSepArg, (XtPointer)NULL},
1789aa228fdSmrg  {"-source",   "*source",             XrmoptionSepArg, (XtPointer)NULL},
1799aa228fdSmrg  {"-title",    "*title",              XrmoptionSepArg, (XtPointer)NULL},
1809aa228fdSmrg};
1819aa228fdSmrg
1829aa228fdSmrg
1839aa228fdSmrg
1849aa228fdSmrg/* action table */
1859aa228fdSmrg
1869aa228fdSmrgstatic XtActionsRec actions_table[] = {
1879aa228fdSmrg  {"close", CloseAP},
1889aa228fdSmrg  {"set-colors", SetCmapPropsAP},
1899aa228fdSmrg  {"unset-colors", UnsetCmapPropsAP},
1909aa228fdSmrg  {"new", NewAP},
1919aa228fdSmrg  {"replace", ReplaceAP},
1929aa228fdSmrg  {"popup-pixel", PopupPixelAP},
1939aa228fdSmrg  {"update-pixel", UpdatePixelAP},
1949aa228fdSmrg  {"popdown-pixel", PopdownPixelAP},
1959aa228fdSmrg  {"select-region", SelectRegionAP}
1969aa228fdSmrg};
1979aa228fdSmrg
1989aa228fdSmrg
1999aa228fdSmrg
2009aa228fdSmrg/*
2010c7e83b2Smrg * Error() -- Error handler:  Catch a bad match in magnifying an
2029aa228fdSmrg *            area that contains bits of different depths.
2039aa228fdSmrg */
2040c7e83b2Smrgstatic int
205e2f3d188SmrgError(Display *display, XErrorEvent *err)
2069aa228fdSmrg{
207e2f3d188Smrg  (void) XmuPrintDefaultErrorMessage (display, err, stderr);
2089aa228fdSmrg  return 0;
2099aa228fdSmrg}
2109aa228fdSmrg
2119aa228fdSmrg
2129aa228fdSmrg/*
2139aa228fdSmrg * CloseAP() -- Close this dialog.  If its the last one exit the program.
2140c7e83b2Smrg *
2159aa228fdSmrg */
216e2f3d188Smrgstatic void
217e2f3d188SmrgCloseAP(Widget w, XEvent *event,
218e2f3d188Smrg        _X_UNUSED String *params, _X_UNUSED Cardinal *num_params)
2199aa228fdSmrg{
2209aa228fdSmrg  Arg wargs[2]; int n; hlPtr data;
2219aa228fdSmrg  if (!--numXmags) exit(0);
2229aa228fdSmrg  if (event->type != ClientMessage) {
2239aa228fdSmrg    n = 0;			/* get user data */
2249aa228fdSmrg    XtSetArg(wargs[0], XtNuserData, &data); n++;
2250c7e83b2Smrg    XtGetValues(w, wargs, n);
2269aa228fdSmrg    w = data->scaleShell;
2279aa228fdSmrg  }
2289aa228fdSmrg  XtPopdown(w);
2299aa228fdSmrg  XtDestroyWidget(w);
2309aa228fdSmrg}
2319aa228fdSmrg
2329aa228fdSmrg
2339aa228fdSmrg
2349aa228fdSmrg/*
2359aa228fdSmrg * SetCmapPropsAP() -- Put the scale widget first in WM_COLORMAP_WINDOWS
2360c7e83b2Smrg *
2379aa228fdSmrg */
238e2f3d188Smrgstatic void
239e2f3d188SmrgSetCmapPropsAP(Widget w, _X_UNUSED XEvent *event,
240e2f3d188Smrg               _X_UNUSED String *params, _X_UNUSED Cardinal *num_params)
2419aa228fdSmrg{
2429aa228fdSmrg  Arg wargs[2]; int n; hlPtr data;
2439aa228fdSmrg  n = 0;			/* get user data */
2449aa228fdSmrg  XtSetArg(wargs[0], XtNuserData, &data); n++;
2459aa228fdSmrg  XtGetValues(w, wargs, n);
2469aa228fdSmrg  if (data->win_info.colormap != DefaultColormap(dpy, scr)) {
2479aa228fdSmrg    data->cmapWinList[0] = data->scaleInstance;
2489aa228fdSmrg    data->cmapWinList[1] = data->scaleShell;
2499aa228fdSmrg    XtSetWMColormapWindows(data->scaleShell, data->cmapWinList, 2);
2509aa228fdSmrg  }
2519aa228fdSmrg}
2529aa228fdSmrg
2539aa228fdSmrg
2549aa228fdSmrg
2559aa228fdSmrg/*
2569aa228fdSmrg * UnsetCmapPropsAP() -- Put the shell first in WM_COLORMAP_WINDOWS
2570c7e83b2Smrg *
2589aa228fdSmrg */
259e2f3d188Smrgstatic void
260e2f3d188SmrgUnsetCmapPropsAP(Widget w, _X_UNUSED XEvent *event,
261e2f3d188Smrg                 _X_UNUSED String *params, _X_UNUSED Cardinal *num_params)
2629aa228fdSmrg{
2639aa228fdSmrg  Arg wargs[2]; int n; hlPtr data;
2649aa228fdSmrg  n = 0;			/* get user data */
2659aa228fdSmrg  XtSetArg(wargs[0], XtNuserData, &data); n++;
2669aa228fdSmrg  XtGetValues(w, wargs, n);
2679aa228fdSmrg  if (data->win_info.colormap != DefaultColormap(dpy, scr)) {
2689aa228fdSmrg    data->cmapWinList[0] = data->scaleShell;
2699aa228fdSmrg    data->cmapWinList[1] = data->scaleInstance;
2709aa228fdSmrg    XtSetWMColormapWindows(data->scaleShell, data->cmapWinList, 2);
2719aa228fdSmrg  }
2729aa228fdSmrg}
2739aa228fdSmrg
2749aa228fdSmrg
2759aa228fdSmrg
2769aa228fdSmrg/*
2779aa228fdSmrg * NewAP() -- Create an additional xmag dialog. THIS IS A COPY OF NewEH
2789aa228fdSmrg *                                              FIND A BETTER WAY....
2799aa228fdSmrg */
280e2f3d188Smrgstatic void
281e2f3d188SmrgNewAP(_X_UNUSED Widget w, _X_UNUSED XEvent *event,
282e2f3d188Smrg      _X_UNUSED String *params, _X_UNUSED Cardinal *num_params)
2839aa228fdSmrg{
2849aa228fdSmrg  StartRootPtrGrab(True, NULL);
2859aa228fdSmrg}
2869aa228fdSmrg
2879aa228fdSmrg
2889aa228fdSmrg
2899aa228fdSmrg/*
2909aa228fdSmrg * ReplaceAP() -- Replace this particular xmag dialog.
2919aa228fdSmrg */
292e2f3d188Smrgstatic void
293e2f3d188SmrgReplaceAP(Widget w, _X_UNUSED XEvent *event,
294e2f3d188Smrg          _X_UNUSED String *params, _X_UNUSED Cardinal *num_params)
2959aa228fdSmrg{
2969aa228fdSmrg  Arg wargs[2]; int n; hlPtr data;
2979aa228fdSmrg  n = 0;			/* get user data */
2989aa228fdSmrg  XtSetArg(wargs[0], XtNuserData, &data); n++;
2990c7e83b2Smrg  XtGetValues(w, wargs, n);
3009aa228fdSmrg  StartRootPtrGrab(False, data);
3019aa228fdSmrg}
3029aa228fdSmrg
3039aa228fdSmrg
3049aa228fdSmrg
3059aa228fdSmrg/*
3069aa228fdSmrg * PopupPixelAP() -- Show pixel information.
3079aa228fdSmrg */
308e2f3d188Smrgstatic void
309e2f3d188SmrgPopupPixelAP(Widget w, XEvent *event,
310e2f3d188Smrg             _X_UNUSED String *params, _X_UNUSED Cardinal *num_params)
3119aa228fdSmrg{
3129aa228fdSmrg    Position scale_x, scale_y;
3139aa228fdSmrg    Dimension scale_height;
3149aa228fdSmrg    Position label_x, label_y;
3159aa228fdSmrg    Dimension label_height;
3169aa228fdSmrg    int n;
3179aa228fdSmrg    Arg wargs[3];
3189aa228fdSmrg    hlPtr data;
3199aa228fdSmrg
3209aa228fdSmrg    n = 0;			/* get user data */
3219aa228fdSmrg    XtSetArg(wargs[0], XtNuserData, &data); n++;
3229aa228fdSmrg    XtGetValues(w, wargs, n);
3239aa228fdSmrg
3249aa228fdSmrg    n = 0;
3259aa228fdSmrg    XtSetArg(wargs[n], XtNheight, &scale_height); n++;
3269aa228fdSmrg    XtGetValues(w, wargs, n);
3279aa228fdSmrg    XtTranslateCoords(w, -1, -1, &scale_x, &scale_y);
3280c7e83b2Smrg
3299aa228fdSmrg    XtRealizeWidget(data->pixShell); /* to get the right height  */
3309aa228fdSmrg
3319aa228fdSmrg    n = 0;
3329aa228fdSmrg    XtSetArg(wargs[n], XtNheight, &label_height); n++;
3339aa228fdSmrg    XtGetValues(data->pixShell, wargs, n);
3340c7e83b2Smrg
3359aa228fdSmrg    if ((double) event->xbutton.y / (double) scale_height > 0.5) {
3369aa228fdSmrg	label_x = scale_x;
3379aa228fdSmrg	label_y = scale_y;
3389aa228fdSmrg    }
3399aa228fdSmrg    else {
3409aa228fdSmrg	label_x = scale_x;
3419aa228fdSmrg	label_y = scale_y + scale_height - label_height;
3429aa228fdSmrg    }
3439aa228fdSmrg
3449aa228fdSmrg    n = 0;
3459aa228fdSmrg    XtSetArg(wargs[n], XtNx, label_x); n++;
3469aa228fdSmrg    XtSetArg(wargs[n], XtNy, label_y); n++;
3479aa228fdSmrg    XtSetValues(data->pixShell, wargs, n);
34883d7c197Smrg
34983d7c197Smrg    UpdatePixelAP(w, event, NULL, NULL);
3509aa228fdSmrg}
3519aa228fdSmrg
3529aa228fdSmrg
3539aa228fdSmrg
3549aa228fdSmrg/*
3559aa228fdSmrg * UpdatePixelAP() -- Update pixel information.
3569aa228fdSmrg */
357e2f3d188Smrgstatic void
358e2f3d188SmrgUpdatePixelAP(Widget w, XEvent *event,
359e2f3d188Smrg              _X_UNUSED String *params, _X_UNUSED Cardinal *num_params)
3609aa228fdSmrg{
3619aa228fdSmrg    Position x, y;
3629aa228fdSmrg    Pixel pixel;
3639aa228fdSmrg    XColor color;
3649aa228fdSmrg    int n;
3659aa228fdSmrg    Arg wargs[3];
3669aa228fdSmrg    char string[80];
3679aa228fdSmrg    hlPtr data;
3689aa228fdSmrg
3699aa228fdSmrg    n = 0;
3709aa228fdSmrg    XtSetArg(wargs[0], XtNuserData, &data); n++;
3719aa228fdSmrg    XtGetValues(w, wargs, n);
3729aa228fdSmrg
3739aa228fdSmrg    if (SWGetImagePixel(w, event->xbutton.x, event->xbutton.y, &x, &y, &pixel))
3749aa228fdSmrg	XtPopdown(data->pixShell);
3759aa228fdSmrg    else {
3769aa228fdSmrg	color.pixel = pixel;
3779aa228fdSmrg	XQueryColor(dpy, data->win_info.colormap, &color);
3780c7e83b2Smrg	snprintf(string, sizeof(string),
3790c7e83b2Smrg		 "Pixel %ld at (%d,%d) colored (%x,%x,%x).",
3800c7e83b2Smrg		 pixel, x + data->x, y + data->y,
3810c7e83b2Smrg		 color.red, color.green, color.blue);
3829aa228fdSmrg	n = 0;
3830c7e83b2Smrg	XtSetArg(wargs[n], XtNlabel, string); n++;
3849aa228fdSmrg	XtSetValues(data->pixLabel, wargs, n);
3859aa228fdSmrg	XtPopup(data->pixShell, XtGrabNone);
3869aa228fdSmrg    }
3879aa228fdSmrg}
3889aa228fdSmrg
3899aa228fdSmrg
3909aa228fdSmrg
3919aa228fdSmrg/*
3929aa228fdSmrg * PopdownPixelAP() -- Remove pixel info.
3939aa228fdSmrg */
394e2f3d188Smrgstatic void
395e2f3d188SmrgPopdownPixelAP(Widget w, _X_UNUSED XEvent *event,
396e2f3d188Smrg               _X_UNUSED String *params, _X_UNUSED Cardinal *num_params)
3979aa228fdSmrg{
3989aa228fdSmrg  int n;
3999aa228fdSmrg  Arg wargs[3];
4009aa228fdSmrg  hlPtr data = NULL;
4010c7e83b2Smrg
4029aa228fdSmrg  n = 0;
4039aa228fdSmrg  XtSetArg(wargs[0], XtNuserData, &data); n++;
4049aa228fdSmrg  XtGetValues(w, wargs, n);
4059aa228fdSmrg
4069aa228fdSmrg  if (data)
4079aa228fdSmrg    XtPopdown(data->pixShell);
4089aa228fdSmrg}
4099aa228fdSmrg
4109aa228fdSmrg
4119aa228fdSmrg
412e2f3d188Smrgstatic void
413e2f3d188SmrgSelectRegionAP(_X_UNUSED Widget w, _X_UNUSED XEvent *event,
414e2f3d188Smrg               _X_UNUSED String *params, _X_UNUSED Cardinal *num_params)
4150c7e83b2Smrg{
4160c7e83b2Smrg/***** NOT SURE WHAT TO DO WITH THIS
4179aa228fdSmrg    if (app_resources.unmap)
4189aa228fdSmrg	XtUnmapWidget(toplevel);
4199aa228fdSmrg    Redisplay(XtDisplay(w), RootWindow(XtDisplay(w),
4209aa228fdSmrg				       DefaultScreen(XtDisplay(w))),
4210c7e83b2Smrg	      source.width, source.height,
4220c7e83b2Smrg	      app_resources.freq, app_resources.puls,
4239aa228fdSmrg	      ul_angle, lr_angle,
4249aa228fdSmrg	      app_resources.grab);
4259aa228fdSmrg
4269aa228fdSmrg    if (app_resources.unmap)
4279aa228fdSmrg	XtMapWidget(toplevel);
4289aa228fdSmrg******/
4299aa228fdSmrg}
4309aa228fdSmrg
4319aa228fdSmrg
4329aa228fdSmrg
4330c7e83b2Smrg/*
4349aa228fdSmrg * CheckPoints() -- Change the cursor for the correct quadrant.
4350c7e83b2Smrg *                  Make sure the first point is less than the second
4369aa228fdSmrg *                  for drawing the selection rectangle.
4379aa228fdSmrg *
4389aa228fdSmrg */
4390c7e83b2Smrgstatic void
4409aa228fdSmrgCheckPoints(Position *x1, Position *x2, Position *y1, Position *y2)
4419aa228fdSmrg{
4420c7e83b2Smrg  Position tmp;
4439aa228fdSmrg  Boolean above, left;
4449aa228fdSmrg  Cursor newC;
4450c7e83b2Smrg  above = (*y2 < *y1); left = (*x2 < *x1);
4469aa228fdSmrg  if (above&&left) newC = ulAngle;
4479aa228fdSmrg  else if (above&&!left) newC = urAngle;
4489aa228fdSmrg  else if (!above&&!left) newC = lrAngle;
4499aa228fdSmrg  else newC = llAngle;
4509aa228fdSmrg  XChangeActivePointerGrab
4519aa228fdSmrg    (dpy, PointerMotionMask|ButtonPressMask|ButtonReleaseMask,
4529aa228fdSmrg     newC, CurrentTime);
4539aa228fdSmrg  if (*x2 < *x1) { tmp = *x1; *x1 = *x2; *x2 = tmp; }
4549aa228fdSmrg  if (*y2 < *y1) { tmp = *y1; *y1 = *y2; *y2 = tmp; }
4559aa228fdSmrg}
4569aa228fdSmrg
4579aa228fdSmrg
4589aa228fdSmrg
4599aa228fdSmrg/*
4609aa228fdSmrg * HighlightTO() -- Timer to highlight the selection box
4619aa228fdSmrg */
4629aa228fdSmrgstatic void
463e2f3d188SmrgHighlightTO(XtPointer closure, _X_UNUSED XtIntervalId *id)
4649aa228fdSmrg{
4659aa228fdSmrg  hlPtr data = (hlPtr)closure;
4669aa228fdSmrg  XGrabServer(dpy);
4679aa228fdSmrg  if (data->selectMode == drag) {
4680c7e83b2Smrg    XDrawRectangle(dpy, DefaultRootWindow(dpy), data->gc,
4699aa228fdSmrg		   data->x, data->y, data->width, data->height);
4709aa228fdSmrg    XFlush(dpy);
4719aa228fdSmrg    HLSLEEP;
4720c7e83b2Smrg    XDrawRectangle(dpy, DefaultRootWindow(dpy), data->gc,
4739aa228fdSmrg		   data->x, data->y, data->width, data->height);
4749aa228fdSmrg  }
4750c7e83b2Smrg  else if (data->selectMode == resize) {
4769aa228fdSmrg    Position x1 = data->homeX,
4779aa228fdSmrg             x2 = data->x,
4789aa228fdSmrg             y1 = data->homeY,
4799aa228fdSmrg             y2 = data->y;
4809aa228fdSmrg    CheckPoints(&x1, &x2, &y1, &y2);
4810c7e83b2Smrg    XDrawRectangle(dpy, DefaultRootWindow(dpy), data->gc,
4829aa228fdSmrg		   x1, y1, x2 - x1, y2 - y1);
4839aa228fdSmrg    XFlush(dpy);
4849aa228fdSmrg    HLSLEEP;
4850c7e83b2Smrg    XDrawRectangle(dpy, DefaultRootWindow(dpy), data->gc,
4869aa228fdSmrg		   x1, y1, x2 - x1, y2 - y1);
4879aa228fdSmrg  }
4889aa228fdSmrg  XUngrabServer(dpy);
4899aa228fdSmrg  if (data->selectMode != done)
4909aa228fdSmrg    XtAppAddTimeOut(app, HLINTERVAL, HighlightTO, (XtPointer)data);
4919aa228fdSmrg}
4929aa228fdSmrg
4939aa228fdSmrg
4949aa228fdSmrg
4959aa228fdSmrg/*
4969aa228fdSmrg * CloseCB() -- Delete this xmag dialog.  If its the only one on the screen
4979aa228fdSmrg *             then exit.
4989aa228fdSmrg */
499e2f3d188Smrgstatic void
500e2f3d188SmrgCloseCB(_X_UNUSED Widget w, XtPointer clientData, _X_UNUSED XtPointer callData)
5019aa228fdSmrg{
5029aa228fdSmrg  Widget shell = (Widget)clientData;
5039aa228fdSmrg  if (!--numXmags) exit(0);
5049aa228fdSmrg  XtPopdown(shell);
5059aa228fdSmrg  XtDestroyWidget(shell);
5069aa228fdSmrg}
5079aa228fdSmrg
5089aa228fdSmrg
5099aa228fdSmrg
5109aa228fdSmrg/*
5119aa228fdSmrg * ReplaceCB() -- Replace this particular xmag dialog.
5129aa228fdSmrg */
513e2f3d188Smrgstatic void
514e2f3d188SmrgReplaceCB(_X_UNUSED Widget w, XtPointer clientData, _X_UNUSED XtPointer callData)
5159aa228fdSmrg{
5169aa228fdSmrg  hlPtr data = (hlPtr)clientData;
5179aa228fdSmrg  StartRootPtrGrab(False, data);
5189aa228fdSmrg}
5199aa228fdSmrg
5209aa228fdSmrg
5219aa228fdSmrg
5229aa228fdSmrg/*
5239aa228fdSmrg * NewCB() -- Create an additional xmag dialog.
5249aa228fdSmrg */
525e2f3d188Smrgstatic void
526e2f3d188SmrgNewCB(_X_UNUSED Widget w, _X_UNUSED XtPointer clientData, _X_UNUSED XtPointer callData)
5279aa228fdSmrg{
5289aa228fdSmrg  StartRootPtrGrab(True, NULL);
5299aa228fdSmrg}
5309aa228fdSmrg
5319aa228fdSmrg
5329aa228fdSmrg
5339aa228fdSmrg/*
5349aa228fdSmrg * SelectCB() -- Own the primary selection.
5359aa228fdSmrg */
536e2f3d188Smrgstatic void
537e2f3d188SmrgSelectCB(_X_UNUSED Widget w, XtPointer clientData, _X_UNUSED XtPointer callData)
5389aa228fdSmrg{
5399aa228fdSmrg  hlPtr data = (hlPtr)clientData;
5409aa228fdSmrg  SWGrabSelection(data->scaleInstance, XtLastTimestampProcessed(dpy));
5419aa228fdSmrg}
5429aa228fdSmrg
5439aa228fdSmrg
5449aa228fdSmrg
5459aa228fdSmrg/*
546f5087fa3Smrg * PasteCB() -- Paste from the primary selection into xmag.
5479aa228fdSmrg */
548e2f3d188Smrgstatic void
549e2f3d188SmrgPasteCB(_X_UNUSED Widget w, XtPointer clientData, _X_UNUSED XtPointer callData)
5509aa228fdSmrg{
5519aa228fdSmrg  hlPtr data = (hlPtr)clientData;
5529aa228fdSmrg  SWRequestSelection(data->scaleInstance, XtLastTimestampProcessed(dpy));
5539aa228fdSmrg}
5549aa228fdSmrg
5559aa228fdSmrg
5569aa228fdSmrg
5579aa228fdSmrg/*
5589aa228fdSmrg * SetupGC() -- Graphics context for magnification selection.
5599aa228fdSmrg */
5600c7e83b2Smrgstatic void
5619aa228fdSmrgSetupGC(void)
5629aa228fdSmrg{
5639aa228fdSmrg    selectGCV.function = GXxor;
5649aa228fdSmrg    selectGCV.foreground = 0xffffffff;
5659aa228fdSmrg    selectGCV.subwindow_mode = IncludeInferiors;
5669aa228fdSmrg    selectGC = XtGetGC(toplevel, GCFunction|GCForeground|GCSubwindowMode,
5679aa228fdSmrg		       &selectGCV);
5680c7e83b2Smrg}
5699aa228fdSmrg
5709aa228fdSmrg
5719aa228fdSmrg
5729aa228fdSmrg/*
5730c7e83b2Smrg * FindWindow() -- Determine window the pointer is over.
5749aa228fdSmrg *
5759aa228fdSmrg */
5760c7e83b2Smrgstatic Window
5770c7e83b2SmrgFindWindow(int x, int y)	/* Location of cursor */
5789aa228fdSmrg{
5799aa228fdSmrg  XWindowAttributes wa;
5809aa228fdSmrg  Window findW = DefaultRootWindow(dpy), stopW, childW;
5819aa228fdSmrg
5829aa228fdSmrg  /* Setup for first window find */
5839aa228fdSmrg  stopW = findW;
5849aa228fdSmrg
5859aa228fdSmrg  while (stopW) {
5860c7e83b2Smrg    XTranslateCoordinates(dpy, findW, stopW,
5879aa228fdSmrg			  x, y, &x, &y, &childW);
5889aa228fdSmrg    findW = stopW;
5899aa228fdSmrg    /* If child is not InputOutput (for example, InputOnly) */
5909aa228fdSmrg    /* then don't continue, return the present findW which */
5919aa228fdSmrg    /* can be the root, or a root child of class InputOutput */
5929aa228fdSmrg    if (childW &&
5939aa228fdSmrg	XGetWindowAttributes(dpy, childW, &wa) &&
5949aa228fdSmrg	wa.class != InputOutput)
5959aa228fdSmrg	break;
5969aa228fdSmrg    stopW = childW;
5979aa228fdSmrg  }
5989aa228fdSmrg  return findW;
5999aa228fdSmrg}
6009aa228fdSmrg
6019aa228fdSmrg
6029aa228fdSmrg
6039aa228fdSmrg/*
6049aa228fdSmrg * ResizeEH() -- Event Handler for resize of selection box.
6059aa228fdSmrg */
6060c7e83b2Smrgstatic void
6070c7e83b2SmrgResizeEH(Widget w, XtPointer closure, XEvent *event,
608e2f3d188Smrg	 _X_UNUSED Boolean *continue_to_dispatch)
6099aa228fdSmrg{
6109aa228fdSmrg  hlPtr data = (hlPtr)closure;
6119aa228fdSmrg  switch (event->type) {
6129aa228fdSmrg  case MotionNotify:
6139aa228fdSmrg    data->x = event->xmotion.x_root;
6140c7e83b2Smrg    data->y = event->xmotion.y_root;
6159aa228fdSmrg    break;
6169aa228fdSmrg  case ButtonRelease:
6179aa228fdSmrg    GetImageAndAttributes(FindWindow(event->xmotion.x_root,
6189aa228fdSmrg			event->xmotion.y_root),
6199aa228fdSmrg	     min(data->homeX,event->xbutton.x_root),
6209aa228fdSmrg	     min(data->homeY,event->xbutton.y_root),
6219aa228fdSmrg	     abs(data->homeX - event->xbutton.x_root),
6229aa228fdSmrg	     abs(data->homeY - event->xbutton.y_root),
6239aa228fdSmrg	     data);
6249aa228fdSmrg    if (data->newScale)
6259aa228fdSmrg      PopupNewScale(data);
6260c7e83b2Smrg    else
6279aa228fdSmrg      SWSetImage(data->scaleInstance, data->image);
6289aa228fdSmrg    XtUngrabPointer(w, CurrentTime);
6299aa228fdSmrg/*****
6309aa228fdSmrg    XtRemoveRawEventHandler(w, PointerMotionMask|ButtonReleaseMask,
6319aa228fdSmrg			 True, ResizeEH, (XtPointer)data);
6329aa228fdSmrg*****/
6339aa228fdSmrg    XtRemoveEventHandler(w, PointerMotionMask|ButtonReleaseMask,
6349aa228fdSmrg			 True, ResizeEH, (XtPointer)data);
6359aa228fdSmrg    data->selectMode = done;
6369aa228fdSmrg    break;
6379aa228fdSmrg  }
6389aa228fdSmrg}
6399aa228fdSmrg
6409aa228fdSmrg
6419aa228fdSmrg
6429aa228fdSmrg/*
6430c7e83b2Smrg * DragEH() -- Event Handler for dragging selection box.
6449aa228fdSmrg */
6450c7e83b2Smrgstatic void
6460c7e83b2SmrgDragEH(Widget w, XtPointer closure, XEvent *event,
647e2f3d188Smrg       _X_UNUSED Boolean *continue_to_dispatch)
6489aa228fdSmrg{
6499aa228fdSmrg  hlPtr data = (hlPtr)closure;
6509aa228fdSmrg  switch (event->type) {
6519aa228fdSmrg  case MotionNotify:		/* drag mode */
6529aa228fdSmrg    data->x = event->xmotion.x_root;
6539aa228fdSmrg    data->y = event->xmotion.y_root;
6549aa228fdSmrg    break;
6559aa228fdSmrg  case ButtonRelease:		/* end drag mode */
6569aa228fdSmrg    if (event->xbutton.button == Button1) { /* get image */
6579aa228fdSmrg      /* Problem: You can't get bits with XGetImage outside of its window.
6589aa228fdSmrg       *          xmag will only do a GetImage on the actual window in the case
6599aa228fdSmrg       *          where the depth of the window does not match the depth of
6609aa228fdSmrg       *          the root window.
6619aa228fdSmrg       */
6620c7e83b2Smrg      GetImageAndAttributes(FindWindow(event->xmotion.x_root,
6639aa228fdSmrg			  event->xmotion.y_root),
6640c7e83b2Smrg	       event->xbutton.x_root,
6659aa228fdSmrg	       event->xbutton.y_root,
6669aa228fdSmrg	       srcWidth, srcHeight, data);
6679aa228fdSmrg      if (data->newScale)
6689aa228fdSmrg	PopupNewScale(data);
6699aa228fdSmrg      else
6709aa228fdSmrg	RedoOldScale(data);
6719aa228fdSmrg      XtUngrabPointer(w, CurrentTime);
6729aa228fdSmrg      XtRemoveRawEventHandler(w, PointerMotionMask|ButtonPressMask|
6739aa228fdSmrg			      ButtonReleaseMask, True, DragEH,
6749aa228fdSmrg			      (XtPointer)data);
6759aa228fdSmrg      data->selectMode = done;
6769aa228fdSmrg    }
6779aa228fdSmrg
6789aa228fdSmrg    break;
6790c7e83b2Smrg  case ButtonPress:
6809aa228fdSmrg    if (event->xbutton.button == Button2) {	/* turn on resize mode */
6810c7e83b2Smrg      data->homeX = event->xbutton.x_root;
6829aa228fdSmrg      data->homeY = event->xbutton.y_root;
6839aa228fdSmrg      data->x = event->xbutton.x_root + srcWidth;
6840c7e83b2Smrg      data->y = event->xbutton.y_root + srcHeight;
6859aa228fdSmrg      data->selectMode = resize;
6869aa228fdSmrg      XtRemoveRawEventHandler(w, PointerMotionMask|ButtonPressMask|
6879aa228fdSmrg			   ButtonReleaseMask, True, DragEH, (XtPointer)data);
6889aa228fdSmrg      XChangeActivePointerGrab
6899aa228fdSmrg	(dpy, PointerMotionMask|ButtonPressMask|ButtonReleaseMask,
6909aa228fdSmrg	 lrAngle, CurrentTime);
6910c7e83b2Smrg      XWarpPointer(dpy, None, None, 0, 0, 0, 0,
6929aa228fdSmrg		   srcWidth, srcHeight);
6930c7e83b2Smrg      XtAddEventHandler(w, PointerMotionMask|ButtonReleaseMask,
6949aa228fdSmrg			True, ResizeEH, (XtPointer)data);
6959aa228fdSmrg    }
6969aa228fdSmrg    break;
6979aa228fdSmrg  }
6989aa228fdSmrg}
6999aa228fdSmrg
7009aa228fdSmrg
7019aa228fdSmrg
7029aa228fdSmrg
7039aa228fdSmrg/*
7049aa228fdSmrg * StartRootPtrGrab() -- Bring up the selection box.
7050c7e83b2Smrg *
7069aa228fdSmrg */
7079aa228fdSmrgstatic void
7080c7e83b2SmrgStartRootPtrGrab(int new, 	/* do we create a new scale instance? */
7090c7e83b2Smrg		 hlPtr data)	/* highlight data */
7109aa228fdSmrg{
7119aa228fdSmrg  Window    rootR, childR;
7129aa228fdSmrg  int       rootX, rootY, winX, winY;
7139aa228fdSmrg  unsigned  int mask;
7149aa228fdSmrg  hlPtr hlData;
7159aa228fdSmrg  XtGrabPointer
7169aa228fdSmrg    (root, False,
7179aa228fdSmrg     PointerMotionMask|ButtonPressMask|ButtonReleaseMask,
7189aa228fdSmrg     GrabModeAsync, GrabModeAsync, None, ulAngle, CurrentTime);
7190c7e83b2Smrg  XQueryPointer(dpy, DefaultRootWindow(dpy), &rootR, &childR,
7209aa228fdSmrg		&rootX, &rootY, &winX, &winY, &mask);
7219aa228fdSmrg  if (new) {
7229aa228fdSmrg    numXmags++;
7239aa228fdSmrg    hlData = (hlPtr)XtMalloc(sizeof(hlStruct));
7249aa228fdSmrg  }
7259aa228fdSmrg  else hlData = data;
7269aa228fdSmrg  hlData->newScale   = new;
7279aa228fdSmrg  hlData->selectMode = drag;
7289aa228fdSmrg  hlData->x          = rootX;
7299aa228fdSmrg  hlData->y          = rootY;
7309aa228fdSmrg  hlData->gc         = selectGC;
7319aa228fdSmrg  hlData->width      = srcWidth;
7329aa228fdSmrg  hlData->height     = srcHeight;
7339aa228fdSmrg  XtAddRawEventHandler
7340c7e83b2Smrg    (root, PointerMotionMask|ButtonPressMask|ButtonReleaseMask,
7359aa228fdSmrg     True, DragEH, (XtPointer)hlData);
7369aa228fdSmrg  (void) XtAppAddTimeOut(app, HLINTERVAL, HighlightTO, (XtPointer)hlData);
7379aa228fdSmrg}
7389aa228fdSmrg
7399aa228fdSmrg
7409aa228fdSmrg
7419aa228fdSmrg/*
7429aa228fdSmrg * CreateRoot() -- Create a root window widget. If the user specified x and y
7430c7e83b2Smrg *                 in the source geometry then use this to directly get the
7449aa228fdSmrg *                 image.
7459aa228fdSmrg */
7469aa228fdSmrgstatic void
7479aa228fdSmrgCreateRoot(void)
7489aa228fdSmrg{
7499aa228fdSmrg  hlPtr data;
7509aa228fdSmrg  root = XtCreateWidget("root", rootWindowWidgetClass, toplevel, NULL, 0);
7519aa228fdSmrg  XtRealizeWidget(root);
7520c7e83b2Smrg  if (XValue & srcStat && YValue &srcStat) {
7539aa228fdSmrg    numXmags = 1;
7549aa228fdSmrg    data = (hlPtr)XtMalloc(sizeof(hlStruct));
755e2f3d188Smrg
7569aa228fdSmrg    data->newScale   = True;
7579aa228fdSmrg    data->selectMode = drag;
7589aa228fdSmrg    data->x          = srcX;
7599aa228fdSmrg    data->y          = srcY;
7609aa228fdSmrg    data->gc         = selectGC;
7619aa228fdSmrg    data->width      = srcWidth;
7629aa228fdSmrg    data->height     = srcHeight;
7630c7e83b2Smrg    GetImageAndAttributes(RootWindow(dpy, scr), srcX, srcY, srcWidth,
7649aa228fdSmrg			  srcHeight, data);
7659aa228fdSmrg    PopupNewScale(data);
7669aa228fdSmrg    return;
7679aa228fdSmrg  }
7689aa228fdSmrg}
7699aa228fdSmrg
7709aa228fdSmrg
7710c7e83b2Smrg/*
7729aa228fdSmrg * GetImageAndAttributes() -- Get the image bits from the screen.
7730c7e83b2Smrg *               We will also determine here the colormap, depth, and
7740c7e83b2Smrg *               visual to be used for the magnification image.
7759aa228fdSmrg */
7760c7e83b2Smrgstatic void
7770c7e83b2SmrgGetImageAndAttributes(Window w, int x, int y, int width, int height,
7789aa228fdSmrg		      hlPtr data)
7799aa228fdSmrg{
78083d7c197Smrg    /* get parameters of window being magnified */
78183d7c197Smrg    XGetWindowAttributes(dpy, w, &data->win_info);
78283d7c197Smrg
78383d7c197Smrg    if (data->win_info.depth == DefaultDepth(dpy, scr)) {
78483d7c197Smrg	/* avoid off screen pixels */
78583d7c197Smrg	if (x < 0)
78683d7c197Smrg	    x = 0;
78783d7c197Smrg	if (y < 0)
78883d7c197Smrg	    y = 0;
78983d7c197Smrg	if (x + width > DisplayWidth(dpy,scr))
79083d7c197Smrg	    x = DisplayWidth(dpy,scr) - width;
79183d7c197Smrg	if (y + height > DisplayHeight(dpy,scr))
79283d7c197Smrg	    y = DisplayHeight(dpy,scr) - height;
79383d7c197Smrg	data->x = x; data->y = y;
79483d7c197Smrg	/* get image pixels */
79583d7c197Smrg	data->image = XGetImage (dpy,
79683d7c197Smrg				 RootWindow(dpy, scr),
79783d7c197Smrg				 x, y,
79883d7c197Smrg				 width, height,
79983d7c197Smrg				 AllPlanes, ZPixmap);
80083d7c197Smrg    }
80183d7c197Smrg    else {
80283d7c197Smrg	int	t0, t1;
80383d7c197Smrg	int	x0, x1, y0, y1;
80483d7c197Smrg	int	xInWin, yInWin;
80583d7c197Smrg	Window	childWin;
80683d7c197Smrg
80783d7c197Smrg	XTranslateCoordinates(dpy, DefaultRootWindow(dpy), w, x, y,
80883d7c197Smrg			      &xInWin, &yInWin, &childWin);
80983d7c197Smrg
81083d7c197Smrg	/* Avoid off screen pixels. Assume this routine is not
81183d7c197Smrg	 * called for totally offscreen windows. */
81283d7c197Smrg	x0 = max(x, 0);
81383d7c197Smrg	y0 = max(y, 0);
81483d7c197Smrg	x1 = min(DisplayWidth(dpy, scr),
81583d7c197Smrg		 min(x0 + width, x0 + (data->win_info.width - xInWin)));
81683d7c197Smrg	y1 = min(DisplayHeight(dpy, scr),
81783d7c197Smrg		 min(y0 + height, y0 + (data->win_info.height - yInWin)));
81883d7c197Smrg
81983d7c197Smrg	/* Try to use up to width x height pixels */
82083d7c197Smrg	if (x1 - x0 < width) {
82183d7c197Smrg	    t0 = x0;
82283d7c197Smrg	    t1 = max(0, x - xInWin + data->win_info.width -
82383d7c197Smrg		     DisplayWidth(dpy, scr));
82483d7c197Smrg	    x0 = max(0, x1 - min(width, data->win_info.width - t1));
82583d7c197Smrg	    xInWin -= t0 - x0;
82683d7c197Smrg	}
82783d7c197Smrg	if (y1 - y0 < height) {
82883d7c197Smrg	    t0 = y0;
82983d7c197Smrg	    t1 = max(0, y - yInWin + data->win_info.height -
83083d7c197Smrg		     DisplayHeight(dpy, scr));
83183d7c197Smrg	    y0 = max(0, y1 - min(height, data->win_info.height - t1));
83283d7c197Smrg	    yInWin -= t0 - y0;
83383d7c197Smrg	}
83483d7c197Smrg
83583d7c197Smrg	data->x = x0;
83683d7c197Smrg	data->y = y0;
83783d7c197Smrg	data->width = x1 - x0;
83883d7c197Smrg	data->height = y1 - y0;
83983d7c197Smrg
84083d7c197Smrg	data->image = XGetImage (dpy,
84183d7c197Smrg				 w,
84283d7c197Smrg				 xInWin, yInWin,
84383d7c197Smrg				 data->width, data->height,
84483d7c197Smrg				 AllPlanes, ZPixmap);
84583d7c197Smrg
84683d7c197Smrg    }
8479aa228fdSmrg}
8489aa228fdSmrg
8499aa228fdSmrg
8509aa228fdSmrg
8519aa228fdSmrg/*
8529aa228fdSmrg * Get_XColors() Get the XColors of all pixels in image - returns # of colors
8539aa228fdSmrg *               This function was taken from xwd (thanks Bob...)
8549aa228fdSmrg */
8559aa228fdSmrg#define lowbit(x) ((x) & (~(x) + 1))
8560c7e83b2Smrgstatic int
8579aa228fdSmrgGet_XColors(XWindowAttributes *win_info, XColor **colors)
8589aa228fdSmrg{
8599aa228fdSmrg    int i, ncolors;
8600c7e83b2Smrg
8619aa228fdSmrg    if (!win_info->colormap)
8629aa228fdSmrg        return(0);
8630c7e83b2Smrg
8649aa228fdSmrg    ncolors = win_info->visual->map_entries;
8659aa228fdSmrg    if (!(*colors = (XColor *) XtMalloc (sizeof(XColor) * ncolors)))
8669aa228fdSmrg      XtError("Out of memory!");
8670c7e83b2Smrg
8689aa228fdSmrg    if (win_info->visual->class == DirectColor ||
8699aa228fdSmrg        win_info->visual->class == TrueColor) {
8709aa228fdSmrg        Pixel red, green, blue, red1, green1, blue1;
8710c7e83b2Smrg
8729aa228fdSmrg        red = green = blue = 0;
8739aa228fdSmrg        red1 = lowbit(win_info->visual->red_mask);
8749aa228fdSmrg        green1 = lowbit(win_info->visual->green_mask);
8759aa228fdSmrg        blue1 = lowbit(win_info->visual->blue_mask);
8769aa228fdSmrg        for (i=0; i<ncolors; i++) {
8779aa228fdSmrg          (*colors)[i].pixel = red|green|blue;
8789aa228fdSmrg          (*colors)[i].pad = 0;
8799aa228fdSmrg          red += red1;
8809aa228fdSmrg          if (red > win_info->visual->red_mask)
8819aa228fdSmrg            red = 0;
8829aa228fdSmrg          green += green1;
8839aa228fdSmrg          if (green > win_info->visual->green_mask)
8849aa228fdSmrg            green = 0;
8859aa228fdSmrg          blue += blue1;
8869aa228fdSmrg          if (blue > win_info->visual->blue_mask)
8879aa228fdSmrg            blue = 0;
8889aa228fdSmrg        }
8899aa228fdSmrg    } else {
8909aa228fdSmrg        for (i=0; i<ncolors; i++) {
8919aa228fdSmrg          (*colors)[i].pixel = i;
8929aa228fdSmrg          (*colors)[i].pad = 0;
8939aa228fdSmrg        }
8949aa228fdSmrg    }
8950c7e83b2Smrg
8969aa228fdSmrg    XQueryColors(dpy, win_info->colormap, *colors, ncolors);
8970c7e83b2Smrg
8989aa228fdSmrg    return(ncolors);
8999aa228fdSmrg}
9009aa228fdSmrg
9019aa228fdSmrg
9029aa228fdSmrg
9039aa228fdSmrg#define Intensity(cptr) (3.0*cptr->red+0.59*cptr->green+0.11*cptr->blue)
9049aa228fdSmrg
9059aa228fdSmrg/*
9069aa228fdSmrg * GetMaxIntensity() -- Find the maximum intensity pixel value for a colormap.
9079aa228fdSmrg */
9089aa228fdSmrgstatic Pixel
9099aa228fdSmrgGetMaxIntensity(hlPtr data)
9109aa228fdSmrg{
9119aa228fdSmrg  XColor *colors = NULL, *mptr, *tptr;
9129aa228fdSmrg  int i, ncolors;
9139aa228fdSmrg
9140c7e83b2Smrg  if (data->win_info.colormap == DefaultColormap(dpy, scr))
9159aa228fdSmrg    return WhitePixel(dpy, scr);
9160c7e83b2Smrg  ncolors = Get_XColors(&data->win_info, &colors);
9179aa228fdSmrg  mptr = tptr = colors; tptr++;
9189aa228fdSmrg  for (i=1; i<ncolors; i++) {
9190c7e83b2Smrg    if ((int)Intensity(mptr) < (int)Intensity(tptr))
9209aa228fdSmrg      mptr = tptr;
9219aa228fdSmrg    tptr++;
9229aa228fdSmrg  }
9239aa228fdSmrg  /* Null pointer protection */
9249aa228fdSmrg  if(mptr)
9259aa228fdSmrg    return mptr->pixel;
9269aa228fdSmrg  else
9279aa228fdSmrg    return WhitePixel(dpy, scr);
9289aa228fdSmrg}
9299aa228fdSmrg
9309aa228fdSmrg/*
9319aa228fdSmrg * GetMinIntensity() -- Find the minimum intensity pixel value for a colormap.
9329aa228fdSmrg */
9339aa228fdSmrgstatic Pixel
9349aa228fdSmrgGetMinIntensity(hlPtr data)
9359aa228fdSmrg{
9369aa228fdSmrg  XColor *colors = NULL, *mptr, *tptr;
9379aa228fdSmrg  int i, ncolors;
9389aa228fdSmrg
9390c7e83b2Smrg  if (data->win_info.colormap == DefaultColormap(dpy, scr))
9409aa228fdSmrg    return BlackPixel(dpy, scr);
9410c7e83b2Smrg  ncolors = Get_XColors(&data->win_info, &colors);
9429aa228fdSmrg  mptr = tptr = colors; tptr++;
9439aa228fdSmrg  for (i=1; i<ncolors; i++)  {
9449aa228fdSmrg    if ((int)Intensity(mptr) > (int)Intensity(tptr))
9450c7e83b2Smrg      mptr = tptr;
9469aa228fdSmrg    tptr++;
9479aa228fdSmrg  }
9489aa228fdSmrg  /* Null pointer protection */
9499aa228fdSmrg  if(mptr)
9509aa228fdSmrg    return mptr->pixel;
9519aa228fdSmrg  else
9529aa228fdSmrg    return BlackPixel(dpy, scr);
9539aa228fdSmrg}
9549aa228fdSmrg
9559aa228fdSmrg
9569aa228fdSmrg
9579aa228fdSmrg
9589aa228fdSmrgstatic Widget pane1, pane2, pane3, cclose, replace, new, select_w, paste;
9599aa228fdSmrg
9609aa228fdSmrg/*
9619aa228fdSmrg * PopupNewScale() -- Create and popup a new scale composite.
9629aa228fdSmrg */
9630c7e83b2Smrgstatic void
9649aa228fdSmrgPopupNewScale(hlPtr data)
9659aa228fdSmrg{
9669aa228fdSmrg  Arg warg;
9679aa228fdSmrg
9680c7e83b2Smrg  data->scaleShell =
9690c7e83b2Smrg    XtVaCreatePopupShell("xmag", topLevelShellWidgetClass, toplevel,
9709aa228fdSmrg			 XtNgeometry, (XtArgVal)options.geometry,
9719aa228fdSmrg			 XtNtitle, (XtArgVal)options.title,
9729aa228fdSmrg			 NULL);
9739aa228fdSmrg  pane1 = XtCreateManagedWidget("pane1", panedWidgetClass, data->scaleShell,
9749aa228fdSmrg				(Arg *) NULL, 0);
9759aa228fdSmrg  pane2 = XtCreateManagedWidget("pane2", panedWidgetClass, pane1,
9769aa228fdSmrg				(Arg *) NULL, 0);
9779aa228fdSmrg  cclose = XtCreateManagedWidget("close", commandWidgetClass, pane2,
9789aa228fdSmrg				 (Arg *) NULL, 0);
9799aa228fdSmrg  XtAddCallback(cclose, XtNcallback, CloseCB, (XtPointer)data->scaleShell);
9809aa228fdSmrg  replace = XtCreateManagedWidget("replace", commandWidgetClass, pane2,
9819aa228fdSmrg				  (Arg *) NULL, 0);
9829aa228fdSmrg  XtAddCallback(replace, XtNcallback, ReplaceCB, (XtPointer)data);
9839aa228fdSmrg  new = XtCreateManagedWidget("new", commandWidgetClass, pane2,
9849aa228fdSmrg			      (Arg *) NULL, 0);
9859aa228fdSmrg  XtAddCallback(new, XtNcallback, NewCB, (XtPointer)NULL);
9869aa228fdSmrg  select_w = XtCreateManagedWidget("select", commandWidgetClass, pane2,
9879aa228fdSmrg			      (Arg *) NULL, 0);
9889aa228fdSmrg  XtAddCallback(select_w, XtNcallback, SelectCB, (XtPointer)data);
9899aa228fdSmrg  paste = XtCreateManagedWidget("paste", commandWidgetClass, pane2,
9909aa228fdSmrg			      (Arg *) NULL, 0);
9919aa228fdSmrg  XtAddCallback(paste, XtNcallback, PasteCB, (XtPointer)data);
9929aa228fdSmrg  (void) XtCreateManagedWidget("helpLabel", labelWidgetClass, pane2,
9939aa228fdSmrg			       (Arg *) NULL, 0);
9949aa228fdSmrg  pane3 = XtCreateManagedWidget("pane2", panedWidgetClass, pane1,
9959aa228fdSmrg				(Arg *) NULL, 0);
9960c7e83b2Smrg  data->scaleInstance =
9970c7e83b2Smrg    XtVaCreateManagedWidget("scale", scaleWidgetClass,
9989aa228fdSmrg			    pane3,
9999aa228fdSmrg			    XtNvisual, (XtArgVal)data->win_info.visual,
10009aa228fdSmrg			    XtNcolormap, (XtArgVal)data->win_info.colormap,
10019aa228fdSmrg			    XtNdepth, (XtArgVal)data->win_info.depth,
10029aa228fdSmrg			    XtNscaleX, (XtArgVal)options.mag,
10039aa228fdSmrg			    XtNscaleY, (XtArgVal)options.mag,
10049aa228fdSmrg			    NULL);
10059aa228fdSmrg  SWSetImage(data->scaleInstance, data->image);
10069aa228fdSmrg  XtOverrideTranslations
10079aa228fdSmrg    (data->scaleShell,
10089aa228fdSmrg     XtParseTranslationTable ("<Message>WM_PROTOCOLS: close()"));
10099aa228fdSmrg  XtSetArg(warg, XtNuserData, data);
10109aa228fdSmrg  XtSetValues(data->scaleInstance, &warg, 1);
10110c7e83b2Smrg  data->pixShell =
10120c7e83b2Smrg    XtVaCreatePopupShell("pixShell", overrideShellWidgetClass,
10139aa228fdSmrg			 toplevel,
10149aa228fdSmrg			 XtNvisual, (XtArgVal)data->win_info.visual,
10159aa228fdSmrg			 XtNcolormap, (XtArgVal)data->win_info.colormap,
10169aa228fdSmrg			 XtNdepth, (XtArgVal)data->win_info.depth,
10179aa228fdSmrg			 XtNborderWidth, (XtPointer)0,
10189aa228fdSmrg			 NULL);
10190c7e83b2Smrg  data->pixLabel =
10200c7e83b2Smrg    XtVaCreateManagedWidget("pixLabel", labelWidgetClass,
10210c7e83b2Smrg			    data->pixShell,
10229aa228fdSmrg			    XtNforeground, (XtPointer)GetMaxIntensity(data),
10239aa228fdSmrg			    XtNbackground, (XtPointer)GetMinIntensity(data),
10249aa228fdSmrg			    XtNborderWidth, (XtPointer)0,
10259aa228fdSmrg			    NULL);
10269aa228fdSmrg  XtInstallAllAccelerators(pane1, pane1);	/* install accelerators */
10279aa228fdSmrg  if (data->newScale) {
10289aa228fdSmrg    XtPopup(data->scaleShell, XtGrabNone);
10299aa228fdSmrg    (void) XSetWMProtocols	/* ICCCM delete window */
10309aa228fdSmrg      (dpy, XtWindow(data->scaleShell), &wm_delete_window, 1);
10319aa228fdSmrg  }
10329aa228fdSmrg  if (data->win_info.colormap != DefaultColormap(dpy, scr)) {
10330c7e83b2Smrg    data->cmapWinList[0] = data->scaleShell;
10349aa228fdSmrg    data->cmapWinList[1] = data->scaleInstance;
10359aa228fdSmrg    XtSetWMColormapWindows(data->scaleShell, data->cmapWinList, 2);
10369aa228fdSmrg  }
10379aa228fdSmrg}
10389aa228fdSmrg
10399aa228fdSmrg
10409aa228fdSmrg
10419aa228fdSmrg/*
10429aa228fdSmrg * RedoOldScale() -- If the visual, depth, or colormap has changed, unrealize
10439aa228fdSmrg *                   the scale widget and change its colormap/depth/visual.
10449aa228fdSmrg *                   Then re-realize it.  Also do this for the pixel display
10459aa228fdSmrg *                   widget.
10469aa228fdSmrg */
10479aa228fdSmrgstatic void
10489aa228fdSmrgRedoOldScale(hlPtr data)
10499aa228fdSmrg{
10509aa228fdSmrg  Arg wargs[3];
10519aa228fdSmrg  int n;
10529aa228fdSmrg  Visual *oldVis;
10539aa228fdSmrg  int oldDepth;
10549aa228fdSmrg  Colormap oldCmap;
10559aa228fdSmrg
10569aa228fdSmrg  n=0;
10579aa228fdSmrg  XtSetArg(wargs[n], XtNvisual, &oldVis); n++;
10589aa228fdSmrg  XtSetArg(wargs[n], XtNdepth, &oldDepth); n++;
10599aa228fdSmrg  XtSetArg(wargs[n], XtNcolormap, &oldCmap); n++;
10600c7e83b2Smrg  XtGetValues(data->scaleInstance, wargs, n);
10619aa228fdSmrg  if (oldVis == data->win_info.visual && oldDepth == data->win_info.depth
10629aa228fdSmrg      && oldCmap == data->win_info.colormap) {
10630c7e83b2Smrg    SWSetImage(data->scaleInstance, data->image);
10649aa228fdSmrg    return;
10659aa228fdSmrg  }
10669aa228fdSmrg  /* get width and height, save and reuse them */
10679aa228fdSmrg  XtUnmanageChild(data->scaleInstance);
10689aa228fdSmrg  XtUnrealizeWidget(data->scaleInstance);
10699aa228fdSmrg  n=0;
10709aa228fdSmrg  XtSetArg(wargs[n], XtNcolormap, data->win_info.colormap); n++;
10719aa228fdSmrg  XtSetArg(wargs[n], XtNdepth, data->win_info.depth); n++;
10729aa228fdSmrg  XtSetArg(wargs[n], XtNvisual, data->win_info.visual); n++;
10739aa228fdSmrg  XtSetValues(data->scaleInstance, wargs, n);
10749aa228fdSmrg  n=0;
10759aa228fdSmrg  XtSetArg(wargs[n], XtNforeground, GetMaxIntensity(data)); n++;
10769aa228fdSmrg  XtSetArg(wargs[n], XtNbackground, GetMinIntensity(data)); n++;
10779aa228fdSmrg  XtSetValues(data->pixLabel, wargs, n);
10780c7e83b2Smrg  SWSetImage(data->scaleInstance, data->image);
10799aa228fdSmrg  XtRealizeWidget(data->scaleInstance);
10809aa228fdSmrg  XtManageChild(data->scaleInstance);
10819aa228fdSmrg}
10829aa228fdSmrg
10839aa228fdSmrg
10849aa228fdSmrg
10859aa228fdSmrg/*
10869aa228fdSmrg * InitCursors() -- Create our cursors for area selection.
10879aa228fdSmrg */
10889aa228fdSmrgstatic void
10899aa228fdSmrgInitCursors(void)
10909aa228fdSmrg{
10919aa228fdSmrg  ulAngle = XCreateFontCursor(dpy, XC_ul_angle);
10929aa228fdSmrg  urAngle = XCreateFontCursor(dpy, XC_ur_angle);
10939aa228fdSmrg  lrAngle = XCreateFontCursor(dpy, XC_lr_angle);
10949aa228fdSmrg  llAngle = XCreateFontCursor(dpy, XC_ll_angle);
10959aa228fdSmrg}
10969aa228fdSmrg
10979aa228fdSmrg
10989aa228fdSmrg
10999aa228fdSmrg/*
11000c7e83b2Smrg * ParseSourceGeom() -- Determine dimensions of area to magnify from resources.
11019aa228fdSmrg */
11020c7e83b2Smrgstatic void
11039aa228fdSmrgParseSourceGeom(void)
11049aa228fdSmrg{
11059aa228fdSmrg				/* source */
11060c7e83b2Smrg  srcStat =
11079aa228fdSmrg    XParseGeometry(options.source, &srcX, &srcY, &srcWidth, &srcHeight);
11089aa228fdSmrg  if (!srcWidth) srcWidth = SRCWIDTH;
11099aa228fdSmrg  if (!srcHeight) srcHeight = SRCHEIGHT;
11109aa228fdSmrg  if (XNegative & srcStat) srcX = DisplayWidth(dpy, scr) + srcX - srcWidth;
11119aa228fdSmrg  if (YNegative & srcStat) srcY = DisplayHeight(dpy, scr) + srcY - srcHeight;
11129aa228fdSmrg				/* mag */
11139aa228fdSmrg}
11149aa228fdSmrg
11159aa228fdSmrg
11169aa228fdSmrg
1117e2f3d188Smrgstatic void _X_NORETURN
1118e2f3d188Smrgusage(const char *progname, int exitval)
1119e2f3d188Smrg{
1120e2f3d188Smrg  fprintf (stderr,
1121e2f3d188Smrg           "usage: %s [-source geom] [-mag magfactor] [-toolkitoption]\n"
1122e2f3d188Smrg           "       %s [-help|-version]\n",
1123e2f3d188Smrg           progname, progname);
1124e2f3d188Smrg  exit (exitval);
1125e2f3d188Smrg}
1126e2f3d188Smrg
11279aa228fdSmrg/*
11289aa228fdSmrg * Main program.
11299aa228fdSmrg */
11300c7e83b2Smrgint
11319aa228fdSmrgmain(int argc, char *argv[])
11329aa228fdSmrg{
1133e2f3d188Smrg  /* Handle args that don't require opening a display */
1134e2f3d188Smrg  for (int n = 1; n < argc; n++) {
1135e2f3d188Smrg    const char *argn = argv[n];
1136e2f3d188Smrg    /* accept single or double dash for -help & -version */
1137e2f3d188Smrg    if (argn[0] == '-' && argn[1] == '-') {
1138e2f3d188Smrg      argn++;
1139e2f3d188Smrg    }
1140e2f3d188Smrg    if (strcmp(argn, "-help") == 0) {
1141e2f3d188Smrg      usage(argv[0], 0);
1142e2f3d188Smrg    }
1143e2f3d188Smrg    if (strcmp(argn, "-version") == 0) {
1144e2f3d188Smrg      puts(PACKAGE_STRING);
1145e2f3d188Smrg      exit(0);
1146e2f3d188Smrg    }
1147e2f3d188Smrg  }
1148e2f3d188Smrg
11499aa228fdSmrg  XSetErrorHandler(Error);
11500c7e83b2Smrg
11519aa228fdSmrg  toplevel = XtAppInitialize(&app, "Xmag", optionDesc, XtNumber(optionDesc),
11529aa228fdSmrg			     &argc, argv, NULL,
11539aa228fdSmrg			     NULL, 0);
11549aa228fdSmrg
11559aa228fdSmrg  dpy = XtDisplay(toplevel);
11569aa228fdSmrg  scr = DefaultScreen(dpy);
11579aa228fdSmrg  XtGetApplicationResources(toplevel, (XtPointer) &options, resources,
11589aa228fdSmrg			    XtNumber(resources), NULL, 0);
11599aa228fdSmrg  if (argc != 1) {
1160e2f3d188Smrg    fputs("Unknown argument(s):", stderr);
1161e2f3d188Smrg    for (int n = 1; n < argc; n++) {
1162e2f3d188Smrg      fprintf(stderr, " %s", argv[n]);
1163e2f3d188Smrg    }
1164e2f3d188Smrg    fputs("\n\n", stderr);
1165e2f3d188Smrg    usage(argv[0], 1);
11669aa228fdSmrg  }
11670c7e83b2Smrg
11689aa228fdSmrg
11699aa228fdSmrg  ParseSourceGeom();
11709aa228fdSmrg  XtAppAddActions(app, actions_table, XtNumber(actions_table));
11719aa228fdSmrg  InitCursors();
11729aa228fdSmrg  SetupGC();
11739aa228fdSmrg  CreateRoot();
11749aa228fdSmrg  if (!(XValue & srcStat && YValue & srcStat))
11759aa228fdSmrg    StartRootPtrGrab(True, (hlPtr)NULL);
11769aa228fdSmrg  wm_delete_window = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
11779aa228fdSmrg  XtAppMainLoop(app);
11789aa228fdSmrg  exit(0);
11799aa228fdSmrg}
1180