1 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
3 loco.c for the Openbox window manager
4 Copyright (c) 2008 Derek Foreman
5 Copyright (c) 2008 Dana Jansens
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.
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.
17 See the COPYING file for a copy of the GNU General Public License.
21 #include "obt/mainloop.h"
22 #include "obt/display.h"
23 #include "obt/mainloop.h"
28 #include <GL/glxext.h>
29 #include <GL/glxtokens.h>
31 <dana> you want CreateNotify, DestroyNotify, MapNotify, UnmapNotify, and
33 <dana> and then xdamage or whatever
42 gint type; /* XXX make this an enum */
45 typedef struct _LocoList {
46 struct _LocoList *next;
47 struct _LocoList *prev;
51 static Window loco_root;
52 /* Maps X Window ID -> LocoWindow* */
53 static GHashTable *window_map;
54 /* Maps X Window ID -> LocoList* which is in the stacking_top/bottom list */
55 static GHashTable *stacking_map;
56 /* From top to bottom */
57 static LocoList *stacking_top;
58 static LocoList *stacking_bottom;
61 static void print_stacking()
65 for (it = stacking_top; it; it = it->next) {
66 printf("0x%lx\n", it->window->id);
71 static LocoList* loco_list_prepend(LocoList **top, LocoList **bottom,
74 LocoList *n = g_new(LocoList, 1);
79 if (n->next) n->next->prev = n;
82 if (!*bottom) *bottom = n;
86 static void loco_list_delete_link(LocoList **top, LocoList **bottom,
89 LocoList *prev = pos->prev;
90 LocoList *next = pos->next;
104 static void loco_list_move_before(LocoList **top, LocoList **bottom,
105 LocoList *move, LocoList *before)
107 LocoList *prev, *next;
109 /* these won't move it anywhere */
110 if (move == before || move->next == before) return;
115 /* remove it from the list */
116 if (next) next->prev = prev;
118 if (prev) prev->next = next;
124 move->prev = before->prev;
125 move->next->prev = move;
126 if (move->prev) move->prev->next = move;
129 /* after the bottom */
130 move->prev = *bottom;
132 if (move->prev) move->prev->next = move;
136 if (!move->prev) *top = move;
139 /* Returns a LocoWindow structure */
140 static LocoWindow* find_window(Window window)
142 return g_hash_table_lookup(window_map, &window);
145 /* Returns a node from the stacking_top/bottom list */
146 static LocoList* find_stacking(Window window)
148 return g_hash_table_lookup(stacking_map, &window);
151 void composite_setup_window(LocoWindow *win)
153 if (win->input_only) return;
155 //XCompositeRedirectWindow(obt_display, win->id, CompositeRedirectAutomatic);
156 /*something useful = */XDamageCreate(obt_display, win->id, XDamageReportRawRectangles);
159 static void add_window(Window window)
163 XWindowAttributes attrib;
165 printf("add window 0x%lx\n", window);
167 if (!XGetWindowAttributes(obt_display, window, &attrib))
170 lw = g_new0(LocoWindow, 1);
172 lw->input_only = attrib.class == InputOnly;
175 lw->w = attrib.width;
176 lw->h = attrib.height;
177 g_hash_table_insert(window_map, &lw->id, lw);
178 /* new windows are at the top */
179 it = loco_list_prepend(&stacking_top, &stacking_bottom, lw);
180 g_hash_table_insert(stacking_map, &lw->id, it);
182 composite_setup_window(lw);
187 static void remove_window(LocoWindow *lw)
189 printf("remove window 0x%lx\n", lw->id);
191 LocoList *pos = find_stacking(lw->id);
194 loco_list_delete_link(&stacking_top, &stacking_bottom, pos);
195 g_hash_table_remove(stacking_map, &lw->id);
196 g_hash_table_remove(window_map, &lw->id);
203 static void show_window(LocoWindow *lw)
210 /* get the window's semantic type (for different effects!) */
211 lw->type = 0; /* XXX set this to the default type */
212 if (OBT_PROP_GETA32(lw->id, NET_WM_WINDOW_TYPE, ATOM, &type, &ntype)) {
213 /* use the first value that we know about in the array */
214 for (i = 0; i < ntype; ++i) {
215 /* XXX SET THESE TO AN ENUM'S VALUES */
216 if (type[i] == OBT_PROP_ATOM(NET_WM_WINDOW_TYPE_DESKTOP))
218 if (type[i] == OBT_PROP_ATOM(NET_WM_WINDOW_TYPE_MENU))
220 /* XXX there are more TYPES that need to be added to prop.h */
227 static void hide_window(LocoWindow *lw, gboolean destroyed)
229 /* if destroyed, then the window is no longer available */
233 void COMPOSTER_RAWR(const XEvent *e, gpointer data)
235 if (e->type == ConfigureNotify) {
237 printf("Window 0x%lx moved or something\n", e->xconfigure.window);
239 lw = find_window(e->xconfigure.window);
241 LocoList *above, *pos;
243 pos = find_stacking(e->xconfigure.window);
244 above = find_stacking(e->xconfigure.above);
246 g_assert(pos != NULL && pos->window != NULL);
247 if (e->xconfigure.above && !above)
248 printf("missing windows from the stacking list!!\n");
250 lw->x = e->xconfigure.x;
251 lw->y = e->xconfigure.y;
252 lw->w = e->xconfigure.width;
253 lw->h = e->xconfigure.height;
254 printf("Window 0x%lx above 0x%lx\n", pos->window->id,
255 above ? above->window->id : 0);
256 loco_list_move_before(&stacking_top, &stacking_bottom, pos, above);
260 else if (e->type == CreateNotify) {
261 add_window(e->xmap.window);
263 else if (e->type == DestroyNotify) {
264 LocoWindow *lw = find_window(e->xdestroywindow.window);
266 hide_window(lw, TRUE);
270 printf("destroy notify for unknown window 0x%lx\n",
271 e->xdestroywindow.window);
273 else if (e->type == ReparentNotify) {
274 if (e->xreparent.parent == loco_root)
275 add_window(e->xreparent.window);
277 LocoWindow *lw = find_window(e->xreparent.window);
279 hide_window(lw, FALSE);
283 printf("reparent notify away from root for unknown window "
284 "0x%lx\n", e->xreparent.window);
287 else if (e->type == MapNotify) {
288 LocoWindow *lw = find_window(e->xmap.window);
289 if (lw) show_window(lw);
291 printf("map notify for unknown window 0x%lx\n",
294 else if (e->type == UnmapNotify) {
295 LocoWindow *lw = find_window(e->xunmap.window);
296 if (lw) hide_window(lw, FALSE);
298 printf("unmap notify for unknown window 0x%lx\n",
301 else if (e->type == obt_display_extension_damage_basep + XDamageNotify) {
305 static void find_all_windows(gint screen)
310 if (!XQueryTree(obt_display, loco_root, &w, &w, &children, &nchild))
313 for (i = 0; i < nchild; ++i)
314 if (children[i] != None) add_window(children[i]);
316 if (children) XFree(children);
319 static guint window_hash(Window *w) { return *w; }
320 static gboolean window_comp(Window *w1, Window *w2) { return *w1 == *w2; }
322 void loco_set_mainloop(gint screen_num, ObtMainLoop *loop)
328 { GLX_DEPTH_SIZE, 1, GLX_DOUBLEBUFFER, GLX_RGBA, None };
330 loco_root = obt_root(screen_num);
332 vi = glXChooseVisual(obt_display, screen_num, config);
333 cont = glXCreateContext(obt_display, vi, NULL, GL_TRUE);
335 printf("context creation failed\n");
336 glXMakeCurrent(obt_display, loco_root, cont);
338 w = WidthOfScreen(ScreenOfDisplay(obt_display, screen_num));
339 h = HeightOfScreen(ScreenOfDisplay(obt_display, screen_num));
340 glViewport(0, 0, w, h);
341 glMatrixMode(GL_PROJECTION);
343 printf("Setting up an orthographic projection of %dx%d\n", w, h);
344 glOrtho(0, w, h, 0.0, -1.0, 100.0);
345 glMatrixMode(GL_MODELVIEW);
347 glClear(GL_COLOR_BUFFER_BIT);
348 glEnable(GL_TEXTURE_RECTANGLE_ARB);
349 glXSwapBuffers(obt_display, loco_root);
350 obt_main_loop_x_add(loop, COMPOSTER_RAWR, NULL, NULL);
351 window_map = g_hash_table_new((GHashFunc)window_hash,
352 (GEqualFunc)window_comp);
353 stacking_map = g_hash_table_new((GHashFunc)window_hash,
354 (GEqualFunc)window_comp);
355 stacking_top = stacking_bottom = NULL;
357 find_all_windows(screen_num);
360 void loco_shutdown(void)