comparison lwlib/xlwscrollbar.c @ 0:376386a54a3c r19-14

Import from CVS: tag r19-14
author cvs
date Mon, 13 Aug 2007 08:45:50 +0200
parents
children ac2d302a0011
comparison
equal deleted inserted replaced
-1:000000000000 0:376386a54a3c
1 /* Implements a lightweight scrollbar widget.
2 Copyright (C) 1992, 1993, 1994 Lucid, Inc.
3
4 This file is part of the Lucid Widget Library.
5
6 The Lucid Widget Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10
11 The Lucid Widget Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs; see the file COPYING. If not, write to
18 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
19
20 /* Created by Douglas Keller <dkeller@vnet.ibm.com> */
21 /* Last changed 03/24/95 */
22
23 /*
24 * Athena-style scrollbar button bindings added on Sun Dec 24 22:03:57 1995
25 * by Jonathan Stigelman <Stig@hackvan.com>... Ho ho ho!
26 *
27 * To use them, put this resource in your .Xdefaults
28 *
29 * Emacs*XlwScrollBar.translations: #override \n\
30 * <Btn1Down>: PageDownOrRight() \n\
31 * <Btn3Down>: PageUpOrLeft()
32 *
33 */
34
35 /*
36 * Resources Supported:
37 * XmNforeground
38 * XmNbackground
39 * XmNtopShadowColor
40 * XmNtopShadowPixmap
41 * XmNbottomShadowColor
42 * XmNbottomShadowPixmap
43 * XmNtroughColor
44 * XmNshadowThickness
45 * XmNshowArrows
46 * XmNorientation
47 * XmNborderWidth
48 *
49 * XmNminimum
50 * XmNmaximum
51 * XmNvalue
52 * XmNincrement
53 * XmNpageIncrement
54 *
55 * XmNvalueChangedCallback
56 * XmNincrementCallback
57 * XmNdecrementCallback
58 * XmNpageIncrementCallback
59 * XmNpageDecrementCallback
60 * XmNtoTopCallback
61 * XmNtoBottomCallback
62 * XmNdragCallback
63 *
64 * XmNknobStyle - values can be: "plain" or "dimple"
65 * XmNarrowPosition - values can be: "opposite" or "same"
66 *
67 */
68
69 #include <stdio.h>
70 #include <stdlib.h>
71 #include <limits.h>
72
73 #include <X11/IntrinsicP.h>
74 #include <X11/StringDefs.h>
75 #include <X11/bitmaps/gray>
76
77 #include "xlwscrollbarP.h"
78 #include "xlwscrollbar.h"
79
80 #define DBUG(x)
81
82 #define MINL(x,y) ((((unsigned long) (x)) < ((unsigned long) (y))) \
83 ? ((unsigned long) (x)) : ((unsigned long) (y)))
84
85 #define VERT(w) (w->sb.orientation == XmVERTICAL)
86
87 #define SS_MIN 8
88
89 #define ARROW_UP 0
90 #define ARROW_DOWN 1
91 #define ARROW_LEFT 2
92 #define ARROW_RIGHT 3
93
94 #define ARM_NONE 0
95 #define ARM_KNOB 1
96 #define ARM_UP 2
97 #define ARM_DOWN 3
98 #define ARM_PAGEUP 4
99 #define ARM_PAGEDOWN 5
100
101 #define BUTTON_NONE 0
102 #define BUTTON_KNOB 1
103 #define BUTTON_UP_ARROW 2
104 #define BUTTON_DOWN_ARROW 3
105 #define BUTTON_TROUGH_ABOVE 4
106 #define BUTTON_TROUGH_BELOW 5
107
108 #define KNOB_PLAIN 0
109 #define KNOB_DIMPLE 1
110
111 /************************************************************************
112 **
113 ** Resources
114 **
115 */
116 #define offset(field) XtOffset(XlwScrollBarWidget, field)
117
118 static XtResource resources[] = {
119 { XmNforeground, XmCForeground, XtRPixel, sizeof(Pixel),
120 offset(sb.foreground), XtRImmediate, XtDefaultForeground },
121
122 { XmNtopShadowColor, XmCTopShadowColor, XtRPixel, sizeof(Pixel),
123 offset(sb.topShadowColor), XtRImmediate, (XtPointer) ~0 },
124 { XmNbottomShadowColor, XmCBottomShadowColor, XtRPixel, sizeof(Pixel),
125 offset(sb.bottomShadowColor), XtRImmediate, (XtPointer)~0 },
126
127 { XmNtopShadowPixmap, XmCTopShadowPixmap, XtRPixmap, sizeof (Pixmap),
128 offset(sb.topShadowPixmap), XtRImmediate, (XtPointer)None},
129 { XmNbottomShadowPixmap, XmCBottomShadowPixmap, XtRPixmap, sizeof (Pixmap),
130 offset(sb.bottomShadowPixmap), XtRImmediate, (XtPointer)None},
131
132 { XmNtroughColor, XmCTroughColor, XtRPixel, sizeof(Pixel),
133 offset(sb.troughColor), XtRImmediate, (XtPointer)~0 },
134
135 { XmNshadowThickness, XmCShadowThickness, XtRInt, sizeof(int),
136 offset(sb.shadowThickness), XtRImmediate, (XtPointer)2 },
137
138 { XmNborderWidth, XmCBorderWidth, XtRDimension, sizeof(Dimension),
139 offset(core.border_width), XtRImmediate, (XtPointer)0 },
140
141 { XmNshowArrows, XmCShowArrows, XtRBoolean, sizeof(Boolean),
142 offset(sb.showArrows), XtRImmediate, (XtPointer)True },
143
144 { XmNinitialDelay, XmCInitialDelay, XtRInt, sizeof(int),
145 offset(sb.initialDelay), XtRImmediate, (XtPointer) 250 },
146 { XmNrepeatDelay, XmCRepeatDelay, XtRInt, sizeof(int),
147 offset(sb.repeatDelay), XtRImmediate, (XtPointer) 50 },
148
149 { XmNorientation, XmCOrientation, XtROrientation, sizeof(unsigned char),
150 offset(sb.orientation), XtRImmediate, (XtPointer) XmVERTICAL },
151
152
153 { XmNminimum, XmCMinimum, XtRInt, sizeof(int),
154 offset(sb.minimum), XtRImmediate, (XtPointer) 0},
155 { XmNmaximum, XmCMaximum, XtRInt, sizeof(int),
156 offset(sb.maximum), XtRImmediate, (XtPointer) 100},
157 { XmNvalue, XmCValue, XtRInt, sizeof(int),
158 offset(sb.value), XtRImmediate, (XtPointer) 0},
159 { XmNsliderSize, XmCSliderSize, XtRInt, sizeof(int),
160 offset(sb.sliderSize), XtRImmediate, (XtPointer) 10},
161 { XmNincrement, XmCIncrement, XtRInt, sizeof(int),
162 offset(sb.increment), XtRImmediate, (XtPointer) 1},
163 { XmNpageIncrement, XmCPageIncrement, XtRInt, sizeof(int),
164 offset(sb.pageIncrement), XtRImmediate, (XtPointer) 10},
165
166 { XmNvalueChangedCallback, XmCValueChangedCallback, XtRCallback, sizeof(XtPointer),
167 offset(sb.valueChangedCBL), XtRCallback, NULL},
168 { XmNincrementCallback, XmCIncrementCallback, XtRCallback, sizeof(XtPointer),
169 offset(sb.incrementCBL), XtRCallback, NULL},
170 { XmNdecrementCallback, XmCDecrementCallback, XtRCallback, sizeof(XtPointer),
171 offset(sb.decrementCBL), XtRCallback, NULL},
172 { XmNpageIncrementCallback, XmCPageIncrementCallback, XtRCallback, sizeof(XtPointer),
173 offset(sb.pageIncrementCBL), XtRCallback, NULL},
174 { XmNpageDecrementCallback, XmCPageDecrementCallback, XtRCallback, sizeof(XtPointer),
175 offset(sb.pageDecrementCBL), XtRCallback, NULL},
176 { XmNtoTopCallback, XmCToTopCallback, XtRCallback, sizeof(XtPointer),
177 offset(sb.toTopCBL), XtRCallback, NULL},
178 { XmNtoBottomCallback, XmCToBottomCallback, XtRCallback, sizeof(XtPointer),
179 offset(sb.toBottomCBL), XtRCallback, NULL},
180 { XmNdragCallback, XmCDragCallback, XtRCallback, sizeof(XtPointer),
181 offset(sb.dragCBL), XtRCallback, NULL},
182
183 { XmNknobStyle, XmCKnobStyle, XtRString, sizeof(char *),
184 offset(sb.knobStyle), XtRImmediate, NULL},
185
186 { XmNarrowPosition, XmCArrowPosition, XtRString, sizeof(char *),
187 offset(sb.arrowPosition), XtRImmediate, NULL},
188 };
189
190 /************************************************************************
191 **
192 ** Prototypes
193 **
194 */
195
196 /*
197 ** Actions
198 */
199 static void Select(Widget w, XEvent *event, String *parms, Cardinal *num_parms);
200 static void PageUpOrLeft(Widget w, XEvent *event, String *parms, Cardinal *num_parms);
201 static void PageDownOrRight(Widget w, XEvent *event, String *parms, Cardinal *num_parms);
202 static void Drag(Widget w, XEvent *event, String *parms, Cardinal *num_parms);
203 static void Release(Widget w, XEvent *event, String *parms, Cardinal *num_parms);
204 static void Jump(Widget w, XEvent *event, String *parms, Cardinal *num_parms);
205 static void Abort(Widget w, XEvent *event, String *parms, Cardinal *num_parms);
206
207 /*
208 ** Methods
209 */
210 static void Initialize(Widget treq, Widget tnew, ArgList args, Cardinal *num_args);
211 static Boolean SetValues(Widget current, Widget request, Widget nw, ArgList args, Cardinal *num_args);
212 static void Destroy(Widget widget);
213 static void Redisplay(Widget widget, XEvent *event, Region region);
214 static void Resize(Widget widget);
215 static void Realize(Widget widget, XtValueMask *valuemask, XSetWindowAttributes *attr);
216
217 /*
218 ** Private
219 */
220
221
222 /************************************************************************
223 **
224 ** Actions Table
225 **
226 */
227 static XtActionsRec actions[] = {
228 {"Select", Select},
229 {"PageDownOrRight", PageDownOrRight},
230 {"PageUpOrLeft", PageUpOrLeft},
231 {"Drag", Drag},
232 {"Release", Release},
233 {"Jump", Jump},
234 {"Abort", Abort},
235 };
236
237 /************************************************************************
238 **
239 ** Default Translation Table
240 **
241 */
242 static char default_translations[] =
243 "<Btn1Down>: Select()\n"
244 "<Btn1Motion>: Drag()\n"
245 "<Btn1Up>: Release()\n"
246 "<Btn2Down>: Jump()\n"
247 "<Btn2Motion>: Drag()\n"
248 "<Btn2Up>: Release()\n"
249 "<Key>Delete: Abort()"
250 ;
251
252 /************************************************************************
253 **
254 ** Class record initalization
255 **
256 */
257 XlwScrollBarClassRec xlwScrollBarClassRec = {
258 /* core_class fields */
259 {
260 /* superclass */ (WidgetClass) &coreClassRec,
261 /* class_name */ "XlwScrollBar",
262 /* widget_size */ sizeof(XlwScrollBarRec),
263 /* class_initialize */ NULL,
264 /* class_part_init */ NULL,
265 /* class_inited */ False,
266 /* initialize */ Initialize,
267 /* initialize_hook */ NULL,
268 /* realize */ Realize,
269 /* actions */ actions,
270 /* num_actions */ XtNumber(actions),
271 /* resources */ resources,
272 /* num_resources */ XtNumber(resources),
273 /* xrm_class */ NULLQUARK,
274 /* compress_motion */ True,
275 /* compress_exposure */ XtExposeCompressMultiple,
276 /* compress_enterleave */ True,
277 /* visible_interest */ False,
278 /* destroy */ Destroy,
279 /* resize */ Resize,
280 /* expose */ Redisplay,
281 /* set_values */ SetValues,
282 /* set_values_hook */ NULL,
283 /* set_values_almost */ XtInheritSetValuesAlmost,
284 /* get_values_hook */ NULL,
285 /* accept_focus */ NULL,
286 /* version */ XtVersionDontCheck,
287 /* callback_private */ NULL,
288 /* tm_table */ default_translations,
289 /* query_geometry */ NULL,
290 },
291 /* scrollbar_class fields */
292 {
293 /* dummy_field */ 0,
294 },
295 };
296
297 WidgetClass xlwScrollBarWidgetClass = (WidgetClass) &xlwScrollBarClassRec;
298
299 /************************************************************************
300 **
301 ** Debug funcitons
302 **
303 */
304
305 #ifdef SHOW_CLEAR
306 static void myXClearArea(Display *dpy, Drawable d, int x, int y, int w, int h, Boolean exp, XlwScrollBarWidget widget)
307 {
308 XFillRectangle(dpy, d, widget->sb.topShadowGC, x, y, w, h);
309 XSync(dpy, False);
310 sleep(2);
311 XClearArea(dpy, d, x, y, w, h, exp);
312 }
313
314 #define XClearArea(dpy,win,x,y,width,height,exp) myXClearArea(dpy,win,x,y,width,height,exp,w)
315 #endif
316
317 #ifdef CHECK_VALUES
318 static void check(XlwScrollBarWidget w)
319 {
320 int height;
321
322 height= widget_h(w);
323 if( w->sb.showArrows ) height -= (2*arrow_h(w));
324
325 if( (w->sb.above + w->sb.ss + w->sb.below > height) ||
326 (w->sb.value < w->sb.minimum) ||
327 (w->sb.value > w->sb.maximum - w->sb.sliderSize )
328 )
329 {
330 printf("above=%d ss=%d below=%d height=%d\n",
331 w->sb.above, w->sb.ss, w->sb.below, height);
332 printf("value=%d min=%d max=%d ss=%d max-ss=%d\n",
333 w->sb.value, w->sb.minimum, w->sb.maximum, w->sb.sliderSize, w->sb.maximum - w->sb.sliderSize);
334 abort();
335 }
336 }
337
338 # define CHECK(w) check(w)
339 #else
340 # define CHECK(w)
341 #endif
342
343 /************************************************************************
344 **
345 ** Static funcitons
346 **
347 */
348
349 static void call_callbacks(XlwScrollBarWidget w, int reason, int value, int pixel,
350 XEvent *event)
351 {
352 XlwScrollBarCallbackStruct cbs;
353 Boolean called_anything;
354
355 cbs.reason = reason;
356 cbs.event = event;
357 cbs.value = value;
358 cbs.pixel = pixel;
359
360 called_anything = False;
361
362 switch( reason )
363 {
364 case XmCR_VALUE_CHANGED:
365 XtCallCallbackList( (Widget)w, w->sb.valueChangedCBL, &cbs );
366 called_anything = True;
367 break;
368 case XmCR_INCREMENT:
369 if( w->sb.incrementCBL )
370 {
371 XtCallCallbackList( (Widget)w, w->sb.incrementCBL, &cbs );
372 called_anything = True;
373 }
374 break;
375 case XmCR_DECREMENT:
376 if( w->sb.decrementCBL )
377 {
378 XtCallCallbackList( (Widget)w, w->sb.decrementCBL, &cbs );
379 called_anything = True;
380 }
381 break;
382 case XmCR_PAGE_INCREMENT:
383 if( w->sb.incrementCBL )
384 {
385 XtCallCallbackList( (Widget)w, w->sb.pageIncrementCBL, &cbs );
386 called_anything = True;
387 }
388 break;
389 case XmCR_PAGE_DECREMENT:
390 if( w->sb.decrementCBL )
391 {
392 XtCallCallbackList( (Widget)w, w->sb.pageDecrementCBL, &cbs );
393 called_anything = True;
394 }
395 break;
396 case XmCR_TO_TOP:
397 if( w->sb.toTopCBL )
398 {
399 XtCallCallbackList( (Widget)w, w->sb.toTopCBL, &cbs );
400 called_anything = True;
401 }
402 break;
403 case XmCR_TO_BOTTOM:
404 if( w->sb.toBottomCBL )
405 {
406 XtCallCallbackList( (Widget)w, w->sb.toBottomCBL, &cbs );
407 called_anything = True;
408 }
409 break;
410 case XmCR_DRAG:
411 if( w->sb.dragCBL )
412 {
413 XtCallCallbackList( (Widget)w, w->sb.dragCBL, &cbs );
414 }
415 called_anything = True; /* Special Case */
416 break;
417 }
418
419 if( !called_anything )
420 {
421 cbs.reason = XmCR_VALUE_CHANGED;
422 XtCallCallbackList( (Widget)w, w->sb.valueChangedCBL, &cbs );
423 }
424 }
425
426 /*
427 ** Widget sizes minus the shadow and highlight area
428 **
429 */
430 static int widget_x(XlwScrollBarWidget w)
431 {
432 return( w->sb.shadowThickness );
433 }
434
435 static int widget_y(XlwScrollBarWidget w)
436 {
437 return( w->sb.shadowThickness );
438 }
439
440 static int widget_w(XlwScrollBarWidget w)
441 {
442 int width, x = w->sb.shadowThickness;
443
444 width = VERT(w) ? w->core.width : w->core.height;
445
446 if( width <= (2 * x) )
447 return( 1 );
448 else
449 return( width - (2 * x) );
450 }
451
452 static int widget_h(XlwScrollBarWidget w)
453 {
454 int height, y = w->sb.shadowThickness;
455
456 height = VERT(w) ? w->core.height : w->core.width;
457
458 if( height <= (2 * y) )
459 return( 1 );
460 else
461 return( height - (2 * y) );
462 }
463
464 static int arrow_h(XlwScrollBarWidget w)
465 {
466 int width, height;
467
468 width = widget_w(w);
469 height= widget_h(w);
470
471 if( width > ((height / 2) - (SS_MIN / 2) - 1) )
472 {
473 return( ((height / 2) - (SS_MIN / 2) - 1) );
474 }
475 else
476 {
477 return( width );
478 }
479 }
480
481 static int event_x(XlwScrollBarWidget w, XEvent *event)
482 {
483 return( VERT(w) ? event->xbutton.x : event->xbutton.y );
484 }
485
486 static int event_y(XlwScrollBarWidget w, XEvent *event)
487 {
488 return( VERT(w) ? event->xbutton.y : event->xbutton.x );
489 }
490
491 /*
492 ** Safe addition and subtraction
493 */
494 static int safe_add(int a, int b)
495 {
496 if( a > 0 && INT_MAX - a < b ) return( INT_MAX );
497 else return( a + b );
498 }
499
500 static int safe_subtract(int a, int b)
501 {
502 if( a < 0 && -(INT_MIN - a) < b ) return( INT_MIN );
503 else return( a - b );
504 }
505
506 static int knob_style(XlwScrollBarWidget w)
507 {
508 if( w->sb.knobStyle )
509 {
510 if( w->sb.knobStyle[0] == 'd' )
511 {
512 return( KNOB_DIMPLE );
513 }
514 }
515 return( KNOB_PLAIN );
516 }
517
518 static Boolean arrow_same_end(XlwScrollBarWidget w)
519 {
520 if( w->sb.arrowPosition && w->sb.arrowPosition[0] == 's' )
521 {
522 return( True );
523 }
524 return( False );
525 }
526
527 /*
528 ** GC and Pixel allocation
529 */
530 static GC get_gc(XlwScrollBarWidget w, Pixel fg, Pixel bg, Pixmap pm)
531 {
532 XGCValues values;
533 XtGCMask mask;
534
535 if (pm == w->sb.grayPixmap) {
536 /* If we're using the gray pixmap, guarantee white on black ...
537 * otherwise, we could end up with something odd like grey on white
538 * when we're on a color display that ran out of color cells
539 */
540
541 fg = WhitePixelOfScreen(DefaultScreenOfDisplay(XtDisplay(w)));
542 bg = BlackPixelOfScreen(DefaultScreenOfDisplay(XtDisplay(w)));
543 }
544
545 values.foreground = fg;
546 values.background = bg;
547 values.fill_style = FillOpaqueStippled;
548 values.stipple = pm;
549 mask = GCForeground | GCBackground |
550 ( pm == None ? 0 : GCStipple | GCFillStyle );
551 return( XtGetGC((Widget)w, mask, &values) );
552 }
553
554 /* Replacement for XAllocColor() that tries to return the nearest
555 available color if the colormap is full. From FSF Emacs. */
556
557 static int
558 allocate_nearest_color (Display *display, Colormap screen_colormap,
559 XColor *color_def)
560 {
561 int status;
562
563 status = XAllocColor (display, screen_colormap, color_def);
564 if (!status)
565 {
566 /* If we got to this point, the colormap is full, so we're
567 going to try and get the next closest color.
568 The algorithm used is a least-squares matching, which is
569 what X uses for closest color matching with StaticColor visuals. */
570
571 XColor *cells;
572 int no_cells;
573 int nearest;
574 long nearest_delta, trial_delta;
575 int x;
576
577 no_cells = XDisplayCells (display, XDefaultScreen (display));
578 /* Don't use alloca here because lwlib doesn't have the
579 necessary configuration information that src does. */
580 cells = (XColor *) malloc (sizeof (XColor) * no_cells);
581
582 for (x = 0; x < no_cells; x++)
583 cells[x].pixel = x;
584
585 XQueryColors (display, screen_colormap, cells, no_cells);
586 nearest = 0;
587 /* I'm assuming CSE so I'm not going to condense this. */
588 nearest_delta = ((((color_def->red >> 8) - (cells[0].red >> 8))
589 * ((color_def->red >> 8) - (cells[0].red >> 8)))
590 +
591 (((color_def->green >> 8) - (cells[0].green >> 8))
592 * ((color_def->green >> 8) - (cells[0].green >> 8)))
593 +
594 (((color_def->blue >> 8) - (cells[0].blue >> 8))
595 * ((color_def->blue >> 8) - (cells[0].blue >> 8))));
596 for (x = 1; x < no_cells; x++)
597 {
598 trial_delta = ((((color_def->red >> 8) - (cells[x].red >> 8))
599 * ((color_def->red >> 8) - (cells[x].red >> 8)))
600 +
601 (((color_def->green >> 8) - (cells[x].green >> 8))
602 * ((color_def->green >> 8) - (cells[x].green >> 8)))
603 +
604 (((color_def->blue >> 8) - (cells[x].blue >> 8))
605 * ((color_def->blue >> 8) - (cells[x].blue >> 8))));
606 if (trial_delta < nearest_delta)
607 {
608 nearest = x;
609 nearest_delta = trial_delta;
610 }
611 }
612 color_def->red = cells[nearest].red;
613 color_def->green = cells[nearest].green;
614 color_def->blue = cells[nearest].blue;
615 status = XAllocColor (display, screen_colormap, color_def);
616
617 free (cells);
618 }
619
620 return status;
621 }
622
623 static void make_shadow_pixels(XlwScrollBarWidget w)
624 {
625 Display *dpy = XtDisplay((Widget) w);
626 Colormap cmap = w->core.colormap;
627 XColor topc, botc;
628 int top_frobbed, bottom_frobbed;
629 Pixel bg, fg;
630
631 top_frobbed = bottom_frobbed = 0;
632
633 bg = w->core.background_pixel;
634 fg = w->sb.foreground;
635
636 if( w->sb.topShadowColor == (Pixel)~0) w->sb.topShadowColor = bg;
637 if( w->sb.bottomShadowColor == (Pixel)~0) w->sb.bottomShadowColor = fg;
638
639 if( w->sb.topShadowColor == bg || w->sb.topShadowColor == fg )
640 {
641 topc.pixel = bg;
642 XQueryColor( dpy, cmap, &topc );
643 /* don't overflow/wrap! */
644 topc.red = MINL(65535, topc.red * 1.2);
645 topc.green = MINL(65535, topc.green * 1.2);
646 topc.blue = MINL(65535, topc.blue * 1.2);
647 if( allocate_nearest_color(dpy, cmap, &topc) )
648 {
649 if( topc.pixel == bg )
650 {
651 XFreeColors( dpy, cmap, &topc.pixel, 1, 0);
652 topc.red = MINL(65535, topc.red + 0x8000);
653 topc.green = MINL(65535, topc.green + 0x8000);
654 topc.blue = MINL(65535, topc.blue + 0x8000);
655 if( allocate_nearest_color(dpy, cmap, &topc) )
656 {
657 w->sb.topShadowColor = topc.pixel;
658 }
659 }
660 else
661 {
662 w->sb.topShadowColor = topc.pixel;
663 }
664
665 top_frobbed = 1;
666 }
667 }
668
669 if( w->sb.bottomShadowColor == fg || w->sb.bottomShadowColor == bg )
670 {
671 botc.pixel = bg;
672 XQueryColor( dpy, cmap, &botc );
673 botc.red *= 0.6;
674 botc.green *= 0.6;
675 botc.blue *= 0.6;
676 if( allocate_nearest_color(dpy, cmap, &botc) )
677 {
678 if( botc.pixel == bg )
679 {
680 XFreeColors( dpy, cmap, &botc.pixel, 1, 0);
681 botc.red = MINL(65535, botc.red + 0x4000);
682 botc.green = MINL(65535, botc.green + 0x4000);
683 botc.blue = MINL(65535, botc.blue + 0x4000);
684 if( allocate_nearest_color(dpy, cmap, &botc) )
685 {
686 w->sb.bottomShadowColor = botc.pixel;
687 }
688 }
689 else
690 {
691 w->sb.bottomShadowColor = botc.pixel;
692 }
693 bottom_frobbed = 1;
694 }
695 }
696
697 if( top_frobbed && bottom_frobbed )
698 {
699 int top_avg = ((topc.red / 3) + (topc.green / 3) + (topc.blue / 3));
700 int bot_avg = ((botc.red / 3) + (botc.green / 3) + (botc.blue / 3));
701 if( bot_avg > top_avg )
702 {
703 Pixel tmp = w->sb.topShadowColor;
704 w->sb.topShadowColor = w->sb.bottomShadowColor;
705 w->sb.bottomShadowColor = tmp;
706 }
707 else if( topc.pixel == botc.pixel )
708 {
709 if( botc.pixel == bg )
710 w->sb.topShadowColor = bg;
711 else
712 w->sb.bottomShadowColor = fg;
713 }
714 }
715
716 if (w->sb.topShadowColor == w->core.background_pixel ||
717 w->sb.bottomShadowColor == w->core.background_pixel) {
718
719 /* Assume we're in mono. This code should be okay even if we're
720 * really in color but just short on color cells -- We want the
721 * following behavior, which has been empirically determined to
722 * work well for all fg/bg combinations in mono: If the trough
723 * and thumb are BOTH black, then use a white top shadow and a
724 * grey bottom shadow, otherwise use a grey top shadow and a
725 * black bottom shadow.
726 */
727
728 Pixel white = WhitePixelOfScreen(DefaultScreenOfDisplay(XtDisplay(w)));
729 Pixel black = BlackPixelOfScreen(DefaultScreenOfDisplay(XtDisplay(w)));
730
731 /* Note: core.background_pixel is the color of the thumb ... */
732
733 if (w->core.background_pixel == black &&
734 w->sb.troughColor == black) {
735
736 w->sb.topShadowColor = white;
737 w->sb.bottomShadowPixmap = w->sb.grayPixmap;
738
739 } else {
740
741 w->sb.topShadowPixmap = w->sb.grayPixmap;
742 w->sb.bottomShadowColor = black;
743 }
744
745 }
746
747
748 }
749
750 static void make_trough_pixel(XlwScrollBarWidget w)
751 {
752 Display *dpy = XtDisplay((Widget) w);
753 Colormap cmap = DefaultColormapOfScreen( XtScreen((Widget)w) );
754 XColor troughC;
755
756 if( w->sb.troughColor == (Pixel)~0) w->sb.troughColor = w->core.background_pixel;
757
758 if( w->sb.troughColor == w->core.background_pixel )
759 {
760 troughC.pixel = w->core.background_pixel;
761 XQueryColor( dpy, cmap, &troughC );
762 troughC.red *= 0.8;
763 troughC.green *= 0.8;
764 troughC.blue *= 0.8;
765 if( allocate_nearest_color(dpy, cmap, &troughC) )
766 {
767 w->sb.troughColor = troughC.pixel;
768 }
769 }
770 }
771
772 /*
773 ** Draw 3d border
774 */
775 static void draw_shadows(Display *dpy, Drawable d,
776 GC shine_gc, GC shadow_gc,
777 int x, int y, int width, int height,
778 int shadowT)
779 {
780 XSegment shine[10], shadow[10];
781 int i;
782
783 if(shadowT > (width / 2)) shadowT = (width / 2);
784 if(shadowT > (height / 2)) shadowT = (height / 2);
785 if(shadowT <= 0) return;
786
787 for(i = 0; i < shadowT; i++)
788 {
789 /* Top segments */
790 shine[i].x1 = x;
791 shine[i].y2 = shine[i].y1 = y + i;
792 shine[i].x2 = x + width - i - 1;
793 /* Left segments */
794 shine[i + shadowT].x2 = shine[i + shadowT].x1 = x + i;
795 shine[i + shadowT].y1 = y + shadowT;
796 shine[i + shadowT].y2 = y + height - i - 1;
797
798 /* Bottom segments */
799 shadow[i].x1 = x + i;
800 shadow[i].y2 = shadow[i].y1 = y + height - i - 1;
801 shadow[i].x2 = x + width - 1 ;
802 /* Right segments */
803 shadow[i + shadowT].x2 = shadow[i + shadowT].x1 = x + width - i - 1;
804 shadow[i + shadowT].y1 = y + i + 1;
805 shadow[i + shadowT].y2 = y + height - 1 ;
806 }
807
808 XDrawSegments( dpy, d, shine_gc, shine, shadowT * 2 );
809 XDrawSegments( dpy, d, shadow_gc, shadow, shadowT * 2 );
810 }
811
812 /*
813 ** Draw 3d arrows, left, up, down, and right
814 */
815 static int make_vert_seg(XSegment *seg, int x1, int y1, int x2, int y2, int shadowT)
816 {
817 int i;
818
819 for(i=0; i<shadowT; i++)
820 {
821 seg[i].x1 = x1;
822 seg[i].y1 = y1 + i;
823 seg[i].x2 = x2;
824 seg[i].y2 = y2 + i;
825 }
826 return( shadowT );
827 }
828
829 static int make_hor_seg(XSegment *seg, int x1, int y1, int x2, int y2, int shadowT)
830 {
831 int i;
832
833 for(i=0; i<shadowT; i++)
834 {
835 seg[i].x1 = x1 + i;
836 seg[i].y1 = y1;
837 seg[i].x2 = x2 + i;
838 seg[i].y2 = y2;
839 }
840 return( shadowT );
841 }
842
843 static void draw_arrow_up(Display *dpy, Drawable win, GC bgGC, GC shineGC, GC shadowGC,
844 int x, int y, int width, int height, int shadowT)
845 {
846 XSegment shine[10], shadow[10];
847 XPoint triangle[3];
848 int mid;
849
850 mid = width / 2;
851
852 if(shadowT > (width / 2)) shadowT = (width / 2);
853 if(shadowT > (height / 2)) shadowT = (height / 2);
854 if(shadowT <= 0) shadowT = 0;
855
856 /* / */
857 make_vert_seg( shine,
858 x, y + height - shadowT - 1,
859 x + mid, y, shadowT );
860 /* _\ */
861 make_vert_seg( shadow,
862 x, y + height - shadowT - 1,
863 x + width - 1, y + height - shadowT - 1, shadowT );
864 make_vert_seg( shadow + shadowT,
865 x + mid, y,
866 x + width - 1, y + height - shadowT - 1, shadowT );
867
868 triangle[0].x = x;
869 triangle[0].y = y + height - 1;
870 triangle[1].x = x + mid;
871 triangle[1].y = y;
872 triangle[2].x = x + width - 1;
873 triangle[2].y = y + height - 1;
874
875 XFillPolygon( dpy, win, bgGC, triangle, 3, Convex, ArcChord );
876
877 XDrawSegments( dpy, win, shadowGC, shadow, shadowT * 2 );
878 XDrawSegments( dpy, win, shineGC, shine, shadowT );
879 }
880
881 static void draw_arrow_left(Display *dpy, Drawable win, GC bgGC, GC shineGC, GC shadowGC,
882 int x, int y, int width, int height, int shadowT)
883 {
884 XSegment shine[10], shadow[10];
885 XPoint triangle[3];
886 int mid;
887
888 mid = width / 2;
889
890 if(shadowT > (width / 2)) shadowT = (width / 2);
891 if(shadowT > (height / 2)) shadowT = (height / 2);
892 if(shadowT <= 0) shadowT = 0;
893
894 /* / */
895 make_hor_seg( shine,
896 x, y + mid,
897 x + width - shadowT - 1, y, shadowT );
898 /* \| */
899 make_hor_seg( shadow,
900 x, y + mid,
901 x + width - shadowT - 1, y + height - 1, shadowT );
902 make_hor_seg( shadow + shadowT,
903 x + width - shadowT - 1, y,
904 x + width - shadowT - 1, y + height - 1, shadowT );
905
906 triangle[0].x = x + width - 1;
907 triangle[0].y = y + height - 1;
908 triangle[1].x = x;
909 triangle[1].y = y + mid;
910 triangle[2].x = x + width - 1;
911 triangle[2].y = y;
912
913 XFillPolygon( dpy, win, bgGC, triangle, 3, Convex, ArcChord );
914
915 XDrawSegments( dpy, win, shadowGC, shadow, shadowT * 2 );
916 XDrawSegments( dpy, win, shineGC, shine, shadowT );
917 }
918
919 static void draw_arrow_down(Display *dpy, Drawable win, GC bgGC, GC shineGC, GC shadowGC,
920 int x, int y, int width, int height, int shadowT)
921 {
922 XSegment shine[10], shadow[10];
923 XPoint triangle[3];
924 int mid;
925
926 mid = width / 2;
927
928 if(shadowT > (width / 2)) shadowT = (width / 2);
929 if(shadowT > (height / 2)) shadowT = (height / 2);
930 if(shadowT <= 0) shadowT = 0;
931
932 /* \- */
933 make_vert_seg( shine,
934 x, y,
935 x + mid, y + height - shadowT - 1, shadowT );
936 make_vert_seg( shine + shadowT,
937 x, y,
938 x + width - 1, y, shadowT );
939 /* / */
940 make_vert_seg( shadow,
941 x + width - 1, y,
942 x + mid, y + height - shadowT - 1, shadowT );
943
944 triangle[0].x = x;
945 triangle[0].y = y;
946 triangle[1].x = x + mid;
947 triangle[1].y = y + height - 1;
948 triangle[2].x = x + width - 1;
949 triangle[2].y = y;
950
951 XFillPolygon( dpy, win, bgGC, triangle, 3, Convex, ArcChord );
952
953 XDrawSegments( dpy, win, shadowGC, shadow, shadowT );
954 XDrawSegments( dpy, win, shineGC, shine, shadowT * 2 );
955 }
956
957 static void draw_arrow_right(Display *dpy, Drawable win, GC bgGC, GC shineGC, GC shadowGC,
958 int x, int y, int width, int height, int shadowT)
959 {
960 XSegment shine[10], shadow[10];
961 XPoint triangle[3];
962 int mid;
963
964 mid = width / 2;
965
966 if(shadowT > (width / 2)) shadowT = (width / 2);
967 if(shadowT > (height / 2)) shadowT = (height / 2);
968 if(shadowT <= 0) shadowT = 0;
969
970 /* |\ */
971 make_hor_seg( shine,
972 x, y,
973 x + width - shadowT - 1, y + mid, shadowT );
974 make_hor_seg( shine + shadowT,
975 x, y,
976 x, y + height -1, shadowT );
977 /* / */
978 make_hor_seg( shadow,
979 x, y + height -1,
980 x + width - shadowT - 1, y + mid, shadowT );
981
982 triangle[0].x = x + 1;
983 triangle[0].y = y + height - 1;
984 triangle[1].x = x + width - 1;
985 triangle[1].y = y + mid;
986 triangle[2].x = x + 1;
987 triangle[2].y = y;
988
989 XFillPolygon( dpy, win, bgGC, triangle, 3, Convex, ArcChord );
990
991 XDrawSegments( dpy, win, shadowGC, shadow, shadowT );
992 XDrawSegments( dpy, win, shineGC, shine, shadowT * 2 );
993 }
994
995 static void draw_dimple(Display *dpy, Drawable win, GC shine, GC shadow,
996 int x, int y, int width, int height)
997 {
998 XDrawArc(dpy, win, shine, x, y, width, height, 46*64, 180*64);
999 XDrawArc(dpy, win, shadow, x, y, width, height, 45*64, -179*64);
1000 }
1001
1002 /*
1003 ** Scrollbar values -> pixels, pixels -> scrollbar values
1004 */
1005
1006 static void seg_pixel_sizes(XlwScrollBarWidget w, int *above_return, int *ss_return,
1007 int *below_return)
1008 {
1009 float total, height, fuz;
1010 int value;
1011 int above, ss, below;
1012
1013 height= widget_h(w);
1014 if( w->sb.showArrows ) height -= (2*arrow_h(w));
1015
1016 value = w->sb.value - w->sb.minimum;
1017
1018 total = w->sb.maximum - w->sb.minimum;
1019 fuz = total / 2;
1020
1021 ss = ((height * w->sb.sliderSize + fuz) / total);
1022 above = ((height * value + fuz) / total);
1023 below = ((height) - (ss + above));
1024
1025 /* Dont' let knob get smaller than SS_MIN */
1026 if( ss < SS_MIN )
1027 {
1028 /* add a percent amount for interger rounding */
1029 float tmp = ((((float)(SS_MIN - ss) * (float)value)) / total) + 0.5;
1030
1031 above -= (int)tmp;
1032 ss = SS_MIN;
1033 below = ((height) - (ss + above));
1034
1035 if( above < 0 )
1036 {
1037 above = 0;
1038 below = height - ss;
1039 }
1040 if( below < 0 )
1041 {
1042 above = height - ss;
1043 below = 0;
1044 }
1045 if( ss > height )
1046 {
1047 above = 0;
1048 ss = height;
1049 below = 0;
1050 }
1051 }
1052
1053 *above_return = above;
1054 *ss_return = ss;
1055 *below_return = below;
1056
1057 CHECK(w);
1058 }
1059
1060 static void verify_values(XlwScrollBarWidget w)
1061 {
1062 int total = w->sb.maximum - w->sb.minimum;
1063
1064 if( w->sb.sliderSize > total )
1065 {
1066 w->sb.sliderSize = total;
1067 }
1068 if( w->sb.pageIncrement > total )
1069 {
1070 w->sb.pageIncrement = total;
1071 }
1072 if( w->sb.increment > total )
1073 {
1074 w->sb.increment = total;
1075 }
1076 if( w->sb.value < w->sb.minimum )
1077 {
1078 w->sb.value = w->sb.minimum;
1079 }
1080 if( w->sb.value > w->sb.maximum - w->sb.sliderSize)
1081 {
1082 w->sb.value = w->sb.maximum - w->sb.sliderSize;
1083 }
1084 }
1085
1086 static int value_from_pixel(XlwScrollBarWidget w, int above)
1087 {
1088 float total, height, fuz;
1089 int value, ss;
1090
1091 height= widget_h(w);
1092 if( w->sb.showArrows ) height -= (2*arrow_h(w));
1093
1094 total = w->sb.maximum - w->sb.minimum;
1095 fuz = height / 2;
1096
1097 ss = ((height * w->sb.sliderSize + (total / 2)) / total);
1098
1099 if( ss < SS_MIN )
1100 {
1101 /* add a percent amount for interger rounding */
1102 above += ((((SS_MIN - ss) * above) + fuz) / height);
1103 }
1104
1105 {
1106 /* Prevent SIGFPE's that would occur if we don't truncate the
1107 value. */
1108 float floatval = w->sb.minimum + ((float)(above * total + fuz ) / height);
1109 if (floatval >= (float) INT_MAX)
1110 value = INT_MAX;
1111 else if (floatval <= (float) INT_MIN)
1112 value = INT_MIN;
1113 else
1114 value = floatval;
1115 }
1116
1117 return( value );
1118 }
1119
1120
1121 static void redraw_dimple(XlwScrollBarWidget w, Display *dpy, Window win,
1122 int x, int y, int width, int height)
1123 {
1124 GC shine, shadow;
1125 int shadowT, size;
1126
1127 if( KNOB_DIMPLE == knob_style(w) )
1128 {
1129 if( w->sb.armed == ARM_KNOB )
1130 {
1131 shine = w->sb.bottomShadowGC;
1132 shadow = w->sb.topShadowGC;
1133 }
1134 else
1135 {
1136 shine = w->sb.topShadowGC;
1137 shadow = w->sb.bottomShadowGC;
1138 }
1139
1140 shadowT = w->sb.shadowThickness;
1141
1142 x += shadowT;
1143 y += shadowT;
1144 width -= 2*shadowT;
1145 height -= 2*shadowT;
1146
1147 size = (width < height ? width : height) * 3 / 4;
1148
1149 if( size%2 != (width < height ? width : height)%2 ) size--;
1150
1151 DBUG (fprintf(stderr, "%d %d\n",
1152 x + (width / 2) - (size / 2) - 2*shadowT,
1153 width - size - shadowT));
1154
1155 draw_dimple( dpy, win, shine, shadow,
1156 x + (width / 2) - (size / 2),
1157 y + (height / 2) - (size / 2),
1158 size, size );
1159 }
1160 }
1161
1162 static void draw_knob(XlwScrollBarWidget w, int above, int ss, int below)
1163 {
1164 Display *dpy = XtDisplay((Widget)w);
1165 Window win = XtWindow((Widget)w);
1166 int x, y, width, height;
1167 int shadowT;
1168
1169 x = widget_x(w);
1170 y = widget_y(w);
1171 width = widget_w(w);
1172 height = widget_h(w);
1173
1174 shadowT = w->sb.shadowThickness;
1175
1176 if(shadowT > (width / 2)) shadowT = (width / 2);
1177 if(shadowT > (height / 2)) shadowT = (height / 2);
1178 if(shadowT <= 0) return;
1179
1180 if( w->sb.showArrows && !arrow_same_end(w) ) y += (arrow_h(w));
1181
1182 /* trough above knob */
1183 if( above > 0 )
1184 {
1185 if( VERT(w) )
1186 XClearArea( dpy, win, x, y, width, above, False );
1187 else
1188 XClearArea( dpy, win, y, x, above, width, False );
1189 }
1190
1191 /* knob */
1192 if( VERT(w) )
1193 {
1194 draw_shadows( dpy, win, w->sb.topShadowGC, w->sb.bottomShadowGC,
1195 x, y + above, width, ss, shadowT);
1196 XFillRectangle( dpy, win,
1197 w->sb.backgroundGC,
1198 x+shadowT, y + above + shadowT, width-2*shadowT, ss-2*shadowT );
1199 redraw_dimple(w, dpy, win, x, y + above, width, ss);
1200 }
1201 else
1202 {
1203 draw_shadows( dpy, win, w->sb.topShadowGC, w->sb.bottomShadowGC,
1204 y + above, x, ss, width, shadowT);
1205 XFillRectangle( dpy, win,
1206 w->sb.backgroundGC,
1207 y + above + shadowT, x+shadowT, ss-2*shadowT, width-2*shadowT );
1208 redraw_dimple(w, dpy, win, y + above, x, ss, width);
1209 }
1210
1211 /* trough below knob */
1212 if( below > 0 )
1213 {
1214 if( VERT(w) )
1215 XClearArea( dpy, win, x, y + above + ss, width, below, False );
1216 else
1217 XClearArea( dpy, win, y + above + ss, x, below, width, False );
1218 }
1219
1220 CHECK(w);
1221 }
1222
1223 static void redraw_up_arrow(XlwScrollBarWidget w, Boolean armed, Boolean clear_behind)
1224 {
1225 Display *dpy = XtDisplay((Widget)w);
1226 Window win = XtWindow((Widget)w);
1227 GC bg, shine, shadow;
1228 int x, y, width, height, arrow_height, shadowT;
1229
1230 x = widget_x(w);
1231 y = widget_y(w);
1232 width = widget_w(w);
1233 height = widget_h(w);
1234 arrow_height = arrow_h(w);
1235
1236 shadowT = w->sb.shadowThickness;
1237 bg = w->sb.backgroundGC;
1238
1239 if( armed )
1240 {
1241 shine = w->sb.bottomShadowGC;
1242 shadow = w->sb.topShadowGC;
1243 }
1244 else
1245 {
1246 shine = w->sb.topShadowGC;
1247 shadow = w->sb.bottomShadowGC;
1248 }
1249
1250 if( VERT(w) )
1251 {
1252 if( arrow_same_end(w) )
1253 {
1254 y += height - 2*arrow_h(w) + 2;
1255 }
1256 if( clear_behind )
1257 XClearArea( dpy, win, x, y, width, arrow_height + 1, False );
1258 draw_arrow_up( dpy, win, bg, shine, shadow,
1259 x + (width - arrow_height)/2, y,
1260 arrow_height, arrow_height, shadowT );
1261 }
1262 else
1263 {
1264 if( arrow_same_end(w) )
1265 {
1266 y += height - 2*arrow_h(w);
1267 }
1268 if( clear_behind )
1269 XClearArea( dpy, win, y, x, arrow_height + 1, height, False );
1270 draw_arrow_left( dpy, win, bg, shine, shadow,
1271 y, x + (width - arrow_height)/2,
1272 arrow_height, arrow_height, shadowT );
1273 }
1274 }
1275
1276 static void redraw_down_arrow(XlwScrollBarWidget w, Boolean armed, Boolean clear_behind)
1277 {
1278 Display *dpy = XtDisplay((Widget)w);
1279 Window win = XtWindow((Widget)w);
1280 GC bg, shine, shadow;
1281 int x, y, width, height, arrow_height, shadowT;
1282
1283 x = widget_x(w);
1284 y = widget_y(w);
1285 width = widget_w(w);
1286 height = widget_h(w);
1287 arrow_height = arrow_h(w);
1288
1289 shadowT = w->sb.shadowThickness;
1290 bg = w->sb.backgroundGC;
1291
1292 if( armed )
1293 {
1294 shine = w->sb.bottomShadowGC;
1295 shadow = w->sb.topShadowGC;
1296 }
1297 else
1298 {
1299 shine = w->sb.topShadowGC;
1300 shadow = w->sb.bottomShadowGC;
1301 }
1302
1303 if( VERT(w) )
1304 {
1305 if( clear_behind )
1306 XClearArea( dpy, win, x, y + height - arrow_height, width, arrow_height + 1, False );
1307 draw_arrow_down( dpy, win, bg, shine, shadow,
1308 x + (width - arrow_height)/2, y + height - arrow_height + 1,
1309 arrow_height, arrow_height, shadowT );
1310 }
1311 else
1312 {
1313 if( clear_behind )
1314 XClearArea( dpy, win, y + height - arrow_height, x, arrow_height + 1, height, False );
1315 draw_arrow_right( dpy, win, bg, shine, shadow,
1316 y + height - arrow_height + 1, x + (width - arrow_height)/2,
1317 arrow_height, arrow_height, shadowT );
1318 }
1319 }
1320
1321 static void redraw_everything(XlwScrollBarWidget w, Region region, Boolean behind_arrows)
1322 {
1323 Display *dpy = XtDisplay((Widget)w);
1324 Window win = XtWindow((Widget)w);
1325 int x, y, width, height, shadowT, tmp;
1326
1327 x = widget_x(w);
1328 y = widget_y(w);
1329 width = widget_w(w);
1330 height = widget_h(w);
1331 shadowT = w->sb.shadowThickness;
1332
1333 if( w->sb.showArrows )
1334 {
1335 if( region == NULL || XRectInRegion( region, x, y, width, width ) )
1336 {
1337 redraw_up_arrow( w, False, behind_arrows );
1338 }
1339 if( VERT(w) )
1340 {
1341 y = y + height - width + 1;
1342 }
1343 else
1344 {
1345 tmp = y;
1346 y = x;
1347 x = tmp + height - width + 1;
1348 }
1349 if( region == NULL || XRectInRegion( region, x, y, width, width ) )
1350 {
1351 redraw_down_arrow( w, False, behind_arrows );
1352 }
1353 }
1354
1355 draw_shadows( dpy, win, w->sb.bottomShadowGC, w->sb.topShadowGC,
1356 0, 0, w->core.width, w->core.height, shadowT);
1357
1358 draw_knob( w, w->sb.above, w->sb.ss, w->sb.below );
1359
1360 }
1361
1362 /************************************************************************
1363 **
1364 ** Method funcitons
1365 **
1366 */
1367
1368 /*
1369 ** Initialize
1370 */
1371 static void Initialize(Widget treq, Widget tnew, ArgList args, Cardinal *num_args)
1372 {
1373 XlwScrollBarWidget request = (XlwScrollBarWidget) treq;
1374 XlwScrollBarWidget w = (XlwScrollBarWidget) tnew;
1375 Display *dpy = XtDisplay((Widget)w);
1376 Window win = RootWindowOfScreen( DefaultScreenOfDisplay(dpy) );
1377
1378 DBUG(fprintf(stderr, "Initialize\n"));
1379
1380 if( request->core.width == 0 ) w->core.width += (VERT(w) ? 12 : 25);
1381 if( request->core.height == 0 ) w->core.height += (VERT(w) ? 25 : 12);
1382
1383 verify_values(w);
1384
1385 w->sb.lastY = 0;
1386 w->sb.above = 0;
1387 w->sb.ss = 0;
1388 w->sb.below = 0;
1389 w->sb.armed = ARM_NONE;
1390
1391 if( w->sb.shadowThickness > 5 ) w->sb.shadowThickness = 5;
1392
1393 w->sb.grayPixmap =
1394 XCreatePixmapFromBitmapData( dpy, win, (char *) gray_bits, gray_width,
1395 gray_height, 1, 0, 1);
1396
1397 make_trough_pixel( w );
1398
1399 make_shadow_pixels( w );
1400
1401 w->sb.backgroundGC = get_gc(w, w->core.background_pixel, w->core.background_pixel, None);
1402 w->sb.topShadowGC = get_gc(w, w->sb.topShadowColor, w->core.background_pixel, w->sb.topShadowPixmap);
1403 w->sb.bottomShadowGC = get_gc(w, w->sb.bottomShadowColor, w->core.background_pixel, w->sb.bottomShadowPixmap);
1404
1405 w->sb.fullRedrawNext = True;
1406 }
1407
1408 /*
1409 ** Destroy
1410 */
1411 static void Destroy(Widget widget)
1412 {
1413 XlwScrollBarWidget w = (XlwScrollBarWidget) widget;
1414 Display *dpy = XtDisplay((Widget)w);
1415
1416 DBUG(fprintf(stderr, "Destroy\n"));
1417
1418 XtReleaseGC(widget, w->sb.bottomShadowGC);
1419 XtReleaseGC(widget, w->sb.topShadowGC);
1420 XtReleaseGC(widget, w->sb.backgroundGC);
1421
1422 XFreePixmap( dpy, w->sb.grayPixmap );
1423 }
1424
1425 /*
1426 ** Realize
1427 */
1428 static void Realize(Widget widget, XtValueMask *valuemask, XSetWindowAttributes *attr)
1429 {
1430 XlwScrollBarWidget w = (XlwScrollBarWidget) widget;
1431 Display *dpy = XtDisplay((Widget)w);
1432 Window win;
1433 XSetWindowAttributes win_attr;
1434
1435 DBUG(fprintf(stderr, "Realize\n"));
1436
1437 (*coreClassRec.core_class.realize)(widget, valuemask, attr);
1438
1439 win = XtWindow((Widget)w);
1440
1441 seg_pixel_sizes(w, &w->sb.above, &w->sb.ss, &w->sb.below);
1442
1443 XSetWindowBackground( dpy, win, w->sb.troughColor);
1444
1445 /* Change bit gravity so widget is not cleared on resize */
1446 win_attr.bit_gravity = NorthWestGravity;
1447 XChangeWindowAttributes( dpy, win, CWBitGravity , &win_attr);
1448
1449 }
1450
1451 /*
1452 ** Resize
1453 */
1454 static void Resize(Widget widget)
1455 {
1456 XlwScrollBarWidget w = (XlwScrollBarWidget) widget;
1457 Display *dpy = XtDisplay((Widget)w);
1458 Window win = XtWindow((Widget)w);
1459
1460 if( XtIsRealized(widget) )
1461 {
1462 DBUG(fprintf(stderr, "Resize = %08lx\n", w));
1463
1464 seg_pixel_sizes(w, &w->sb.above, &w->sb.ss, &w->sb.below);
1465
1466 /*redraw_everything(w, NULL, True);*/
1467
1468 w->sb.fullRedrawNext = True;
1469 /* Force expose event */
1470 XClearArea(dpy, win, widget_x(w), widget_y(w), 1, 1, True);
1471 }
1472 }
1473
1474 /*
1475 ** Redisplay
1476 */
1477 static void Redisplay(Widget widget, XEvent *event, Region region)
1478 {
1479 XlwScrollBarWidget w = (XlwScrollBarWidget) widget;
1480
1481 DBUG(fprintf(stderr, "Redisplay = %08lx\n", w));
1482
1483 if( XtIsRealized(widget) )
1484 {
1485 if( w->sb.fullRedrawNext )
1486 {
1487 redraw_everything(w, NULL, True);
1488 }
1489 else
1490 {
1491 redraw_everything(w, region, False);
1492 }
1493 w->sb.fullRedrawNext = False;
1494 }
1495 }
1496
1497 /*
1498 ** SetValues
1499 */
1500 static Boolean SetValues(Widget current, Widget request, Widget neww, ArgList args, Cardinal *num_args)
1501 {
1502 XlwScrollBarWidget cur = (XlwScrollBarWidget) current;
1503 XlwScrollBarWidget w = (XlwScrollBarWidget) neww;
1504 Boolean do_redisplay = False;
1505
1506 if( cur->sb.troughColor != w->sb.troughColor )
1507 {
1508 if( XtIsRealized((Widget)w) )
1509 {
1510 XSetWindowBackground( XtDisplay((Widget)w), XtWindow((Widget)w),
1511 w->sb.troughColor);
1512 do_redisplay = True;
1513 }
1514 }
1515
1516 if( cur->core.background_pixel != w->core.background_pixel )
1517 {
1518 XtReleaseGC((Widget)cur, cur->sb.backgroundGC);
1519 w->sb.backgroundGC = get_gc(w, w->core.background_pixel, w->core.background_pixel, None);
1520 do_redisplay = True;
1521 }
1522
1523 if( cur->sb.topShadowColor != w->sb.topShadowColor ||
1524 cur->sb.topShadowPixmap != w->sb.topShadowPixmap )
1525 {
1526 XtReleaseGC((Widget)cur, cur->sb.topShadowGC);
1527 w->sb.topShadowGC = get_gc(w, w->sb.topShadowColor, w->core.background_pixel, w->sb.topShadowPixmap);
1528 do_redisplay = True;
1529 }
1530
1531 if( cur->sb.bottomShadowColor != w->sb.bottomShadowColor ||
1532 cur->sb.bottomShadowPixmap != w->sb.bottomShadowPixmap )
1533 {
1534 XtReleaseGC((Widget)cur, cur->sb.bottomShadowGC);
1535 w->sb.bottomShadowGC = get_gc(w, w->sb.bottomShadowColor, w->core.background_pixel, w->sb.bottomShadowPixmap);
1536 do_redisplay = True;
1537 }
1538
1539 if( cur->sb.orientation != w->sb.orientation )
1540 {
1541 do_redisplay = True;
1542 }
1543
1544
1545 if( cur->sb.minimum != w->sb.minimum ||
1546 cur->sb.maximum != w->sb.maximum ||
1547 cur->sb.sliderSize != w->sb.sliderSize ||
1548 cur->sb.value != w->sb.value ||
1549 cur->sb.pageIncrement != w->sb.pageIncrement ||
1550 cur->sb.increment != w->sb.increment )
1551 {
1552 verify_values(w);
1553 if( XtIsRealized((Widget)w) )
1554 {
1555 seg_pixel_sizes(w, &w->sb.above, &w->sb.ss, &w->sb.below);
1556 draw_knob( w, w->sb.above, w->sb.ss, w->sb.below );
1557 }
1558 }
1559
1560 if( w->sb.shadowThickness > 5 ) w->sb.shadowThickness = 5;
1561
1562 return( do_redisplay );
1563 }
1564
1565 void XlwScrollBarGetValues(Widget widget, int *value, int *sliderSize,
1566 int *increment, int *pageIncrement)
1567 {
1568 XlwScrollBarWidget w = (XlwScrollBarWidget)widget;
1569
1570 if( w && XtClass((Widget)w) == xlwScrollBarWidgetClass )
1571 {
1572 if( value ) *value = w->sb.value;
1573 if( sliderSize ) *sliderSize = w->sb.sliderSize;
1574 if( increment ) *increment = w->sb.increment;
1575 if( pageIncrement ) *pageIncrement = w->sb.pageIncrement;
1576 }
1577 }
1578
1579 void XlwScrollBarSetValues(Widget widget, int value, int sliderSize,
1580 int increment, int pageIncrement, Boolean notify)
1581 {
1582 XlwScrollBarWidget w = (XlwScrollBarWidget)widget;
1583 int last_value;
1584
1585 if( w && XtClass((Widget)w) == xlwScrollBarWidgetClass &&
1586 (w->sb.value != value ||
1587 w->sb.sliderSize != sliderSize ||
1588 w->sb.increment != increment ||
1589 w->sb.pageIncrement != pageIncrement ))
1590 {
1591 w->sb.value = value;
1592 w->sb.sliderSize = sliderSize;
1593 w->sb.increment = increment;
1594 w->sb.pageIncrement = pageIncrement;
1595
1596 verify_values(w);
1597
1598 if( XtIsRealized(widget) )
1599 {
1600 seg_pixel_sizes(w, &w->sb.above, &w->sb.ss, &w->sb.below);
1601 draw_knob(w, w->sb.above, w->sb.ss, w->sb.below);
1602
1603 last_value = w->sb.value;
1604 w->sb.value = value_from_pixel(w, w->sb.above);
1605 verify_values(w);
1606
1607 if( w->sb.value != last_value && notify )
1608 {
1609 call_callbacks( w, XmCR_VALUE_CHANGED, w->sb.value, 0, NULL );
1610 }
1611 }
1612 }
1613 }
1614
1615 /************************************************************************
1616 **
1617 ** Action funcitons
1618 **
1619 */
1620
1621 static void timer(XtPointer data, XtIntervalId *id)
1622 {
1623 XlwScrollBarWidget w = (XlwScrollBarWidget)data;
1624 int reason, last_value;
1625
1626 if( w->sb.armed != ARM_NONE )
1627 {
1628 last_value = w->sb.value;
1629 reason = XmCR_NONE;
1630
1631 switch( w->sb.armed )
1632 {
1633 case ARM_PAGEUP:
1634 w->sb.value = safe_subtract( w->sb.value, w->sb.pageIncrement );
1635 reason = XmCR_PAGE_DECREMENT;
1636 break;
1637 case ARM_PAGEDOWN:
1638 w->sb.value = safe_add( w->sb.value, w->sb.pageIncrement );
1639 reason = XmCR_PAGE_INCREMENT;
1640 break;
1641 case ARM_UP:
1642 w->sb.value = safe_subtract( w->sb.value, w->sb.increment );
1643 reason = XmCR_DECREMENT;
1644 break;
1645 case ARM_DOWN:
1646 w->sb.value = safe_add( w->sb.value, w->sb.increment );
1647 reason = XmCR_INCREMENT;
1648 break;
1649 }
1650
1651 verify_values(w);
1652
1653 if( last_value != w->sb.value )
1654 {
1655 seg_pixel_sizes(w, &w->sb.above, &w->sb.ss, &w->sb.below);
1656 draw_knob(w, w->sb.above, w->sb.ss, w->sb.below);
1657
1658 call_callbacks( w, reason, w->sb.value, 0, NULL );
1659
1660 XtAppAddTimeOut( XtWidgetToApplicationContext((Widget)w),
1661 (unsigned long) w->sb.repeatDelay,
1662 timer, (XtPointer) w );
1663 }
1664 }
1665 }
1666
1667 static int what_button(XlwScrollBarWidget w, int mouse_x, int mouse_y)
1668 {
1669 int x, y, width, height, arrow_height_top, arrow_height_bottom;
1670 int where;
1671
1672 x = widget_x(w);
1673 y = widget_y(w);
1674 width = widget_w(w);
1675 height = widget_h(w);
1676
1677 #if 0
1678 arrow_height = w->sb.showArrows ? arrow_h(w) : 0;
1679 #endif
1680 if( w->sb.showArrows )
1681 {
1682 if( arrow_same_end(w) )
1683 {
1684 arrow_height_top = 0;
1685 arrow_height_bottom = 2*arrow_h(w);
1686 }
1687 else
1688 {
1689 arrow_height_top = arrow_height_bottom = arrow_h(w);
1690 }
1691 }
1692 else
1693 {
1694 arrow_height_top = arrow_height_bottom = 0;
1695 }
1696
1697 where = BUTTON_NONE;
1698
1699 if( mouse_x > x && mouse_x < (x + width) )
1700 {
1701 if( mouse_y > (y + arrow_height_top) && mouse_y < (y + height - arrow_height_bottom) )
1702 {
1703 if( mouse_y < (y + w->sb.above + arrow_height_top) )
1704 {
1705 where = BUTTON_TROUGH_ABOVE;
1706 }
1707 else if( mouse_y > (y + w->sb.above + w->sb.ss + arrow_height_top) )
1708 {
1709 where = BUTTON_TROUGH_BELOW;
1710 }
1711 else
1712 {
1713 where = BUTTON_KNOB;
1714 }
1715 }
1716 else if( arrow_same_end(w) )
1717 {
1718 if( mouse_y > (y + height - arrow_height_bottom + 1) && mouse_y < (y + height) )
1719 {
1720 if( mouse_y < (y + height - arrow_height_bottom/2) )
1721 {
1722 where = BUTTON_UP_ARROW;
1723 }
1724 else
1725 {
1726 where = BUTTON_DOWN_ARROW;
1727 }
1728 }
1729 }
1730 else
1731 {
1732 if( mouse_y > y && mouse_y < (y + arrow_height_top) )
1733 {
1734 where = BUTTON_UP_ARROW;
1735 }
1736 else if( mouse_y > (y + height - arrow_height_bottom + 1) && mouse_y < (y + height) )
1737 {
1738 where = BUTTON_DOWN_ARROW;
1739 }
1740 }
1741 }
1742 #if 0
1743 if( mouse_x > x && mouse_x < (x + width) )
1744 {
1745 if( mouse_y > (y + arrow_height) && mouse_y < (y + height - arrow_height) )
1746 {
1747 if( mouse_y < (y+w->sb.above+arrow_height) )
1748 {
1749 where = BUTTON_TROUGH_ABOVE;
1750 }
1751 else if( mouse_y > (y + w->sb.above + w->sb.ss + arrow_height) )
1752 {
1753 where = BUTTON_TROUGH_BELOW;
1754 }
1755 else
1756 {
1757 where = BUTTON_KNOB;
1758 }
1759 }
1760 else if( mouse_y > y && mouse_y < (y + arrow_height) )
1761 {
1762 where = BUTTON_UP_ARROW;
1763 }
1764 else if( mouse_y > (y + height - arrow_height + 1) && mouse_y < (y + height) )
1765 {
1766 where = BUTTON_DOWN_ARROW;
1767 }
1768 }
1769 #endif
1770 return( where );
1771 }
1772
1773 #define FORCED_SCROLL_NONE 0
1774 #define FORCED_SCROLL_DOWNRIGHT 1
1775 #define FORCED_SCROLL_UPLEFT 2
1776
1777 int forced_scroll_flag = FORCED_SCROLL_NONE;
1778
1779 /*
1780 ** PageDownOrRight
1781 */
1782 static void PageDownOrRight(Widget widget, XEvent *event, String *parms, Cardinal *num_parms)
1783 {
1784 forced_scroll_flag = FORCED_SCROLL_DOWNRIGHT;
1785 Select(widget, event, parms, num_parms);
1786 forced_scroll_flag = FORCED_SCROLL_NONE;
1787 }
1788
1789 /*
1790 ** PageUpOrLeft
1791 */
1792 static void PageUpOrLeft(Widget widget, XEvent *event, String *parms, Cardinal *num_parms)
1793 {
1794 forced_scroll_flag = FORCED_SCROLL_UPLEFT;
1795 Select(widget, event, parms, num_parms);
1796 forced_scroll_flag = FORCED_SCROLL_NONE;
1797 }
1798
1799 /*
1800 ** Select
1801 */
1802 static void Select(Widget widget, XEvent *event, String *parms, Cardinal *num_parms)
1803 {
1804 XlwScrollBarWidget w = (XlwScrollBarWidget)widget;
1805 int mouse_x, mouse_y;
1806 int reason, last_value;
1807 int sb_button;
1808
1809 DBUG(fprintf(stderr, "Select:\n"));
1810
1811 mouse_x = event_x( w, event );
1812 mouse_y = event_y( w, event );
1813
1814 w->sb.savedValue = w->sb.value;
1815
1816 last_value = w->sb.value;
1817 reason = XmCR_NONE;
1818
1819 XtGrabKeyboard( (Widget)w, False, GrabModeAsync, GrabModeAsync, event->xbutton.time );
1820
1821 sb_button = what_button(w, mouse_x, mouse_y);
1822
1823 if ( forced_scroll_flag != FORCED_SCROLL_NONE )
1824 {
1825 switch ( sb_button )
1826 {
1827 case BUTTON_TROUGH_ABOVE:
1828 case BUTTON_TROUGH_BELOW:
1829 case BUTTON_KNOB:
1830 sb_button= BUTTON_NONE; /* cause next switch to fall through */
1831 if ( forced_scroll_flag == FORCED_SCROLL_UPLEFT )
1832 {
1833 w->sb.value = safe_subtract( w->sb.value, w->sb.pageIncrement );
1834 w->sb.armed = ARM_PAGEUP;
1835 reason = XmCR_PAGE_DECREMENT;
1836 break;
1837 }
1838 else if ( forced_scroll_flag == FORCED_SCROLL_DOWNRIGHT )
1839 {
1840 w->sb.value = safe_add( w->sb.value, w->sb.pageIncrement );
1841 w->sb.armed = ARM_PAGEDOWN;
1842 reason = XmCR_PAGE_INCREMENT;
1843 break;
1844 }
1845 abort();
1846 }
1847 }
1848
1849 switch( sb_button )
1850 {
1851 case BUTTON_TROUGH_ABOVE:
1852 w->sb.value = safe_subtract( w->sb.value, w->sb.pageIncrement );
1853 w->sb.armed = ARM_PAGEUP;
1854 reason = XmCR_PAGE_DECREMENT;
1855 break;
1856 case BUTTON_TROUGH_BELOW:
1857 w->sb.value = safe_add( w->sb.value, w->sb.pageIncrement );
1858 w->sb.armed = ARM_PAGEDOWN;
1859 reason = XmCR_PAGE_INCREMENT;
1860 break;
1861 case BUTTON_KNOB:
1862 w->sb.lastY = mouse_y;
1863 w->sb.armed = ARM_KNOB;
1864 draw_knob(w, w->sb.above, w->sb.ss, w->sb.below);
1865 break;
1866 case BUTTON_UP_ARROW:
1867 if( event->xbutton.state & ControlMask )
1868 {
1869 w->sb.value = INT_MIN;
1870 w->sb.armed = ARM_UP;
1871 reason = XmCR_TO_TOP;
1872 }
1873 else
1874 {
1875 w->sb.value = safe_subtract( w->sb.value, w->sb.increment );
1876 w->sb.armed = ARM_UP;
1877 reason = XmCR_DECREMENT;
1878 }
1879 redraw_up_arrow(w, True, False);
1880 break;
1881 case BUTTON_DOWN_ARROW:
1882 if( event->xbutton.state & ControlMask )
1883 {
1884 w->sb.value = INT_MAX;
1885 w->sb.armed = ARM_DOWN;
1886 reason = XmCR_TO_BOTTOM;
1887 }
1888 else
1889 {
1890 w->sb.value = safe_add( w->sb.value, w->sb.increment );
1891 w->sb.armed = ARM_DOWN;
1892 reason = XmCR_INCREMENT;
1893 }
1894 redraw_down_arrow(w, True, False);
1895 break;
1896 }
1897
1898 verify_values(w);
1899
1900 if( last_value != w->sb.value )
1901 {
1902 seg_pixel_sizes(w, &w->sb.above, &w->sb.ss, &w->sb.below);
1903 draw_knob(w, w->sb.above, w->sb.ss, w->sb.below);
1904
1905 call_callbacks( w, reason, w->sb.value, mouse_y, event );
1906
1907 XtAppAddTimeOut( XtWidgetToApplicationContext((Widget)w),
1908 (unsigned long) w->sb.initialDelay,
1909 timer, (XtPointer) w );
1910 }
1911
1912 CHECK(w);
1913 }
1914
1915 /*
1916 ** Drag
1917 */
1918 static void Drag(Widget widget, XEvent *event, String *parms, Cardinal *num_parms)
1919 {
1920 XlwScrollBarWidget w = (XlwScrollBarWidget)widget;
1921 int diff;
1922 int height, mouse_y;
1923 int last_value, last_above;
1924
1925 DBUG(fprintf(stderr, "Drag:\n"));
1926
1927 if( w->sb.armed == ARM_KNOB )
1928 {
1929 height = widget_h(w);
1930 if( w->sb.showArrows ) height -= (2*arrow_h(w));
1931
1932 mouse_y = event_y( w, event );
1933
1934 diff = mouse_y - w->sb.lastY;
1935
1936 last_above = w->sb.above;
1937 last_value = w->sb.value;
1938
1939 if( diff < 0 )
1940 {
1941 /* up */
1942 w->sb.above -= (-diff);
1943 if( w->sb.above < 0 )
1944 {
1945 mouse_y = (mouse_y - w->sb.above);
1946 w->sb.above = 0;
1947 diff = 0;
1948 w->sb.below = height - w->sb.ss;
1949 }
1950 w->sb.below -= diff;
1951 CHECK(w);
1952 }
1953 else if( diff > 0 )
1954 {
1955 /* down */
1956 w->sb.above += diff;
1957 if( w->sb.above + w->sb.ss > height )
1958 {
1959 mouse_y = height + (mouse_y - (w->sb.above + w->sb.ss));
1960 w->sb.above = height - w->sb.ss;
1961 diff = 0;
1962 w->sb.below = 0;
1963 }
1964 w->sb.below -= diff;
1965 CHECK(w);
1966 }
1967
1968 if( last_above != w->sb.above )
1969 {
1970 draw_knob(w, w->sb.above, w->sb.ss, w->sb.below);
1971
1972 w->sb.lastY = mouse_y;
1973
1974 w->sb.value = value_from_pixel(w, w->sb.above);
1975 verify_values(w);
1976 CHECK(w);
1977
1978 if( w->sb.value != last_value )
1979 {
1980 call_callbacks( w, XmCR_DRAG, w->sb.value, event_y(w, event), event );
1981 }
1982 }
1983 }
1984 CHECK(w);
1985 }
1986
1987 /*
1988 ** Release
1989 */
1990 static void Release(Widget widget, XEvent *event, String *parms, Cardinal *num_parms)
1991 {
1992 XlwScrollBarWidget w = (XlwScrollBarWidget)widget;
1993
1994 DBUG(fprintf(stderr, "EndDrag:\n"));
1995
1996 switch( w->sb.armed )
1997 {
1998 case ARM_KNOB:
1999 call_callbacks( w, XmCR_VALUE_CHANGED, w->sb.value, event_y(w, event), event );
2000 w->sb.armed = ARM_NONE;
2001 draw_knob(w, w->sb.above, w->sb.ss, w->sb.below);
2002 break;
2003 case ARM_UP:
2004 redraw_up_arrow(w, False, False);
2005 break;
2006 case ARM_DOWN:
2007 redraw_down_arrow(w, False, False);
2008 break;
2009 }
2010
2011 XtUngrabKeyboard( (Widget)w, event->xbutton.time );
2012
2013 w->sb.armed = ARM_NONE;
2014 }
2015
2016 /*
2017 ** Jump
2018 */
2019 static void Jump(Widget widget, XEvent *event, String *parms, Cardinal *num_parms)
2020 {
2021 XlwScrollBarWidget w = (XlwScrollBarWidget)widget;
2022 int x, y, width, height, mouse_x, mouse_y;
2023 int arrow_height;
2024 int last_above, last_value;
2025
2026 DBUG(fprintf(stderr, "Jump:\n"));
2027
2028 x = widget_x(w);
2029 y = widget_y(w);
2030 width = widget_w(w);
2031 height = widget_h(w);
2032 mouse_x = event_x( w, event );
2033 mouse_y = event_y( w, event );
2034
2035 arrow_height = w->sb.showArrows ? arrow_h(w) : 0;
2036
2037 XtGrabKeyboard( (Widget)w, False, GrabModeAsync, GrabModeAsync, event->xbutton.time );
2038
2039 switch( what_button(w, mouse_x, mouse_y) )
2040 {
2041 case BUTTON_TROUGH_ABOVE:
2042 case BUTTON_TROUGH_BELOW:
2043 case BUTTON_KNOB:
2044 w->sb.savedValue = w->sb.value;
2045
2046 height -= (2*arrow_height);
2047 y += arrow_height;
2048
2049 last_above = w->sb.above;
2050 last_value = w->sb.value;
2051
2052 w->sb.armed = ARM_KNOB;
2053 draw_knob(w, w->sb.above, w->sb.ss, w->sb.below);
2054
2055 w->sb.above = mouse_y - (w->sb.ss / 2) - arrow_height;
2056 if( w->sb.above < 0 )
2057 {
2058 w->sb.above = 0;
2059 }
2060 else if( w->sb.above + w->sb.ss > height )
2061 {
2062 w->sb.above = height - w->sb.ss;
2063 }
2064 w->sb.below = (height - (w->sb.ss + w->sb.above));
2065
2066 if( last_above != w->sb.above )
2067 {
2068 draw_knob(w, w->sb.above, w->sb.ss, w->sb.below);
2069
2070 w->sb.value = value_from_pixel(w, w->sb.above);
2071 verify_values(w);
2072 CHECK(w);
2073
2074 w->sb.lastY = mouse_y;
2075 w->sb.lastY = w->sb.above + arrow_height + (w->sb.ss / 2);
2076
2077 if( w->sb.value != last_value )
2078 {
2079 call_callbacks( w, XmCR_DRAG, w->sb.value, event_y(w, event), event );
2080 }
2081 }
2082 break;
2083 }
2084 CHECK(w);
2085 }
2086
2087 /*
2088 ** Abort
2089 */
2090 static void Abort(Widget widget, XEvent *event, String *parms, Cardinal *num_parms)
2091 {
2092 XlwScrollBarWidget w = (XlwScrollBarWidget)widget;
2093
2094 DBUG(fprintf(stderr, "Abort:\n"));
2095
2096 if( w->sb.armed != ARM_NONE )
2097 {
2098 if( w->sb.value != w->sb.savedValue )
2099 {
2100 w->sb.value = w->sb.savedValue;
2101
2102 seg_pixel_sizes(w, &w->sb.above, &w->sb.ss, &w->sb.below);
2103 draw_knob(w, w->sb.above, w->sb.ss, w->sb.below);
2104
2105 call_callbacks( w, XmCR_VALUE_CHANGED, w->sb.value, event_y(w, event), event );
2106 }
2107
2108 switch( w->sb.armed )
2109 {
2110 case ARM_UP:
2111 redraw_up_arrow(w, False, False);
2112 break;
2113 case ARM_DOWN:
2114 redraw_down_arrow(w, False, False);
2115 break;
2116 }
2117
2118 w->sb.armed = ARM_NONE;
2119
2120 XtUngrabKeyboard( (Widget)w, event->xbutton.time );
2121 }
2122 }