otktimer works. imagecontrol is underway!
This commit is contained in:
parent
4c9bf6c9a1
commit
065c6efa77
17 changed files with 719 additions and 12 deletions
|
@ -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`
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
325
otk_c/imagecontrol.c
Normal file
325
otk_c/imagecontrol.c
Normal file
|
@ -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 */
|
||||
};
|
115
otk_c/imagecontrol.h
Normal file
115
otk_c/imagecontrol.h
Normal file
|
@ -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
|
|
@ -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();
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -10,6 +10,7 @@ extern PyTypeObject OtkScreenInfo_Type;
|
|||
struct OtkRect;
|
||||
|
||||
typedef struct OtkScreenInfo {
|
||||
PyObject_HEAD
|
||||
int screen;
|
||||
Window root_window;
|
||||
|
||||
|
|
79
otk_c/timer.c
Normal file
79
otk_c/timer.c
Normal file
|
@ -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 */
|
||||
};
|
52
otk_c/timer.h
Normal file
52
otk_c/timer.h
Normal file
|
@ -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
|
98
otk_c/timerqueue.c
Normal file
98
otk_c/timerqueue.c
Normal file
|
@ -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);
|
||||
}
|
27
otk_c/timerqueue.h
Normal file
27
otk_c/timerqueue.h
Normal file
|
@ -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
|
Loading…
Reference in a new issue