create a LocoList data structure for tracking the stacking order of windows. watch...
authorDana Jansens <danakj@orodu.net>
Fri, 1 Feb 2008 06:54:41 +0000 (01:54 -0500)
committerDana Jansens <danakj@orodu.net>
Mon, 4 Feb 2008 14:33:29 +0000 (09:33 -0500)
loco/loco.c

index f214cb1..0bf8062 100644 (file)
 
 */
 
-void composite_setup_window(Window win)
+typedef struct {
+    Window id;
+    gint x, y, w, h;
+    gboolean input_only;
+} LocoWindow;
+
+typedef struct _LocoList {
+    struct _LocoList *next;
+    struct _LocoList *prev;
+    LocoWindow *window;
+} LocoList;
+
+static Window      loco_root;
+/* Maps X Window ID -> LocoWindow* */
+static GHashTable *window_map;
+/* Maps X Window ID -> LocoList* which is in the stacking_top/bottom list */
+static GHashTable *stacking_map;
+/* From top to bottom */
+static LocoList   *stacking_top;
+static LocoList   *stacking_bottom;
+
+/*
+static void print_stacking()
+{
+    LocoList *it;
+
+    for (it = stacking_top; it; it = it->next) {
+        printf("0x%lx\n", it->window->id);
+    }
+}
+*/
+
+static LocoList* loco_list_prepend(LocoList **top, LocoList **bottom,
+                                   LocoWindow *window)
+{
+    LocoList *n = g_new(LocoList, 1);
+    n->window = window;
+
+    n->prev = NULL;
+    n->next = *top;
+    if (n->next) n->next->prev = n;
+
+    *top = n;
+    if (!*bottom) *bottom = n;
+    return n;
+}
+
+static void loco_list_delete_link(LocoList **top, LocoList **bottom,
+                                  LocoList *pos)
+{
+    LocoList *prev = pos->prev;
+    LocoList *next = pos->next;
+
+    if (next)
+        next->prev = prev;
+    if (prev)
+        prev->next = next;
+    if (!next)
+        *bottom = prev;
+    if (!prev)
+        *top = next;
+
+    g_free(pos);
+}
+
+static void loco_list_move_before(LocoList **top, LocoList **bottom,
+                                  LocoList *move, LocoList *before)
+{
+    LocoList *prev, *next;
+
+    /* these won't move it anywhere */
+    if (move == before || move->next == before) return;
+
+    prev = move->prev;
+    next = move->next;
+
+    /* remove it from the list */
+    if (next) next->prev = prev;
+    else      *bottom = prev;
+    if (prev) prev->next = next;
+    else      *top = next;
+
+    /* reinsert it */
+    if (before) {
+        move->next = before;
+        move->prev = before->prev;
+        move->next->prev = move;
+        if (move->prev) move->prev->next = move;
+    }
+    else {
+        /* after the bottom */
+        move->prev = *bottom;
+        move->next = NULL;
+        if (move->prev) move->prev->next = move;
+        *bottom = move;
+    }
+
+    if (!move->prev) *top = move;
+}
+
+void composite_setup_window(LocoWindow *win)
 {
-    XCompositeRedirectWindow(obt_display, win, CompositeRedirectAutomatic);
-    /*something useful = */XDamageCreate(obt_display, win, XDamageReportRawRectangles);
+    if (win->input_only) return;
+
+    //XCompositeRedirectWindow(obt_display, win->id, CompositeRedirectAutomatic);
+    /*something useful = */XDamageCreate(obt_display, win->id, XDamageReportRawRectangles);
+}
+
+static void add_window(Window window)
+{
+    LocoWindow *lw;
+    LocoList *it;
+    XWindowAttributes attrib;
+
+    printf("add window 0x%lx\n", window);
+
+    if (!XGetWindowAttributes(obt_display, window, &attrib))
+        return;
+
+    lw = g_new0(LocoWindow, 1);
+    lw->id = window;
+    lw->input_only = attrib.class == InputOnly;
+    lw->x = attrib.x;
+    lw->y = attrib.y;
+    lw->w = attrib.width;
+    lw->h = attrib.height;
+    g_hash_table_insert(window_map, &lw->id, lw);
+    /* new windows are at the top */
+    it = loco_list_prepend(&stacking_top, &stacking_bottom, lw);
+    g_hash_table_insert(stacking_map, &lw->id, it);
+
+    composite_setup_window(lw);
+
+    //print_stacking();
+}
+
+static void remove_window(Window window)
+{
+    LocoWindow *lw;
+
+    printf("remove window 0x%lx\n", window);
+
+    lw = g_hash_table_lookup(window_map, &window);
+    if (lw) {
+        LocoList *pos = g_hash_table_lookup(stacking_map, &window);
+        g_assert(pos);
+
+        loco_list_delete_link(&stacking_top, &stacking_bottom, pos);
+        g_hash_table_remove(stacking_map, &window);
+        g_hash_table_remove(window_map, &window);
+
+        g_free(lw);
+    }
+
+    //print_stacking();
 }
 
 void COMPOSTER_RAWR(const XEvent *e, gpointer data)
 {
-    Window window;
     if (e->type == CreateNotify) {
-        window = e->xmap.window;
-        printf("Do first time stuff\n");
-        composite_setup_window(window);
+        add_window(e->xmap.window);
     }
-    if (e->type == obt_display_extension_damage_basep + XDamageNotify) {
+    else if (e->type == DestroyNotify) {
+        remove_window(e->xdestroywindow.window);
     }
-    if (e->type == ConfigureNotify) {
-        printf("Window moved or something\n");
+    else if (e->type == ReparentNotify) {
+        if (e->xreparent.parent == loco_root)
+            add_window(e->xreparent.window);
+        else
+            remove_window(e->xreparent.window);
+    }
+    else if (e->type == obt_display_extension_damage_basep + XDamageNotify) {
+    }
+    else if (e->type == ConfigureNotify) {
+        LocoWindow *lw;
+        printf("Window 0x%lx moved or something\n", e->xconfigure.window);
+
+        lw = g_hash_table_lookup(window_map, &e->xconfigure.window);
+        if (lw) {
+            LocoList *above, *pos;
+
+            pos = g_hash_table_lookup(stacking_map, &e->xconfigure.window);
+            above = g_hash_table_lookup(stacking_map, &e->xconfigure.above);
+
+            g_assert(pos != NULL && pos->window != NULL);
+            if (e->xconfigure.above && !above)
+                printf("missing windows from the stacking list!!\n");
+
+            lw->x = e->xconfigure.x;
+            lw->y = e->xconfigure.y;
+            lw->w = e->xconfigure.width;
+            lw->h = e->xconfigure.height;
+            printf("Window 0x%lx above 0x%lx\n", pos->window->id,
+                   above ? above->window->id : 0);
+            loco_list_move_before(&stacking_top, &stacking_bottom, pos, above);
+        }
+        //print_stacking();
     }
 }
 
-void loco_set_mainloop(gint ob_screen, ObtMainLoop *loop)
+static void find_all_windows(gint screen)
+{
+    guint i, nchild;
+    Window w, *children;
+
+    if (!XQueryTree(obt_display, loco_root, &w, &w, &children, &nchild))
+        nchild = 0;
+
+    for (i = 0; i < nchild; ++i)
+        if (children[i] != None) add_window(children[i]);
+
+    if (children) XFree(children);
+}
+
+static guint window_hash(Window *w) { return *w; }
+static gboolean window_comp(Window *w1, Window *w2) { return *w1 == *w2; }
+
+void loco_set_mainloop(gint screen_num, ObtMainLoop *loop)
 {
     int w, h;
     XVisualInfo *vi;
@@ -62,14 +258,16 @@ void loco_set_mainloop(gint ob_screen, ObtMainLoop *loop)
     int config[] =
         { GLX_DEPTH_SIZE, 1, GLX_DOUBLEBUFFER, GLX_RGBA, None };
 
-    vi = glXChooseVisual(obt_display, DefaultScreen(obt_display), config);
+    loco_root = obt_root(screen_num);
+
+    vi = glXChooseVisual(obt_display, screen_num, config);
     cont = glXCreateContext(obt_display, vi, NULL, GL_TRUE);
     if (cont == NULL)
         printf("context creation failed\n");
-    glXMakeCurrent(obt_display, RootWindow(obt_display, ob_screen), cont);
+    glXMakeCurrent(obt_display, loco_root, cont);
 
-    w = WidthOfScreen(ScreenOfDisplay(obt_display, ob_screen));
-    h = HeightOfScreen(ScreenOfDisplay(obt_display, ob_screen));
+    w = WidthOfScreen(ScreenOfDisplay(obt_display, screen_num));
+    h = HeightOfScreen(ScreenOfDisplay(obt_display, screen_num));
     glViewport(0, 0, w, h);
     glMatrixMode(GL_PROJECTION);
     glLoadIdentity();
@@ -79,8 +277,15 @@ printf("Setting up an orthographic projection of %dx%d\n", w, h);
     glLoadIdentity();
     glClear(GL_COLOR_BUFFER_BIT);
     glEnable(GL_TEXTURE_RECTANGLE_ARB);
-    glXSwapBuffers(obt_display, RootWindow(obt_display, ob_screen));
+    glXSwapBuffers(obt_display, loco_root);
     obt_main_loop_x_add(loop, COMPOSTER_RAWR, NULL, NULL);
+    window_map = g_hash_table_new((GHashFunc)window_hash,
+                                  (GEqualFunc)window_comp);
+    stacking_map = g_hash_table_new((GHashFunc)window_hash,
+                                    (GEqualFunc)window_comp);
+    stacking_top = stacking_bottom = NULL;
+
+    find_all_windows(screen_num);
 }
 
 void loco_shutdown(void)