From 7df331d7e982ce91b2000364ca8b64b6ca562f83 Mon Sep 17 00:00:00 2001 From: Dana Jansens Date: Sat, 9 Feb 2008 02:28:06 -0500 Subject: [PATCH] split loco into a bunch of files. it looks an awful lot like glxcompmgr somehow.. --- Makefile.am | 11 +- loco/glerror.h | 38 +++ loco/list.c | 90 ++++++ loco/list.h | 43 +++ loco/loco.c | 796 +++++++--------------------------------------- loco/loco.h | 13 +- loco/paint.c | 102 ++++++ loco/paint.h | 30 ++ loco/screen.c | 228 +++++++++++++ loco/screen.h | 72 +++++ loco/window.c | 271 ++++++++++++++++ loco/window.h | 67 ++++ obt/display.c | 6 +- obt/mainloop.c | 20 +- obt/mainloop.h | 3 + openbox/openbox.c | 14 +- 16 files changed, 1105 insertions(+), 699 deletions(-) create mode 100644 loco/glerror.h create mode 100644 loco/list.c create mode 100644 loco/list.h create mode 100644 loco/paint.c create mode 100644 loco/paint.h create mode 100644 loco/screen.c create mode 100644 loco/screen.h create mode 100644 loco/window.c create mode 100644 loco/window.h diff --git a/Makefile.am b/Makefile.am index f8c1a17d..dc38093f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -164,7 +164,16 @@ loco_liboco_la_LIBADD = \ $(XCOMPOSITE_LIBS) \ $(GLIB_LIBS) loco_liboco_la_SOURCES = \ - loco/loco.c + loco/list.c \ + loco/list.h \ + loco/loco.c \ + loco/loco.h \ + loco/paint.c \ + loco/paint.h \ + loco/screen.c \ + loco/screen.h \ + loco/window.c \ + loco/window.h ## openbox ## diff --git a/loco/glerror.h b/loco/glerror.h new file mode 100644 index 00000000..9d1c719d --- /dev/null +++ b/loco/glerror.h @@ -0,0 +1,38 @@ +/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*- + + glerror.h for the Openbox compositor + Copyright (c) 2008 Derek Foreman + Copyright (c) 2008 Dana Jansens + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + See the COPYING file for a copy of the GNU General Public License. +*/ + +#ifndef loco__glerror_h +#define loco__glerror_h + +#include + +#define glError() \ +{ \ + /*const GLchar *err_file = strrchr(err_path, '/');*/ \ + GLenum gl_error = glGetError(); \ + \ + /*++err_file;*/ \ + \ + for (; (gl_error); gl_error = glGetError()) \ + g_print("%s: %d caught at line %u\n", \ + __FUNCTION__, gl_error, __LINE__); \ + /*(const GLchar*)gluErrorString(gl_error)*/ \ +} + +#endif diff --git a/loco/list.c b/loco/list.c new file mode 100644 index 00000000..f9bbfb71 --- /dev/null +++ b/loco/list.c @@ -0,0 +1,90 @@ +/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*- + + list.c for the Openbox window manager + Copyright (c) 2008 Derek Foreman + Copyright (c) 2008 Dana Jansens + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + See the COPYING file for a copy of the GNU General Public License. +*/ + +#include "list.h" +#include "window.h" + +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; +} + +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); +} + +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; +} + diff --git a/loco/list.h b/loco/list.h new file mode 100644 index 00000000..11d5ddb2 --- /dev/null +++ b/loco/list.h @@ -0,0 +1,43 @@ +/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*- + + list.h for the Openbox compositor + Copyright (c) 2008 Dana Jansens + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + See the COPYING file for a copy of the GNU General Public License. +*/ + +#ifndef loco__list_h +#define loco__list_h + +struct _LocoWindow; + +/* To make a new LocoList, create 2 pointers: one for the head, one for the + tail. Initialize them both to NULL. Then pass them to loco_list_prepend. +*/ + +typedef struct _LocoList { + struct _LocoList *next; + struct _LocoList *prev; + struct _LocoWindow *window; +} LocoList; + +LocoList* loco_list_prepend(LocoList **top, LocoList **bottom, + struct _LocoWindow *window); + +void loco_list_delete_link(LocoList **top, LocoList **bottom, + LocoList *pos); + +void loco_list_move_before(LocoList **top, LocoList **bottom, + LocoList *move, LocoList *before); + +#endif diff --git a/loco/loco.c b/loco/loco.c index b28f4ef7..85d93bdb 100644 --- a/loco/loco.c +++ b/loco/loco.c @@ -17,738 +17,156 @@ See the COPYING file for a copy of the GNU General Public License. */ -#include +#include "loco.h" +#include "screen.h" +#include "window.h" +#include "paint.h" + #include "obt/mainloop.h" #include "obt/display.h" -#include "obt/mainloop.h" #include "obt/prop.h" -#include -#include -#include -#include -#include -/* - you want CreateNotify, DestroyNotify, MapNotify, UnmapNotify, and - ConfigureNotify - and then xdamage or whatever - -*/ - -#define glError() \ -{ \ - /*const GLchar *err_file = strrchr(err_path, '/');*/ \ - GLenum gl_error = glGetError(); \ - \ - /*++err_file;*/ \ - \ - for (; (gl_error); gl_error = glGetError()) \ - fprintf(stderr, "%s: %d caught at line %u\n", \ - __FUNCTION__, gl_error, __LINE__); \ - /*(const GLchar*)gluErrorString(gl_error)*/ \ -} +#include -#define MAX_DEPTH 32 #define REFRESH_RATE (G_USEC_PER_SEC/60) -typedef struct { - Window id; - gint x, y, w, h; - gint depth; - gboolean input_only; - gboolean visible; - gint type; /* XXX make this an enum */ - GLuint texname; - Damage damage; - Pixmap pixmap; - GLXPixmap glpixmap; - gboolean damaged; -} LocoWindow; - -typedef struct _LocoList { - struct _LocoList *next; - struct _LocoList *prev; - LocoWindow *window; -} LocoList; - -static Window loco_root; -static Window loco_overlay; -/* 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 GLXFBConfig glxFBConfig[MAX_DEPTH + 1]; -static int loco_screen_num; -static gboolean full_redraw_required; -static gboolean redraw_required; - -typedef void (*BindEXTFunc)(Display *, GLXDrawable, int, const int *); -typedef void (*ReleaseEXTFunc)(Display *, GLXDrawable, int); - -BindEXTFunc BindTexImageEXT; -ReleaseEXTFunc ReleaseTexImageEXT; - -static void show_window(LocoWindow *lw); -static void remove_window(LocoWindow *lw); - -/* -static void print_stacking() -{ - LocoList *it; - - for (it = stacking_top; it; it = it->next) { - printf("0x%lx\n", it->window->id); - } -} -*/ - -static glong timecompare(GTimeVal *a, GTimeVal *b) -{ - glong r; - if ((r = a->tv_sec - b->tv_sec)) return r; - return a->tv_usec - b->tv_usec; -} - -static void timeadd(GTimeVal *t, glong microseconds) -{ - t->tv_usec += microseconds; - while (t->tv_usec >= G_USEC_PER_SEC) { - t->tv_usec -= G_USEC_PER_SEC; - ++t->tv_sec; - } - while (t->tv_usec < 0) { - t->tv_usec += G_USEC_PER_SEC; - --t->tv_sec; - } -} - -static Bool look_for_destroy_notify(Display *d, XEvent *e, XPointer arg) -{ - const Window w = (Window)*arg; - return e->type == DestroyNotify && e->xdestroywindow.window == w; -} - -gboolean create_glxpixmap(LocoWindow *lw) -{ - static const int attrs[] = - { GLX_TEXTURE_FORMAT_EXT, GLX_TEXTURE_FORMAT_RGBA_EXT, None }; - XEvent ce; - - if (!glxFBConfig[lw->depth]) { - printf("no glxFBConfig for depth %d for window 0x%lx\n", - lw->depth, lw->id); - return FALSE; - } - - /* make sure the window exists */ - XGrabServer(obt_display); - XSync(obt_display, FALSE); - - if (!XCheckIfEvent(obt_display, &ce, look_for_destroy_notify, - (XPointer)&lw->id)) - { - lw->pixmap = XCompositeNameWindowPixmap(obt_display, lw->id); - lw->glpixmap = glXCreatePixmap(obt_display, glxFBConfig[lw->depth], - lw->pixmap, attrs); - if (!lw->glpixmap) { - XFreePixmap(obt_display, lw->pixmap); - lw->pixmap = None; - } - } - - XUngrabServer(obt_display); - XFlush(obt_display); - - return !!lw->glpixmap; -} - -int bindPixmapToTexture(LocoWindow *lw) -{ - if (lw->glpixmap != None) - return 1; /* already bound */ - - if (!create_glxpixmap(lw)) - return 0; /* horrible failure */ - -/* - if (screen->queryDrawable (screen->display->display, - texture->pixmap, - GLX_TEXTURE_TARGET_EXT, - &target)) - { - fprintf (stderr, "%s: glXQueryDrawable failed\n", programName); - - glXDestroyGLXPixmap (screen->display->display, texture->pixmap); - texture->pixmap = None; - - return FALSE; - } -*/ - - glBindTexture(GL_TEXTURE_2D, lw->texname); -glError(); - BindTexImageEXT(obt_display, lw->glpixmap, GLX_FRONT_LEFT_EXT, NULL); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - return 1; -} - -void destroy_glxpixmap(LocoWindow *lw) -{ - if (lw->glpixmap) { - glBindTexture(GL_TEXTURE_2D, lw->texname); - ReleaseTexImageEXT(obt_display, lw->glpixmap, GLX_FRONT_LEFT_EXT); - glBindTexture(GL_TEXTURE_2D, 0); - - obt_display_ignore_errors(TRUE); - glXDestroyGLXPixmap(obt_display, lw->glpixmap); - obt_display_ignore_errors(FALSE); - - XFreePixmap(obt_display, lw->pixmap); - - lw->pixmap = None; - lw->glpixmap = None; - } -} - -static void full_composite(void) -{ - int ret; - LocoList *it; - - /* XXX if (full_redraw_required) */ - glClear(GL_COLOR_BUFFER_BIT); - - for (it = stacking_bottom; it != stacking_top; it = it->prev) { - if (it->window->input_only) continue; - if (!it->window->visible) continue; - /* XXX if (!full_redraw_required && !it->window->damaged) continue; */ - - if (!full_redraw_required) { - /* XXX if the window is transparent, then clear the background - behind it */ - } - - glBindTexture(GL_TEXTURE_2D, it->window->texname); - ret = bindPixmapToTexture(it->window); - if (ret) { - glBegin(GL_QUADS); - glColor3f(1.0, 1.0, 1.0); - glVertex2i(it->window->x, it->window->y); - glTexCoord2f(1, 0); - glVertex2i(it->window->x + it->window->w, it->window->y); - glTexCoord2f(1, 1); - glVertex2i(it->window->x + it->window->w, - it->window->y + it->window->h); - glTexCoord2f(0, 1); - glVertex2i(it->window->x, it->window->y + it->window->h); - glTexCoord2f(0, 0); - glEnd(); - } - - it->window->damaged = FALSE; - } - glXSwapBuffers(obt_display, loco_overlay); - - full_redraw_required = redraw_required = FALSE; -} - -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; -} - -/* Returns a LocoWindow structure */ -static LocoWindow* find_window(Window window) -{ - return g_hash_table_lookup(window_map, &window); -} - -/* Returns a node from the stacking_top/bottom list */ -static LocoList* find_stacking(Window window) -{ - return g_hash_table_lookup(stacking_map, &window); -} - -static void add_window(Window window) -{ - LocoWindow *lw; - LocoList *it; - XWindowAttributes attrib; +static LocoScreen **screens = NULL; +static ObtMainLoop *mainloop = NULL; - 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; - lw->depth = attrib.depth; - - 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); - - if (!lw->input_only) { - glGenTextures(1, &lw->texname); - // glTexImage2D(TARGET, 0, GL_RGB, lw->w, lw->h, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL); - lw->damage = XDamageCreate(obt_display, window, XDamageReportNonEmpty); - } - - //print_stacking(); - - if (attrib.map_state != IsUnmapped) - show_window(lw); -} - -static void remove_window(LocoWindow *lw) -{ - printf("remove window 0x%lx\n", lw->id); - - LocoList *pos = find_stacking(lw->id); - g_assert(pos); - - if (!lw->input_only) { - glDeleteTextures(1, &lw->texname); - obt_display_ignore_errors(TRUE); - XDamageDestroy(obt_display, lw->damage); - obt_display_ignore_errors(FALSE); - } - - loco_list_delete_link(&stacking_top, &stacking_bottom, pos); - g_hash_table_remove(stacking_map, &lw->id); - g_hash_table_remove(window_map, &lw->id); - - g_free(lw); - - //print_stacking(); -} - -static void show_window(LocoWindow *lw) -{ - guint32 *type; - guint i, ntype; - - lw->visible = TRUE; - - /* get the window's semantic type (for different effects!) */ - lw->type = 0; /* XXX set this to the default type */ - if (OBT_PROP_GETA32(lw->id, NET_WM_WINDOW_TYPE, ATOM, &type, &ntype)) { - /* use the first value that we know about in the array */ - for (i = 0; i < ntype; ++i) { - /* XXX SET THESE TO AN ENUM'S VALUES */ - if (type[i] == OBT_PROP_ATOM(NET_WM_WINDOW_TYPE_DESKTOP)) - lw->type = 1; - if (type[i] == OBT_PROP_ATOM(NET_WM_WINDOW_TYPE_MENU)) - lw->type = 2; - /* XXX there are more TYPES that need to be added to prop.h */ - } - g_free(type); - } - - full_redraw_required = redraw_required = TRUE; -} - -static void hide_window(LocoWindow *lw, gboolean destroyed) -{ - /* if destroyed, then the window is no longer available */ - lw->visible = FALSE; - destroy_glxpixmap(lw); - - full_redraw_required = redraw_required = TRUE; -} - -static void configure_window(LocoWindow *lw, const XConfigureEvent *e) -{ - LocoList *above, *pos; - - pos = find_stacking(e->window); - above = find_stacking(e->above); - - g_assert(pos != NULL && pos->window != NULL); - if (e->above && !above) - printf("missing windows from the stacking list!!\n"); - - if ((lw->x != e->x) || (lw->y != e->y)) { - lw->x = e->x; - lw->y = e->y; - - full_redraw_required = redraw_required = TRUE; - } - - if ((lw->w != e->width) || (lw->h != e->height)) { - lw->w = e->width; - lw->h = e->height; - - destroy_glxpixmap(lw); - - full_redraw_required = redraw_required = TRUE; - } - - if (pos->next != above) { - //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); - - full_redraw_required = redraw_required = TRUE; - } -} - -static void damage_window(LocoWindow *lw) -{ - LocoList *it, *pos; - - pos = find_stacking(lw->id); - - /* XXX if it is transparent, then damage any windows below it that - intersect */ - - /* damage any windows above it that intersect */ - for (it = pos; it; it = it->prev) { - const LocoWindow *lwa = it->window; - if (lwa->x < lw->x + lw->w && lwa->x + lwa->w > lw->x && - lwa->y < lw->y + lw->h && lwa->y + lwa->h > lw->y) - { - it->window->damaged = TRUE; - } - } - - /* mark the damage as fixed - we know about it now */ - obt_display_ignore_errors(TRUE); - XDamageSubtract(obt_display, lw->damage, None, None); - obt_display_ignore_errors(FALSE); - - lw->damaged = TRUE; - redraw_required = TRUE; -} +/* XXX stop removing windows from the stacking until they have no more refs */ void COMPOSTER_RAWR(const XEvent *e, gpointer data) { - //g_print("COMPOSTER_RAWR() %d\n", e->type); + LocoScreen *sc = data; + LocoWindow *lw = NULL; - if (e->type == ConfigureNotify) { - LocoWindow *lw; + /*g_print("COMPOSTER_RAWR() %d\n", e->type);*/ - lw = find_window(e->xconfigure.window); - if (lw) - configure_window(lw, &e->xconfigure); - //print_stacking(); - } - else if (e->type == CreateNotify) { - add_window(e->xmap.window); - } - else if (e->type == DestroyNotify) { - LocoWindow *lw = find_window(e->xdestroywindow.window); + switch (e->type) { + case CreateNotify: + if (e->xcreatewindow.parent == sc->root) + loco_screen_add_window(sc, e->xcreatewindow.window); + break; + case DestroyNotify: + lw = loco_screen_find_window(sc, e->xdestroywindow.window); if (lw) { - hide_window(lw, TRUE); - remove_window(lw); + loco_window_hide(lw, TRUE); + loco_screen_remove_window(sc, lw); } else - printf("destroy notify for unknown window 0x%lx\n", - e->xdestroywindow.window); - } - else if (e->type == ReparentNotify) { - if (e->xreparent.parent == loco_root) - add_window(e->xreparent.window); + g_print("destroy notify for unknown window 0x%lx\n", + e->xdestroywindow.window); + break; + case ReparentNotify: + if (e->xreparent.parent == sc->root) + /* reparented to root */ + loco_screen_add_window(sc, e->xreparent.window); else { - LocoWindow *lw = find_window(e->xreparent.window); + /* reparented away from root */ + lw = loco_screen_find_window(sc, e->xreparent.window); if (lw) { - printf("window 0x%lx reparented from root\n", lw->id); - hide_window(lw, FALSE); - remove_window(lw); + g_print("window 0x%lx reparented from root\n", lw->id); + loco_window_hide(lw, FALSE); + loco_screen_remove_window(sc, lw); } else - printf("reparent notify away from root for unknown window " - "0x%lx\n", e->xreparent.window); + g_print("reparent notify away from root for unknown window " + "0x%lx\n", e->xreparent.window); } - } - - else if (e->type == MapNotify) { - LocoWindow *lw = find_window(e->xmap.window); - if (lw) - show_window(lw); - else - printf("map notify for unknown window 0x%lx\n", - e->xmap.window); - } - else if (e->type == UnmapNotify) { - LocoWindow *lw = find_window(e->xunmap.window); - if (lw) - hide_window(lw, FALSE); - else - printf("unmap notify for unknown window 0x%lx\n", - e->xunmap.window); - } - else if (e->type == obt_display_extension_damage_basep + XDamageNotify) { - const XDamageNotifyEvent *de; - LocoWindow *lw; - - de = (const XDamageNotifyEvent*)e; - lw = find_window(de->drawable); - if (lw) { - damage_window(lw); - } - else if (de->drawable == loco_root) { + break; + case MapNotify: + lw = loco_screen_find_window(sc, e->xmap.window); + if (lw) loco_window_show(lw); + else g_print("map notify for unknown window 0x%lx\n", e->xmap.window); + break; + case UnmapNotify: + lw = loco_screen_find_window(sc, e->xunmap.window); + if (lw) loco_window_hide(lw, FALSE); + else g_print("unmap notify for unknown window 0x%lx\n", + e->xunmap.window); + break; + case ConfigureNotify: + lw = loco_screen_find_window(sc, e->xconfigure.window); + if (lw) loco_window_configure(lw, &e->xconfigure); + break; + default: + if (e->type == obt_display_extension_damage_basep + XDamageNotify) { + const XDamageNotifyEvent *de = (const XDamageNotifyEvent*)e; + + lw = loco_screen_find_window(sc, de->drawable); + if (de->drawable == sc->root) + loco_screen_redraw(sc); + else if (lw) + loco_screen_redraw(sc); + + /* mark the damage as fixed - we know about it now */ + obt_display_ignore_errors(TRUE); XDamageSubtract(obt_display, de->damage, None, None); - full_redraw_required = redraw_required = TRUE; + obt_display_ignore_errors(FALSE); } } } -static void find_all_windows(gint screen) +static gboolean compositor_timeout(gpointer data) { - guint i, nchild; - Window w, *children; + LocoScreen *sc = data; - if (!XQueryTree(obt_display, loco_root, &w, &w, &children, &nchild)) - nchild = 0; + if (sc->redraw) + paint_everything(sc); - for (i = 0; i < nchild; ++i) - if (children[i] != None) add_window(children[i]); - - if (children) XFree(children); + return TRUE; /* repeat */ } -static gboolean compositor_timeout(gpointer data) +void loco_startup(ObtMainLoop *loop) { - if (redraw_required) - full_composite(); - return TRUE; /* repeat */ + mainloop = loop; + screens = g_new0(LocoScreen*, ScreenCount(obt_display)); } -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) +void loco_shutdown() { - int db, stencil, depth; - int i, j, value, count; - int w, h; - XVisualInfo *vi, tvis, *visinfo; - GLXFBConfig *allfbconfigs; - int numfbconfigs; - GLXContext cont; - static int config[] = - { GLX_DEPTH_SIZE, 1, GLX_DOUBLEBUFFER, GLX_RGBA, None }; - static const int drawable_tfp_attrs[] = - { - GLX_CONFIG_CAVEAT, GLX_NONE, - GLX_DOUBLEBUFFER, False, - GLX_DEPTH_SIZE, 0, - GLX_RED_SIZE, 1, - GLX_GREEN_SIZE, 1, - GLX_BLUE_SIZE, 1, - GLX_ALPHA_SIZE, 1, - GLX_RENDER_TYPE, GLX_RGBA_BIT, - GLX_BIND_TO_TEXTURE_RGBA_EXT, True, // additional for tfp - None - }; - - loco_screen_num = screen_num; - loco_root = obt_root(screen_num); - loco_overlay = XCompositeGetOverlayWindow(obt_display, loco_root); - XserverRegion region = XFixesCreateRegion(obt_display, NULL, 0); - - XFixesSetWindowShapeRegion (obt_display, - loco_overlay, - ShapeBounding, - 0, 0, - 0); - XFixesSetWindowShapeRegion (obt_display, - loco_overlay, - ShapeInput, - 0, 0, - region); - - XFixesDestroyRegion (obt_display, region); - - 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, loco_overlay, cont); + int i; + for (i = 0; i < ScreenCount(obt_display); ++i) + loco_screen_unref(screens[i]); - BindTexImageEXT = (BindEXTFunc) - glXGetProcAddress((const guchar*)"glXBindTexImageEXT"); - ReleaseTexImageEXT = (ReleaseEXTFunc) - glXGetProcAddress((const guchar*)"glXReleaseTexImageEXT"); - - w = WidthOfScreen(ScreenOfDisplay(obt_display, screen_num)); - h = HeightOfScreen(ScreenOfDisplay(obt_display, screen_num)); - glViewport(0, 0, w, h); - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); -printf("Setting up an orthographic projection of %dx%d\n", w, h); - glOrtho(0, w, h, 0.0, -1.0, 100.0); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - glClear(GL_COLOR_BUFFER_BIT); - glEnable(GL_TEXTURE_2D); -glError(); - glXSwapBuffers(obt_display, loco_overlay); - glClearColor(1.0, 0.0, 0.0, 1.0); -// glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA); -// glEnable(GL_BLEND); - - allfbconfigs = glXChooseFBConfig(obt_display, - loco_screen_num, - drawable_tfp_attrs, - &numfbconfigs); - - db = 32767; - stencil = 32767; - depth = 32767; - for (i = 0; i <= MAX_DEPTH; i++) { - VisualID vid; - - vid = 0; - glxFBConfig[i] = 0; - - tvis.depth = i; - visinfo = XGetVisualInfo(obt_display, VisualDepthMask, &tvis, &count); - /* pick the nicest visual for the depth */ - for (j = 0; j < count; j++) { - glXGetConfig(obt_display, &visinfo[j], GLX_USE_GL, &value); - if (!value) - continue; - - glXGetConfig(obt_display, &visinfo[j], GLX_DOUBLEBUFFER, &value); - if (value > db) - continue; - db = value; - - glXGetConfig(obt_display, &visinfo[j], GLX_STENCIL_SIZE, &value); - if (value > stencil) - continue; - stencil = value; - - glXGetConfig(obt_display, &visinfo[j], GLX_DEPTH_SIZE, &value); - if (value > depth) - continue; - depth = value; - - /* use this visual */ - vid = visinfo[j].visualid; - } - - if (!vid) - continue; - - printf("found visual %d\n", i); + g_free(screens); + screens = NULL; +} - /* find the fbconfig for this depth/visual */ - for(j = 0; j < numfbconfigs; ++j) { - glXGetFBConfigAttrib(obt_display, allfbconfigs[j], - GLX_VISUAL_ID, &value); - if (value == (int)vid) { - glxFBConfig[i] = allfbconfigs[j]; /* save it */ - printf("supporting depth %d\n", i); - break; /* next depth */ - } +void loco_start_screen(gint number) +{ + if (!screens[number]) + screens[number] = loco_screen_new(number); + if (screens[number]) { + if (!paint_setup(screens[number])) + loco_stop_screen(number); + else { + obt_main_loop_x_add(mainloop, COMPOSTER_RAWR, + screens[number], NULL); + obt_main_loop_timeout_add(mainloop, REFRESH_RATE, + (GSourceFunc)compositor_timeout, + screens[number], g_direct_equal, NULL); } } +} - XFree(allfbconfigs); - - 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; - - XGrabServer(obt_display); - - XCompositeRedirectSubwindows(obt_display, loco_root, - CompositeRedirectManual); - find_all_windows(screen_num); - - XUngrabServer(obt_display); +void loco_stop_screen(gint number) +{ + obt_main_loop_x_remove_data(mainloop, COMPOSTER_RAWR, screens[number]); + obt_main_loop_timeout_remove_data(mainloop, + compositor_timeout, screens[number], + FALSE); - full_redraw_required = redraw_required = TRUE; + loco_screen_unref(screens[number]); + screens[number] = NULL; +} - obt_main_loop_timeout_add(loop, REFRESH_RATE, - (GSourceFunc)compositor_timeout, - NULL, NULL, NULL); +void loco_reconfigure_screen(gint number) +{ + /* reload stuff.. */ } -void loco_shutdown(void) +gboolean loco_on_screen(gint number) { + return screens[number] != NULL; } diff --git a/loco/loco.h b/loco/loco.h index 8d645293..80d3f158 100644 --- a/loco/loco.h +++ b/loco/loco.h @@ -20,10 +20,19 @@ #ifndef loco__loco_h #define loco__loco_h +#include + struct _ObtMainLoop; -void loco_set_mainloop(gint ob_screen, struct _ObtMainLoop *loop); -void loco_shutdown(void); +void loco_startup(struct _ObtMainLoop *loop); +void loco_shutdown(); + +void loco_start_screen(gint number); +void loco_stop_screen(gint number); + +void loco_reconfigure_screen(gint number); + +gboolean loco_on_screen(gint number); #endif diff --git a/loco/paint.c b/loco/paint.c new file mode 100644 index 00000000..dc87f08f --- /dev/null +++ b/loco/paint.c @@ -0,0 +1,102 @@ +#include "paint.h" +#include "screen.h" +#include "list.h" +#include "window.h" +#include "glerror.h" + +#include "obt/display.h" + +#include +#include +#include +#include + +static int context_visual_config[] = { + GLX_DEPTH_SIZE, 1, + GLX_DOUBLEBUFFER, + GLX_RGBA, + None +}; + +gboolean paint_setup(LocoScreen *sc) +{ + XVisualInfo *vi; + GLXContext context; + gint w, h; + + w = WidthOfScreen(ScreenOfDisplay(obt_display, sc->number)); + h = HeightOfScreen(ScreenOfDisplay(obt_display, sc->number)); + + vi = glXChooseVisual(obt_display, sc->number, context_visual_config); + context = glXCreateContext(obt_display, vi, NULL, GL_TRUE); + if (context == NULL) { + g_print("context creation failed\n"); + return FALSE; + } + glXMakeCurrent(obt_display, sc->overlay, context); + + glViewport(0, 0, w, h); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + g_print("Setting up an orthographic projection of %dx%d\n", w, h); + glOrtho(0, w, h, 0.0, -1.0, 100.0); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glClear(GL_COLOR_BUFFER_BIT); + glEnable(GL_TEXTURE_2D); +glError(); + glXSwapBuffers(obt_display, sc->overlay); + glClearColor(0.4, 0.4, 0.4, 1.0); +/* + glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA); + glEnable(GL_BLEND); +*/ + return TRUE; +} + +void paint_everything(LocoScreen *sc) +{ + int ret; + LocoList *it; + + /* XXX if (full_redraw_required) */ + glClear(GL_COLOR_BUFFER_BIT); + + for (it = sc->stacking_bottom; it != NULL; it = it->prev) { + if (it->window->id == sc->overlay) continue; + if (it->window->input_only) continue; + if (!it->window->visible) continue; + /* XXX if (!full_redraw_required && !it->window->damaged) continue; */ + + /* XXX if (!full_redraw_required) { + /\* XXX if the window is transparent, then clear the background + behind it *\/ + }*/ + + /* get the window's updated contents + XXX if animating the window, then don't do this, depending + */ + loco_window_update_pixmap(it->window); + + glBindTexture(GL_TEXTURE_2D, it->window->texname); + if (ret) { + glBegin(GL_QUADS); + glColor3f(1.0, 1.0, 1.0); + glVertex2i(it->window->x, it->window->y); + glTexCoord2f(1, 0); + glVertex2i(it->window->x + it->window->w, it->window->y); + glTexCoord2f(1, 1); + glVertex2i(it->window->x + it->window->w, + it->window->y + it->window->h); + glTexCoord2f(0, 1); + glVertex2i(it->window->x, it->window->y + it->window->h); + glTexCoord2f(0, 0); + glEnd(); + } + + it->window->damaged = FALSE; + } + glXSwapBuffers(obt_display, sc->overlay); + + loco_screen_redraw_done(sc); +} diff --git a/loco/paint.h b/loco/paint.h new file mode 100644 index 00000000..30ade3eb --- /dev/null +++ b/loco/paint.h @@ -0,0 +1,30 @@ +/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*- + + paint.h for the Openbox compositor + Copyright (c) 2008 Dana Jansens + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + See the COPYING file for a copy of the GNU General Public License. +*/ + +#ifndef loco__paint_h +#define loco__paint_h + +#include + +struct _LocoScreen; + +gboolean paint_setup(struct _LocoScreen *sc); + +void paint_everything(struct _LocoScreen *sc); + +#endif diff --git a/loco/screen.c b/loco/screen.c new file mode 100644 index 00000000..b44f3165 --- /dev/null +++ b/loco/screen.c @@ -0,0 +1,228 @@ +#include "screen.h" +#include "window.h" +#include "list.h" +#include "obt/display.h" + +static void find_all_windows(LocoScreen *sc); +static void find_visuals(LocoScreen *sc); + +static guint window_hash(Window *w) { return *w; } +static gboolean window_comp(Window *w1, Window *w2) { return *w1 == *w2; } + +static const int drawable_tfp_attrs[] = { + GLX_CONFIG_CAVEAT, GLX_NONE, + GLX_DOUBLEBUFFER, FALSE, + GLX_DEPTH_SIZE, 0, + GLX_RED_SIZE, 1, + GLX_GREEN_SIZE, 1, + GLX_BLUE_SIZE, 1, + GLX_ALPHA_SIZE, 1, + GLX_RENDER_TYPE, GLX_RGBA_BIT, + GLX_BIND_TO_TEXTURE_RGBA_EXT, TRUE, /* For TextureFromPixmap */ + None +}; + +LocoScreen* loco_screen_new(gint number) +{ + LocoScreen *sc; + + /* try get the root redirect */ + obt_display_ignore_errors(TRUE); + XCompositeRedirectSubwindows(obt_display, obt_root(number), + CompositeRedirectManual); + obt_display_ignore_errors(FALSE); + if (obt_display_error_occured) { + g_message("Another composite manager is running on screen %d", number); + return NULL; + } + + sc = g_new0(LocoScreen, 1); + sc->ref = 1; + sc->number = number; + sc->root = obt_root(number); + //sc->root = loco_window_new(obt_root(number)); + sc->stacking_map = g_hash_table_new((GHashFunc)window_hash, + (GEqualFunc)window_comp); + sc->bindTexImageEXT = (BindEXTFunc) + glXGetProcAddress((const guchar*)"glXBindTexImageEXT"); + sc->releaseTexImageEXT = (ReleaseEXTFunc) + glXGetProcAddress((const guchar*)"glXReleaseTexImageEXT"); + + find_visuals(sc); + + sc->overlay = XCompositeGetOverlayWindow(obt_display, sc->root); + + if (sc->overlay) { + XserverRegion region; + + region = XFixesCreateRegion(obt_display, NULL, 0); + XFixesSetWindowShapeRegion(obt_display, sc->overlay, + ShapeBounding, 0, 0, 0); + XFixesSetWindowShapeRegion(obt_display, sc->overlay, + ShapeInput, 0, 0, region); + XFixesDestroyRegion(obt_display, region); + } + + find_all_windows(sc); + loco_screen_redraw(sc); + + return sc; +} + +void loco_screen_ref(LocoScreen *sc) +{ + ++sc->ref; +} + +void loco_screen_unref(LocoScreen *sc) +{ + if (sc && --sc->ref == 0) { + /*XXX loco_window_unref(sc->root);*/ + + if (sc->overlay) + XCompositeReleaseOverlayWindow(obt_display, sc->overlay); + + g_hash_table_destroy(sc->stacking_map); + + g_free(sc); + } +} + +static void find_all_windows(LocoScreen *sc) +{ + guint i, nchild; + Window w, *children; + + if (!XQueryTree(obt_display, sc->root, &w, &w, &children, &nchild)) + nchild = 0; + + for (i = 0; i < nchild; ++i) + if (children[i] != None) + loco_screen_add_window(sc, children[i]); + + if (children) XFree(children); +} + +static void find_visuals(LocoScreen *sc) +{ + gint db, stencil, depth; + gint i, j, value, count; + XVisualInfo tvis, *visinfo; + GLXFBConfig *fbcons; + gint numfb; + + fbcons = glXChooseFBConfig(obt_display, sc->number, + drawable_tfp_attrs, &numfb); + + db = 32767; + stencil = 32767; + depth = 32767; + for (i = 0; i <= LOCO_SCREEN_MAX_DEPTH; i++) { + VisualID vid; + + vid = 0; + sc->glxFBConfig[i] = 0; + + tvis.depth = i; + visinfo = XGetVisualInfo(obt_display, VisualDepthMask, &tvis, &count); + /* pick the nicest visual for the depth */ + for (j = 0; j < count; j++) { + glXGetConfig(obt_display, &visinfo[j], GLX_USE_GL, &value); + if (!value) + continue; + + glXGetConfig(obt_display, &visinfo[j], GLX_DOUBLEBUFFER, &value); + if (value > db) + continue; + db = value; + + glXGetConfig(obt_display, &visinfo[j], GLX_STENCIL_SIZE, &value); + if (value > stencil) + continue; + stencil = value; + + glXGetConfig(obt_display, &visinfo[j], GLX_DEPTH_SIZE, &value); + if (value > depth) + continue; + depth = value; + + /* use this visual */ + vid = visinfo[j].visualid; + } + + if (!vid) + continue; + + g_print("found visual %d\n", i); + + /* find the fbconfig for this depth/visual */ + for(j = 0; j < numfb; ++j) { + glXGetFBConfigAttrib(obt_display, fbcons[j], + GLX_VISUAL_ID, &value); + if (value == (int)vid) { + sc->glxFBConfig[i] = fbcons[j]; /* save it */ + g_print("supporting depth %d\n", i); + break; /* next depth */ + } + } + } + + XFree(fbcons); +} + +void loco_screen_add_window(LocoScreen *sc, Window xwin) +{ + LocoWindow *lw; + LocoList *it; + + if (loco_screen_find_window(sc, xwin)) return; + + g_print("add window 0x%lx\n", xwin); + + lw = loco_window_new(xwin, sc); + if (lw) { + /* new windows are at the top */ + it = loco_list_prepend(&sc->stacking_top, &sc->stacking_bottom, lw); + g_hash_table_insert(sc->stacking_map, &lw->id, it); + } + + //print_stacking(); +} + +void loco_screen_remove_window(LocoScreen *sc, LocoWindow *lw) +{ + LocoList *pos = loco_screen_find_stacking(sc, lw->id); + g_assert(pos); + + g_print("remove window 0x%lx\n", lw->id); + + loco_list_delete_link(&sc->stacking_top, &sc->stacking_bottom, pos); + g_hash_table_remove(sc->stacking_map, &lw->id); + + loco_window_unref(lw); + + //print_stacking(); +} + +struct _LocoWindow* loco_screen_find_window(LocoScreen *sc, Window xwin) +{ + LocoList *it; + + it = g_hash_table_lookup(sc->stacking_map, &xwin); + return (it ? it->window : NULL); +} + +struct _LocoList* loco_screen_find_stacking(LocoScreen *sc, Window xwin) +{ + return g_hash_table_lookup(sc->stacking_map, &xwin); +} + +void loco_screen_redraw(LocoScreen *sc) +{ + sc->redraw = TRUE; +} + +void loco_screen_redraw_done(LocoScreen *sc) +{ + sc->redraw = TRUE; +} diff --git a/loco/screen.h b/loco/screen.h new file mode 100644 index 00000000..ff46aa54 --- /dev/null +++ b/loco/screen.h @@ -0,0 +1,72 @@ +/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*- + + screen.h for the Openbox compositor + Copyright (c) 2008 Dana Jansens + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + See the COPYING file for a copy of the GNU General Public License. +*/ + +#ifndef loco__screen_h +#define loco__screen_h + +#include +#include +#include + +#define LOCO_SCREEN_MAX_DEPTH 32 + +struct _LocoWindow; +struct _LocoList; + +typedef void (*BindEXTFunc)(Display *, GLXDrawable, int, const int *); +typedef void (*ReleaseEXTFunc)(Display *, GLXDrawable, int); + +typedef struct _LocoScreen { + gint ref; + + gint number; + + //struct _Window *root; + Window root; + Window overlay; + + GLXFBConfig glxFBConfig[LOCO_SCREEN_MAX_DEPTH + 1]; + + gboolean redraw; + + /* Maps X Window ID -> LocoList* which is in the stacking_top/bottom list + */ + GHashTable *stacking_map; + /* The stacking list goes from top-most to bottom-most window */ + struct _LocoList *stacking_top; + struct _LocoList *stacking_bottom; + + BindEXTFunc bindTexImageEXT; + ReleaseEXTFunc releaseTexImageEXT; +} LocoScreen; + +LocoScreen* loco_screen_new(gint number); +void loco_screen_ref(LocoScreen *sc); +void loco_screen_unref(LocoScreen *sc); + +void loco_screen_add_window(LocoScreen *sc, Window xwin); +void loco_screen_remove_window(LocoScreen *sc, struct _LocoWindow *lw); + +struct _LocoWindow* loco_screen_find_window(LocoScreen *sc, Window xwin); +struct _LocoList* loco_screen_find_stacking(LocoScreen *sc, Window xwin); + +void loco_screen_redraw(LocoScreen *sc); + +void loco_screen_redraw_done(LocoScreen *sc); + +#endif diff --git a/loco/window.c b/loco/window.c new file mode 100644 index 00000000..92e013f0 --- /dev/null +++ b/loco/window.c @@ -0,0 +1,271 @@ +/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*- + + window.c for the Openbox window manager + Copyright (c) 2008 Derek Foreman + Copyright (c) 2008 Dana Jansens + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + See the COPYING file for a copy of the GNU General Public License. +*/ + +#include "window.h" +#include "screen.h" +#include "list.h" +#include "obt/prop.h" + +static void pixmap_create(LocoWindow *lw); +static void texture_create(LocoWindow *lw); +static void texture_destroy(LocoWindow *lw); +static void pixmap_destroy(LocoWindow *lw); +static Bool look_for_destroy(Display *d, XEvent *e, XPointer arg); + +LocoWindow* loco_window_new(Window xwin, LocoScreen *screen) +{ + LocoWindow *lw; + XWindowAttributes attrib; + + if (!XGetWindowAttributes(obt_display, xwin, &attrib)) + return NULL; + + lw = g_new0(LocoWindow, 1); + lw->ref = 1; + lw->id = xwin; + lw->screen = screen; + lw->input_only = attrib.class == InputOnly; + lw->x = attrib.x; + lw->y = attrib.y; + lw->w = attrib.width; + lw->h = attrib.height; + lw->depth = attrib.depth; + + if (!lw->input_only) { + glGenTextures(1, &lw->texname); + /*glTexImage2D(TARGET, 0, GL_RGB, lw->w, lw->h, + 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL);*/ + lw->damage = XDamageCreate(obt_display, lw->id, XDamageReportNonEmpty); + } + + if (attrib.map_state != IsUnmapped) + loco_window_show(lw); + + return lw; +} + +void loco_window_ref(LocoWindow *lw) +{ + ++lw->ref; +} + +void loco_window_unref(LocoWindow *lw) +{ + if (lw && --lw->ref == 0) { + if (!lw->input_only) { + glDeleteTextures(1, &lw->texname); + + obt_display_ignore_errors(TRUE); + XDamageDestroy(obt_display, lw->damage); + obt_display_ignore_errors(FALSE); + } + + g_free(lw); + } +} + +void loco_window_show(LocoWindow *lw) { + guint32 *type; + guint i, ntype; + + lw->visible = TRUE; + + /* get the window's semantic type (for different effects!) */ + lw->type = 0; /* XXX set this to the default type */ + if (OBT_PROP_GETA32(lw->id, NET_WM_WINDOW_TYPE, ATOM, &type, &ntype)) { + /* use the first value that we know about in the array */ + for (i = 0; i < ntype; ++i) { + /* XXX SET THESE TO AN ENUM'S VALUES */ + if (type[i] == OBT_PROP_ATOM(NET_WM_WINDOW_TYPE_DESKTOP)) + lw->type = 1; + if (type[i] == OBT_PROP_ATOM(NET_WM_WINDOW_TYPE_MENU)) + lw->type = 2; + /* XXX there are more TYPES that need to be added to prop.h */ + } + g_free(type); + } + + loco_screen_redraw(lw->screen); +} + +void loco_window_hide(LocoWindow *lw, gboolean destroyed) +{ + /* if destroyed = TRUE, then the window is no longer available */ + + lw->visible = FALSE; + + /* leave the glx texture alone though.. */ + lw->stale = TRUE; + pixmap_destroy(lw); + + loco_screen_redraw(lw->screen); +} + +void loco_window_configure(LocoWindow *lw, const XConfigureEvent *e) +{ + LocoList *above, *pos; + + pos = loco_screen_find_stacking(lw->screen, e->window); + above = loco_screen_find_stacking(lw->screen, e->above); + + g_assert(pos != NULL && pos->window != NULL); + + if (e->above && !above) + g_error("missing windows from the stacking list!!\n"); + + if ((lw->x != e->x) || (lw->y != e->y)) { + lw->x = e->x; + lw->y = e->y; + + loco_screen_redraw(lw->screen); + } + + if ((lw->w != e->width) || (lw->h != e->height)) { + lw->w = e->width; + lw->h = e->height; + + /* leave the glx texture alone though.. */ + lw->stale = TRUE; + pixmap_destroy(lw); + + loco_screen_redraw(lw->screen); + } + + if (pos->next != above) { + //printf("Window 0x%lx above 0x%lx\n", pos->window->id, + // above ? above->window->id : 0); + loco_list_move_before(&lw->screen->stacking_top, + &lw->screen->stacking_bottom, + pos, above); + + loco_screen_redraw(lw->screen); + } +} + +static Bool look_for_destroy(Display *d, XEvent *e, XPointer arg) +{ + const Window w = (Window)*arg; + return e->type == DestroyNotify && e->xdestroywindow.window == w; +} + +static void pixmap_create(LocoWindow *lw) +{ + XEvent ce; + + if (lw->pixmap) return; + + /* make sure the window exists */ + XGrabServer(obt_display); + XSync(obt_display, FALSE); + + if (!XCheckIfEvent(obt_display, &ce, look_for_destroy, (XPointer)&lw->id)) + lw->pixmap = XCompositeNameWindowPixmap(obt_display, lw->id); + XUngrabServer(obt_display); +} + +static void texture_create(LocoWindow *lw) +{ + static const int attrs[] = { + GLX_TEXTURE_FORMAT_EXT, + GLX_TEXTURE_FORMAT_RGBA_EXT, + None + }; + + if (lw->glpixmap) return; + + g_assert(lw->pixmap); + + if (!lw->screen->glxFBConfig[lw->depth]) { + g_print("no glxFBConfig for depth %d for window 0x%lx\n", + lw->depth, lw->id); + return; + } + + lw->glpixmap = glXCreatePixmap(obt_display, + lw->screen->glxFBConfig[lw->depth], + lw->pixmap, attrs); + if (!lw->glpixmap) return; + +#if 0 + if (screen->queryDrawable (screen->display->display, + texture->pixmap, + GLX_TEXTURE_TARGET_EXT, + &target)) + { + fprintf (stderr, "%s: glXQueryDrawable failed\n", programName); + + glXDestroyGLXPixmap (screen->display->display, texture->pixmap); + texture->pixmap = None; + + return FALSE; + } +#endif + + glBindTexture(GL_TEXTURE_2D, lw->texname); + + lw->screen->bindTexImageEXT(obt_display, lw->glpixmap, + GLX_FRONT_LEFT_EXT, NULL); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + + glBindTexture(GL_TEXTURE_2D, 0); +} + +static void texture_destroy(LocoWindow *lw) +{ + if (!lw->glpixmap) return; + + glBindTexture(GL_TEXTURE_2D, lw->texname); + + lw->screen->releaseTexImageEXT(obt_display, lw->glpixmap, + GLX_FRONT_LEFT_EXT); + + glBindTexture(GL_TEXTURE_2D, 0); + + obt_display_ignore_errors(TRUE); + glXDestroyGLXPixmap(obt_display, lw->glpixmap); + obt_display_ignore_errors(FALSE); + + lw->glpixmap = None; +} + +static void pixmap_destroy(LocoWindow *lw) +{ + if (!lw->pixmap) return; + + XFreePixmap(obt_display, lw->pixmap); + lw->pixmap = None; +} + +void loco_window_update_pixmap(LocoWindow *lw) +{ + if (lw->stale || lw->glpixmap == None) { + g_assert(lw->pixmap == None); + + texture_destroy(lw); + pixmap_create(lw); + texture_create(lw); + lw->stale = FALSE; + } +} diff --git a/loco/window.h b/loco/window.h new file mode 100644 index 00000000..f3c1fc5a --- /dev/null +++ b/loco/window.h @@ -0,0 +1,67 @@ +/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*- + + window.h for the Openbox compositor + Copyright (c) 2008 Dana Jansens + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + See the COPYING file for a copy of the GNU General Public License. +*/ + +#ifndef loco__window_h +#define loco__window_h + +#include "obt/display.h" +#include +#include + +struct _LocoScreen; + +typedef enum { + a /* XXX fill this in */ +} LocoWindowType; + +typedef struct _LocoWindow { + gint ref; + + Window id; + gint type; /* XXX make this an enum */ + + struct _LocoScreen *screen; + + gint x, y, w, h; + + gint depth; + + gboolean input_only; + gboolean visible; + gboolean damaged; + gboolean stale; /* glpixmap is out of date */ + + GLuint texname; + Damage damage; + Pixmap pixmap; + GLXPixmap glpixmap; +} LocoWindow; + +LocoWindow* loco_window_new(Window xwin, struct _LocoScreen *screen); +void loco_window_ref(LocoWindow *lw); +void loco_window_unref(LocoWindow *lw); + +void loco_window_show(LocoWindow *lw); +void loco_window_hide(LocoWindow *lw, gboolean destroyed); + +void loco_window_configure(LocoWindow *lw, const XConfigureEvent *e); +void loco_window_damage(LocoWindow *lw); + +void loco_window_update_pixmap(LocoWindow *lw); + +#endif diff --git a/obt/display.c b/obt/display.c index 22f97db8..bc5a6253 100644 --- a/obt/display.c +++ b/obt/display.c @@ -120,11 +120,13 @@ gboolean obt_display_open(const char *display_name) if (XCompositeQueryExtension(d, &obt_display_extension_composite_basep, &junk)) { - gint major = 0, minor = 2; + gint major = 0, minor = 3; XCompositeQueryVersion(d, &major, &minor); /* Version 0.2 is the first version to have the XCompositeNameWindowPixmap() request. */ - if (major > 0 || minor >= 2) + /* Version 0.3 is the first version to have the + composite overlay window */ + if (major > 0 || minor >= 3) obt_display_extension_composite = TRUE; } if (!obt_display_extension_composite) diff --git a/obt/mainloop.c b/obt/mainloop.c index 64972dd7..3139794d 100644 --- a/obt/mainloop.c +++ b/obt/mainloop.c @@ -352,15 +352,16 @@ void obt_main_loop_x_add(ObtMainLoop *loop, loop->x_handlers = g_slist_prepend(loop->x_handlers, h); } -void obt_main_loop_x_remove(ObtMainLoop *loop, - ObtMainLoopXHandler handler) +static void obt_main_loop_x_remove_intern(ObtMainLoop *loop, + ObtMainLoopXHandler handler, + gboolean bydata, gpointer data) { GSList *it, *next; for (it = loop->x_handlers; it; it = next) { ObtMainLoopXHandlerType *h = it->data; next = g_slist_next(it); - if (h->func == handler) { + if (h->func == handler && (!bydata || data == h->data)) { loop->x_handlers = g_slist_delete_link(loop->x_handlers, it); if (h->destroy) h->destroy(h->data); g_free(h); @@ -373,6 +374,19 @@ void obt_main_loop_x_remove(ObtMainLoop *loop, } } +void obt_main_loop_x_remove_data(ObtMainLoop *loop, + ObtMainLoopXHandler handler, + gpointer data) +{ + obt_main_loop_x_remove_intern(loop, handler, TRUE, data); +} + +void obt_main_loop_x_remove(ObtMainLoop *loop, + ObtMainLoopXHandler handler) +{ + obt_main_loop_x_remove_intern(loop, handler, FALSE, NULL); +} + /*** SIGNAL WATCHERS ***/ static void sighandler(gint sig) diff --git a/obt/mainloop.h b/obt/mainloop.h index cce7d5b5..29763889 100644 --- a/obt/mainloop.h +++ b/obt/mainloop.h @@ -39,6 +39,9 @@ void obt_main_loop_x_add(ObtMainLoop *loop, GDestroyNotify notify); void obt_main_loop_x_remove(ObtMainLoop *loop, ObtMainLoopXHandler handler); +void obt_main_loop_x_remove_data(ObtMainLoop *loop, + ObtMainLoopXHandler handler, + gpointer data); typedef void (*ObtMainLoopFdHandler) (gint fd, gpointer data); diff --git a/openbox/openbox.c b/openbox/openbox.c index 041ef853..b8cfbbe7 100644 --- a/openbox/openbox.c +++ b/openbox/openbox.c @@ -200,8 +200,7 @@ gint main(gint argc, gchar **argv) XC_top_left_corner); if (screen_annex()) { /* it will be ours! */ - loco_set_mainloop(ob_screen, ob_main_loop); - + loco_startup(ob_main_loop); do { if (reconfigure) obt_keyboard_reload(); @@ -283,6 +282,7 @@ gint main(gint argc, gchar **argv) frame_adjust_theme(c->frame); } } + event_startup(reconfigure); /* focus_backup is used for stacking, so this needs to come before anything that calls stacking_add */ @@ -304,6 +304,15 @@ gint main(gint argc, gchar **argv) menu_frame_startup(reconfigure); menu_startup(reconfigure); + /* XXX check config */ + if (!loco_on_screen(ob_screen) && TRUE) + loco_start_screen(ob_screen); + else if (loco_on_screen(ob_screen) && FALSE) + loco_stop_screen(ob_screen); + + if (loco_on_screen(ob_screen) && reconfigure) + loco_reconfigure_screen(ob_screen); + if (!reconfigure) { guint32 xid; ObWindow *w; @@ -367,6 +376,7 @@ gint main(gint argc, gchar **argv) actions_shutdown(reconfigure); } while (reconfigure); + loco_stop_screen(ob_screen); loco_shutdown(); } -- 2.34.1