fixed crash when saving empty menu items in wprefs
[wmaker-crm.git] / WINGs / wballoon.c
blobf0c4e36668117247fc3500d58c63099bef1d9046
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;
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(Display *dpy, Pixmap pix, GC gc, int x, int y, int w, int h,
279 int side)
281 int rad = h*3/10;
282 XPoint pt[3];
284 XFillArc(dpy, pix, gc, x, y, rad, rad, 90*64, 90*64);
285 XFillArc(dpy, pix, gc, x, y+h-1-rad, rad, rad, 180*64, 90*64);
287 XFillArc(dpy, pix, gc, x+w-1-rad, y, rad, rad, 0*64, 90*64);
288 XFillArc(dpy, pix, gc, x+w-1-rad, y+h-1-rad, rad, rad, 270*64, 90*64);
290 XFillRectangle(dpy, pix, gc, x, y+rad/2, w, h-rad);
291 XFillRectangle(dpy, pix, gc, x+rad/2, y, w-rad, h);
293 if (side & BOTTOM) {
294 pt[0].y = y+h-1;
295 pt[1].y = y+h-1+SPACE;
296 pt[2].y = y+h-1;
297 } else {
298 pt[0].y = y;
299 pt[1].y = y-SPACE;
300 pt[2].y = y;
302 if (side & RIGHT) {
303 pt[0].x = x+w-h+2*h/16;
304 pt[1].x = x+w-h+11*h/16;
305 pt[2].x = x+w-h+7*h/16;
306 } else {
307 pt[0].x = x+h-2*h/16;
308 pt[1].x = x+h-11*h/16;
309 pt[2].x = x+h-7*h/16;
311 XFillPolygon(dpy, pix, gc, pt, 3, Convex, CoordModeOrigin);
315 static Pixmap
316 makePixmap(WMScreen *scr, int width, int height, int side, Pixmap *mask)
318 Display *dpy = WMScreenDisplay(scr);
319 Pixmap bitmap;
320 Pixmap pixmap;
321 int x, y;
322 WMColor *black = WMBlackColor(scr);
323 WMColor *white = WMWhiteColor(scr);
325 bitmap = XCreatePixmap(dpy, scr->rootWin, width+SPACE, height+SPACE, 1);
327 XSetForeground(dpy, scr->monoGC, 0);
328 XFillRectangle(dpy, bitmap, scr->monoGC, 0, 0, width+SPACE, height+SPACE);
330 pixmap = XCreatePixmap(dpy, scr->rootWin, width+SPACE, height+SPACE,
331 scr->depth);
333 XFillRectangle(dpy, pixmap, WMColorGC(black), 0, 0,
334 width+SPACE, height+SPACE);
336 if (side & BOTTOM) {
337 y = 0;
338 } else {
339 y = SPACE;
341 x = 0;
343 XSetForeground(dpy, scr->monoGC, 1);
344 drawBalloon(dpy, bitmap, scr->monoGC, x, y, width, height, side);
345 drawBalloon(dpy, pixmap, WMColorGC(white), x+1, y+1, width-2, height-2,
346 side);
348 *mask = bitmap;
350 WMReleaseColor(black);
351 WMReleaseColor(white);
353 return pixmap;
357 static void
358 showText(Balloon *bPtr, int x, int y, int h, int w, char *text)
360 WMScreen *scr = bPtr->view->screen;
361 Display *dpy = WMScreenDisplay(scr);
362 int width;
363 int height;
364 Pixmap pixmap;
365 Pixmap mask;
366 WMFont *font = bPtr->font ? bPtr->font : scr->normalFont;
367 int textHeight;
368 int side = 0;
369 int ty;
370 int bx, by;
373 int w;
374 char *ptr, *ptr2;
376 ptr2 = ptr = text;
377 width = 0;
378 while (ptr && ptr2) {
379 ptr2 = strchr(ptr, '\n');
380 if (ptr2) {
381 w = WMWidthOfString(font, ptr, ptr2 - ptr);
382 } else {
383 w = WMWidthOfString(font, ptr, strlen(ptr));
385 if (w > width)
386 width = w;
387 ptr = ptr2 + 1;
391 width += 16;
393 textHeight = W_GetTextHeight(font, text, width, False);
395 height = textHeight + 4;
397 if (height < 16)
398 height = 16;
399 if (width < height)
400 width = height;
402 if (x + width > scr->rootView->size.width) {
403 side = RIGHT;
404 bx = x - width + w/2;
405 if (bx < 0)
406 bx = 0;
407 } else {
408 side = LEFT;
409 bx = x + w/2;
411 if (bx + width > scr->rootView->size.width)
412 bx = scr->rootView->size.width - width;
414 if (y - (height + SPACE) < 0) {
415 side |= TOP;
416 by = y+h-1;
417 ty = SPACE;
418 } else {
419 side |= BOTTOM;
420 by = y - (height + SPACE);
421 ty = 0;
423 pixmap = makePixmap(scr, width, height, side, &mask);
425 W_PaintText(bPtr->view, pixmap, font, 8, ty + (height - textHeight)/2,
426 width, bPtr->flags.alignment,
427 WMColorGC(bPtr->textColor ? bPtr->textColor : scr->black),
428 False, text, strlen(text));
430 XSetWindowBackgroundPixmap(dpy, bPtr->view->window, pixmap);
432 W_ResizeView(bPtr->view, width, height+SPACE);
434 XFreePixmap(dpy, pixmap);
436 #ifdef SHAPE
437 XShapeCombineMask(dpy, bPtr->view->window, ShapeBounding, 0, 0, mask,
438 ShapeSet);
439 #endif
440 XFreePixmap(dpy, mask);
442 W_MoveView(bPtr->view, bx, by);
444 W_MapView(bPtr->view);
448 static void
449 handleEvents(XEvent *event, void *data)
451 Balloon *bPtr = (Balloon*)data;
453 switch (event->type) {
454 case DestroyNotify:
455 destroyBalloon(bPtr);
456 break;
461 static void
462 destroyBalloon(Balloon *bPtr)
464 WMHashEnumerator e;
465 char *str;
467 e = WMEnumerateHashTable(bPtr->table);
469 while ((str = WMNextHashEnumeratorItem(&e))) {
470 wfree(str);
472 WMFreeHashTable(bPtr->table);
474 if (bPtr->textColor)
475 WMReleaseColor(bPtr->textColor);
477 if (bPtr->font)
478 WMReleaseFont(bPtr->font);
480 wfree(bPtr);