rev |
line source |
nuclear@0
|
1 #include <stdio.h>
|
nuclear@0
|
2 #include <stdlib.h>
|
nuclear@0
|
3 #include <X11/Xlib.h>
|
nuclear@0
|
4 #include <X11/extensions/shape.h>
|
nuclear@0
|
5 #include <GL/glx.h>
|
nuclear@0
|
6 #include "image.h"
|
nuclear@0
|
7 #include "texture.h"
|
nuclear@0
|
8
|
nuclear@0
|
9 void redraw(void);
|
nuclear@0
|
10 void reshape(int x, int y);
|
nuclear@0
|
11 int handle_event(XEvent *ev);
|
nuclear@0
|
12
|
nuclear@0
|
13 /* X helper functions */
|
nuclear@0
|
14 Window create_window(int xsz, int ysz);
|
nuclear@0
|
15 void set_window_title(Window win, const char *title);
|
nuclear@0
|
16 int get_window_shape(Window win, struct image *img);
|
nuclear@0
|
17
|
nuclear@0
|
18 Display *dpy;
|
nuclear@0
|
19 Window win;
|
nuclear@0
|
20 GLXContext ctx;
|
nuclear@0
|
21 int width, height;
|
nuclear@0
|
22 int mapped;
|
nuclear@0
|
23 int redisp_pending;
|
nuclear@0
|
24 Atom xa_wm_prot, xa_wm_del_win;
|
nuclear@0
|
25 struct image img;
|
nuclear@0
|
26 struct texture tex;
|
nuclear@0
|
27 struct texture chess_tex;
|
nuclear@0
|
28 float aspect;
|
nuclear@0
|
29
|
nuclear@0
|
30 unsigned int target_xid = 0;
|
nuclear@0
|
31
|
nuclear@0
|
32 int main(int argc, char **argv)
|
nuclear@0
|
33 {
|
nuclear@0
|
34 int event_base, error_base;
|
nuclear@0
|
35 char *endp;
|
nuclear@0
|
36 struct image chess_img;
|
nuclear@0
|
37
|
nuclear@0
|
38 if(!argv[1]) {
|
nuclear@0
|
39 fprintf(stderr, "pass the window id to use\n");
|
nuclear@0
|
40 return 1;
|
nuclear@0
|
41 }
|
nuclear@0
|
42 if(!(target_xid = strtol(argv[1], &endp, 0))) {
|
nuclear@0
|
43 fprintf(stderr, "invalid argument: %s\n", argv[1]);
|
nuclear@0
|
44 return 1;
|
nuclear@0
|
45 }
|
nuclear@0
|
46
|
nuclear@0
|
47 if(!(dpy = XOpenDisplay(0))) {
|
nuclear@0
|
48 fprintf(stderr, "failed to open display\n");
|
nuclear@0
|
49 return 1;
|
nuclear@0
|
50 }
|
nuclear@0
|
51 xa_wm_prot = XInternAtom(dpy, "WM_PROTOCOLS", False);
|
nuclear@0
|
52 xa_wm_del_win = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
|
nuclear@0
|
53
|
nuclear@0
|
54 if(!XShapeQueryExtension(dpy, &event_base, &error_base)) {
|
nuclear@0
|
55 fprintf(stderr, "shape extension unsupported by this X server\n");
|
nuclear@0
|
56 XCloseDisplay(dpy);
|
nuclear@0
|
57 return 1;
|
nuclear@0
|
58 }
|
nuclear@0
|
59 if(get_window_shape(target_xid, &img) == -1) {
|
nuclear@0
|
60 XCloseDisplay(dpy);
|
nuclear@0
|
61 return 1;
|
nuclear@0
|
62 }
|
nuclear@0
|
63
|
nuclear@0
|
64 if(!(win = create_window(1280, 800))) {
|
nuclear@0
|
65 return 1;
|
nuclear@0
|
66 }
|
nuclear@0
|
67
|
nuclear@0
|
68 image_texture(&tex, &img);
|
nuclear@0
|
69
|
nuclear@0
|
70 image_create(&chess_img, 256, 256);
|
nuclear@0
|
71 image_chess(&chess_img, 8, 255, 128, 64, 64, 128, 255);
|
nuclear@0
|
72 image_texture(&chess_tex, &chess_img);
|
nuclear@0
|
73 image_destroy(&chess_img);
|
nuclear@0
|
74
|
nuclear@0
|
75 for(;;) {
|
nuclear@0
|
76 XEvent ev;
|
nuclear@0
|
77 XNextEvent(dpy, &ev);
|
nuclear@0
|
78
|
nuclear@0
|
79 if(handle_event(&ev) == -1) {
|
nuclear@0
|
80 break;
|
nuclear@0
|
81 }
|
nuclear@0
|
82 }
|
nuclear@0
|
83
|
nuclear@0
|
84 XDestroyWindow(dpy, win);
|
nuclear@0
|
85 XCloseDisplay(dpy);
|
nuclear@0
|
86 return 0;
|
nuclear@0
|
87 }
|
nuclear@0
|
88
|
nuclear@0
|
89 void redraw(void)
|
nuclear@0
|
90 {
|
nuclear@0
|
91 glClearColor(0.4, 0.4, 0.4, 1);
|
nuclear@0
|
92 glClear(GL_COLOR_BUFFER_BIT);
|
nuclear@0
|
93
|
nuclear@0
|
94 glMatrixMode(GL_MODELVIEW);
|
nuclear@0
|
95 glLoadIdentity();
|
nuclear@0
|
96
|
nuclear@0
|
97 glEnable(GL_TEXTURE_2D);
|
nuclear@0
|
98 glBindTexture(GL_TEXTURE_2D, chess_tex.id);
|
nuclear@0
|
99
|
nuclear@0
|
100
|
nuclear@0
|
101 /* background */
|
nuclear@0
|
102 glBegin(GL_QUADS);
|
nuclear@0
|
103 glTexCoord2f(0, 0); glVertex2f(-aspect, -1);
|
nuclear@0
|
104 glTexCoord2f(1, 0); glVertex2f(aspect, -1);
|
nuclear@0
|
105 glTexCoord2f(1, 1); glVertex2f(aspect, 1);
|
nuclear@0
|
106 glTexCoord2f(0, 1); glVertex2f(-aspect, 1);
|
nuclear@0
|
107 glEnd();
|
nuclear@0
|
108
|
nuclear@0
|
109 /* draw the window shape */
|
nuclear@0
|
110 glEnable(GL_BLEND);
|
nuclear@0
|
111 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
nuclear@0
|
112
|
nuclear@0
|
113 glBindTexture(GL_TEXTURE_2D, tex.id);
|
nuclear@0
|
114 glMatrixMode(GL_TEXTURE);
|
nuclear@0
|
115 glLoadIdentity();
|
nuclear@0
|
116 glScalef((float)tex.width / (float)tex.tex_width,
|
nuclear@0
|
117 (float)tex.height / (float)tex.tex_height,
|
nuclear@0
|
118 1.0);
|
nuclear@0
|
119
|
nuclear@0
|
120 glMatrixMode(GL_MODELVIEW);
|
nuclear@0
|
121 glPushMatrix();
|
nuclear@0
|
122 glScalef(0.7, 0.7, 0.7);
|
nuclear@0
|
123
|
nuclear@0
|
124 /* shadow */
|
nuclear@0
|
125 glPushMatrix();
|
nuclear@0
|
126 glTranslatef(0.1, -0.1, 0);
|
nuclear@0
|
127 glBegin(GL_QUADS);
|
nuclear@0
|
128 glColor3f(0, 0, 0);
|
nuclear@0
|
129 glTexCoord2f(0, 1); glVertex2f(-1, -1);
|
nuclear@0
|
130 glTexCoord2f(1, 1); glVertex2f(1, -1);
|
nuclear@0
|
131 glTexCoord2f(1, 0); glVertex2f(1, 1);
|
nuclear@0
|
132 glTexCoord2f(0, 0); glVertex2f(-1, 1);
|
nuclear@0
|
133 glEnd();
|
nuclear@0
|
134 glPopMatrix();
|
nuclear@0
|
135
|
nuclear@0
|
136 /* window */
|
nuclear@0
|
137 glBegin(GL_QUADS);
|
nuclear@0
|
138 glColor3f(1, 1, 0);
|
nuclear@0
|
139 glTexCoord2f(0, 1); glVertex2f(-1, -1);
|
nuclear@0
|
140 glTexCoord2f(1, 1); glVertex2f(1, -1);
|
nuclear@0
|
141 glTexCoord2f(1, 0); glVertex2f(1, 1);
|
nuclear@0
|
142 glTexCoord2f(0, 0); glVertex2f(-1, 1);
|
nuclear@0
|
143 glEnd();
|
nuclear@0
|
144
|
nuclear@0
|
145 glMatrixMode(GL_TEXTURE);
|
nuclear@0
|
146 glLoadIdentity();
|
nuclear@0
|
147 glMatrixMode(GL_MODELVIEW);
|
nuclear@0
|
148 glPopMatrix();
|
nuclear@0
|
149
|
nuclear@0
|
150 glDisable(GL_BLEND);
|
nuclear@0
|
151
|
nuclear@0
|
152 glXSwapBuffers(dpy, win);
|
nuclear@0
|
153 }
|
nuclear@0
|
154
|
nuclear@0
|
155 void reshape(int x, int y)
|
nuclear@0
|
156 {
|
nuclear@0
|
157 aspect = (float)x / (float)y;
|
nuclear@0
|
158 glViewport(0, 0, x, y);
|
nuclear@0
|
159
|
nuclear@0
|
160 glMatrixMode(GL_PROJECTION);
|
nuclear@0
|
161 glLoadIdentity();
|
nuclear@0
|
162 glScalef(1.0 / aspect, 1.0, 1.0);
|
nuclear@0
|
163 }
|
nuclear@0
|
164
|
nuclear@0
|
165 int handle_event(XEvent *ev)
|
nuclear@0
|
166 {
|
nuclear@0
|
167 switch(ev->type) {
|
nuclear@0
|
168 case MapNotify:
|
nuclear@0
|
169 case UnmapNotify:
|
nuclear@0
|
170 mapped = ev->type == MapNotify ? 1 : 0;
|
nuclear@0
|
171 break;
|
nuclear@0
|
172
|
nuclear@0
|
173 case Expose:
|
nuclear@0
|
174 if(mapped && ev->xexpose.count == 0) {
|
nuclear@0
|
175 redraw();
|
nuclear@0
|
176 }
|
nuclear@0
|
177 break;
|
nuclear@0
|
178
|
nuclear@0
|
179 case KeyPress:
|
nuclear@0
|
180 {
|
nuclear@0
|
181 KeySym sym = XLookupKeysym(&ev->xkey, 0);
|
nuclear@0
|
182
|
nuclear@0
|
183 switch(sym) {
|
nuclear@0
|
184 case XK_Escape:
|
nuclear@0
|
185 return -1;
|
nuclear@0
|
186 }
|
nuclear@0
|
187 }
|
nuclear@0
|
188 break;
|
nuclear@0
|
189
|
nuclear@0
|
190 case ConfigureNotify:
|
nuclear@0
|
191 if(ev->xconfigure.width != width || ev->xconfigure.height != height) {
|
nuclear@0
|
192 width = ev->xconfigure.width;
|
nuclear@0
|
193 height = ev->xconfigure.height;
|
nuclear@0
|
194 reshape(width, height);
|
nuclear@0
|
195 }
|
nuclear@0
|
196 break;
|
nuclear@0
|
197
|
nuclear@0
|
198 case ClientMessage:
|
nuclear@0
|
199 if(ev->xclient.message_type == xa_wm_prot) {
|
nuclear@0
|
200 if(ev->xclient.data.l[0] == xa_wm_del_win) {
|
nuclear@0
|
201 return -1;
|
nuclear@0
|
202 }
|
nuclear@0
|
203 }
|
nuclear@0
|
204 break;
|
nuclear@0
|
205 }
|
nuclear@0
|
206 return 0;
|
nuclear@0
|
207 }
|
nuclear@0
|
208
|
nuclear@0
|
209 Window create_window(int xsz, int ysz)
|
nuclear@0
|
210 {
|
nuclear@0
|
211 Window w, root;
|
nuclear@0
|
212 XVisualInfo *vis;
|
nuclear@0
|
213 XClassHint chint;
|
nuclear@0
|
214 XSetWindowAttributes xattr;
|
nuclear@0
|
215 unsigned int evmask, xattr_mask;
|
nuclear@0
|
216 int scr;
|
nuclear@0
|
217 int glxattr[] = {
|
nuclear@0
|
218 GLX_RGBA, GLX_DOUBLEBUFFER,
|
nuclear@0
|
219 GLX_RED_SIZE, 8,
|
nuclear@0
|
220 GLX_GREEN_SIZE, 8,
|
nuclear@0
|
221 GLX_BLUE_SIZE, 8,
|
nuclear@0
|
222 GLX_DEPTH_SIZE, 24,
|
nuclear@0
|
223 GLX_USE_GL, 1,
|
nuclear@0
|
224 None
|
nuclear@0
|
225 };
|
nuclear@0
|
226
|
nuclear@0
|
227 scr = DefaultScreen(dpy);
|
nuclear@0
|
228 root = RootWindow(dpy, scr);
|
nuclear@0
|
229
|
nuclear@0
|
230 if(!(vis = glXChooseVisual(dpy, scr, glxattr))) {
|
nuclear@0
|
231 printf("failed to find a suitable visual\n");
|
nuclear@0
|
232 return 0;
|
nuclear@0
|
233 }
|
nuclear@0
|
234 if(!(ctx = glXCreateContext(dpy, vis, 0, True))) {
|
nuclear@0
|
235 XFree(vis);
|
nuclear@0
|
236 return 0;
|
nuclear@0
|
237 }
|
nuclear@0
|
238
|
nuclear@0
|
239 xattr.background_pixel = xattr.border_pixel = BlackPixel(dpy, scr);
|
nuclear@0
|
240 xattr.colormap = XCreateColormap(dpy, root, vis->visual, AllocNone);
|
nuclear@0
|
241 xattr_mask = CWColormap | CWBackPixel | CWBorderPixel;
|
nuclear@0
|
242
|
nuclear@0
|
243 if(!(w = XCreateWindow(dpy, root, 0, 0, xsz, ysz, 0, vis->depth, InputOutput,
|
nuclear@0
|
244 vis->visual, xattr_mask, &xattr))) {
|
nuclear@0
|
245 printf("failed to create window\n");
|
nuclear@0
|
246 glXDestroyContext(dpy, ctx);
|
nuclear@0
|
247 XFree(vis);
|
nuclear@0
|
248 return 0;
|
nuclear@0
|
249 }
|
nuclear@0
|
250 XFree(vis);
|
nuclear@0
|
251
|
nuclear@0
|
252 evmask = StructureNotifyMask | VisibilityChangeMask | KeyPressMask |
|
nuclear@0
|
253 ExposureMask;
|
nuclear@0
|
254 XSelectInput(dpy, w, evmask);
|
nuclear@0
|
255
|
nuclear@0
|
256 XSetWMProtocols(dpy, w, &xa_wm_del_win, 1);
|
nuclear@0
|
257
|
nuclear@0
|
258 chint.res_name = chint.res_class = "xgetshape";
|
nuclear@0
|
259 XSetClassHint(dpy, w, &chint);
|
nuclear@0
|
260
|
nuclear@0
|
261 set_window_title(w, "GL xgetshape");
|
nuclear@0
|
262
|
nuclear@0
|
263 glXMakeCurrent(dpy, w, ctx);
|
nuclear@0
|
264 XMapWindow(dpy, w);
|
nuclear@0
|
265 return w;
|
nuclear@0
|
266 }
|
nuclear@0
|
267
|
nuclear@0
|
268 void set_window_title(Window win, const char *title)
|
nuclear@0
|
269 {
|
nuclear@0
|
270 XTextProperty wm_name;
|
nuclear@0
|
271 XStringListToTextProperty((char**)&title, 1, &wm_name);
|
nuclear@0
|
272 XSetWMName(dpy, win, &wm_name);
|
nuclear@0
|
273 XSetWMIconName(dpy, win, &wm_name);
|
nuclear@0
|
274 XFree(wm_name.value);
|
nuclear@0
|
275 }
|
nuclear@0
|
276
|
nuclear@0
|
277 int get_window_shape(Window win, struct image *img)
|
nuclear@0
|
278 {
|
nuclear@0
|
279 Bool buse, cuse;
|
nuclear@0
|
280 int bx, by, cx, cy;
|
nuclear@0
|
281 unsigned int bw, bh, cw, ch;
|
nuclear@0
|
282 int kind;
|
nuclear@0
|
283 int x, y, w, h;
|
nuclear@0
|
284 XRectangle *rects;
|
nuclear@0
|
285 int i, rect_count, rect_order;
|
nuclear@0
|
286
|
nuclear@0
|
287 XShapeQueryExtents(dpy, win, &buse, &bx, &by, &bw, &bh,
|
nuclear@0
|
288 &cuse, &cx, &cy, &bw, &bh);
|
nuclear@0
|
289 if(cuse) {
|
nuclear@0
|
290 x = cx;
|
nuclear@0
|
291 y = cy;
|
nuclear@0
|
292 w = cw;
|
nuclear@0
|
293 h = ch;
|
nuclear@0
|
294 kind = ShapeClip;
|
nuclear@0
|
295 } else if(buse) {
|
nuclear@0
|
296 x = bx;
|
nuclear@0
|
297 y = by;
|
nuclear@0
|
298 w = bw;
|
nuclear@0
|
299 h = bh;
|
nuclear@0
|
300 kind = ShapeBounding;
|
nuclear@0
|
301 } else {
|
nuclear@0
|
302 fprintf(stderr, "XShapeQueryExtents returned no extents\n");
|
nuclear@0
|
303 return -1;
|
nuclear@0
|
304 }
|
nuclear@0
|
305
|
nuclear@0
|
306 if(image_create(img, w, h) == -1) {
|
nuclear@0
|
307 fprintf(stderr, "failed to create shape image (%dx%d)\n", w, h);
|
nuclear@0
|
308 return -1;
|
nuclear@0
|
309 }
|
nuclear@0
|
310 image_clear(img, 0, 0, 0, 0);
|
nuclear@0
|
311
|
nuclear@0
|
312 if(!(rects = XShapeGetRectangles(dpy, win, kind, &rect_count, &rect_order))) {
|
nuclear@0
|
313 fprintf(stderr, "failed to get the shape rectangles\n");
|
nuclear@0
|
314 image_destroy(img);
|
nuclear@0
|
315 return -1;
|
nuclear@0
|
316 }
|
nuclear@0
|
317
|
nuclear@0
|
318 for(i=0; i<rect_count; i++) {
|
nuclear@0
|
319 image_fillrect(img, rects[i].x, rects[i].y, rects[i].width, rects[i].height,
|
nuclear@0
|
320 255, 255, 255, 255);
|
nuclear@0
|
321 }
|
nuclear@0
|
322 return 0;
|
nuclear@0
|
323 }
|