fixed some compilation warnings.
[wmaker-crm.git] / WINGs / wballoon.c
blob8457bcf3530b4f68c8e8aa3a1b5109ef069a37ab
5 #include "WINGsP.h"
7 #include <X11/extensions/shape.h>
10 typedef struct W_Balloon {
11 W_View *view;
13 WMHashTable *table; /* Table from view ptr to text */
15 WMColor *backColor;
16 WMColor *textColor;
17 WMFont *font;
19 WMHandlerID timer; /* timer for showing balloon */
21 WMHandlerID noDelayTimer;
23 int delay;
25 Window forWindow; /* window for which the balloon
26 * is being show in the moment */
28 struct {
29 WMAlignment alignment:2;
30 unsigned enabled:1;
32 unsigned noDelay:1;
33 } flags;
34 } Balloon;
38 #define DEFAULT_WIDTH 60
39 #define DEFAULT_HEIGHT 14
40 #define DEFAULT_ALIGNMENT WALeft
41 #define DEFAULT_DELAY 500
43 #define NO_DELAY_DELAY 150
46 static void destroyBalloon(Balloon *bPtr);
49 static void handleEvents(XEvent *event, void *data);
51 static void showText(Balloon *bPtr, int x, int y, int w, int h, char *text);
54 struct W_Balloon*
55 W_CreateBalloon(WMScreen *scr)
57 Balloon *bPtr;
59 bPtr = wmalloc(sizeof(Balloon));
60 memset(bPtr, 0, sizeof(Balloon));
62 bPtr->view = W_CreateTopView(scr);
63 if (!bPtr->view) {
64 free(bPtr);
65 return NULL;
67 bPtr->view->self = bPtr;
69 bPtr->view->attribFlags |= CWOverrideRedirect;
70 bPtr->view->attribs.override_redirect = True;
72 bPtr->textColor = WMRetainColor(bPtr->view->screen->black);
74 WMCreateEventHandler(bPtr->view, StructureNotifyMask, handleEvents, bPtr);
76 W_ResizeView(bPtr->view, DEFAULT_WIDTH, DEFAULT_HEIGHT);
77 bPtr->flags.alignment = DEFAULT_ALIGNMENT;
79 bPtr->table = WMCreateHashTable(WMIntHashCallbacks);
81 bPtr->delay = DEFAULT_DELAY;
83 bPtr->flags.enabled = 1;
85 return bPtr;
90 void
91 WMSetBalloonTextAlignment(WMScreen *scr, WMAlignment alignment)
93 scr->balloon->flags.alignment = alignment;
98 void
99 WMSetBalloonTextForView(char *text, WMView *view)
101 char *oldText = NULL;
102 WMScreen *scr = view->screen;
104 if (text) {
105 oldText = WMHashInsert(scr->balloon->table, view, wstrdup(text));
106 } else {
107 oldText = WMHashGet(scr->balloon->table, view);
109 WMHashRemove(scr->balloon->table, view);
112 if (oldText) {
113 free(oldText);
118 void
119 WMSetBalloonFont(WMScreen *scr, WMFont *font)
121 Balloon *bPtr = scr->balloon;
123 if (bPtr->font!=NULL)
124 WMReleaseFont(bPtr->font);
126 if (font)
127 bPtr->font = WMRetainFont(font);
128 else
129 bPtr->font = NULL;
133 void
134 WMSetBalloonTextColor(WMScreen *scr, WMColor *color)
136 Balloon *bPtr = scr->balloon;
138 if (bPtr->textColor)
139 WMReleaseColor(bPtr->textColor);
141 bPtr->textColor = WMRetainColor(color);
145 void
146 WMSetBalloonDelay(WMScreen *scr, int delay)
148 scr->balloon->delay = delay;
152 void
153 WMSetBalloonEnabled(WMScreen *scr, Bool flag)
155 scr->balloon->flags.enabled = flag;
157 W_UnmapView(scr->balloon->view);
161 static void
162 clearNoDelay(void *data)
164 Balloon *bPtr = (Balloon*)data;
166 bPtr->flags.noDelay = 0;
167 bPtr->noDelayTimer = NULL;
171 void
172 W_BalloonHandleLeaveView(WMView *view)
174 Balloon *bPtr = view->screen->balloon;
176 if (bPtr->forWindow == view->window) {
177 if (bPtr->view->flags.mapped) {
178 W_UnmapView(bPtr->view);
179 bPtr->noDelayTimer = WMAddTimerHandler(NO_DELAY_DELAY,
180 clearNoDelay, bPtr);
182 if (bPtr->timer)
183 WMDeleteTimerHandler(bPtr->timer);
185 bPtr->timer = NULL;
187 bPtr->forWindow = None;
193 * botar balao perto do cursor
194 * so mapear balao se o mouse ficar parado pelo delay
198 static void
199 showBalloon(void *data)
201 char *text;
202 WMView *view = (WMView*)data;
203 Balloon *bPtr = view->screen->balloon;
204 int x, y;
205 Window foo;
207 bPtr->timer = NULL;
209 text = WMHashGet(bPtr->table, view);
210 if (!text)
211 return;
213 XTranslateCoordinates(view->screen->display, view->window,
214 view->screen->rootWin, 0, 0, &x, &y, &foo);
216 if (!bPtr->view->flags.realized)
217 W_RealizeView(bPtr->view);
219 showText(bPtr, x, y, view->size.width, view->size.height, text);
221 bPtr->flags.noDelay = 1;
226 void
227 W_BalloonHandleEnterView(WMView *view)
229 Balloon *bPtr = view->screen->balloon;
230 char *text;
232 if (!bPtr->flags.enabled)
233 return;
235 text = WMHashGet(bPtr->table, view);
236 if (!text) {
237 if (bPtr->view->flags.realized)
238 W_UnmapView(bPtr->view);
240 return;
243 if (bPtr->timer)
244 WMDeleteTimerHandler(bPtr->timer);
245 bPtr->timer = NULL;
247 if (bPtr->noDelayTimer)
248 WMDeleteTimerHandler(bPtr->noDelayTimer);
249 bPtr->noDelayTimer = NULL;
251 bPtr->forWindow = view->window;
253 if (bPtr->flags.noDelay) {
254 bPtr->timer = NULL;
256 showBalloon(view);
257 } else {
258 bPtr->timer = WMAddTimerHandler(bPtr->delay, showBalloon, view);
263 #define TOP 0
264 #define BOTTOM 1
265 #define LEFT 0
266 #define RIGHT 2
268 #define TLEFT (TOP|LEFT)
269 #define TRIGHT (TOP|RIGHT)
270 #define BLEFT (BOTTOM|LEFT)
271 #define BRIGHT (BOTTOM|RIGHT)
275 #define SPACE 12
278 static void
279 drawBalloon(Display *dpy, Pixmap pix, GC gc, int x, int y, int w, int h,
280 int side)
282 int rad = h*3/10;
283 XPoint pt[3];
285 XFillArc(dpy, pix, gc, x, y, rad, rad, 90*64, 90*64);
286 XFillArc(dpy, pix, gc, x, y+h-1-rad, rad, rad, 180*64, 90*64);
288 XFillArc(dpy, pix, gc, x+w-1-rad, y, rad, rad, 0*64, 90*64);
289 XFillArc(dpy, pix, gc, x+w-1-rad, y+h-1-rad, rad, rad, 270*64, 90*64);
291 XFillRectangle(dpy, pix, gc, x, y+rad/2, w, h-rad);
292 XFillRectangle(dpy, pix, gc, x+rad/2, y, w-rad, h);
294 if (side & BOTTOM) {
295 pt[0].y = y+h-1;
296 pt[1].y = y+h-1+SPACE;
297 pt[2].y = y+h-1;
298 } else {
299 pt[0].y = y;
300 pt[1].y = y-SPACE;
301 pt[2].y = y;
303 if (side & RIGHT) {
304 pt[0].x = x+w-h+2*h/16;
305 pt[1].x = x+w-h+11*h/16;
306 pt[2].x = x+w-h+7*h/16;
307 } else {
308 pt[0].x = x+h-2*h/16;
309 pt[1].x = x+h-11*h/16;
310 pt[2].x = x+h-7*h/16;
312 XFillPolygon(dpy, pix, gc, pt, 3, Convex, CoordModeOrigin);
316 static Pixmap
317 makePixmap(WMScreen *scr, int width, int height, int side, Pixmap *mask)
319 Display *dpy = WMScreenDisplay(scr);
320 Pixmap bitmap;
321 Pixmap pixmap;
322 int x, y;
323 WMColor *black = WMBlackColor(scr);
324 WMColor *white = WMWhiteColor(scr);
326 bitmap = XCreatePixmap(dpy, scr->rootWin, width+SPACE, height+SPACE, 1);
328 XSetForeground(dpy, scr->monoGC, 0);
329 XFillRectangle(dpy, bitmap, scr->monoGC, 0, 0, width+SPACE, height+SPACE);
331 pixmap = XCreatePixmap(dpy, scr->rootWin, width+SPACE, height+SPACE,
332 scr->depth);
334 XFillRectangle(dpy, pixmap, WMColorGC(black), 0, 0,
335 width+SPACE, height+SPACE);
337 if (side & BOTTOM) {
338 y = 0;
339 } else {
340 y = SPACE;
342 x = 0;
344 XSetForeground(dpy, scr->monoGC, 1);
345 drawBalloon(dpy, bitmap, scr->monoGC, x, y, width, height, side);
346 drawBalloon(dpy, pixmap, WMColorGC(white), x+1, y+1, width-2, height-2,
347 side);
349 *mask = bitmap;
351 WMReleaseColor(black);
352 WMReleaseColor(white);
354 return pixmap;
358 static void
359 showText(Balloon *bPtr, int x, int y, int h, int w, char *text)
361 WMScreen *scr = bPtr->view->screen;
362 Display *dpy = WMScreenDisplay(scr);
363 int width;
364 int height;
365 Pixmap pixmap;
366 Pixmap mask;
367 WMFont *font = bPtr->font ? bPtr->font : scr->normalFont;
368 int textHeight;
369 int side = 0;
370 int ty;
371 int bx, by;
374 int w;
375 char *ptr, *ptr2;
377 ptr2 = ptr = text;
378 width = 0;
379 while (ptr && ptr2) {
380 ptr2 = strchr(ptr, '\n');
381 if (ptr2) {
382 w = WMWidthOfString(font, ptr, ptr2 - ptr);
383 } else {
384 w = WMWidthOfString(font, ptr, strlen(ptr));
386 if (w > width)
387 width = w;
388 ptr = ptr2 + 1;
392 width += 16;
394 textHeight = W_GetTextHeight(font, text, width, False);
396 height = textHeight + 4;
398 if (height < 16)
399 height = 16;
400 if (width < height)
401 width = height;
403 if (x + width > scr->rootView->size.width) {
404 side = RIGHT;
405 bx = x - width + w/2;
406 if (bx < 0)
407 bx = 0;
408 } else {
409 side = LEFT;
410 bx = x + w/2;
412 if (bx + width > scr->rootView->size.width)
413 bx = scr->rootView->size.width - width;
415 if (y - (height + SPACE) < 0) {
416 side |= TOP;
417 by = y+h-1;
418 ty = SPACE;
419 } else {
420 side |= BOTTOM;
421 by = y - (height + SPACE);
422 ty = 0;
424 pixmap = makePixmap(scr, width, height, side, &mask);
426 W_PaintText(bPtr->view, pixmap, font, 8, ty + (height - textHeight)/2,
427 width, bPtr->flags.alignment,
428 WMColorGC(bPtr->textColor ? bPtr->textColor : scr->black),
429 False, text, strlen(text));
431 XSetWindowBackgroundPixmap(dpy, bPtr->view->window, pixmap);
433 W_ResizeView(bPtr->view, width, height+SPACE);
435 XFreePixmap(dpy, pixmap);
437 XShapeCombineMask(dpy, bPtr->view->window, ShapeBounding, 0, 0, mask,
438 ShapeSet);
439 XFreePixmap(dpy, mask);
441 W_MoveView(bPtr->view, bx, by);
443 W_MapView(bPtr->view);
447 static void
448 handleEvents(XEvent *event, void *data)
450 Balloon *bPtr = (Balloon*)data;
452 switch (event->type) {
453 case DestroyNotify:
454 destroyBalloon(bPtr);
455 break;
460 static void
461 destroyBalloon(Balloon *bPtr)
463 WMHashEnumerator e;
464 char *str;
466 e = WMEnumerateHashTable(bPtr->table);
468 while ((str = WMNextHashEnumeratorItem(&e))) {
469 free(str);
471 WMFreeHashTable(bPtr->table);
473 if (bPtr->textColor)
474 WMReleaseColor(bPtr->textColor);
476 if (bPtr->font)
477 WMReleaseFont(bPtr->font);
479 free(bPtr);