]> Dogcows Code - chaz/openbox/commitdiff
otktimer works. imagecontrol is underway!
authorDana Jansens <danakj@orodu.net>
Sat, 21 Dec 2002 19:54:15 +0000 (19:54 +0000)
committerDana Jansens <danakj@orodu.net>
Sat, 21 Dec 2002 19:54:15 +0000 (19:54 +0000)
17 files changed:
otk_c/Makefile
otk_c/color.c
otk_c/display.c
otk_c/display.h
otk_c/font.c
otk_c/font.h
otk_c/gccache.c
otk_c/gccache.h
otk_c/imagecontrol.c [new file with mode: 0644]
otk_c/imagecontrol.h [new file with mode: 0644]
otk_c/init.c
otk_c/screeninfo.c
otk_c/screeninfo.h
otk_c/timer.c [new file with mode: 0644]
otk_c/timer.h [new file with mode: 0644]
otk_c/timerqueue.c [new file with mode: 0644]
otk_c/timerqueue.h [new file with mode: 0644]

index 397227ef84edfa6c9d0d3be71e57d4ec908b5ba6..f6cb0c54020b4b8d3732249721f4ea034bce8a96 100644 (file)
@@ -3,8 +3,10 @@ exec_prefix = $(prefix)
 libdir = $(exec_prefix)/lib
 
 targets = libotk.so libotk.a
-sources = init.c display.c screeninfo.c rect.c gccache.c color.c font.c
-headers = init.h display.h screeninfo.h rect.h gccache.h color.h font.h
+sources = init.c display.c screeninfo.c rect.c gccache.c color.c font.c \
+          timer.c timerqueue.c imagecontrol.c
+headers = init.h display.h screeninfo.h rect.h gccache.h color.h font.h \
+          timer.h timerqueue.h imagecontrol.h
 
 CFLAGS += -g -W -Wall -I/usr/gwar/include/python2.2 `pkg-config --cflags xft`
 LDFLAGS += `pkg-config --libs xft`
index 732f7b7d8d5baf5ef7915649b3e62f28d2f1822c..81f5b76a6b2a3fd3d069d580ea0cab710d5ec92c 100644 (file)
@@ -1,4 +1,4 @@
-// -*- mode: C; indent-tabs-mode: nil; -*-
+// -*- mode: C; indent-tabs-mode: nil; c-basic-offset: 2; -*-
 
 #include "../config.h"
 #include "color.h"
index 3ce7f06b535c49d8b15968ab0980bb98bffe5959..c0cae13cb07f5c37cbdd9bc5db25c7ad170aee11 100644 (file)
@@ -148,6 +148,7 @@ void OtkDisplay_Ungrab(OtkDisplay *self)
 
 OtkScreenInfo *OtkDisplay_ScreenInfo(OtkDisplay *self, int num)
 {
+  assert(num >= 0);
   return (OtkScreenInfo*)PyList_GetItem((PyObject*)self->screenInfoList, num);
 }
 
index aa55e0b9b3e8678939e1a308d892df28132abff4..32e92c4a6aee6e1c9f6356a4ae50d55668f5ad60 100644 (file)
@@ -1,4 +1,4 @@
-// -*- mode: C; indent-tabs-mode: nil; -*-
+// -*- mode: C; indent-tabs-mode: nil; c-basic-offset: 2; -*-
 #ifndef   __display_h
 #define   __display_h
 
index 7c9b4f5f797d061b4baaad69408cc8536384b1d8..a709f587ea22a2aa8d70b0381109b164e16e6ca4 100644 (file)
@@ -1,4 +1,4 @@
-// -*- mode: C; indent-tabs-mode: nil; -*-
+// -*- mode: C; indent-tabs-mode: nil; c-basic-offset: 2; -*-
 
 #include "../config.h"
 #include "font.h"
@@ -135,7 +135,7 @@ static PyObject *otkfont_getattr(PyObject *obj, char *name)
   return Py_FindMethod(get_methods, obj, name);
 }
 
-PyTypeObject Otkfont_Type = {
+PyTypeObject OtkFont_Type = {
   PyObject_HEAD_INIT(NULL)
   0,
   "OtkFont",
index 637a215d47b88943d8c6ce5de854a3ef77cf15eb..a1b2449069675b9c89d1c81d525663ccbb0ad018 100644 (file)
@@ -1,4 +1,4 @@
-// -*- mode: C; indent-tabs-mode: nil; -*-
+// -*- mode: C; indent-tabs-mode: nil; c-basic-offset: 2; -*-
 #ifndef   __font_h
 #define   __font_h
 
index f8b40f31e6d6fdfe148d2fa18de9287bbaa69e34..85ab9f9e4bf9fe8dfaa4651198e0f5feae61d2b4 100644 (file)
@@ -1,4 +1,4 @@
-// -*- mode: C; indent-tabs-mode: nil; -*-
+// -*- mode: C; indent-tabs-mode: nil; c-basic-offset: 2; -*-
 
 #include "../config.h"
 #include "gccache.h"
@@ -40,7 +40,7 @@ void OtkGCCacheContext_Set(OtkGCCacheContext *self,
   XGCValues gcv;
   unsigned long mask;
   
-  self->pixel = gcv.foreground = OtkColor_Pixel(color);
+  self->pixel = gcv.foreground = color->pixel;
   self->function = gcv.function = function;
   self->subwindow = gcv.subwindow_mode = subwindow;
   self->linewidth = gcv.line_width = linewidth;
@@ -156,7 +156,7 @@ static void OtkGCCache_InternalRelease(OtkGCCacheContext *ctx)
 OtkGCCacheItem *OtkGCCache_Find(OtkColor *color, XFontStruct *font,
                                int function, int subwindow, int linewidth)
 {
-  const unsigned long pixel = OtkColor_Pixel(color);
+  const unsigned long pixel = color->pixel;
   const int screen = color->screen;
   const int key = color->red ^ color->green ^ color->blue;
   int k = (key % gccache->cache_size) * gccache->cache_buckets;
index d731826020b24e6de4753cde865530577618cb00..119c256b9fd03d9b14c2a18e49a14a44b25df284 100644 (file)
@@ -1,4 +1,4 @@
-// -*- mode: C; indent-tabs-mode: nil; -*-
+// -*- mode: C; indent-tabs-mode: nil; c-basic-offset: 2; -*-
 #ifndef __gccache_h
 #define __gccache_h
 
diff --git a/otk_c/imagecontrol.c b/otk_c/imagecontrol.c
new file mode 100644 (file)
index 0000000..93eddc4
--- /dev/null
@@ -0,0 +1,325 @@
+// -*- mode: C; indent-tabs-mode: nil; c-basic-offset: 2; -*-
+
+#include "../config.h"
+#include "imagecontrol.h"
+#include "timer.h"
+#include "screeninfo.h"
+#include "display.h"
+
+typedef struct CachedImage {
+  Pixmap pixmap;
+  
+  unsigned int count, width, height;
+  unsigned long pixel1, pixel2, texture;
+} CachedImage;
+
+static void timeout(OtkImageControl *self);
+static void initColors(OtkImageControl *self, Visual *visual);
+
+PyObject *OtkImageControl_New(int screen)
+{
+  OtkImageControl *self;
+  int count, i;
+  XPixmapFormatValues *pmv;
+
+  self = PyObject_New(OtkImageControl, &OtkImageControl_Type);
+
+  self->screen = OtkDisplay_ScreenInfo(OBDisplay, screen);
+
+  self->timer = (OtkTimer*)OtkTimer_New((OtkTimeoutHandler)timeout, self);
+  self->timer->timeout = 300000;
+  OtkTimer_Start(self->timer);
+  self->cache_max = 200;
+  
+  self->dither = True; // default value
+  self->cpc = 4; // default value
+
+  // get the BPP from the X server
+  self->bpp = 0;
+  if ((pmv = XListPixmapFormats(OBDisplay->display, &count))) {
+    for (i = 0; i < count; i++)
+      if (pmv[i].depth == self->screen->depth) {
+       self->bpp = pmv[i].bits_per_pixel;
+       break;
+      }
+    XFree(pmv);
+  }
+  if (!self->bpp) self->bpp = self->screen->depth;
+  if (self->bpp >= 24) self->dither = False; // don't need dither at >= 24 bpp
+
+  self->grad_xbuffer = self->grad_ybuffer = NULL;
+  self->grad_buffer_width = self->grad_buffer_height = 0;
+  self->sqrt_table = NULL;
+
+  initColors(self, self->screen->visual);
+
+  return (PyObject*)self;
+}
+
+static void initColors(OtkImageControl *self, Visual *visual)
+{
+  // these are not used for !TrueColor
+  self->red_offset = self->green_offset = self->blue_offset = 0;
+  // these are not used for TrueColor
+  self->colors = NULL;
+  self->ncolors = 0;
+
+  // figure out all our color settings based on the visual type
+  switch (visual->class) {
+  case TrueColor: {
+    int i;
+    unsigned long red_mask, green_mask, blue_mask;
+
+    // find the offsets for each color in the visual's masks
+    red_mask = visual->red_mask;
+    green_mask = visual->green_mask;
+    blue_mask = visual->blue_mask;
+
+    while (! (red_mask & 1)) { self->red_offset++; red_mask >>= 1; }
+    while (! (green_mask & 1)) { self->green_offset++; green_mask >>= 1; }
+    while (! (blue_mask & 1)) { self->blue_offset++; blue_mask >>= 1; }
+
+    // use the mask to determine the number of bits for each shade of color
+    // so, best case, red_mask == 0xff (255), and so each bit is a different
+    // shade!
+    self->red_bits = 255 / red_mask;
+    self->green_bits = 255 / green_mask;
+    self->blue_bits = 255 / blue_mask;
+
+    // compute color tables, based on the number of bits for each shade
+    for (i = 0; i < 256; i++) {
+      self->red_color_table[i] = i / self->red_bits;
+      self->green_color_table[i] = i / self->green_bits;
+      self->blue_color_table[i] = i / self->blue_bits;
+    }
+    break;
+  }
+/*
+  case PseudoColor:
+  case StaticColor: {
+    ncolors = self->cpc * self->cpc * self->cpc; // cpc ^ 3
+
+    if (ncolors > (1 << self->screen->depth)) {
+      self->cpc = (1 << self->screen->depth) / 3;
+      ncolors = self->cpc * self->cpc * self->cpc; // cpc ^ 3
+    }
+
+    if (self->cpc < 2 || self->ncolors > (1 << self->screen->depth)) {
+      fprintf(stderr,
+             "OtkImageControl_New: invalid colormap size %d "
+              "(%d/%d/%d) - reducing",
+             self->ncolors, self->cpc, self->cpc, self->cpc);
+
+      self->cpc = (1 << self->screen->depth) / 3;
+    }
+
+    self->colors = malloc(sizeof(XColor) * self->ncolors);
+    if (! self->colors) {
+      fprintf(stderr, "OtkImageControl_New: error allocating colormap\n");
+      exit(1);
+    }
+
+    int i = 0, ii, p, r, g, b,
+      bits = 255 / (colors_per_channel - 1);
+
+    red_bits = green_bits = blue_bits = bits;
+
+    for (i = 0; i < 256; i++)
+      red_color_table[i] = green_color_table[i] = blue_color_table[i] =
+       i / bits;
+
+    for (r = 0, i = 0; r < colors_per_channel; r++)
+      for (g = 0; g < colors_per_channel; g++)
+       for (b = 0; b < colors_per_channel; b++, i++) {
+         colors[i].red = (r * 0xffff) / (colors_per_channel - 1);
+         colors[i].green = (g * 0xffff) / (colors_per_channel - 1);
+         colors[i].blue = (b * 0xffff) / (colors_per_channel - 1);;
+         colors[i].flags = DoRed|DoGreen|DoBlue;
+       }
+
+    for (i = 0; i < ncolors; i++) {
+      if (! XAllocColor(OBDisplay::display, colormap, &colors[i])) {
+       fprintf(stderr, "couldn't alloc color %i %i %i\n",
+               colors[i].red, colors[i].green, colors[i].blue);
+       colors[i].flags = 0;
+      } else {
+       colors[i].flags = DoRed|DoGreen|DoBlue;
+      }
+    }
+
+    XColor icolors[256];
+    int incolors = (((1 << screen_depth) > 256) ? 256 : (1 << screen_depth));
+
+    for (i = 0; i < incolors; i++)
+      icolors[i].pixel = i;
+
+    XQueryColors(OBDisplay::display, colormap, icolors, incolors);
+    for (i = 0; i < ncolors; i++) {
+      if (! colors[i].flags) {
+       unsigned long chk = 0xffffffff, pixel, close = 0;
+
+       p = 2;
+       while (p--) {
+         for (ii = 0; ii < incolors; ii++) {
+           r = (colors[i].red - icolors[i].red) >> 8;
+           g = (colors[i].green - icolors[i].green) >> 8;
+           b = (colors[i].blue - icolors[i].blue) >> 8;
+           pixel = (r * r) + (g * g) + (b * b);
+
+           if (pixel < chk) {
+             chk = pixel;
+             close = ii;
+           }
+
+           colors[i].red = icolors[close].red;
+           colors[i].green = icolors[close].green;
+           colors[i].blue = icolors[close].blue;
+
+           if (XAllocColor(OBDisplay::display, colormap,
+                           &colors[i])) {
+             colors[i].flags = DoRed|DoGreen|DoBlue;
+             break;
+           }
+         }
+       }
+      }
+    }
+
+    break;
+  }
+
+  case GrayScale:
+  case StaticGray: {
+    if (visual->c_class == StaticGray) {
+      ncolors = 1 << screen_depth;
+    } else {
+      ncolors = colors_per_channel * colors_per_channel * colors_per_channel;
+
+      if (ncolors > (1 << screen_depth)) {
+       colors_per_channel = (1 << screen_depth) / 3;
+       ncolors =
+         colors_per_channel * colors_per_channel * colors_per_channel;
+      }
+    }
+
+    if (colors_per_channel < 2 || ncolors > (1 << screen_depth)) {
+      fprintf(stderr,
+              "BImageControl::BImageControl: invalid colormap size %d "
+              "(%d/%d/%d) - reducing",
+             ncolors, colors_per_channel, colors_per_channel,
+             colors_per_channel);
+
+      colors_per_channel = (1 << screen_depth) / 3;
+    }
+
+    colors = new XColor[ncolors];
+    if (! colors) {
+      fprintf(stderr,
+              "BImageControl::BImageControl: error allocating colormap\n");
+      exit(1);
+    }
+
+    int i = 0, ii, p, bits = 255 / (colors_per_channel - 1);
+    red_bits = green_bits = blue_bits = bits;
+
+    for (i = 0; i < 256; i++)
+      red_color_table[i] = green_color_table[i] = blue_color_table[i] =
+       i / bits;
+
+    for (i = 0; i < ncolors; i++) {
+      colors[i].red = (i * 0xffff) / (colors_per_channel - 1);
+      colors[i].green = (i * 0xffff) / (colors_per_channel - 1);
+      colors[i].blue = (i * 0xffff) / (colors_per_channel - 1);;
+      colors[i].flags = DoRed|DoGreen|DoBlue;
+
+      if (! XAllocColor(OBDisplay::display, colormap,
+                       &colors[i])) {
+       fprintf(stderr, "couldn't alloc color %i %i %i\n",
+               colors[i].red, colors[i].green, colors[i].blue);
+       colors[i].flags = 0;
+      } else {
+       colors[i].flags = DoRed|DoGreen|DoBlue;
+      }
+    }
+
+    XColor icolors[256];
+    int incolors = (((1 << screen_depth) > 256) ? 256 :
+                   (1 << screen_depth));
+
+    for (i = 0; i < incolors; i++)
+      icolors[i].pixel = i;
+
+    XQueryColors(OBDisplay::display, colormap, icolors, incolors);
+    for (i = 0; i < ncolors; i++) {
+      if (! colors[i].flags) {
+       unsigned long chk = 0xffffffff, pixel, close = 0;
+
+       p = 2;
+       while (p--) {
+         for (ii = 0; ii < incolors; ii++) {
+           int r = (colors[i].red - icolors[i].red) >> 8;
+           int g = (colors[i].green - icolors[i].green) >> 8;
+           int b = (colors[i].blue - icolors[i].blue) >> 8;
+           pixel = (r * r) + (g * g) + (b * b);
+
+           if (pixel < chk) {
+             chk = pixel;
+             close = ii;
+           }
+
+           colors[i].red = icolors[close].red;
+           colors[i].green = icolors[close].green;
+           colors[i].blue = icolors[close].blue;
+
+           if (XAllocColor(OBDisplay::display, colormap,
+                           &colors[i])) {
+             colors[i].flags = DoRed|DoGreen|DoBlue;
+             break;
+           }
+         }
+       }
+      }
+    }
+
+    break;
+  }
+*/
+  default:
+    fprintf(stderr, "OtkImageControl: unsupported visual class: %d\n",
+           visual->class);
+    exit(1);
+  }
+}
+
+
+static void timeout(OtkImageControl *self)
+{
+  (void)self;
+}
+
+
+
+static void otkimagecontrol_dealloc(OtkImageControl* self)
+{
+  Py_DECREF(self->screen);
+  Py_DECREF(self->timer);
+  PyObject_Del((PyObject*)self);
+}
+
+PyTypeObject OtkImageControl_Type = {
+  PyObject_HEAD_INIT(NULL)
+  0,
+  "OtkImageControl",
+  sizeof(OtkImageControl),
+  0,
+  (destructor)otkimagecontrol_dealloc, /*tp_dealloc*/
+  0,                            /*tp_print*/
+  0,                            /*tp_getattr*/
+  0,                            /*tp_setattr*/
+  0,                            /*tp_compare*/
+  0,                            /*tp_repr*/
+  0,                            /*tp_as_number*/
+  0,                            /*tp_as_sequence*/
+  0,                            /*tp_as_mapping*/
+  0,                            /*tp_hash */
+};
diff --git a/otk_c/imagecontrol.h b/otk_c/imagecontrol.h
new file mode 100644 (file)
index 0000000..7ed6aec
--- /dev/null
@@ -0,0 +1,115 @@
+// -*- mode: C; indent-tabs-mode: nil; c-basic-offset: 2; -*-
+#ifndef   __imagecontrol_h
+#define   __imagecontrol_h
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <Python.h>
+
+struct OtkScreenInfo;
+struct OtkTimer;
+
+extern PyTypeObject OtkImageControl_Type;
+
+typedef struct OtkImageControl {
+  struct OtkScreenInfo *screen;
+
+  // for the pixmap cache
+  struct OtkTimer *timer;
+  unsigned long cache_max;
+
+  Bool dither;
+
+  int cpc; // colors-per-channel: must be a value between [2,6]
+  int bpp; // bits-per-pixel
+
+  unsigned int *grad_xbuffer;
+  unsigned int *grad_ybuffer;
+  unsigned int grad_buffer_width;
+  unsigned int grad_buffer_height;
+
+  unsigned long *sqrt_table;
+
+  // These values are all determined based on a visual
+  
+  int red_bits;    // the number of bits (1-255) that each shade of color
+  int green_bits;  // spans across. best case is 1, which gives 255 shades.
+  int blue_bits;
+  unsigned char red_color_table[256];
+  unsigned char green_color_table[256];
+  unsigned char blue_color_table[256];
+
+  // These are only used for TrueColor visuals
+  int red_offset;  // the offset of each color in a color mask
+  int green_offset;
+  int blue_offset;
+
+  // These are only used for !TrueColor visuals
+  XColor *colors;
+  int ncolors;
+
+} OtkImageControl;
+
+PyObject *OtkImageControl_New(int screen);
+
+
+/*
+  inline bool doDither(void) { return dither; }
+
+  inline const ScreenInfo* getScreenInfo() const { return screeninfo; }
+
+  inline Window getDrawable(void) const { return window; }
+
+  inline Visual *getVisual(void) { return screeninfo->visual(); }
+
+  inline int getBitsPerPixel(void) const { return bits_per_pixel; }
+  inline int getDepth(void) const { return screen_depth; }
+  inline int getColorsPerChannel(void) const
+    { return colors_per_channel; }
+
+  unsigned long getSqrt(unsigned int x);
+
+  Pixmap renderImage(unsigned int width, unsigned int height,
+                     const BTexture &texture);
+
+  void installRootColormap(void);
+  void removeImage(Pixmap pixmap);
+  void getColorTables(unsigned char **rmt, unsigned char **gmt,
+                      unsigned char **bmt,
+                      int *roff, int *goff, int *boff,
+                      int *rbit, int *gbit, int *bbit);
+  void getXColorTable(XColor **c, int *n);
+  void getGradientBuffers(unsigned int w, unsigned int h,
+                          unsigned int **xbuf, unsigned int **ybuf);
+  void setDither(bool d) { dither = d; }
+
+  static void timeout(BImageControl *t);
+
+private:
+  bool dither;
+  const ScreenInfo *screeninfo;
+  OBTimer *timer;
+
+  Colormap colormap;
+
+  Window window;
+  XColor *colors;
+  int colors_per_channel, ncolors, screen_number, screen_depth,
+    bits_per_pixel, red_offset, green_offset, blue_offset,
+    red_bits, green_bits, blue_bits;
+  unsigned char red_color_table[256], green_color_table[256],
+    blue_color_table[256];
+  unsigned int *grad_xbuffer, *grad_ybuffer, grad_buffer_width,
+    grad_buffer_height;
+  unsigned long *sqrt_table, cache_max;
+
+  typedef std::list<CachedImage> CacheContainer;
+  CacheContainer cache;
+
+  Pixmap searchCache(const unsigned int width, const unsigned int height,
+                     const unsigned long texture,
+                     const BColor &c1, const BColor &c2);
+};
+*/
+
+#endif // __imagecontrol_h
index 8ea5d4a1d6fbbe9087356fcf32958201fddf0171..32a651bc9c75edf3902ad3a6720bb597fda3794a 100644 (file)
@@ -6,6 +6,10 @@
 #include "color.h"
 #include "gccache.h"
 #include "font.h"
+#include "rect.h"
+#include "timer.h"
+#include "timerqueue.h"
+#include "imagecontrol.h"
 
 #include <X11/Xlib.h>
 #include <Python.h>
@@ -24,9 +28,12 @@ void initotk(char *display)
   OtkScreenInfo_Type.ob_type = &PyType_Type;
   OtkColor_Type.ob_type = &PyType_Type;
   OtkFont_Type.ob_type = &PyType_Type;
+  OtkTimer_Type.ob_type = &PyType_Type;
+  OtkImageControl_Type.ob_type = &PyType_Type;
 
   Py_InitModule("otk", otk_methods);
 
+  OtkTimerQueue_Initialize();
   OtkDisplay_Initialize(display);
   assert(OBDisplay);
   OtkGCCache_Initialize();
index 62d65eb59d284bdef4de8286cb4e5dabb0a5305f..2f11cfd9661e0f5f2114ad8868bd7ab1b3983b9b 100644 (file)
@@ -1,4 +1,4 @@
-// -*- mode: C; indent-tabs-mode: nil; -*-
+// -*- mode: C; indent-tabs-mode: nil; c-basic-offset: 2; -*-
 
 #include "../config.h"
 #include "screeninfo.h"
index 745d62adfccd38fda3c2417d6050dba6316b7b96..70ce7d3acba75d32d2d0219c9690fcaf706cc257 100644 (file)
@@ -10,6 +10,7 @@ extern PyTypeObject OtkScreenInfo_Type;
 struct OtkRect;
 
 typedef struct OtkScreenInfo {
+  PyObject_HEAD
   int screen;
   Window root_window;
 
diff --git a/otk_c/timer.c b/otk_c/timer.c
new file mode 100644 (file)
index 0000000..8764a0e
--- /dev/null
@@ -0,0 +1,79 @@
+// -*- mode: C; indent-tabs-mode: nil; c-basic-offset: 2; -*-
+
+#include "../config.h"
+#include "timer.h"
+#include "timerqueue.h"
+
+PyObject *OtkTimer_New(OtkTimeoutHandler handler, OtkTimeoutData data)
+{
+  OtkTimer *self = PyObject_New(OtkTimer, &OtkTimer_Type);
+
+  assert(handler); assert(data);
+  self->handler = handler;
+  self->data = data;
+  self->recur = self->timing = False;
+
+  return (PyObject*)self;
+}
+
+void OtkTimer_Start(OtkTimer *self)
+{
+  gettimeofday(&(self->start), 0);
+
+  self->end.tv_sec = self->start.tv_sec + self->timeout / 1000;
+  self->end.tv_usec = self->start.tv_usec + self->timeout % 1000 * 1000;
+
+  if (! self->timing) {
+    self->timing = True;
+    OtkTimerQueue_Add(self);
+  }
+}
+
+void OtkTimer_Stop(OtkTimer *self)
+{
+  if (self->timing) {
+    self->timing = False;
+    OtkTimerQueue_Remove(self);
+  }
+}
+
+
+
+
+
+static void otktimer_dealloc(OtkTimer* self)
+{
+  OtkTimer_Stop(self);  
+  // when this is called, the color has already been cleaned out of the cache
+  PyObject_Del((PyObject*)self);
+}
+
+static int otktimer_compare(OtkTimer *t1, OtkTimer *t2)
+{
+  if (t1->end.tv_sec == t2->end.tv_sec && t1->end.tv_usec == t2->end.tv_usec)
+    return 0;
+  else if ((t1->end.tv_sec < t2->end.tv_sec) ||
+          (t1->end.tv_sec == t2->end.tv_sec &&
+           t1->end.tv_usec < t2->end.tv_usec))
+    return -1;
+  else
+    return 1;
+}
+
+PyTypeObject OtkTimer_Type = {
+  PyObject_HEAD_INIT(NULL)
+  0,
+  "OtkTimer",
+  sizeof(OtkTimer),
+  0,
+  (destructor)otktimer_dealloc, /*tp_dealloc*/
+  0,                            /*tp_print*/
+  0,                            /*tp_getattr*/
+  0,                            /*tp_setattr*/
+  (cmpfunc)otktimer_compare,    /*tp_compare*/
+  0,                            /*tp_repr*/
+  0,                            /*tp_as_number*/
+  0,                            /*tp_as_sequence*/
+  0,                            /*tp_as_mapping*/
+  0,                            /*tp_hash */
+};
diff --git a/otk_c/timer.h b/otk_c/timer.h
new file mode 100644 (file)
index 0000000..8e5399e
--- /dev/null
@@ -0,0 +1,52 @@
+// -*- mode: C; indent-tabs-mode: nil; c-basic-offset: 2; -*-
+#ifndef __timer_h
+#define __timer_h
+
+#include <X11/Xlib.h>
+#include <Python.h>
+
+#ifdef    TIME_WITH_SYS_TIME
+#  include <sys/time.h>
+#  include <time.h>
+#else // !TIME_WITH_SYS_TIME
+#  ifdef    HAVE_SYS_TIME_H
+#    include <sys/time.h>
+#  else // !HAVE_SYS_TIME_H
+#    include <time.h>
+#  endif // HAVE_SYS_TIME_H
+#endif // TIME_WITH_SYS_TIME
+
+extern PyTypeObject OtkTimer_Type;
+
+//! The data passed to the OtkTimeoutHandler function.
+/*!
+  Note: this is a very useful place to put an object instance, and set the
+  event handler to a static function in the same class.
+*/
+typedef void *OtkTimeoutData;
+//! The type of function which can be set as the callback for an OtkTimer
+//! firing
+typedef void (*OtkTimeoutHandler)(OtkTimeoutData);
+
+typedef struct OtkTimer {
+  PyObject_HEAD
+  OtkTimeoutHandler handler;
+  OtkTimeoutData data;
+  Bool recur;
+  long timeout;
+
+  // don't edit these
+  Bool timing;
+  struct timeval start;
+  struct timeval end;
+} OtkTimer;
+
+PyObject *OtkTimer_New(OtkTimeoutHandler handler, OtkTimeoutData data);
+
+//! Causes the timer to begin
+void OtkTimer_Start(OtkTimer *self);
+
+//! Causes the timer to stop
+void OtkTimer_Stop(OtkTimer *self);
+
+#endif // __timer_h
diff --git a/otk_c/timerqueue.c b/otk_c/timerqueue.c
new file mode 100644 (file)
index 0000000..25fd850
--- /dev/null
@@ -0,0 +1,98 @@
+// -*- mode: C; indent-tabs-mode: nil; c-basic-offset: 2; -*-
+
+#include "../config.h"
+#include "timerqueue.h"
+#include "display.h"
+
+#include <X11/Xlib.h>
+#include <Python.h>
+
+static PyObject *list = NULL; // PyListObject
+
+void OtkTimerQueue_Initialize()
+{
+  list = PyList_New(0);
+}
+
+void OtkTimerQueue_Add(OtkTimer* timer)
+{
+  PyList_Append(list, (PyObject*)timer);
+  PyList_Sort(list);
+}
+
+void OtkTimerQueue_Remove(OtkTimer* timer)
+{
+  int index;
+
+  index = PySequence_Index(list, (PyObject*)timer);
+  if (index >= 0)
+    PySequence_DelItem(list, index);
+}
+
+static Bool shouldFire(OtkTimer *timer, const struct timeval *now)
+{
+  return ! ((now->tv_sec < timer->end.tv_sec) ||
+           (now->tv_sec == timer->end.tv_sec &&
+            now->tv_usec < timer->end.tv_usec));
+}
+
+static void normalizeTimeval(struct timeval *time)
+{
+  while (time->tv_usec < 0) {
+    if (time->tv_sec > 0) {
+      --time->tv_sec;
+      time->tv_usec += 1000000;
+    } else {
+      time->tv_usec = 0;
+    }
+  }
+
+  if (time->tv_usec >= 1000000) {
+    time->tv_sec += time->tv_usec / 1000000;
+    time->tv_usec %= 1000000;
+  }
+
+  if (time->tv_sec < 0) time->tv_sec = 0;
+}
+
+void OtkTimerQueue_Fire()
+{
+  fd_set rfds;
+  struct timeval now, tm, *timeout = NULL;
+
+  const int xfd = ConnectionNumber(OBDisplay->display);
+  
+  FD_ZERO(&rfds);
+  FD_SET(xfd, &rfds); // break on any x events
+
+  // check for timer timeout
+  gettimeofday(&now, 0);
+  
+  // there is a small chance for deadlock here:
+  // *IF* the timer list keeps getting refreshed *AND* the time between
+  // timer->start() and timer->shouldFire() is within the timer's period
+  // then the timer will keep firing.  This should be VERY near impossible.
+  while (PyList_Size(list)) {
+    OtkTimer *timer = (OtkTimer*)PyList_GetItem(list, 0);
+    
+    if (! shouldFire(timer, &now)) {
+      tm.tv_sec = timer->end.tv_sec - now.tv_sec;
+      tm.tv_usec = timer->end.tv_usec - now.tv_usec;
+      normalizeTimeval(&tm);
+      timeout = &tm; // set the timeout for the select
+      break; // go on and wait
+    }
+
+    // stop and remove the timer from the queue
+    PySequence_DelItem(list, 0);
+    timer->timing = False;
+
+    if (timer->handler)
+      timer->handler(timer->data);
+
+    if (timer->recur)
+      OtkTimer_Start(timer);
+  }
+
+  select(xfd + 1, &rfds, 0, 0, timeout);
+}
diff --git a/otk_c/timerqueue.h b/otk_c/timerqueue.h
new file mode 100644 (file)
index 0000000..151aea0
--- /dev/null
@@ -0,0 +1,27 @@
+// -*- mode: C; indent-tabs-mode: nil; c-basic-offset: 2; -*-
+#ifndef __timerqueue_h
+#define __timerqueue_h
+
+#include "timer.h"
+
+void OtkTimerQueue_Initialize();
+
+//! Will wait for and fire the next timer in the queue.
+/*!
+  The function will stop waiting if an event is received from the X server.
+*/
+void OtkTimerQueue_Fire();
+
+//! Adds a new timer to the queue
+/*!
+  @param timer An OtkTimer to add to the queue
+*/
+void OtkTimerQueue_Add(OtkTimer* timer);
+
+//! Removes a timer from the queue
+/*!
+  @param timer An OtkTimer already in the queue to remove
+*/
+void OtkTimerQueue_Remove(OtkTimer* timer);
+
+#endif // __timerqueue_h
This page took 0.043978 seconds and 4 git commands to generate.