Change to the linux kernel coding style
[wmaker-crm.git] / WINGs / wballoon.c
blob1b33a8957e9dc9c569e46fd6854fe6184b712840
2 #include "wconfig.h"
3 #include "WINGsP.h"
5 #ifdef SHAPE
6 #include <X11/extensions/shape.h>
7 #endif
9 typedef struct W_Balloon {
10 W_View *view;
12 WMHashTable *table; /* Table from view ptr to text */
14 WMColor *backColor;
15 WMColor *textColor;
16 WMFont *font;
18 WMHandlerID timer; /* timer for showing balloon */
20 WMHandlerID noDelayTimer;
22 int delay;
24 Window forWindow; /* window for which the balloon
25 * is being show in the moment */
27 struct {
28 WMAlignment alignment:2;
29 unsigned enabled:1;
31 unsigned noDelay:1;
32 } flags;
33 } Balloon;
35 #define DEFAULT_WIDTH 60
36 #define DEFAULT_HEIGHT 14
37 #define DEFAULT_ALIGNMENT WALeft
38 #define DEFAULT_DELAY 500
40 #define NO_DELAY_DELAY 150
42 static void destroyBalloon(Balloon * bPtr);
44 static void handleEvents(XEvent * event, void *data);
46 static void showText(Balloon * bPtr, int x, int y, int w, int h, char *text);
48 struct W_Balloon *W_CreateBalloon(WMScreen * scr)
50 Balloon *bPtr;
52 bPtr = wmalloc(sizeof(Balloon));
53 memset(bPtr, 0, sizeof(Balloon));
55 bPtr->view = W_CreateUnmanagedTopView(scr);
56 if (!bPtr->view) {
57 wfree(bPtr);
58 return NULL;
60 bPtr->view->self = bPtr;
62 bPtr->textColor = WMRetainColor(bPtr->view->screen->black);
64 WMCreateEventHandler(bPtr->view, StructureNotifyMask, handleEvents, bPtr);
66 W_ResizeView(bPtr->view, DEFAULT_WIDTH, DEFAULT_HEIGHT);
67 bPtr->flags.alignment = DEFAULT_ALIGNMENT;
69 bPtr->table = WMCreateHashTable(WMIntHashCallbacks);
71 bPtr->delay = DEFAULT_DELAY;
73 bPtr->flags.enabled = 1;
75 return bPtr;
78 void WMSetBalloonTextAlignment(WMScreen * scr, WMAlignment alignment)
80 scr->balloon->flags.alignment = alignment;
84 void WMSetBalloonTextForView(char *text, WMView * view)
86 char *oldText = NULL;
87 WMScreen *scr = view->screen;
89 if (text) {
90 oldText = WMHashInsert(scr->balloon->table, view, wstrdup(text));
91 } else {
92 oldText = WMHashGet(scr->balloon->table, view);
94 WMHashRemove(scr->balloon->table, view);
97 if (oldText) {
98 wfree(oldText);
102 void WMSetBalloonFont(WMScreen * scr, WMFont * font)
104 Balloon *bPtr = scr->balloon;
106 if (bPtr->font != NULL)
107 WMReleaseFont(bPtr->font);
109 if (font)
110 bPtr->font = WMRetainFont(font);
111 else
112 bPtr->font = NULL;
115 void WMSetBalloonTextColor(WMScreen * scr, WMColor * color)
117 Balloon *bPtr = scr->balloon;
119 if (bPtr->textColor)
120 WMReleaseColor(bPtr->textColor);
122 bPtr->textColor = WMRetainColor(color);
125 void WMSetBalloonDelay(WMScreen * scr, int delay)
127 scr->balloon->delay = delay;
130 void WMSetBalloonEnabled(WMScreen * scr, Bool flag)
132 scr->balloon->flags.enabled = ((flag == 0) ? 0 : 1);
134 W_UnmapView(scr->balloon->view);
137 static void clearNoDelay(void *data)
139 Balloon *bPtr = (Balloon *) data;
141 bPtr->flags.noDelay = 0;
142 bPtr->noDelayTimer = NULL;
145 void W_BalloonHandleLeaveView(WMView * view)
147 Balloon *bPtr = view->screen->balloon;
149 if (bPtr->forWindow == view->window) {
150 if (bPtr->view->flags.mapped) {
151 W_UnmapView(bPtr->view);
152 bPtr->noDelayTimer = WMAddTimerHandler(NO_DELAY_DELAY, clearNoDelay, bPtr);
154 if (bPtr->timer)
155 WMDeleteTimerHandler(bPtr->timer);
157 bPtr->timer = NULL;
159 bPtr->forWindow = None;
164 * botar balao perto do cursor
165 * so mapear balao se o mouse ficar parado pelo delay
169 static void showBalloon(void *data)
171 char *text;
172 WMView *view = (WMView *) data;
173 Balloon *bPtr = view->screen->balloon;
174 int x, y;
175 Window foo;
177 bPtr->timer = NULL;
179 text = WMHashGet(bPtr->table, view);
180 if (!text)
181 return;
183 XTranslateCoordinates(view->screen->display, view->window, view->screen->rootWin, 0, 0, &x, &y, &foo);
185 if (!bPtr->view->flags.realized)
186 W_RealizeView(bPtr->view);
188 showText(bPtr, x, y, view->size.width, view->size.height, text);
190 bPtr->flags.noDelay = 1;
193 void W_BalloonHandleEnterView(WMView * view)
195 Balloon *bPtr = view->screen->balloon;
196 char *text;
198 if (!bPtr->flags.enabled)
199 return;
201 text = WMHashGet(bPtr->table, view);
202 if (!text) {
203 if (bPtr->view->flags.realized)
204 W_UnmapView(bPtr->view);
206 return;
209 if (bPtr->timer)
210 WMDeleteTimerHandler(bPtr->timer);
211 bPtr->timer = NULL;
213 if (bPtr->noDelayTimer)
214 WMDeleteTimerHandler(bPtr->noDelayTimer);
215 bPtr->noDelayTimer = NULL;
217 bPtr->forWindow = view->window;
219 if (bPtr->flags.noDelay) {
220 bPtr->timer = NULL;
222 showBalloon(view);
223 } else {
224 bPtr->timer = WMAddTimerHandler(bPtr->delay, showBalloon, view);
228 #define TOP 0
229 #define BOTTOM 1
230 #define LEFT 0
231 #define RIGHT 2
233 #define TLEFT (TOP|LEFT)
234 #define TRIGHT (TOP|RIGHT)
235 #define BLEFT (BOTTOM|LEFT)
236 #define BRIGHT (BOTTOM|RIGHT)
238 #define SPACE 12
240 static void drawBalloon(WMScreen * scr, Pixmap bitmap, Pixmap pix, int x, int y, int w, int h, int side)
242 Display *dpy = scr->display;
243 WMColor *white = WMWhiteColor(scr);
244 WMColor *black = WMBlackColor(scr);
245 GC bgc = scr->monoGC;
246 GC gc = WMColorGC(white);
247 int rad = h * 3 / 10;
248 XPoint pt[3], ipt[3];
249 int w1;
251 /* outline */
252 XSetForeground(dpy, bgc, 1);
254 XFillArc(dpy, bitmap, bgc, x, y, rad, rad, 90 * 64, 90 * 64);
255 XFillArc(dpy, bitmap, bgc, x, y + h - 1 - rad, rad, rad, 180 * 64, 90 * 64);
257 XFillArc(dpy, bitmap, bgc, x + w - 1 - rad, y, rad, rad, 0 * 64, 90 * 64);
258 XFillArc(dpy, bitmap, bgc, x + w - 1 - rad, y + h - 1 - rad, rad, rad, 270 * 64, 90 * 64);
260 XFillRectangle(dpy, bitmap, bgc, x, y + rad / 2, w, h - rad);
261 XFillRectangle(dpy, bitmap, bgc, x + rad / 2, y, w - rad, h);
263 /* interior */
264 XFillArc(dpy, pix, gc, x + 1, y + 1, rad, rad, 90 * 64, 90 * 64);
265 XFillArc(dpy, pix, gc, x + 1, y + h - 2 - rad, rad, rad, 180 * 64, 90 * 64);
267 XFillArc(dpy, pix, gc, x + w - 2 - rad, y + 1, rad, rad, 0 * 64, 90 * 64);
268 XFillArc(dpy, pix, gc, x + w - 2 - rad, y + h - 2 - rad, rad, rad, 270 * 64, 90 * 64);
270 XFillRectangle(dpy, pix, gc, x + 1, y + 1 + rad / 2, w - 2, h - 2 - rad);
271 XFillRectangle(dpy, pix, gc, x + 1 + rad / 2, y + 1, w - 2 - rad, h - 2);
273 if (side & BOTTOM) {
274 pt[0].y = y + h - 1;
275 pt[1].y = y + h - 1 + SPACE;
276 pt[2].y = y + h - 1;
277 ipt[0].y = pt[0].y - 1;
278 ipt[1].y = pt[1].y - 1;
279 ipt[2].y = pt[2].y - 1;
280 } else {
281 pt[0].y = y;
282 pt[1].y = y - SPACE;
283 pt[2].y = y;
284 ipt[0].y = pt[0].y + 1;
285 ipt[1].y = pt[1].y + 1;
286 ipt[2].y = pt[2].y + 1;
289 /*w1 = WMAX(h, 24); */
290 w1 = WMAX(h, 21);
292 if (side & RIGHT) {
293 pt[0].x = x + w - w1 + 2 * w1 / 16;
294 pt[1].x = x + w - w1 + 11 * w1 / 16;
295 pt[2].x = x + w - w1 + 7 * w1 / 16;
296 ipt[0].x = x + 1 + w - w1 + 2 * (w1 - 1) / 16;
297 ipt[1].x = x + 1 + w - w1 + 11 * (w1 - 1) / 16;
298 ipt[2].x = x + 1 + w - w1 + 7 * (w1 - 1) / 16;
299 /*ipt[0].x = pt[0].x+1;
300 ipt[1].x = pt[1].x;
301 ipt[2].x = pt[2].x; */
302 } else {
303 pt[0].x = x + w1 - 2 * w1 / 16;
304 pt[1].x = x + w1 - 11 * w1 / 16;
305 pt[2].x = x + w1 - 7 * w1 / 16;
306 ipt[0].x = x - 1 + w1 - 2 * (w1 - 1) / 16;
307 ipt[1].x = x - 1 + w1 - 11 * (w1 - 1) / 16;
308 ipt[2].x = x - 1 + w1 - 7 * (w1 - 1) / 16;
309 /*ipt[0].x = pt[0].x-1;
310 ipt[1].x = pt[1].x;
311 ipt[2].x = pt[2].x; */
314 XFillPolygon(dpy, bitmap, bgc, pt, 3, Convex, CoordModeOrigin);
315 XFillPolygon(dpy, pix, gc, ipt, 3, Convex, CoordModeOrigin);
317 /* fix outline */
318 XDrawLines(dpy, pix, WMColorGC(black), pt, 3, CoordModeOrigin);
319 if (side & RIGHT) {
320 pt[0].x++;
321 pt[2].x--;
322 } else {
323 pt[0].x--;
324 pt[2].x++;
326 XDrawLines(dpy, pix, WMColorGC(black), pt, 3, CoordModeOrigin);
328 WMReleaseColor(white);
329 WMReleaseColor(black);
332 static Pixmap makePixmap(WMScreen * scr, int width, int height, int side, Pixmap * mask)
334 Display *dpy = WMScreenDisplay(scr);
335 Pixmap bitmap;
336 Pixmap pixmap;
337 int x, y;
338 WMColor *black = WMBlackColor(scr);
340 bitmap = XCreatePixmap(dpy, scr->rootWin, width + SPACE, height + SPACE, 1);
342 XSetForeground(dpy, scr->monoGC, 0);
343 XFillRectangle(dpy, bitmap, scr->monoGC, 0, 0, width + SPACE, height + SPACE);
345 pixmap = XCreatePixmap(dpy, scr->rootWin, width + SPACE, height + SPACE, scr->depth);
347 XFillRectangle(dpy, pixmap, WMColorGC(black), 0, 0, width + SPACE, height + SPACE);
349 if (side & BOTTOM) {
350 y = 0;
351 } else {
352 y = SPACE;
354 x = 0;
356 drawBalloon(scr, bitmap, pixmap, x, y, width, height, side);
358 *mask = bitmap;
360 WMReleaseColor(black);
362 return pixmap;
365 static void showText(Balloon * bPtr, int x, int y, int w, int h, char *text)
367 WMScreen *scr = bPtr->view->screen;
368 Display *dpy = WMScreenDisplay(scr);
369 int width;
370 int height;
371 Pixmap pixmap;
372 Pixmap mask;
373 WMFont *font = bPtr->font ? bPtr->font : scr->normalFont;
374 int textHeight;
375 int side = 0;
376 int ty;
377 int bx, by;
380 int w;
381 char *ptr, *ptr2;
383 ptr2 = ptr = text;
384 width = 0;
385 while (ptr && ptr2) {
386 ptr2 = strchr(ptr, '\n');
387 if (ptr2) {
388 w = WMWidthOfString(font, ptr, ptr2 - ptr);
389 } else {
390 w = WMWidthOfString(font, ptr, strlen(ptr));
392 if (w > width)
393 width = w;
394 ptr = ptr2 + 1;
398 width += 16;
400 textHeight = W_GetTextHeight(font, text, width, False);
402 height = textHeight + 4;
404 if (height < 16)
405 height = 16;
406 if (width < height)
407 width = height;
409 if (x + width > scr->rootView->size.width) {
410 side = RIGHT;
411 bx = x - width + w / 2;
412 if (bx < 0)
413 bx = 0;
414 } else {
415 side = LEFT;
416 bx = x + w / 2;
418 if (bx + width > scr->rootView->size.width)
419 bx = scr->rootView->size.width - width;
421 if (y - (height + SPACE) < 0) {
422 side |= TOP;
423 by = y + h - 1;
424 ty = SPACE;
425 } else {
426 side |= BOTTOM;
427 by = y - (height + SPACE);
428 ty = 0;
430 pixmap = makePixmap(scr, width, height, side, &mask);
432 W_PaintText(bPtr->view, pixmap, font, 8, ty + (height - textHeight) / 2,
433 width, bPtr->flags.alignment,
434 bPtr->textColor ? bPtr->textColor : scr->black, False, text, strlen(text));
436 XSetWindowBackgroundPixmap(dpy, bPtr->view->window, pixmap);
438 W_ResizeView(bPtr->view, width, height + SPACE);
440 XFreePixmap(dpy, pixmap);
442 #ifdef SHAPE
443 XShapeCombineMask(dpy, bPtr->view->window, ShapeBounding, 0, 0, mask, ShapeSet);
444 #endif
445 XFreePixmap(dpy, mask);
447 W_MoveView(bPtr->view, bx, by);
449 W_MapView(bPtr->view);
452 static void handleEvents(XEvent * event, void *data)
454 Balloon *bPtr = (Balloon *) data;
456 switch (event->type) {
457 case DestroyNotify:
458 destroyBalloon(bPtr);
459 break;
463 static void destroyBalloon(Balloon * bPtr)
465 WMHashEnumerator e;
466 char *str;
468 e = WMEnumerateHashTable(bPtr->table);
470 while ((str = WMNextHashEnumeratorItem(&e))) {
471 wfree(str);
473 WMFreeHashTable(bPtr->table);
475 if (bPtr->textColor)
476 WMReleaseColor(bPtr->textColor);
478 if (bPtr->font)
479 WMReleaseFont(bPtr->font);
481 wfree(bPtr);