rename the Client struct to ObClient
[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     XSetWindowAttributes attrib;
30     Popup *self = g_new(Popup, 1);
31
32     self->obwin.type = Window_Internal;
33     self->hasicon = hasicon;
34     self->a_text = NULL;
35     self->gravity = NorthWestGravity;
36     self->x = self->y = self->w = self->h = 0;
37     self->mapped = FALSE;
38     self->a_bg = self->a_icon = self->a_text = NULL;
39
40     attrib.override_redirect = True;
41     self->bg = XCreateWindow(ob_display, ob_root,
42                              0, 0, 1, 1, 0, RrDepth(ob_rr_inst),
43                              InputOutput, RrVisual(ob_rr_inst),
44                              CWOverrideRedirect, &attrib);
45     
46     self->text = XCreateWindow(ob_display, self->bg,
47                                0, 0, 1, 1, 0, RrDepth(ob_rr_inst),
48                                InputOutput, RrVisual(ob_rr_inst), 0, NULL);
49
50     if (self->hasicon)
51         self->icon = XCreateWindow(ob_display, self->bg,
52                                    0, 0, 1, 1, 0,
53                                    RrDepth(ob_rr_inst), InputOutput,
54                                    RrVisual(ob_rr_inst), 0, NULL);
55
56     XMapWindow(ob_display, self->text);
57     XMapWindow(ob_display, self->icon);
58
59     stacking_add(INTERNAL_AS_WINDOW(self));
60     return self;
61 }
62
63 void popup_free(Popup *self)
64 {
65     if (self) {
66         XDestroyWindow(ob_display, self->bg);
67         XDestroyWindow(ob_display, self->text);
68         XDestroyWindow(ob_display, self->icon);
69         RrAppearanceFree(self->a_bg);
70         RrAppearanceFree(self->a_icon);
71         RrAppearanceFree(self->a_text);
72         stacking_remove(self);
73         g_free(self);
74     }
75 }
76
77 void popup_position(Popup *self, int gravity, int x, int y)
78 {
79     self->gravity = gravity;
80     self->x = x;
81     self->y = y;
82 }
83
84 void popup_size(Popup *self, int w, int h)
85 {
86     self->w = w;
87     self->h = h;
88 }
89
90 void popup_size_to_string(Popup *self, char *text)
91 {
92     int textw, texth;
93     int iconw;
94
95     if (!self->a_text)
96         self->a_text = RrAppearanceCopy(ob_rr_theme->app_hilite_label);
97
98     self->a_text->texture[0].data.text.string = text;
99     RrMinsize(self->a_text, &textw, &texth);
100     textw += ob_rr_theme->bevel * 2;
101     texth += ob_rr_theme->bevel * 2;
102
103     self->h = texth + ob_rr_theme->bevel * 2;
104     iconw = (self->hasicon ? texth : 0);
105     self->w = textw + iconw + ob_rr_theme->bevel * (self->hasicon ? 3 : 2);
106 }
107
108 void popup_show(Popup *self, char *text, ObClientIcon *icon)
109 {
110     int x, y, w, h;
111     int textw, texth;
112     int iconw;
113
114     /* create the shit if needed */
115     if (!self->a_bg)
116         self->a_bg = RrAppearanceCopy(ob_rr_theme->app_hilite_bg);
117     if (self->hasicon && !self->a_icon)
118         self->a_icon = RrAppearanceCopy(ob_rr_theme->app_icon);
119     if (!self->a_text)
120         self->a_text = RrAppearanceCopy(ob_rr_theme->app_hilite_label);
121
122     XSetWindowBorderWidth(ob_display, self->bg, ob_rr_theme->bwidth);
123     XSetWindowBorder(ob_display, self->bg, ob_rr_theme->b_color->pixel);
124
125     /* set up the textures */
126     self->a_text->texture[0].data.text.string = text;
127     if (self->hasicon) {
128         if (icon) {
129             self->a_icon->texture[0].type = RR_TEXTURE_RGBA;
130             self->a_icon->texture[0].data.rgba.width = icon->width;
131             self->a_icon->texture[0].data.rgba.height = icon->height;
132             self->a_icon->texture[0].data.rgba.data = icon->data;
133         } else
134             self->a_icon->texture[0].type = RR_TEXTURE_NONE;
135     }
136
137     /* measure the shit out */
138     RrMinsize(self->a_text, &textw, &texth);
139     textw += ob_rr_theme->bevel * 2;
140     texth += ob_rr_theme->bevel * 2;
141
142     /* set the sizes up and reget the text sizes from the calculated
143        outer sizes */
144     if (self->h) {
145         h = self->h;
146         texth = h - (ob_rr_theme->bevel * 2);
147     } else
148         h = texth + ob_rr_theme->bevel * 2;
149     iconw = (self->hasicon ? texth : 0);
150     if (self->w) {
151         w = self->w;
152         textw = w - (iconw + ob_rr_theme->bevel * (self->hasicon ? 3 : 2));
153     } else
154         w = textw + iconw + ob_rr_theme->bevel * (self->hasicon ? 3 : 2);
155     /* sanity checks to avoid crashes! */
156     if (w < 1) w = 1;
157     if (h < 1) h = 1;
158     if (textw < 1) textw = 1;
159     if (texth < 1) texth = 1;
160
161     /* set up the x coord */
162     x = self->x;
163     switch (self->gravity) {
164     case NorthGravity:
165     case CenterGravity:
166     case SouthGravity:
167         x -= w / 2;
168         break;
169     case NorthEastGravity:
170     case EastGravity:
171     case SouthEastGravity:
172         x -= w;
173         break;
174     }
175
176     /* set up the y coord */
177     y = self->y;
178     switch (self->gravity) {
179     case WestGravity:
180     case CenterGravity:
181     case EastGravity:
182         y -= h / 2;
183         break;
184     case SouthWestGravity:
185     case SouthGravity:
186     case SouthEastGravity:
187         y -= h;
188         break;
189     }
190
191     /* set the windows/appearances up */
192     XMoveResizeWindow(ob_display, self->bg, x, y, w, h);
193
194     self->a_text->surface.parent = self->a_bg;
195     self->a_text->surface.parentx = iconw +
196         ob_rr_theme->bevel * (self->hasicon ? 2 : 1);
197     self->a_text->surface.parenty = ob_rr_theme->bevel;
198     XMoveResizeWindow(ob_display, self->text,
199                       iconw + ob_rr_theme->bevel * (self->hasicon ? 2 : 1),
200                       ob_rr_theme->bevel, textw, texth);
201
202     if (self->hasicon) {
203         if (iconw < 1) iconw = 1; /* sanity check for crashes */
204         self->a_icon->surface.parent = self->a_bg;
205         self->a_icon->surface.parentx = ob_rr_theme->bevel;
206         self->a_icon->surface.parenty = ob_rr_theme->bevel;
207         XMoveResizeWindow(ob_display, self->icon,
208                           ob_rr_theme->bevel, ob_rr_theme->bevel,
209                           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 }