]> icculus.org git repositories - dana/openbox.git/blob - render2/surface.c
calc shadow offset when measuring a string
[dana/openbox.git] / render2 / surface.c
1 #include "surface.h"
2 #include "instance.h"
3 #include <assert.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #ifdef    SHAPE
7 #include <X11/extensions/shape.h>
8 #endif
9
10 /* doesn't set win or parent */
11 static struct RrSurface *surface_new(enum RrSurfaceType type,
12                                      int numtex)
13 {
14     struct RrSurface *sur;
15
16     sur = malloc(sizeof(struct RrSurface));
17     sur->type = type;
18     sur->shape_base = None;
19     sur->shape_base_x = 0;
20     sur->shape_base_y = 0;
21     sur->ntextures = numtex;
22     if (numtex) {
23         sur->texture = malloc(sizeof(struct RrTexture) * numtex);
24         memset(sur->texture, 0, sizeof(struct RrTexture) * numtex);
25     } else
26         sur->texture = NULL;
27     sur->x = 0;
28     sur->y = 0;
29     sur->w = 1;
30     sur->h = 1;
31     sur->visible = 0;
32     sur->children = NULL;
33     return sur;
34 }
35
36 static Window create_window(struct RrInstance *inst, Window parent)
37 {
38     XSetWindowAttributes attrib;
39     Window win;
40
41     attrib.event_mask = ExposureMask;
42     win = XCreateWindow(RrDisplay(inst), parent, 0, 0, 1, 1, 0,
43                         RrDepth(inst), InputOutput, RrVisual(inst),
44                         CWEventMask, &attrib);
45     return win;
46 }
47
48 struct RrSurface *RrSurfaceNewProto(enum RrSurfaceType type,
49                                     int numtex)
50 {
51     struct RrSurface *sur;
52
53     sur = surface_new(type, numtex);
54     sur->inst = NULL;
55     sur->win = None;
56     sur->parent = NULL;
57     sur->visible = 0;
58     return sur;
59 }
60
61 struct RrSurface *RrSurfaceNew(struct RrInstance *inst,
62                                enum RrSurfaceType type,
63                                Window win,
64                                int numtex)
65 {
66     struct RrSurface *sur;
67
68     sur = surface_new(type, numtex);
69     sur->inst = inst;
70     sur->win = win;
71     sur->parent = NULL;
72     sur->visible = 0;
73
74     RrInstaceAddSurface(sur);
75     return sur;
76 }
77
78 struct RrSurface *RrSurfaceNewChild(enum RrSurfaceType type,
79                                     struct RrSurface *parent,
80                                     int numtex)
81 {
82     struct RrSurface *sur;
83
84     /* can't be a child of a prototype! */
85     assert(parent->inst);
86     if (!parent->inst) return NULL;
87
88     sur = surface_new(type, numtex);
89     sur->inst = parent->inst;
90     sur->win = create_window(sur->inst, parent->win);
91     sur->parent = parent;
92     RrSurfaceShow(sur);
93
94     parent->children = g_slist_append(parent->children, sur);
95
96     RrInstaceAddSurface(sur);
97     return sur;
98 }
99
100 void RrSurfaceCopy(struct RrSurface *dest, struct RrSurface *src)
101 {
102     dest->type = src->type;
103     switch (dest->type) {
104     case RR_SURFACE_PLANAR:
105         dest->data = src->data;
106         break;
107     case RR_SURFACE_NONPLANAR:
108         assert(0);
109         break;
110     case RR_SURFACE_NONE:
111         break;
112     }
113     free(dest->texture);
114     dest->ntextures = src->ntextures;
115     dest->texture = malloc(sizeof(struct RrTexture) * dest->ntextures);
116     memcpy(dest->texture, src->texture,
117            sizeof(struct RrTexture) * dest->ntextures);
118 }
119
120 void RrSurfaceFree(struct RrSurface *sur)
121 {
122     int i;
123     if (sur) {
124         if (sur->parent)
125             sur->parent->children = g_slist_remove(sur->parent->children, sur);
126
127         RrInstaceRemoveSurface(sur);
128         for (i = 0; i < sur->ntextures; ++i)
129             RrTextureFreeContents(&sur->texture[i]);
130         if (sur->ntextures)
131             free(sur->texture);
132         if (sur->parent && sur->win)
133             XDestroyWindow(RrDisplay(sur->inst), sur->win);
134         free(sur);
135     }
136 }
137
138 void RrSurfaceSetPos(struct RrSurface *sur,
139                      int x,
140                      int y)
141 {
142     RrSurfaceSetArea(sur, x, y, sur->w, sur->h);
143 }
144
145 void RrSurfaceSetSize(struct RrSurface *sur,
146                       int w,
147                       int h)
148 {
149     RrSurfaceSetArea(sur, sur->x, sur->y, w, h);
150 }
151
152 void RrSurfaceSetArea(struct RrSurface *sur,
153                       int x,
154                       int y,
155                       int w,
156                       int h)
157 {
158     int m, r;
159
160     assert(w > 0 && h > 0);
161     if (!(w > 0 && h > 0)) return;
162
163     m = sur->x != x || sur->y != y;
164     r = sur->w != w || sur->h != h;
165
166     sur->x = x;
167     sur->y = y;
168     sur->w = w;
169     sur->h = h;
170     if (sur->win) {
171         if (m && r)
172             XMoveResizeWindow(RrDisplay(sur->inst), sur->win, x, y, w, h);
173         else if (m)
174             XMoveWindow(RrDisplay(sur->inst), sur->win, x, y);
175         else if (r)
176             XResizeWindow(RrDisplay(sur->inst), sur->win, w, h);
177     }
178 }
179
180 Window RrSurfaceWindow(struct RrSurface *sur)
181 {
182     /* can't get a window for a prototype */
183     assert(sur->inst);
184     if (!sur->inst) return None;
185
186     return sur->win;
187 }
188
189 struct RrTexture *RrSurfaceTexture(struct RrSurface *sur, int texnum)
190 {
191     assert(texnum < sur->ntextures);
192     return &(sur->texture[texnum]);
193 }
194
195 void RrSurfaceMinSize(struct RrSurface *sur, int *w, int *h)
196 {
197     int i;
198     int minw, minh;
199
200     switch(sur->type) {
201     case RR_SURFACE_NONE:
202         *w = *h = 0;
203         break;
204     case RR_SURFACE_PLANAR:
205         RrPlanarMinSize(sur, w, h);
206         break;
207     case RR_SURFACE_NONPLANAR:
208         assert(0);
209         break;
210     }
211
212     minw = minh = 0;
213     for (i = 0; i < sur->ntextures; ++i) {
214         switch (sur->texture[i].type) {
215         case RR_TEXTURE_NONE:
216             minw = MAX(minw, 0);
217             minh = MAX(minh, 0);
218             break;
219         case RR_TEXTURE_TEXT:
220             minw =
221                 MAX(minw,
222                     RrFontMeasureString(sur->texture[i].data.text.font,
223                                         sur->texture[i].data.text.string)); 
224             minh = MAX(minh, RrFontHeight(sur->texture[i].data.text.font));
225             break;
226         case RR_TEXTURE_RGBA:
227             minw = MAX(minw, (sur->texture[i].data.rgba.x +
228                               sur->texture[i].data.rgba.w));
229             minh = MAX(minw, (sur->texture[i].data.rgba.y +
230                               sur->texture[i].data.rgba.h));
231             break;
232         }
233     }
234
235     *w += minw;
236     *h += minh;
237     /* zeros are bad. */
238     if (*w == 0) *w = 1;
239     if (*h == 0) *h = 1;
240 }
241
242 void RrSurfaceShow(struct RrSurface *sur)
243 {
244     sur->visible = 1;
245     if (sur->win)
246         XMapWindow(RrDisplay(sur->inst), sur->win);
247 }
248
249 void RrSurfaceHide(struct RrSurface *sur)
250 {
251     sur->visible = 0;
252     if (sur->win)
253         XUnmapWindow(RrDisplay(sur->inst), sur->win);
254 }
255
256 int RrSurfaceVisible(struct RrSurface *sur)
257 {
258     assert(sur->inst);
259     return sur->visible;
260 }
261
262 void RrSurfaceShapeSetBase(struct RrSurface *sur, Window base, int x, int y)
263 {
264     assert(sur->inst);
265     sur->shape_base = base;
266     sur->shape_base_x = x;
267     sur->shape_base_y = y;
268 }
269
270 void RrSurfaceShape(struct RrSurface *sur)
271 {
272     GSList *it;
273
274     assert(sur->inst);
275
276 #ifdef SHAPE
277     XResizeWindow(RrDisplay(sur->inst), RrShapeWindow(sur->inst),
278                   sur->w, sur->h);
279     XShapeCombineShape(RrDisplay(sur->inst), RrShapeWindow(sur->inst),
280                        ShapeBounding,
281                        sur->shape_base_x, sur->shape_base_y,
282                        sur->shape_base, ShapeBounding, ShapeSet);
283     /* include the shape of the children */
284     for (it = sur->children; it; it = g_slist_next(it)) {
285         struct RrSurface *ch = it->data;
286         if (ch->win)
287             XShapeCombineShape(RrDisplay(sur->inst),
288                                RrShapeWindow(sur->inst),
289                                ShapeBounding, ch->x, ch->y, ch->win,
290                                ShapeBounding, ShapeUnion);
291     }
292     switch (sur->type) {
293     case RR_SURFACE_NONE:
294         break;
295     case RR_SURFACE_PLANAR:
296         /* XXX shape me based on something! an alpha mask? */
297         break;
298     case RR_SURFACE_NONPLANAR:
299         /* XXX shape me based on my GL form! */
300         assert(0);
301         break;
302     }
303
304     /* apply the final shape */
305     XShapeCombineShape(RrDisplay(sur->inst), sur->win, ShapeBounding, 0, 0,
306                        RrShapeWindow(sur->inst), ShapeBounding, ShapeSet);
307 #endif
308 }