Guess what? Yep, another wmtext update. Now this was all, please go to
[wmaker-crm.git] / WINGs / wballoon.c
blob1ead48b47cfbe64671fd7230aa0f359f341b2588
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_CreateTopView(scr);
65 if (!bPtr->view) {
66 wfree(bPtr);
67 return NULL;
69 bPtr->view->self = bPtr;
71 bPtr->view->attribFlags |= CWOverrideRedirect;
72 bPtr->view->attribs.override_redirect = True;
74 bPtr->textColor = WMRetainColor(bPtr->view->screen->black);
76 WMCreateEventHandler(bPtr->view, StructureNotifyMask, handleEvents, bPtr);
78 W_ResizeView(bPtr->view, DEFAULT_WIDTH, DEFAULT_HEIGHT);
79 bPtr->flags.alignment = DEFAULT_ALIGNMENT;
81 bPtr->table = WMCreateHashTable(WMIntHashCallbacks);
83 bPtr->delay = DEFAULT_DELAY;
85 bPtr->flags.enabled = 1;
87 return bPtr;
92 void
93 WMSetBalloonTextAlignment(WMScreen *scr, WMAlignment alignment)
95 scr->balloon->flags.alignment = alignment;
100 void
101 WMSetBalloonTextForView(char *text, WMView *view)
103 char *oldText = NULL;
104 WMScreen *scr = view->screen;
106 if (text) {
107 oldText = WMHashInsert(scr->balloon->table, view, wstrdup(text));
108 } else {
109 oldText = WMHashGet(scr->balloon->table, view);
111 WMHashRemove(scr->balloon->table, view);
114 if (oldText) {
115 wfree(oldText);
120 void
121 WMSetBalloonFont(WMScreen *scr, WMFont *font)
123 Balloon *bPtr = scr->balloon;
125 if (bPtr->font!=NULL)
126 WMReleaseFont(bPtr->font);
128 if (font)
129 bPtr->font = WMRetainFont(font);
130 else
131 bPtr->font = NULL;
135 void
136 WMSetBalloonTextColor(WMScreen *scr, WMColor *color)
138 Balloon *bPtr = scr->balloon;
140 if (bPtr->textColor)
141 WMReleaseColor(bPtr->textColor);
143 bPtr->textColor = WMRetainColor(color);
147 void
148 WMSetBalloonDelay(WMScreen *scr, int delay)
150 scr->balloon->delay = delay;
154 void
155 WMSetBalloonEnabled(WMScreen *scr, Bool flag)
157 scr->balloon->flags.enabled = flag;
159 W_UnmapView(scr->balloon->view);
163 static void
164 clearNoDelay(void *data)
166 Balloon *bPtr = (Balloon*)data;
168 bPtr->flags.noDelay = 0;
169 bPtr->noDelayTimer = NULL;
173 void
174 W_BalloonHandleLeaveView(WMView *view)
176 Balloon *bPtr = view->screen->balloon;
178 if (bPtr->forWindow == view->window) {
179 if (bPtr->view->flags.mapped) {
180 W_UnmapView(bPtr->view);
181 bPtr->noDelayTimer = WMAddTimerHandler(NO_DELAY_DELAY,
182 clearNoDelay, bPtr);
184 if (bPtr->timer)
185 WMDeleteTimerHandler(bPtr->timer);
187 bPtr->timer = NULL;
189 bPtr->forWindow = None;
195 * botar balao perto do cursor
196 * so mapear balao se o mouse ficar parado pelo delay
200 static void
201 showBalloon(void *data)
203 char *text;
204 WMView *view = (WMView*)data;
205 Balloon *bPtr = view->screen->balloon;
206 int x, y;
207 Window foo;
209 bPtr->timer = NULL;
211 text = WMHashGet(bPtr->table, view);
212 if (!text)
213 return;
215 XTranslateCoordinates(view->screen->display, view->window,
216 view->screen->rootWin, 0, 0, &x, &y, &foo);
218 if (!bPtr->view->flags.realized)
219 W_RealizeView(bPtr->view);
221 showText(bPtr, x, y, view->size.width, view->size.height, text);
223 bPtr->flags.noDelay = 1;
228 void
229 W_BalloonHandleEnterView(WMView *view)
231 Balloon *bPtr = view->screen->balloon;
232 char *text;
234 if (!bPtr->flags.enabled)
235 return;
237 text = WMHashGet(bPtr->table, view);
238 if (!text) {
239 if (bPtr->view->flags.realized)
240 W_UnmapView(bPtr->view);
242 return;
245 if (bPtr->timer)
246 WMDeleteTimerHandler(bPtr->timer);
247 bPtr->timer = NULL;
249 if (bPtr->noDelayTimer)
250 WMDeleteTimerHandler(bPtr->noDelayTimer);
251 bPtr->noDelayTimer = NULL;
253 bPtr->forWindow = view->window;
255 if (bPtr->flags.noDelay) {
256 bPtr->timer = NULL;
258 showBalloon(view);
259 } else {
260 bPtr->timer = WMAddTimerHandler(bPtr->delay, showBalloon, view);
265 #define TOP 0
266 #define BOTTOM 1
267 #define LEFT 0
268 #define RIGHT 2
270 #define TLEFT (TOP|LEFT)
271 #define TRIGHT (TOP|RIGHT)
272 #define BLEFT (BOTTOM|LEFT)
273 #define BRIGHT (BOTTOM|RIGHT)
277 #define SPACE 12
280 static void
281 drawBalloon(Display *dpy, Pixmap pix, GC gc, int x, int y, int w, int h,
282 int side)
284 int rad = h*3/10;
285 XPoint pt[3];
287 XFillArc(dpy, pix, gc, x, y, rad, rad, 90*64, 90*64);
288 XFillArc(dpy, pix, gc, x, y+h-1-rad, rad, rad, 180*64, 90*64);
290 XFillArc(dpy, pix, gc, x+w-1-rad, y, rad, rad, 0*64, 90*64);
291 XFillArc(dpy, pix, gc, x+w-1-rad, y+h-1-rad, rad, rad, 270*64, 90*64);
293 XFillRectangle(dpy, pix, gc, x, y+rad/2, w, h-rad);
294 XFillRectangle(dpy, pix, gc, x+rad/2, y, w-rad, h);
296 if (side & BOTTOM) {
297 pt[0].y = y+h-1;
298 pt[1].y = y+h-1+SPACE;
299 pt[2].y = y+h-1;
300 } else {
301 pt[0].y = y;
302 pt[1].y = y-SPACE;
303 pt[2].y = y;
305 if (side & RIGHT) {
306 pt[0].x = x+w-h+2*h/16;
307 pt[1].x = x+w-h+11*h/16;
308 pt[2].x = x+w-h+7*h/16;
309 } else {
310 pt[0].x = x+h-2*h/16;
311 pt[1].x = x+h-11*h/16;
312 pt[2].x = x+h-7*h/16;
314 XFillPolygon(dpy, pix, gc, pt, 3, Convex, CoordModeOrigin);
318 static Pixmap
319 makePixmap(WMScreen *scr, int width, int height, int side, Pixmap *mask)
321 Display *dpy = WMScreenDisplay(scr);
322 Pixmap bitmap;
323 Pixmap pixmap;
324 int x, y;
325 WMColor *black = WMBlackColor(scr);
326 WMColor *white = WMWhiteColor(scr);
328 bitmap = XCreatePixmap(dpy, scr->rootWin, width+SPACE, height+SPACE, 1);
330 XSetForeground(dpy, scr->monoGC, 0);
331 XFillRectangle(dpy, bitmap, scr->monoGC, 0, 0, width+SPACE, height+SPACE);
333 pixmap = XCreatePixmap(dpy, scr->rootWin, width+SPACE, height+SPACE,
334 scr->depth);
336 XFillRectangle(dpy, pixmap, WMColorGC(black), 0, 0,
337 width+SPACE, height+SPACE);
339 if (side & BOTTOM) {
340 y = 0;
341 } else {
342 y = SPACE;
344 x = 0;
346 XSetForeground(dpy, scr->monoGC, 1);
347 drawBalloon(dpy, bitmap, scr->monoGC, x, y, width, height, side);
348 drawBalloon(dpy, pixmap, WMColorGC(white), x+1, y+1, width-2, height-2,
349 side);
351 *mask = bitmap;
353 WMReleaseColor(black);
354 WMReleaseColor(white);
356 return pixmap;
360 static void
361 showText(Balloon *bPtr, int x, int y, int h, int w, char *text)
363 WMScreen *scr = bPtr->view->screen;
364 Display *dpy = WMScreenDisplay(scr);
365 int width;
366 int height;
367 Pixmap pixmap;
368 Pixmap mask;
369 WMFont *font = bPtr->font ? bPtr->font : scr->normalFont;
370 int textHeight;
371 int side = 0;
372 int ty;
373 int bx, by;
376 int w;
377 char *ptr, *ptr2;
379 ptr2 = ptr = text;
380 width = 0;
381 while (ptr && ptr2) {
382 ptr2 = strchr(ptr, '\n');
383 if (ptr2) {
384 w = WMWidthOfString(font, ptr, ptr2 - ptr);
385 } else {
386 w = WMWidthOfString(font, ptr, strlen(ptr));
388 if (w > width)
389 width = w;
390 ptr = ptr2 + 1;
394 width += 16;
396 textHeight = W_GetTextHeight(font, text, width, False);
398 height = textHeight + 4;
400 if (height < 16)
401 height = 16;
402 if (width < height)
403 width = height;
405 if (x + width > scr->rootView->size.width) {
406 side = RIGHT;
407 bx = x - width + w/2;
408 if (bx < 0)
409 bx = 0;
410 } else {
411 side = LEFT;
412 bx = x + w/2;
414 if (bx + width > scr->rootView->size.width)
415 bx = scr->rootView->size.width - width;
417 if (y - (height + SPACE) < 0) {
418 side |= TOP;
419 by = y+h-1;
420 ty = SPACE;
421 } else {
422 side |= BOTTOM;
423 by = y - (height + SPACE);
424 ty = 0;
426 pixmap = makePixmap(scr, width, height, side, &mask);
428 W_PaintText(bPtr->view, pixmap, font, 8, ty + (height - textHeight)/2,
429 width, bPtr->flags.alignment,
430 WMColorGC(bPtr->textColor ? bPtr->textColor : scr->black),
431 False, text, strlen(text));
433 XSetWindowBackgroundPixmap(dpy, bPtr->view->window, pixmap);
435 W_ResizeView(bPtr->view, width, height+SPACE);
437 XFreePixmap(dpy, pixmap);
439 #ifdef SHAPE
440 XShapeCombineMask(dpy, bPtr->view->window, ShapeBounding, 0, 0, mask,
441 ShapeSet);
442 #endif
443 XFreePixmap(dpy, mask);
445 W_MoveView(bPtr->view, bx, by);
447 W_MapView(bPtr->view);
451 static void
452 handleEvents(XEvent *event, void *data)
454 Balloon *bPtr = (Balloon*)data;
456 switch (event->type) {
457 case DestroyNotify:
458 destroyBalloon(bPtr);
459 break;
464 static void
465 destroyBalloon(Balloon *bPtr)
467 WMHashEnumerator e;
468 char *str;
470 e = WMEnumerateHashTable(bPtr->table);
472 while ((str = WMNextHashEnumeratorItem(&e))) {
473 wfree(str);
475 WMFreeHashTable(bPtr->table);
477 if (bPtr->textColor)
478 WMReleaseColor(bPtr->textColor);
480 if (bPtr->font)
481 WMReleaseFont(bPtr->font);
483 wfree(bPtr);