fixed to accomodate the changes to the render/ API.
[dana/openbox.git] / openbox / popup.c
1 #include "openbox.h"
2 #include "frame.h"
3 #include "window.h"
4 #include "stacking.h"
5 #include "render/render.h"
6 #include "render/theme.h"
7
8 typedef struct Popup {
9     ObWindow obwin;
10     Window bg;
11
12     Window icon;
13     Window text;
14
15     gboolean hasicon;
16     RrAppearance *a_bg;
17     RrAppearance *a_icon;
18     RrAppearance *a_text;
19     int gravity;
20     int x;
21     int y;
22     int w;
23     int h;
24     gboolean mapped;
25 } Popup;
26
27 Popup *popup_new(gboolean hasicon)
28 {
29     Popup *self = g_new(Popup, 1);
30     self->obwin.type = Window_Internal;
31     self->hasicon = hasicon;
32     self->bg = None;
33     self->a_text = NULL;
34     self->gravity = NorthWestGravity;
35     self->x = self->y = self->w = self->h = 0;
36     self->mapped = FALSE;
37     stacking_add(INTERNAL_AS_WINDOW(self));
38     stacking_raise(INTERNAL_AS_WINDOW(self));
39     return self;
40 }
41
42 void popup_free(Popup *self)
43 {
44     if (self->bg) {
45         XDestroyWindow(ob_display, self->bg);
46         XDestroyWindow(ob_display, self->text);
47         XDestroyWindow(ob_display, self->icon);
48         RrAppearanceFree(self->a_bg);
49         if (self->hasicon)
50             RrAppearanceFree(self->a_icon);
51     }
52     if (self->a_text)
53         RrAppearanceFree(self->a_text);
54     stacking_remove(self);
55     g_free(self);
56 }
57
58 void popup_position(Popup *self, int gravity, int x, int y)
59 {
60     self->gravity = gravity;
61     self->x = x;
62     self->y = y;
63 }
64
65 void popup_size(Popup *self, int w, int h)
66 {
67     self->w = w;
68     self->h = h;
69 }
70
71 void popup_size_to_string(Popup *self, char *text)
72 {
73     int textw, texth;
74     int iconw;
75
76     if (!self->a_text)
77         self->a_text = RrAppearanceCopy(theme_app_hilite_label);
78
79     self->a_text->texture[0].data.text.string = text;
80     RrMinsize(self->a_text, &textw, &texth);
81     textw += theme_bevel * 2;
82     texth += theme_bevel * 2;
83
84     self->h = texth + theme_bevel * 2;
85     iconw = (self->hasicon ? texth : 0);
86     self->w = textw + iconw + theme_bevel * (self->hasicon ? 3 : 2);
87 }
88
89 void popup_show(Popup *self, char *text, Icon *icon)
90 {
91     XSetWindowAttributes attrib;
92     int x, y, w, h;
93     int textw, texth;
94     int iconw;
95
96     /* create the shit if needed */
97     if (!self->bg) {
98         attrib.override_redirect = True;
99         self->bg = XCreateWindow(ob_display, ob_root,
100                                  0, 0, 1, 1, 0, RrDepth(ob_rr_inst),
101                                  InputOutput, RrVisual(ob_rr_inst),
102                                  CWOverrideRedirect, &attrib);
103
104         XSetWindowBorderWidth(ob_display, self->bg, theme_bwidth);
105         XSetWindowBorder(ob_display, self->bg, theme_b_color->pixel);
106
107         self->text = XCreateWindow(ob_display, self->bg,
108                                    0, 0, 1, 1, 0, RrDepth(ob_rr_inst),
109                                    InputOutput, RrVisual(ob_rr_inst), 0, NULL);
110         if (self->hasicon)
111             self->icon = XCreateWindow(ob_display, self->bg,
112                                        0, 0, 1, 1, 0,
113                                        RrDepth(ob_rr_inst), InputOutput,
114                                        RrVisual(ob_rr_inst), 0, NULL);
115
116         XMapWindow(ob_display, self->text);
117         XMapWindow(ob_display, self->icon);
118
119         self->a_bg = RrAppearanceCopy(theme_app_hilite_bg);
120         if (self->hasicon)
121             self->a_icon = RrAppearanceCopy(theme_app_icon);
122     }
123     if (!self->a_text)
124         self->a_text = RrAppearanceCopy(theme_app_hilite_label);
125
126     /* set up the textures */
127     self->a_text->texture[0].data.text.string = text;
128     if (self->hasicon) {
129         if (icon) {
130             self->a_icon->texture[0].type = RR_TEXTURE_RGBA;
131             self->a_icon->texture[0].data.rgba.width = icon->width;
132             self->a_icon->texture[0].data.rgba.height = icon->height;
133             self->a_icon->texture[0].data.rgba.data = icon->data;
134         } else
135             self->a_icon->texture[0].type = RR_TEXTURE_NONE;
136     }
137
138     /* measure the shit out */
139     RrMinsize(self->a_text, &textw, &texth);
140     textw += theme_bevel * 2;
141     texth += theme_bevel * 2;
142
143     /* set the sizes up and reget the text sizes from the calculated
144        outer sizes */
145     if (self->h) {
146         h = self->h;
147         texth = h - (theme_bevel * 2);
148     } else
149         h = texth + theme_bevel * 2;
150     iconw = (self->hasicon ? texth : 0);
151     if (self->w) {
152         w = self->w;
153         textw = w - (iconw + theme_bevel * (self->hasicon ? 3 : 2));
154     } else
155         w = textw + iconw + theme_bevel * (self->hasicon ? 3 : 2);
156     /* sanity checks to avoid crashes! */
157     if (w < 1) w = 1;
158     if (h < 1) h = 1;
159     if (textw < 1) textw = 1;
160     if (texth < 1) texth = 1;
161
162     /* set up the x coord */
163     x = self->x;
164     switch (self->gravity) {
165     case NorthGravity:
166     case CenterGravity:
167     case SouthGravity:
168         x -= w / 2;
169         break;
170     case NorthEastGravity:
171     case EastGravity:
172     case SouthEastGravity:
173         x -= w;
174         break;
175     }
176
177     /* set up the y coord */
178     y = self->y;
179     switch (self->gravity) {
180     case WestGravity:
181     case CenterGravity:
182     case EastGravity:
183         y -= h / 2;
184         break;
185     case SouthWestGravity:
186     case SouthGravity:
187     case SouthEastGravity:
188         y -= h;
189         break;
190     }
191
192     /* set the windows/appearances up */
193     XMoveResizeWindow(ob_display, self->bg, x, y, w, h);
194
195     self->a_text->surface.parent = self->a_bg;
196     self->a_text->surface.parentx = iconw +
197         theme_bevel * (self->hasicon ? 2 : 1);
198     self->a_text->surface.parenty = theme_bevel;
199     XMoveResizeWindow(ob_display, self->text,
200                       iconw + theme_bevel * (self->hasicon ? 2 : 1),
201                       theme_bevel, textw, texth);
202
203     if (self->hasicon) {
204         if (iconw < 1) iconw = 1; /* sanity check for crashes */
205         self->a_icon->surface.parent = self->a_bg;
206         self->a_icon->surface.parentx = theme_bevel;
207         self->a_icon->surface.parenty = theme_bevel;
208         XMoveResizeWindow(ob_display, self->icon,
209                           theme_bevel, theme_bevel, iconw, texth);
210     }
211
212     RrPaint(self->a_bg, self->bg, w, h);
213     RrPaint(self->a_text, self->text, textw, texth);
214     if (self->hasicon)
215         RrPaint(self->a_icon, self->icon, iconw, texth);
216
217     if (!self->mapped) {
218         XMapWindow(ob_display, self->bg);
219         stacking_raise(INTERNAL_AS_WINDOW(self));
220         self->mapped = TRUE;
221     }
222 }
223
224 void popup_hide(Popup *self)
225 {
226     if (self->mapped) {
227         XUnmapWindow(ob_display, self->bg);
228         self->mapped = FALSE;
229     }
230 }