1 |
/* $Header$ */ |
2 |
|
3 |
/* |
4 |
* tkWinScrollbar.c -- |
5 |
* |
6 |
* This file implements the Windows specific portion of the scrollbar |
7 |
* widget. |
8 |
* |
9 |
* Copyright (c) 1996 by Sun Microsystems, Inc. |
10 |
* |
11 |
* See the file "license.terms" for information on usage and redistribution |
12 |
* of this file, and for a DISCLAIMER OF ALL WARRANTIES. |
13 |
* |
14 |
* RCS: @(#) $Id: tkwinscrlbr.c,v 1.1.1.1 2001/06/13 05:14:22 dtashley Exp $ |
15 |
*/ |
16 |
|
17 |
#include "tkWinInt.h" |
18 |
#include "tkScrollbar.h" |
19 |
|
20 |
|
21 |
/* |
22 |
* The following constant is used to specify the maximum scroll position. |
23 |
* This value is limited by the Win32 API to either 16-bits or 32-bits, |
24 |
* depending on the context. For now we'll just use a value small |
25 |
* enough to fit in 16-bits, but which gives us 4-digits of precision. |
26 |
*/ |
27 |
|
28 |
#define MAX_SCROLL 10000 |
29 |
|
30 |
/* |
31 |
* Declaration of Windows specific scrollbar structure. |
32 |
*/ |
33 |
|
34 |
typedef struct WinScrollbar { |
35 |
TkScrollbar info; /* Generic scrollbar info. */ |
36 |
WNDPROC oldProc; /* Old window procedure. */ |
37 |
int lastVertical; /* 1 if was vertical at last refresh. */ |
38 |
HWND hwnd; /* Current window handle. */ |
39 |
int winFlags; /* Various flags; see below. */ |
40 |
} WinScrollbar; |
41 |
|
42 |
/* |
43 |
* Flag bits for native scrollbars: |
44 |
* |
45 |
* IN_MODAL_LOOP: Non-zero means this scrollbar is in the middle |
46 |
* of a modal loop. |
47 |
* ALREADY_DEAD: Non-zero means this scrollbar has been |
48 |
* destroyed, but has not been cleaned up. |
49 |
*/ |
50 |
|
51 |
#define IN_MODAL_LOOP 1 |
52 |
#define ALREADY_DEAD 2 |
53 |
|
54 |
/* |
55 |
* Cached system metrics used to determine scrollbar geometry. |
56 |
*/ |
57 |
|
58 |
static int initialized = 0; |
59 |
static int hArrowWidth, hThumb; /* Horizontal control metrics. */ |
60 |
static int vArrowWidth, vArrowHeight, vThumb; /* Vertical control metrics. */ |
61 |
|
62 |
TCL_DECLARE_MUTEX(winScrlbrMutex) |
63 |
|
64 |
/* |
65 |
* This variable holds the default width for a scrollbar in string |
66 |
* form for use in a Tk_ConfigSpec. |
67 |
*/ |
68 |
|
69 |
static char defWidth[TCL_INTEGER_SPACE]; |
70 |
|
71 |
/* |
72 |
* Declarations for functions defined in this file. |
73 |
*/ |
74 |
|
75 |
static Window CreateProc _ANSI_ARGS_((Tk_Window tkwin, |
76 |
Window parent, ClientData instanceData)); |
77 |
static void ModalLoopProc _ANSI_ARGS_((Tk_Window tkwin, |
78 |
XEvent *eventPtr)); |
79 |
static int ScrollbarBindProc _ANSI_ARGS_((ClientData clientData, |
80 |
Tcl_Interp *interp, XEvent *eventPtr, |
81 |
Tk_Window tkwin, KeySym keySym)); |
82 |
static LRESULT CALLBACK ScrollbarProc _ANSI_ARGS_((HWND hwnd, UINT message, |
83 |
WPARAM wParam, LPARAM lParam)); |
84 |
static void UpdateScrollbar _ANSI_ARGS_(( |
85 |
WinScrollbar *scrollPtr)); |
86 |
static void UpdateScrollbarMetrics _ANSI_ARGS_((void)); |
87 |
|
88 |
/* |
89 |
* The class procedure table for the scrollbar widget. |
90 |
*/ |
91 |
|
92 |
TkClassProcs tkpScrollbarProcs = { |
93 |
CreateProc, /* createProc */ |
94 |
NULL, /* geometryProc */ |
95 |
ModalLoopProc, /* modalProc */ |
96 |
}; |
97 |
|
98 |
|
99 |
/* |
100 |
*---------------------------------------------------------------------- |
101 |
* |
102 |
* TkpCreateScrollbar -- |
103 |
* |
104 |
* Allocate a new TkScrollbar structure. |
105 |
* |
106 |
* Results: |
107 |
* Returns a newly allocated TkScrollbar structure. |
108 |
* |
109 |
* Side effects: |
110 |
* Registers an event handler for the widget. |
111 |
* |
112 |
*---------------------------------------------------------------------- |
113 |
*/ |
114 |
|
115 |
TkScrollbar * |
116 |
TkpCreateScrollbar(tkwin) |
117 |
Tk_Window tkwin; |
118 |
{ |
119 |
WinScrollbar *scrollPtr; |
120 |
TkWindow *winPtr = (TkWindow *)tkwin; |
121 |
|
122 |
if (!initialized) { |
123 |
Tcl_MutexLock(&winScrlbrMutex); |
124 |
UpdateScrollbarMetrics(); |
125 |
initialized = 1; |
126 |
Tcl_MutexUnlock(&winScrlbrMutex); |
127 |
} |
128 |
|
129 |
scrollPtr = (WinScrollbar *) ckalloc(sizeof(WinScrollbar)); |
130 |
scrollPtr->winFlags = 0; |
131 |
scrollPtr->hwnd = NULL; |
132 |
|
133 |
Tk_CreateEventHandler(tkwin, |
134 |
ExposureMask|StructureNotifyMask|FocusChangeMask, |
135 |
TkScrollbarEventProc, (ClientData) scrollPtr); |
136 |
|
137 |
if (!Tcl_GetAssocData(winPtr->mainPtr->interp, "TkScrollbar", NULL)) { |
138 |
Tcl_SetAssocData(winPtr->mainPtr->interp, "TkScrollbar", NULL, |
139 |
(ClientData)1); |
140 |
TkCreateBindingProcedure(winPtr->mainPtr->interp, |
141 |
winPtr->mainPtr->bindingTable, |
142 |
(ClientData)Tk_GetUid("Scrollbar"), "<ButtonPress>", |
143 |
ScrollbarBindProc, NULL, NULL); |
144 |
} |
145 |
|
146 |
return (TkScrollbar*) scrollPtr; |
147 |
} |
148 |
|
149 |
/* |
150 |
*---------------------------------------------------------------------- |
151 |
* |
152 |
* UpdateScrollbar -- |
153 |
* |
154 |
* This function updates the position and size of the scrollbar |
155 |
* thumb based on the current settings. |
156 |
* |
157 |
* Results: |
158 |
* None. |
159 |
* |
160 |
* Side effects: |
161 |
* Moves the thumb. |
162 |
* |
163 |
*---------------------------------------------------------------------- |
164 |
*/ |
165 |
|
166 |
static void |
167 |
UpdateScrollbar(scrollPtr) |
168 |
WinScrollbar *scrollPtr; |
169 |
{ |
170 |
SCROLLINFO scrollInfo; |
171 |
double thumbSize; |
172 |
|
173 |
/* |
174 |
* Update the current scrollbar position and shape. |
175 |
*/ |
176 |
|
177 |
scrollInfo.fMask = SIF_PAGE | SIF_POS | SIF_RANGE; |
178 |
scrollInfo.cbSize = sizeof(scrollInfo); |
179 |
scrollInfo.nMin = 0; |
180 |
scrollInfo.nMax = MAX_SCROLL; |
181 |
thumbSize = (scrollPtr->info.lastFraction - scrollPtr->info.firstFraction); |
182 |
scrollInfo.nPage = ((UINT) (thumbSize * (double) MAX_SCROLL)) + 1; |
183 |
if (thumbSize < 1.0) { |
184 |
scrollInfo.nPos = (int) |
185 |
((scrollPtr->info.firstFraction / (1.0-thumbSize)) |
186 |
* (MAX_SCROLL - (scrollInfo.nPage - 1))); |
187 |
} else { |
188 |
scrollInfo.nPos = 0; |
189 |
} |
190 |
SetScrollInfo(scrollPtr->hwnd, SB_CTL, &scrollInfo, TRUE); |
191 |
} |
192 |
|
193 |
/* |
194 |
*---------------------------------------------------------------------- |
195 |
* |
196 |
* CreateProc -- |
197 |
* |
198 |
* This function creates a new Scrollbar control, subclasses |
199 |
* the instance, and generates a new Window object. |
200 |
* |
201 |
* Results: |
202 |
* Returns the newly allocated Window object, or None on failure. |
203 |
* |
204 |
* Side effects: |
205 |
* Causes a new Scrollbar control to come into existence. |
206 |
* |
207 |
*---------------------------------------------------------------------- |
208 |
*/ |
209 |
|
210 |
static Window |
211 |
CreateProc(tkwin, parentWin, instanceData) |
212 |
Tk_Window tkwin; /* Token for window. */ |
213 |
Window parentWin; /* Parent of new window. */ |
214 |
ClientData instanceData; /* Scrollbar instance data. */ |
215 |
{ |
216 |
DWORD style; |
217 |
Window window; |
218 |
HWND parent; |
219 |
TkWindow *winPtr; |
220 |
WinScrollbar *scrollPtr = (WinScrollbar *)instanceData; |
221 |
|
222 |
parent = Tk_GetHWND(parentWin); |
223 |
|
224 |
if (scrollPtr->info.vertical) { |
225 |
style = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS |
226 |
| SBS_VERT | SBS_RIGHTALIGN; |
227 |
} else { |
228 |
style = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS |
229 |
| SBS_HORZ | SBS_BOTTOMALIGN; |
230 |
} |
231 |
|
232 |
scrollPtr->hwnd = CreateWindow("SCROLLBAR", NULL, style, |
233 |
Tk_X(tkwin), Tk_Y(tkwin), Tk_Width(tkwin), Tk_Height(tkwin), |
234 |
parent, NULL, Tk_GetHINSTANCE(), NULL); |
235 |
|
236 |
/* |
237 |
* Ensure new window is inserted into the stacking order at the correct |
238 |
* place. |
239 |
*/ |
240 |
|
241 |
SetWindowPos(scrollPtr->hwnd, HWND_TOP, 0, 0, 0, 0, |
242 |
SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE); |
243 |
|
244 |
for (winPtr = ((TkWindow*)tkwin)->nextPtr; winPtr != NULL; |
245 |
winPtr = winPtr->nextPtr) { |
246 |
if ((winPtr->window != None) && !(winPtr->flags & TK_TOP_LEVEL)) { |
247 |
TkWinSetWindowPos(scrollPtr->hwnd, Tk_GetHWND(winPtr->window), |
248 |
Below); |
249 |
break; |
250 |
} |
251 |
} |
252 |
|
253 |
scrollPtr->lastVertical = scrollPtr->info.vertical; |
254 |
scrollPtr->oldProc = (WNDPROC)SetWindowLong(scrollPtr->hwnd, GWL_WNDPROC, |
255 |
(DWORD) ScrollbarProc); |
256 |
window = Tk_AttachHWND(tkwin, scrollPtr->hwnd); |
257 |
|
258 |
UpdateScrollbar(scrollPtr); |
259 |
return window; |
260 |
} |
261 |
|
262 |
/* |
263 |
*-------------------------------------------------------------- |
264 |
* |
265 |
* TkpDisplayScrollbar -- |
266 |
* |
267 |
* This procedure redraws the contents of a scrollbar window. |
268 |
* It is invoked as a do-when-idle handler, so it only runs |
269 |
* when there's nothing else for the application to do. |
270 |
* |
271 |
* Results: |
272 |
* None. |
273 |
* |
274 |
* Side effects: |
275 |
* Information appears on the screen. |
276 |
* |
277 |
*-------------------------------------------------------------- |
278 |
*/ |
279 |
|
280 |
void |
281 |
TkpDisplayScrollbar(clientData) |
282 |
ClientData clientData; /* Information about window. */ |
283 |
{ |
284 |
WinScrollbar *scrollPtr = (WinScrollbar *) clientData; |
285 |
Tk_Window tkwin = scrollPtr->info.tkwin; |
286 |
|
287 |
scrollPtr->info.flags &= ~REDRAW_PENDING; |
288 |
if ((tkwin == NULL) || !Tk_IsMapped(tkwin)) { |
289 |
return; |
290 |
} |
291 |
|
292 |
/* |
293 |
* Destroy and recreate the scrollbar control if the orientation |
294 |
* has changed. |
295 |
*/ |
296 |
|
297 |
if (scrollPtr->lastVertical != scrollPtr->info.vertical) { |
298 |
HWND hwnd = Tk_GetHWND(Tk_WindowId(tkwin)); |
299 |
|
300 |
SetWindowLong(hwnd, GWL_WNDPROC, (DWORD) scrollPtr->oldProc); |
301 |
DestroyWindow(hwnd); |
302 |
|
303 |
CreateProc(tkwin, Tk_WindowId(Tk_Parent(tkwin)), |
304 |
(ClientData) scrollPtr); |
305 |
} else { |
306 |
UpdateScrollbar(scrollPtr); |
307 |
} |
308 |
} |
309 |
|
310 |
/* |
311 |
*---------------------------------------------------------------------- |
312 |
* |
313 |
* TkpDestroyScrollbar -- |
314 |
* |
315 |
* Free data structures associated with the scrollbar control. |
316 |
* |
317 |
* Results: |
318 |
* None. |
319 |
* |
320 |
* Side effects: |
321 |
* Restores the default control state. |
322 |
* |
323 |
*---------------------------------------------------------------------- |
324 |
*/ |
325 |
|
326 |
void |
327 |
TkpDestroyScrollbar(scrollPtr) |
328 |
TkScrollbar *scrollPtr; |
329 |
{ |
330 |
WinScrollbar *winScrollPtr = (WinScrollbar *)scrollPtr; |
331 |
HWND hwnd = winScrollPtr->hwnd; |
332 |
if (hwnd) { |
333 |
SetWindowLong(hwnd, GWL_WNDPROC, (DWORD) winScrollPtr->oldProc); |
334 |
if (winScrollPtr->winFlags & IN_MODAL_LOOP) { |
335 |
((TkWindow *)scrollPtr->tkwin)->flags |= TK_DONT_DESTROY_WINDOW; |
336 |
SetParent(hwnd, NULL); |
337 |
} |
338 |
} |
339 |
winScrollPtr->winFlags |= ALREADY_DEAD; |
340 |
} |
341 |
|
342 |
/* |
343 |
*---------------------------------------------------------------------- |
344 |
* |
345 |
* UpdateScrollbarMetrics -- |
346 |
* |
347 |
* This function retrieves the current system metrics for a |
348 |
* scrollbar. |
349 |
* |
350 |
* Results: |
351 |
* None. |
352 |
* |
353 |
* Side effects: |
354 |
* Updates the geometry cache info for all scrollbars. |
355 |
* |
356 |
*---------------------------------------------------------------------- |
357 |
*/ |
358 |
|
359 |
void |
360 |
UpdateScrollbarMetrics() |
361 |
{ |
362 |
Tk_ConfigSpec *specPtr; |
363 |
|
364 |
hArrowWidth = GetSystemMetrics(SM_CXHSCROLL); |
365 |
hThumb = GetSystemMetrics(SM_CXHTHUMB); |
366 |
vArrowWidth = GetSystemMetrics(SM_CXVSCROLL); |
367 |
vArrowHeight = GetSystemMetrics(SM_CYVSCROLL); |
368 |
vThumb = GetSystemMetrics(SM_CYVTHUMB); |
369 |
|
370 |
sprintf(defWidth, "%d", vArrowWidth); |
371 |
for (specPtr = tkpScrollbarConfigSpecs; specPtr->type != TK_CONFIG_END; |
372 |
specPtr++) { |
373 |
if (specPtr->offset == Tk_Offset(TkScrollbar, width)) { |
374 |
specPtr->defValue = defWidth; |
375 |
} |
376 |
} |
377 |
} |
378 |
|
379 |
/* |
380 |
*---------------------------------------------------------------------- |
381 |
* |
382 |
* TkpComputeScrollbarGeometry -- |
383 |
* |
384 |
* After changes in a scrollbar's size or configuration, this |
385 |
* procedure recomputes various geometry information used in |
386 |
* displaying the scrollbar. |
387 |
* |
388 |
* Results: |
389 |
* None. |
390 |
* |
391 |
* Side effects: |
392 |
* The scrollbar will be displayed differently. |
393 |
* |
394 |
*---------------------------------------------------------------------- |
395 |
*/ |
396 |
|
397 |
void |
398 |
TkpComputeScrollbarGeometry(scrollPtr) |
399 |
register TkScrollbar *scrollPtr; /* Scrollbar whose geometry may |
400 |
* have changed. */ |
401 |
{ |
402 |
int fieldLength, minThumbSize; |
403 |
|
404 |
/* |
405 |
* Windows doesn't use focus rings on scrollbars, but we still |
406 |
* perform basic sanity checks to appease backwards compatibility. |
407 |
*/ |
408 |
|
409 |
if (scrollPtr->highlightWidth < 0) { |
410 |
scrollPtr->highlightWidth = 0; |
411 |
} |
412 |
|
413 |
if (scrollPtr->vertical) { |
414 |
scrollPtr->arrowLength = vArrowHeight; |
415 |
fieldLength = Tk_Height(scrollPtr->tkwin); |
416 |
minThumbSize = vThumb; |
417 |
} else { |
418 |
scrollPtr->arrowLength = hArrowWidth; |
419 |
fieldLength = Tk_Width(scrollPtr->tkwin); |
420 |
minThumbSize = hThumb; |
421 |
} |
422 |
fieldLength -= 2*scrollPtr->arrowLength; |
423 |
if (fieldLength < 0) { |
424 |
fieldLength = 0; |
425 |
} |
426 |
scrollPtr->sliderFirst = (int) ((double)fieldLength |
427 |
* scrollPtr->firstFraction); |
428 |
scrollPtr->sliderLast = (int) ((double)fieldLength |
429 |
* scrollPtr->lastFraction); |
430 |
|
431 |
/* |
432 |
* Adjust the slider so that some piece of it is always |
433 |
* displayed in the scrollbar and so that it has at least |
434 |
* a minimal width (so it can be grabbed with the mouse). |
435 |
*/ |
436 |
|
437 |
if (scrollPtr->sliderFirst > fieldLength) { |
438 |
scrollPtr->sliderFirst = fieldLength; |
439 |
} |
440 |
if (scrollPtr->sliderFirst < 0) { |
441 |
scrollPtr->sliderFirst = 0; |
442 |
} |
443 |
if (scrollPtr->sliderLast < (scrollPtr->sliderFirst |
444 |
+ minThumbSize)) { |
445 |
scrollPtr->sliderLast = scrollPtr->sliderFirst + minThumbSize; |
446 |
} |
447 |
if (scrollPtr->sliderLast > fieldLength) { |
448 |
scrollPtr->sliderLast = fieldLength; |
449 |
} |
450 |
scrollPtr->sliderFirst += scrollPtr->arrowLength; |
451 |
scrollPtr->sliderLast += scrollPtr->arrowLength; |
452 |
|
453 |
/* |
454 |
* Register the desired geometry for the window (leave enough space |
455 |
* for the two arrows plus a minimum-size slider, plus border around |
456 |
* the whole window, if any). Then arrange for the window to be |
457 |
* redisplayed. |
458 |
*/ |
459 |
|
460 |
if (scrollPtr->vertical) { |
461 |
Tk_GeometryRequest(scrollPtr->tkwin, |
462 |
scrollPtr->width, 2*scrollPtr->arrowLength + minThumbSize); |
463 |
} else { |
464 |
Tk_GeometryRequest(scrollPtr->tkwin, |
465 |
2*scrollPtr->arrowLength + minThumbSize, scrollPtr->width); |
466 |
} |
467 |
Tk_SetInternalBorder(scrollPtr->tkwin, 0); |
468 |
} |
469 |
|
470 |
/* |
471 |
*---------------------------------------------------------------------- |
472 |
* |
473 |
* ScrollbarProc -- |
474 |
* |
475 |
* This function is call by Windows whenever an event occurs on |
476 |
* a scrollbar control created by Tk. |
477 |
* |
478 |
* Results: |
479 |
* Standard Windows return value. |
480 |
* |
481 |
* Side effects: |
482 |
* May generate events. |
483 |
* |
484 |
*---------------------------------------------------------------------- |
485 |
*/ |
486 |
|
487 |
static LRESULT CALLBACK |
488 |
ScrollbarProc(hwnd, message, wParam, lParam) |
489 |
HWND hwnd; |
490 |
UINT message; |
491 |
WPARAM wParam; |
492 |
LPARAM lParam; |
493 |
{ |
494 |
LRESULT result; |
495 |
POINT point; |
496 |
WinScrollbar *scrollPtr; |
497 |
Tk_Window tkwin = Tk_HWNDToWindow(hwnd); |
498 |
|
499 |
if (tkwin == NULL) { |
500 |
panic("ScrollbarProc called on an invalid HWND"); |
501 |
} |
502 |
scrollPtr = (WinScrollbar *)((TkWindow*)tkwin)->instanceData; |
503 |
|
504 |
switch(message) { |
505 |
case WM_HSCROLL: |
506 |
case WM_VSCROLL: { |
507 |
Tcl_Interp *interp; |
508 |
Tcl_DString cmdString; |
509 |
int command = LOWORD(wParam); |
510 |
int code; |
511 |
|
512 |
GetCursorPos(&point); |
513 |
Tk_TranslateWinEvent(NULL, WM_MOUSEMOVE, 0, |
514 |
MAKELPARAM(point.x, point.y), &result); |
515 |
|
516 |
if (command == SB_ENDSCROLL) { |
517 |
return 0; |
518 |
} |
519 |
|
520 |
/* |
521 |
* Bail out immediately if there isn't a command to invoke. |
522 |
*/ |
523 |
|
524 |
if (scrollPtr->info.commandSize == 0) { |
525 |
Tcl_ServiceAll(); |
526 |
return 0; |
527 |
} |
528 |
|
529 |
Tcl_DStringInit(&cmdString); |
530 |
Tcl_DStringAppend(&cmdString, scrollPtr->info.command, |
531 |
scrollPtr->info.commandSize); |
532 |
|
533 |
if (command == SB_LINELEFT || command == SB_LINERIGHT) { |
534 |
Tcl_DStringAppendElement(&cmdString, "scroll"); |
535 |
Tcl_DStringAppendElement(&cmdString, |
536 |
(command == SB_LINELEFT ) ? "-1" : "1"); |
537 |
Tcl_DStringAppendElement(&cmdString, "units"); |
538 |
} else if (command == SB_PAGELEFT || command == SB_PAGERIGHT) { |
539 |
Tcl_DStringAppendElement(&cmdString, "scroll"); |
540 |
Tcl_DStringAppendElement(&cmdString, |
541 |
(command == SB_PAGELEFT ) ? "-1" : "1"); |
542 |
Tcl_DStringAppendElement(&cmdString, "pages"); |
543 |
} else { |
544 |
char valueString[TCL_DOUBLE_SPACE]; |
545 |
double pos = 0.0; |
546 |
switch (command) { |
547 |
case SB_THUMBPOSITION: |
548 |
pos = ((double)HIWORD(wParam)) / MAX_SCROLL; |
549 |
break; |
550 |
|
551 |
case SB_THUMBTRACK: |
552 |
pos = ((double)HIWORD(wParam)) / MAX_SCROLL; |
553 |
break; |
554 |
|
555 |
case SB_TOP: |
556 |
pos = 0.0; |
557 |
break; |
558 |
|
559 |
case SB_BOTTOM: |
560 |
pos = 1.0; |
561 |
break; |
562 |
} |
563 |
sprintf(valueString, "%g", pos); |
564 |
Tcl_DStringAppendElement(&cmdString, "moveto"); |
565 |
Tcl_DStringAppendElement(&cmdString, valueString); |
566 |
} |
567 |
|
568 |
interp = scrollPtr->info.interp; |
569 |
code = Tcl_GlobalEval(interp, cmdString.string); |
570 |
if (code != TCL_OK && code != TCL_CONTINUE && code != TCL_BREAK) { |
571 |
Tcl_AddErrorInfo(interp, "\n (scrollbar command)"); |
572 |
Tcl_BackgroundError(interp); |
573 |
} |
574 |
Tcl_DStringFree(&cmdString); |
575 |
|
576 |
Tcl_ServiceAll(); |
577 |
return 0; |
578 |
} |
579 |
|
580 |
default: |
581 |
if (Tk_TranslateWinEvent(hwnd, message, wParam, lParam, &result)) { |
582 |
return result; |
583 |
} |
584 |
} |
585 |
return CallWindowProc(scrollPtr->oldProc, hwnd, message, wParam, lParam); |
586 |
} |
587 |
|
588 |
/* |
589 |
*---------------------------------------------------------------------- |
590 |
* |
591 |
* TkpConfigureScrollbar -- |
592 |
* |
593 |
* This procedure is called after the generic code has finished |
594 |
* processing configuration options, in order to configure |
595 |
* platform specific options. |
596 |
* |
597 |
* Results: |
598 |
* None. |
599 |
* |
600 |
* Side effects: |
601 |
* None. |
602 |
* |
603 |
*---------------------------------------------------------------------- |
604 |
*/ |
605 |
|
606 |
void |
607 |
TkpConfigureScrollbar(scrollPtr) |
608 |
register TkScrollbar *scrollPtr; /* Information about widget; may or |
609 |
* may not already have values for |
610 |
* some fields. */ |
611 |
{ |
612 |
} |
613 |
|
614 |
/* |
615 |
*-------------------------------------------------------------- |
616 |
* |
617 |
* ScrollbarBindProc -- |
618 |
* |
619 |
* This procedure is invoked when the default <ButtonPress> |
620 |
* binding on the Scrollbar bind tag fires. |
621 |
* |
622 |
* Results: |
623 |
* None. |
624 |
* |
625 |
* Side effects: |
626 |
* The event enters a modal loop. |
627 |
* |
628 |
*-------------------------------------------------------------- |
629 |
*/ |
630 |
|
631 |
static int |
632 |
ScrollbarBindProc(clientData, interp, eventPtr, tkwin, keySym) |
633 |
ClientData clientData; |
634 |
Tcl_Interp *interp; |
635 |
XEvent *eventPtr; |
636 |
Tk_Window tkwin; |
637 |
KeySym keySym; |
638 |
{ |
639 |
TkWindow *winPtr = (TkWindow*)tkwin; |
640 |
if (eventPtr->type == ButtonPress) { |
641 |
winPtr->flags |= TK_DEFER_MODAL; |
642 |
} |
643 |
return TCL_OK; |
644 |
} |
645 |
|
646 |
/* |
647 |
*---------------------------------------------------------------------- |
648 |
* |
649 |
* ModalLoopProc -- |
650 |
* |
651 |
* This function is invoked at the end of the event processing |
652 |
* whenever the ScrollbarBindProc has been invoked for a ButtonPress |
653 |
* event. |
654 |
* |
655 |
* Results: |
656 |
* None. |
657 |
* |
658 |
* Side effects: |
659 |
* Enters a modal loop. |
660 |
* |
661 |
*---------------------------------------------------------------------- |
662 |
*/ |
663 |
|
664 |
static void |
665 |
ModalLoopProc(tkwin, eventPtr) |
666 |
Tk_Window tkwin; |
667 |
XEvent *eventPtr; |
668 |
{ |
669 |
TkWindow *winPtr = (TkWindow*)tkwin; |
670 |
WinScrollbar *scrollPtr = (WinScrollbar *) winPtr->instanceData; |
671 |
int oldMode; |
672 |
|
673 |
if (scrollPtr->hwnd) { |
674 |
Tcl_Preserve((ClientData)scrollPtr); |
675 |
scrollPtr->winFlags |= IN_MODAL_LOOP; |
676 |
oldMode = Tcl_SetServiceMode(TCL_SERVICE_ALL); |
677 |
TkWinResendEvent(scrollPtr->oldProc, scrollPtr->hwnd, eventPtr); |
678 |
(void) Tcl_SetServiceMode(oldMode); |
679 |
scrollPtr->winFlags &= ~IN_MODAL_LOOP; |
680 |
if (scrollPtr->hwnd && scrollPtr->winFlags & ALREADY_DEAD) { |
681 |
DestroyWindow(scrollPtr->hwnd); |
682 |
} |
683 |
Tcl_Release((ClientData)scrollPtr); |
684 |
} |
685 |
} |
686 |
|
687 |
/* |
688 |
*-------------------------------------------------------------- |
689 |
* |
690 |
* TkpScrollbarPosition -- |
691 |
* |
692 |
* Determine the scrollbar element corresponding to a |
693 |
* given position. |
694 |
* |
695 |
* Results: |
696 |
* One of TOP_ARROW, TOP_GAP, etc., indicating which element |
697 |
* of the scrollbar covers the position given by (x, y). If |
698 |
* (x,y) is outside the scrollbar entirely, then OUTSIDE is |
699 |
* returned. |
700 |
* |
701 |
* Side effects: |
702 |
* None. |
703 |
* |
704 |
*-------------------------------------------------------------- |
705 |
*/ |
706 |
|
707 |
int |
708 |
TkpScrollbarPosition(scrollPtr, x, y) |
709 |
register TkScrollbar *scrollPtr; /* Scrollbar widget record. */ |
710 |
int x, y; /* Coordinates within scrollPtr's |
711 |
* window. */ |
712 |
{ |
713 |
int length, width, tmp; |
714 |
|
715 |
if (scrollPtr->vertical) { |
716 |
length = Tk_Height(scrollPtr->tkwin); |
717 |
width = Tk_Width(scrollPtr->tkwin); |
718 |
} else { |
719 |
tmp = x; |
720 |
x = y; |
721 |
y = tmp; |
722 |
length = Tk_Width(scrollPtr->tkwin); |
723 |
width = Tk_Height(scrollPtr->tkwin); |
724 |
} |
725 |
|
726 |
if ((x < scrollPtr->inset) || (x >= (width - scrollPtr->inset)) |
727 |
|| (y < scrollPtr->inset) || (y >= (length - scrollPtr->inset))) { |
728 |
return OUTSIDE; |
729 |
} |
730 |
|
731 |
/* |
732 |
* All of the calculations in this procedure mirror those in |
733 |
* TkpDisplayScrollbar. Be sure to keep the two consistent. |
734 |
*/ |
735 |
|
736 |
if (y < (scrollPtr->inset + scrollPtr->arrowLength)) { |
737 |
return TOP_ARROW; |
738 |
} |
739 |
if (y < scrollPtr->sliderFirst) { |
740 |
return TOP_GAP; |
741 |
} |
742 |
if (y < scrollPtr->sliderLast) { |
743 |
return SLIDER; |
744 |
} |
745 |
if (y >= (length - (scrollPtr->arrowLength + scrollPtr->inset))) { |
746 |
return BOTTOM_ARROW; |
747 |
} |
748 |
return BOTTOM_GAP; |
749 |
} |
750 |
|
751 |
/* End of tkwinscrlbr.c */ |