]> icculus.org git repositories - dana/openbox.git/blob - openbox/popup.c
add ability to set a texture to None
[dana/openbox.git] / openbox / popup.c
1 #include "openbox.h"
2 #include "frame.h"
3 #include "window.h"
4 #include "stacking.h"
5 #include "render2/render.h"
6
7 /* XXX temp */
8 static int theme_bevel = 1;
9 static int theme_bwidth = 3;
10
11 typedef struct Popup {
12     ObWindow obwin;
13     Window bg;
14
15     Window icon;
16     Window text;
17
18     gboolean hasicon;
19     struct RrSurface *s_bg;
20     struct RrSurface *s_icon;
21     struct RrSurface *s_text;
22     int gravity;
23     int x;
24     int y;
25     int w;
26     int h;
27 } Popup;
28
29 Popup *popup_new(gboolean hasicon)
30 {
31     XSetWindowAttributes attrib;
32     Popup *self;
33
34     self = g_new(Popup, 1);
35     self->obwin.type = Window_Internal;
36     self->hasicon = hasicon;
37     self->gravity = NorthWestGravity;
38     self->x = self->y = self->w = self->h = 0;
39     stacking_add(INTERNAL_AS_WINDOW(self));
40     stacking_raise(INTERNAL_AS_WINDOW(self));
41
42     attrib.override_redirect = True;
43     self->bg = XCreateWindow(ob_display, ob_root,
44                              0, 0, 1, 1, 0, RrInstanceDepth(ob_render_inst),
45                              InputOutput, RrInstanceVisual(ob_render_inst),
46                              CWOverrideRedirect, &attrib);
47     self->s_bg = RrSurfaceNew(ob_render_inst, RR_SURFACE_PLANAR, self->bg, 0);
48     self->s_text = RrSurfaceNewChild(RR_SURFACE_PLANAR, self->s_bg, 1);
49     self->text = RrSurfaceWindow(self->s_text);
50     if (self->hasicon) {
51         self->s_icon = RrSurfaceNewChild(RR_SURFACE_PLANAR, self->s_bg, 1);
52         self->icon = RrSurfaceWindow(self->s_icon);
53     } else {
54         self->s_icon = NULL;
55         self->icon = None;
56     }
57
58     /* XXX COPY THE APPEARANCES FROM THE THEME...... LIKE THIS SORTA!
59     self->a_text = appearance_copy(theme_app_hilite_label);
60     */
61
62     return self;
63 }
64
65 void popup_free(Popup *self)
66 {
67     RrSurfaceFree(self->s_bg);
68     RrSurfaceFree(self->s_icon);
69     RrSurfaceFree(self->s_text);
70     XDestroyWindow(ob_display, self->bg);
71     stacking_remove(self);
72     g_free(self);
73 }
74
75 void popup_position(Popup *self, int gravity, int x, int y)
76 {
77     self->gravity = gravity;
78     self->x = x;
79     self->y = y;
80 }
81
82 void popup_size(Popup *self, int w, int h)
83 {
84     self->w = w;
85     self->h = h;
86 }
87
88 void popup_size_to_string(Popup *self, char *text)
89 {
90     int textw, texth;
91     int iconw;
92
93     RrTextureSetText(self->s_text, 0, NULL, RR_LEFT, text);
94     RrSurfaceMinSize(self->s_text, &textw, &texth);
95     textw += theme_bevel * 2;
96     texth += theme_bevel * 2;
97
98     self->h = texth + theme_bevel * 2 + theme_bwidth * 2;
99     iconw = (self->hasicon ? texth + theme_bevel : 0);
100     self->w = textw + iconw + theme_bevel * 2 + theme_bwidth * 2;
101 }
102
103 void popup_show(Popup *self, char *text, Icon *icon)
104 {
105     int x, y, w, h;
106     int textw, texth;
107     int iconw;
108
109     /* set up the textures */
110     RrTextureSetText(self->s_text, 0, NULL, RR_LEFT, text);
111
112     /* measure the shit out */
113     RrSurfaceMinSize(self->s_text, &textw, &texth);
114     textw += theme_bevel * 2;
115     texth += theme_bevel * 2;
116
117     /* set the sizes up and reget the text sizes from the calculated
118        outer sizes */
119     if (self->h) {
120         h = self->h;
121         texth = h - (theme_bevel * 2);
122     } else
123         h = texth + theme_bevel * 2;
124     iconw = (self->hasicon ? texth : 0);
125     if (self->w) {
126         w = self->w;
127         textw = w - (iconw + theme_bevel * (self->hasicon ? 3 : 2));
128     } else
129         w = textw + iconw + theme_bevel * (self->hasicon ? 3 : 2);
130     /* sanity checks to avoid crashes! */
131     if (w < 1) w = 1;
132     if (h < 1) h = 1;
133     if (textw < 1) textw = 1;
134     if (texth < 1) texth = 1;
135
136     /* set up the x coord */
137     x = self->x;
138     switch (self->gravity) {
139     case NorthGravity:
140     case CenterGravity:
141     case SouthGravity:
142         x -= w / 2;
143         break;
144     case NorthEastGravity:
145     case EastGravity:
146     case SouthEastGravity:
147         x -= w;
148         break;
149     }
150
151     /* set up the y coord */
152     y = self->y;
153     switch (self->gravity) {
154     case WestGravity:
155     case CenterGravity:
156     case EastGravity:
157         y -= h / 2;
158         break;
159     case SouthWestGravity:
160     case SouthGravity:
161     case SouthEastGravity:
162         y -= h;
163         break;
164     }
165
166     /* set the surfaces up */
167     RrSurfaceSetArea(self->s_bg, x, y, w, h);
168
169     RrSurfaceSetArea(self->s_text,
170                      iconw + theme_bevel * (self->hasicon ? 3 : 2) +
171                      theme_bwidth,
172                      theme_bevel + theme_bwidth,
173                      textw, texth);
174
175     if (self->hasicon) {
176         RrTextureSetRGBA(self->s_icon, 0, icon->data, 0, 0, icon->width,
177                          icon->height);
178         if (iconw < 1) iconw = 1; /* sanity check for crashes */
179         RrSurfaceSetArea(self->s_icon,
180                          theme_bwidth + theme_bevel,
181                          theme_bwidth + theme_bevel,
182                          iconw, iconw);
183     }
184
185     if (!RrSurfaceVisible(self->s_bg)) {
186         RrSurfaceShow(self->s_bg);
187         stacking_raise(INTERNAL_AS_WINDOW(self));
188     }
189 }
190
191 void popup_hide(Popup *self)
192 {
193     if (RrSurfaceVisible(self->s_bg)) {
194         RrSurfaceHide(self->s_bg);
195     }
196 }