rev |
line source |
nuclear@0
|
1 #include <stdio.h>
|
nuclear@0
|
2 #include <stdlib.h>
|
nuclear@0
|
3 #include <unistd.h>
|
nuclear@0
|
4 #include <X11/Xlib.h>
|
nuclear@0
|
5 #include <X11/Xutil.h>
|
nuclear@0
|
6 #include <X11/Xatom.h>
|
nuclear@0
|
7 #include <X11/extensions/Xcomposite.h>
|
nuclear@1
|
8 #include <X11/extensions/Xdamage.h>
|
nuclear@0
|
9 #include "cwin.h"
|
nuclear@2
|
10 #include "opengl.h"
|
nuclear@1
|
11 #include "logger.h"
|
nuclear@1
|
12
|
nuclear@1
|
13 static bool register_compositor();
|
nuclear@2
|
14 static void start_comp();
|
nuclear@2
|
15 static void manage_window(Window xwin);
|
nuclear@2
|
16 static void unmanage_window(Window xwin);
|
nuclear@2
|
17 static void redraw();
|
nuclear@3
|
18 static void draw_window(CompWindow *cwin);
|
nuclear@2
|
19 static void reshape(int x, int y);
|
nuclear@1
|
20
|
nuclear@2
|
21 Display *dpy;
|
nuclear@2
|
22 int screen_num;
|
nuclear@2
|
23 Window root_win, comp_win;
|
nuclear@2
|
24 int root_width, root_height;
|
nuclear@1
|
25
|
nuclear@1
|
26 int main(int argc, char **argv)
|
nuclear@1
|
27 {
|
nuclear@1
|
28 if(!(dpy = XOpenDisplay(0))) {
|
nuclear@1
|
29 log_error("failed to open X display\n");
|
nuclear@1
|
30 return 1;
|
nuclear@1
|
31 }
|
nuclear@2
|
32 screen_num = DefaultScreen(dpy);
|
nuclear@2
|
33 root_win = RootWindow(dpy, screen_num);
|
nuclear@2
|
34 root_width = DisplayWidth(dpy, screen_num);
|
nuclear@2
|
35 root_height = DisplayHeight(dpy, screen_num);
|
nuclear@1
|
36 log_info("display size %dx%d\n", root_width, root_height);
|
nuclear@1
|
37
|
nuclear@2
|
38 int xcomp_ev_base, xcomp_err_base;
|
nuclear@1
|
39 if(!XCompositeQueryExtension(dpy, &xcomp_ev_base, &xcomp_err_base)) {
|
nuclear@1
|
40 log_error("X server doesn't support the composite extension\n");
|
nuclear@1
|
41 return 1;
|
nuclear@1
|
42 }
|
nuclear@2
|
43 int xcomp_ver_major = 0, xcomp_ver_minor = 4;
|
nuclear@1
|
44 XCompositeQueryVersion(dpy, &xcomp_ver_major, &xcomp_ver_minor);
|
nuclear@1
|
45 log_info("Found composite extension version %d.%d\n", xcomp_ver_major, xcomp_ver_minor);
|
nuclear@2
|
46 if(xcomp_ver_major <= 0 && xcomp_ver_minor < 3) {
|
nuclear@2
|
47 // for NameWindowPixmap & CompositeGetoverlayWindow
|
nuclear@2
|
48 log_error("I need at least version 0.3\n");
|
nuclear@1
|
49 return 1;
|
nuclear@1
|
50 }
|
nuclear@1
|
51
|
nuclear@1
|
52 int xdmg_ev_base, xdmg_err_base;
|
nuclear@1
|
53 if(!XDamageQueryExtension(dpy, &xdmg_ev_base, &xdmg_err_base)) {
|
nuclear@1
|
54 log_error("X server doesn't support the damage extension\n");
|
nuclear@1
|
55 return 1;
|
nuclear@1
|
56 }
|
nuclear@1
|
57 // TODO also XFixes ?
|
nuclear@1
|
58
|
nuclear@1
|
59 if(!register_compositor()) {
|
nuclear@1
|
60 return 1;
|
nuclear@1
|
61 }
|
nuclear@1
|
62
|
nuclear@2
|
63 comp_win = XCompositeGetOverlayWindow(dpy, root_win);
|
nuclear@2
|
64 if(!create_gl(comp_win)) {
|
nuclear@2
|
65 return 1;
|
nuclear@2
|
66 }
|
nuclear@2
|
67
|
nuclear@2
|
68 start_comp();
|
nuclear@2
|
69 reshape(root_width, root_height);
|
nuclear@2
|
70 redraw();
|
nuclear@1
|
71
|
nuclear@1
|
72 for(;;) {
|
nuclear@1
|
73 XEvent ev;
|
nuclear@1
|
74 XNextEvent(dpy, &ev);
|
nuclear@2
|
75
|
nuclear@3
|
76 CompWindow *cwin;
|
nuclear@2
|
77 switch(ev.type) {
|
nuclear@2
|
78 case CreateNotify:
|
nuclear@2
|
79 manage_window(ev.xcreatewindow.window);
|
nuclear@2
|
80 break;
|
nuclear@2
|
81
|
nuclear@2
|
82 case ConfigureNotify:
|
nuclear@2
|
83 break;
|
nuclear@2
|
84
|
nuclear@2
|
85 case DestroyNotify:
|
nuclear@2
|
86 unmanage_window(ev.xdestroywindow.window);
|
nuclear@2
|
87 break;
|
nuclear@2
|
88
|
nuclear@2
|
89 case MapNotify:
|
nuclear@3
|
90 if((cwin = find_window_xid(ev.xmap.window))) {
|
nuclear@3
|
91 cwin->mapped = true;
|
nuclear@3
|
92 }
|
nuclear@2
|
93 break;
|
nuclear@3
|
94
|
nuclear@2
|
95 case UnmapNotify:
|
nuclear@3
|
96 if((cwin = find_window_xid(ev.xunmap.window))) {
|
nuclear@3
|
97 cwin->mapped = false;
|
nuclear@3
|
98 }
|
nuclear@2
|
99 break;
|
nuclear@2
|
100
|
nuclear@2
|
101 case ReparentNotify:
|
nuclear@2
|
102 if(ev.xreparent.parent == root_win) {
|
nuclear@2
|
103 manage_window(ev.xreparent.window);
|
nuclear@2
|
104 } else {
|
nuclear@2
|
105 unmanage_window(ev.xreparent.window);
|
nuclear@2
|
106 }
|
nuclear@2
|
107 break;
|
nuclear@2
|
108
|
nuclear@2
|
109 case CirculateNotify:
|
nuclear@2
|
110 break;
|
nuclear@2
|
111
|
nuclear@2
|
112 case Expose:
|
nuclear@3
|
113 // TODO?
|
nuclear@2
|
114 break;
|
nuclear@2
|
115
|
nuclear@2
|
116 default:
|
nuclear@2
|
117 if(ev.type == xdmg_ev_base + XDamageNotify) {
|
nuclear@2
|
118 }
|
nuclear@2
|
119 }
|
nuclear@1
|
120 }
|
nuclear@1
|
121 }
|
nuclear@1
|
122
|
nuclear@1
|
123 static bool register_compositor()
|
nuclear@1
|
124 {
|
nuclear@1
|
125 char atom_name[64];
|
nuclear@2
|
126 sprintf(atom_name, "_NET_WM_CM_S%d", screen_num);
|
nuclear@1
|
127 Atom xa_wm_cm = XInternAtom(dpy, atom_name, False);
|
nuclear@1
|
128
|
nuclear@1
|
129 Window win = XGetSelectionOwner(dpy, xa_wm_cm);
|
nuclear@1
|
130 if(win != None) {
|
nuclear@1
|
131 log_error("Another compositor is running. Stop it and try again.\n");
|
nuclear@1
|
132 return false;
|
nuclear@1
|
133 }
|
nuclear@1
|
134
|
nuclear@1
|
135 win = XCreateSimpleWindow(dpy, root_win, 0, 0, 1, 1, 0, None, None);
|
nuclear@1
|
136 XSetSelectionOwner(dpy, xa_wm_cm, win, 0);
|
nuclear@1
|
137 return true;
|
nuclear@1
|
138 }
|
nuclear@2
|
139
|
nuclear@2
|
140 static void start_comp()
|
nuclear@2
|
141 {
|
nuclear@2
|
142 XGrabServer(dpy);
|
nuclear@2
|
143 XCompositeRedirectSubwindows(dpy, root_win, CompositeRedirectManual);
|
nuclear@2
|
144 XSelectInput(dpy, root_win, SubstructureNotifyMask | ExposureMask | StructureNotifyMask);
|
nuclear@2
|
145
|
nuclear@2
|
146 // manage all top-level windows
|
nuclear@2
|
147 Window root_ret, parent;
|
nuclear@2
|
148 Window *children;
|
nuclear@2
|
149 unsigned int num_children;
|
nuclear@2
|
150 XQueryTree(dpy, root_win, &root_ret, &parent, &children, &num_children);
|
nuclear@2
|
151
|
nuclear@2
|
152 for(unsigned int i=0; i<num_children; i++) {
|
nuclear@2
|
153 manage_window(children[i]);
|
nuclear@2
|
154 }
|
nuclear@2
|
155 log_info("starting compositor, managing %u top-level windows\n", num_children);
|
nuclear@2
|
156 XFree(children);
|
nuclear@2
|
157
|
nuclear@2
|
158 XUngrabServer(dpy);
|
nuclear@2
|
159 }
|
nuclear@2
|
160
|
nuclear@2
|
161 static void manage_window(Window xwin)
|
nuclear@2
|
162 {
|
nuclear@2
|
163 //log_debug("manage_window %u\n", xwin);
|
nuclear@2
|
164 CompWindow *cwin = new CompWindow(xwin);
|
nuclear@2
|
165 XGetWindowAttributes(dpy, xwin, &cwin->attr);
|
nuclear@3
|
166 cwin->mapped = cwin->attr.map_state != IsUnmapped;
|
nuclear@2
|
167 add_window(cwin);
|
nuclear@2
|
168 }
|
nuclear@2
|
169
|
nuclear@2
|
170 static void unmanage_window(Window xwin)
|
nuclear@2
|
171 {
|
nuclear@2
|
172 //log_debug("unmanage_window %u\n", xwin);
|
nuclear@2
|
173 CompWindow *cwin = find_window_xid(xwin);
|
nuclear@3
|
174 if(!cwin) return;
|
nuclear@3
|
175
|
nuclear@3
|
176 if(cwin->xpixmap) {
|
nuclear@3
|
177 XFreePixmap(dpy, cwin->xpixmap);
|
nuclear@2
|
178 }
|
nuclear@3
|
179
|
nuclear@3
|
180 remove_window(cwin);
|
nuclear@3
|
181 delete cwin;
|
nuclear@2
|
182 }
|
nuclear@2
|
183
|
nuclear@2
|
184 static void redraw()
|
nuclear@2
|
185 {
|
nuclear@2
|
186 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
nuclear@2
|
187
|
nuclear@3
|
188 glPushAttrib(GL_ENABLE_BIT);
|
nuclear@3
|
189 glEnable(GL_TEXTURE_2D);
|
nuclear@2
|
190 glEnable(GL_BLEND);
|
nuclear@2
|
191 glBlendFunc(GL_ONE, GL_ONE);
|
nuclear@2
|
192
|
nuclear@2
|
193 int num_win = get_window_count();
|
nuclear@2
|
194 for(int i=0; i<num_win; i++) {
|
nuclear@2
|
195 CompWindow *cwin = get_window(i);
|
nuclear@2
|
196
|
nuclear@3
|
197 if(!cwin->mapped) continue;
|
nuclear@3
|
198
|
nuclear@3
|
199 if(cwin->attr.x + cwin->attr.width <= 0 ||
|
nuclear@3
|
200 cwin->attr.y + cwin->attr.height <= 0 ||
|
nuclear@3
|
201 cwin->attr.x >= root_width || cwin->attr.y >= root_height) {
|
nuclear@3
|
202 continue;
|
nuclear@3
|
203 }
|
nuclear@3
|
204
|
nuclear@3
|
205 draw_window(cwin);
|
nuclear@2
|
206 }
|
nuclear@2
|
207
|
nuclear@3
|
208 glPopAttrib();
|
nuclear@2
|
209
|
nuclear@2
|
210 glXSwapBuffers(dpy, comp_win);
|
nuclear@2
|
211 }
|
nuclear@2
|
212
|
nuclear@3
|
213 static void draw_window(CompWindow *cwin)
|
nuclear@3
|
214 {
|
nuclear@3
|
215 if(!cwin->xpixmap) {
|
nuclear@3
|
216 cwin->xpixmap = XCompositeNameWindowPixmap(dpy, cwin->xwin);
|
nuclear@3
|
217 if(!cwin->xpixmap) {
|
nuclear@3
|
218 log_warning("failed to get pixmap\n");
|
nuclear@3
|
219 return;
|
nuclear@3
|
220 }
|
nuclear@3
|
221 cwin->tex.set_image(dpy, cwin->xpixmap);
|
nuclear@3
|
222 }
|
nuclear@3
|
223
|
nuclear@3
|
224 glBindTexture(GL_TEXTURE_2D, cwin->tex.get_id());
|
nuclear@3
|
225
|
nuclear@3
|
226 glBegin(GL_QUADS);
|
nuclear@3
|
227 glColor3f(0.3, 0.3, 0.3);
|
nuclear@3
|
228 glTexCoord2f(0, 0);
|
nuclear@3
|
229 glVertex2f(cwin->attr.x, cwin->attr.y);
|
nuclear@3
|
230 glTexCoord2f(1, 0);
|
nuclear@3
|
231 glVertex2f(cwin->attr.x + cwin->attr.width, cwin->attr.y);
|
nuclear@3
|
232 glTexCoord2f(1, 1);
|
nuclear@3
|
233 glVertex2f(cwin->attr.x + cwin->attr.width, cwin->attr.y + cwin->attr.height);
|
nuclear@3
|
234 glTexCoord2f(0, 1);
|
nuclear@3
|
235 glVertex2f(cwin->attr.x, cwin->attr.y + cwin->attr.height);
|
nuclear@3
|
236 glEnd();
|
nuclear@3
|
237 }
|
nuclear@3
|
238
|
nuclear@2
|
239 static void reshape(int x, int y)
|
nuclear@2
|
240 {
|
nuclear@2
|
241 glViewport(0, 0, x, y);
|
nuclear@2
|
242
|
nuclear@2
|
243 glMatrixMode(GL_PROJECTION);
|
nuclear@2
|
244 glLoadIdentity();
|
nuclear@2
|
245 glOrtho(0, x, y, 0, -1, 1);
|
nuclear@2
|
246 }
|