2 * Copyright (c) 2002 Alban G. Hertroys
4 * libDockapp example - Usage of action rectangles
6 * Some clickable and draggable areas for you to play
9 * There's a bit much in here...
12 /* The cursor font - stamdard cursor glyphs. */
13 #include <X11/cursorfont.h>
15 /* Required because we don't use a pixmap for the shape (using a DASetShape
16 * variation). Instead we use the XLib call "XShapeCombineRegion".
17 * Window shapes are an extension (since X11R5).
19 #include <X11/extensions/shape.h>
21 #include <libdockapp/dockapp.h>
23 /* already includes Xlib, Xresources, XPM, stdlib and stdio */
29 /* I like to keep my graphic contexts (GCs) together */
31 GC white
; /* foreground color from X-resource, or default */
32 GC black
; /* background color, idem */
33 GC lightGray
; /* Some GC's we'll have to define for colors */
35 GC slider
; /* draw-color when not highlighted,
36 * dark-color when highlighted
38 GC sliderLight
; /* draw-color when highlighted */
39 GC sliderDark
; /* dark-color when not highlighted */
46 Pixmap pixmap
; /* pixmap pixmap */
47 DARect
*buttonDown
= NULL
;
48 struct Colors
*colors
; /* our colors */
49 DAActionRect
**actionRects
;
50 float sliderPos
= 0.7;
55 * Prototypes for local functions
57 struct Colors
*setGCs(Drawable d
);
58 unsigned long adjustColor(unsigned long color
, signed int adjustment
);
60 /* drawing routines */
61 void createBtn(DARect rect
);
62 void drawRaisedFrame(DARect rect
);
63 void drawSunkenFrame(DARect rect
);
64 void createSquare(DARect rect
);
65 void drawSquare(DARect rect
, int button
);
66 void createSlider(DARect rect
);
67 void drawSlider(DARect rect
);
68 void setPointerColor(GC
);
70 /* utility functions */
71 DAActionRect
setRectAction(DARect rect
, DARectCallback action
);
74 /* event handlers functions */
76 void buttonPress(int button
, int state
, int x
, int y
);
77 void buttonRelease(int button
, int state
, int x
, int y
);
78 void mouseMove(int x
, int y
);
79 void mouseEnter(void);
80 void mouseLeave(void);
82 /* what to do for a specific event for every 'item' in the dockapp */
83 /* Button that can be pressed "down" and jumps back "up" again */
84 void btnDown(int x
, int y
, DARect rect
, void *data
);
85 void btnUp(int x
, int y
, DARect rect
, void *data
);
86 void btnLeave(int x
, int y
, DARect rect
, void *data
);
88 /* Square that tells which button was pressed (number) */
89 void squareDown(int x
, int y
, DARect rect
, void *data
);
91 /* A draggable slider that highlights when the mouse is over it */
92 void sliderDown(int x
, int y
, DARect rect
, void *data
);
93 void sliderUp(int x
, int y
, DARect rect
, void *data
);
94 void sliderMove(int x
, int y
, DARect rect
, void *data
);
95 void sliderEnter(int x
, int y
, DARect rect
, void *data
);
96 void sliderLeave(int x
, int y
, DARect rect
, void *data
);
104 main(int argc
, char **argv
)
106 /* define the event handlers for the events */
107 DACallbacks eventCallbacks
= {
108 destroy
, /* destroy */
109 buttonPress
, /* buttonPress */
110 buttonRelease
, /* buttonRelease */
111 mouseMove
, /* motion (mouse) */
112 mouseEnter
, /* mouse enters window */
113 mouseLeave
, /* mouse leaves window */
117 /* define regions (x, y, width, height) that need event-handling */
118 Region clipRegion
= XCreateRegion();
120 DARect btn
= {0, 0, 16, 16},
121 square
= {0, 25, 22, 22},
122 slider
= {24, 0, 23, 48};
124 /* define what to do if an event occurs in a rectangle */
125 DAActionRect
*buttonPressRects
, *buttonReleaseRects
,
126 *mouseMoveRects
, *mouseEnterRects
, *mouseLeaveRects
;
128 buttonPressRects
= malloc(3 * sizeof(DAActionRect
));
129 buttonPressRects
[0] = setRectAction(btn
, btnDown
);
130 buttonPressRects
[1] = setRectAction(square
, squareDown
);
131 buttonPressRects
[2] = setRectAction(slider
, sliderDown
);
133 buttonReleaseRects
= malloc(2 * sizeof(DAActionRect
));
134 buttonReleaseRects
[0] = setRectAction(btn
, btnUp
);
135 buttonReleaseRects
[1] = setRectAction(slider
, sliderUp
);
137 mouseMoveRects
= malloc(sizeof(DAActionRect
));
138 mouseMoveRects
[0] = setRectAction(slider
, sliderMove
);
140 mouseEnterRects
= malloc(sizeof(DAActionRect
));
141 mouseEnterRects
[0] = setRectAction(slider
, sliderEnter
);
143 mouseLeaveRects
= malloc(2 * sizeof(DAActionRect
));
144 mouseLeaveRects
[0] = setRectAction(btn
, btnLeave
);
145 mouseLeaveRects
[1] = setRectAction(slider
, sliderLeave
);
148 /* XXX: make action rectangles available outside main()
149 * ...libDockapp should be able to do this... (reminder)
151 actionRects
= malloc(6 * sizeof(DAActionRect
*));
152 actionRects
[0] = buttonPressRects
;
153 actionRects
[1] = buttonReleaseRects
;
154 actionRects
[2] = mouseMoveRects
;
155 actionRects
[3] = mouseEnterRects
;
156 actionRects
[4] = mouseLeaveRects
;
157 actionRects
[5] = NULL
;
159 /* provide standard command-line options */
161 argc
, argv
, /* Where the options come from */
162 NULL
, 0, /* Our list with options - none as you can see */
163 "This is the help text for the rectangle example of how to "
165 "Rectangle example version 1.0");
167 /* Tell libdockapp what version we expect it to be, so that you can use
168 * older programs with newer versions of libdockapp with less risc for
169 * compatibility problems.
171 DASetExpectedVersion(20030126);
173 /* Initialize a dockapp */
175 "", /* Use default display */
176 "daRectangleExample", /* WM_CLASS hint; don't use chars in [.?*: ] */
177 48, 48, /* geometry of dockapp internals */
178 argc
, argv
/* (needed internally) */
181 /* Create a pixmap to draw on, and to display */
182 pixmap
= DAMakePixmap(); /* size == dockapp geometry (48,48) */
184 colors
= setGCs(pixmap
);
186 XFillRectangle(DADisplay
, pixmap
, DAClearGC
, 0, 0, 48, 48);
187 XClearWindow(DADisplay
, DAWindow
);
189 /* Make a "Region" from the shapes we have */
190 XUnionRectWithRegion(&btn
, clipRegion
, clipRegion
);
191 XUnionRectWithRegion(&square
, clipRegion
, clipRegion
);
192 XUnionRectWithRegion(&slider
, clipRegion
, clipRegion
);
194 /* Make this region a window shape mask */
195 XShapeCombineRegion(DADisplay
, DAWindow
, ShapeBounding
,
196 0, 0, clipRegion
, ShapeSet
);
198 /* We don't need the region anymore (it is copied by XShapeCombineRegion).
199 * XXX: That's not certain, it is not documented. XSetRegion does so,
200 * though, so it is a likely assumption that it does copy.
202 XDestroyRegion(clipRegion
);
204 /* The cursor we want to use.
205 * Specify 'None' for the default,
206 * or one from X11/cursorfont.h
208 pointer
= XCreateFontCursor(DADisplay
, XC_based_arrow_up
);
209 XDefineCursor(DADisplay
, DAWindow
, pointer
);
211 /* a square with an image that changes when clicked (A button). */
214 /* a square that shows the number of the mouse-button pressed on click. */
215 createSquare(square
);
217 /* a slider a using two dashed line GC's. */
218 createSlider(slider
);
220 /* Tell libdockapp this is the pixmap that we want to show */
223 /* Process events every 100ms */
226 /* set event callbacks */
227 DASetCallbacks(&eventCallbacks
);
229 /* Display the pixmap we said it to show */
232 /* Process events and keep the dockapp running */
239 /* Create our GC's to draw colored lines and such */
243 struct Colors
*colors
;
245 unsigned long origColor
;
246 char dashList
[2] = {3, 1};
248 colors
= malloc(sizeof(struct Colors
));
252 /* Get the GC-values of the default GC */
253 XGetGCValues(DADisplay
, DAGC
,
254 GCForeground
| GCBackground
| GCGraphicsExposures
, &gcv
);
256 origColor
= gcv
.foreground
;
258 /* don't send expose events */
259 gcv
.graphics_exposures
= False
;
261 /* GC for white color */
262 gcv
.foreground
= WhitePixel(DADisplay
, DefaultScreen(DADisplay
));
263 colors
->white
= XCreateGC(DADisplay
, d
,
264 GCForeground
| GCGraphicsExposures
, &gcv
);
266 /* GC for dark blue color */
268 gcv
.foreground
= DAGetColor("navy");
272 colors
->black
= XCreateGC(DADisplay
, d
,
273 GCForeground
| GCGraphicsExposures
, &gcv
);
275 /* GC for light borders */
276 gcv
.foreground
= DAGetColor("lightGray");
277 colors
->lightGray
= XCreateGC(DADisplay
, d
,
278 GCForeground
| GCGraphicsExposures
, &gcv
);
280 /* GC for dark borders (note re-use of gcv-values) */
281 gcv
.foreground
= DAGetColor("#222222");
282 colors
->darkGray
= XCreateGC(DADisplay
, d
,
283 GCForeground
| GCGraphicsExposures
, &gcv
);
285 /* GC for the un-/highlighted colors and dashed line of the slider */
286 gcv
.foreground
= origColor
;
288 gcv
.line_style
= LineOnOffDash
;
290 colors
->slider
= XCreateGC(DADisplay
, d
,
291 GCForeground
| GCBackground
| GCGraphicsExposures
|
292 GCLineWidth
| GCLineStyle
, &gcv
);
294 XSetDashes(DADisplay
, colors
->slider
, 1, dashList
, 2);
296 /* light slider GC */
297 gcv
.foreground
= adjustColor(origColor
, +0x40);
299 colors
->sliderLight
= XCreateGC(DADisplay
, d
,
300 GCForeground
| GCBackground
| GCGraphicsExposures
|
301 GCLineWidth
| GCLineStyle
, &gcv
);
303 XSetDashes(DADisplay
, colors
->sliderLight
, 1, dashList
, 2);
306 gcv
.foreground
= adjustColor(origColor
, -0x40);
308 colors
->sliderDark
= XCreateGC(DADisplay
, d
,
309 GCForeground
| GCBackground
| GCGraphicsExposures
|
310 GCLineWidth
| GCLineStyle
, &gcv
);
312 XSetDashes(DADisplay
, colors
->sliderDark
, 1, dashList
, 2);
318 /* Make a (GC) color lighter or darker */
320 adjustColor(unsigned long color
, signed int adjustment
)
325 g
= (color
- (r
<< 16)) >> 8;
326 b
= (color
- (g
<< 8) - (r
<< 16));
350 return ((unsigned short)r
<< 16) +
351 ((unsigned short)g
<< 8) +
357 setPointerColor(GC color
)
360 XColor fcolor
, bcolor
;
362 XGetGCValues(DADisplay
, color
, GCForeground
, &gcv
);
364 fcolor
.pixel
= gcv
.foreground
;
365 fcolor
.flags
= DoRed
| DoGreen
| DoBlue
;
371 XRecolorCursor(DADisplay
, pointer
, &fcolor
, &bcolor
);
375 /* event handlers functions */
380 void buttonPress(int button
, int state
, int x
, int y
)
382 int *data
= malloc(sizeof(int *));
386 DAProcessActionRects(x
, y
, actionRects
[0], 3, (void *)data
);
391 void buttonRelease(int button
, int state
, int x
, int y
)
393 DAProcessActionRects(x
, y
, actionRects
[1], 2, NULL
);
398 mouseMove(int x
, int y
)
400 DAProcessActionRects(x
, y
, actionRects
[2], 1, NULL
);
408 drawSlider(actionRects
[3][0].rect
);
417 /* mouse pointer left the dockapp window */
418 DAProcessActionRects(0, 0, actionRects
[4], 2, NULL
);
420 /* if the button is still depressed, make it go up again. */
421 /* TODO: Use data in actionRects[4] here instead of below check */
422 if (buttonDown
!= NULL
)
423 btnUp(0, 0, *buttonDown
, NULL
);
425 drawSlider(actionRects
[4][1].rect
);
428 /* what to do for a specific event for every 'item' in the dockapp */
429 /* Button that can be pressed "down" and jumps back "up" again */
431 btnDown(int x
, int y
, DARect rect
, void *data
)
434 drawSunkenFrame(rect
);
439 btnUp(int x
, int y
, DARect rect
, void *data
)
442 drawRaisedFrame(rect
);
447 btnLeave(int x
, int y
, DARect rect
, void *data
)
449 if (buttonDown
== NULL
)
452 drawRaisedFrame(rect
);
456 /* Square that tells which button was pressed (number) */
458 squareDown(int x
, int y
, DARect rect
, void *data
)
463 int *tmp
= (int *)data
;
469 drawSquare(rect
, button
);
473 /* A draggable slider that highlights when the mouse is over it */
475 sliderDown(int x
, int y
, DARect rect
, void *data
)
478 setPointerColor(colors
->sliderDark
);
483 sliderUp(int x
, int y
, DARect rect
, void *data
)
486 setPointerColor(colors
->black
);
491 sliderMove(int x
, int y
, DARect rect
, void *data
)
493 if (buttonDown
== NULL
/* ||
494 rect.x != buttonDown->x ||
495 rect.y != buttonDown->y ||
496 rect.width != buttonDown->width ||
497 rect.height != buttonDown->height */)
500 sliderPos
= (float)(rect
.height
- y
) / (float)rect
.height
;
510 void sliderEnter(int x
, int y
, DARect rect
, void *data
)
513 void sliderLeave(int x
, int y
, DARect rect
, void *data
)
523 createBtn(DARect rect
)
525 /* fill square excluding borders */
526 XFillRectangle(DADisplay
, pixmap
, colors
->lightGray
,
527 rect
.x
+ 1, rect
.y
+ 1, rect
.width
- 2, rect
.height
- 2);
529 drawRaisedFrame(rect
);
534 drawRaisedFrame(DARect rect
)
537 XDrawLine(DADisplay
, pixmap
, colors
->white
,
538 rect
.x
, rect
.y
, rect
.x
, rect
.y
+ rect
.height
- 2);
540 XDrawLine(DADisplay
, pixmap
, colors
->white
,
541 rect
.x
+ 1, rect
.y
, rect
.width
- 1, rect
.y
);
543 XDrawLine(DADisplay
, pixmap
, colors
->darkGray
,
544 rect
.x
, rect
.y
+ rect
.height
- 1,
545 rect
.x
+ rect
.width
- 1, rect
.y
+ rect
.height
- 1);
547 XDrawLine(DADisplay
, pixmap
, colors
->darkGray
,
548 rect
.x
+ rect
.width
- 1, rect
.y
+ 1,
549 rect
.x
+ rect
.width
- 1, rect
.y
+ rect
.height
- 2);
556 drawSunkenFrame(DARect rect
)
559 XDrawLine(DADisplay
, pixmap
, colors
->darkGray
,
560 rect
.x
, rect
.y
, rect
.x
, rect
.y
+ rect
.height
- 2);
562 XDrawLine(DADisplay
, pixmap
, colors
->darkGray
,
563 rect
.x
+ 1, rect
.y
, rect
.width
- 1, rect
.y
);
565 XDrawLine(DADisplay
, pixmap
, colors
->white
,
566 rect
.x
, rect
.y
+ rect
.height
- 1,
567 rect
.x
+ rect
.width
- 1, rect
.y
+ rect
.height
- 1);
569 XDrawLine(DADisplay
, pixmap
, colors
->white
,
570 rect
.x
+ rect
.width
- 1, rect
.y
+ 1,
571 rect
.x
+ rect
.width
- 1, rect
.y
+ rect
.height
- 2);
578 createSquare(DARect rect
)
580 /* fill square excluding borders */
581 XFillRectangle(DADisplay
, pixmap
, colors
->black
,
582 rect
.x
+ 1, rect
.y
+ 1, rect
.width
- 2, rect
.height
- 2);
584 XDrawRectangle(DADisplay
, pixmap
, colors
->lightGray
,
585 rect
.x
, rect
.y
, rect
.width
- 1, rect
.height
- 1);
592 drawSquare(DARect rect
, int button
)
596 XFillRectangle(DADisplay
, pixmap
, colors
->black
,
597 rect
.x
+ 1, rect
.y
+ 1, rect
.width
- 2, rect
.height
- 2);
599 snprintf(label
, 3, "%2d", button
);
600 XDrawString(DADisplay
, pixmap
, colors
->white
,
601 rect
.x
+ 3, rect
.y
+ rect
.height
- 5, label
, 2);
608 createSlider(DARect rect
)
610 /* fill square excluding borders */
611 XFillRectangle(DADisplay
, pixmap
, colors
->black
,
612 rect
.x
+ 1, rect
.y
+ 1, rect
.width
- 2, rect
.height
- 2);
614 drawSunkenFrame(rect
);
621 drawSlider(DARect rect
)
623 GC highColor
, lowColor
; /* determine colors to use */
626 highColor
= colors
->sliderLight
;
627 lowColor
= colors
->slider
;
629 highColor
= colors
->slider
;
630 lowColor
= colors
->sliderDark
;
633 /* Draw two lines from bottom to sliderPos fraction of height */
634 if (sliderPos
< 1.0) {
635 XDrawLine(DADisplay
, pixmap
, highColor
,
636 rect
.x
+ 6, rect
.y
+ rect
.height
- 2,
637 rect
.x
+ 6, rect
.y
+ (1.0 - sliderPos
) * (rect
.height
- 2));
639 XDrawLine(DADisplay
, pixmap
, highColor
,
640 rect
.x
+ 17, rect
.y
+ rect
.height
- 2,
641 rect
.x
+ 17, rect
.y
+ (1.0 - sliderPos
) * (rect
.height
- 2));
644 if (sliderPos
> 0.0) {
645 XDrawLine(DADisplay
, pixmap
, lowColor
,
646 rect
.x
+ 6, rect
.y
+ 1,
647 rect
.x
+ 6, rect
.y
+ (1.0 - sliderPos
) * (rect
.height
- 2));
649 XDrawLine(DADisplay
, pixmap
, lowColor
,
650 rect
.x
+ 17, rect
.y
+ 1,
651 rect
.x
+ 17, rect
.y
+ (1.0 - sliderPos
) * (rect
.height
- 2));
659 setRectAction(DARect rect
, DARectCallback action
)