libdockapp: Fix for missing windowname and one more.
[dockapps.git] / libdockapp / examples / rectangles / rectangles.c
blobb37ec3766317e0b9d64f27cf953767a307b12383
1 /*
2 * Copyright (c) 2002 Alban G. Hertroys
4 * libDockapp example - Usage of action rectangles
6 * Some clickable and draggable areas for you to play
7 * with.
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 */
26 * Type definitions
29 /* I like to keep my graphic contexts (GCs) together */
30 struct Colors {
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 */
34 GC darkGray;
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 */
44 * Global variables
46 Pixmap pixmap; /* pixmap pixmap */
47 DARect *buttonDown = NULL;
48 struct Colors *colors; /* our colors */
49 DAActionRect **actionRects;
50 float sliderPos = 0.7;
51 int mouseIn = 0;
52 Cursor pointer;
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 */
75 void destroy(void);
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);
100 * M A I N
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 */
114 NULL /* timeout */
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 */
160 DAParseArguments(
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 "
164 "use libDockapp.\n",
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 */
174 DAInitialize(
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). */
212 createBtn(btn);
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 */
221 DASetPixmap(pixmap);
223 /* Process events every 100ms */
224 DASetTimeout(100);
226 /* set event callbacks */
227 DASetCallbacks(&eventCallbacks);
229 /* Display the pixmap we said it to show */
230 DAShow();
232 /* Process events and keep the dockapp running */
233 DAEventLoop();
235 return 0;
239 /* Create our GC's to draw colored lines and such */
240 struct Colors *
241 setGCs(Drawable d)
243 struct Colors *colors;
244 XGCValues gcv;
245 unsigned long origColor;
246 char dashList[2] = {3, 1};
248 colors = malloc(sizeof(struct Colors));
249 if (colors == NULL)
250 return NULL;
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 */
267 #if 1
268 gcv.foreground = DAGetColor("navy");
269 #else
270 gcv.foreground = 0;
271 #endif
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;
287 gcv.line_width = 9;
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);
305 /* dark slider GC */
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);
314 return colors;
318 /* Make a (GC) color lighter or darker */
319 unsigned long
320 adjustColor(unsigned long color, signed int adjustment)
322 signed long r, g, b;
324 r = color >> 16;
325 g = (color - (r << 16)) >> 8;
326 b = (color - (g << 8) - (r << 16));
328 r += adjustment;
329 g += adjustment;
330 b += adjustment;
332 if (r > 0xff)
333 r = 0xff;
335 if (g > 0xff)
336 g = 0xff;
338 if (b > 0xff)
339 b = 0xff;
341 if (r < 0)
342 r = 0;
344 if (g < 0)
345 g = 0;
347 if (b < 0)
348 b = 0;
350 return ((unsigned short)r << 16) +
351 ((unsigned short)g << 8) +
352 (unsigned short)b;
356 void
357 setPointerColor(GC color)
359 XGCValues gcv;
360 XColor fcolor, bcolor;
362 XGetGCValues(DADisplay, color, GCForeground, &gcv);
364 fcolor.pixel = gcv.foreground;
365 fcolor.flags = DoRed | DoGreen | DoBlue;
367 bcolor.red = 0;
368 bcolor.green = 0;
369 bcolor.blue = 0;
371 XRecolorCursor(DADisplay, pointer, &fcolor, &bcolor);
375 /* event handlers functions */
376 void destroy(void)
380 void buttonPress(int button, int state, int x, int y)
382 int *data = malloc(sizeof(int *));
384 *data = button;
386 DAProcessActionRects(x, y, actionRects[0], 3, (void *)data);
388 free(data);
391 void buttonRelease(int button, int state, int x, int y)
393 DAProcessActionRects(x, y, actionRects[1], 2, NULL);
397 void
398 mouseMove(int x, int y)
400 DAProcessActionRects(x, y, actionRects[2], 1, NULL);
403 void
404 mouseEnter(void)
406 mouseIn = 1;
408 drawSlider(actionRects[3][0].rect);
412 void
413 mouseLeave(void)
415 mouseIn = 0;
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 */
430 void
431 btnDown(int x, int y, DARect rect, void *data)
433 buttonDown = &rect;
434 drawSunkenFrame(rect);
438 void
439 btnUp(int x, int y, DARect rect, void *data)
441 buttonDown = NULL;
442 drawRaisedFrame(rect);
446 void
447 btnLeave(int x, int y, DARect rect, void *data)
449 if (buttonDown == NULL)
450 return;
452 drawRaisedFrame(rect);
456 /* Square that tells which button was pressed (number) */
457 void
458 squareDown(int x, int y, DARect rect, void *data)
460 int button;
462 if (data) {
463 int *tmp = (int *)data;
465 button = *tmp;
466 } else
467 button = 0;
469 drawSquare(rect, button);
473 /* A draggable slider that highlights when the mouse is over it */
474 void
475 sliderDown(int x, int y, DARect rect, void *data)
477 buttonDown = &rect;
478 setPointerColor(colors->sliderDark);
482 void
483 sliderUp(int x, int y, DARect rect, void *data)
485 buttonDown = NULL;
486 setPointerColor(colors->black);
490 void
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 */)
498 return;
500 sliderPos = (float)(rect.height - y) / (float)rect.height;
501 if (sliderPos > 1.0)
502 sliderPos = 1.0;
504 if (sliderPos < 0.0)
505 sliderPos = 0.0;
507 drawSlider(rect);
510 void sliderEnter(int x, int y, DARect rect, void *data)
513 void sliderLeave(int x, int y, DARect rect, void *data)
520 * Drawing functions
522 void
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);
533 void
534 drawRaisedFrame(DARect rect)
536 /* left border */
537 XDrawLine(DADisplay, pixmap, colors->white,
538 rect.x, rect.y, rect.x, rect.y + rect.height - 2);
539 /* top border */
540 XDrawLine(DADisplay, pixmap, colors->white,
541 rect.x + 1, rect.y, rect.width - 1, rect.y);
542 /* bottom border */
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);
546 /* right border */
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);
551 DASetPixmap(pixmap);
555 void
556 drawSunkenFrame(DARect rect)
558 /* left border */
559 XDrawLine(DADisplay, pixmap, colors->darkGray,
560 rect.x, rect.y, rect.x, rect.y + rect.height - 2);
561 /* top border */
562 XDrawLine(DADisplay, pixmap, colors->darkGray,
563 rect.x + 1, rect.y, rect.width - 1, rect.y);
564 /* bottom border */
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);
568 /* right border */
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);
573 DASetPixmap(pixmap);
577 void
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);
587 drawSquare(rect, 0);
591 void
592 drawSquare(DARect rect, int button)
594 char label[3];
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);
603 DASetPixmap(pixmap);
607 void
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);
616 drawSlider(rect);
620 void
621 drawSlider(DARect rect)
623 GC highColor, lowColor; /* determine colors to use */
625 if (mouseIn) {
626 highColor = colors->sliderLight;
627 lowColor = colors->slider;
628 } else {
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));
654 DASetPixmap(pixmap);
658 DAActionRect
659 setRectAction(DARect rect, DARectCallback action)
661 DAActionRect ar;
663 ar.rect = rect;
664 ar.action = action;
666 return ar;