changed indentation to use spaces only
[wmaker-crm.git] / WINGs / wballoon.c
blobf6547796649bd974d081302a06a1fa19bf59f50c
4 #include "../src/config.h"
5 #include "WINGsP.h"
7 #ifdef SHAPE
8 #include <X11/extensions/shape.h>
9 #endif
12 typedef struct W_Balloon {
13 W_View *view;
15 WMHashTable *table; /* Table from view ptr to text */
17 WMColor *backColor;
18 WMColor *textColor;
19 WMFont *font;
21 WMHandlerID timer; /* timer for showing balloon */
23 WMHandlerID noDelayTimer;
25 int delay;
27 Window forWindow; /* window for which the balloon
28 * is being show in the moment */
30 struct {
31 WMAlignment alignment:2;
32 unsigned enabled:1;
34 unsigned noDelay:1;
35 } flags;
36 } Balloon;
40 #define DEFAULT_WIDTH 60
41 #define DEFAULT_HEIGHT 14
42 #define DEFAULT_ALIGNMENT WALeft
43 #define DEFAULT_DELAY 500
45 #define NO_DELAY_DELAY 150
48 static void destroyBalloon(Balloon *bPtr);
51 static void handleEvents(XEvent *event, void *data);
53 static void showText(Balloon *bPtr, int x, int y, int w, int h, char *text);
56 struct W_Balloon*
57 W_CreateBalloon(WMScreen *scr)
59 Balloon *bPtr;
61 bPtr = wmalloc(sizeof(Balloon));
62 memset(bPtr, 0, sizeof(Balloon));
64 bPtr->view = W_CreateUnmanagedTopView(scr);
65 if (!bPtr->view) {
66 wfree(bPtr);
67 return NULL;
69 bPtr->view->self = bPtr;
71 bPtr->textColor = WMRetainColor(bPtr->view->screen->black);
73 WMCreateEventHandler(bPtr->view, StructureNotifyMask, handleEvents, bPtr);
75 W_ResizeView(bPtr->view, DEFAULT_WIDTH, DEFAULT_HEIGHT);
76 bPtr->flags.alignment = DEFAULT_ALIGNMENT;
78 bPtr->table = WMCreateHashTable(WMIntHashCallbacks);
80 bPtr->delay = DEFAULT_DELAY;
82 bPtr->flags.enabled = 1;
84 return bPtr;
89 void
90 WMSetBalloonTextAlignment(WMScreen *scr, WMAlignment alignment)
92 scr->balloon->flags.alignment = alignment;
97 void
98 WMSetBalloonTextForView(char *text, WMView *view)
100 char *oldText = NULL;
101 WMScreen *scr = view->screen;
103 if (text) {
104 oldText = WMHashInsert(scr->balloon->table, view, wstrdup(text));
105 } else {
106 oldText = WMHashGet(scr->balloon->table, view);
108 WMHashRemove(scr->balloon->table, view);
111 if (oldText) {
112 wfree(oldText);
117 void
118 WMSetBalloonFont(WMScreen *scr, WMFont *font)
120 Balloon *bPtr = scr->balloon;
122 if (bPtr->font!=NULL)
123 WMReleaseFont(bPtr->font);
125 if (font)
126 bPtr->font = WMRetainFont(font);
127 else
128 bPtr->font = NULL;
132 void
133 WMSetBalloonTextColor(WMScreen *scr, WMColor *color)
135 Balloon *bPtr = scr->balloon;
137 if (bPtr->textColor)
138 WMReleaseColor(bPtr->textColor);
140 bPtr->textColor = WMRetainColor(color);
144 void
145 WMSetBalloonDelay(WMScreen *scr, int delay)
147 scr->balloon->delay = delay;
151 void
152 WMSetBalloonEnabled(WMScreen *scr, Bool flag)
154 scr->balloon->flags.enabled = ((flag==0) ? 0 : 1);
156 W_UnmapView(scr->balloon->view);
160 static void
161 clearNoDelay(void *data)
163 Balloon *bPtr = (Balloon*)data;
165 bPtr->flags.noDelay = 0;
166 bPtr->noDelayTimer = NULL;
170 void
171 W_BalloonHandleLeaveView(WMView *view)
173 Balloon *bPtr = view->screen->balloon;
175 if (bPtr->forWindow == view->window) {
176 if (bPtr->view->flags.mapped) {
177 W_UnmapView(bPtr->view);
178 bPtr->noDelayTimer = WMAddTimerHandler(NO_DELAY_DELAY,
179 clearNoDelay, bPtr);
181 if (bPtr->timer)
182 WMDeleteTimerHandler(bPtr->timer);
184 bPtr->timer = NULL;
186 bPtr->forWindow = None;
192 * botar balao perto do cursor
193 * so mapear balao se o mouse ficar parado pelo delay
197 static void
198 showBalloon(void *data)
200 char *text;
201 WMView *view = (WMView*)data;
202 Balloon *bPtr = view->screen->balloon;
203 int x, y;
204 Window foo;
206 bPtr->timer = NULL;
208 text = WMHashGet(bPtr->table, view);
209 if (!text)
210 return;
212 XTranslateCoordinates(view->screen->display, view->window,
213 view->screen->rootWin, 0, 0, &x, &y, &foo);
215 if (!bPtr->view->flags.realized)
216 W_RealizeView(bPtr->view);
218 showText(bPtr, x, y, view->size.width, view->size.height, text);
220 bPtr->flags.noDelay = 1;
225 void
226 W_BalloonHandleEnterView(WMView *view)
228 Balloon *bPtr = view->screen->balloon;
229 char *text;
231 if (!bPtr->flags.enabled)
232 return;
234 text = WMHashGet(bPtr->table, view);
235 if (!text) {
236 if (bPtr->view->flags.realized)
237 W_UnmapView(bPtr->view);
239 return;
242 if (bPtr->timer)
243 WMDeleteTimerHandler(bPtr->timer);
244 bPtr->timer = NULL;
246 if (bPtr->noDelayTimer)
247 WMDeleteTimerHandler(bPtr->noDelayTimer);
248 bPtr->noDelayTimer = NULL;
250 bPtr->forWindow = view->window;
252 if (bPtr->flags.noDelay) {
253 bPtr->timer = NULL;
255 showBalloon(view);
256 } else {
257 bPtr->timer = WMAddTimerHandler(bPtr->delay, showBalloon, view);
262 #define TOP 0
263 #define BOTTOM 1
264 #define LEFT 0
265 #define RIGHT 2
267 #define TLEFT (TOP|LEFT)
268 #define TRIGHT (TOP|RIGHT)
269 #define BLEFT (BOTTOM|LEFT)
270 #define BRIGHT (BOTTOM|RIGHT)
274 #define SPACE 12
277 static void
278 drawBalloon(WMScreen *scr, Pixmap bitmap, Pixmap pix, int x, int y, int w,
279 int h, int side)
281 Display *dpy = scr->display;
282 WMColor *white = WMWhiteColor(scr);
283 WMColor *black = WMBlackColor(scr);
284 GC bgc = scr->monoGC;
285 GC gc = WMColorGC(white);
286 int rad = h*3/10;
287 XPoint pt[3], ipt[3];
288 int w1;
290 /* outline */
291 XSetForeground(dpy, bgc, 1);
293 XFillArc(dpy, bitmap, bgc, x, y, rad, rad, 90*64, 90*64);
294 XFillArc(dpy, bitmap, bgc, x, y+h-1-rad, rad, rad, 180*64, 90*64);
296 XFillArc(dpy, bitmap, bgc, x+w-1-rad, y, rad, rad, 0*64, 90*64);
297 XFillArc(dpy, bitmap, bgc, x+w-1-rad, y+h-1-rad, rad, rad, 270*64, 90*64);
299 XFillRectangle(dpy, bitmap, bgc, x, y+rad/2, w, h-rad);
300 XFillRectangle(dpy, bitmap, bgc, x+rad/2, y, w-rad, h);
302 /* interior */
303 XFillArc(dpy, pix, gc, x+1, y+1, rad, rad, 90*64, 90*64);
304 XFillArc(dpy, pix, gc, x+1, y+h-2-rad, rad, rad, 180*64, 90*64);
306 XFillArc(dpy, pix, gc, x+w-2-rad, y+1, rad, rad, 0*64, 90*64);
307 XFillArc(dpy, pix, gc, x+w-2-rad, y+h-2-rad, rad, rad, 270*64, 90*64);
309 XFillRectangle(dpy, pix, gc, x+1, y+1+rad/2, w-2, h-2-rad);
310 XFillRectangle(dpy, pix, gc, x+1+rad/2, y+1, w-2-rad, h-2);
312 if (side & BOTTOM) {
313 pt[0].y = y+h-1;
314 pt[1].y = y+h-1+SPACE;
315 pt[2].y = y+h-1;
316 ipt[0].y = pt[0].y-1;
317 ipt[1].y = pt[1].y-1;
318 ipt[2].y = pt[2].y-1;
319 } else {
320 pt[0].y = y;
321 pt[1].y = y-SPACE;
322 pt[2].y = y;
323 ipt[0].y = pt[0].y+1;
324 ipt[1].y = pt[1].y+1;
325 ipt[2].y = pt[2].y+1;
328 /*w1 = WMAX(h, 24);*/
329 w1 = WMAX(h, 21);
331 if (side & RIGHT) {
332 pt[0].x = x+w-w1+2*w1/16;
333 pt[1].x = x+w-w1+11*w1/16;
334 pt[2].x = x+w-w1+7*w1/16;
335 ipt[0].x = x+1+w-w1+2*(w1-1)/16;
336 ipt[1].x = x+1+w-w1+11*(w1-1)/16;
337 ipt[2].x = x+1+w-w1+7*(w1-1)/16;
338 /*ipt[0].x = pt[0].x+1;
339 ipt[1].x = pt[1].x;
340 ipt[2].x = pt[2].x;*/
341 } else {
342 pt[0].x = x+w1-2*w1/16;
343 pt[1].x = x+w1-11*w1/16;
344 pt[2].x = x+w1-7*w1/16;
345 ipt[0].x = x-1+w1-2*(w1-1)/16;
346 ipt[1].x = x-1+w1-11*(w1-1)/16;
347 ipt[2].x = x-1+w1-7*(w1-1)/16;
348 /*ipt[0].x = pt[0].x-1;
349 ipt[1].x = pt[1].x;
350 ipt[2].x = pt[2].x;*/
353 XFillPolygon(dpy, bitmap, bgc, pt, 3, Convex, CoordModeOrigin);
354 XFillPolygon(dpy, pix, gc, ipt, 3, Convex, CoordModeOrigin);
356 /* fix outline */
357 XDrawLines(dpy, pix, WMColorGC(black), pt, 3, CoordModeOrigin);
358 if (side & RIGHT) {
359 pt[0].x++;
360 pt[2].x--;
361 } else {
362 pt[0].x--;
363 pt[2].x++;
365 XDrawLines(dpy, pix, WMColorGC(black), pt, 3, CoordModeOrigin);
367 WMReleaseColor(white);
368 WMReleaseColor(black);
372 static Pixmap
373 makePixmap(WMScreen *scr, int width, int height, int side, Pixmap *mask)
375 Display *dpy = WMScreenDisplay(scr);
376 Pixmap bitmap;
377 Pixmap pixmap;
378 int x, y;
379 WMColor *black = WMBlackColor(scr);
381 bitmap = XCreatePixmap(dpy, scr->rootWin, width+SPACE, height+SPACE, 1);
383 XSetForeground(dpy, scr->monoGC, 0);
384 XFillRectangle(dpy, bitmap, scr->monoGC, 0, 0, width+SPACE, height+SPACE);
386 pixmap = XCreatePixmap(dpy, scr->rootWin, width+SPACE, height+SPACE,
387 scr->depth);
389 XFillRectangle(dpy, pixmap, WMColorGC(black), 0, 0, width+SPACE,
390 height+SPACE);
392 if (side & BOTTOM) {
393 y = 0;
394 } else {
395 y = SPACE;
397 x = 0;
399 drawBalloon(scr, bitmap, pixmap, x, y, width, height, side);
401 *mask = bitmap;
403 WMReleaseColor(black);
405 return pixmap;
409 static void
410 showText(Balloon *bPtr, int x, int y, int w, int h, char *text)
412 WMScreen *scr = bPtr->view->screen;
413 Display *dpy = WMScreenDisplay(scr);
414 int width;
415 int height;
416 Pixmap pixmap;
417 Pixmap mask;
418 WMFont *font = bPtr->font ? bPtr->font : scr->normalFont;
419 int textHeight;
420 int side = 0;
421 int ty;
422 int bx, by;
425 int w;
426 char *ptr, *ptr2;
428 ptr2 = ptr = text;
429 width = 0;
430 while (ptr && ptr2) {
431 ptr2 = strchr(ptr, '\n');
432 if (ptr2) {
433 w = WMWidthOfString(font, ptr, ptr2 - ptr);
434 } else {
435 w = WMWidthOfString(font, ptr, strlen(ptr));
437 if (w > width)
438 width = w;
439 ptr = ptr2 + 1;
443 width += 16;
445 textHeight = W_GetTextHeight(font, text, width, False);
447 height = textHeight + 4;
449 if (height < 16)
450 height = 16;
451 if (width < height)
452 width = height;
454 if (x + width > scr->rootView->size.width) {
455 side = RIGHT;
456 bx = x - width + w/2;
457 if (bx < 0)
458 bx = 0;
459 } else {
460 side = LEFT;
461 bx = x + w/2;
463 if (bx + width > scr->rootView->size.width)
464 bx = scr->rootView->size.width - width;
466 if (y - (height + SPACE) < 0) {
467 side |= TOP;
468 by = y+h-1;
469 ty = SPACE;
470 } else {
471 side |= BOTTOM;
472 by = y - (height + SPACE);
473 ty = 0;
475 pixmap = makePixmap(scr, width, height, side, &mask);
477 W_PaintText(bPtr->view, pixmap, font, 8, ty + (height - textHeight)/2,
478 width, bPtr->flags.alignment,
479 bPtr->textColor ? bPtr->textColor : scr->black,
480 False, text, strlen(text));
482 XSetWindowBackgroundPixmap(dpy, bPtr->view->window, pixmap);
484 W_ResizeView(bPtr->view, width, height+SPACE);
486 XFreePixmap(dpy, pixmap);
488 #ifdef SHAPE
489 XShapeCombineMask(dpy, bPtr->view->window, ShapeBounding, 0, 0, mask,
490 ShapeSet);
491 #endif
492 XFreePixmap(dpy, mask);
494 W_MoveView(bPtr->view, bx, by);
496 W_MapView(bPtr->view);
500 static void
501 handleEvents(XEvent *event, void *data)
503 Balloon *bPtr = (Balloon*)data;
505 switch (event->type) {
506 case DestroyNotify:
507 destroyBalloon(bPtr);
508 break;
513 static void
514 destroyBalloon(Balloon *bPtr)
516 WMHashEnumerator e;
517 char *str;
519 e = WMEnumerateHashTable(bPtr->table);
521 while ((str = WMNextHashEnumeratorItem(&e))) {
522 wfree(str);
524 WMFreeHashTable(bPtr->table);
526 if (bPtr->textColor)
527 WMReleaseColor(bPtr->textColor);
529 if (bPtr->font)
530 WMReleaseFont(bPtr->font);
532 wfree(bPtr);