xmag.c revision 0c7e83b2
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
299aa228fdSmrg#include "config.h"
309aa228fdSmrg
319aa228fdSmrg#include <stdlib.h>		/* for exit() and abs() */
329aa228fdSmrg#include <stdio.h>
339aa228fdSmrg
349aa228fdSmrg#include <X11/Intrinsic.h>
359aa228fdSmrg#include <X11/StringDefs.h>
369aa228fdSmrg#include <X11/Xaw/Paned.h>
379aa228fdSmrg#include <X11/Xaw/Command.h>
389aa228fdSmrg#include <X11/Xaw/Label.h>
399aa228fdSmrg#include <X11/Shell.h>
409aa228fdSmrg#include <X11/cursorfont.h>
419aa228fdSmrg#include <X11/Xmu/Error.h>
429aa228fdSmrg#include "RootWin.h"
439aa228fdSmrg#include "Scale.h"
449aa228fdSmrg#include "CutPaste.h"
459aa228fdSmrg
469aa228fdSmrg#define SRCWIDTH  64
479aa228fdSmrg#define SRCHEIGHT 64
489aa228fdSmrg
499aa228fdSmrg#ifndef min
509aa228fdSmrg#define min(a, b) ((a) < (b) ? (a) : (b))
519aa228fdSmrg#endif
529aa228fdSmrg
5383d7c197Smrg#ifndef max
5483d7c197Smrg#define max(a, b) ((a) > (b) ? (a) : (b))
5583d7c197Smrg#endif
5683d7c197Smrg
579aa228fdSmrg
589aa228fdSmrg
599aa228fdSmrg/* highlight interval (in milliseconds) */
609aa228fdSmrg#define HLINTERVAL  100
619aa228fdSmrg
629aa228fdSmrg/* sleep between draw & erase of highlight
639aa228fdSmrg * 20 milliseconds - enough for screen refresh - not too long to annoy users
649aa228fdSmrg *  since we hold a server grab during this time
659aa228fdSmrg */
669aa228fdSmrg#define HLSLEEPINTERVAL 20 /* milliseconds */
679aa228fdSmrg
689aa228fdSmrg#ifdef HAVE_NANOSLEEP
699aa228fdSmrg#include <time.h>
709aa228fdSmrg#define HLSLEEP	    do { \
719aa228fdSmrg	struct timespec sleeptime = { 0 , HLSLEEPINTERVAL * 1000000 } ;	\
729aa228fdSmrg	nanosleep(&sleeptime, NULL); \
739aa228fdSmrg    } while(0)
749aa228fdSmrg#elif defined(HAVE_POLL)
759aa228fdSmrg#include <poll.h>
769aa228fdSmrg#define HLSLEEP	    poll(NULL, 0, HLSLEEPINTERVAL)
779aa228fdSmrg#elif defined(HAVE_SELECT)
789aa228fdSmrg#include <X11/Xpoll.h>
799aa228fdSmrg#define HLSLEEP	    do { \
809aa228fdSmrg	struct timeval sleeptime = { 0 , HLSLEEPINTERVAL * 1000 } ;	\
819aa228fdSmrg	select(0, NULL, NULL, NULL, &sleeptime); \
829aa228fdSmrg    } while(0)
839aa228fdSmrg#else
849aa228fdSmrg#define HLSLEEP	XSync(dpy, False)
859aa228fdSmrg#endif
869aa228fdSmrg
879aa228fdSmrg/* highlight mode */
880c7e83b2Smrgtypedef enum { drag, resize, done } hlMode;
899aa228fdSmrg
909aa228fdSmrg/* highlight data structure */
910c7e83b2Smrgtypedef struct {
929aa228fdSmrg  Boolean   newScale;
939aa228fdSmrg  hlMode    selectMode;
949aa228fdSmrg  GC        gc;
950c7e83b2Smrg  XWindowAttributes win_info;
969aa228fdSmrg  XImage     *image;
979aa228fdSmrg  Position  homeX, homeY, x, y;
989aa228fdSmrg  Dimension width, height;
999aa228fdSmrg  Widget    scaleShell, scaleInstance, pixShell, pixLabel, cmapWinList [2];
1009aa228fdSmrg  } hlStruct, *hlPtr;
1019aa228fdSmrg
1029aa228fdSmrg
1039aa228fdSmrg
1049aa228fdSmrg/* global variables */
1059aa228fdSmrgstatic XtAppContext app;
1069aa228fdSmrgstatic Cursor ulAngle, urAngle, lrAngle, llAngle;
1079aa228fdSmrgstatic Display *dpy;
1089aa228fdSmrgstatic int scr;
1090c7e83b2Smrgstatic GC selectGC;
1109aa228fdSmrgstatic XGCValues selectGCV;
1119aa228fdSmrgstatic Widget toplevel, root;
1129aa228fdSmrgstatic Atom wm_delete_window;
1139aa228fdSmrgstatic int numXmags = 0;
1149aa228fdSmrgstatic int srcStat, srcX, srcY;
1159aa228fdSmrgstatic unsigned int srcWidth, srcHeight;
1169aa228fdSmrg
1179aa228fdSmrg/* forward declarations */
1189aa228fdSmrg
1199aa228fdSmrgstatic int Error(Display *, XErrorEvent *);
1209aa228fdSmrgstatic void CloseAP(Widget, XEvent *, String *, Cardinal *);
1219aa228fdSmrgstatic void SetCmapPropsAP(Widget, XEvent *, String *, Cardinal *);
1229aa228fdSmrgstatic void UnsetCmapPropsAP(Widget, XEvent *, String *, Cardinal *);
1239aa228fdSmrgstatic void NewAP(Widget, XEvent *, String *, Cardinal *);
1249aa228fdSmrgstatic void ReplaceAP(Widget, XEvent *, String *, Cardinal *);
1259aa228fdSmrgstatic void PopupPixelAP(Widget, XEvent *, String *, Cardinal *);
1269aa228fdSmrgstatic void UpdatePixelAP(Widget, XEvent *, String *, Cardinal *);
1279aa228fdSmrgstatic void PopdownPixelAP(Widget, XEvent *, String *, Cardinal *);
1289aa228fdSmrgstatic void SelectRegionAP(Widget, XEvent *, String *, Cardinal *);
1299aa228fdSmrgstatic void CheckPoints(Position *, Position *, Position *, Position *);
1309aa228fdSmrgstatic void HighlightTO(XtPointer, XtIntervalId *);
1319aa228fdSmrgstatic void CloseCB(Widget, XtPointer, XtPointer);
1329aa228fdSmrgstatic void ReplaceCB(Widget, XtPointer, XtPointer);
1339aa228fdSmrgstatic void NewCB(Widget, XtPointer, XtPointer);
1349aa228fdSmrgstatic void SelectCB(Widget, XtPointer, XtPointer);
1359aa228fdSmrgstatic void PasteCB(Widget, XtPointer, XtPointer);
1369aa228fdSmrgstatic void SetupGC(void);
1379aa228fdSmrgstatic Window FindWindow(int, int);
1389aa228fdSmrgstatic void ResizeEH(Widget, XtPointer, XEvent *, Boolean *);
1399aa228fdSmrgstatic void DragEH(Widget, XtPointer, XEvent *, Boolean *);
1409aa228fdSmrgstatic void StartRootPtrGrab(int, hlPtr);
1419aa228fdSmrgstatic void CreateRoot(void);
1429aa228fdSmrgstatic void GetImageAndAttributes(Window, int, int, int, int, hlPtr);
1439aa228fdSmrgstatic int Get_XColors(XWindowAttributes *, XColor **);
1449aa228fdSmrgstatic Pixel GetMaxIntensity(hlPtr);
1459aa228fdSmrgstatic Pixel GetMinIntensity(hlPtr);
1469aa228fdSmrgstatic void PopupNewScale(hlPtr);
1479aa228fdSmrgstatic void RedoOldScale(hlPtr);
1489aa228fdSmrgstatic void InitCursors(void);
1499aa228fdSmrgstatic void ParseSourceGeom(void);
1509aa228fdSmrg
1519aa228fdSmrg/* application resources */
1529aa228fdSmrg
1539aa228fdSmrgtypedef struct { String geometry, source, mag, title; } OptionsRec;
1549aa228fdSmrgstatic OptionsRec options;
1559aa228fdSmrg
1569aa228fdSmrg#define Offset(field) XtOffsetOf(OptionsRec, field)
1579aa228fdSmrgstatic XtResource resources[] = {
1589aa228fdSmrg  {"geometry", "Geometry", XtRString, sizeof(String),
1599aa228fdSmrg     Offset(geometry), XtRString, (XtPointer)NULL},
1609aa228fdSmrg  {"mag", "Mag", XtRString, sizeof(String),
1619aa228fdSmrg     Offset(mag), XtRString, (XtPointer)"5.0"},
1629aa228fdSmrg  {"source", "Source", XtRString, sizeof(String),
1639aa228fdSmrg     Offset(source), XtRString, (XtPointer)"SRCWIDTHxSRCHEIGHT"},
1649aa228fdSmrg  {"title", XtCString, XtRString, sizeof(char *),
1659aa228fdSmrg     Offset(title), XtRString, "xmag"},
1669aa228fdSmrg};
1679aa228fdSmrg#undef Offset
1689aa228fdSmrg
1699aa228fdSmrgstatic XrmOptionDescRec optionDesc[] = {
1709aa228fdSmrg  {"-bd",         "*borderColor", XrmoptionSepArg, (XtPointer)NULL},
1719aa228fdSmrg  {"-bg",         "*background",   XrmoptionSepArg, (XtPointer)NULL},
1729aa228fdSmrg  {"-bw",         "*borderWidth", XrmoptionSepArg, (XtPointer)NULL},
1730c7e83b2Smrg
1749aa228fdSmrg  {"-geometry", "*geometry", XrmoptionSepArg, (XtPointer)NULL},
1759aa228fdSmrg  {"-mag",      "*mag",                XrmoptionSepArg, (XtPointer)NULL},
1769aa228fdSmrg  {"-source",   "*source",             XrmoptionSepArg, (XtPointer)NULL},
1779aa228fdSmrg  {"-title",    "*title",              XrmoptionSepArg, (XtPointer)NULL},
1789aa228fdSmrg};
1799aa228fdSmrg
1809aa228fdSmrg
1819aa228fdSmrg
1829aa228fdSmrg/* action table */
1839aa228fdSmrg
1849aa228fdSmrgstatic XtActionsRec actions_table[] = {
1859aa228fdSmrg  {"close", CloseAP},
1869aa228fdSmrg  {"set-colors", SetCmapPropsAP},
1879aa228fdSmrg  {"unset-colors", UnsetCmapPropsAP},
1889aa228fdSmrg  {"new", NewAP},
1899aa228fdSmrg  {"replace", ReplaceAP},
1909aa228fdSmrg  {"popup-pixel", PopupPixelAP},
1919aa228fdSmrg  {"update-pixel", UpdatePixelAP},
1929aa228fdSmrg  {"popdown-pixel", PopdownPixelAP},
1939aa228fdSmrg  {"select-region", SelectRegionAP}
1949aa228fdSmrg};
1959aa228fdSmrg
1969aa228fdSmrg
1979aa228fdSmrg
1989aa228fdSmrg/*
1990c7e83b2Smrg * Error() -- Error handler:  Catch a bad match in magnifying an
2009aa228fdSmrg *            area that contains bits of different depths.
2019aa228fdSmrg */
2020c7e83b2Smrgstatic int
2039aa228fdSmrgError(Display *dpy, XErrorEvent *err)
2049aa228fdSmrg{
2059aa228fdSmrg  (void) XmuPrintDefaultErrorMessage (dpy, err, stderr);
2069aa228fdSmrg  return 0;
2079aa228fdSmrg}
2089aa228fdSmrg
2099aa228fdSmrg
2109aa228fdSmrg/*
2119aa228fdSmrg * CloseAP() -- Close this dialog.  If its the last one exit the program.
2120c7e83b2Smrg *
2139aa228fdSmrg */
2149aa228fdSmrgstatic void			/* ARGSUSED */
2159aa228fdSmrgCloseAP(Widget w, XEvent *event, String *params, Cardinal *num_params)
2169aa228fdSmrg{
2179aa228fdSmrg  Arg wargs[2]; int n; hlPtr data;
2189aa228fdSmrg  if (!--numXmags) exit(0);
2199aa228fdSmrg  if (event->type != ClientMessage) {
2209aa228fdSmrg    n = 0;			/* get user data */
2219aa228fdSmrg    XtSetArg(wargs[0], XtNuserData, &data); n++;
2220c7e83b2Smrg    XtGetValues(w, wargs, n);
2239aa228fdSmrg    w = data->scaleShell;
2249aa228fdSmrg  }
2259aa228fdSmrg  XtPopdown(w);
2269aa228fdSmrg  XtDestroyWidget(w);
2279aa228fdSmrg}
2289aa228fdSmrg
2299aa228fdSmrg
2309aa228fdSmrg
2319aa228fdSmrg/*
2329aa228fdSmrg * SetCmapPropsAP() -- Put the scale widget first in WM_COLORMAP_WINDOWS
2330c7e83b2Smrg *
2349aa228fdSmrg */
2359aa228fdSmrgstatic void			/* ARGSUSED */
2369aa228fdSmrgSetCmapPropsAP(Widget w, XEvent *event, String *params, Cardinal *num_params)
2379aa228fdSmrg{
2389aa228fdSmrg  Arg wargs[2]; int n; hlPtr data;
2399aa228fdSmrg  n = 0;			/* get user data */
2409aa228fdSmrg  XtSetArg(wargs[0], XtNuserData, &data); n++;
2419aa228fdSmrg  XtGetValues(w, wargs, n);
2429aa228fdSmrg  if (data->win_info.colormap != DefaultColormap(dpy, scr)) {
2439aa228fdSmrg    data->cmapWinList[0] = data->scaleInstance;
2449aa228fdSmrg    data->cmapWinList[1] = data->scaleShell;
2459aa228fdSmrg    XtSetWMColormapWindows(data->scaleShell, data->cmapWinList, 2);
2469aa228fdSmrg  }
2479aa228fdSmrg}
2489aa228fdSmrg
2499aa228fdSmrg
2509aa228fdSmrg
2519aa228fdSmrg/*
2529aa228fdSmrg * UnsetCmapPropsAP() -- Put the shell first in WM_COLORMAP_WINDOWS
2530c7e83b2Smrg *
2549aa228fdSmrg */
2559aa228fdSmrgstatic void			/* ARGSUSED */
2569aa228fdSmrgUnsetCmapPropsAP(Widget w, XEvent *event, String *params, Cardinal *num_params)
2579aa228fdSmrg{
2589aa228fdSmrg  Arg wargs[2]; int n; hlPtr data;
2599aa228fdSmrg  n = 0;			/* get user data */
2609aa228fdSmrg  XtSetArg(wargs[0], XtNuserData, &data); n++;
2619aa228fdSmrg  XtGetValues(w, wargs, n);
2629aa228fdSmrg  if (data->win_info.colormap != DefaultColormap(dpy, scr)) {
2639aa228fdSmrg    data->cmapWinList[0] = data->scaleShell;
2649aa228fdSmrg    data->cmapWinList[1] = data->scaleInstance;
2659aa228fdSmrg    XtSetWMColormapWindows(data->scaleShell, data->cmapWinList, 2);
2669aa228fdSmrg  }
2679aa228fdSmrg}
2689aa228fdSmrg
2699aa228fdSmrg
2709aa228fdSmrg
2719aa228fdSmrg/*
2729aa228fdSmrg * NewAP() -- Create an additional xmag dialog. THIS IS A COPY OF NewEH
2739aa228fdSmrg *                                              FIND A BETTER WAY....
2749aa228fdSmrg */
2759aa228fdSmrgstatic void			/* ARGSUSED */
2769aa228fdSmrgNewAP(Widget w, XEvent *event, String *params, Cardinal *num_params)
2779aa228fdSmrg{
2789aa228fdSmrg  StartRootPtrGrab(True, NULL);
2799aa228fdSmrg}
2809aa228fdSmrg
2819aa228fdSmrg
2829aa228fdSmrg
2839aa228fdSmrg/*
2849aa228fdSmrg * ReplaceAP() -- Replace this particular xmag dialog.
2859aa228fdSmrg */
2869aa228fdSmrgstatic void                     /* ARGSUSED */
2879aa228fdSmrgReplaceAP(Widget w, XEvent *event, String *params, Cardinal *num_params)
2889aa228fdSmrg{
2899aa228fdSmrg  Arg wargs[2]; int n; hlPtr data;
2909aa228fdSmrg  n = 0;			/* get user data */
2919aa228fdSmrg  XtSetArg(wargs[0], XtNuserData, &data); n++;
2920c7e83b2Smrg  XtGetValues(w, wargs, n);
2939aa228fdSmrg  StartRootPtrGrab(False, data);
2949aa228fdSmrg}
2959aa228fdSmrg
2969aa228fdSmrg
2979aa228fdSmrg
2989aa228fdSmrg/*
2999aa228fdSmrg * PopupPixelAP() -- Show pixel information.
3009aa228fdSmrg */
3019aa228fdSmrgstatic void			/* ARGSUSED */
3029aa228fdSmrgPopupPixelAP(Widget w, XEvent *event, String *params, Cardinal *num_params)
3039aa228fdSmrg{
3049aa228fdSmrg    Position scale_x, scale_y;
3059aa228fdSmrg    Dimension scale_height;
3069aa228fdSmrg    Position label_x, label_y;
3079aa228fdSmrg    Dimension label_height;
3089aa228fdSmrg    int n;
3099aa228fdSmrg    Arg wargs[3];
3109aa228fdSmrg    hlPtr data;
3119aa228fdSmrg
3129aa228fdSmrg    n = 0;			/* get user data */
3139aa228fdSmrg    XtSetArg(wargs[0], XtNuserData, &data); n++;
3149aa228fdSmrg    XtGetValues(w, wargs, n);
3159aa228fdSmrg
3169aa228fdSmrg    n = 0;
3179aa228fdSmrg    XtSetArg(wargs[n], XtNheight, &scale_height); n++;
3189aa228fdSmrg    XtGetValues(w, wargs, n);
3199aa228fdSmrg    XtTranslateCoords(w, -1, -1, &scale_x, &scale_y);
3200c7e83b2Smrg
3219aa228fdSmrg    XtRealizeWidget(data->pixShell); /* to get the right height  */
3229aa228fdSmrg
3239aa228fdSmrg    n = 0;
3249aa228fdSmrg    XtSetArg(wargs[n], XtNheight, &label_height); n++;
3259aa228fdSmrg    XtGetValues(data->pixShell, wargs, n);
3260c7e83b2Smrg
3279aa228fdSmrg    if ((double) event->xbutton.y / (double) scale_height > 0.5) {
3289aa228fdSmrg	label_x = scale_x;
3299aa228fdSmrg	label_y = scale_y;
3309aa228fdSmrg    }
3319aa228fdSmrg    else {
3329aa228fdSmrg	label_x = scale_x;
3339aa228fdSmrg	label_y = scale_y + scale_height - label_height;
3349aa228fdSmrg    }
3359aa228fdSmrg
3369aa228fdSmrg    n = 0;
3379aa228fdSmrg    XtSetArg(wargs[n], XtNx, label_x); n++;
3389aa228fdSmrg    XtSetArg(wargs[n], XtNy, label_y); n++;
3399aa228fdSmrg    XtSetValues(data->pixShell, wargs, n);
34083d7c197Smrg
34183d7c197Smrg    UpdatePixelAP(w, event, NULL, NULL);
3429aa228fdSmrg}
3439aa228fdSmrg
3449aa228fdSmrg
3459aa228fdSmrg
3469aa228fdSmrg/*
3479aa228fdSmrg * UpdatePixelAP() -- Update pixel information.
3489aa228fdSmrg */
3499aa228fdSmrgstatic void			/* ARGSUSED */
3509aa228fdSmrgUpdatePixelAP(Widget w, XEvent *event, String *params, Cardinal *num_params)
3519aa228fdSmrg{
3529aa228fdSmrg    Position x, y;
3539aa228fdSmrg    Pixel pixel;
3549aa228fdSmrg    XColor color;
3559aa228fdSmrg    int n;
3569aa228fdSmrg    Arg wargs[3];
3579aa228fdSmrg    char string[80];
3589aa228fdSmrg    hlPtr data;
3599aa228fdSmrg
3609aa228fdSmrg    n = 0;
3619aa228fdSmrg    XtSetArg(wargs[0], XtNuserData, &data); n++;
3629aa228fdSmrg    XtGetValues(w, wargs, n);
3639aa228fdSmrg
3649aa228fdSmrg    if (SWGetImagePixel(w, event->xbutton.x, event->xbutton.y, &x, &y, &pixel))
3659aa228fdSmrg	XtPopdown(data->pixShell);
3669aa228fdSmrg    else {
3679aa228fdSmrg	color.pixel = pixel;
3689aa228fdSmrg	XQueryColor(dpy, data->win_info.colormap, &color);
3690c7e83b2Smrg	snprintf(string, sizeof(string),
3700c7e83b2Smrg		 "Pixel %ld at (%d,%d) colored (%x,%x,%x).",
3710c7e83b2Smrg		 pixel, x + data->x, y + data->y,
3720c7e83b2Smrg		 color.red, color.green, color.blue);
3739aa228fdSmrg	n = 0;
3740c7e83b2Smrg	XtSetArg(wargs[n], XtNlabel, string); n++;
3759aa228fdSmrg	XtSetValues(data->pixLabel, wargs, n);
3769aa228fdSmrg	XtPopup(data->pixShell, XtGrabNone);
3779aa228fdSmrg    }
3789aa228fdSmrg}
3799aa228fdSmrg
3809aa228fdSmrg
3819aa228fdSmrg
3829aa228fdSmrg/*
3839aa228fdSmrg * PopdownPixelAP() -- Remove pixel info.
3849aa228fdSmrg */
3859aa228fdSmrgstatic void			/* ARGSUSED */
3869aa228fdSmrgPopdownPixelAP(Widget w, XEvent *event, String *params, Cardinal *num_params)
3879aa228fdSmrg{
3889aa228fdSmrg  int n;
3899aa228fdSmrg  Arg wargs[3];
3909aa228fdSmrg  hlPtr data = NULL;
3910c7e83b2Smrg
3929aa228fdSmrg  n = 0;
3939aa228fdSmrg  XtSetArg(wargs[0], XtNuserData, &data); n++;
3949aa228fdSmrg  XtGetValues(w, wargs, n);
3959aa228fdSmrg
3969aa228fdSmrg  if (data)
3979aa228fdSmrg    XtPopdown(data->pixShell);
3989aa228fdSmrg}
3999aa228fdSmrg
4009aa228fdSmrg
4019aa228fdSmrg
4029aa228fdSmrgstatic void			/* ARGSUSED */
4039aa228fdSmrgSelectRegionAP(Widget w, XEvent *event, String *params, Cardinal *num_params)
4040c7e83b2Smrg{
4050c7e83b2Smrg/***** NOT SURE WHAT TO DO WITH THIS
4069aa228fdSmrg    if (app_resources.unmap)
4079aa228fdSmrg	XtUnmapWidget(toplevel);
4089aa228fdSmrg    Redisplay(XtDisplay(w), RootWindow(XtDisplay(w),
4099aa228fdSmrg				       DefaultScreen(XtDisplay(w))),
4100c7e83b2Smrg	      source.width, source.height,
4110c7e83b2Smrg	      app_resources.freq, app_resources.puls,
4129aa228fdSmrg	      ul_angle, lr_angle,
4139aa228fdSmrg	      app_resources.grab);
4149aa228fdSmrg
4159aa228fdSmrg    if (app_resources.unmap)
4169aa228fdSmrg	XtMapWidget(toplevel);
4179aa228fdSmrg******/
4189aa228fdSmrg}
4199aa228fdSmrg
4209aa228fdSmrg
4219aa228fdSmrg
4220c7e83b2Smrg/*
4239aa228fdSmrg * CheckPoints() -- Change the cursor for the correct quadrant.
4240c7e83b2Smrg *                  Make sure the first point is less than the second
4259aa228fdSmrg *                  for drawing the selection rectangle.
4269aa228fdSmrg *
4279aa228fdSmrg */
4280c7e83b2Smrgstatic void
4299aa228fdSmrgCheckPoints(Position *x1, Position *x2, Position *y1, Position *y2)
4309aa228fdSmrg{
4310c7e83b2Smrg  Position tmp;
4329aa228fdSmrg  Boolean above, left;
4339aa228fdSmrg  Cursor newC;
4340c7e83b2Smrg  above = (*y2 < *y1); left = (*x2 < *x1);
4359aa228fdSmrg  if (above&&left) newC = ulAngle;
4369aa228fdSmrg  else if (above&&!left) newC = urAngle;
4379aa228fdSmrg  else if (!above&&!left) newC = lrAngle;
4389aa228fdSmrg  else newC = llAngle;
4399aa228fdSmrg  XChangeActivePointerGrab
4409aa228fdSmrg    (dpy, PointerMotionMask|ButtonPressMask|ButtonReleaseMask,
4419aa228fdSmrg     newC, CurrentTime);
4429aa228fdSmrg  if (*x2 < *x1) { tmp = *x1; *x1 = *x2; *x2 = tmp; }
4439aa228fdSmrg  if (*y2 < *y1) { tmp = *y1; *y1 = *y2; *y2 = tmp; }
4449aa228fdSmrg}
4459aa228fdSmrg
4469aa228fdSmrg
4479aa228fdSmrg
4489aa228fdSmrg/*
4499aa228fdSmrg * HighlightTO() -- Timer to highlight the selection box
4509aa228fdSmrg */
4519aa228fdSmrgstatic void
4529aa228fdSmrgHighlightTO(XtPointer closure, XtIntervalId *id)	/* ARGSUSED */
4539aa228fdSmrg{
4549aa228fdSmrg  hlPtr data = (hlPtr)closure;
4559aa228fdSmrg  XGrabServer(dpy);
4569aa228fdSmrg  if (data->selectMode == drag) {
4570c7e83b2Smrg    XDrawRectangle(dpy, DefaultRootWindow(dpy), data->gc,
4589aa228fdSmrg		   data->x, data->y, data->width, data->height);
4599aa228fdSmrg    XFlush(dpy);
4609aa228fdSmrg    HLSLEEP;
4610c7e83b2Smrg    XDrawRectangle(dpy, DefaultRootWindow(dpy), data->gc,
4629aa228fdSmrg		   data->x, data->y, data->width, data->height);
4639aa228fdSmrg  }
4640c7e83b2Smrg  else if (data->selectMode == resize) {
4659aa228fdSmrg    Position x1 = data->homeX,
4669aa228fdSmrg             x2 = data->x,
4679aa228fdSmrg             y1 = data->homeY,
4689aa228fdSmrg             y2 = data->y;
4699aa228fdSmrg    CheckPoints(&x1, &x2, &y1, &y2);
4700c7e83b2Smrg    XDrawRectangle(dpy, DefaultRootWindow(dpy), data->gc,
4719aa228fdSmrg		   x1, y1, x2 - x1, y2 - y1);
4729aa228fdSmrg    XFlush(dpy);
4739aa228fdSmrg    HLSLEEP;
4740c7e83b2Smrg    XDrawRectangle(dpy, DefaultRootWindow(dpy), data->gc,
4759aa228fdSmrg		   x1, y1, x2 - x1, y2 - y1);
4769aa228fdSmrg  }
4779aa228fdSmrg  XUngrabServer(dpy);
4789aa228fdSmrg  if (data->selectMode != done)
4799aa228fdSmrg    XtAppAddTimeOut(app, HLINTERVAL, HighlightTO, (XtPointer)data);
4809aa228fdSmrg}
4819aa228fdSmrg
4829aa228fdSmrg
4839aa228fdSmrg
4849aa228fdSmrg/*
4859aa228fdSmrg * CloseCB() -- Delete this xmag dialog.  If its the only one on the screen
4869aa228fdSmrg *             then exit.
4879aa228fdSmrg */
4889aa228fdSmrgstatic void			/* ARGSUSED */
4899aa228fdSmrgCloseCB(Widget w, XtPointer clientData, XtPointer callData)
4909aa228fdSmrg{
4919aa228fdSmrg  Widget shell = (Widget)clientData;
4929aa228fdSmrg  if (!--numXmags) exit(0);
4939aa228fdSmrg  XtPopdown(shell);
4949aa228fdSmrg  XtDestroyWidget(shell);
4959aa228fdSmrg}
4969aa228fdSmrg
4979aa228fdSmrg
4989aa228fdSmrg
4999aa228fdSmrg/*
5009aa228fdSmrg * ReplaceCB() -- Replace this particular xmag dialog.
5019aa228fdSmrg */
5029aa228fdSmrgstatic void                     /* ARGSUSED */
5039aa228fdSmrgReplaceCB(Widget w, XtPointer clientData, XtPointer callData)
5049aa228fdSmrg{
5059aa228fdSmrg  hlPtr data = (hlPtr)clientData;
5069aa228fdSmrg  StartRootPtrGrab(False, data);
5079aa228fdSmrg}
5089aa228fdSmrg
5099aa228fdSmrg
5109aa228fdSmrg
5119aa228fdSmrg/*
5129aa228fdSmrg * NewCB() -- Create an additional xmag dialog.
5139aa228fdSmrg */
5149aa228fdSmrgstatic void			/* ARGSUSED */
5159aa228fdSmrgNewCB(Widget w, XtPointer clientData, XtPointer callData)
5169aa228fdSmrg{
5179aa228fdSmrg  StartRootPtrGrab(True, NULL);
5189aa228fdSmrg}
5199aa228fdSmrg
5209aa228fdSmrg
5219aa228fdSmrg
5229aa228fdSmrg/*
5239aa228fdSmrg * SelectCB() -- Own the primary selection.
5249aa228fdSmrg */
5259aa228fdSmrgstatic void			/* ARGSUSED */
5269aa228fdSmrgSelectCB(Widget w, XtPointer clientData, XtPointer callData)
5279aa228fdSmrg{
5289aa228fdSmrg  hlPtr data = (hlPtr)clientData;
5299aa228fdSmrg  SWGrabSelection(data->scaleInstance, XtLastTimestampProcessed(dpy));
5309aa228fdSmrg}
5319aa228fdSmrg
5329aa228fdSmrg
5339aa228fdSmrg
5349aa228fdSmrg/*
5359aa228fdSmrg * PasteCB() -- Paste from the primary selectin into xmag.
5369aa228fdSmrg */
5379aa228fdSmrgstatic void			/* ARGSUSED */
5389aa228fdSmrgPasteCB(Widget w, XtPointer clientData, XtPointer callData)
5399aa228fdSmrg{
5409aa228fdSmrg  hlPtr data = (hlPtr)clientData;
5419aa228fdSmrg  SWRequestSelection(data->scaleInstance, XtLastTimestampProcessed(dpy));
5429aa228fdSmrg}
5439aa228fdSmrg
5449aa228fdSmrg
5459aa228fdSmrg
5469aa228fdSmrg/*
5479aa228fdSmrg * SetupGC() -- Graphics context for magnification selection.
5489aa228fdSmrg */
5490c7e83b2Smrgstatic void
5509aa228fdSmrgSetupGC(void)
5519aa228fdSmrg{
5529aa228fdSmrg    selectGCV.function = GXxor;
5539aa228fdSmrg    selectGCV.foreground = 0xffffffff;
5549aa228fdSmrg    selectGCV.subwindow_mode = IncludeInferiors;
5559aa228fdSmrg    selectGC = XtGetGC(toplevel, GCFunction|GCForeground|GCSubwindowMode,
5569aa228fdSmrg		       &selectGCV);
5570c7e83b2Smrg}
5589aa228fdSmrg
5599aa228fdSmrg
5609aa228fdSmrg
5619aa228fdSmrg/*
5620c7e83b2Smrg * FindWindow() -- Determine window the pointer is over.
5639aa228fdSmrg *
5649aa228fdSmrg */
5650c7e83b2Smrgstatic Window
5660c7e83b2SmrgFindWindow(int x, int y)	/* Location of cursor */
5679aa228fdSmrg{
5689aa228fdSmrg  XWindowAttributes wa;
5699aa228fdSmrg  Window findW = DefaultRootWindow(dpy), stopW, childW;
5709aa228fdSmrg
5719aa228fdSmrg  /* Setup for first window find */
5729aa228fdSmrg  stopW = findW;
5739aa228fdSmrg
5749aa228fdSmrg  while (stopW) {
5750c7e83b2Smrg    XTranslateCoordinates(dpy, findW, stopW,
5769aa228fdSmrg			  x, y, &x, &y, &childW);
5779aa228fdSmrg    findW = stopW;
5789aa228fdSmrg    /* If child is not InputOutput (for example, InputOnly) */
5799aa228fdSmrg    /* then don't continue, return the present findW which */
5809aa228fdSmrg    /* can be the root, or a root child of class InputOutput */
5819aa228fdSmrg    if (childW &&
5829aa228fdSmrg	XGetWindowAttributes(dpy, childW, &wa) &&
5839aa228fdSmrg	wa.class != InputOutput)
5849aa228fdSmrg	break;
5859aa228fdSmrg    stopW = childW;
5869aa228fdSmrg  }
5879aa228fdSmrg  return findW;
5889aa228fdSmrg}
5899aa228fdSmrg
5909aa228fdSmrg
5919aa228fdSmrg
5929aa228fdSmrg/*
5939aa228fdSmrg * ResizeEH() -- Event Handler for resize of selection box.
5949aa228fdSmrg */
5950c7e83b2Smrgstatic void
5960c7e83b2SmrgResizeEH(Widget w, XtPointer closure, XEvent *event,
5979aa228fdSmrg	 Boolean *continue_to_dispatch)	/* ARGSUSED */
5989aa228fdSmrg{
5999aa228fdSmrg  hlPtr data = (hlPtr)closure;
6009aa228fdSmrg  switch (event->type) {
6019aa228fdSmrg  case MotionNotify:
6029aa228fdSmrg    data->x = event->xmotion.x_root;
6030c7e83b2Smrg    data->y = event->xmotion.y_root;
6049aa228fdSmrg    break;
6059aa228fdSmrg  case ButtonRelease:
6069aa228fdSmrg    GetImageAndAttributes(FindWindow(event->xmotion.x_root,
6079aa228fdSmrg			event->xmotion.y_root),
6089aa228fdSmrg	     min(data->homeX,event->xbutton.x_root),
6099aa228fdSmrg	     min(data->homeY,event->xbutton.y_root),
6109aa228fdSmrg	     abs(data->homeX - event->xbutton.x_root),
6119aa228fdSmrg	     abs(data->homeY - event->xbutton.y_root),
6129aa228fdSmrg	     data);
6139aa228fdSmrg    if (data->newScale)
6149aa228fdSmrg      PopupNewScale(data);
6150c7e83b2Smrg    else
6169aa228fdSmrg      SWSetImage(data->scaleInstance, data->image);
6179aa228fdSmrg    XtUngrabPointer(w, CurrentTime);
6189aa228fdSmrg/*****
6199aa228fdSmrg    XtRemoveRawEventHandler(w, PointerMotionMask|ButtonReleaseMask,
6209aa228fdSmrg			 True, ResizeEH, (XtPointer)data);
6219aa228fdSmrg*****/
6229aa228fdSmrg    XtRemoveEventHandler(w, PointerMotionMask|ButtonReleaseMask,
6239aa228fdSmrg			 True, ResizeEH, (XtPointer)data);
6249aa228fdSmrg    data->selectMode = done;
6259aa228fdSmrg    break;
6269aa228fdSmrg  }
6279aa228fdSmrg}
6289aa228fdSmrg
6299aa228fdSmrg
6309aa228fdSmrg
6319aa228fdSmrg/*
6320c7e83b2Smrg * DragEH() -- Event Handler for dragging selection box.
6339aa228fdSmrg */
6340c7e83b2Smrgstatic void
6350c7e83b2SmrgDragEH(Widget w, XtPointer closure, XEvent *event,
6369aa228fdSmrg       Boolean *continue_to_dispatch) /* ARGSUSED */
6379aa228fdSmrg{
6389aa228fdSmrg  hlPtr data = (hlPtr)closure;
6399aa228fdSmrg  switch (event->type) {
6409aa228fdSmrg  case MotionNotify:		/* drag mode */
6419aa228fdSmrg    data->x = event->xmotion.x_root;
6429aa228fdSmrg    data->y = event->xmotion.y_root;
6439aa228fdSmrg    break;
6449aa228fdSmrg  case ButtonRelease:		/* end drag mode */
6459aa228fdSmrg    if (event->xbutton.button == Button1) { /* get image */
6469aa228fdSmrg      /* Problem: You can't get bits with XGetImage outside of its window.
6479aa228fdSmrg       *          xmag will only do a GetImage on the actual window in the case
6489aa228fdSmrg       *          where the depth of the window does not match the depth of
6499aa228fdSmrg       *          the root window.
6509aa228fdSmrg       */
6510c7e83b2Smrg      GetImageAndAttributes(FindWindow(event->xmotion.x_root,
6529aa228fdSmrg			  event->xmotion.y_root),
6530c7e83b2Smrg	       event->xbutton.x_root,
6549aa228fdSmrg	       event->xbutton.y_root,
6559aa228fdSmrg	       srcWidth, srcHeight, data);
6569aa228fdSmrg      if (data->newScale)
6579aa228fdSmrg	PopupNewScale(data);
6589aa228fdSmrg      else
6599aa228fdSmrg	RedoOldScale(data);
6609aa228fdSmrg      XtUngrabPointer(w, CurrentTime);
6619aa228fdSmrg      XtRemoveRawEventHandler(w, PointerMotionMask|ButtonPressMask|
6629aa228fdSmrg			      ButtonReleaseMask, True, DragEH,
6639aa228fdSmrg			      (XtPointer)data);
6649aa228fdSmrg      data->selectMode = done;
6659aa228fdSmrg    }
6669aa228fdSmrg
6679aa228fdSmrg    break;
6680c7e83b2Smrg  case ButtonPress:
6699aa228fdSmrg    if (event->xbutton.button == Button2) {	/* turn on resize mode */
6700c7e83b2Smrg      data->homeX = event->xbutton.x_root;
6719aa228fdSmrg      data->homeY = event->xbutton.y_root;
6729aa228fdSmrg      data->x = event->xbutton.x_root + srcWidth;
6730c7e83b2Smrg      data->y = event->xbutton.y_root + srcHeight;
6749aa228fdSmrg      data->selectMode = resize;
6759aa228fdSmrg      XtRemoveRawEventHandler(w, PointerMotionMask|ButtonPressMask|
6769aa228fdSmrg			   ButtonReleaseMask, True, DragEH, (XtPointer)data);
6779aa228fdSmrg      XChangeActivePointerGrab
6789aa228fdSmrg	(dpy, PointerMotionMask|ButtonPressMask|ButtonReleaseMask,
6799aa228fdSmrg	 lrAngle, CurrentTime);
6800c7e83b2Smrg      XWarpPointer(dpy, None, None, 0, 0, 0, 0,
6819aa228fdSmrg		   srcWidth, srcHeight);
6820c7e83b2Smrg      XtAddEventHandler(w, PointerMotionMask|ButtonReleaseMask,
6839aa228fdSmrg			True, ResizeEH, (XtPointer)data);
6849aa228fdSmrg    }
6859aa228fdSmrg    break;
6869aa228fdSmrg  }
6879aa228fdSmrg}
6889aa228fdSmrg
6899aa228fdSmrg
6909aa228fdSmrg
6919aa228fdSmrg
6929aa228fdSmrg/*
6939aa228fdSmrg * StartRootPtrGrab() -- Bring up the selection box.
6940c7e83b2Smrg *
6959aa228fdSmrg */
6969aa228fdSmrgstatic void
6970c7e83b2SmrgStartRootPtrGrab(int new, 	/* do we create a new scale instance? */
6980c7e83b2Smrg		 hlPtr data)	/* highlight data */
6999aa228fdSmrg{
7009aa228fdSmrg  Window    rootR, childR;
7019aa228fdSmrg  int       rootX, rootY, winX, winY;
7029aa228fdSmrg  unsigned  int mask;
7039aa228fdSmrg  hlPtr hlData;
7049aa228fdSmrg  XtGrabPointer
7059aa228fdSmrg    (root, False,
7069aa228fdSmrg     PointerMotionMask|ButtonPressMask|ButtonReleaseMask,
7079aa228fdSmrg     GrabModeAsync, GrabModeAsync, None, ulAngle, CurrentTime);
7080c7e83b2Smrg  XQueryPointer(dpy, DefaultRootWindow(dpy), &rootR, &childR,
7099aa228fdSmrg		&rootX, &rootY, &winX, &winY, &mask);
7109aa228fdSmrg  if (new) {
7119aa228fdSmrg    numXmags++;
7129aa228fdSmrg    hlData = (hlPtr)XtMalloc(sizeof(hlStruct));
7139aa228fdSmrg  }
7149aa228fdSmrg  else hlData = data;
7159aa228fdSmrg  hlData->newScale   = new;
7169aa228fdSmrg  hlData->selectMode = drag;
7179aa228fdSmrg  hlData->x          = rootX;
7189aa228fdSmrg  hlData->y          = rootY;
7199aa228fdSmrg  hlData->gc         = selectGC;
7209aa228fdSmrg  hlData->width      = srcWidth;
7219aa228fdSmrg  hlData->height     = srcHeight;
7229aa228fdSmrg  XtAddRawEventHandler
7230c7e83b2Smrg    (root, PointerMotionMask|ButtonPressMask|ButtonReleaseMask,
7249aa228fdSmrg     True, DragEH, (XtPointer)hlData);
7259aa228fdSmrg  (void) XtAppAddTimeOut(app, HLINTERVAL, HighlightTO, (XtPointer)hlData);
7269aa228fdSmrg}
7279aa228fdSmrg
7289aa228fdSmrg
7299aa228fdSmrg
7309aa228fdSmrg/*
7319aa228fdSmrg * CreateRoot() -- Create a root window widget. If the user specified x and y
7320c7e83b2Smrg *                 in the source geometry then use this to directly get the
7339aa228fdSmrg *                 image.
7349aa228fdSmrg */
7359aa228fdSmrgstatic void
7369aa228fdSmrgCreateRoot(void)
7379aa228fdSmrg{
7389aa228fdSmrg  hlPtr data;
7399aa228fdSmrg  root = XtCreateWidget("root", rootWindowWidgetClass, toplevel, NULL, 0);
7409aa228fdSmrg  XtRealizeWidget(root);
7410c7e83b2Smrg  if (XValue & srcStat && YValue &srcStat) {
7429aa228fdSmrg    numXmags = 1;
7439aa228fdSmrg    data = (hlPtr)XtMalloc(sizeof(hlStruct));
7449aa228fdSmrg    data = data;
7459aa228fdSmrg    data->newScale   = True;
7469aa228fdSmrg    data->selectMode = drag;
7479aa228fdSmrg    data->x          = srcX;
7489aa228fdSmrg    data->y          = srcY;
7499aa228fdSmrg    data->gc         = selectGC;
7509aa228fdSmrg    data->width      = srcWidth;
7519aa228fdSmrg    data->height     = srcHeight;
7520c7e83b2Smrg    GetImageAndAttributes(RootWindow(dpy, scr), srcX, srcY, srcWidth,
7539aa228fdSmrg			  srcHeight, data);
7549aa228fdSmrg    PopupNewScale(data);
7559aa228fdSmrg    return;
7569aa228fdSmrg  }
7579aa228fdSmrg}
7589aa228fdSmrg
7599aa228fdSmrg
7600c7e83b2Smrg/*
7619aa228fdSmrg * GetImageAndAttributes() -- Get the image bits from the screen.
7620c7e83b2Smrg *               We will also determine here the colormap, depth, and
7630c7e83b2Smrg *               visual to be used for the magnification image.
7649aa228fdSmrg */
7650c7e83b2Smrgstatic void
7660c7e83b2SmrgGetImageAndAttributes(Window w, int x, int y, int width, int height,
7679aa228fdSmrg		      hlPtr data)
7689aa228fdSmrg{
76983d7c197Smrg    /* get parameters of window being magnified */
77083d7c197Smrg    XGetWindowAttributes(dpy, w, &data->win_info);
77183d7c197Smrg
77283d7c197Smrg    if (data->win_info.depth == DefaultDepth(dpy, scr)) {
77383d7c197Smrg	/* avoid off screen pixels */
77483d7c197Smrg	if (x < 0)
77583d7c197Smrg	    x = 0;
77683d7c197Smrg	if (y < 0)
77783d7c197Smrg	    y = 0;
77883d7c197Smrg	if (x + width > DisplayWidth(dpy,scr))
77983d7c197Smrg	    x = DisplayWidth(dpy,scr) - width;
78083d7c197Smrg	if (y + height > DisplayHeight(dpy,scr))
78183d7c197Smrg	    y = DisplayHeight(dpy,scr) - height;
78283d7c197Smrg	data->x = x; data->y = y;
78383d7c197Smrg	/* get image pixels */
78483d7c197Smrg	data->image = XGetImage (dpy,
78583d7c197Smrg				 RootWindow(dpy, scr),
78683d7c197Smrg				 x, y,
78783d7c197Smrg				 width, height,
78883d7c197Smrg				 AllPlanes, ZPixmap);
78983d7c197Smrg    }
79083d7c197Smrg    else {
79183d7c197Smrg	int	t0, t1;
79283d7c197Smrg	int	x0, x1, y0, y1;
79383d7c197Smrg	int	xInWin, yInWin;
79483d7c197Smrg	Window	childWin;
79583d7c197Smrg
79683d7c197Smrg	XTranslateCoordinates(dpy, DefaultRootWindow(dpy), w, x, y,
79783d7c197Smrg			      &xInWin, &yInWin, &childWin);
79883d7c197Smrg
79983d7c197Smrg	/* Avoid off screen pixels. Assume this routine is not
80083d7c197Smrg	 * called for totally offscreen windows. */
80183d7c197Smrg	x0 = max(x, 0);
80283d7c197Smrg	y0 = max(y, 0);
80383d7c197Smrg	x1 = min(DisplayWidth(dpy, scr),
80483d7c197Smrg		 min(x0 + width, x0 + (data->win_info.width - xInWin)));
80583d7c197Smrg	y1 = min(DisplayHeight(dpy, scr),
80683d7c197Smrg		 min(y0 + height, y0 + (data->win_info.height - yInWin)));
80783d7c197Smrg
80883d7c197Smrg	/* Try to use up to width x height pixels */
80983d7c197Smrg	if (x1 - x0 < width) {
81083d7c197Smrg	    t0 = x0;
81183d7c197Smrg	    t1 = max(0, x - xInWin + data->win_info.width -
81283d7c197Smrg		     DisplayWidth(dpy, scr));
81383d7c197Smrg	    x0 = max(0, x1 - min(width, data->win_info.width - t1));
81483d7c197Smrg	    xInWin -= t0 - x0;
81583d7c197Smrg	}
81683d7c197Smrg	if (y1 - y0 < height) {
81783d7c197Smrg	    t0 = y0;
81883d7c197Smrg	    t1 = max(0, y - yInWin + data->win_info.height -
81983d7c197Smrg		     DisplayHeight(dpy, scr));
82083d7c197Smrg	    y0 = max(0, y1 - min(height, data->win_info.height - t1));
82183d7c197Smrg	    yInWin -= t0 - y0;
82283d7c197Smrg	}
82383d7c197Smrg
82483d7c197Smrg	data->x = x0;
82583d7c197Smrg	data->y = y0;
82683d7c197Smrg	data->width = x1 - x0;
82783d7c197Smrg	data->height = y1 - y0;
82883d7c197Smrg
82983d7c197Smrg	data->image = XGetImage (dpy,
83083d7c197Smrg				 w,
83183d7c197Smrg				 xInWin, yInWin,
83283d7c197Smrg				 data->width, data->height,
83383d7c197Smrg				 AllPlanes, ZPixmap);
83483d7c197Smrg
83583d7c197Smrg    }
8369aa228fdSmrg}
8379aa228fdSmrg
8389aa228fdSmrg
8399aa228fdSmrg
8409aa228fdSmrg/*
8419aa228fdSmrg * Get_XColors() Get the XColors of all pixels in image - returns # of colors
8429aa228fdSmrg *               This function was taken from xwd (thanks Bob...)
8439aa228fdSmrg */
8449aa228fdSmrg#define lowbit(x) ((x) & (~(x) + 1))
8450c7e83b2Smrgstatic int
8469aa228fdSmrgGet_XColors(XWindowAttributes *win_info, XColor **colors)
8479aa228fdSmrg{
8489aa228fdSmrg    int i, ncolors;
8490c7e83b2Smrg
8509aa228fdSmrg    if (!win_info->colormap)
8519aa228fdSmrg        return(0);
8520c7e83b2Smrg
8539aa228fdSmrg    ncolors = win_info->visual->map_entries;
8549aa228fdSmrg    if (!(*colors = (XColor *) XtMalloc (sizeof(XColor) * ncolors)))
8559aa228fdSmrg      XtError("Out of memory!");
8560c7e83b2Smrg
8579aa228fdSmrg    if (win_info->visual->class == DirectColor ||
8589aa228fdSmrg        win_info->visual->class == TrueColor) {
8599aa228fdSmrg        Pixel red, green, blue, red1, green1, blue1;
8600c7e83b2Smrg
8619aa228fdSmrg        red = green = blue = 0;
8629aa228fdSmrg        red1 = lowbit(win_info->visual->red_mask);
8639aa228fdSmrg        green1 = lowbit(win_info->visual->green_mask);
8649aa228fdSmrg        blue1 = lowbit(win_info->visual->blue_mask);
8659aa228fdSmrg        for (i=0; i<ncolors; i++) {
8669aa228fdSmrg          (*colors)[i].pixel = red|green|blue;
8679aa228fdSmrg          (*colors)[i].pad = 0;
8689aa228fdSmrg          red += red1;
8699aa228fdSmrg          if (red > win_info->visual->red_mask)
8709aa228fdSmrg            red = 0;
8719aa228fdSmrg          green += green1;
8729aa228fdSmrg          if (green > win_info->visual->green_mask)
8739aa228fdSmrg            green = 0;
8749aa228fdSmrg          blue += blue1;
8759aa228fdSmrg          if (blue > win_info->visual->blue_mask)
8769aa228fdSmrg            blue = 0;
8779aa228fdSmrg        }
8789aa228fdSmrg    } else {
8799aa228fdSmrg        for (i=0; i<ncolors; i++) {
8809aa228fdSmrg          (*colors)[i].pixel = i;
8819aa228fdSmrg          (*colors)[i].pad = 0;
8829aa228fdSmrg        }
8839aa228fdSmrg    }
8840c7e83b2Smrg
8859aa228fdSmrg    XQueryColors(dpy, win_info->colormap, *colors, ncolors);
8860c7e83b2Smrg
8879aa228fdSmrg    return(ncolors);
8889aa228fdSmrg}
8899aa228fdSmrg
8909aa228fdSmrg
8919aa228fdSmrg
8929aa228fdSmrg#define Intensity(cptr) (3.0*cptr->red+0.59*cptr->green+0.11*cptr->blue)
8939aa228fdSmrg
8949aa228fdSmrg/*
8959aa228fdSmrg * GetMaxIntensity() -- Find the maximum intensity pixel value for a colormap.
8969aa228fdSmrg */
8979aa228fdSmrgstatic Pixel
8989aa228fdSmrgGetMaxIntensity(hlPtr data)
8999aa228fdSmrg{
9009aa228fdSmrg  XColor *colors = NULL, *mptr, *tptr;
9019aa228fdSmrg  int i, ncolors;
9029aa228fdSmrg
9030c7e83b2Smrg  if (data->win_info.colormap == DefaultColormap(dpy, scr))
9049aa228fdSmrg    return WhitePixel(dpy, scr);
9050c7e83b2Smrg  ncolors = Get_XColors(&data->win_info, &colors);
9069aa228fdSmrg  mptr = tptr = colors; tptr++;
9079aa228fdSmrg  for (i=1; i<ncolors; i++) {
9080c7e83b2Smrg    if ((int)Intensity(mptr) < (int)Intensity(tptr))
9099aa228fdSmrg      mptr = tptr;
9109aa228fdSmrg    tptr++;
9119aa228fdSmrg  }
9129aa228fdSmrg  /* Null pointer protection */
9139aa228fdSmrg  if(mptr)
9149aa228fdSmrg    return mptr->pixel;
9159aa228fdSmrg  else
9169aa228fdSmrg    return WhitePixel(dpy, scr);
9179aa228fdSmrg}
9189aa228fdSmrg
9199aa228fdSmrg/*
9209aa228fdSmrg * GetMinIntensity() -- Find the minimum intensity pixel value for a colormap.
9219aa228fdSmrg */
9229aa228fdSmrgstatic Pixel
9239aa228fdSmrgGetMinIntensity(hlPtr data)
9249aa228fdSmrg{
9259aa228fdSmrg  XColor *colors = NULL, *mptr, *tptr;
9269aa228fdSmrg  int i, ncolors;
9279aa228fdSmrg
9280c7e83b2Smrg  if (data->win_info.colormap == DefaultColormap(dpy, scr))
9299aa228fdSmrg    return BlackPixel(dpy, scr);
9300c7e83b2Smrg  ncolors = Get_XColors(&data->win_info, &colors);
9319aa228fdSmrg  mptr = tptr = colors; tptr++;
9329aa228fdSmrg  for (i=1; i<ncolors; i++)  {
9339aa228fdSmrg    if ((int)Intensity(mptr) > (int)Intensity(tptr))
9340c7e83b2Smrg      mptr = tptr;
9359aa228fdSmrg    tptr++;
9369aa228fdSmrg  }
9379aa228fdSmrg  /* Null pointer protection */
9389aa228fdSmrg  if(mptr)
9399aa228fdSmrg    return mptr->pixel;
9409aa228fdSmrg  else
9419aa228fdSmrg    return BlackPixel(dpy, scr);
9429aa228fdSmrg}
9439aa228fdSmrg
9449aa228fdSmrg
9459aa228fdSmrg
9469aa228fdSmrg
9479aa228fdSmrgstatic Widget pane1, pane2, pane3, cclose, replace, new, select_w, paste;
9489aa228fdSmrg
9499aa228fdSmrg/*
9509aa228fdSmrg * PopupNewScale() -- Create and popup a new scale composite.
9519aa228fdSmrg */
9520c7e83b2Smrgstatic void
9539aa228fdSmrgPopupNewScale(hlPtr data)
9549aa228fdSmrg{
9559aa228fdSmrg  Arg warg;
9569aa228fdSmrg
9570c7e83b2Smrg  data->scaleShell =
9580c7e83b2Smrg    XtVaCreatePopupShell("xmag", topLevelShellWidgetClass, toplevel,
9599aa228fdSmrg			 XtNgeometry, (XtArgVal)options.geometry,
9609aa228fdSmrg			 XtNtitle, (XtArgVal)options.title,
9619aa228fdSmrg			 NULL);
9629aa228fdSmrg  pane1 = XtCreateManagedWidget("pane1", panedWidgetClass, data->scaleShell,
9639aa228fdSmrg				(Arg *) NULL, 0);
9649aa228fdSmrg  pane2 = XtCreateManagedWidget("pane2", panedWidgetClass, pane1,
9659aa228fdSmrg				(Arg *) NULL, 0);
9669aa228fdSmrg  cclose = XtCreateManagedWidget("close", commandWidgetClass, pane2,
9679aa228fdSmrg				 (Arg *) NULL, 0);
9689aa228fdSmrg  XtAddCallback(cclose, XtNcallback, CloseCB, (XtPointer)data->scaleShell);
9699aa228fdSmrg  replace = XtCreateManagedWidget("replace", commandWidgetClass, pane2,
9709aa228fdSmrg				  (Arg *) NULL, 0);
9719aa228fdSmrg  XtAddCallback(replace, XtNcallback, ReplaceCB, (XtPointer)data);
9729aa228fdSmrg  new = XtCreateManagedWidget("new", commandWidgetClass, pane2,
9739aa228fdSmrg			      (Arg *) NULL, 0);
9749aa228fdSmrg  XtAddCallback(new, XtNcallback, NewCB, (XtPointer)NULL);
9759aa228fdSmrg  select_w = XtCreateManagedWidget("select", commandWidgetClass, pane2,
9769aa228fdSmrg			      (Arg *) NULL, 0);
9779aa228fdSmrg  XtAddCallback(select_w, XtNcallback, SelectCB, (XtPointer)data);
9789aa228fdSmrg  paste = XtCreateManagedWidget("paste", commandWidgetClass, pane2,
9799aa228fdSmrg			      (Arg *) NULL, 0);
9809aa228fdSmrg  XtAddCallback(paste, XtNcallback, PasteCB, (XtPointer)data);
9819aa228fdSmrg  (void) XtCreateManagedWidget("helpLabel", labelWidgetClass, pane2,
9829aa228fdSmrg			       (Arg *) NULL, 0);
9839aa228fdSmrg  pane3 = XtCreateManagedWidget("pane2", panedWidgetClass, pane1,
9849aa228fdSmrg				(Arg *) NULL, 0);
9850c7e83b2Smrg  data->scaleInstance =
9860c7e83b2Smrg    XtVaCreateManagedWidget("scale", scaleWidgetClass,
9879aa228fdSmrg			    pane3,
9889aa228fdSmrg			    XtNvisual, (XtArgVal)data->win_info.visual,
9899aa228fdSmrg			    XtNcolormap, (XtArgVal)data->win_info.colormap,
9909aa228fdSmrg			    XtNdepth, (XtArgVal)data->win_info.depth,
9919aa228fdSmrg			    XtNscaleX, (XtArgVal)options.mag,
9929aa228fdSmrg			    XtNscaleY, (XtArgVal)options.mag,
9939aa228fdSmrg			    NULL);
9949aa228fdSmrg  SWSetImage(data->scaleInstance, data->image);
9959aa228fdSmrg  XtOverrideTranslations
9969aa228fdSmrg    (data->scaleShell,
9979aa228fdSmrg     XtParseTranslationTable ("<Message>WM_PROTOCOLS: close()"));
9989aa228fdSmrg  XtSetArg(warg, XtNuserData, data);
9999aa228fdSmrg  XtSetValues(data->scaleInstance, &warg, 1);
10000c7e83b2Smrg  data->pixShell =
10010c7e83b2Smrg    XtVaCreatePopupShell("pixShell", overrideShellWidgetClass,
10029aa228fdSmrg			 toplevel,
10039aa228fdSmrg			 XtNvisual, (XtArgVal)data->win_info.visual,
10049aa228fdSmrg			 XtNcolormap, (XtArgVal)data->win_info.colormap,
10059aa228fdSmrg			 XtNdepth, (XtArgVal)data->win_info.depth,
10069aa228fdSmrg			 XtNborderWidth, (XtPointer)0,
10079aa228fdSmrg			 NULL);
10080c7e83b2Smrg  data->pixLabel =
10090c7e83b2Smrg    XtVaCreateManagedWidget("pixLabel", labelWidgetClass,
10100c7e83b2Smrg			    data->pixShell,
10119aa228fdSmrg			    XtNforeground, (XtPointer)GetMaxIntensity(data),
10129aa228fdSmrg			    XtNbackground, (XtPointer)GetMinIntensity(data),
10139aa228fdSmrg			    XtNborderWidth, (XtPointer)0,
10149aa228fdSmrg			    NULL);
10159aa228fdSmrg  XtInstallAllAccelerators(pane1, pane1);	/* install accelerators */
10169aa228fdSmrg  if (data->newScale) {
10179aa228fdSmrg    XtPopup(data->scaleShell, XtGrabNone);
10189aa228fdSmrg    (void) XSetWMProtocols	/* ICCCM delete window */
10199aa228fdSmrg      (dpy, XtWindow(data->scaleShell), &wm_delete_window, 1);
10209aa228fdSmrg  }
10219aa228fdSmrg  if (data->win_info.colormap != DefaultColormap(dpy, scr)) {
10220c7e83b2Smrg    data->cmapWinList[0] = data->scaleShell;
10239aa228fdSmrg    data->cmapWinList[1] = data->scaleInstance;
10249aa228fdSmrg    XtSetWMColormapWindows(data->scaleShell, data->cmapWinList, 2);
10259aa228fdSmrg  }
10269aa228fdSmrg}
10279aa228fdSmrg
10289aa228fdSmrg
10299aa228fdSmrg
10309aa228fdSmrg/*
10319aa228fdSmrg * RedoOldScale() -- If the visual, depth, or colormap has changed, unrealize
10329aa228fdSmrg *                   the scale widget and change its colormap/depth/visual.
10339aa228fdSmrg *                   Then re-realize it.  Also do this for the pixel display
10349aa228fdSmrg *                   widget.
10359aa228fdSmrg */
10369aa228fdSmrgstatic void
10379aa228fdSmrgRedoOldScale(hlPtr data)
10389aa228fdSmrg{
10399aa228fdSmrg  Arg wargs[3];
10409aa228fdSmrg  int n;
10419aa228fdSmrg  Visual *oldVis;
10429aa228fdSmrg  int oldDepth;
10439aa228fdSmrg  Colormap oldCmap;
10449aa228fdSmrg
10459aa228fdSmrg  n=0;
10469aa228fdSmrg  XtSetArg(wargs[n], XtNvisual, &oldVis); n++;
10479aa228fdSmrg  XtSetArg(wargs[n], XtNdepth, &oldDepth); n++;
10489aa228fdSmrg  XtSetArg(wargs[n], XtNcolormap, &oldCmap); n++;
10490c7e83b2Smrg  XtGetValues(data->scaleInstance, wargs, n);
10509aa228fdSmrg  if (oldVis == data->win_info.visual && oldDepth == data->win_info.depth
10519aa228fdSmrg      && oldCmap == data->win_info.colormap) {
10520c7e83b2Smrg    SWSetImage(data->scaleInstance, data->image);
10539aa228fdSmrg    return;
10549aa228fdSmrg  }
10559aa228fdSmrg  /* get width and height, save and reuse them */
10569aa228fdSmrg  XtUnmanageChild(data->scaleInstance);
10579aa228fdSmrg  XtUnrealizeWidget(data->scaleInstance);
10589aa228fdSmrg  n=0;
10599aa228fdSmrg  XtSetArg(wargs[n], XtNcolormap, data->win_info.colormap); n++;
10609aa228fdSmrg  XtSetArg(wargs[n], XtNdepth, data->win_info.depth); n++;
10619aa228fdSmrg  XtSetArg(wargs[n], XtNvisual, data->win_info.visual); n++;
10629aa228fdSmrg  XtSetValues(data->scaleInstance, wargs, n);
10639aa228fdSmrg  n=0;
10649aa228fdSmrg  XtSetArg(wargs[n], XtNforeground, GetMaxIntensity(data)); n++;
10659aa228fdSmrg  XtSetArg(wargs[n], XtNbackground, GetMinIntensity(data)); n++;
10669aa228fdSmrg  XtSetValues(data->pixLabel, wargs, n);
10670c7e83b2Smrg  SWSetImage(data->scaleInstance, data->image);
10689aa228fdSmrg  XtRealizeWidget(data->scaleInstance);
10699aa228fdSmrg  XtManageChild(data->scaleInstance);
10709aa228fdSmrg}
10719aa228fdSmrg
10729aa228fdSmrg
10739aa228fdSmrg
10749aa228fdSmrg/*
10759aa228fdSmrg * InitCursors() -- Create our cursors for area selection.
10769aa228fdSmrg */
10779aa228fdSmrgstatic void
10789aa228fdSmrgInitCursors(void)
10799aa228fdSmrg{
10809aa228fdSmrg  ulAngle = XCreateFontCursor(dpy, XC_ul_angle);
10819aa228fdSmrg  urAngle = XCreateFontCursor(dpy, XC_ur_angle);
10829aa228fdSmrg  lrAngle = XCreateFontCursor(dpy, XC_lr_angle);
10839aa228fdSmrg  llAngle = XCreateFontCursor(dpy, XC_ll_angle);
10849aa228fdSmrg}
10859aa228fdSmrg
10869aa228fdSmrg
10879aa228fdSmrg
10889aa228fdSmrg/*
10890c7e83b2Smrg * ParseSourceGeom() -- Determine dimensions of area to magnify from resources.
10909aa228fdSmrg */
10910c7e83b2Smrgstatic void
10929aa228fdSmrgParseSourceGeom(void)
10939aa228fdSmrg{
10949aa228fdSmrg				/* source */
10950c7e83b2Smrg  srcStat =
10969aa228fdSmrg    XParseGeometry(options.source, &srcX, &srcY, &srcWidth, &srcHeight);
10979aa228fdSmrg  if (!srcWidth) srcWidth = SRCWIDTH;
10989aa228fdSmrg  if (!srcHeight) srcHeight = SRCHEIGHT;
10999aa228fdSmrg  if (XNegative & srcStat) srcX = DisplayWidth(dpy, scr) + srcX - srcWidth;
11009aa228fdSmrg  if (YNegative & srcStat) srcY = DisplayHeight(dpy, scr) + srcY - srcHeight;
11019aa228fdSmrg				/* mag */
11029aa228fdSmrg}
11039aa228fdSmrg
11049aa228fdSmrg
11059aa228fdSmrg
11069aa228fdSmrg/*
11079aa228fdSmrg * Main program.
11089aa228fdSmrg */
11090c7e83b2Smrgint
11109aa228fdSmrgmain(int argc, char *argv[])
11119aa228fdSmrg{
11129aa228fdSmrg  XSetErrorHandler(Error);
11130c7e83b2Smrg
11149aa228fdSmrg				/* SUPPRESS 594 */
11159aa228fdSmrg  toplevel = XtAppInitialize(&app, "Xmag", optionDesc, XtNumber(optionDesc),
11169aa228fdSmrg			     &argc, argv, NULL,
11179aa228fdSmrg			     NULL, 0);
11189aa228fdSmrg
11199aa228fdSmrg  dpy = XtDisplay(toplevel);
11209aa228fdSmrg  scr = DefaultScreen(dpy);
11219aa228fdSmrg  XtGetApplicationResources(toplevel, (XtPointer) &options, resources,
11229aa228fdSmrg			    XtNumber(resources), NULL, 0);
11239aa228fdSmrg  if (argc != 1) {
11249aa228fdSmrg    fprintf (stderr,
11259aa228fdSmrg	    "usage:  xmag [-source geom] [-mag magfactor] [-toolkitoption]\n");
11269aa228fdSmrg    exit(1);
11279aa228fdSmrg  }
11280c7e83b2Smrg
11299aa228fdSmrg
11309aa228fdSmrg  ParseSourceGeom();
11319aa228fdSmrg  XtAppAddActions(app, actions_table, XtNumber(actions_table));
11329aa228fdSmrg  InitCursors();
11339aa228fdSmrg  SetupGC();
11349aa228fdSmrg  CreateRoot();
11359aa228fdSmrg  if (!(XValue & srcStat && YValue & srcStat))
11369aa228fdSmrg    StartRootPtrGrab(True, (hlPtr)NULL);
11379aa228fdSmrg  wm_delete_window = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
11389aa228fdSmrg  XtAppMainLoop(app);
11399aa228fdSmrg  exit(0);
11409aa228fdSmrg}
1141