1
/* $TOG: panner.c /main/6 1997/03/31 13:38:32 dbl $ */
3
* @OPENGROUP_COPYRIGHT@
5
* Copyright (c) 1990, 1991, 1992, 1993 Open Software Foundation, Inc.
6
* Copyright (c) 1996, 1997, 1998, 1999, 2000 The Open Group
7
* ALL RIGHTS RESERVED (MOTIF). See the file named COPYRIGHT.MOTIF for
8
* the full copyright text.
10
* This software is subject to an open license. It may only be
11
* used on, with or for operating systems which are themselves open
12
* source systems. You must contact The Open Group for a license
13
* allowing distribution and sublicensing of this software on, with,
14
* or for operating systems which are not Open Source programs.
16
* See http://www.opengroup.org/openmotif/license for full
17
* details of the license agreement. Any use, reproduction, or
18
* distribution of the program constitutes recipient's acceptance of
21
* EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS
22
* PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
23
* KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY
24
* WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY
25
* OR FITNESS FOR A PARTICULAR PURPOSE
27
* EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT
28
* NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT,
29
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30
* DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED
31
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
33
* ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE
34
* EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE
35
* POSSIBILITY OF SUCH DAMAGES.
44
#include <Xm/TransferP.h>
45
#include <Xm/AtomMgr.h>
46
#include <Xm/CascadeB.h>
47
#include <Xm/DrawingA.h>
50
#include <Xm/MessageB.h>
51
#include <Xm/Notebook.h>
53
#include <Xm/RowColumn.h>
54
#include <Xm/SelectioB.h>
55
#include <Xm/XmStrDefs.h>
57
#define INIT_SCREEN_WIDTH 50
58
#define MAX_DISPLAY_COUNT 10
62
#define WM_SELECTION_FORMAT "WM_S%1d"
63
#define COLOR_COUNT 20
67
"Panner.mappedWhenManaged: FALSE",
71
"Panner*frame.marginWidth: 7",
72
"Panner*frame.marginHeight: 7",
73
"Panner*notebook.firstPageNumber: 0",
75
"Panner*tab.shadowThickness: 1",
77
"Panner*canvas.background: grey40",
78
"Panner*canvas.foreground: yellow",
81
/* Menu entry definitions */
82
"Panner*cascade1.labelString: File",
83
"Panner*cascade2.labelString: Display",
84
"Panner*cascade3.labelString: Help",
86
"Panner*b1.labelString: Quit",
87
"Panner*b2.labelString: Update",
88
"Panner*b3.labelString: New Display...",
90
"Panner*promptDlog*selectionLabelString: Display name:",
92
"Panner*messageDlog*messageString:\
93
Panner Demo\\n-----------\\nGrab and move dashed box to pan display.\\n\
94
Use 'New Display...' command to add another display.\\n\
95
Select displays from tabs in the notebook.",
97
"Panner*warningDlog*messageString:\
98
The panner window is not pinned!\\n\
99
Add the line:\\n\\n \"Mwm*Panner*ClientPinned: True\"\\n\\n\
100
to your .Xdefaults file and restart Mwm.",
105
typedef struct _PannerInfoRec {
109
Widget utmShell; /* drawing area used for UTM */
112
unsigned int thumbW, thumbH;
113
int lastEventX, lastEventY;
114
Atom WM; /* need selections on the correct display */
120
typedef struct _PanPostion {
126
typedef enum { MENU_QUIT, MENU_UPDATE, MENU_NEW, MENU_HELP } MenuFunction;
127
typedef enum { UNKNOWN, VERIFYING, VERIFIED } PinState;
133
unsigned short DSP; /* index of active display */
135
GC thumbGC, canvasGC;
137
PannerInfoRec *pInfoList;
138
unsigned long cells[COLOR_COUNT];
139
PinState pinnedState = UNKNOWN;
143
Boolean LOCK = False;
149
static void OpenNewDisplay(String, Widget, PannerInfoRec *);
150
static void UpdatePannerCB (Widget, XtPointer, XtPointer);
151
static void ChangePageCB (Widget, XtPointer, XtPointer);
152
static void DoAddDisplayCB (Widget, XtPointer, XtPointer);
153
static void DestinationCB (Widget, XtPointer, XtPointer);
154
static void DoneMoveScreenCB (Widget, XtPointer, XtPointer);
155
static void WatchForWindowPanning (Display *dsp);
156
static void HandlePropertyChange (XEvent *event);
157
static void UpdatePannerView (PannerInfoRec *pInfoList, int remoteDsp);
158
static void DrawWindows (PannerInfoRec *);
159
static void DrawThumb (PannerInfoRec *);
160
static void SetupColorsAndGCs();
161
static GC GetXorGC (Widget);
162
static GC GetCanvasGC (Widget);
163
static void SetWindowColor (PannerInfoRec *, int);
164
static void TranslateCoordinates (PannerInfoRec *,
165
int, int, unsigned int, unsigned int,
166
int*,int*,unsigned int*,unsigned int*);
167
static int IgnoreError (Display *dsp, XErrorEvent *event);
168
static void StartTracking (Widget, XtPointer, XEvent *, Boolean *);
169
static void DoTracking (Widget, XtPointer, XEvent *, Boolean *);
170
static void StopTracking (Widget, XtPointer, XEvent *, Boolean *);
171
static void MoveScreen (PannerInfoRec *, int, int, Time);
172
static XtPointer PackCARD32 (XtPointer, CARD32);
173
static XtPointer PackCARD16 (XtPointer, CARD16);
174
static XtPointer PackCARD8 (XtPointer, CARD8);
175
static void CreateMenuBar (Widget parent);
176
static void MenuCB (Widget w, XtPointer clientData, XtPointer callData);
177
static void DoUpdatePanner ();
178
static void DoAddDisplay ();
179
static void DoHelp ();
180
static void DoQuit ();
181
static void CheckPinnedState ();
182
static void ShowPinStateWarning ();
183
static void HandleInitialExpose (Widget, XtPointer, XEvent *, Boolean *);
188
/*----------------------------------------------------------------*
190
*----------------------------------------------------------------*/
192
main (int argc, char** argv)
194
Widget mainWin, frame;
198
pInfoList = (PannerInfoRec *) XtMalloc(sizeof(PannerInfoRec) *
200
for (DSP = 0; DSP < MAX_DISPLAY_COUNT; DSP++)
201
pInfoList[DSP].display = NULL;
204
XtSetLanguageProc(NULL, (XtLanguageProc) NULL, NULL);
207
pInfoList[LOCAL].shell = XtVaOpenApplication(&app, "Panner", NULL, 0,
210
sessionShellWidgetClass, NULL);
211
pInfoList[LOCAL].display = XtDisplay(pInfoList[LOCAL].shell);
214
mainWin = XmCreateMainWindow(pInfoList[LOCAL].shell, "mainWin", NULL, 0);
215
XtManageChild(mainWin);
216
CreateMenuBar(mainWin);
218
frame = XtVaCreateManagedWidget("frame", xmFrameWidgetClass, mainWin,
220
notebook = XtVaCreateManagedWidget("notebook", xmNotebookWidgetClass, frame,
223
XtRealizeWidget(pInfoList[LOCAL].shell);
225
context = XUniqueContext ();
226
OpenNewDisplay(/*$DISPLAY*/NULL, notebook, pInfoList);
230
XtAddCallback(notebook, XmNpageChangedCallback, ChangePageCB, pInfoList);
231
XtAddEventHandler(notebook, ExposureMask, False, HandleInitialExpose, NULL);
233
XtMapWidget(pInfoList[LOCAL].shell);
237
XtAppNextEvent(app, &event);
239
if (event.type == PropertyNotify)
240
HandlePropertyChange(&event);
242
XtDispatchEvent(&event);
250
/*----------------------------------------------------------------*
252
| - Get new display connection to named display. |
253
| - If display name is not NULL, create shell on the display. |
254
| - Fill in correct record in pInfoList. |
255
*----------------------------------------------------------------*/
260
PannerInfoRec *pInfoList)
265
Dimension canvasW, canvasH;
266
char selectionName[40];
267
PannerInfoRec *pInfo;
270
XtCallbackList cbList;
274
* If NULL, then the display's already been created.
276
if (displayName != NULL)
278
XtVaGetValues(notebook, XmNlastPageNumber, &newDsp,
279
XmNpageChangedCallback, &cbList, NULL);
283
if ((pInfoList[newDsp].display = XOpenDisplay(displayName)) == NULL)
285
fprintf(stderr, "ERROR - Can't open display \"%s\".\n", displayName);
289
XtDisplayInitialize(app, pInfoList[newDsp].display, "panner", "Panner",
290
NULL, 0, &argc, argv);
292
/* create an unmapped shell on the remote display */
293
pInfoList[newDsp].shell =
294
XtVaAppCreateShell( "panner", "Panner", applicationShellWidgetClass,
295
pInfoList[newDsp].display,
296
XmNmappedWhenManaged, False, NULL);
298
XtRealizeWidget(pInfoList[newDsp].shell);
301
* For UTM to work, there must be a drawing area or UTM saavy
304
* We must set-up a destination callback function that
305
* does the actual transfer of the parameter info to Mwm.
308
pInfoList[newDsp].utmShell
309
= XtVaCreateManagedWidget("utmShell", xmDrawingAreaWidgetClass,
310
pInfoList[newDsp].shell,
311
XmNmappedWhenManaged, False,
314
XtAddCallback(pInfoList[newDsp].utmShell, XmNdestinationCallback,
315
DestinationCB, &(pInfoList[newDsp]));
318
* Initialize the correct record in the pInfoList.
320
pInfoList[newDsp].screen = XtScreen(pInfoList[newDsp].shell);
324
* setup handler to watch when Mwm changes the root property.
325
* first store some data on the root window.
327
XSaveContext(pInfoList[newDsp].display,
328
DefaultRootWindow(pInfoList[newDsp].display),
330
(XPointer)(long)newDsp); /* store index into panner info. */
331
WatchForWindowPanning(pInfoList[newDsp].display);
335
* Add another page to the notebook.
336
* First must set size correctly.
339
XtVaGetValues(pInfoList[LOCAL].shell,
340
XmNwidth, &canvasW, XmNheight, &canvasH, NULL);
341
pInfoList[newDsp].canvas
342
= XtVaCreateManagedWidget("canvas", xmDrawingAreaWidgetClass, notebook,
343
XmNchildType, XmPAGE,
344
XmNpageNumber, newDsp,
348
XtAddCallback(pInfoList[newDsp].canvas, XmNexposeCallback, UpdatePannerCB,
351
if (displayName == NULL)
352
tabName = XmStringCreate("LOCAL",XmFONTLIST_DEFAULT_TAG);
354
tabName = XmStringCreate(displayName,XmFONTLIST_DEFAULT_TAG);
355
tab = XtVaCreateManagedWidget("tab", xmPushButtonWidgetClass, notebook,
356
XmNlabelString, tabName,
357
XmNchildType, XmMAJOR_TAB, NULL);
358
XmStringFree(tabName);
360
pInfoList[newDsp].thumbW = INIT_SCREEN_WIDTH;
361
pInfoList[newDsp].thumbH = pInfoList[newDsp].thumbW *
362
HeightOfScreen(pInfoList[newDsp].screen) /
363
WidthOfScreen(pInfoList[newDsp].screen);
364
XtVaGetValues(pInfoList[newDsp].canvas, XmNwidth, &canvasW,
365
XmNheight, &canvasH, NULL);
366
pInfoList[newDsp].thumbX = (int)canvasW/2 - (int)pInfoList[newDsp].thumbW/2;
367
pInfoList[newDsp].thumbY = (int)canvasH/2 - (int)pInfoList[newDsp].thumbH/2;
369
/* Setup the atoms needed to communicate with Mwm. Check screen number! */
370
sprintf(selectionName, WM_SELECTION_FORMAT,
371
XScreenNumberOfScreen(pInfoList[newDsp].screen));
372
pInfoList[newDsp].WM = XmInternAtom(pInfoList[newDsp].display,
373
selectionName, False);
374
pInfoList[newDsp].WM_PAN = XmInternAtom(pInfoList[newDsp].display,
375
"_MOTIF_WM_PAN", False);
376
pInfoList[newDsp].WM_GOTO = XmInternAtom(pInfoList[newDsp].display,
377
"_MOTIF_WM_GOTO", False);
378
pInfoList[newDsp].WM_PAN_POS = XmInternAtom(pInfoList[newDsp].display,
379
"_MOTIF_WM_PAN_POSITION", False);
381
XtAddEventHandler(pInfoList[newDsp].canvas, ButtonPressMask, False,
382
StartTracking, (XtPointer)&pInfoList[newDsp]);
387
/*========================== CALLBACKS ==========================*/
389
/*----------------------------------------------------------------*
391
*----------------------------------------------------------------*/
395
XtPointer clientData,
398
XmDrawingAreaCallbackStruct *cb = (XmDrawingAreaCallbackStruct *)callData;
399
PannerInfoRec *pInfoList = (PannerInfoRec *)clientData;
401
if (cb->reason == XmCR_EXPOSE)
403
XExposeEvent *event = (XExposeEvent *)cb->event;
405
/* Last expose event received - do the drawing. */
406
if (event->count == 0)
407
UpdatePannerView(pInfoList, DSP);
412
* Update button pressed.
414
UpdatePannerView(pInfoList, DSP);
418
/*----------------------------------------------------------------*
420
| Invoked just prior to notebook page change. Any drawing here |
422
*----------------------------------------------------------------*/
426
XtPointer clientData,
429
PannerInfoRec *pInfoList = (PannerInfoRec *)clientData;
430
XmNotebookCallbackStruct *nbData = (XmNotebookCallbackStruct *)callData;
433
pageNumber = nbData->page_number;
434
if ((pageNumber >= MAX_DISPLAY_COUNT) ||
435
(pInfoList[pageNumber].display == NULL))
437
fprintf(stderr, "ERROR - bad display index. (%d).\n", pageNumber);
446
/*----------------------------------------------------------------*
448
*----------------------------------------------------------------*/
452
XtPointer clientData,
455
XmSelectionBoxCallbackStruct *cb = (XmSelectionBoxCallbackStruct *)callData;
456
PannerInfoRec *pInfoList = (PannerInfoRec *)clientData;
457
char *dspName; /* Free when done. */
458
String appName, appClass; /* Don't free - owned by Xt. */
461
XtGetApplicationNameAndClass(pInfoList[LOCAL].display, &appName, &appClass);
462
XmStringGetLtoR(cb->value, XmSTRING_DEFAULT_CHARSET, &dspName);
464
OpenNewDisplay(dspName, notebook, pInfoList);
465
if (dspName) XtFree(dspName);
469
/*----------------------------------------------------------------*
471
| This function gets invoked by UTM when a sink has been estab- |
472
| lished and a request initiated against another selection. The |
473
| purpose here is to set-up the parameters and pass them to the |
474
| owner of the selection. The parameter data has already been |
475
| allocated in the MoveScreen() function. |
476
| clientData holds the pannerInfoRec corresponding to the right |
478
*----------------------------------------------------------------*/
482
XtPointer clientData,
485
XmDestinationCallbackStruct *dcs = (XmDestinationCallbackStruct *)callData;
486
PannerInfoRec *pInfo = (PannerInfoRec *)clientData;
491
* Pass the data to free in the clientData field.
492
* location_data points to the param data. This was set in
496
/* FIRST - setup the parameters to pass. */
497
XmTransferSetParameters(dcs->transfer_id,
498
dcs->location_data, /* pointer to param data. */
500
PAN_SIZE, /* should be calculated. */
501
dcs->selection); /* type - don't care. */
503
/* LAST - Make the transfer. */
504
XmTransferValue(dcs->transfer_id,
505
pInfo->WM_PAN, /* target for conversion. */
506
DoneMoveScreenCB, /* CB proc invoked when done. */
507
dcs->location_data, /* clientData - to be freed. */
513
/*----------------------------------------------------------------*
515
*----------------------------------------------------------------*/
519
XtPointer clientData,
523
* Conversion completed. Safe to free param data.
526
XtFree((char *)clientData);
534
/*=========================== PAN-HANDLING ==========================*/
537
/*----------------------------------------------------------------*
538
| WatchForWindowPanning |
539
*----------------------------------------------------------------*/
541
WatchForWindowPanning (Display *dsp)
543
XWindowAttributes attr;
544
Window rwin = DefaultRootWindow(dsp);
547
/* Watch whenever the window manager's panning position changes. */
548
/* Mwm stores the position in properties on the root window. */
549
/* This is stored in the _MOTIF_WM_PAN_POSITION property. */
551
XGetWindowAttributes(dsp, rwin, &attr);
553
if (! (attr.your_event_mask & PropertyChangeMask))
554
XSelectInput(dsp, rwin, attr.your_event_mask | PropertyChangeMask);
559
/*----------------------------------------------------------------*
560
| HandlePropertyChange |
561
| This routine checks the property changed and if its the right |
562
| property, grab the new panning position. |
563
*----------------------------------------------------------------*/
565
HandlePropertyChange (XEvent *event)
567
XPropertyEvent *propEvent = (XPropertyEvent *)event;
571
/* Get the correct info record stored with the context manager. */
572
if (XFindContext(propEvent->display, propEvent->window, context,
576
/* check if this is the right one. Othersize, we'll update when another
579
if (propEvent && propEvent->atom != pInfoList[iDsp].WM_PAN_POS)
582
/* if the display doesn't match the current one, then punt. */
585
if (pinnedState == VERIFIED)
586
UpdatePannerView(pInfoList, iDsp);
590
int x, y, newX, newY;
591
unsigned int width, height, bWidth, depth;
593
/* Get position of the top-level shell */
594
XGetGeometry(pInfoList[LOCAL].display, XtWindow(pInfoList[LOCAL].shell),
595
&rWin, &x, &y, &width, &height, &bWidth, &depth);
597
XTranslateCoordinates(pInfoList[LOCAL].display,
598
XtWindow(pInfoList[LOCAL].shell),
599
rWin, x, y, &newX, &newY, &child);
601
if ((newX == origX) && (newY == origY))
602
pinnedState = VERIFIED;
604
ShowPinStateWarning();
615
/*============================ DRAWING ===========================*/
617
/*----------------------------------------------------------------*
619
*----------------------------------------------------------------*/
622
PannerInfoRec *pInfoList,
625
XClearArea(pInfoList[LOCAL].display,
626
XtWindow(pInfoList[remoteDsp].canvas),
629
DrawWindows(pInfoList);
630
DrawThumb(&pInfoList[remoteDsp]);
634
/*----------------------------------------------------------------*
636
*----------------------------------------------------------------*/
638
DrawWindows (PannerInfoRec *pInfoList)
640
Window realRoot, root, parent, *child = NULL;
642
unsigned int childCount, width, height;
646
realRoot = RootWindow(pInfoList[DSP].display,
647
XScreenNumberOfScreen(pInfoList[DSP].screen));
649
if (XQueryTree(pInfoList[DSP].display, realRoot,
650
&root, &parent, &child, &childCount))
653
* We need to install an error handler since the window-tree may
654
* become invalid while where still processing the list.
656
oldHandler = XSetErrorHandler(IgnoreError);
657
for (i=0; i<childCount; i++)
659
XWindowAttributes attr;
661
XGetWindowAttributes(pInfoList[DSP].display, child[i], &attr);
663
if (attr.map_state == IsViewable)
665
TranslateCoordinates(&pInfoList[DSP],
666
attr.x, attr.y, attr.width, attr.height,
667
&x, &y, &width, &height);
669
SetWindowColor (&pInfoList[LOCAL], i);
670
XFillRectangle(pInfoList[LOCAL].display,
671
XtWindow(pInfoList[DSP].canvas),
672
canvasGC, x, y, width, height);
675
XSetErrorHandler(oldHandler);
683
/*----------------------------------------------------------------*
685
*----------------------------------------------------------------*/
687
DrawThumb (PannerInfoRec *pInfo)
689
XDrawRectangle(XtDisplay(pInfo->canvas), XtWindow(pInfo->canvas), thumbGC,
690
pInfo->thumbX, pInfo->thumbY,
691
pInfo->thumbW, pInfo->thumbH);
695
/*----------------------------------------------------------------*
696
| SetupColorsAndGCs |
697
| Called once at the beginning to setup some drawing stuff. |
698
*----------------------------------------------------------------*/
704
Colormap cmap = DefaultColormapOfScreen(pInfoList[LOCAL].screen);
707
* set-up the global GCs.
709
thumbGC = GetXorGC(pInfoList[LOCAL].canvas);
710
canvasGC = GetCanvasGC(pInfoList[LOCAL].canvas);
713
* Allocate the global color cells for the drawing of each windows.
714
* The more random the colors, the better.
716
if (XAllocColorCells(pInfoList[LOCAL].display,
717
cmap, False, NULL, 0, cells, COLOR_COUNT))
718
for (i=0; i<COLOR_COUNT; i++)
720
color.red = rand() % 65535;
721
color.blue = rand() % 65535;
722
color.green = rand() % 65535;
723
color.pixel = cells[i];
724
XStoreColor(pInfoList[LOCAL].display, cmap, &color);
729
/*----------------------------------------------------------------*
731
*----------------------------------------------------------------*/
739
XtVaGetValues(w, XmNforeground, &values.foreground,
740
XmNbackground, &values.background, NULL);
741
values.foreground = values.foreground ^ values.background;
742
values.function = GXxor;
743
values.line_style = LineOnOffDash;
746
GCForeground | GCBackground | GCFunction | GCLineStyle,
753
/*----------------------------------------------------------------*
755
*----------------------------------------------------------------*/
757
GetCanvasGC (Widget w)
763
XtVaGetValues(w, XmNforeground, &values.foreground,
764
XmNbackground, &values.background, NULL);
765
values.foreground = values.background;
766
values.function = GXcopy;
769
GCForeground | GCBackground | GCFunction,
776
/*----------------------------------------------------------------*
778
*----------------------------------------------------------------*/
780
SetWindowColor (PannerInfoRec *pInfo, int i)
782
XSetForeground(pInfo->display, canvasGC, cells[(i+1)%COLOR_COUNT]);
786
/*----------------------------------------------------------------*
787
| TranslateCoordinates |
788
*----------------------------------------------------------------*/
790
TranslateCoordinates (
791
PannerInfoRec *pInfo,
792
int x1, int y1, unsigned int width1, unsigned int height1,
793
int *x2, int *y2, unsigned int *width2, unsigned int *height2)
798
rootW = WidthOfScreen(pInfo->screen);
799
rootH = HeightOfScreen(pInfo->screen);
801
*x2 = x1 * (int)pInfo->thumbW / (int)rootW + pInfo->thumbX;
802
*y2 = y1 * (int)pInfo->thumbH / (int)rootH + pInfo->thumbY;
803
*width2 = width1 * pInfo->thumbW / rootW;
804
*height2 = height1 * pInfo->thumbH / rootH;
808
/*----------------------------------------------------------------*
810
*----------------------------------------------------------------*/
812
IgnoreError (Display *dsp, XErrorEvent *event)
816
* This is needed since we will may be updating the list of window
817
* while one of them goes away. Ie: the window list received from
818
* XQueryTree may not be valid for the entire loop where we get each
821
return 0; /* make compiler happy */
826
/*======================= TRACKING HANDLERS ======================*/
829
/*----------------------------------------------------------------*
831
*----------------------------------------------------------------*/
835
XtPointer clientData,
839
PannerInfoRec *pInfo = (PannerInfoRec *)clientData;
840
XPointerMovedEvent *motionEvent = (XPointerMovedEvent *)event;
843
if ((pinnedState == VERIFIED) && (event->xbutton.button == Button1))
845
pInfo->lastEventX = event->xbutton.x;
846
pInfo->lastEventY = event->xbutton.y;
848
if ((event->xbutton.x < pInfo->thumbX) ||
849
(event->xbutton.y < pInfo->thumbY) ||
850
(event->xbutton.x > pInfo->thumbX + (int)pInfo->thumbW) ||
851
(event->xbutton.y > pInfo->thumbY + (int)pInfo->thumbH))
854
* if on the canvas, then center the thumb over the pointer.
858
event->xbutton.x - (int)pInfo->thumbW/2,
859
event->xbutton.y - (int)pInfo->thumbH/2,
863
XtAddEventHandler(w, ButtonReleaseMask, False, StopTracking, clientData);
864
XtAddEventHandler(w, Button1MotionMask, False, DoTracking, clientData);
866
else if (pinnedState != VERIFIED)
871
/*----------------------------------------------------------------*
873
*----------------------------------------------------------------*/
877
XtPointer clientData,
881
PannerInfoRec *pInfo = (PannerInfoRec *)clientData;
882
XPointerMovedEvent *motionEvent = (XPointerMovedEvent *)event;
886
pInfo->thumbX + event->xbutton.x - pInfo->lastEventX,
887
pInfo->thumbY + event->xbutton.y - pInfo->lastEventY,
890
pInfo->lastEventX = event->xbutton.x;
891
pInfo->lastEventY = event->xbutton.y;
895
/*----------------------------------------------------------------*
897
*----------------------------------------------------------------*/
901
XtPointer clientData,
905
if (event->xbutton.button == Button1)
907
XtRemoveEventHandler(w, Button1MotionMask, False, DoTracking,
909
XtRemoveEventHandler(w, ButtonReleaseMask, False, StopTracking,
916
/*----------------------------------------------------------------*
918
*----------------------------------------------------------------*/
921
PannerInfoRec *pInfo,
926
int dx, dy, panDx, panDy, rootW, rootH;
927
XtPointer msg, fulldata;
933
dx = newX - pInfo->thumbX;
934
dy = newY - pInfo->thumbY;
936
pInfo->thumbX = newX;
937
pInfo->thumbY = newY;
943
* Send Pan message to mwm.
946
rootW = WidthOfScreen(pInfo->screen);
947
rootH = HeightOfScreen(pInfo->screen);
948
panDx = -(dx * rootW / (int)pInfo->thumbW);
949
panDy = -(dy * rootH / (int)pInfo->thumbH);
951
size = sizeof(CARD32); /* panDx */
952
size += sizeof(CARD32); /* panDy */
953
size += sizeof(CARD8); /* config */
955
msg = fulldata = (XtPointer) XtMalloc(sizeof(CARD8) * size);
957
msg = PackCARD32(msg, panDx);
958
msg = PackCARD32(msg, panDy);
959
msg = PackCARD8(msg, True);
968
display = XtDisplay(notebook); /* notebook just happens to be a global. */
969
window = XtWindow(notebook);
971
MY_PANNER_PROP = XInternAtom(display, "MY_PANNER_PROP", False);
975
* Note - to really make this work across multiple displays,
976
* the window argument must reside on the same display as WM_Si.
980
* Use a lock to make sure the property was read by Mwm.
981
* When the pan-property is updated, it's safe to make another
986
LOCK = True; /* Freed in HandlePropertyChange. */
987
XChangeProperty(display, window, MY_PANNER_PROP, MY_PANNER_PROP,
988
PAN_FORMAT, PropModeReplace,
989
(unsigned char *)fulldata, size);
991
XConvertSelection(pInfo->display, pInfo->WM, pInfo->WM_PAN,
997
if (! XmeNamedSink(pInfo->utmShell, /* widget with destination callback */
998
pInfo->WM, /* named selection - ie. Window Manager */
999
XmCOPY, /* operation to perform on the data */
1000
(XtPointer)fulldata, /* pointer to param data, */
1001
time) /* free n TransferDone proc. */
1003
printf("Error - UTM Transfer failed.\n");
1009
/*----------------------------------------------------------------*
1010
| PACKING FUNCTIONS |
1011
*----------------------------------------------------------------*/
1014
PackCARD32 (XtPointer data, CARD32 val)
1016
CARD16 bottom = val & (0xFFFF);
1017
CARD16 top = val >> 16;
1019
data = PackCARD16(data, top);
1020
data = PackCARD16(data, bottom);
1026
PackCARD16 (XtPointer data, CARD16 val)
1028
CARD8 bottom = val & (0xFF);
1029
CARD8 top = val >> 8;
1031
data = PackCARD8(data, top);
1032
data = PackCARD8(data, bottom);
1038
PackCARD8 (XtPointer data, CARD8 val)
1040
CARD8 *ptr = (CARD8 *) data;
1043
data = ((char*)data) + 1;
1048
/*======================= USER INTERFACE ======================*/
1050
/*----------------------------------------------------------------*
1052
*----------------------------------------------------------------*/
1054
CreateMenuBar (Widget parent)
1059
Widget cascade1, cascade2, cascade3;
1060
Widget menuPane1, menuPane2;
1063
menuBar = XmCreateMenuBar(parent, "menuBar", NULL, 0);
1065
menuPane1 = XmCreatePulldownMenu(menuBar, "menuPane1", NULL, 0);
1066
menuPane2 = XmCreatePulldownMenu(menuBar, "menuPane2", NULL, 0);
1068
b1 = XtCreateManagedWidget("b1", xmPushButtonWidgetClass, menuPane1, NULL,0);
1069
XtAddCallback(b1, XmNactivateCallback, MenuCB, (XtPointer)MENU_QUIT);
1071
b2 = XtCreateManagedWidget("b2", xmPushButtonWidgetClass, menuPane2, NULL,0);
1072
XtAddCallback(b2, XmNactivateCallback, MenuCB, (XtPointer)MENU_UPDATE);
1074
b3 = XtCreateManagedWidget("b3", xmPushButtonWidgetClass, menuPane2, NULL,0);
1075
XtAddCallback(b3, XmNactivateCallback, MenuCB, (XtPointer)MENU_NEW);
1078
XtSetArg(args[n], XmNsubMenuId, menuPane1); n++;
1079
cascade1 = XmCreateCascadeButton(menuBar, "cascade1", args, n);
1080
XtManageChild(cascade1);
1083
XtSetArg(args[n], XmNsubMenuId, menuPane2); n++;
1084
cascade2 = XmCreateCascadeButton(menuBar, "cascade2", args, n);
1085
XtManageChild(cascade2);
1088
cascade3 = XmCreateCascadeButton(menuBar, "cascade3", args, n);
1089
XtAddCallback(cascade3, XmNactivateCallback, MenuCB, (XtPointer)MENU_HELP);
1090
XtManageChild(cascade3);
1093
XtSetArg(args[n], XmNmenuHelpWidget, cascade3); n++;
1094
XtSetValues(menuBar, args, n);
1096
XtManageChild(menuBar);
1100
/*----------------------------------------------------------------*
1102
*----------------------------------------------------------------*/
1104
MenuCB (Widget w, XtPointer clientData, XtPointer callData)
1107
switch ((long)clientData)
1109
case MENU_UPDATE: DoUpdatePanner(); break;
1110
case MENU_NEW: DoAddDisplay(); break;
1111
case MENU_QUIT: DoQuit(); break;
1112
case MENU_HELP: DoHelp(); break;
1118
/*----------------------------------------------------------------*
1120
*----------------------------------------------------------------*/
1124
XClearArea(pInfoList[LOCAL].display,
1125
XtWindow(pInfoList[DSP].canvas),
1128
DrawWindows(pInfoList);
1129
DrawThumb(&pInfoList[DSP]);
1133
/*----------------------------------------------------------------*
1135
*----------------------------------------------------------------*/
1139
static Widget dlog = NULL;
1146
XtSetArg(args[n], XmNdialogStyle, XmDIALOG_FULL_APPLICATION_MODAL); n++;
1147
dlog = XmCreatePromptDialog(pInfoList[LOCAL].shell, "promptDlog",
1150
XtAddCallback(dlog, XmNokCallback, DoAddDisplayCB, pInfoList);
1151
XtUnmanageChild( XmSelectionBoxGetChild (dlog, XmDIALOG_HELP_BUTTON) );
1153
XtManageChild(dlog);
1157
/*----------------------------------------------------------------*
1159
*----------------------------------------------------------------*/
1163
static Widget dlog = NULL;
1169
dlog = XmCreateInformationDialog(pInfoList[LOCAL].shell, "messageDlog",
1171
XtUnmanageChild( XmMessageBoxGetChild (dlog, XmDIALOG_HELP_BUTTON) );
1172
XtUnmanageChild( XmMessageBoxGetChild (dlog, XmDIALOG_CANCEL_BUTTON) );
1175
XtManageChild(dlog);
1179
/*----------------------------------------------------------------*
1181
*----------------------------------------------------------------*/
1185
XSync (pInfoList[LOCAL].display, False);
1186
XCloseDisplay (pInfoList[LOCAL].display);
1193
/*----------------------------------------------------------------*
1195
*----------------------------------------------------------------*/
1197
GetTimestamp (Display *dsp)
1200
XWindowAttributes attr;
1201
Atom timeProp = XInternAtom(dsp, "_MOTIF_CURRENT_TIME", False);
1202
Window rwin = DefaultRootWindow(dsp);
1205
XGetWindowAttributes(dsp, rwin, &attr);
1207
if (! (attr.your_event_mask & PropertyChangeMask))
1208
XSelectInput(dsp, rwin, attr.your_event_mask | PropertyChangeMask);
1210
XChangeProperty(dsp, rwin, timeProp, timeProp, 8, PropModeAppend, NULL, 0);
1212
XWindowEvent(dsp, rwin, PropertyChangeMask, &event);
1214
if (! (attr.your_event_mask & PropertyChangeMask))
1215
XSelectInput(dsp, rwin, attr.your_event_mask);
1217
return(event.xproperty.time);
1221
/*----------------------------------------------------------------*
1222
| CheckPinnedState |
1223
*----------------------------------------------------------------*/
1224
static void CheckPinnedState ()
1226
static int panDx=0, panDy=-1;
1227
XtPointer msg, fulldata;
1231
unsigned int width, height, bWidth, depth;
1232
Time time = GetTimestamp(pInfoList[LOCAL].display);
1234
if (pinnedState == VERIFIED)
1239
pinnedState = VERIFYING;
1241
/* Get position of the top-level shell */
1242
XGetGeometry(pInfoList[LOCAL].display, XtWindow(pInfoList[LOCAL].shell),
1243
&rWin, &x, &y, &width, &height, &bWidth, &depth);
1245
XTranslateCoordinates(pInfoList[LOCAL].display, XtWindow(pInfoList[LOCAL].shell),
1246
rWin, x, y, &origX, &origY, &child);
1248
size = sizeof(CARD32); /* panDx */
1249
size += sizeof(CARD32); /* panDy */
1250
size += sizeof(CARD8); /* config */
1252
msg = fulldata = (XtPointer) XtMalloc(sizeof(CARD8) * size);
1254
msg = PackCARD32(msg, panDx);
1255
msg = PackCARD32(msg, panDy);
1256
msg = PackCARD8(msg, True);
1258
if (! XmeNamedSink(pInfoList[LOCAL].utmShell,
1259
pInfoList[LOCAL].WM,
1261
(XtPointer)fulldata,
1264
printf("Error - UTM Transfer failed.\n");
1267
/*----------------------------------------------------------------*
1268
| ShowPinStateWarning |
1269
*----------------------------------------------------------------*/
1271
ShowPinStateWarning ()
1273
static Widget dlog = NULL;
1279
dlog = XmCreateWarningDialog(pInfoList[LOCAL].shell, "warningDlog",
1281
XtUnmanageChild( XmMessageBoxGetChild (dlog, XmDIALOG_HELP_BUTTON) );
1282
XtUnmanageChild( XmMessageBoxGetChild (dlog, XmDIALOG_CANCEL_BUTTON) );
1285
XtManageChild(dlog);
1289
/*----------------------------------------------------------------*
1290
| HandleInitialExpose |
1291
*----------------------------------------------------------------*/
1293
HandleInitialExpose (
1295
XtPointer clientData,
1299
XtRemoveEventHandler(w, ExposureMask, False, HandleInitialExpose, NULL);