X-Git-Url: https://repo.or.cz/w/wmaker-crm.git/blobdiff_plain/59fc927dc9f183802621138534fa6eaafe5593ba..688a56e8ab67b56550e2874d9d7423f0d435bfd9:/src/balloon.c diff --git a/src/balloon.c b/src/balloon.c dissimilarity index 88% index f7515081..c7dfebab 100644 --- a/src/balloon.c +++ b/src/balloon.c @@ -1,631 +1,559 @@ -/* - * Window Maker window manager - * - * Copyright (c) 1998-2003 Alfredo K. Kojima - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - * USA. - */ - -#include "wconfig.h" - -#ifdef BALLOON_TEXT - -#include -#include -#ifdef SHAPED_BALLOON -#include -#endif - -#include -#include - -#include - -#include "WindowMaker.h" -#include "screen.h" -#include "texture.h" -#include "wcore.h" -#include "framewin.h" -#include "icon.h" -#include "appicon.h" -#include "funcs.h" -#include "workspace.h" -#include "balloon.h" - - - -extern WPreferences wPreferences; - -typedef struct _WBalloon { - Window window; - -#ifdef SHAPED_BALLOON - GC monoGC; -#endif - int prevType; - - Window objectWindow; - char *text; - int h; - - WMHandlerID timer; - - Pixmap contents; - - char mapped; - char ignoreTimer; -} WBalloon; - - -#define TOP 0 -#define BOTTOM 1 -#define LEFT 0 -#define RIGHT 2 - -#define TLEFT (TOP|LEFT) -#define TRIGHT (TOP|RIGHT) -#define BLEFT (BOTTOM|LEFT) -#define BRIGHT (BOTTOM|RIGHT) - - -static int -countLines(const char *text) -{ - const char *p = text; - int h = 1; - - while (*p) { - if (*p == '\n' && p[1] != 0) - h++; - p++; - } - return h; -} - - -static int -getMaxStringWidth(WMFont *font, char *text) -{ - char *p = text; - char *pb = p; - int pos = 0; - int w = 0, wt; - - while (*p) { - if (*p == '\n') { - wt = WMWidthOfString(font, pb, pos); - if (wt > w) - w = wt; - pos = 0; - pb = p + 1; - } else { - pos++; - } - p++; - } - if (pos > 0) { - wt = WMWidthOfString(font, pb, pos); - if (wt > w) - w = wt; - } - return w; -} - - -static void -drawMultiLineString(WMScreen *scr, Pixmap pixmap, WMColor *color, - WMFont *font, int x, int y, char *text, int len) -{ - char *p = text; - char *pb = p; - int l = 0, pos = 0; - int height = WMFontHeight(font); - - while (*p && p - text < len) { - if (*p == '\n') { - WMDrawString(scr, pixmap, color, font, x, y + l * height, pb, - pos); - l++; - pos = 0; - pb = p + 1; - } else { - pos++; - } - p++; - } - if (pos > 0) { - WMDrawString(scr, pixmap, color, font, x, y + l * height, pb, pos); - } -} - - - - -#ifdef SHAPED_BALLOON - -#define SPACE 12 - - -static void -drawBalloon(WScreen *scr, Pixmap bitmap, Pixmap pix, int x, int y, int w, - int h, int side) -{ - GC bgc = scr->balloon->monoGC; - GC gc = scr->draw_gc; - int rad = h * 3 / 10; - XPoint pt[3], ipt[3]; - int w1; - - /* outline */ - XSetForeground(dpy, bgc, 1); - - XFillArc(dpy, bitmap, bgc, x, y, rad, rad, 90 * 64, 90 * 64); - XFillArc(dpy, bitmap, bgc, x, y + h - 1 - rad, rad, rad, 180 * 64, - 90 * 64); - - XFillArc(dpy, bitmap, bgc, x + w - 1 - rad, y, rad, rad, 0 * 64, - 90 * 64); - XFillArc(dpy, bitmap, bgc, x + w - 1 - rad, y + h - 1 - rad, rad, rad, - 270 * 64, 90 * 64); - - XFillRectangle(dpy, bitmap, bgc, x, y + rad / 2, w, h - rad); - XFillRectangle(dpy, bitmap, bgc, x + rad / 2, y, w - rad, h); - - /* interior */ - XSetForeground(dpy, gc, scr->white_pixel); - - XFillArc(dpy, pix, gc, x + 1, y + 1, rad, rad, 90 * 64, 90 * 64); - XFillArc(dpy, pix, gc, x + 1, y + h - 2 - rad, rad, rad, 180 * 64, - 90 * 64); - - XFillArc(dpy, pix, gc, x + w - 2 - rad, y + 1, rad, rad, 0 * 64, - 90 * 64); - XFillArc(dpy, pix, gc, x + w - 2 - rad, y + h - 2 - rad, rad, rad, - 270 * 64, 90 * 64); - - XFillRectangle(dpy, pix, gc, x + 1, y + 1 + rad / 2, w - 2, - h - 2 - rad); - XFillRectangle(dpy, pix, gc, x + 1 + rad / 2, y + 1, w - 2 - rad, - h - 2); - - if (side & BOTTOM) { - pt[0].y = y + h - 1; - pt[1].y = y + h - 1 + SPACE; - pt[2].y = y + h - 1; - ipt[0].y = pt[0].y - 1; - ipt[1].y = pt[1].y - 1; - ipt[2].y = pt[2].y - 1; - } else { - pt[0].y = y; - pt[1].y = y - SPACE; - pt[2].y = y; - ipt[0].y = pt[0].y + 1; - ipt[1].y = pt[1].y + 1; - ipt[2].y = pt[2].y + 1; - } - - /*w1 = WMAX(h, 24); */ - w1 = WMAX(h, 21); - - if (side & RIGHT) { - pt[0].x = x + w - w1 + 2 * w1 / 16; - pt[1].x = x + w - w1 + 11 * w1 / 16; - pt[2].x = x + w - w1 + 7 * w1 / 16; - ipt[0].x = x + 1 + w - w1 + 2 * (w1 - 1) / 16; - ipt[1].x = x + 1 + w - w1 + 11 * (w1 - 1) / 16; - ipt[2].x = x + 1 + w - w1 + 7 * (w1 - 1) / 16; - /*ipt[0].x = pt[0].x+1; - ipt[1].x = pt[1].x; - ipt[2].x = pt[2].x; */ - } else { - pt[0].x = x + w1 - 2 * w1 / 16; - pt[1].x = x + w1 - 11 * w1 / 16; - pt[2].x = x + w1 - 7 * w1 / 16; - ipt[0].x = x - 1 + w1 - 2 * (w1 - 1) / 16; - ipt[1].x = x - 1 + w1 - 11 * (w1 - 1) / 16; - ipt[2].x = x - 1 + w1 - 7 * (w1 - 1) / 16; - /*ipt[0].x = pt[0].x-1; - ipt[1].x = pt[1].x; - ipt[2].x = pt[2].x; */ - } - - XFillPolygon(dpy, bitmap, bgc, pt, 3, Convex, CoordModeOrigin); - XFillPolygon(dpy, pix, gc, ipt, 3, Convex, CoordModeOrigin); - - /* fix outline */ - XSetForeground(dpy, gc, scr->black_pixel); - - XDrawLines(dpy, pix, gc, pt, 3, CoordModeOrigin); - if (side & RIGHT) { - pt[0].x++; - pt[2].x--; - } else { - pt[0].x--; - pt[2].x++; - } - XDrawLines(dpy, pix, gc, pt, 3, CoordModeOrigin); -} - - -static Pixmap -makePixmap(WScreen *scr, int width, int height, int side, Pixmap *mask) -{ - WBalloon *bal = scr->balloon; - Pixmap bitmap; - Pixmap pixmap; - int x, y; - - bitmap = - XCreatePixmap(dpy, scr->root_win, width + SPACE, height + SPACE, - 1); - - if (!bal->monoGC) { - bal->monoGC = XCreateGC(dpy, bitmap, 0, NULL); - } - XSetForeground(dpy, bal->monoGC, 0); - XFillRectangle(dpy, bitmap, bal->monoGC, 0, 0, width + SPACE, - height + SPACE); - - pixmap = - XCreatePixmap(dpy, scr->root_win, width + SPACE, height + SPACE, - scr->w_depth); - XSetForeground(dpy, scr->draw_gc, scr->black_pixel); - XFillRectangle(dpy, pixmap, scr->draw_gc, 0, 0, width + SPACE, - height + SPACE); - - if (side & BOTTOM) { - y = 0; - } else { - y = SPACE; - } - x = 0; - - drawBalloon(scr, bitmap, pixmap, x, y, width, height, side); - - *mask = bitmap; - - return pixmap; -} - - -static void -showText(WScreen *scr, int x, int y, int h, int w, char *text) -{ - int width; - int height; - Pixmap pixmap; - Pixmap mask; - WMFont *font = scr->info_text_font; - int side = 0; - int ty; - int bx, by; - - if (scr->balloon->contents) - XFreePixmap(dpy, scr->balloon->contents); - - width = getMaxStringWidth(font, text) + 16; - height = countLines(text) * WMFontHeight(font) + 4; - - if (height < 16) - height = 16; - if (width < height) - width = height; - - - if (x + width > scr->scr_width) { - side = RIGHT; - bx = x - width + w / 2; - if (bx < 0) - bx = 0; - } else { - side = LEFT; - bx = x + w / 2; - } - if (bx + width > scr->scr_width) - bx = scr->scr_width - width; - - if (y - (height + SPACE) < 0) { - side |= TOP; - by = y + h - 1; - ty = SPACE; - } else { - side |= BOTTOM; - by = y - (height + SPACE); - ty = 0; - } - pixmap = makePixmap(scr, width, height, side, &mask); - - drawMultiLineString(scr->wmscreen, pixmap, scr->black, font, 8, ty + 2, - text, strlen(text)); - - XSetWindowBackgroundPixmap(dpy, scr->balloon->window, pixmap); - scr->balloon->contents = pixmap; - - XResizeWindow(dpy, scr->balloon->window, width, height + SPACE); - XShapeCombineMask(dpy, scr->balloon->window, ShapeBounding, 0, 0, mask, - ShapeSet); - XFreePixmap(dpy, mask); - XMoveWindow(dpy, scr->balloon->window, bx, by); - XMapRaised(dpy, scr->balloon->window); - - - scr->balloon->mapped = 1; -} -#else /* !SHAPED_BALLOON */ - - -static void -showText(WScreen *scr, int x, int y, int h, int w, char *text) -{ - int width; - int height; - Pixmap pixmap; - WMFont *font = scr->info_text_font; - - if (scr->balloon->contents) - XFreePixmap(dpy, scr->balloon->contents); - - width = getMaxStringWidth(font, text) + 8; - /*width = WMWidthOfString(font, text, strlen(text))+8;*/ - height = countLines(text) * WMFontHeight(font) + 4; - - if (x < 0) - x = 0; - else if (x + width > scr->scr_width - 1) - x = scr->scr_width - width; - - if (y - height - 2 < 0) { - y += h; - if (y < 0) - y = 0; - } else { - y -= height + 2; - } - - if (scr->window_title_texture[0]) - XSetForeground(dpy, scr->draw_gc, - scr->window_title_texture[0]->any.color.pixel); - else - XSetForeground(dpy, scr->draw_gc, scr->light_pixel); - - pixmap = - XCreatePixmap(dpy, scr->root_win, width, height, scr->w_depth); - XFillRectangle(dpy, pixmap, scr->draw_gc, 0, 0, width, height); - - drawMultiLineString(scr->wmscreen, pixmap, scr->window_title_color[0], - font, 4, 2, text, strlen(text)); - - XResizeWindow(dpy, scr->balloon->window, width, height); - XMoveWindow(dpy, scr->balloon->window, x, y); - - XSetWindowBackgroundPixmap(dpy, scr->balloon->window, pixmap); - XClearWindow(dpy, scr->balloon->window); - XMapRaised(dpy, scr->balloon->window); - - scr->balloon->contents = pixmap; - - scr->balloon->mapped = 1; -} -#endif /* !SHAPED_BALLOON */ - - -static void -showBalloon(WScreen *scr) -{ - int x, y; - Window foow; - unsigned foo, w; - - if (scr->balloon) { - scr->balloon->timer = NULL; - scr->balloon->ignoreTimer = 1; - } - - if (!XGetGeometry(dpy, scr->balloon->objectWindow, &foow, &x, &y, - &w, &foo, &foo, &foo)) { - scr->balloon->prevType = 0; - return; - } - showText(scr, x, y, scr->balloon->h, w, scr->balloon->text); -} - - -static void -frameBalloon(WObjDescriptor *object) -{ - WFrameWindow *fwin = (WFrameWindow *) object->parent; - WScreen *scr = fwin->core->screen_ptr; - - if (fwin->titlebar != object->self - || !fwin->flags.is_client_window_frame) { - wBalloonHide(scr); - return; - } - if (fwin->title && fwin->flags.incomplete_title) { - scr->balloon->h = (fwin->titlebar ? fwin->titlebar->height : 0); - scr->balloon->text = wstrdup(fwin->title); - scr->balloon->objectWindow = fwin->core->window; - scr->balloon->timer = WMAddTimerHandler(BALLOON_DELAY, - (WMCallback *) showBalloon, - scr); - } -} - - -static void -miniwindowBalloon(WObjDescriptor *object) -{ - WIcon *icon = (WIcon *) object->parent; - WScreen *scr = icon->core->screen_ptr; - - if (!icon->icon_name) { - wBalloonHide(scr); - return; - } - scr->balloon->h = icon->core->height; - scr->balloon->text = wstrdup(icon->icon_name); - scr->balloon->objectWindow = icon->core->window; - if ((scr->balloon->prevType == object->parent_type - || scr->balloon->prevType == WCLASS_APPICON) - && scr->balloon->ignoreTimer) { - XUnmapWindow(dpy, scr->balloon->window); - showBalloon(scr); - } else { - scr->balloon->timer = WMAddTimerHandler(BALLOON_DELAY, - (WMCallback *) showBalloon, - scr); - } -} - - -static void -appiconBalloon(WObjDescriptor *object) -{ - WAppIcon *aicon = (WAppIcon *) object->parent; - WScreen *scr = aicon->icon->core->screen_ptr; - char *tmp; - - if (aicon->command && aicon->wm_class) { - int len = strlen(aicon->command) + strlen(aicon->wm_class) + 8; - tmp = wmalloc(len); - snprintf(tmp, len, "%s\n(%s)", aicon->wm_class, aicon->command); - scr->balloon->text = tmp; - } else if (aicon->command) { - scr->balloon->text = wstrdup(aicon->command); - } else if (aicon->wm_class) { - scr->balloon->text = wstrdup(aicon->wm_class); - } else { - wBalloonHide(scr); - return; - } - scr->balloon->h = aicon->icon->core->height - 2; - - scr->balloon->objectWindow = aicon->icon->core->window; - if ((scr->balloon->prevType == object->parent_type - || scr->balloon->prevType == WCLASS_MINIWINDOW) - && scr->balloon->ignoreTimer) { - XUnmapWindow(dpy, scr->balloon->window); - showBalloon(scr); - } else { - scr->balloon->timer = WMAddTimerHandler(BALLOON_DELAY, - (WMCallback *) showBalloon, - scr); - } -} - - - -void -wBalloonInitialize(WScreen *scr) -{ - WBalloon *bal; - XSetWindowAttributes attribs; - unsigned long vmask; - - bal = wmalloc(sizeof(WBalloon)); - memset(bal, 0, sizeof(WBalloon)); - - scr->balloon = bal; - - vmask = CWSaveUnder | CWOverrideRedirect | CWColormap | CWBackPixel - | CWBorderPixel; - attribs.save_under = True; - attribs.override_redirect = True; - attribs.colormap = scr->w_colormap; - attribs.background_pixel = scr->icon_back_texture->normal.pixel; - attribs.border_pixel = 0; /* do not care */ - - bal->window = XCreateWindow(dpy, scr->root_win, 1, 1, 10, 10, 1, - scr->w_depth, CopyFromParent, - scr->w_visual, vmask, &attribs); -#if 0 - /* select EnterNotify to so that the balloon will be unmapped - * when the pointer is moved over it */ - XSelectInput(dpy, bal->window, EnterWindowMask); -#endif -} - - -void -wBalloonEnteredObject(WScreen *scr, WObjDescriptor *object) -{ - WBalloon *balloon = scr->balloon; - - if (balloon->timer) { - WMDeleteTimerHandler(balloon->timer); - balloon->timer = NULL; - balloon->ignoreTimer = 0; - } - - if (scr->balloon->text) - wfree(scr->balloon->text); - scr->balloon->text = NULL; - - if (!object) { - wBalloonHide(scr); - balloon->ignoreTimer = 0; - return; - } - switch (object->parent_type) { - case WCLASS_FRAME: - if (wPreferences.window_balloon) { - frameBalloon(object); - } - break; - - case WCLASS_DOCK_ICON: - if (object->parent != scr->clip_icon - && wPreferences.appicon_balloon) - appiconBalloon(object); - else - wBalloonHide(scr); - break; - - case WCLASS_MINIWINDOW: - if (wPreferences.miniwin_balloon) { - miniwindowBalloon(object); - } - break; - case WCLASS_APPICON: - if (wPreferences.appicon_balloon) - appiconBalloon(object); - break; - default: - wBalloonHide(scr); - break; - } - scr->balloon->prevType = object->parent_type; -} - - - -void -wBalloonHide(WScreen *scr) -{ - if (scr) { - if (scr->balloon->mapped) { - XUnmapWindow(dpy, scr->balloon->window); - scr->balloon->mapped = 0; - } else if (scr->balloon->timer) { - WMDeleteTimerHandler(scr->balloon->timer); - scr->balloon->timer = NULL; - } - scr->balloon->prevType = 0; - } -} - -#endif - +/* + * Window Maker window manager + * + * Copyright (c) 1998-2003 Alfredo K. Kojima + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +#include "wconfig.h" + +#ifdef BALLOON_TEXT + +#include +#include +#ifdef SHAPED_BALLOON +#include +#endif + +#include +#include + +#include + +#include "WindowMaker.h" +#include "screen.h" +#include "texture.h" +#include "wcore.h" +#include "framewin.h" +#include "icon.h" +#include "appicon.h" +#include "funcs.h" +#include "workspace.h" +#include "balloon.h" + +extern WPreferences wPreferences; + +typedef struct _WBalloon { + Window window; + +#ifdef SHAPED_BALLOON + GC monoGC; +#endif + int prevType; + + Window objectWindow; + char *text; + int h; + + WMHandlerID timer; + + Pixmap contents; + + char mapped; + char ignoreTimer; +} WBalloon; + +#define TOP 0 +#define BOTTOM 1 +#define LEFT 0 +#define RIGHT 2 + +#define TLEFT (TOP|LEFT) +#define TRIGHT (TOP|RIGHT) +#define BLEFT (BOTTOM|LEFT) +#define BRIGHT (BOTTOM|RIGHT) + +static int countLines(const char *text) +{ + const char *p = text; + int h = 1; + + while (*p) { + if (*p == '\n' && p[1] != 0) + h++; + p++; + } + return h; +} + +static int getMaxStringWidth(WMFont * font, char *text) +{ + char *p = text; + char *pb = p; + int pos = 0; + int w = 0, wt; + + while (*p) { + if (*p == '\n') { + wt = WMWidthOfString(font, pb, pos); + if (wt > w) + w = wt; + pos = 0; + pb = p + 1; + } else { + pos++; + } + p++; + } + if (pos > 0) { + wt = WMWidthOfString(font, pb, pos); + if (wt > w) + w = wt; + } + return w; +} + +static void +drawMultiLineString(WMScreen * scr, Pixmap pixmap, WMColor * color, + WMFont * font, int x, int y, char *text, int len) +{ + char *p = text; + char *pb = p; + int l = 0, pos = 0; + int height = WMFontHeight(font); + + while (*p && p - text < len) { + if (*p == '\n') { + WMDrawString(scr, pixmap, color, font, x, y + l * height, pb, pos); + l++; + pos = 0; + pb = p + 1; + } else { + pos++; + } + p++; + } + if (pos > 0) { + WMDrawString(scr, pixmap, color, font, x, y + l * height, pb, pos); + } +} + +#ifdef SHAPED_BALLOON + +#define SPACE 12 + +static void drawBalloon(WScreen * scr, Pixmap bitmap, Pixmap pix, int x, int y, int w, int h, int side) +{ + GC bgc = scr->balloon->monoGC; + GC gc = scr->draw_gc; + int rad = h * 3 / 10; + XPoint pt[3], ipt[3]; + int w1; + + /* outline */ + XSetForeground(dpy, bgc, 1); + + XFillArc(dpy, bitmap, bgc, x, y, rad, rad, 90 * 64, 90 * 64); + XFillArc(dpy, bitmap, bgc, x, y + h - 1 - rad, rad, rad, 180 * 64, 90 * 64); + + XFillArc(dpy, bitmap, bgc, x + w - 1 - rad, y, rad, rad, 0 * 64, 90 * 64); + XFillArc(dpy, bitmap, bgc, x + w - 1 - rad, y + h - 1 - rad, rad, rad, 270 * 64, 90 * 64); + + XFillRectangle(dpy, bitmap, bgc, x, y + rad / 2, w, h - rad); + XFillRectangle(dpy, bitmap, bgc, x + rad / 2, y, w - rad, h); + + /* interior */ + XSetForeground(dpy, gc, scr->white_pixel); + + XFillArc(dpy, pix, gc, x + 1, y + 1, rad, rad, 90 * 64, 90 * 64); + XFillArc(dpy, pix, gc, x + 1, y + h - 2 - rad, rad, rad, 180 * 64, 90 * 64); + + XFillArc(dpy, pix, gc, x + w - 2 - rad, y + 1, rad, rad, 0 * 64, 90 * 64); + XFillArc(dpy, pix, gc, x + w - 2 - rad, y + h - 2 - rad, rad, rad, 270 * 64, 90 * 64); + + XFillRectangle(dpy, pix, gc, x + 1, y + 1 + rad / 2, w - 2, h - 2 - rad); + XFillRectangle(dpy, pix, gc, x + 1 + rad / 2, y + 1, w - 2 - rad, h - 2); + + if (side & BOTTOM) { + pt[0].y = y + h - 1; + pt[1].y = y + h - 1 + SPACE; + pt[2].y = y + h - 1; + ipt[0].y = pt[0].y - 1; + ipt[1].y = pt[1].y - 1; + ipt[2].y = pt[2].y - 1; + } else { + pt[0].y = y; + pt[1].y = y - SPACE; + pt[2].y = y; + ipt[0].y = pt[0].y + 1; + ipt[1].y = pt[1].y + 1; + ipt[2].y = pt[2].y + 1; + } + + /*w1 = WMAX(h, 24); */ + w1 = WMAX(h, 21); + + if (side & RIGHT) { + pt[0].x = x + w - w1 + 2 * w1 / 16; + pt[1].x = x + w - w1 + 11 * w1 / 16; + pt[2].x = x + w - w1 + 7 * w1 / 16; + ipt[0].x = x + 1 + w - w1 + 2 * (w1 - 1) / 16; + ipt[1].x = x + 1 + w - w1 + 11 * (w1 - 1) / 16; + ipt[2].x = x + 1 + w - w1 + 7 * (w1 - 1) / 16; + /*ipt[0].x = pt[0].x+1; + ipt[1].x = pt[1].x; + ipt[2].x = pt[2].x; */ + } else { + pt[0].x = x + w1 - 2 * w1 / 16; + pt[1].x = x + w1 - 11 * w1 / 16; + pt[2].x = x + w1 - 7 * w1 / 16; + ipt[0].x = x - 1 + w1 - 2 * (w1 - 1) / 16; + ipt[1].x = x - 1 + w1 - 11 * (w1 - 1) / 16; + ipt[2].x = x - 1 + w1 - 7 * (w1 - 1) / 16; + /*ipt[0].x = pt[0].x-1; + ipt[1].x = pt[1].x; + ipt[2].x = pt[2].x; */ + } + + XFillPolygon(dpy, bitmap, bgc, pt, 3, Convex, CoordModeOrigin); + XFillPolygon(dpy, pix, gc, ipt, 3, Convex, CoordModeOrigin); + + /* fix outline */ + XSetForeground(dpy, gc, scr->black_pixel); + + XDrawLines(dpy, pix, gc, pt, 3, CoordModeOrigin); + if (side & RIGHT) { + pt[0].x++; + pt[2].x--; + } else { + pt[0].x--; + pt[2].x++; + } + XDrawLines(dpy, pix, gc, pt, 3, CoordModeOrigin); +} + +static Pixmap makePixmap(WScreen * scr, int width, int height, int side, Pixmap * mask) +{ + WBalloon *bal = scr->balloon; + Pixmap bitmap; + Pixmap pixmap; + int x, y; + + bitmap = XCreatePixmap(dpy, scr->root_win, width + SPACE, height + SPACE, 1); + + if (!bal->monoGC) { + bal->monoGC = XCreateGC(dpy, bitmap, 0, NULL); + } + XSetForeground(dpy, bal->monoGC, 0); + XFillRectangle(dpy, bitmap, bal->monoGC, 0, 0, width + SPACE, height + SPACE); + + pixmap = XCreatePixmap(dpy, scr->root_win, width + SPACE, height + SPACE, scr->w_depth); + XSetForeground(dpy, scr->draw_gc, scr->black_pixel); + XFillRectangle(dpy, pixmap, scr->draw_gc, 0, 0, width + SPACE, height + SPACE); + + if (side & BOTTOM) { + y = 0; + } else { + y = SPACE; + } + x = 0; + + drawBalloon(scr, bitmap, pixmap, x, y, width, height, side); + + *mask = bitmap; + + return pixmap; +} + +static void showText(WScreen * scr, int x, int y, int h, int w, char *text) +{ + int width; + int height; + Pixmap pixmap; + Pixmap mask; + WMFont *font = scr->info_text_font; + int side = 0; + int ty; + int bx, by; + + if (scr->balloon->contents) + XFreePixmap(dpy, scr->balloon->contents); + + width = getMaxStringWidth(font, text) + 16; + height = countLines(text) * WMFontHeight(font) + 4; + + if (height < 16) + height = 16; + if (width < height) + width = height; + + if (x + width > scr->scr_width) { + side = RIGHT; + bx = x - width + w / 2; + if (bx < 0) + bx = 0; + } else { + side = LEFT; + bx = x + w / 2; + } + if (bx + width > scr->scr_width) + bx = scr->scr_width - width; + + if (y - (height + SPACE) < 0) { + side |= TOP; + by = y + h - 1; + ty = SPACE; + } else { + side |= BOTTOM; + by = y - (height + SPACE); + ty = 0; + } + pixmap = makePixmap(scr, width, height, side, &mask); + + drawMultiLineString(scr->wmscreen, pixmap, scr->black, font, 8, ty + 2, text, strlen(text)); + + XSetWindowBackgroundPixmap(dpy, scr->balloon->window, pixmap); + scr->balloon->contents = pixmap; + + XResizeWindow(dpy, scr->balloon->window, width, height + SPACE); + XShapeCombineMask(dpy, scr->balloon->window, ShapeBounding, 0, 0, mask, ShapeSet); + XFreePixmap(dpy, mask); + XMoveWindow(dpy, scr->balloon->window, bx, by); + XMapRaised(dpy, scr->balloon->window); + + scr->balloon->mapped = 1; +} +#else /* !SHAPED_BALLOON */ + +static void showText(WScreen * scr, int x, int y, int h, int w, char *text) +{ + int width; + int height; + Pixmap pixmap; + WMFont *font = scr->info_text_font; + + if (scr->balloon->contents) + XFreePixmap(dpy, scr->balloon->contents); + + width = getMaxStringWidth(font, text) + 8; + /*width = WMWidthOfString(font, text, strlen(text))+8; */ + height = countLines(text) * WMFontHeight(font) + 4; + + if (x < 0) + x = 0; + else if (x + width > scr->scr_width - 1) + x = scr->scr_width - width; + + if (y - height - 2 < 0) { + y += h; + if (y < 0) + y = 0; + } else { + y -= height + 2; + } + + if (scr->window_title_texture[0]) + XSetForeground(dpy, scr->draw_gc, scr->window_title_texture[0]->any.color.pixel); + else + XSetForeground(dpy, scr->draw_gc, scr->light_pixel); + + pixmap = XCreatePixmap(dpy, scr->root_win, width, height, scr->w_depth); + XFillRectangle(dpy, pixmap, scr->draw_gc, 0, 0, width, height); + + drawMultiLineString(scr->wmscreen, pixmap, scr->window_title_color[0], font, 4, 2, text, strlen(text)); + + XResizeWindow(dpy, scr->balloon->window, width, height); + XMoveWindow(dpy, scr->balloon->window, x, y); + + XSetWindowBackgroundPixmap(dpy, scr->balloon->window, pixmap); + XClearWindow(dpy, scr->balloon->window); + XMapRaised(dpy, scr->balloon->window); + + scr->balloon->contents = pixmap; + + scr->balloon->mapped = 1; +} +#endif /* !SHAPED_BALLOON */ + +static void showBalloon(WScreen * scr) +{ + int x, y; + Window foow; + unsigned foo, w; + + if (scr->balloon) { + scr->balloon->timer = NULL; + scr->balloon->ignoreTimer = 1; + } + + if (!XGetGeometry(dpy, scr->balloon->objectWindow, &foow, &x, &y, &w, &foo, &foo, &foo)) { + scr->balloon->prevType = 0; + return; + } + showText(scr, x, y, scr->balloon->h, w, scr->balloon->text); +} + +static void frameBalloon(WObjDescriptor * object) +{ + WFrameWindow *fwin = (WFrameWindow *) object->parent; + WScreen *scr = fwin->core->screen_ptr; + + if (fwin->titlebar != object->self || !fwin->flags.is_client_window_frame) { + wBalloonHide(scr); + return; + } + if (fwin->title && fwin->flags.incomplete_title) { + scr->balloon->h = (fwin->titlebar ? fwin->titlebar->height : 0); + scr->balloon->text = wstrdup(fwin->title); + scr->balloon->objectWindow = fwin->core->window; + scr->balloon->timer = WMAddTimerHandler(BALLOON_DELAY, (WMCallback *) showBalloon, scr); + } +} + +static void miniwindowBalloon(WObjDescriptor * object) +{ + WIcon *icon = (WIcon *) object->parent; + WScreen *scr = icon->core->screen_ptr; + + if (!icon->icon_name) { + wBalloonHide(scr); + return; + } + scr->balloon->h = icon->core->height; + scr->balloon->text = wstrdup(icon->icon_name); + scr->balloon->objectWindow = icon->core->window; + if ((scr->balloon->prevType == object->parent_type || scr->balloon->prevType == WCLASS_APPICON) + && scr->balloon->ignoreTimer) { + XUnmapWindow(dpy, scr->balloon->window); + showBalloon(scr); + } else { + scr->balloon->timer = WMAddTimerHandler(BALLOON_DELAY, (WMCallback *) showBalloon, scr); + } +} + +static void appiconBalloon(WObjDescriptor * object) +{ + WAppIcon *aicon = (WAppIcon *) object->parent; + WScreen *scr = aicon->icon->core->screen_ptr; + char *tmp; + + if (aicon->command && aicon->wm_class) { + int len = strlen(aicon->command) + strlen(aicon->wm_class) + 8; + tmp = wmalloc(len); + snprintf(tmp, len, "%s\n(%s)", aicon->wm_class, aicon->command); + scr->balloon->text = tmp; + } else if (aicon->command) { + scr->balloon->text = wstrdup(aicon->command); + } else if (aicon->wm_class) { + scr->balloon->text = wstrdup(aicon->wm_class); + } else { + wBalloonHide(scr); + return; + } + scr->balloon->h = aicon->icon->core->height - 2; + + scr->balloon->objectWindow = aicon->icon->core->window; + if ((scr->balloon->prevType == object->parent_type || scr->balloon->prevType == WCLASS_MINIWINDOW) + && scr->balloon->ignoreTimer) { + XUnmapWindow(dpy, scr->balloon->window); + showBalloon(scr); + } else { + scr->balloon->timer = WMAddTimerHandler(BALLOON_DELAY, (WMCallback *) showBalloon, scr); + } +} + +void wBalloonInitialize(WScreen * scr) +{ + WBalloon *bal; + XSetWindowAttributes attribs; + unsigned long vmask; + + bal = wmalloc(sizeof(WBalloon)); + memset(bal, 0, sizeof(WBalloon)); + + scr->balloon = bal; + + vmask = CWSaveUnder | CWOverrideRedirect | CWColormap | CWBackPixel | CWBorderPixel; + attribs.save_under = True; + attribs.override_redirect = True; + attribs.colormap = scr->w_colormap; + attribs.background_pixel = scr->icon_back_texture->normal.pixel; + attribs.border_pixel = 0; /* do not care */ + + bal->window = XCreateWindow(dpy, scr->root_win, 1, 1, 10, 10, 1, + scr->w_depth, CopyFromParent, scr->w_visual, vmask, &attribs); +#if 0 + /* select EnterNotify to so that the balloon will be unmapped + * when the pointer is moved over it */ + XSelectInput(dpy, bal->window, EnterWindowMask); +#endif +} + +void wBalloonEnteredObject(WScreen * scr, WObjDescriptor * object) +{ + WBalloon *balloon = scr->balloon; + + if (balloon->timer) { + WMDeleteTimerHandler(balloon->timer); + balloon->timer = NULL; + balloon->ignoreTimer = 0; + } + + if (scr->balloon->text) + wfree(scr->balloon->text); + scr->balloon->text = NULL; + + if (!object) { + wBalloonHide(scr); + balloon->ignoreTimer = 0; + return; + } + switch (object->parent_type) { + case WCLASS_FRAME: + if (wPreferences.window_balloon) { + frameBalloon(object); + } + break; + + case WCLASS_DOCK_ICON: + if (object->parent != scr->clip_icon && wPreferences.appicon_balloon) + appiconBalloon(object); + else + wBalloonHide(scr); + break; + + case WCLASS_MINIWINDOW: + if (wPreferences.miniwin_balloon) { + miniwindowBalloon(object); + } + break; + case WCLASS_APPICON: + if (wPreferences.appicon_balloon) + appiconBalloon(object); + break; + default: + wBalloonHide(scr); + break; + } + scr->balloon->prevType = object->parent_type; +} + +void wBalloonHide(WScreen * scr) +{ + if (scr) { + if (scr->balloon->mapped) { + XUnmapWindow(dpy, scr->balloon->window); + scr->balloon->mapped = 0; + } else if (scr->balloon->timer) { + WMDeleteTimerHandler(scr->balloon->timer); + scr->balloon->timer = NULL; + } + scr->balloon->prevType = 0; + } +} + +#endif