0bf8062690456205e5ed30e9162210fee6f746b8
[dana/openbox.git] / loco / loco.c
1 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
2
3    loco.c for the Openbox window manager
4    Copyright (c) 2008        Derek Foreman
5    Copyright (c) 2008        Dana Jansens
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    See the COPYING file for a copy of the GNU General Public License.
18 */
19
20 #include <stdio.h>
21 #include "obt/mainloop.h"
22 #include "obt/display.h"
23 #include "obt/mainloop.h"
24 #include <glib.h>
25 #include <GL/glx.h>
26 #include <GL/glext.h>
27 #include <GL/glxext.h>
28 #include <GL/glxtokens.h>
29 /*
30 <dana> you want CreateNotify, DestroyNotify, MapNotify, UnmapNotify, and
31           ConfigureNotify
32           <dana> and then xdamage or whatever
33
34 */
35
36 typedef struct {
37     Window id;
38     gint x, y, w, h;
39     gboolean input_only;
40 } LocoWindow;
41
42 typedef struct _LocoList {
43     struct _LocoList *next;
44     struct _LocoList *prev;
45     LocoWindow *window;
46 } LocoList;
47
48 static Window      loco_root;
49 /* Maps X Window ID -> LocoWindow* */
50 static GHashTable *window_map;
51 /* Maps X Window ID -> LocoList* which is in the stacking_top/bottom list */
52 static GHashTable *stacking_map;
53 /* From top to bottom */
54 static LocoList   *stacking_top;
55 static LocoList   *stacking_bottom;
56
57 /*
58 static void print_stacking()
59 {
60     LocoList *it;
61
62     for (it = stacking_top; it; it = it->next) {
63         printf("0x%lx\n", it->window->id);
64     }
65 }
66 */
67
68 static LocoList* loco_list_prepend(LocoList **top, LocoList **bottom,
69                                    LocoWindow *window)
70 {
71     LocoList *n = g_new(LocoList, 1);
72     n->window = window;
73
74     n->prev = NULL;
75     n->next = *top;
76     if (n->next) n->next->prev = n;
77
78     *top = n;
79     if (!*bottom) *bottom = n;
80     return n;
81 }
82
83 static void loco_list_delete_link(LocoList **top, LocoList **bottom,
84                                   LocoList *pos)
85 {
86     LocoList *prev = pos->prev;
87     LocoList *next = pos->next;
88
89     if (next)
90         next->prev = prev;
91     if (prev)
92         prev->next = next;
93     if (!next)
94         *bottom = prev;
95     if (!prev)
96         *top = next;
97
98     g_free(pos);
99 }
100
101 static void loco_list_move_before(LocoList **top, LocoList **bottom,
102                                   LocoList *move, LocoList *before)
103 {
104     LocoList *prev, *next;
105
106     /* these won't move it anywhere */
107     if (move == before || move->next == before) return;
108
109     prev = move->prev;
110     next = move->next;
111
112     /* remove it from the list */
113     if (next) next->prev = prev;
114     else      *bottom = prev;
115     if (prev) prev->next = next;
116     else      *top = next;
117
118     /* reinsert it */
119     if (before) {
120         move->next = before;
121         move->prev = before->prev;
122         move->next->prev = move;
123         if (move->prev) move->prev->next = move;
124     }
125     else {
126         /* after the bottom */
127         move->prev = *bottom;
128         move->next = NULL;
129         if (move->prev) move->prev->next = move;
130         *bottom = move;
131     }
132
133     if (!move->prev) *top = move;
134 }
135
136 void composite_setup_window(LocoWindow *win)
137 {
138     if (win->input_only) return;
139
140     //XCompositeRedirectWindow(obt_display, win->id, CompositeRedirectAutomatic);
141     /*something useful = */XDamageCreate(obt_display, win->id, XDamageReportRawRectangles);
142 }
143
144 static void add_window(Window window)
145 {
146     LocoWindow *lw;
147     LocoList *it;
148     XWindowAttributes attrib;
149
150     printf("add window 0x%lx\n", window);
151
152     if (!XGetWindowAttributes(obt_display, window, &attrib))
153         return;
154
155     lw = g_new0(LocoWindow, 1);
156     lw->id = window;
157     lw->input_only = attrib.class == InputOnly;
158     lw->x = attrib.x;
159     lw->y = attrib.y;
160     lw->w = attrib.width;
161     lw->h = attrib.height;
162     g_hash_table_insert(window_map, &lw->id, lw);
163     /* new windows are at the top */
164     it = loco_list_prepend(&stacking_top, &stacking_bottom, lw);
165     g_hash_table_insert(stacking_map, &lw->id, it);
166
167     composite_setup_window(lw);
168
169     //print_stacking();
170 }
171
172 static void remove_window(Window window)
173 {
174     LocoWindow *lw;
175
176     printf("remove window 0x%lx\n", window);
177
178     lw = g_hash_table_lookup(window_map, &window);
179     if (lw) {
180         LocoList *pos = g_hash_table_lookup(stacking_map, &window);
181         g_assert(pos);
182
183         loco_list_delete_link(&stacking_top, &stacking_bottom, pos);
184         g_hash_table_remove(stacking_map, &window);
185         g_hash_table_remove(window_map, &window);
186
187         g_free(lw);
188     }
189
190     //print_stacking();
191 }
192
193 void COMPOSTER_RAWR(const XEvent *e, gpointer data)
194 {
195     if (e->type == CreateNotify) {
196         add_window(e->xmap.window);
197     }
198     else if (e->type == DestroyNotify) {
199         remove_window(e->xdestroywindow.window);
200     }
201     else if (e->type == ReparentNotify) {
202         if (e->xreparent.parent == loco_root)
203             add_window(e->xreparent.window);
204         else
205             remove_window(e->xreparent.window);
206     }
207     else if (e->type == obt_display_extension_damage_basep + XDamageNotify) {
208     }
209     else if (e->type == ConfigureNotify) {
210         LocoWindow *lw;
211         printf("Window 0x%lx moved or something\n", e->xconfigure.window);
212
213         lw = g_hash_table_lookup(window_map, &e->xconfigure.window);
214         if (lw) {
215             LocoList *above, *pos;
216
217             pos = g_hash_table_lookup(stacking_map, &e->xconfigure.window);
218             above = g_hash_table_lookup(stacking_map, &e->xconfigure.above);
219
220             g_assert(pos != NULL && pos->window != NULL);
221             if (e->xconfigure.above && !above)
222                 printf("missing windows from the stacking list!!\n");
223
224             lw->x = e->xconfigure.x;
225             lw->y = e->xconfigure.y;
226             lw->w = e->xconfigure.width;
227             lw->h = e->xconfigure.height;
228             printf("Window 0x%lx above 0x%lx\n", pos->window->id,
229                    above ? above->window->id : 0);
230             loco_list_move_before(&stacking_top, &stacking_bottom, pos, above);
231         }
232         //print_stacking();
233     }
234 }
235
236 static void find_all_windows(gint screen)
237 {
238     guint i, nchild;
239     Window w, *children;
240
241     if (!XQueryTree(obt_display, loco_root, &w, &w, &children, &nchild))
242         nchild = 0;
243
244     for (i = 0; i < nchild; ++i)
245         if (children[i] != None) add_window(children[i]);
246
247     if (children) XFree(children);
248 }
249
250 static guint window_hash(Window *w) { return *w; }
251 static gboolean window_comp(Window *w1, Window *w2) { return *w1 == *w2; }
252
253 void loco_set_mainloop(gint screen_num, ObtMainLoop *loop)
254 {
255     int w, h;
256     XVisualInfo *vi;
257     GLXContext cont;
258     int config[] =
259         { GLX_DEPTH_SIZE, 1, GLX_DOUBLEBUFFER, GLX_RGBA, None };
260
261     loco_root = obt_root(screen_num);
262
263     vi = glXChooseVisual(obt_display, screen_num, config);
264     cont = glXCreateContext(obt_display, vi, NULL, GL_TRUE);
265     if (cont == NULL)
266         printf("context creation failed\n");
267     glXMakeCurrent(obt_display, loco_root, cont);
268
269     w = WidthOfScreen(ScreenOfDisplay(obt_display, screen_num));
270     h = HeightOfScreen(ScreenOfDisplay(obt_display, screen_num));
271     glViewport(0, 0, w, h);
272     glMatrixMode(GL_PROJECTION);
273     glLoadIdentity();
274 printf("Setting up an orthographic projection of %dx%d\n", w, h);
275     glOrtho(0, w, h, 0.0, -1.0, 100.0);
276     glMatrixMode(GL_MODELVIEW);
277     glLoadIdentity();
278     glClear(GL_COLOR_BUFFER_BIT);
279     glEnable(GL_TEXTURE_RECTANGLE_ARB);
280     glXSwapBuffers(obt_display, loco_root);
281     obt_main_loop_x_add(loop, COMPOSTER_RAWR, NULL, NULL);
282     window_map = g_hash_table_new((GHashFunc)window_hash,
283                                   (GEqualFunc)window_comp);
284     stacking_map = g_hash_table_new((GHashFunc)window_hash,
285                                     (GEqualFunc)window_comp);
286     stacking_top = stacking_bottom = NULL;
287
288     find_all_windows(screen_num);
289 }
290
291 void loco_shutdown(void)
292 {
293 }