#include "screen.h"
#include "window.h"
+#include "list.h"
#include "display.h"
#include "gettext.h"
#include "time.h"
if (!ev->response_type) {
display_error(dpy, (xcb_generic_error_t*)ev);
free(ev);
- return;
+ continue;
}
switch (ev->response_type) {
w = screen_find_window(sc, dev->window);
sc->window_hide(w);
screen_remove_window(sc, w);
+ printf("** refresh needed **\n");
+ screen_refresh(sc);
break;
}
case XCB_REPARENT_NOTIFY:
static void
paint(d_display_t *dpy)
{
- int i;
+ d_list_it_t *it;
struct timeval now;
gettimeofday(&now, NULL);
- for (i = 0; i < dpy->nscreens; ++i) {
- d_screen_t *sc = display_screen_n(dpy, i);
+ for (it = list_top(dpy->screens); it; it = it->next) {
+ d_screen_t *sc = it->data;
if (time_compare(&sc->next_repaint, &now) <= 0)
sc->screen_paint(sc);
quit = FALSE;
while (!quit) {
- int r;
+ struct timeval next, now, *wait;
+ int r, npaint;
+ d_list_it_t *it;
+
+ npaint = 0;
+ for (it = list_top(dpy->screens); it; it = it->next) {
+ d_screen_t *sc = it->data;
+ if (sc->need_repaint &&
+ (!npaint || time_compare(&sc->next_repaint, &next) < 0))
+ {
+ next = sc->next_repaint;
+ ++npaint;
+ }
+ }
+
+ gettimeofday(&now, 0);
- r = select(max+1, &fds, NULL, NULL, NULL);
+ printf("* loop paint %d *\n", npaint);
+
+ if (!npaint)
+ /* wait forever, there is nothing that needs drawing */
+ wait = NULL;
+ else if (time_compare(&next, &now) > 0) {
+ /* wait until the next allowed redraw time */
+ time_difference(&next, &now, &next);
+ wait = &next;
+ }
+ else {
+ /* don't wait cuz a redraw is due now already */
+ next.tv_sec = 0;
+ next.tv_usec = 1;
+ wait = &next;
+ }
+
+ r = select(max+1, &fds, NULL, NULL, wait);
if (r < 0)
printf("select error\n");
- else if (r == 0)
+ else if (r == 0) {
printf("select timeout\n");
+ paint(dpy);
+ }
else {
printf("select data\n");
/*if (FD_ISSET(dpy->fd, &fds))*/ {
event(dpy);
- paint(dpy);
}
}
static void
setup_functions(d_display_t *dpy)
{
- int i;
+ d_list_it_t *it;
- for (i = 0; i < dpy->nscreens; ++i) {
- d_screen_t *sc = display_screen_n(dpy, i);
+ for (it = list_top(dpy->screens); it; it = it->next) {
+ d_screen_t *sc = it->data;
screen_setup_default_functions(sc);
/* these can be plugins.. */
static void
cleanup_functions(d_display_t *dpy)
{
- int i;
+ d_list_it_t *it;
- for (i = 0; i < dpy->nscreens; ++i) {
- d_screen_t *sc = display_screen_n(dpy, i);
+ for (it = list_top(dpy->screens); it; it = it->next) {
+ d_screen_t *sc = it->data;
/* these can be plugins.. */
render_free(sc);
#include "display.h"
#include "screen.h"
+#include "list.h"
#include "gettext.h"
#include <stdlib.h>
#include <assert.h>
dpy->conn = conn;
dpy->ref = 1;
dpy->fd = xcb_get_file_descriptor(conn);
- dpy->screens = NULL;
- dpy->nscreens = 0;
+ dpy->screens = list_new();
query_statics(dpy);
}
display_unref(d_display_t *dpy)
{
if (dpy && --dpy->ref == 0) {
- int i;
+ d_list_it_t *it;
+
xcb_disconnect(dpy->conn);
- for (i = 0; i < dpy->nscreens; ++i)
- screen_free(&dpy->screens[i]);
- free(dpy->screens);
+ for (it = list_top(dpy->screens); it; it = it->next)
+ screen_unref(it->data);
+ list_unref(dpy->screens);
free(dpy);
}
}
static const xcb_setup_t *setup;
xcb_screen_iterator_t it;
int i;
- d_screen_t sc;
+ d_screen_t *sc;
setup = xcb_get_setup(dpy->conn);
i = 0;
for (it = xcb_setup_roots_iterator(setup); it.rem; xcb_screen_next(&it)) {
- sc.super = *it.data;
- sc.dpy = dpy;
- sc.num = i++;
- if (screen_register(dpy, i, &sc)) {
- ++dpy->nscreens;
- dpy->screens = realloc(dpy->screens,
- sizeof(d_screen_t)*dpy->nscreens);
- dpy->screens[dpy->nscreens-1] = sc;
- printf(_("managing screen %d\n"), sc.num);
+ sc = screen_new(dpy, i++, it.data);
+ if (screen_register(sc)) {
+ list_append(dpy->screens, sc);
+ printf(_("managing screen %d\n"), sc->num);
}
+ else
+ screen_unref(sc);
}
- return dpy->nscreens;
+ return list_length(dpy->screens);
}
d_screen_t*
display_screen_from_root(d_display_t *dpy, xcb_window_t root)
{
- int i;
- for (i = 0; i < dpy->nscreens; ++i)
- if (dpy->screens[i].super.root == root)
- return &dpy->screens[i];
+ d_list_it_t *it;
+
+ for (it = list_top(dpy->screens); it; it = it->next) {
+ d_screen_t *sc = it->data;
+ if (sc->super.root == root)
+ return sc;
+ }
assert(0);
return NULL;
}
-
-struct d_screen*
-display_screen_n(d_display_t *dpy, int n)
-{
- assert(n >= 0 && n < dpy->nscreens);
- return &dpy->screens[n];
-}
#include <glib.h>
+struct d_list;
+
typedef struct d_display_ext {
gboolean present;
int error;
xcb_connection_t *conn;
int ref;
int fd;
- struct d_screen *screens;
- int nscreens;
+ struct d_list *screens;
d_display_ext_t xfixes;
d_display_ext_t render;
int display_claim_screens(d_display_t *dpy);
struct d_screen* display_screen_from_root(d_display_t *dpy, xcb_window_t root);
-struct d_screen* display_screen_n(d_display_t *dpy, int n);
void display_error(d_display_t *dpy, xcb_generic_error_t *ev);
return n;
}
+d_list_it_t*
+list_append(d_list_t *list, void *data)
+{
+ d_list_it_t *n = malloc(sizeof(d_list_it_t));
+ n->data = data;
+
+ n->prev = list->bottom;
+ n->next = NULL;
+ if (n->prev) n->prev->next = n;
+
+ list->bottom = n;
+ if (!list->top) list->top = n;
+ ++list->len;
+ return n;
+}
+
void
list_delete_link(d_list_t *list, d_list_it_t *pos)
{
void list_unref(d_list_t *list);
d_list_it_t* list_prepend(d_list_t *list, void *data);
+d_list_it_t* list_append(d_list_t *list, void *data);
void list_delete_link(d_list_t *list, d_list_it_t *pos);
void list_move_before(d_list_t *list, d_list_it_t *move, d_list_it_t *before);
void list_remove(d_list_t *list, void *data);
{
data_t *d = screen_find_plugin_data(sc, PLUGIN_NAME);
- printf("painting\n");
+ printf("-- painting --\n");
/* call the function we replaced in the chain */
d->screen_paint(sc);
static void screen_add_existing_windows(d_screen_t *sc);
static void screen_set_next_repaint(d_screen_t *sc);
+static guint
+xcb_window_hash(xcb_window_t *w) { return *w; }
+
+static gboolean
+xcb_window_equal(xcb_window_t *w1, xcb_window_t *w2) { return *w1 == *w2; }
+
+
+d_screen_t*
+screen_new(struct d_display *dpy, int num, xcb_screen_t *xcb)
+{
+ d_screen_t *sc;
+
+ sc = malloc(sizeof(d_screen_t));
+ sc->super = *xcb;
+ sc->ref = 1;
+ sc->dpy = dpy;
+ sc->num = num;
+
+ gettimeofday(&sc->next_repaint, NULL);
+ sc->need_repaint = TRUE;
+
+ sc->winhash = g_hash_table_new((GHashFunc)xcb_window_hash,
+ (GEqualFunc)xcb_window_equal);
+ sc->stacking = list_new();
+ sc->plugin_data = g_hash_table_new_full((GHashFunc)g_str_hash,
+ (GEqualFunc)g_str_equal,
+ g_free, NULL);
+
+ return sc;
+}
+
+void
+screen_ref(d_screen_t *sc)
+{
+ ++sc->ref;
+}
+
+void
+screen_unref(d_screen_t *sc)
+{
+ if (sc && --sc->ref == 0) {
+ g_hash_table_unref(sc->winhash);
+ list_unref(sc->stacking);
+ g_hash_table_unref(sc->plugin_data);
+ free(sc);
+ }
+}
+
gboolean
-screen_register(struct d_display *dpy, int num, d_screen_t *sc)
+screen_register(d_screen_t *sc)
{
char *name;
xcb_window_t w;
uint32_t event_mask;
gboolean taken, ret;
- sc->dpy = dpy;
- sc->num = num;
w = xcb_generate_id(sc->dpy->conn);
event_mask = SELECTION_MASK;
xcb_create_window(sc->dpy->conn, XCB_COPY_FROM_PARENT, w, sc->super.root,
return ret;
}
-static guint
-xcb_window_hash(xcb_window_t *w) { return *w; }
-
-static gboolean
-xcb_window_equal(xcb_window_t *w1, xcb_window_t *w2) { return *w1 == *w2; }
-
static gboolean
screen_init(d_screen_t *sc)
{
xcb_change_window_attributes(sc->dpy->conn, sc->super.root,
XCB_CW_EVENT_MASK, &mask);
- gettimeofday(&sc->next_repaint, NULL);
-
- sc->winhash = g_hash_table_new((GHashFunc)xcb_window_hash,
- (GEqualFunc)xcb_window_equal);
- sc->stacking = list_new();
- sc->plugin_data = g_hash_table_new_full((GHashFunc)g_str_hash,
- (GEqualFunc)g_str_equal,
- g_free, NULL);
-
return TRUE;
}
-void screen_free(d_screen_t *sc)
-{
- g_hash_table_unref(sc->winhash);
- list_unref(sc->stacking);
- g_hash_table_unref(sc->plugin_data);
-}
-
void
screen_add_window(d_screen_t *sc, xcb_window_t wid)
{
gettimeofday(&sc->next_repaint, NULL);
/* add time for the refresh rate (60 hz) */
time_add(&sc->next_repaint, 1000000/60);
+ sc->need_repaint = FALSE;
}
void
{
g_hash_table_remove(sc->plugin_data, key);
}
+
+void screen_refresh(d_screen_t *sc)
+{
+ sc->need_repaint = TRUE;
+}
/* inherits from xcb_screen_t */
typedef struct d_screen {
xcb_screen_t super;
+ int ref;
struct d_display *dpy;
int num;
xcb_window_t overlay;
struct timeval next_repaint;
+ gboolean need_repaint;
GHashTable *winhash;
struct d_list *stacking;
void (*window_become_zombie)(struct d_window *w);
} d_screen_t;
+d_screen_t* screen_new(struct d_display *dpy, int num, xcb_screen_t *xcb);
+
+void screen_ref(d_screen_t *sc);
+void screen_unref(d_screen_t *sc);
+
/*! Tries to register on the screen given by @sc. If it succeeds, it fills
in @sc and returns TRUE, otherwise it returns FALSE.
*/
-gboolean screen_register(struct d_display *dpy, int num, d_screen_t *sc);
-void screen_free(d_screen_t *sc);
+gboolean screen_register(d_screen_t *sc);
void screen_add_window(d_screen_t *sc, xcb_window_t wid);
void screen_remove_window(d_screen_t *sc, struct d_window *w);
void* screen_find_plugin_data(d_screen_t *sc, const char *key);
void screen_remove_plugin_data(d_screen_t *sc, const char *key);
+void screen_refresh(d_screen_t *sc);
+
#endif
#include "time.h"
-void
-time_add(struct timeval *tv, long microseconds)
+static inline void
+time_fix(struct timeval *tv)
{
- tv->tv_usec += microseconds;
while (tv->tv_usec >= 1000000) {
tv->tv_usec -= 1000000;
++tv->tv_sec;
}
}
+void
+time_add(struct timeval *tv, long microseconds)
+{
+ tv->tv_usec += microseconds;
+ time_fix(tv);
+}
+
long
time_compare(struct timeval *a, struct timeval *b)
{
if ((r = a->tv_sec - b->tv_sec)) return r;
return a->tv_usec - b->tv_usec;
}
+
+void
+time_difference(struct timeval *a, struct timeval *b, struct timeval *r)
+{
+ struct timeval v;
+ v.tv_sec = a->tv_sec - b->tv_sec;
+ v.tv_usec = a->tv_usec - b->tv_usec;
+ time_fix(&v);
+ *r = v;
+}
void time_add(struct timeval *tv, long microseconds);
long time_compare(struct timeval *a, struct timeval *b);
+void time_difference(struct timeval *a, struct timeval *b, struct timeval *r);
#endif