tsst
[skippy-xd] / tooltip.c
1 /* Skippy - Seduces Kids Into Perversion
2  *
3  * Copyright (C) 2004 Hyriand <hyriand@thegraveyard.org>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  */
19
20 #include "skippy.h"
21
22 void
23 tooltip_destroy(Tooltip *tt)
24 {
25         if(tt->text)
26                 free(tt->text);
27         if(tt->font)
28                 XftFontClose(tt->mainwin->dpy, tt->font);
29         if(tt->draw)
30                 XftDrawDestroy(tt->draw);
31         if(tt->color.pixel != None)
32                 XftColorFree(tt->mainwin->dpy,
33                              tt->mainwin->visual,
34                              tt->mainwin->colormap,
35                              &tt->color);
36         if(tt->background.pixel != None)
37                 XftColorFree(tt->mainwin->dpy,
38                              tt->mainwin->visual,
39                              tt->mainwin->colormap,
40                              &tt->background);
41         if(tt->border.pixel != None)
42                 XftColorFree(tt->mainwin->dpy,
43                              tt->mainwin->visual,
44                              tt->mainwin->colormap,
45                              &tt->border);
46         if(tt->shadow.pixel != None)
47                 XftColorFree(tt->mainwin->dpy,
48                              tt->mainwin->visual,
49                              tt->mainwin->colormap,
50                              &tt->shadow);
51         if(tt->window != None)
52                 XDestroyWindow(tt->mainwin->dpy, tt->window);
53         
54         free(tt);
55 }
56
57 Tooltip *
58 tooltip_create(MainWin *mw, dlist *config)
59 {
60         Tooltip *tt;
61         XSetWindowAttributes attr;
62         const char *tmp;
63         long int tmp_l;
64         
65         tt = (Tooltip *)malloc(sizeof(Tooltip));
66         if(! tt)
67                 return 0;
68         
69         tt->mainwin = mw;
70         tt->window = None;
71         tt->font = 0;
72         tt->draw = 0;
73         tt->text = 0;
74         tt->color.pixel = tt->background.pixel = tt->border.pixel = tt->shadow.pixel = None;
75         
76         attr.override_redirect = True;
77         attr.border_pixel = None;
78         attr.background_pixel = None;
79         attr.event_mask = ExposureMask;
80         attr.colormap = mw->colormap;
81         
82         tt->window = XCreateWindow(mw->dpy, mw->root,
83                                    0, 0, 1, 1, 0,
84                                    mw->depth, InputOutput, mw->visual,
85                                    CWBorderPixel|CWBackPixel|CWOverrideRedirect|CWEventMask|CWColormap,
86                                    &attr);
87         if(tt->window == None)
88         {
89                 fprintf(stderr, "WARNING: Couldn't create tooltip window.\n");
90                 tooltip_destroy(tt);
91                 return 0;
92         }
93         
94         tmp = config_get(config, "tooltip", "border", "#e0e0e0");
95         if(! XftColorAllocName(mw->dpy, mw->visual, mw->colormap, tmp, &tt->border))
96         {
97                 fprintf(stderr, "WARNING: Invalid color '%s'.\n", tmp);
98                 tooltip_destroy(tt);
99                 return 0;
100         }
101         
102         tmp = config_get(config, "tooltip", "background", "#404040");
103         if(! XftColorAllocName(mw->dpy, mw->visual, mw->colormap, tmp, &tt->background))
104         {
105                 fprintf(stderr, "WARNING: Invalid color '%s'.\n", tmp);
106                 tooltip_destroy(tt);
107                 return 0;
108         }
109         
110         tmp = config_get(config, "tooltip", "opacity", "128");
111         tmp_l = MIN(MAX(0, strtol(tmp, 0, 0) * 256), 65535);
112         tt->background.color.alpha = tmp_l;
113         tt->border.color.alpha = tmp_l;
114         
115         tmp = config_get(config, "tooltip", "text", "#e0e0e0");
116         if(! XftColorAllocName(mw->dpy, mw->visual, mw->colormap, tmp, &tt->color))
117         {
118                 fprintf(stderr, "WARNING: Couldn't allocate color '%s'.\n", tmp);
119                 tooltip_destroy(tt);
120                 return 0;
121         }
122         
123         tmp = config_get(config, "tooltip", "textShadow", "black");
124         if(strcasecmp(tmp, "none") != 0)
125         {
126                 if(! XftColorAllocName(mw->dpy, mw->visual, mw->colormap, tmp, &tt->shadow))
127                 {
128                         fprintf(stderr, "WARNING: Couldn't allocate color '%s'.\n", tmp);
129                         tooltip_destroy(tt);
130                         return 0;
131                 }
132         }
133         
134         tt->draw = XftDrawCreate(mw->dpy, tt->window, mw->visual, mw->colormap);
135         if(! tt->draw)
136         {
137                 fprintf(stderr, "WARNING: Couldn't create Xft draw surface.\n");
138                 tooltip_destroy(tt);
139                 return 0;
140         }
141         
142         tt->font = XftFontOpenName(mw->dpy, mw->screen, config_get(config, "tooltip", "font", "fixed-11:weight=bold"));
143         if(! tt->font)
144         {
145                 fprintf(stderr, "WARNING: Couldn't open Xft font.\n");
146                 tooltip_destroy(tt);
147                 return 0;
148         }
149         
150         tt->font_height = tt->font->ascent + tt->font->descent;
151         
152         return tt;
153 }
154
155 void
156 tooltip_map(Tooltip *tt, int x, int y, const FcChar8 *text, int len)
157 {
158         XUnmapWindow(tt->mainwin->dpy, tt->window);
159         
160         XftTextExtents8(tt->mainwin->dpy, tt->font, text, len, &tt->extents);
161         
162         tt->width = tt->extents.width + 8;
163         tt->height = tt->font_height + 5 + (tt->shadow.pixel ? 2 : 0);
164         XResizeWindow(tt->mainwin->dpy, tt->window, tt->width, tt->height);
165         tooltip_move(tt, x, y);
166         
167         if(tt->text)
168                 free(tt->text);
169         
170         tt->text = (FcChar8 *)malloc(len);
171         memcpy(tt->text, text, len);
172         
173         tt->text_len = len;
174         
175         XMapWindow(tt->mainwin->dpy, tt->window);
176         XRaiseWindow(tt->mainwin->dpy, tt->window);
177 }
178
179 void
180 tooltip_move(Tooltip *tt, int x, int y)
181 {
182         if(x + tt->extents.width + 9 > tt->mainwin->x + tt->mainwin->width)
183                 x = tt->mainwin->x + tt->mainwin->width - tt->extents.width - 9;
184         x = MAX(0, x);
185         
186         if(y + tt->extents.height + 8 > tt->mainwin->y + tt->mainwin->height)
187                 y = tt->mainwin->height + tt->mainwin->y - tt->extents.height - 8;
188         y = MAX(0, y);
189         
190         XMoveWindow(tt->mainwin->dpy, tt->window, x, y);
191 }
192
193 void
194 tooltip_unmap(Tooltip *tt)
195 {
196         XUnmapWindow(tt->mainwin->dpy, tt->window);
197         if(tt->text)
198                 free(tt->text);
199         tt->text = 0;
200         tt->text_len = 0;
201 }
202
203 void
204 tooltip_handle(Tooltip *tt, XEvent *ev)
205 {
206         if(! tt->text)
207                 return;
208         
209         if(ev->type == Expose && ev->xexpose.count == 0)
210         {
211                 XftDrawRect(tt->draw, &tt->border, 0, 0, tt->width, 1);
212                 XftDrawRect(tt->draw, &tt->border, 0, 1, 1, tt->height - 2);
213                 XftDrawRect(tt->draw, &tt->border, 0, tt->height - 1, tt->width, 1);
214                 XftDrawRect(tt->draw, &tt->border, tt->width - 1, 1, 1, tt->height - 2);
215                 XftDrawRect(tt->draw, &tt->background, 1, 1, tt->width - 2, tt->height - 2);
216                 if(tt->shadow.pixel)
217                         XftDrawString8(tt->draw, &tt->shadow, tt->font, 6, 3 + tt->extents.y + (tt->font_height - tt->extents.y) / 2, tt->text, tt->text_len);
218                 XftDrawString8(tt->draw, &tt->color, tt->font, 4, 1 + tt->extents.y + (tt->font_height - tt->extents.y) / 2, tt->text, tt->text_len);
219         }
220 }