xmag.c revision 15106172
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
2059aa228fdSmrgError(Display *dpy, XErrorEvent *err)
2069aa228fdSmrg{
2079aa228fdSmrg  (void) XmuPrintDefaultErrorMessage (dpy, err, stderr);
2089aa228fdSmrg  return 0;
2099aa228fdSmrg}
2109aa228fdSmrg
2119aa228fdSmrg
2129aa228fdSmrg/*
2139aa228fdSmrg * CloseAP() -- Close this dialog.  If its the last one exit the program.
2140c7e83b2Smrg *
2159aa228fdSmrg */
2169aa228fdSmrgstatic void			/* ARGSUSED */
2179aa228fdSmrgCloseAP(Widget w, XEvent *event, String *params, Cardinal *num_params)
2189aa228fdSmrg{
2199aa228fdSmrg  Arg wargs[2]; int n; hlPtr data;
2209aa228fdSmrg  if (!--numXmags) exit(0);
2219aa228fdSmrg  if (event->type != ClientMessage) {
2229aa228fdSmrg    n = 0;			/* get user data */
2239aa228fdSmrg    XtSetArg(wargs[0], XtNuserData, &data); n++;
2240c7e83b2Smrg    XtGetValues(w, wargs, n);
2259aa228fdSmrg    w = data->scaleShell;
2269aa228fdSmrg  }
2279aa228fdSmrg  XtPopdown(w);
2289aa228fdSmrg  XtDestroyWidget(w);
2299aa228fdSmrg}
2309aa228fdSmrg
2319aa228fdSmrg
2329aa228fdSmrg
2339aa228fdSmrg/*
2349aa228fdSmrg * SetCmapPropsAP() -- Put the scale widget first in WM_COLORMAP_WINDOWS
2350c7e83b2Smrg *
2369aa228fdSmrg */
2379aa228fdSmrgstatic void			/* ARGSUSED */
2389aa228fdSmrgSetCmapPropsAP(Widget w, XEvent *event, String *params, Cardinal *num_params)
2399aa228fdSmrg{
2409aa228fdSmrg  Arg wargs[2]; int n; hlPtr data;
2419aa228fdSmrg  n = 0;			/* get user data */
2429aa228fdSmrg  XtSetArg(wargs[0], XtNuserData, &data); n++;
2439aa228fdSmrg  XtGetValues(w, wargs, n);
2449aa228fdSmrg  if (data->win_info.colormap != DefaultColormap(dpy, scr)) {
2459aa228fdSmrg    data->cmapWinList[0] = data->scaleInstance;
2469aa228fdSmrg    data->cmapWinList[1] = data->scaleShell;
2479aa228fdSmrg    XtSetWMColormapWindows(data->scaleShell, data->cmapWinList, 2);
2489aa228fdSmrg  }
2499aa228fdSmrg}
2509aa228fdSmrg
2519aa228fdSmrg
2529aa228fdSmrg
2539aa228fdSmrg/*
2549aa228fdSmrg * UnsetCmapPropsAP() -- Put the shell first in WM_COLORMAP_WINDOWS
2550c7e83b2Smrg *
2569aa228fdSmrg */
2579aa228fdSmrgstatic void			/* ARGSUSED */
2589aa228fdSmrgUnsetCmapPropsAP(Widget w, XEvent *event, String *params, Cardinal *num_params)
2599aa228fdSmrg{
2609aa228fdSmrg  Arg wargs[2]; int n; hlPtr data;
2619aa228fdSmrg  n = 0;			/* get user data */
2629aa228fdSmrg  XtSetArg(wargs[0], XtNuserData, &data); n++;
2639aa228fdSmrg  XtGetValues(w, wargs, n);
2649aa228fdSmrg  if (data->win_info.colormap != DefaultColormap(dpy, scr)) {
2659aa228fdSmrg    data->cmapWinList[0] = data->scaleShell;
2669aa228fdSmrg    data->cmapWinList[1] = data->scaleInstance;
2679aa228fdSmrg    XtSetWMColormapWindows(data->scaleShell, data->cmapWinList, 2);
2689aa228fdSmrg  }
2699aa228fdSmrg}
2709aa228fdSmrg
2719aa228fdSmrg
2729aa228fdSmrg
2739aa228fdSmrg/*
2749aa228fdSmrg * NewAP() -- Create an additional xmag dialog. THIS IS A COPY OF NewEH
2759aa228fdSmrg *                                              FIND A BETTER WAY....
2769aa228fdSmrg */
2779aa228fdSmrgstatic void			/* ARGSUSED */
2789aa228fdSmrgNewAP(Widget w, XEvent *event, String *params, Cardinal *num_params)
2799aa228fdSmrg{
2809aa228fdSmrg  StartRootPtrGrab(True, NULL);
2819aa228fdSmrg}
2829aa228fdSmrg
2839aa228fdSmrg
2849aa228fdSmrg
2859aa228fdSmrg/*
2869aa228fdSmrg * ReplaceAP() -- Replace this particular xmag dialog.
2879aa228fdSmrg */
2889aa228fdSmrgstatic void                     /* ARGSUSED */
2899aa228fdSmrgReplaceAP(Widget w, XEvent *event, String *params, Cardinal *num_params)
2909aa228fdSmrg{
2919aa228fdSmrg  Arg wargs[2]; int n; hlPtr data;
2929aa228fdSmrg  n = 0;			/* get user data */
2939aa228fdSmrg  XtSetArg(wargs[0], XtNuserData, &data); n++;
2940c7e83b2Smrg  XtGetValues(w, wargs, n);
2959aa228fdSmrg  StartRootPtrGrab(False, data);
2969aa228fdSmrg}
2979aa228fdSmrg
2989aa228fdSmrg
2999aa228fdSmrg
3009aa228fdSmrg/*
3019aa228fdSmrg * PopupPixelAP() -- Show pixel information.
3029aa228fdSmrg */
3039aa228fdSmrgstatic void			/* ARGSUSED */
3049aa228fdSmrgPopupPixelAP(Widget w, XEvent *event, String *params, Cardinal *num_params)
3059aa228fdSmrg{
3069aa228fdSmrg    Position scale_x, scale_y;
3079aa228fdSmrg    Dimension scale_height;
3089aa228fdSmrg    Position label_x, label_y;
3099aa228fdSmrg    Dimension label_height;
3109aa228fdSmrg    int n;
3119aa228fdSmrg    Arg wargs[3];
3129aa228fdSmrg    hlPtr data;
3139aa228fdSmrg
3149aa228fdSmrg    n = 0;			/* get user data */
3159aa228fdSmrg    XtSetArg(wargs[0], XtNuserData, &data); n++;
3169aa228fdSmrg    XtGetValues(w, wargs, n);
3179aa228fdSmrg
3189aa228fdSmrg    n = 0;
3199aa228fdSmrg    XtSetArg(wargs[n], XtNheight, &scale_height); n++;
3209aa228fdSmrg    XtGetValues(w, wargs, n);
3219aa228fdSmrg    XtTranslateCoords(w, -1, -1, &scale_x, &scale_y);
3220c7e83b2Smrg
3239aa228fdSmrg    XtRealizeWidget(data->pixShell); /* to get the right height  */
3249aa228fdSmrg
3259aa228fdSmrg    n = 0;
3269aa228fdSmrg    XtSetArg(wargs[n], XtNheight, &label_height); n++;
3279aa228fdSmrg    XtGetValues(data->pixShell, wargs, n);
3280c7e83b2Smrg
3299aa228fdSmrg    if ((double) event->xbutton.y / (double) scale_height > 0.5) {
3309aa228fdSmrg	label_x = scale_x;
3319aa228fdSmrg	label_y = scale_y;
3329aa228fdSmrg    }
3339aa228fdSmrg    else {
3349aa228fdSmrg	label_x = scale_x;
3359aa228fdSmrg	label_y = scale_y + scale_height - label_height;
3369aa228fdSmrg    }
3379aa228fdSmrg
3389aa228fdSmrg    n = 0;
3399aa228fdSmrg    XtSetArg(wargs[n], XtNx, label_x); n++;
3409aa228fdSmrg    XtSetArg(wargs[n], XtNy, label_y); n++;
3419aa228fdSmrg    XtSetValues(data->pixShell, wargs, n);
34283d7c197Smrg
34383d7c197Smrg    UpdatePixelAP(w, event, NULL, NULL);
3449aa228fdSmrg}
3459aa228fdSmrg
3469aa228fdSmrg
3479aa228fdSmrg
3489aa228fdSmrg/*
3499aa228fdSmrg * UpdatePixelAP() -- Update pixel information.
3509aa228fdSmrg */
3519aa228fdSmrgstatic void			/* ARGSUSED */
3529aa228fdSmrgUpdatePixelAP(Widget w, XEvent *event, String *params, Cardinal *num_params)
3539aa228fdSmrg{
3549aa228fdSmrg    Position x, y;
3559aa228fdSmrg    Pixel pixel;
3569aa228fdSmrg    XColor color;
3579aa228fdSmrg    int n;
3589aa228fdSmrg    Arg wargs[3];
3599aa228fdSmrg    char string[80];
3609aa228fdSmrg    hlPtr data;
3619aa228fdSmrg
3629aa228fdSmrg    n = 0;
3639aa228fdSmrg    XtSetArg(wargs[0], XtNuserData, &data); n++;
3649aa228fdSmrg    XtGetValues(w, wargs, n);
3659aa228fdSmrg
3669aa228fdSmrg    if (SWGetImagePixel(w, event->xbutton.x, event->xbutton.y, &x, &y, &pixel))
3679aa228fdSmrg	XtPopdown(data->pixShell);
3689aa228fdSmrg    else {
3699aa228fdSmrg	color.pixel = pixel;
3709aa228fdSmrg	XQueryColor(dpy, data->win_info.colormap, &color);
3710c7e83b2Smrg	snprintf(string, sizeof(string),
3720c7e83b2Smrg		 "Pixel %ld at (%d,%d) colored (%x,%x,%x).",
3730c7e83b2Smrg		 pixel, x + data->x, y + data->y,
3740c7e83b2Smrg		 color.red, color.green, color.blue);
3759aa228fdSmrg	n = 0;
3760c7e83b2Smrg	XtSetArg(wargs[n], XtNlabel, string); n++;
3779aa228fdSmrg	XtSetValues(data->pixLabel, wargs, n);
3789aa228fdSmrg	XtPopup(data->pixShell, XtGrabNone);
3799aa228fdSmrg    }
3809aa228fdSmrg}
3819aa228fdSmrg
3829aa228fdSmrg
3839aa228fdSmrg
3849aa228fdSmrg/*
3859aa228fdSmrg * PopdownPixelAP() -- Remove pixel info.
3869aa228fdSmrg */
3879aa228fdSmrgstatic void			/* ARGSUSED */
3889aa228fdSmrgPopdownPixelAP(Widget w, XEvent *event, String *params, Cardinal *num_params)
3899aa228fdSmrg{
3909aa228fdSmrg  int n;
3919aa228fdSmrg  Arg wargs[3];
3929aa228fdSmrg  hlPtr data = NULL;
3930c7e83b2Smrg
3949aa228fdSmrg  n = 0;
3959aa228fdSmrg  XtSetArg(wargs[0], XtNuserData, &data); n++;
3969aa228fdSmrg  XtGetValues(w, wargs, n);
3979aa228fdSmrg
3989aa228fdSmrg  if (data)
3999aa228fdSmrg    XtPopdown(data->pixShell);
4009aa228fdSmrg}
4019aa228fdSmrg
4029aa228fdSmrg
4039aa228fdSmrg
4049aa228fdSmrgstatic void			/* ARGSUSED */
4059aa228fdSmrgSelectRegionAP(Widget w, XEvent *event, String *params, Cardinal *num_params)
4060c7e83b2Smrg{
4070c7e83b2Smrg/***** NOT SURE WHAT TO DO WITH THIS
4089aa228fdSmrg    if (app_resources.unmap)
4099aa228fdSmrg	XtUnmapWidget(toplevel);
4109aa228fdSmrg    Redisplay(XtDisplay(w), RootWindow(XtDisplay(w),
4119aa228fdSmrg				       DefaultScreen(XtDisplay(w))),
4120c7e83b2Smrg	      source.width, source.height,
4130c7e83b2Smrg	      app_resources.freq, app_resources.puls,
4149aa228fdSmrg	      ul_angle, lr_angle,
4159aa228fdSmrg	      app_resources.grab);
4169aa228fdSmrg
4179aa228fdSmrg    if (app_resources.unmap)
4189aa228fdSmrg	XtMapWidget(toplevel);
4199aa228fdSmrg******/
4209aa228fdSmrg}
4219aa228fdSmrg
4229aa228fdSmrg
4239aa228fdSmrg
4240c7e83b2Smrg/*
4259aa228fdSmrg * CheckPoints() -- Change the cursor for the correct quadrant.
4260c7e83b2Smrg *                  Make sure the first point is less than the second
4279aa228fdSmrg *                  for drawing the selection rectangle.
4289aa228fdSmrg *
4299aa228fdSmrg */
4300c7e83b2Smrgstatic void
4319aa228fdSmrgCheckPoints(Position *x1, Position *x2, Position *y1, Position *y2)
4329aa228fdSmrg{
4330c7e83b2Smrg  Position tmp;
4349aa228fdSmrg  Boolean above, left;
4359aa228fdSmrg  Cursor newC;
4360c7e83b2Smrg  above = (*y2 < *y1); left = (*x2 < *x1);
4379aa228fdSmrg  if (above&&left) newC = ulAngle;
4389aa228fdSmrg  else if (above&&!left) newC = urAngle;
4399aa228fdSmrg  else if (!above&&!left) newC = lrAngle;
4409aa228fdSmrg  else newC = llAngle;
4419aa228fdSmrg  XChangeActivePointerGrab
4429aa228fdSmrg    (dpy, PointerMotionMask|ButtonPressMask|ButtonReleaseMask,
4439aa228fdSmrg     newC, CurrentTime);
4449aa228fdSmrg  if (*x2 < *x1) { tmp = *x1; *x1 = *x2; *x2 = tmp; }
4459aa228fdSmrg  if (*y2 < *y1) { tmp = *y1; *y1 = *y2; *y2 = tmp; }
4469aa228fdSmrg}
4479aa228fdSmrg
4489aa228fdSmrg
4499aa228fdSmrg
4509aa228fdSmrg/*
4519aa228fdSmrg * HighlightTO() -- Timer to highlight the selection box
4529aa228fdSmrg */
4539aa228fdSmrgstatic void
4549aa228fdSmrgHighlightTO(XtPointer closure, XtIntervalId *id)	/* ARGSUSED */
4559aa228fdSmrg{
4569aa228fdSmrg  hlPtr data = (hlPtr)closure;
4579aa228fdSmrg  XGrabServer(dpy);
4589aa228fdSmrg  if (data->selectMode == drag) {
4590c7e83b2Smrg    XDrawRectangle(dpy, DefaultRootWindow(dpy), data->gc,
4609aa228fdSmrg		   data->x, data->y, data->width, data->height);
4619aa228fdSmrg    XFlush(dpy);
4629aa228fdSmrg    HLSLEEP;
4630c7e83b2Smrg    XDrawRectangle(dpy, DefaultRootWindow(dpy), data->gc,
4649aa228fdSmrg		   data->x, data->y, data->width, data->height);
4659aa228fdSmrg  }
4660c7e83b2Smrg  else if (data->selectMode == resize) {
4679aa228fdSmrg    Position x1 = data->homeX,
4689aa228fdSmrg             x2 = data->x,
4699aa228fdSmrg             y1 = data->homeY,
4709aa228fdSmrg             y2 = data->y;
4719aa228fdSmrg    CheckPoints(&x1, &x2, &y1, &y2);
4720c7e83b2Smrg    XDrawRectangle(dpy, DefaultRootWindow(dpy), data->gc,
4739aa228fdSmrg		   x1, y1, x2 - x1, y2 - y1);
4749aa228fdSmrg    XFlush(dpy);
4759aa228fdSmrg    HLSLEEP;
4760c7e83b2Smrg    XDrawRectangle(dpy, DefaultRootWindow(dpy), data->gc,
4779aa228fdSmrg		   x1, y1, x2 - x1, y2 - y1);
4789aa228fdSmrg  }
4799aa228fdSmrg  XUngrabServer(dpy);
4809aa228fdSmrg  if (data->selectMode != done)
4819aa228fdSmrg    XtAppAddTimeOut(app, HLINTERVAL, HighlightTO, (XtPointer)data);
4829aa228fdSmrg}
4839aa228fdSmrg
4849aa228fdSmrg
4859aa228fdSmrg
4869aa228fdSmrg/*
4879aa228fdSmrg * CloseCB() -- Delete this xmag dialog.  If its the only one on the screen
4889aa228fdSmrg *             then exit.
4899aa228fdSmrg */
4909aa228fdSmrgstatic void			/* ARGSUSED */
4919aa228fdSmrgCloseCB(Widget w, XtPointer clientData, XtPointer callData)
4929aa228fdSmrg{
4939aa228fdSmrg  Widget shell = (Widget)clientData;
4949aa228fdSmrg  if (!--numXmags) exit(0);
4959aa228fdSmrg  XtPopdown(shell);
4969aa228fdSmrg  XtDestroyWidget(shell);
4979aa228fdSmrg}
4989aa228fdSmrg
4999aa228fdSmrg
5009aa228fdSmrg
5019aa228fdSmrg/*
5029aa228fdSmrg * ReplaceCB() -- Replace this particular xmag dialog.
5039aa228fdSmrg */
5049aa228fdSmrgstatic void                     /* ARGSUSED */
5059aa228fdSmrgReplaceCB(Widget w, XtPointer clientData, XtPointer callData)
5069aa228fdSmrg{
5079aa228fdSmrg  hlPtr data = (hlPtr)clientData;
5089aa228fdSmrg  StartRootPtrGrab(False, data);
5099aa228fdSmrg}
5109aa228fdSmrg
5119aa228fdSmrg
5129aa228fdSmrg
5139aa228fdSmrg/*
5149aa228fdSmrg * NewCB() -- Create an additional xmag dialog.
5159aa228fdSmrg */
5169aa228fdSmrgstatic void			/* ARGSUSED */
5179aa228fdSmrgNewCB(Widget w, XtPointer clientData, XtPointer callData)
5189aa228fdSmrg{
5199aa228fdSmrg  StartRootPtrGrab(True, NULL);
5209aa228fdSmrg}
5219aa228fdSmrg
5229aa228fdSmrg
5239aa228fdSmrg
5249aa228fdSmrg/*
5259aa228fdSmrg * SelectCB() -- Own the primary selection.
5269aa228fdSmrg */
5279aa228fdSmrgstatic void			/* ARGSUSED */
5289aa228fdSmrgSelectCB(Widget w, XtPointer clientData, XtPointer callData)
5299aa228fdSmrg{
5309aa228fdSmrg  hlPtr data = (hlPtr)clientData;
5319aa228fdSmrg  SWGrabSelection(data->scaleInstance, XtLastTimestampProcessed(dpy));
5329aa228fdSmrg}
5339aa228fdSmrg
5349aa228fdSmrg
5359aa228fdSmrg
5369aa228fdSmrg/*
5379aa228fdSmrg * PasteCB() -- Paste from the primary selectin into xmag.
5389aa228fdSmrg */
5399aa228fdSmrgstatic void			/* ARGSUSED */
5409aa228fdSmrgPasteCB(Widget w, XtPointer clientData, XtPointer callData)
5419aa228fdSmrg{
5429aa228fdSmrg  hlPtr data = (hlPtr)clientData;
5439aa228fdSmrg  SWRequestSelection(data->scaleInstance, XtLastTimestampProcessed(dpy));
5449aa228fdSmrg}
5459aa228fdSmrg
5469aa228fdSmrg
5479aa228fdSmrg
5489aa228fdSmrg/*
5499aa228fdSmrg * SetupGC() -- Graphics context for magnification selection.
5509aa228fdSmrg */
5510c7e83b2Smrgstatic void
5529aa228fdSmrgSetupGC(void)
5539aa228fdSmrg{
5549aa228fdSmrg    selectGCV.function = GXxor;
5559aa228fdSmrg    selectGCV.foreground = 0xffffffff;
5569aa228fdSmrg    selectGCV.subwindow_mode = IncludeInferiors;
5579aa228fdSmrg    selectGC = XtGetGC(toplevel, GCFunction|GCForeground|GCSubwindowMode,
5589aa228fdSmrg		       &selectGCV);
5590c7e83b2Smrg}
5609aa228fdSmrg
5619aa228fdSmrg
5629aa228fdSmrg
5639aa228fdSmrg/*
5640c7e83b2Smrg * FindWindow() -- Determine window the pointer is over.
5659aa228fdSmrg *
5669aa228fdSmrg */
5670c7e83b2Smrgstatic Window
5680c7e83b2SmrgFindWindow(int x, int y)	/* Location of cursor */
5699aa228fdSmrg{
5709aa228fdSmrg  XWindowAttributes wa;
5719aa228fdSmrg  Window findW = DefaultRootWindow(dpy), stopW, childW;
5729aa228fdSmrg
5739aa228fdSmrg  /* Setup for first window find */
5749aa228fdSmrg  stopW = findW;
5759aa228fdSmrg
5769aa228fdSmrg  while (stopW) {
5770c7e83b2Smrg    XTranslateCoordinates(dpy, findW, stopW,
5789aa228fdSmrg			  x, y, &x, &y, &childW);
5799aa228fdSmrg    findW = stopW;
5809aa228fdSmrg    /* If child is not InputOutput (for example, InputOnly) */
5819aa228fdSmrg    /* then don't continue, return the present findW which */
5829aa228fdSmrg    /* can be the root, or a root child of class InputOutput */
5839aa228fdSmrg    if (childW &&
5849aa228fdSmrg	XGetWindowAttributes(dpy, childW, &wa) &&
5859aa228fdSmrg	wa.class != InputOutput)
5869aa228fdSmrg	break;
5879aa228fdSmrg    stopW = childW;
5889aa228fdSmrg  }
5899aa228fdSmrg  return findW;
5909aa228fdSmrg}
5919aa228fdSmrg
5929aa228fdSmrg
5939aa228fdSmrg
5949aa228fdSmrg/*
5959aa228fdSmrg * ResizeEH() -- Event Handler for resize of selection box.
5969aa228fdSmrg */
5970c7e83b2Smrgstatic void
5980c7e83b2SmrgResizeEH(Widget w, XtPointer closure, XEvent *event,
5999aa228fdSmrg	 Boolean *continue_to_dispatch)	/* ARGSUSED */
6009aa228fdSmrg{
6019aa228fdSmrg  hlPtr data = (hlPtr)closure;
6029aa228fdSmrg  switch (event->type) {
6039aa228fdSmrg  case MotionNotify:
6049aa228fdSmrg    data->x = event->xmotion.x_root;
6050c7e83b2Smrg    data->y = event->xmotion.y_root;
6069aa228fdSmrg    break;
6079aa228fdSmrg  case ButtonRelease:
6089aa228fdSmrg    GetImageAndAttributes(FindWindow(event->xmotion.x_root,
6099aa228fdSmrg			event->xmotion.y_root),
6109aa228fdSmrg	     min(data->homeX,event->xbutton.x_root),
6119aa228fdSmrg	     min(data->homeY,event->xbutton.y_root),
6129aa228fdSmrg	     abs(data->homeX - event->xbutton.x_root),
6139aa228fdSmrg	     abs(data->homeY - event->xbutton.y_root),
6149aa228fdSmrg	     data);
6159aa228fdSmrg    if (data->newScale)
6169aa228fdSmrg      PopupNewScale(data);
6170c7e83b2Smrg    else
6189aa228fdSmrg      SWSetImage(data->scaleInstance, data->image);
6199aa228fdSmrg    XtUngrabPointer(w, CurrentTime);
6209aa228fdSmrg/*****
6219aa228fdSmrg    XtRemoveRawEventHandler(w, PointerMotionMask|ButtonReleaseMask,
6229aa228fdSmrg			 True, ResizeEH, (XtPointer)data);
6239aa228fdSmrg*****/
6249aa228fdSmrg    XtRemoveEventHandler(w, PointerMotionMask|ButtonReleaseMask,
6259aa228fdSmrg			 True, ResizeEH, (XtPointer)data);
6269aa228fdSmrg    data->selectMode = done;
6279aa228fdSmrg    break;
6289aa228fdSmrg  }
6299aa228fdSmrg}
6309aa228fdSmrg
6319aa228fdSmrg
6329aa228fdSmrg
6339aa228fdSmrg/*
6340c7e83b2Smrg * DragEH() -- Event Handler for dragging selection box.
6359aa228fdSmrg */
6360c7e83b2Smrgstatic void
6370c7e83b2SmrgDragEH(Widget w, XtPointer closure, XEvent *event,
6389aa228fdSmrg       Boolean *continue_to_dispatch) /* ARGSUSED */
6399aa228fdSmrg{
6409aa228fdSmrg  hlPtr data = (hlPtr)closure;
6419aa228fdSmrg  switch (event->type) {
6429aa228fdSmrg  case MotionNotify:		/* drag mode */
6439aa228fdSmrg    data->x = event->xmotion.x_root;
6449aa228fdSmrg    data->y = event->xmotion.y_root;
6459aa228fdSmrg    break;
6469aa228fdSmrg  case ButtonRelease:		/* end drag mode */
6479aa228fdSmrg    if (event->xbutton.button == Button1) { /* get image */
6489aa228fdSmrg      /* Problem: You can't get bits with XGetImage outside of its window.
6499aa228fdSmrg       *          xmag will only do a GetImage on the actual window in the case
6509aa228fdSmrg       *          where the depth of the window does not match the depth of
6519aa228fdSmrg       *          the root window.
6529aa228fdSmrg       */
6530c7e83b2Smrg      GetImageAndAttributes(FindWindow(event->xmotion.x_root,
6549aa228fdSmrg			  event->xmotion.y_root),
6550c7e83b2Smrg	       event->xbutton.x_root,
6569aa228fdSmrg	       event->xbutton.y_root,
6579aa228fdSmrg	       srcWidth, srcHeight, data);
6589aa228fdSmrg      if (data->newScale)
6599aa228fdSmrg	PopupNewScale(data);
6609aa228fdSmrg      else
6619aa228fdSmrg	RedoOldScale(data);
6629aa228fdSmrg      XtUngrabPointer(w, CurrentTime);
6639aa228fdSmrg      XtRemoveRawEventHandler(w, PointerMotionMask|ButtonPressMask|
6649aa228fdSmrg			      ButtonReleaseMask, True, DragEH,
6659aa228fdSmrg			      (XtPointer)data);
6669aa228fdSmrg      data->selectMode = done;
6679aa228fdSmrg    }
6689aa228fdSmrg
6699aa228fdSmrg    break;
6700c7e83b2Smrg  case ButtonPress:
6719aa228fdSmrg    if (event->xbutton.button == Button2) {	/* turn on resize mode */
6720c7e83b2Smrg      data->homeX = event->xbutton.x_root;
6739aa228fdSmrg      data->homeY = event->xbutton.y_root;
6749aa228fdSmrg      data->x = event->xbutton.x_root + srcWidth;
6750c7e83b2Smrg      data->y = event->xbutton.y_root + srcHeight;
6769aa228fdSmrg      data->selectMode = resize;
6779aa228fdSmrg      XtRemoveRawEventHandler(w, PointerMotionMask|ButtonPressMask|
6789aa228fdSmrg			   ButtonReleaseMask, True, DragEH, (XtPointer)data);
6799aa228fdSmrg      XChangeActivePointerGrab
6809aa228fdSmrg	(dpy, PointerMotionMask|ButtonPressMask|ButtonReleaseMask,
6819aa228fdSmrg	 lrAngle, CurrentTime);
6820c7e83b2Smrg      XWarpPointer(dpy, None, None, 0, 0, 0, 0,
6839aa228fdSmrg		   srcWidth, srcHeight);
6840c7e83b2Smrg      XtAddEventHandler(w, PointerMotionMask|ButtonReleaseMask,
6859aa228fdSmrg			True, ResizeEH, (XtPointer)data);
6869aa228fdSmrg    }
6879aa228fdSmrg    break;
6889aa228fdSmrg  }
6899aa228fdSmrg}
6909aa228fdSmrg
6919aa228fdSmrg
6929aa228fdSmrg
6939aa228fdSmrg
6949aa228fdSmrg/*
6959aa228fdSmrg * StartRootPtrGrab() -- Bring up the selection box.
6960c7e83b2Smrg *
6979aa228fdSmrg */
6989aa228fdSmrgstatic void
6990c7e83b2SmrgStartRootPtrGrab(int new, 	/* do we create a new scale instance? */
7000c7e83b2Smrg		 hlPtr data)	/* highlight data */
7019aa228fdSmrg{
7029aa228fdSmrg  Window    rootR, childR;
7039aa228fdSmrg  int       rootX, rootY, winX, winY;
7049aa228fdSmrg  unsigned  int mask;
7059aa228fdSmrg  hlPtr hlData;
7069aa228fdSmrg  XtGrabPointer
7079aa228fdSmrg    (root, False,
7089aa228fdSmrg     PointerMotionMask|ButtonPressMask|ButtonReleaseMask,
7099aa228fdSmrg     GrabModeAsync, GrabModeAsync, None, ulAngle, CurrentTime);
7100c7e83b2Smrg  XQueryPointer(dpy, DefaultRootWindow(dpy), &rootR, &childR,
7119aa228fdSmrg		&rootX, &rootY, &winX, &winY, &mask);
7129aa228fdSmrg  if (new) {
7139aa228fdSmrg    numXmags++;
7149aa228fdSmrg    hlData = (hlPtr)XtMalloc(sizeof(hlStruct));
7159aa228fdSmrg  }
7169aa228fdSmrg  else hlData = data;
7179aa228fdSmrg  hlData->newScale   = new;
7189aa228fdSmrg  hlData->selectMode = drag;
7199aa228fdSmrg  hlData->x          = rootX;
7209aa228fdSmrg  hlData->y          = rootY;
7219aa228fdSmrg  hlData->gc         = selectGC;
7229aa228fdSmrg  hlData->width      = srcWidth;
7239aa228fdSmrg  hlData->height     = srcHeight;
7249aa228fdSmrg  XtAddRawEventHandler
7250c7e83b2Smrg    (root, PointerMotionMask|ButtonPressMask|ButtonReleaseMask,
7269aa228fdSmrg     True, DragEH, (XtPointer)hlData);
7279aa228fdSmrg  (void) XtAppAddTimeOut(app, HLINTERVAL, HighlightTO, (XtPointer)hlData);
7289aa228fdSmrg}
7299aa228fdSmrg
7309aa228fdSmrg
7319aa228fdSmrg
7329aa228fdSmrg/*
7339aa228fdSmrg * CreateRoot() -- Create a root window widget. If the user specified x and y
7340c7e83b2Smrg *                 in the source geometry then use this to directly get the
7359aa228fdSmrg *                 image.
7369aa228fdSmrg */
7379aa228fdSmrgstatic void
7389aa228fdSmrgCreateRoot(void)
7399aa228fdSmrg{
7409aa228fdSmrg  hlPtr data;
7419aa228fdSmrg  root = XtCreateWidget("root", rootWindowWidgetClass, toplevel, NULL, 0);
7429aa228fdSmrg  XtRealizeWidget(root);
7430c7e83b2Smrg  if (XValue & srcStat && YValue &srcStat) {
7449aa228fdSmrg    numXmags = 1;
7459aa228fdSmrg    data = (hlPtr)XtMalloc(sizeof(hlStruct));
7469aa228fdSmrg    data = data;
7479aa228fdSmrg    data->newScale   = True;
7489aa228fdSmrg    data->selectMode = drag;
7499aa228fdSmrg    data->x          = srcX;
7509aa228fdSmrg    data->y          = srcY;
7519aa228fdSmrg    data->gc         = selectGC;
7529aa228fdSmrg    data->width      = srcWidth;
7539aa228fdSmrg    data->height     = srcHeight;
7540c7e83b2Smrg    GetImageAndAttributes(RootWindow(dpy, scr), srcX, srcY, srcWidth,
7559aa228fdSmrg			  srcHeight, data);
7569aa228fdSmrg    PopupNewScale(data);
7579aa228fdSmrg    return;
7589aa228fdSmrg  }
7599aa228fdSmrg}
7609aa228fdSmrg
7619aa228fdSmrg
7620c7e83b2Smrg/*
7639aa228fdSmrg * GetImageAndAttributes() -- Get the image bits from the screen.
7640c7e83b2Smrg *               We will also determine here the colormap, depth, and
7650c7e83b2Smrg *               visual to be used for the magnification image.
7669aa228fdSmrg */
7670c7e83b2Smrgstatic void
7680c7e83b2SmrgGetImageAndAttributes(Window w, int x, int y, int width, int height,
7699aa228fdSmrg		      hlPtr data)
7709aa228fdSmrg{
77183d7c197Smrg    /* get parameters of window being magnified */
77283d7c197Smrg    XGetWindowAttributes(dpy, w, &data->win_info);
77383d7c197Smrg
77483d7c197Smrg    if (data->win_info.depth == DefaultDepth(dpy, scr)) {
77583d7c197Smrg	/* avoid off screen pixels */
77683d7c197Smrg	if (x < 0)
77783d7c197Smrg	    x = 0;
77883d7c197Smrg	if (y < 0)
77983d7c197Smrg	    y = 0;
78083d7c197Smrg	if (x + width > DisplayWidth(dpy,scr))
78183d7c197Smrg	    x = DisplayWidth(dpy,scr) - width;
78283d7c197Smrg	if (y + height > DisplayHeight(dpy,scr))
78383d7c197Smrg	    y = DisplayHeight(dpy,scr) - height;
78483d7c197Smrg	data->x = x; data->y = y;
78583d7c197Smrg	/* get image pixels */
78683d7c197Smrg	data->image = XGetImage (dpy,
78783d7c197Smrg				 RootWindow(dpy, scr),
78883d7c197Smrg				 x, y,
78983d7c197Smrg				 width, height,
79083d7c197Smrg				 AllPlanes, ZPixmap);
79183d7c197Smrg    }
79283d7c197Smrg    else {
79383d7c197Smrg	int	t0, t1;
79483d7c197Smrg	int	x0, x1, y0, y1;
79583d7c197Smrg	int	xInWin, yInWin;
79683d7c197Smrg	Window	childWin;
79783d7c197Smrg
79883d7c197Smrg	XTranslateCoordinates(dpy, DefaultRootWindow(dpy), w, x, y,
79983d7c197Smrg			      &xInWin, &yInWin, &childWin);
80083d7c197Smrg
80183d7c197Smrg	/* Avoid off screen pixels. Assume this routine is not
80283d7c197Smrg	 * called for totally offscreen windows. */
80383d7c197Smrg	x0 = max(x, 0);
80483d7c197Smrg	y0 = max(y, 0);
80583d7c197Smrg	x1 = min(DisplayWidth(dpy, scr),
80683d7c197Smrg		 min(x0 + width, x0 + (data->win_info.width - xInWin)));
80783d7c197Smrg	y1 = min(DisplayHeight(dpy, scr),
80883d7c197Smrg		 min(y0 + height, y0 + (data->win_info.height - yInWin)));
80983d7c197Smrg
81083d7c197Smrg	/* Try to use up to width x height pixels */
81183d7c197Smrg	if (x1 - x0 < width) {
81283d7c197Smrg	    t0 = x0;
81383d7c197Smrg	    t1 = max(0, x - xInWin + data->win_info.width -
81483d7c197Smrg		     DisplayWidth(dpy, scr));
81583d7c197Smrg	    x0 = max(0, x1 - min(width, data->win_info.width - t1));
81683d7c197Smrg	    xInWin -= t0 - x0;
81783d7c197Smrg	}
81883d7c197Smrg	if (y1 - y0 < height) {
81983d7c197Smrg	    t0 = y0;
82083d7c197Smrg	    t1 = max(0, y - yInWin + data->win_info.height -
82183d7c197Smrg		     DisplayHeight(dpy, scr));
82283d7c197Smrg	    y0 = max(0, y1 - min(height, data->win_info.height - t1));
82383d7c197Smrg	    yInWin -= t0 - y0;
82483d7c197Smrg	}
82583d7c197Smrg
82683d7c197Smrg	data->x = x0;
82783d7c197Smrg	data->y = y0;
82883d7c197Smrg	data->width = x1 - x0;
82983d7c197Smrg	data->height = y1 - y0;
83083d7c197Smrg
83183d7c197Smrg	data->image = XGetImage (dpy,
83283d7c197Smrg				 w,
83383d7c197Smrg				 xInWin, yInWin,
83483d7c197Smrg				 data->width, data->height,
83583d7c197Smrg				 AllPlanes, ZPixmap);
83683d7c197Smrg
83783d7c197Smrg    }
8389aa228fdSmrg}
8399aa228fdSmrg
8409aa228fdSmrg
8419aa228fdSmrg
8429aa228fdSmrg/*
8439aa228fdSmrg * Get_XColors() Get the XColors of all pixels in image - returns # of colors
8449aa228fdSmrg *               This function was taken from xwd (thanks Bob...)
8459aa228fdSmrg */
8469aa228fdSmrg#define lowbit(x) ((x) & (~(x) + 1))
8470c7e83b2Smrgstatic int
8489aa228fdSmrgGet_XColors(XWindowAttributes *win_info, XColor **colors)
8499aa228fdSmrg{
8509aa228fdSmrg    int i, ncolors;
8510c7e83b2Smrg
8529aa228fdSmrg    if (!win_info->colormap)
8539aa228fdSmrg        return(0);
8540c7e83b2Smrg
8559aa228fdSmrg    ncolors = win_info->visual->map_entries;
8569aa228fdSmrg    if (!(*colors = (XColor *) XtMalloc (sizeof(XColor) * ncolors)))
8579aa228fdSmrg      XtError("Out of memory!");
8580c7e83b2Smrg
8599aa228fdSmrg    if (win_info->visual->class == DirectColor ||
8609aa228fdSmrg        win_info->visual->class == TrueColor) {
8619aa228fdSmrg        Pixel red, green, blue, red1, green1, blue1;
8620c7e83b2Smrg
8639aa228fdSmrg        red = green = blue = 0;
8649aa228fdSmrg        red1 = lowbit(win_info->visual->red_mask);
8659aa228fdSmrg        green1 = lowbit(win_info->visual->green_mask);
8669aa228fdSmrg        blue1 = lowbit(win_info->visual->blue_mask);
8679aa228fdSmrg        for (i=0; i<ncolors; i++) {
8689aa228fdSmrg          (*colors)[i].pixel = red|green|blue;
8699aa228fdSmrg          (*colors)[i].pad = 0;
8709aa228fdSmrg          red += red1;
8719aa228fdSmrg          if (red > win_info->visual->red_mask)
8729aa228fdSmrg            red = 0;
8739aa228fdSmrg          green += green1;
8749aa228fdSmrg          if (green > win_info->visual->green_mask)
8759aa228fdSmrg            green = 0;
8769aa228fdSmrg          blue += blue1;
8779aa228fdSmrg          if (blue > win_info->visual->blue_mask)
8789aa228fdSmrg            blue = 0;
8799aa228fdSmrg        }
8809aa228fdSmrg    } else {
8819aa228fdSmrg        for (i=0; i<ncolors; i++) {
8829aa228fdSmrg          (*colors)[i].pixel = i;
8839aa228fdSmrg          (*colors)[i].pad = 0;
8849aa228fdSmrg        }
8859aa228fdSmrg    }
8860c7e83b2Smrg
8879aa228fdSmrg    XQueryColors(dpy, win_info->colormap, *colors, ncolors);
8880c7e83b2Smrg
8899aa228fdSmrg    return(ncolors);
8909aa228fdSmrg}
8919aa228fdSmrg
8929aa228fdSmrg
8939aa228fdSmrg
8949aa228fdSmrg#define Intensity(cptr) (3.0*cptr->red+0.59*cptr->green+0.11*cptr->blue)
8959aa228fdSmrg
8969aa228fdSmrg/*
8979aa228fdSmrg * GetMaxIntensity() -- Find the maximum intensity pixel value for a colormap.
8989aa228fdSmrg */
8999aa228fdSmrgstatic Pixel
9009aa228fdSmrgGetMaxIntensity(hlPtr data)
9019aa228fdSmrg{
9029aa228fdSmrg  XColor *colors = NULL, *mptr, *tptr;
9039aa228fdSmrg  int i, ncolors;
9049aa228fdSmrg
9050c7e83b2Smrg  if (data->win_info.colormap == DefaultColormap(dpy, scr))
9069aa228fdSmrg    return WhitePixel(dpy, scr);
9070c7e83b2Smrg  ncolors = Get_XColors(&data->win_info, &colors);
9089aa228fdSmrg  mptr = tptr = colors; tptr++;
9099aa228fdSmrg  for (i=1; i<ncolors; i++) {
9100c7e83b2Smrg    if ((int)Intensity(mptr) < (int)Intensity(tptr))
9119aa228fdSmrg      mptr = tptr;
9129aa228fdSmrg    tptr++;
9139aa228fdSmrg  }
9149aa228fdSmrg  /* Null pointer protection */
9159aa228fdSmrg  if(mptr)
9169aa228fdSmrg    return mptr->pixel;
9179aa228fdSmrg  else
9189aa228fdSmrg    return WhitePixel(dpy, scr);
9199aa228fdSmrg}
9209aa228fdSmrg
9219aa228fdSmrg/*
9229aa228fdSmrg * GetMinIntensity() -- Find the minimum intensity pixel value for a colormap.
9239aa228fdSmrg */
9249aa228fdSmrgstatic Pixel
9259aa228fdSmrgGetMinIntensity(hlPtr data)
9269aa228fdSmrg{
9279aa228fdSmrg  XColor *colors = NULL, *mptr, *tptr;
9289aa228fdSmrg  int i, ncolors;
9299aa228fdSmrg
9300c7e83b2Smrg  if (data->win_info.colormap == DefaultColormap(dpy, scr))
9319aa228fdSmrg    return BlackPixel(dpy, scr);
9320c7e83b2Smrg  ncolors = Get_XColors(&data->win_info, &colors);
9339aa228fdSmrg  mptr = tptr = colors; tptr++;
9349aa228fdSmrg  for (i=1; i<ncolors; i++)  {
9359aa228fdSmrg    if ((int)Intensity(mptr) > (int)Intensity(tptr))
9360c7e83b2Smrg      mptr = tptr;
9379aa228fdSmrg    tptr++;
9389aa228fdSmrg  }
9399aa228fdSmrg  /* Null pointer protection */
9409aa228fdSmrg  if(mptr)
9419aa228fdSmrg    return mptr->pixel;
9429aa228fdSmrg  else
9439aa228fdSmrg    return BlackPixel(dpy, scr);
9449aa228fdSmrg}
9459aa228fdSmrg
9469aa228fdSmrg
9479aa228fdSmrg
9489aa228fdSmrg
9499aa228fdSmrgstatic Widget pane1, pane2, pane3, cclose, replace, new, select_w, paste;
9509aa228fdSmrg
9519aa228fdSmrg/*
9529aa228fdSmrg * PopupNewScale() -- Create and popup a new scale composite.
9539aa228fdSmrg */
9540c7e83b2Smrgstatic void
9559aa228fdSmrgPopupNewScale(hlPtr data)
9569aa228fdSmrg{
9579aa228fdSmrg  Arg warg;
9589aa228fdSmrg
9590c7e83b2Smrg  data->scaleShell =
9600c7e83b2Smrg    XtVaCreatePopupShell("xmag", topLevelShellWidgetClass, toplevel,
9619aa228fdSmrg			 XtNgeometry, (XtArgVal)options.geometry,
9629aa228fdSmrg			 XtNtitle, (XtArgVal)options.title,
9639aa228fdSmrg			 NULL);
9649aa228fdSmrg  pane1 = XtCreateManagedWidget("pane1", panedWidgetClass, data->scaleShell,
9659aa228fdSmrg				(Arg *) NULL, 0);
9669aa228fdSmrg  pane2 = XtCreateManagedWidget("pane2", panedWidgetClass, pane1,
9679aa228fdSmrg				(Arg *) NULL, 0);
9689aa228fdSmrg  cclose = XtCreateManagedWidget("close", commandWidgetClass, pane2,
9699aa228fdSmrg				 (Arg *) NULL, 0);
9709aa228fdSmrg  XtAddCallback(cclose, XtNcallback, CloseCB, (XtPointer)data->scaleShell);
9719aa228fdSmrg  replace = XtCreateManagedWidget("replace", commandWidgetClass, pane2,
9729aa228fdSmrg				  (Arg *) NULL, 0);
9739aa228fdSmrg  XtAddCallback(replace, XtNcallback, ReplaceCB, (XtPointer)data);
9749aa228fdSmrg  new = XtCreateManagedWidget("new", commandWidgetClass, pane2,
9759aa228fdSmrg			      (Arg *) NULL, 0);
9769aa228fdSmrg  XtAddCallback(new, XtNcallback, NewCB, (XtPointer)NULL);
9779aa228fdSmrg  select_w = XtCreateManagedWidget("select", commandWidgetClass, pane2,
9789aa228fdSmrg			      (Arg *) NULL, 0);
9799aa228fdSmrg  XtAddCallback(select_w, XtNcallback, SelectCB, (XtPointer)data);
9809aa228fdSmrg  paste = XtCreateManagedWidget("paste", commandWidgetClass, pane2,
9819aa228fdSmrg			      (Arg *) NULL, 0);
9829aa228fdSmrg  XtAddCallback(paste, XtNcallback, PasteCB, (XtPointer)data);
9839aa228fdSmrg  (void) XtCreateManagedWidget("helpLabel", labelWidgetClass, pane2,
9849aa228fdSmrg			       (Arg *) NULL, 0);
9859aa228fdSmrg  pane3 = XtCreateManagedWidget("pane2", panedWidgetClass, pane1,
9869aa228fdSmrg				(Arg *) NULL, 0);
9870c7e83b2Smrg  data->scaleInstance =
9880c7e83b2Smrg    XtVaCreateManagedWidget("scale", scaleWidgetClass,
9899aa228fdSmrg			    pane3,
9909aa228fdSmrg			    XtNvisual, (XtArgVal)data->win_info.visual,
9919aa228fdSmrg			    XtNcolormap, (XtArgVal)data->win_info.colormap,
9929aa228fdSmrg			    XtNdepth, (XtArgVal)data->win_info.depth,
9939aa228fdSmrg			    XtNscaleX, (XtArgVal)options.mag,
9949aa228fdSmrg			    XtNscaleY, (XtArgVal)options.mag,
9959aa228fdSmrg			    NULL);
9969aa228fdSmrg  SWSetImage(data->scaleInstance, data->image);
9979aa228fdSmrg  XtOverrideTranslations
9989aa228fdSmrg    (data->scaleShell,
9999aa228fdSmrg     XtParseTranslationTable ("<Message>WM_PROTOCOLS: close()"));
10009aa228fdSmrg  XtSetArg(warg, XtNuserData, data);
10019aa228fdSmrg  XtSetValues(data->scaleInstance, &warg, 1);
10020c7e83b2Smrg  data->pixShell =
10030c7e83b2Smrg    XtVaCreatePopupShell("pixShell", overrideShellWidgetClass,
10049aa228fdSmrg			 toplevel,
10059aa228fdSmrg			 XtNvisual, (XtArgVal)data->win_info.visual,
10069aa228fdSmrg			 XtNcolormap, (XtArgVal)data->win_info.colormap,
10079aa228fdSmrg			 XtNdepth, (XtArgVal)data->win_info.depth,
10089aa228fdSmrg			 XtNborderWidth, (XtPointer)0,
10099aa228fdSmrg			 NULL);
10100c7e83b2Smrg  data->pixLabel =
10110c7e83b2Smrg    XtVaCreateManagedWidget("pixLabel", labelWidgetClass,
10120c7e83b2Smrg			    data->pixShell,
10139aa228fdSmrg			    XtNforeground, (XtPointer)GetMaxIntensity(data),
10149aa228fdSmrg			    XtNbackground, (XtPointer)GetMinIntensity(data),
10159aa228fdSmrg			    XtNborderWidth, (XtPointer)0,
10169aa228fdSmrg			    NULL);
10179aa228fdSmrg  XtInstallAllAccelerators(pane1, pane1);	/* install accelerators */
10189aa228fdSmrg  if (data->newScale) {
10199aa228fdSmrg    XtPopup(data->scaleShell, XtGrabNone);
10209aa228fdSmrg    (void) XSetWMProtocols	/* ICCCM delete window */
10219aa228fdSmrg      (dpy, XtWindow(data->scaleShell), &wm_delete_window, 1);
10229aa228fdSmrg  }
10239aa228fdSmrg  if (data->win_info.colormap != DefaultColormap(dpy, scr)) {
10240c7e83b2Smrg    data->cmapWinList[0] = data->scaleShell;
10259aa228fdSmrg    data->cmapWinList[1] = data->scaleInstance;
10269aa228fdSmrg    XtSetWMColormapWindows(data->scaleShell, data->cmapWinList, 2);
10279aa228fdSmrg  }
10289aa228fdSmrg}
10299aa228fdSmrg
10309aa228fdSmrg
10319aa228fdSmrg
10329aa228fdSmrg/*
10339aa228fdSmrg * RedoOldScale() -- If the visual, depth, or colormap has changed, unrealize
10349aa228fdSmrg *                   the scale widget and change its colormap/depth/visual.
10359aa228fdSmrg *                   Then re-realize it.  Also do this for the pixel display
10369aa228fdSmrg *                   widget.
10379aa228fdSmrg */
10389aa228fdSmrgstatic void
10399aa228fdSmrgRedoOldScale(hlPtr data)
10409aa228fdSmrg{
10419aa228fdSmrg  Arg wargs[3];
10429aa228fdSmrg  int n;
10439aa228fdSmrg  Visual *oldVis;
10449aa228fdSmrg  int oldDepth;
10459aa228fdSmrg  Colormap oldCmap;
10469aa228fdSmrg
10479aa228fdSmrg  n=0;
10489aa228fdSmrg  XtSetArg(wargs[n], XtNvisual, &oldVis); n++;
10499aa228fdSmrg  XtSetArg(wargs[n], XtNdepth, &oldDepth); n++;
10509aa228fdSmrg  XtSetArg(wargs[n], XtNcolormap, &oldCmap); n++;
10510c7e83b2Smrg  XtGetValues(data->scaleInstance, wargs, n);
10529aa228fdSmrg  if (oldVis == data->win_info.visual && oldDepth == data->win_info.depth
10539aa228fdSmrg      && oldCmap == data->win_info.colormap) {
10540c7e83b2Smrg    SWSetImage(data->scaleInstance, data->image);
10559aa228fdSmrg    return;
10569aa228fdSmrg  }
10579aa228fdSmrg  /* get width and height, save and reuse them */
10589aa228fdSmrg  XtUnmanageChild(data->scaleInstance);
10599aa228fdSmrg  XtUnrealizeWidget(data->scaleInstance);
10609aa228fdSmrg  n=0;
10619aa228fdSmrg  XtSetArg(wargs[n], XtNcolormap, data->win_info.colormap); n++;
10629aa228fdSmrg  XtSetArg(wargs[n], XtNdepth, data->win_info.depth); n++;
10639aa228fdSmrg  XtSetArg(wargs[n], XtNvisual, data->win_info.visual); n++;
10649aa228fdSmrg  XtSetValues(data->scaleInstance, wargs, n);
10659aa228fdSmrg  n=0;
10669aa228fdSmrg  XtSetArg(wargs[n], XtNforeground, GetMaxIntensity(data)); n++;
10679aa228fdSmrg  XtSetArg(wargs[n], XtNbackground, GetMinIntensity(data)); n++;
10689aa228fdSmrg  XtSetValues(data->pixLabel, wargs, n);
10690c7e83b2Smrg  SWSetImage(data->scaleInstance, data->image);
10709aa228fdSmrg  XtRealizeWidget(data->scaleInstance);
10719aa228fdSmrg  XtManageChild(data->scaleInstance);
10729aa228fdSmrg}
10739aa228fdSmrg
10749aa228fdSmrg
10759aa228fdSmrg
10769aa228fdSmrg/*
10779aa228fdSmrg * InitCursors() -- Create our cursors for area selection.
10789aa228fdSmrg */
10799aa228fdSmrgstatic void
10809aa228fdSmrgInitCursors(void)
10819aa228fdSmrg{
10829aa228fdSmrg  ulAngle = XCreateFontCursor(dpy, XC_ul_angle);
10839aa228fdSmrg  urAngle = XCreateFontCursor(dpy, XC_ur_angle);
10849aa228fdSmrg  lrAngle = XCreateFontCursor(dpy, XC_lr_angle);
10859aa228fdSmrg  llAngle = XCreateFontCursor(dpy, XC_ll_angle);
10869aa228fdSmrg}
10879aa228fdSmrg
10889aa228fdSmrg
10899aa228fdSmrg
10909aa228fdSmrg/*
10910c7e83b2Smrg * ParseSourceGeom() -- Determine dimensions of area to magnify from resources.
10929aa228fdSmrg */
10930c7e83b2Smrgstatic void
10949aa228fdSmrgParseSourceGeom(void)
10959aa228fdSmrg{
10969aa228fdSmrg				/* source */
10970c7e83b2Smrg  srcStat =
10989aa228fdSmrg    XParseGeometry(options.source, &srcX, &srcY, &srcWidth, &srcHeight);
10999aa228fdSmrg  if (!srcWidth) srcWidth = SRCWIDTH;
11009aa228fdSmrg  if (!srcHeight) srcHeight = SRCHEIGHT;
11019aa228fdSmrg  if (XNegative & srcStat) srcX = DisplayWidth(dpy, scr) + srcX - srcWidth;
11029aa228fdSmrg  if (YNegative & srcStat) srcY = DisplayHeight(dpy, scr) + srcY - srcHeight;
11039aa228fdSmrg				/* mag */
11049aa228fdSmrg}
11059aa228fdSmrg
11069aa228fdSmrg
11079aa228fdSmrg
11089aa228fdSmrg/*
11099aa228fdSmrg * Main program.
11109aa228fdSmrg */
11110c7e83b2Smrgint
11129aa228fdSmrgmain(int argc, char *argv[])
11139aa228fdSmrg{
11149aa228fdSmrg  XSetErrorHandler(Error);
11150c7e83b2Smrg
11169aa228fdSmrg				/* SUPPRESS 594 */
11179aa228fdSmrg  toplevel = XtAppInitialize(&app, "Xmag", optionDesc, XtNumber(optionDesc),
11189aa228fdSmrg			     &argc, argv, NULL,
11199aa228fdSmrg			     NULL, 0);
11209aa228fdSmrg
11219aa228fdSmrg  dpy = XtDisplay(toplevel);
11229aa228fdSmrg  scr = DefaultScreen(dpy);
11239aa228fdSmrg  XtGetApplicationResources(toplevel, (XtPointer) &options, resources,
11249aa228fdSmrg			    XtNumber(resources), NULL, 0);
11259aa228fdSmrg  if (argc != 1) {
11269aa228fdSmrg    fprintf (stderr,
11279aa228fdSmrg	    "usage:  xmag [-source geom] [-mag magfactor] [-toolkitoption]\n");
11289aa228fdSmrg    exit(1);
11299aa228fdSmrg  }
11300c7e83b2Smrg
11319aa228fdSmrg
11329aa228fdSmrg  ParseSourceGeom();
11339aa228fdSmrg  XtAppAddActions(app, actions_table, XtNumber(actions_table));
11349aa228fdSmrg  InitCursors();
11359aa228fdSmrg  SetupGC();
11369aa228fdSmrg  CreateRoot();
11379aa228fdSmrg  if (!(XValue & srcStat && YValue & srcStat))
11389aa228fdSmrg    StartRootPtrGrab(True, (hlPtr)NULL);
11399aa228fdSmrg  wm_delete_window = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
11409aa228fdSmrg  XtAppMainLoop(app);
11419aa228fdSmrg  exit(0);
11429aa228fdSmrg}
1143