Fixed poor handling of RCS logs by last CVS checkin
[dyninst.git] / paradyn / src / UIthread / tkTools.C
1 /*
2  * Copyright (c) 1996-1998 Barton P. Miller
3  * 
4  * We provide the Paradyn Parallel Performance Tools (below
5  * described as Paradyn") on an AS IS basis, and do not warrant its
6  * validity or performance.  We reserve the right to update, modify,
7  * or discontinue this software at any time.  We shall have no
8  * obligation to supply such updates or modifications or any other
9  * form of support to you.
10  * 
11  * This license is for research uses.  For such uses, there is no
12  * charge. We define "research use" to mean you may freely use it
13  * inside your organization for whatever purposes you see fit. But you
14  * may not re-distribute Paradyn or parts of Paradyn, in any form
15  * source or binary (including derivatives), electronic or otherwise,
16  * to any other organization or entity without our permission.
17  * 
18  * (for other uses, please contact us at paradyn@cs.wisc.edu)
19  * 
20  * All warranties, including without limitation, any warranty of
21  * merchantability or fitness for a particular purpose, are hereby
22  * excluded.
23  * 
24  * By your use of Paradyn, you understand and agree that we (or any
25  * other person or entity with proprietary rights in Paradyn) are
26  * under no obligation to provide either maintenance services,
27  * update services, notices of latent defects, or correction of
28  * defects for Paradyn.
29  * 
30  * Even if advised of the possibility of such damages, under no
31  * circumstances shall we (or any other person or entity with
32  * proprietary rights in the software licensed hereunder) be liable
33  * to you or any third party for direct, indirect, or consequential
34  * damages of any character regardless of type of action, including,
35  * without limitation, loss of profits, loss of use, loss of good
36  * will, or computer failure or malfunction.  You agree to indemnify
37  * us (and any other person or entity with proprietary rights in the
38  * software licensed hereunder) for any and all liability it may
39  * incur to third parties resulting from your use of Paradyn.
40  */
41
42 // tkTools.C
43 // Ariel Tamches
44
45 /* $Log: tkTools.C,v $
46 /* Revision 1.9  1999/03/12 22:59:32  pcroth
47 /* Fixed poor handling of RCS logs by last CVS checkin
48 /*
49  * Revision 1.8  1999/03/03 18:16:12  pcroth
50  * Updated to support Windows NT as a front-end platform
51  * Changes made to X code, to use Tcl analogues when appropriate
52  * Also changed in response to modifications in thread library and igen output.
53  *
54  * Revision 1.7  1996/11/26 16:06:59  naim
55  * Fixing asserts - naim
56  *
57  * Revision 1.6  1996/08/16 21:07:27  tamches
58  * updated copyright for release 1.1
59  *
60  * Revision 1.5  1996/02/15 22:47:34  tamches
61  * changed setResultBool a bit
62  *
63  * Revision 1.4  1996/02/02 18:54:46  tamches
64  * added setResultBool
65  *
66  * Revision 1.3  1995/11/28 15:50:04  naim
67  * Minor fix. Changing char[number] by string - naim
68  *
69  * Revision 1.2  1995/11/06  02:29:18  tamches
70  * added tclpanic and resizeScrollbar
71  *
72  */
73
74 #include <assert.h>
75 #include <stdlib.h> // exit()
76 #include "minmax.h"
77 #include "util/h/headers.h"
78 #include "tkTools.h"
79
80 tkInstallIdle::tkInstallIdle(void (*iUsersRoutine)(ClientData)) {
81    currentlyInstalled = false;
82    usersRoutine = iUsersRoutine;
83 }
84
85 tkInstallIdle::~tkInstallIdle() {
86    if (currentlyInstalled)
87       ;
88    currentlyInstalled = false;
89 }
90
91 void tkInstallIdle::install(ClientData cd) {
92    // Installs installMe(), below.
93
94    if (!currentlyInstalled) {
95       Tk_DoWhenIdle(installMe, (ClientData)this);
96       usersClientData = cd;
97
98       currentlyInstalled = true;
99    }
100 }
101
102 void tkInstallIdle::installMe(ClientData cd) {
103    // A static member function that gets installed
104    // Please don't confuse this with the routine that does the installation.
105    tkInstallIdle *pthis = (tkInstallIdle *)cd;
106
107    pthis->currentlyInstalled = false;
108    pthis->usersRoutine(pthis->usersClientData);
109 }
110
111 /* ******************************************************** */
112
113 void myTclEval(Tcl_Interp *interp, const string &str) {
114    myTclEval(interp, str.string_of());
115 }
116
117 void myTclEval(Tcl_Interp *interp, const char *buffer) {
118    if (TCL_OK != Tcl_Eval(interp, (char*)buffer)) {
119       cerr << interp->result << endl;
120       exit(5);
121    }
122 }
123
124 void tclpanic(Tcl_Interp *interp, const string &str) {
125    cerr << str << ": " << interp->result << endl;
126    exit(5);
127 }
128
129 /* ******************************************************** */
130
131 void getScrollBarValues(Tcl_Interp *interp, const string &scrollBarName,
132                         float &first, float &last) {
133    string commandStr = scrollBarName + " get";
134    myTclEval(interp, commandStr.string_of());
135    bool aflag;
136    aflag = (2==sscanf(interp->result, "%f %f", &first, &last));
137    assert(aflag);
138 }
139
140 float moveScrollBar(Tcl_Interp *interp, const string &scrollBarName,
141                     float newFirst) {
142    // This routine adjusts a scrollbar to a new position.
143    // The width of the scrollbar thumb stays unchanged.
144    // If pinning is necessary, we make an effort to keep newFirst close to oldFirst
145
146    float oldFirst, oldLast;
147    getScrollBarValues(interp, scrollBarName, oldFirst, oldLast);
148    const float oldDifference = oldLast-oldFirst;
149    if (oldDifference > 1) {
150       cerr << "moveScrollBar: I was handed a scrollbar with bad values [first=" << oldFirst << "; last=" << oldLast << "]...ignoring" << endl;
151       return newFirst;
152    }
153    if (oldLast > 1.0) {
154       cerr << "moveScrollBar: I was handed a scrollbar with bad last [first=" << oldFirst << "; last=" << oldLast << "]...ignoring" << endl;
155       return newFirst;
156    }
157
158    newFirst = max(newFirst, 0.0f);
159
160    assert(newFirst >= 0.0);
161
162    float newLast = newFirst + oldDifference;
163    if (newLast > 1.0) {
164       newLast = 1.0;
165       newFirst = 1.0 - oldDifference;
166    }
167
168    assert(newLast <= 1.0);
169    assert(newFirst >= 0.0);
170
171    string buffer;
172    buffer = string(newFirst) + string(" ");
173    buffer += string(newLast);
174
175    string commandStr = scrollBarName + " set " + buffer;
176    myTclEval(interp, commandStr.string_of());
177
178    return newFirst;
179 }
180
181 int set_scrollbar(Tcl_Interp *interp, const string &sbname,
182                   int total_width, 
183                   int global_coord, int &screen_coord) {
184    int new_first_pix = global_coord - screen_coord;
185    float new_first_frac = moveScrollBar(interp, sbname,
186                                         1.0*new_first_pix / total_width);
187    new_first_pix = (int)(new_first_frac * total_width);
188       // will differ from earlier value if pinning occurred.
189    
190    // now let's modify screen_coord to reflect actual placement.
191    // That is, we tried to put global_coord at pixel screen_coord.
192    // We may not have succeeded, if pinning occurred.
193    // By definition, first_pix = global_coord - screen_coord, so
194    // screen_coord = global_coord - first_pix
195    screen_coord = global_coord - new_first_pix;
196
197    return new_first_pix;
198 }
199
200 bool processScrollCallback(Tcl_Interp *interp,
201                            int argc, char **argv,
202                            const string &sbName,
203                            int oldOffsetUnits, int totalWidthUnits,
204                            int visibleWidthUnits,
205                            float &newFirst) {
206    // tk4.0 has a complex method of reporting scroll events.
207    // It will invoke a callback with a variable number of arguments,
208    // depending on whether the sb was unit-moved, page-moved, or dragged.
209    // This routine parses those arguments, modifies the scrollbar,
210    // and returns true iff anything changed.  If so, the parameter
211    // "newFirst" is modified (so you can read it and invoke application-specific
212    // stuff.  after all, this routine merely updates the scrollbar)
213    
214    assert(argc >= 2);
215
216    float oldFirst, oldLast;
217    getScrollBarValues(interp, sbName, oldFirst, oldLast);
218
219    float tentativeNewFirst;   
220    if (0==strcmp(argv[1], "moveto"))
221       tentativeNewFirst = atof(argv[2]);
222    else if (0==strcmp(argv[1], "scroll")) {
223       int num = atoi(argv[2]);
224       if (0==strcmp(argv[3], "units"))
225          tentativeNewFirst = (float)(-oldOffsetUnits + num) / totalWidthUnits;
226       else if (0==strcmp(argv[3], "pages"))
227          tentativeNewFirst = (float)(-oldOffsetUnits + visibleWidthUnits*num) / totalWidthUnits;
228       else
229          assert(false);
230    }
231    else {
232       cerr << "processScrollCallback: unexpected argv[1] (expected 'moveto' or 'units'): " << argv[1] << endl;
233       assert(false);
234    }
235
236    float actualNewFirst = moveScrollBar(interp, sbName, tentativeNewFirst);
237    if (actualNewFirst != oldFirst) {
238       newFirst = actualNewFirst;
239       return true;
240    }
241    return false; // no changes
242 }
243
244 void resizeScrollbar(Tcl_Interp *interp, const string &sbName,
245                      int total_width, int visible_width) {
246    // A C++ version of resize1Scrollbar (the tcl routine)
247    float oldFirst, oldLast;
248    getScrollBarValues(interp, sbName, oldFirst, oldLast);
249
250    float newFirst, newLast;
251    if (visible_width < total_width) {
252       // the usual case: not everything fits
253       float fracVisible = 1.0 * visible_width / total_width;
254
255       newFirst = oldFirst;
256       newLast = newFirst + fracVisible;
257
258       if (newLast > 1.0) {
259          float theOverflow = newLast - 1.0;
260          newFirst = oldFirst - theOverflow;
261          newLast = newFirst + fracVisible;
262       }
263    }
264    else {
265       // the unusual case: everything fits on screen
266       newFirst = 0.0;
267       newLast = 1.0;
268    }
269
270    // some assertion checking
271    if (newFirst < 0)
272       cerr << "resizeScrollbar warning: newFirst is " << newFirst << endl;
273    if (newLast > 1)
274       cerr << "resizeScrollbar warning: newLast is " << newLast << endl;
275
276    string commandStr = sbName + " set " + string(newFirst) + " " + string(newLast);
277    myTclEval(interp, commandStr);
278 }
279
280 void setResultBool(Tcl_Interp *interp, bool val) {
281    // Apparantly, tcl scripts cannot use the ! operator on "true"
282    // or "false; only on "1" or "0".  Hence, the latter style is preferred.
283    if (val)
284       //strcpy(interp->result, "true");
285       strcpy(interp->result, "1");
286    else
287       //strcpy(interp->result, "false");
288       strcpy(interp->result, "0");
289 }