]> icculus.org git repositories - dana/openbox.git/blob - render2/surface.c
add support for shaped surfaces
[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 /* doesn't set win or parent */
101 static struct RrSurface *surface_copy(struct RrSurface *orig)
102 {
103     struct RrSurface *sur;
104
105     sur = malloc(sizeof(struct RrSurface));
106     sur->type = orig->type;
107     switch (sur->type) {
108     case RR_SURFACE_PLANAR:
109         sur->data = orig->data;
110         break;
111     case RR_SURFACE_NONPLANAR:
112         assert(0);
113         break;
114     case RR_SURFACE_NONE:
115         break;
116     }
117     sur->ntextures = orig->ntextures;
118     sur->texture = malloc(sizeof(struct RrTexture) * sur->ntextures);
119     memcpy(sur->texture, orig->texture,
120            sizeof(struct RrTexture) * sur->ntextures);
121     return sur;
122 }
123
124 struct RrSurface *RrSurfaceCopy(struct RrInstance *inst,
125                                 struct RrSurface *orig,
126                                 Window win)
127 {
128     struct RrSurface *sur;
129
130     sur = surface_copy(orig);
131     sur->inst = inst;
132     sur->win = win;
133     sur->parent = NULL;
134     sur->visible = 0;
135
136     RrInstaceAddSurface(sur);
137     return sur;
138 }
139
140 struct RrSurface *RrSurfaceCopyChild(struct RrSurface *orig,
141                                      struct RrSurface *parent)
142 {
143     struct RrSurface *sur;
144
145     /* can't be a child of a prototype! */
146     assert(parent->inst);
147     if (!parent->inst) return NULL;
148
149     sur = surface_copy(orig);
150     sur->inst = parent->inst;
151     sur->win = create_window(sur->inst, parent->win);
152     sur->parent = parent;
153     RrSurfaceShow(sur);
154
155     parent->children = g_slist_append(parent->children, sur);
156
157     RrInstaceAddSurface(sur);
158     return sur;
159 }
160
161 void RrSurfaceFree(struct RrSurface *sur)
162 {
163     int i;
164     if (sur) {
165         if (sur->parent)
166             sur->parent->children = g_slist_remove(sur->parent->children, sur);
167
168         RrInstaceRemoveSurface(sur);
169         for (i = 0; i < sur->ntextures; ++i)
170             RrTextureFreeContents(&sur->texture[i]);
171         if (sur->ntextures)
172             free(sur->texture);
173         if (sur->parent && sur->win)
174             XDestroyWindow(RrDisplay(sur->inst), sur->win);
175         free(sur);
176     }
177 }
178
179 void RrSurfaceSetPos(struct RrSurface *sur,
180                      int x,
181                      int y)
182 {
183     RrSurfaceSetArea(sur, x, y, sur->w, sur->h);
184 }
185
186 void RrSurfaceSetSize(struct RrSurface *sur,
187                       int w,
188                       int h)
189 {
190     RrSurfaceSetArea(sur, sur->x, sur->y, w, h);
191 }
192
193 void RrSurfaceSetArea(struct RrSurface *sur,
194                       int x,
195                       int y,
196                       int w,
197                       int h)
198 {
199     assert(w > 0 && h > 0);
200     if (!(w > 0 && h > 0)) return;
201
202     sur->x = x;
203     sur->y = y;
204     sur->w = w;
205     sur->h = h;
206     if (sur->win)
207         XMoveResizeWindow(RrDisplay(sur->inst), sur->win, x, y, w, h);
208 }
209
210 Window RrSurfaceWindow(struct RrSurface *sur)
211 {
212     /* can't get a window for a prototype */
213     assert(sur->inst);
214     if (!sur->inst) return None;
215
216     return sur->win;
217 }
218
219 struct RrTexture *RrSurfaceTexture(struct RrSurface *sur, int texnum)
220 {
221     assert(texnum < sur->ntextures);
222     return &(sur->texture[texnum]);
223 }
224
225 void RrSurfaceMinSize(struct RrSurface *sur, int *w, int *h)
226 {
227     int i;
228     int minw, minh;
229
230     switch(sur->type) {
231     case RR_SURFACE_NONE:
232         *w = *h = 0;
233         break;
234     case RR_SURFACE_PLANAR:
235         RrPlanarMinSize(sur, w, h);
236         break;
237     case RR_SURFACE_NONPLANAR:
238         assert(0);
239         break;
240     }
241
242     minw = minh = 0;
243     for (i = 0; i < sur->ntextures; ++i) {
244         switch (sur->texture[i].type) {
245         case RR_TEXTURE_NONE:
246             minw = MAX(minw, 0);
247             minh = MAX(minh, 0);
248             break;
249         case RR_TEXTURE_TEXT:
250             /* XXX MEASUER STRING PLS */
251             minw = MAX(minw, 100 /*MEASURESTRING*/); 
252             minh = MAX(minh, 10  /*HEIGHTOFFONT*/);
253             break;
254         case RR_TEXTURE_RGBA:
255             minw = MAX(minw, (sur->texture[i].data.rgba.x +
256                               sur->texture[i].data.rgba.w));
257             minh = MAX(minw, (sur->texture[i].data.rgba.y +
258                               sur->texture[i].data.rgba.h));
259             break;
260         }
261     }
262
263     *w += minw;
264     *h += minh;
265     /* zeros are bad. */
266     if (*w == 0) *w = 1;
267     if (*h == 0) *h = 1;
268 }
269
270 void RrSurfaceShow(struct RrSurface *sur)
271 {
272     sur->visible = 1;
273     if (sur->win)
274         XMapWindow(RrDisplay(sur->inst), sur->win);
275 }
276
277 void RrSurfaceHide(struct RrSurface *sur)
278 {
279     sur->visible = 0;
280     if (sur->win)
281         XUnmapWindow(RrDisplay(sur->inst), sur->win);
282 }
283
284 int RrSurfaceVisible(struct RrSurface *sur)
285 {
286     assert(sur->inst);
287     return sur->visible;
288 }
289
290 void RrSurfaceShapeSetBase(struct RrSurface *sur, Window base, int x, int y)
291 {
292     assert(sur->inst);
293     sur->shape_base = base;
294     sur->shape_base_x = x;
295     sur->shape_base_y = y;
296 }
297
298 void RrSurfaceShape(struct RrSurface *sur)
299 {
300     GSList *it;
301
302     assert(sur->inst);
303
304 #ifdef SHAPE
305     XResizeWindow(RrDisplay(sur->inst), RrShapeWindow(sur->inst),
306                   sur->w, sur->h);
307     XShapeCombineShape(RrDisplay(sur->inst), RrShapeWindow(sur->inst),
308                        ShapeBounding,
309                        sur->shape_base_x, sur->shape_base_y,
310                        sur->shape_base, ShapeBounding, ShapeSet);
311     /* include the shape of the children */
312     for (it = sur->children; it; it = g_slist_next(it)) {
313         struct RrSurface *ch = it->data;
314         if (ch->win)
315             XShapeCombineShape(RrDisplay(sur->inst),
316                                RrShapeWindow(sur->inst),
317                                ShapeBounding, ch->x, ch->y, ch->win,
318                                ShapeBounding, ShapeUnion);
319     }
320     switch (sur->type) {
321     case RR_SURFACE_NONE:
322         break;
323     case RR_SURFACE_PLANAR:
324         /* XXX shape me based on something! an alpha mask? */
325         break;
326     case RR_SURFACE_NONPLANAR:
327         /* XXX shape me based on my GL form! */
328         assert(0);
329         break;
330     }
331
332     /* apply the final shape */
333     XShapeCombineShape(RrDisplay(sur->inst), sur->win, ShapeBounding, 0, 0,
334                        RrShapeWindow(sur->inst), ShapeBounding, ShapeSet);
335 #endif
336 }