prefixing and capitalization for the Frame->ObFrame struct and the Context->ObFrameCo...
[mikachu/openbox.git] / openbox / popup.c
1 #include "openbox.h"
2 #include "frame.h"
3 #include "client.h"
4 #include "window.h"
5 #include "stacking.h"
6 #include "render/render.h"
7 #include "render/theme.h"
8
9 typedef struct Popup {
10     ObWindow obwin;
11     Window bg;
12
13     Window icon;
14     Window text;
15
16     gboolean hasicon;
17     RrAppearance *a_bg;
18     RrAppearance *a_icon;
19     RrAppearance *a_text;
20     int gravity;
21     int x;
22     int y;
23     int w;
24     int h;
25     gboolean mapped;
26 } Popup;
27
28 Popup *popup_new(gboolean hasicon)
29 {
30     XSetWindowAttributes attrib;
31     Popup *self = g_new(Popup, 1);
32
33     self->obwin.type = Window_Internal;
34     self->hasicon = hasicon;
35     self->a_text = NULL;
36     self->gravity = NorthWestGravity;
37     self->x = self->y = self->w = self->h = 0;
38     self->mapped = FALSE;
39     self->a_bg = self->a_icon = self->a_text = NULL;
40
41     attrib.override_redirect = True;
42     self->bg = XCreateWindow(ob_display, ob_root,
43                              0, 0, 1, 1, 0, RrDepth(ob_rr_inst),
44                              InputOutput, RrVisual(ob_rr_inst),
45                              CWOverrideRedirect, &attrib);
46     
47     self->text = XCreateWindow(ob_display, self->bg,
48                                0, 0, 1, 1, 0, RrDepth(ob_rr_inst),
49                                InputOutput, RrVisual(ob_rr_inst), 0, NULL);
50
51     if (self->hasicon)
52         self->icon = XCreateWindow(ob_display, self->bg,
53                                    0, 0, 1, 1, 0,
54                                    RrDepth(ob_rr_inst), InputOutput,
55                                    RrVisual(ob_rr_inst), 0, NULL);
56
57     XMapWindow(ob_display, self->text);
58     XMapWindow(ob_display, self->icon);
59
60     stacking_add(INTERNAL_AS_WINDOW(self));
61     return self;
62 }
63
64 void popup_free(Popup *self)
65 {
66     if (self) {
67         XDestroyWindow(ob_display, self->bg);
68         XDestroyWindow(ob_display, self->text);
69         XDestroyWindow(ob_display, self->icon);
70         RrAppearanceFree(self->a_bg);
71         RrAppearanceFree(self->a_icon);
72         RrAppearanceFree(self->a_text);
73         stacking_remove(self);
74         g_free(self);
75     }
76 }
77
78 void popup_position(Popup *self, int gravity, int x, int y)
79 {
80     self->gravity = gravity;
81     self->x = x;
82     self->y = y;
83 }
84
85 void popup_size(Popup *self, int w, int h)
86 {
87     self->w = w;
88     self->h = h;
89 }
90
91 void popup_size_to_string(Popup *self, char *text)
92 {
93     int textw, texth;
94     int iconw;
95
96     if (!self->a_text)
97         self->a_text = RrAppearanceCopy(ob_rr_theme->app_hilite_label);
98
99     self->a_text->texture[0].data.text.string = text;
100     RrMinsize(self->a_text, &textw, &texth);
101     textw += ob_rr_theme->bevel * 2;
102     texth += ob_rr_theme->bevel * 2;
103
104     self->h = texth + ob_rr_theme->bevel * 2;
105     iconw = (self->hasicon ? texth : 0);
106     self->w = textw + iconw + ob_rr_theme->bevel * (self->hasicon ? 3 : 2);
107 }
108
109 void popup_show(Popup *self, char *text, ObClientIcon *icon)
110 {
111     int x, y, w, h;
112     int textw, texth;
113     int iconw;
114
115     /* create the shit if needed */
116     if (!self->a_bg)
117         self->a_bg = RrAppearanceCopy(ob_rr_theme->app_hilite_bg);
118     if (self->hasicon && !self->a_icon)
119         self->a_icon = RrAppearanceCopy(ob_rr_theme->app_icon);
120     if (!self->a_text)
121         self->a_text = RrAppearanceCopy(ob_rr_theme->app_hilite_label);
122
123     XSetWindowBorderWidth(ob_display, self->bg, ob_rr_theme->bwidth);
124     XSetWindowBorder(ob_display, self->bg, ob_rr_theme->b_color->pixel);
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 += ob_rr_theme->bevel * 2;
141     texth += ob_rr_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 - (ob_rr_theme->bevel * 2);
148     } else
149         h = texth + ob_rr_theme->bevel * 2;
150     iconw = (self->hasicon ? texth : 0);
151     if (self->w) {
152         w = self->w;
153         textw = w - (iconw + ob_rr_theme->bevel * (self->hasicon ? 3 : 2));
154     } else
155         w = textw + iconw + ob_rr_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         ob_rr_theme->bevel * (self->hasicon ? 2 : 1);
198     self->a_text->surface.parenty = ob_rr_theme->bevel;
199     XMoveResizeWindow(ob_display, self->text,
200                       iconw + ob_rr_theme->bevel * (self->hasicon ? 2 : 1),
201                       ob_rr_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 = ob_rr_theme->bevel;
207         self->a_icon->surface.parenty = ob_rr_theme->bevel;
208         XMoveResizeWindow(ob_display, self->icon,
209                           ob_rr_theme->bevel, ob_rr_theme->bevel,
210                           iconw, texth);
211     }
212
213     RrPaint(self->a_bg, self->bg, w, h);
214     RrPaint(self->a_text, self->text, textw, texth);
215     if (self->hasicon)
216         RrPaint(self->a_icon, self->icon, iconw, texth);
217
218     if (!self->mapped) {
219         XMapWindow(ob_display, self->bg);
220         stacking_raise(INTERNAL_AS_WINDOW(self));
221         self->mapped = TRUE;
222     }
223 }
224
225 void popup_hide(Popup *self)
226 {
227     if (self->mapped) {
228         XUnmapWindow(ob_display, self->bg);
229         self->mapped = FALSE;
230     }
231 }