diff options
author | Keith Packard <keithp@keithp.com> | 2004-10-06 00:11:27 +0000 |
---|---|---|
committer | Keith Packard <keithp@keithp.com> | 2004-10-06 00:11:27 +0000 |
commit | dc7477b9826f7cb6e95d591698daaf5251e65bf4 (patch) | |
tree | 37bb92d430656e47d9d307cd25cea9822f1a48e4 | |
parent | a8611583a5e0e2539be9841c8d5a6e37b7cff7a6 (diff) | |
download | libtwin-dc7477b9826f7cb6e95d591698daaf5251e65bf4.tar.gz |
Add the beginings of event dispatch and a bit of window management
including titles. Default event dispatcher does restacking and motion.
-rw-r--r-- | ChangeLog | 32 | ||||
-rw-r--r-- | Makefile.am | 2 | ||||
-rw-r--r-- | twin.h | 213 | ||||
-rw-r--r-- | twin_draw.c | 18 | ||||
-rw-r--r-- | twin_path.c | 1 | ||||
-rw-r--r-- | twin_pixmap.c | 95 | ||||
-rw-r--r-- | twin_screen.c | 140 | ||||
-rw-r--r-- | twin_thread.c | 83 | ||||
-rw-r--r-- | twin_window.c | 251 | ||||
-rw-r--r-- | twin_x11.c | 73 | ||||
-rw-r--r-- | twin_x11.h | 9 | ||||
-rw-r--r-- | xtwin.c | 92 |
12 files changed, 851 insertions, 158 deletions
@@ -1,5 +1,37 @@ 2004-10-05 Keith Packard <keithp@keithp.com> + * Makefile.am: + * twin.h: + * twin_draw.c: (twin_fill): + * twin_path.c: (twin_composite_path): + * twin_pixmap.c: (twin_pixmap_create), (twin_pixmap_show), + (twin_pixmap_hide), (_twin_pixmap_fetch), + (twin_pixmap_transparent), (twin_pixmap_move), + (twin_pixmap_dispatch): + * twin_screen.c: (twin_screen_create), (twin_screen_lock), + (twin_screen_unlock), (twin_screen_update), + (twin_screen_set_active), (twin_screen_get_active), + (twin_screen_dispatch): + * twin_thread.c: (twin_mutex_init), (twin_mutex_lock), + (twin_mutex_unlock), (twin_cond_init), (twin_cond_broadcast), + (twin_cond_wait), (twin_thread_create): + * twin_window.c: (twin_window_create), (twin_window_destroy), + (twin_window_show), (twin_window_hide), (twin_window_configure), + (twin_window_style_size), (twin_window_set_name), + (twin_window_frame), (twin_window_draw), (twin_window_dispatch): + * twin_x11.c: (_twin_x11_put_begin), (_twin_x11_put_span), + (twin_x11_damage_thread), (twin_x11_event_thread), + (twin_x11_screen_damaged), (twin_x11_create), (twin_x11_destroy): + * twin_x11.h: + * xtwin.c: (twin_clock_set_transform), (twin_clock_hand), + (twin_clock_face), (twin_clock), (twin_app_thread), + (twin_start_app), (twin_start_clock), (main): + Add the beginings of event dispatch and a bit of + window management including titles. Default event dispatcher + does restacking and motion. + +2004-10-05 Keith Packard <keithp@keithp.com> + * twin.h: * twin_draw.c: (twin_composite), (twin_fill): * twin_matrix.c: (twin_matrix_multiply), (twin_matrix_translate), diff --git a/Makefile.am b/Makefile.am index 4b7f8d7..999deae 100644 --- a/Makefile.am +++ b/Makefile.am @@ -30,7 +30,9 @@ xtwin_SOURCES = \ twin_primitive.c \ twin_screen.c \ twin_spline.c \ + twin_thread.c \ twin_trig.c \ + twin_window.c \ twin_x11.c \ twinint.h \ xtwin.c @@ -44,6 +44,19 @@ typedef int16_t twin_count_t; typedef int16_t twin_keysym_t; typedef int32_t twin_area_t; +/* + * Mutexes + */ +#if HAVE_PTHREAD_H +typedef pthread_mutex_t twin_mutex_t; +typedef pthread_cond_t twin_cond_t; +typedef pthread_t twin_thread_t; +#else +typedef int twin_mutext_t; +typedef int twin_cond_t; +typedef int twin_thread_t; +#endif + #define TWIN_FALSE 0 #define TWIN_TRUE 1 @@ -80,6 +93,8 @@ typedef union _twin_pointer { twin_argb32_t *argb32; } twin_pointer_t; +typedef struct _twin_window twin_window_t; + /* * A rectangular array of pixels */ @@ -92,7 +107,7 @@ typedef struct _twin_pixmap { /* * List of displayed pixmaps */ - struct _twin_pixmap *higher; + struct _twin_pixmap *down, *up; /* * Screen position */ @@ -108,20 +123,25 @@ typedef struct _twin_pixmap { * Pixels */ twin_pointer_t p; + /* + * When representing a window, this point + * refers to the window object + */ + twin_window_t *window; } twin_pixmap_t; /* * twin_put_begin_t: called before data are drawn to the screen * twin_put_span_t: called for each scanline drawn */ -typedef void (*twin_put_begin_t) (twin_coord_t x, - twin_coord_t y, - twin_coord_t width, - twin_coord_t height, +typedef void (*twin_put_begin_t) (twin_coord_t left, + twin_coord_t top, + twin_coord_t right, + twin_coord_t bottom, void *closure); -typedef void (*twin_put_span_t) (twin_coord_t x, - twin_coord_t y, - twin_coord_t width, +typedef void (*twin_put_span_t) (twin_coord_t left, + twin_coord_t top, + twin_coord_t right, twin_argb32_t *pixels, void *closure); @@ -132,7 +152,15 @@ typedef struct _twin_screen { /* * List of displayed pixmaps */ - twin_pixmap_t *bottom; + twin_pixmap_t *top, *bottom; + /* + * One of them receives all key events + */ + twin_pixmap_t *active; + /* + * pointer down for this window + */ + twin_pixmap_t *pointer; /* * Output size */ @@ -144,15 +172,17 @@ typedef struct _twin_screen { void (*damaged) (void *); void *damaged_closure; twin_count_t disable; -#if HAVE_PTHREAD_H - pthread_mutex_t screen_mutex; -#endif + twin_mutex_t screen_mutex; /* * Repaint function */ twin_put_begin_t put_begin; twin_put_span_t put_span; void *closure; + /* + * Window manager stuff + */ + twin_coord_t button_x, button_y; } twin_screen_t; /* @@ -226,7 +256,8 @@ typedef struct _twin_text_metrics { typedef enum _twin_event_kind { EventButtonDown, EventButtonUp, EventMotion, - EventKeyDown, EventKeyUp, EventUcs4 + EventKeyDown, EventKeyUp, EventUcs4, + EventActivate, EventDeactivate, } twin_event_kind_t; typedef struct _twin_event { @@ -234,11 +265,9 @@ typedef struct _twin_event { union { struct { twin_coord_t x, y; + twin_coord_t screen_x, screen_y; twin_count_t button; - } button; - struct { - twin_coord_t x, y; - } motion; + } pointer; struct { twin_keysym_t key; } key; @@ -248,6 +277,53 @@ typedef struct _twin_event { } u; } twin_event_t; +typedef struct _twin_event_queue { + struct _twin_event_queue *next; + twin_event_t event; +} twin_event_queue_t; + +/* + * Windows + */ + +typedef enum _twin_window_style { + WindowPlain, + WindowApplication, +} twin_window_style_t; + +typedef void (*twin_draw_func_t) (twin_window_t *window); + +typedef twin_bool_t (*twin_event_func_t) (twin_window_t *window, + twin_event_t *event); + +typedef void (*twin_destroy_func_t) (twin_window_t *window); + +struct _twin_window { + twin_screen_t *screen; + twin_pixmap_t *pixmap; + twin_window_style_t style; + twin_rect_t client; + twin_rect_t damage; + void *client_data; + char *name; + + twin_draw_func_t draw; + twin_event_func_t event; + twin_destroy_func_t destroy; +}; + +/* + * Widgets + */ + +typedef struct { + twin_rect_t geometry; +} twin_widget_t; + +typedef struct { + twin_widget_t core; +} twin_button_t; + /* * twin_convolve.c */ @@ -278,10 +354,17 @@ void twin_fill (twin_pixmap_t *dst, twin_argb32_t pixel, twin_operator_t operator, - twin_coord_t x, - twin_coord_t y, - twin_coord_t width, - twin_coord_t height); + twin_coord_t left, + twin_coord_t top, + twin_coord_t right, + twin_coord_t bottom); + +/* + * twin_event.c + */ + +void +twin_event_enqueue (const twin_event_t *event); /* * twin_fixed.c @@ -515,6 +598,12 @@ twin_pixmap_move (twin_pixmap_t *pixmap, twin_coord_t x, twin_coord_t y); twin_pointer_t twin_pixmap_pointer (twin_pixmap_t *pixmap, twin_coord_t x, twin_coord_t y); +twin_bool_t +twin_pixmap_transparent (twin_pixmap_t *pixmap, twin_coord_t x, twin_coord_t y); + +twin_bool_t +twin_pixmap_dispatch (twin_pixmap_t *pixmap, twin_event_t *event); + /* * twin_poly.c */ @@ -563,6 +652,16 @@ void twin_screen_update (twin_screen_t *screen); void +twin_screen_set_active (twin_screen_t *screen, twin_pixmap_t *pixmap); + +twin_pixmap_t * +twin_screen_get_active (twin_screen_t *screen); + +twin_bool_t +twin_screen_dispatch (twin_screen_t *screen, + twin_event_t *event); + +void twin_screen_lock (twin_screen_t *screen); void @@ -580,6 +679,33 @@ twin_path_curve (twin_path_t *path, twin_fixed_t x3, twin_fixed_t y3); /* + * twin_thread.c + */ + +void +twin_mutex_init (twin_mutex_t *mutex); + +void +twin_mutex_lock (twin_mutex_t *mutex); + +void +twin_mutex_unlock (twin_mutex_t *mutex); + +void +twin_cond_init (twin_cond_t *cond); + +void +twin_cond_broadcast (twin_cond_t *cond); + +void +twin_cond_wait (twin_cond_t *cond, twin_mutex_t *mutex); + +typedef void * (*twin_thread_func_t) (void *arg); + +int +twin_thread_create (twin_thread_t *thread, twin_thread_func_t func, void *arg); + +/* * twin_trig.c */ @@ -592,4 +718,49 @@ twin_cos (twin_angle_t a); twin_fixed_t twin_tan (twin_angle_t a); +/* + * twin_window.c + */ + +twin_window_t * +twin_window_create (twin_screen_t *screen, + twin_format_t format, + twin_window_style_t style, + twin_coord_t x, + twin_coord_t y, + twin_coord_t width, + twin_coord_t height); + +void +twin_window_destroy (twin_window_t *window); + +void +twin_window_show (twin_window_t *window); + +void +twin_window_hide (twin_window_t *window); + +void +twin_window_configure (twin_window_t *window, + twin_window_style_t style, + twin_coord_t x, + twin_coord_t y, + twin_coord_t width, + twin_coord_t height); + +void +twin_window_set_name (twin_window_t *window, + const char *name); + +void +twin_window_style_size (twin_window_style_t style, + twin_rect_t *size); + +void +twin_window_draw (twin_window_t *window); + +twin_bool_t +twin_window_dispatch (twin_window_t *window, twin_event_t *event); + + #endif /* _TWIN_H_ */ diff --git a/twin_draw.c b/twin_draw.c index 505eed7..9a8a2c6 100644 --- a/twin_draw.c +++ b/twin_draw.c @@ -370,32 +370,28 @@ void twin_fill (twin_pixmap_t *dst, twin_argb32_t pixel, twin_operator_t operator, - twin_coord_t x, - twin_coord_t y, - twin_coord_t width, - twin_coord_t height) + twin_coord_t left, + twin_coord_t top, + twin_coord_t right, + twin_coord_t bottom) { twin_src_op op; twin_source_u src; twin_coord_t iy; - twin_coord_t left, right, top, bottom; twin_pixmap_lock (dst); src.c = pixel; - left = x; - right = x + width; - top = y; - bottom = y + height; if (left < 0) left = 0; if (right > dst->width) right = dst->width; if (top < 0) top = 0; - if (top > dst->height) - top = dst->height; + if (bottom > dst->height) + bottom = dst->height; op = fill[operator][dst->format]; for (iy = top; iy < bottom; iy++) (*op) (twin_pixmap_pointer (dst, left, iy), src, right - left); + twin_pixmap_damage (dst, left, right, top, bottom); twin_pixmap_unlock (dst); } diff --git a/twin_path.c b/twin_path.c index 468e22e..74d527a 100644 --- a/twin_path.c +++ b/twin_path.c @@ -443,7 +443,6 @@ twin_composite_path (twin_pixmap_t *dst, if (!mask) return; - twin_fill (mask, 0x00000000, TWIN_SOURCE, 0, 0, width, height); twin_fill_path (mask, path, -bounds.left, -bounds.top); msk.source_kind = TWIN_PIXMAP; msk.u.pixmap = mask; diff --git a/twin_pixmap.c b/twin_pixmap.c index 5882bfe..ad0abe5 100644 --- a/twin_pixmap.c +++ b/twin_pixmap.c @@ -30,12 +30,14 @@ twin_pixmap_create (twin_format_t format, twin_coord_t height) { twin_coord_t stride = twin_bytes_per_pixel (format) * width; - twin_area_t size = sizeof (twin_pixmap_t) + (twin_area_t) stride * height; + twin_area_t space = (twin_area_t) stride * height; + twin_area_t size = sizeof (twin_pixmap_t) + space; twin_pixmap_t *pixmap = malloc (size); if (!pixmap) return 0; pixmap->screen = 0; - pixmap->higher = 0; + pixmap->up = 0; + pixmap->down = 0; pixmap->x = pixmap->y = 0; pixmap->format = format; pixmap->width = width; @@ -43,6 +45,7 @@ twin_pixmap_create (twin_format_t format, pixmap->stride = stride; pixmap->disable = 0; pixmap->p.v = pixmap + 1; + memset (pixmap->p.v, '\0', space); return pixmap; } @@ -59,23 +62,36 @@ twin_pixmap_show (twin_pixmap_t *pixmap, twin_screen_t *screen, twin_pixmap_t *lower) { - twin_pixmap_t **higherp; - - twin_screen_lock (screen); - if (pixmap->disable) twin_screen_disable_update (screen); + if (lower == pixmap) + lower = pixmap->down; + if (pixmap->screen) twin_pixmap_hide (pixmap); + twin_screen_lock (screen); + pixmap->screen = screen; + if (lower) - higherp = &lower->higher; + { + pixmap->down = lower; + pixmap->up = lower->up; + lower->up = pixmap; + if (!pixmap->up) + screen->top = pixmap; + } else - higherp = &screen->bottom; - pixmap->higher = *higherp; - *higherp = pixmap; + { + pixmap->down = NULL; + pixmap->up = screen->bottom; + screen->bottom = pixmap; + if (!pixmap->up) + screen->top = pixmap; + } + twin_pixmap_damage (pixmap, 0, 0, pixmap->width, pixmap->height); twin_screen_unlock (screen); } @@ -84,17 +100,29 @@ void twin_pixmap_hide (twin_pixmap_t *pixmap) { twin_screen_t *screen = pixmap->screen; - twin_pixmap_t **higherp; + twin_pixmap_t **up, **down; if (!screen) return; twin_screen_lock (screen); twin_pixmap_damage (pixmap, 0, 0, pixmap->width, pixmap->height); - for (higherp = &screen->bottom; *higherp != pixmap; higherp = &(*higherp)->higher) - ; - *higherp = pixmap->higher; + + if (pixmap->up) + down = &pixmap->up->down; + else + down = &screen->top; + + if (pixmap->down) + up = &pixmap->down->up; + else + up = &screen->bottom; + + *down = pixmap->down; + *up = pixmap->up; + pixmap->screen = 0; - pixmap->higher = 0; + pixmap->up = 0; + pixmap->down = 0; if (pixmap->disable) twin_screen_enable_update (screen); twin_screen_unlock (screen); @@ -158,11 +186,48 @@ twin_pixmap_unlock (twin_pixmap_t *pixmap) twin_screen_unlock (pixmap->screen); } +static twin_argb32_t +_twin_pixmap_fetch (twin_pixmap_t *pixmap, twin_coord_t x, twin_coord_t y) +{ + twin_pointer_t p = twin_pixmap_pointer (pixmap, x - pixmap->x, y - pixmap->y); + + if (pixmap->x <= x && x < pixmap->x + pixmap->width && + pixmap->y <= y && y < pixmap->y + pixmap->height) + { + switch (pixmap->format) { + case TWIN_A8: + return *p.a8 << 24; + case TWIN_RGB16: + return twin_rgb16_to_argb32 (*p.rgb16); + case TWIN_ARGB32: + return *p.argb32; + } + } + return 0; +} + +twin_bool_t +twin_pixmap_transparent (twin_pixmap_t *pixmap, twin_coord_t x, twin_coord_t y) +{ + return (_twin_pixmap_fetch (pixmap, x, y) >> 24) == 0; +} + void twin_pixmap_move (twin_pixmap_t *pixmap, twin_coord_t x, twin_coord_t y) { + twin_pixmap_lock (pixmap); twin_pixmap_damage (pixmap, 0, 0, pixmap->width, pixmap->height); pixmap->x = x; pixmap->y = y; twin_pixmap_damage (pixmap, 0, 0, pixmap->width, pixmap->height); + twin_pixmap_unlock (pixmap); } + +twin_bool_t +twin_pixmap_dispatch (twin_pixmap_t *pixmap, twin_event_t *event) +{ + if (pixmap->window) + return twin_window_dispatch (pixmap->window, event); + return TWIN_FALSE; +} + diff --git a/twin_screen.c b/twin_screen.c index 1821cc6..bb031e3 100644 --- a/twin_screen.c +++ b/twin_screen.c @@ -34,6 +34,7 @@ twin_screen_create (twin_coord_t width, twin_screen_t *screen = malloc (sizeof (twin_screen_t)); if (!screen) return 0; + screen->top = 0; screen->bottom = 0; screen->width = width; screen->height = height; @@ -42,29 +43,25 @@ twin_screen_create (twin_coord_t width, screen->damaged = NULL; screen->damaged_closure = NULL; screen->disable = 0; -#if HAVE_PTHREAD_H - pthread_mutex_init (&screen->screen_mutex, NULL); -#endif + twin_mutex_init (&screen->screen_mutex); screen->put_begin = put_begin; screen->put_span = put_span; screen->closure = closure; + + screen->button_x = screen->button_y = -1; return screen; } void twin_screen_lock (twin_screen_t *screen) { -#if HAVE_PTHREAD_H - pthread_mutex_lock (&screen->screen_mutex); -#endif + twin_mutex_lock (&screen->screen_mutex); } void twin_screen_unlock (twin_screen_t *screen) { -#if HAVE_PTHREAD_H - pthread_mutex_unlock (&screen->screen_mutex); -#endif + twin_mutex_unlock (&screen->screen_mutex); } void @@ -104,6 +101,8 @@ twin_screen_disable_update (twin_screen_t *screen) screen->disable++; } +#include <stdio.h> + void twin_screen_damage (twin_screen_t *screen, twin_coord_t left, twin_coord_t top, @@ -150,59 +149,128 @@ twin_screen_damaged (twin_screen_t *screen) void twin_screen_update (twin_screen_t *screen) { - if (!screen->disable && - screen->damage.left < screen->damage.right && - screen->damage.top < screen->damage.bottom) + twin_coord_t left = screen->damage.left; + twin_coord_t top = screen->damage.top; + twin_coord_t right = screen->damage.right; + twin_coord_t bottom = screen->damage.bottom; + + if (!screen->disable && left < right && top < bottom) { - twin_coord_t x = screen->damage.left; - twin_coord_t y = screen->damage.top; - twin_coord_t width = screen->damage.right - screen->damage.left; - twin_coord_t height = screen->damage.bottom - screen->damage.top; twin_argb32_t *span; twin_pixmap_t *p; + twin_coord_t y; + twin_coord_t width = right - left; + screen->damage.left = screen->damage.right = 0; + screen->damage.top = screen->damage.bottom = 0; /* XXX what is the maximum number of lines? */ span = malloc (width * sizeof (twin_argb32_t)); if (!span) return; if (screen->put_begin) - (*screen->put_begin) (x, y, width, height, screen->closure); - while (height--) + (*screen->put_begin) (left, top, right, bottom, screen->closure); + for (y = top; y < bottom; y++) { memset (span, 0xff, width * sizeof (twin_argb32_t)); - for (p = screen->bottom; p; p = p->higher) + for (p = screen->bottom; p; p = p->up) { twin_pointer_t dst; twin_source_u src; - - int left, right; + twin_coord_t p_left, p_right; + /* bounds check in y */ if (y < p->y) continue; if (p->y + p->height <= y) continue; /* bounds check in x*/ - left = x; - if (left < p->x) - left = p->x; - right = x + width; - if (right > p->x + p->width) - right = p->x + p->width; - if (left >= right) + p_left = left; + if (p_left < p->x) + p_left = p->x; + p_right = right; + if (p_right > p->x + p->width) + p_right = p->x + p->width; + if (p_left >= p_right) continue; - dst.argb32 = span + (left - x); - src.p = twin_pixmap_pointer (p, left - p->x, y - p->y); + dst.argb32 = span + (p_left - left); + src.p = twin_pixmap_pointer (p, p_left - p->x, y - p->y); if (p->format == TWIN_RGB16) - _twin_rgb16_source_argb32 (dst, src, right - left); + _twin_rgb16_source_argb32 (dst, src, p_right - p_left); else - _twin_argb32_over_argb32 (dst, src, right - left); + _twin_argb32_over_argb32 (dst, src, p_right - p_left); } - (*screen->put_span) (x, y, width, span, screen->closure); - y++; + (*screen->put_span) (left, y, right, span, screen->closure); } free (span); - screen->damage.left = screen->damage.right = 0; - screen->damage.top = screen->damage.bottom = 0; } } + +void +twin_screen_set_active (twin_screen_t *screen, twin_pixmap_t *pixmap) +{ + twin_event_t ev; + twin_pixmap_t *old = screen->active; + screen->active = pixmap; + if (old) + { + ev.kind = EventDeactivate; + twin_pixmap_dispatch (old, &ev); + } + if (pixmap) + { + ev.kind = EventActivate; + twin_pixmap_dispatch (pixmap, &ev); + } +} + +twin_pixmap_t * +twin_screen_get_active (twin_screen_t *screen) +{ + return screen->active; +} + +twin_bool_t +twin_screen_dispatch (twin_screen_t *screen, + twin_event_t *event) +{ + twin_pixmap_t *pixmap; + + switch (event->kind) { + case EventMotion: + case EventButtonDown: + case EventButtonUp: + pixmap = screen->pointer; + if (!pixmap) + { + for (pixmap = screen->top; pixmap; pixmap = pixmap->down) + if (!twin_pixmap_transparent (pixmap, + event->u.pointer.screen_x, + event->u.pointer.screen_y)) + { + break; + } + if (event->kind == EventButtonDown) + screen->pointer = pixmap; + } + if (event->kind == EventButtonUp) + screen->pointer = NULL; + if (pixmap) + { + event->u.pointer.x = event->u.pointer.screen_x - pixmap->x; + event->u.pointer.y = event->u.pointer.screen_y - pixmap->y; + } + break; + case EventKeyDown: + case EventKeyUp: + case EventUcs4: + pixmap = screen->active; + break; + default: + pixmap = NULL; + break; + } + if (pixmap) + return twin_pixmap_dispatch (pixmap, event); + return TWIN_FALSE; +} diff --git a/twin_thread.c b/twin_thread.c new file mode 100644 index 0000000..1faddc0 --- /dev/null +++ b/twin_thread.c @@ -0,0 +1,83 @@ +/* + * $Id$ + * + * Copyright © 2004 Keith Packard + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of Keith Packard not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Keith Packard makes no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "twinint.h" + +void +twin_mutex_init (twin_mutex_t *mutex) +{ +#if HAVE_PTHREAD_H + pthread_mutex_init (mutex, NULL); +#endif +} + +void +twin_mutex_lock (twin_mutex_t *mutex) +{ +#if HAVE_PTHREAD_H + pthread_mutex_lock (mutex); +#endif +} + +void +twin_mutex_unlock (twin_mutex_t *mutex) +{ +#if HAVE_PTHREAD_H + pthread_mutex_unlock (mutex); +#endif +} + +void +twin_cond_init (twin_cond_t *cond) +{ +#if HAVE_PTHREAD_H + pthread_cond_init (cond, NULL); +#endif +} + +void +twin_cond_broadcast (twin_cond_t *cond) +{ +#if HAVE_PTHREAD_H + pthread_cond_broadcast (cond); +#else + OOPS - need some synchronization mechanism +#endif +} + +void +twin_cond_wait (twin_cond_t *cond, twin_mutex_t *mutex) +{ +#if HAVE_PTHREAD_H + pthread_cond_wait (cond, mutex); +#else + OOPS - need some synchronization mechanism +#endif +} + +int +twin_thread_create (twin_thread_t *thread, twin_thread_func_t func, void *arg) +{ + return pthread_create (thread, NULL, func, arg); +} diff --git a/twin_window.c b/twin_window.c new file mode 100644 index 0000000..6071877 --- /dev/null +++ b/twin_window.c @@ -0,0 +1,251 @@ +/* + * $Id$ + * + * Copyright © 2004 Keith Packard + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of Keith Packard not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Keith Packard makes no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "twinint.h" + +#define TWIN_ACTIVE_BG 0xff3b80ae +#define TWIN_INACTIVE_BG 0xff808080 +#define TWIN_FRAME_TEXT 0xffffffff +#define TWIN_ACTIVE_BORDER 0xff000000 +#define TWIN_BW 3 +#define TWIN_TITLE_HEIGHT 18 + +twin_window_t * +twin_window_create (twin_screen_t *screen, + twin_format_t format, + twin_window_style_t style, + twin_coord_t x, + twin_coord_t y, + twin_coord_t width, + twin_coord_t height) +{ + twin_window_t *window = malloc (sizeof (twin_window_t)); + + if (!window) return NULL; + window->screen = screen; + window->pixmap = twin_pixmap_create (format, width, height); + window->pixmap->window = window; + twin_pixmap_move (window->pixmap, x, y); + window->style = style; + window->client.left = TWIN_BW; + window->client.top = TWIN_BW + TWIN_TITLE_HEIGHT + TWIN_BW; + window->client.right = width - TWIN_BW; + window->client.bottom = height - TWIN_BW; + window->damage.left = window->damage.right = 0; + window->damage.top = window->damage.bottom = 0; + window->client_data = 0; + window->name = 0; + + window->draw = 0; + window->event = 0; + window->destroy = 0; + return window; +} + +void +twin_window_destroy (twin_window_t *window) +{ + twin_window_hide (window); + twin_pixmap_destroy (window->pixmap); + if (window->name) free (window->name); + free (window); +} + +void +twin_window_show (twin_window_t *window) +{ + if (window->pixmap != window->screen->top) + twin_pixmap_show (window->pixmap, window->screen, window->screen->top); +} + +void +twin_window_hide (twin_window_t *window) +{ + twin_pixmap_hide (window->pixmap); +} + +void +twin_window_configure (twin_window_t *window, + twin_window_style_t style, + twin_coord_t x, + twin_coord_t y, + twin_coord_t width, + twin_coord_t height) +{ + twin_bool_t need_repaint = TWIN_FALSE; + + twin_pixmap_disable_update (window->pixmap); + if (style != window->style) + { + window->style = style; + need_repaint = TWIN_TRUE; + } + if (width != window->pixmap->width || height != window->pixmap->height) + { + twin_pixmap_t *old = window->pixmap; + int i; + + window->pixmap = twin_pixmap_create (old->format, width, height); + window->pixmap->window = window; + twin_pixmap_move (window->pixmap, x, y); + if (old->screen) + twin_pixmap_show (window->pixmap, window->screen, old); + for (i = 0; i < old->disable; i++) + twin_pixmap_disable_update (window->pixmap); + twin_pixmap_destroy (old); + } + if (x != window->pixmap->x || y != window->pixmap->y) + twin_pixmap_move (window->pixmap, x, y); + if (need_repaint) + twin_window_draw (window); + twin_pixmap_enable_update (window->pixmap); +} + +void +twin_window_style_size (twin_window_style_t style, + twin_rect_t *size) +{ + switch (style) { + case WindowPlain: + size->left = size->right = size->top = size->bottom = 0; + break; + case WindowApplication: + size->left = TWIN_BW; + size->right = TWIN_BW; + size->top = TWIN_BW + TWIN_TITLE_HEIGHT + TWIN_BW; + size->bottom = TWIN_BW; + break; + } +} + +void +twin_window_set_name (twin_window_t *window, + const char *name) +{ + if (window->name) free (window->name); + window->name = malloc (strlen (name) + 1); + if (window->name) strcpy (window->name, name); + twin_window_draw (window); +} + +static void +twin_window_frame (twin_window_t *window) +{ + twin_coord_t bw = window->client.left; + twin_path_t *path; + twin_coord_t name_height; + twin_text_metrics_t m; + twin_pixmap_t *pixmap = window->pixmap; + + /* border */ + + twin_fill (pixmap, TWIN_ACTIVE_BORDER, + TWIN_SOURCE, + 0, 0, pixmap->width, bw); + twin_fill (pixmap, TWIN_ACTIVE_BORDER, + TWIN_SOURCE, + 0, bw, bw, pixmap->height - bw); + twin_fill (pixmap, TWIN_ACTIVE_BORDER, + TWIN_SOURCE, + window->client.right, bw, pixmap->width, pixmap->height - bw); + twin_fill (pixmap, TWIN_ACTIVE_BORDER, + TWIN_SOURCE, + window->client.left, window->client.top - bw, + window->client.right, window->client.top); + twin_fill (pixmap, TWIN_ACTIVE_BORDER, + TWIN_SOURCE, + 0, window->client.bottom, + pixmap->width, pixmap->height); + + /* name background */ + twin_fill (pixmap, TWIN_ACTIVE_BG, + TWIN_SOURCE, + bw, bw, pixmap->width - bw, window->client.top - bw); + + /* name */ + if (window->name) + { + path = twin_path_create (); + name_height = window->client.top - bw * 4; + if (name_height < 1) + name_height = 1; + twin_path_translate (path, twin_int_to_fixed (bw*2), + twin_int_to_fixed (bw*2)); + twin_path_set_font_size (path, twin_int_to_fixed (name_height)); + twin_path_set_font_style (path, TWIN_TEXT_OBLIQUE); + twin_text_metrics_utf8 (path, window->name, &m); + twin_path_move (path, 0, m.font_ascent); + twin_path_utf8 (path, window->name); + twin_paint_path (pixmap, TWIN_FRAME_TEXT, path); + twin_path_destroy (path); + } +} + +void +twin_window_draw (twin_window_t *window) +{ + switch (window->style) { + case WindowPlain: + break; + case WindowApplication: + twin_window_frame (window); + break; + } + if (window->draw) + (*window->draw) (window); +} + +twin_bool_t +twin_window_dispatch (twin_window_t *window, twin_event_t *event) +{ + if (window->event && (*window->event) (window, event)) + return TWIN_TRUE; + switch (event->kind) { + case EventButtonDown: + twin_window_show (window); + window->screen->button_x = event->u.pointer.x; + window->screen->button_y = event->u.pointer.y; + return TWIN_TRUE; + case EventButtonUp: + window->screen->button_x = -1; + window->screen->button_y = -1; + case EventMotion: + if (window->screen->button_x >= 0) + { + twin_coord_t x, y; + + x = event->u.pointer.screen_x - window->screen->button_x; + y = event->u.pointer.screen_y - window->screen->button_y; + twin_window_configure (window, + window->style, + x, y, + window->pixmap->width, + window->pixmap->height); + } + return TWIN_TRUE; + default: + break; + } + return TWIN_FALSE; +} @@ -26,15 +26,17 @@ #include "twinint.h" static void -_twin_x11_put_begin (twin_coord_t x, - twin_coord_t y, - twin_coord_t width, - twin_coord_t height, +_twin_x11_put_begin (twin_coord_t left, + twin_coord_t top, + twin_coord_t right, + twin_coord_t bottom, void *closure) { - twin_x11_t *tx = closure; + twin_x11_t *tx = closure; + twin_coord_t width = right - left; + twin_coord_t height = bottom - top; - tx->iy = 0; + tx->image_y = top; tx->image = XCreateImage (tx->dpy, tx->visual, tx->depth, ZPixmap, 0, 0, width, height, 32, 0); if (tx->image) @@ -49,33 +51,32 @@ _twin_x11_put_begin (twin_coord_t x, } static void -_twin_x11_put_span (twin_coord_t x, - twin_coord_t y, - twin_coord_t width, +_twin_x11_put_span (twin_coord_t left, + twin_coord_t top, + twin_coord_t right, twin_argb32_t *pixels, void *closure) { - twin_x11_t *tx = closure; - twin_coord_t ix = 0; - twin_coord_t iw = width; + twin_x11_t *tx = closure; + twin_coord_t width = right - left; + twin_coord_t ix; + twin_coord_t iy = top - tx->image_y; if (!tx->image) return; - while (iw--) + for (ix = 0; ix < width; ix++) { twin_argb32_t pixel = *pixels++; if (tx->depth == 16) pixel = twin_argb32_to_rgb16 (pixel); - XPutPixel (tx->image, ix, tx->iy, pixel); - ix++; + XPutPixel (tx->image, ix, iy, pixel); } - tx->iy++; - if (tx->iy == tx->image->height) + if ((top + 1 - tx->image_y) == tx->image->height) { XPutImage (tx->dpy, tx->win, tx->gc, tx->image, 0, 0, - x, (y + 1) - tx->iy, width, tx->image->height); + left, tx->image_y, tx->image->width, tx->image->height); XDestroyImage (tx->image); tx->image = 0; } @@ -86,10 +87,10 @@ twin_x11_damage_thread (void *arg) { twin_x11_t *tx = arg; - pthread_mutex_lock (&tx->screen->screen_mutex); + twin_mutex_lock (&tx->screen->screen_mutex); for (;;) { - pthread_cond_wait (&tx->damage_cond, &tx->screen->screen_mutex); + twin_cond_wait (&tx->damage_cond, &tx->screen->screen_mutex); if (!tx->win) break; if (twin_screen_damaged (tx->screen)) @@ -98,15 +99,16 @@ twin_x11_damage_thread (void *arg) XFlush (tx->dpy); } } - pthread_mutex_unlock (&tx->screen->screen_mutex); + twin_mutex_unlock (&tx->screen->screen_mutex); return 0; } static void * twin_x11_event_thread (void *arg) { - twin_x11_t *tx = arg; - XEvent ev; + twin_x11_t *tx = arg; + XEvent ev; + twin_event_t tev; for (;;) { @@ -117,6 +119,21 @@ twin_x11_event_thread (void *arg) break; case DestroyNotify: return 0; + case ButtonPress: + case ButtonRelease: + tev.u.pointer.screen_x = ev.xbutton.x; + tev.u.pointer.screen_y = ev.xbutton.y; + tev.kind = ((ev.type == ButtonPress) ? + EventButtonDown : EventButtonUp); + twin_screen_dispatch (tx->screen, &tev); + break; + case MotionNotify: + tev.u.pointer.screen_x = ev.xmotion.x; + tev.u.pointer.screen_y = ev.xmotion.y; + tev.kind = EventMotion; + tev.u.pointer.button = ev.xmotion.state; + twin_screen_dispatch (tx->screen, &tev); + break; } } } @@ -126,7 +143,7 @@ twin_x11_screen_damaged (void *closure) { twin_x11_t *tx = closure; - pthread_cond_broadcast (&tx->damage_cond); + twin_cond_broadcast (&tx->damage_cond); } twin_x11_t * @@ -187,11 +204,11 @@ twin_x11_create (Display *dpy, int width, int height) XMapWindow (dpy, tx->win); - pthread_cond_init (&tx->damage_cond, NULL); + twin_cond_init (&tx->damage_cond); - pthread_create (&tx->damage_thread, NULL, twin_x11_damage_thread, tx); + twin_thread_create (&tx->damage_thread, twin_x11_damage_thread, tx); - pthread_create (&tx->event_thread, NULL, twin_x11_event_thread, tx); + twin_thread_create (&tx->event_thread, twin_x11_event_thread, tx); return tx; } @@ -201,7 +218,7 @@ twin_x11_destroy (twin_x11_t *tx) { XDestroyWindow (tx->dpy, tx->win); tx->win = 0; - pthread_cond_broadcast (&tx->damage_cond); + twin_cond_broadcast (&tx->damage_cond); twin_screen_destroy (tx->screen); } @@ -29,7 +29,6 @@ #include <X11/Xlib.h> #include <X11/Xutil.h> #include <X11/Xatom.h> -#include <pthread.h> typedef struct _twin_x11 { twin_screen_t *screen; @@ -38,11 +37,11 @@ typedef struct _twin_x11 { GC gc; Visual *visual; int depth; - pthread_t damage_thread; - pthread_cond_t damage_cond; - pthread_t event_thread; + twin_thread_t damage_thread; + twin_cond_t damage_cond; + twin_thread_t event_thread; XImage *image; - int iy; + int image_y; } twin_x11_t; /* @@ -48,24 +48,28 @@ #define TWIN_CLOCK_BORDER_WIDTH D(0.01) static void -twin_clock_set_transform (twin_pixmap_t *clock, +twin_clock_set_transform (twin_window_t *clock, twin_path_t *path) { twin_fixed_t scale; - scale = D(1) / 2; - scale = twin_fixed_mul (scale, TWIN_FIXED_ONE - TWIN_CLOCK_BORDER_WIDTH * 3); + scale = (TWIN_FIXED_ONE - TWIN_CLOCK_BORDER_WIDTH * 3) / 2; + twin_path_translate (path, + twin_int_to_fixed (clock->client.left), + twin_int_to_fixed (clock->client.top)); twin_path_scale (path, - clock->width * scale, - clock->height * scale); + (clock->client.right - clock->client.left) * scale, + (clock->client.bottom - clock->client.top) * scale); - twin_path_translate (path, D(1) + TWIN_CLOCK_BORDER_WIDTH * 3, - D(1) + TWIN_CLOCK_BORDER_WIDTH * 3); + twin_path_translate (path, + TWIN_FIXED_ONE + TWIN_CLOCK_BORDER_WIDTH * 3, + TWIN_FIXED_ONE + TWIN_CLOCK_BORDER_WIDTH * 3); + twin_path_rotate (path, -TWIN_ANGLE_90); } static void -twin_clock_hand (twin_pixmap_t *clock, +twin_clock_hand (twin_window_t *clock, twin_angle_t angle, twin_fixed_t len, twin_fixed_t fill_width, @@ -92,9 +96,9 @@ twin_clock_hand (twin_pixmap_t *clock, twin_path_circle (pen, fill_width); twin_path_convolve (path, stroke, pen); - twin_paint_path (clock, fill_pixel, path); + twin_paint_path (clock->pixmap, fill_pixel, path); - twin_paint_stroke (clock, out_pixel, path, out_width); + twin_paint_stroke (clock->pixmap, out_pixel, path, out_width); twin_path_destroy (path); twin_path_destroy (pen); @@ -108,7 +112,7 @@ twin_clock_minute_angle (int min) } static void -twin_clock_face (twin_pixmap_t *clock) +twin_clock_face (twin_window_t *clock) { twin_path_t *path = twin_path_create (); int m; @@ -118,9 +122,9 @@ twin_clock_face (twin_pixmap_t *clock) twin_path_move (path, 0, 0); twin_path_circle (path, TWIN_FIXED_ONE); - twin_paint_path (clock, TWIN_CLOCK_BACKGROUND, path); + twin_paint_path (clock->pixmap, TWIN_CLOCK_BACKGROUND, path); - twin_paint_stroke (clock, TWIN_CLOCK_BORDER, path, TWIN_CLOCK_BORDER_WIDTH); + twin_paint_stroke (clock->pixmap, TWIN_CLOCK_BORDER, path, TWIN_CLOCK_BORDER_WIDTH); { twin_state_t state = twin_path_save (path); @@ -138,12 +142,12 @@ twin_clock_face (twin_pixmap_t *clock) twin_path_move (path, -width / 2, metrics.ascent - height/2 + D(0.01)); twin_path_draw (path, width / 2, metrics.ascent - height/2 + D(0.01)); - twin_paint_stroke (clock, TWIN_CLOCK_WATER_UNDER, path, D(0.02)); + twin_paint_stroke (clock->pixmap, TWIN_CLOCK_WATER_UNDER, path, D(0.02)); twin_path_empty (path); twin_path_move (path, -width / 2 - metrics.left_side_bearing, metrics.ascent - height/2); twin_path_utf8 (path, label); - twin_paint_path (clock, TWIN_CLOCK_WATER, path); + twin_paint_path (clock->pixmap, TWIN_CLOCK_WATER, path); twin_path_restore (path, &state); } @@ -159,7 +163,7 @@ twin_clock_face (twin_pixmap_t *clock) { twin_path_move (path, 0, -TWIN_FIXED_ONE); twin_path_draw (path, 0, -D(0.9)); - twin_paint_stroke (clock, TWIN_CLOCK_TIC, path, D(0.01)); + twin_paint_stroke (clock->pixmap, TWIN_CLOCK_TIC, path, D(0.01)); } else { @@ -174,7 +178,7 @@ twin_clock_face (twin_pixmap_t *clock) left = -width / 2 - metrics.left_side_bearing; twin_path_move (path, left, -D(0.98) + metrics.ascent); twin_path_utf8 (path, hour); - twin_paint_path (clock, TWIN_CLOCK_NUMBERS, path); + twin_paint_path (clock->pixmap, TWIN_CLOCK_NUMBERS, path); } twin_path_restore (path, &state); } @@ -185,21 +189,27 @@ twin_clock_face (twin_pixmap_t *clock) int nclock; static void -twin_clock (twin_screen_t *screen, int x, int y, int w, int h) +twin_clock (twin_screen_t *screen, const char *name, int x, int y, int w, int h) { - twin_pixmap_t *clock = twin_pixmap_create (TWIN_ARGB32, w, h); + twin_window_t *clock = twin_window_create (screen, TWIN_ARGB32, + WindowApplication, + x, y, w, h); struct timeval tv; struct tm t; twin_angle_t hour_angle, minute_angle, second_angle; - twin_pixmap_move (clock, x, y); - twin_pixmap_show (clock, screen, 0); + twin_window_set_name (clock, name); + twin_window_show (clock); for (;;) { - twin_pixmap_disable_update (clock); - twin_fill (clock, 0x00000000, TWIN_SOURCE, 0, 0, - clock->width, clock->height); + twin_pixmap_disable_update (clock->pixmap); + twin_window_draw (clock); + twin_fill (clock->pixmap, 0x00000000, TWIN_SOURCE, + clock->client.left, clock->client.top, + clock->client.right, clock->client.bottom); + + twin_clock_face (clock); gettimeofday (&tv, NULL); @@ -209,7 +219,6 @@ twin_clock (twin_screen_t *screen, int x, int y, int w, int h) TWIN_ANGLE_360) / 6000; minute_angle = twin_clock_minute_angle (t.tm_min) + second_angle / 60; hour_angle = (t.tm_hour * TWIN_ANGLE_360 + minute_angle) / 12; - twin_clock_face (clock); twin_clock_hand (clock, hour_angle, D(0.4), D(0.07), D(0.01), TWIN_CLOCK_HOUR, TWIN_CLOCK_HOUR_OUT); twin_clock_hand (clock, minute_angle, D(0.8), D(0.05), D(0.01), @@ -217,7 +226,7 @@ twin_clock (twin_screen_t *screen, int x, int y, int w, int h) twin_clock_hand (clock, second_angle, D(0.9), D(0.01), D(0.01), TWIN_CLOCK_SECOND, TWIN_CLOCK_SECOND_OUT); - twin_pixmap_enable_update (clock); + twin_pixmap_enable_update (clock->pixmap); gettimeofday (&tv, NULL); @@ -228,12 +237,13 @@ twin_clock (twin_screen_t *screen, int x, int y, int w, int h) nclock--; } -typedef void (*twin_app_func_t) (twin_screen_t *screen, +typedef void (*twin_app_func_t) (twin_screen_t *screen, const char *name, int x, int y, int w, int h); typedef struct _twin_app_args { twin_app_func_t func; twin_screen_t *screen; + char *name; int x, y, w, h; } twin_app_args_t; @@ -242,7 +252,7 @@ twin_app_thread (void *closure) { twin_app_args_t *a = closure; - (*a->func) (a->screen, a->x, a->y, a->w, a->h); + (*a->func) (a->screen, a->name, a->x, a->y, a->w, a->h); free (a); return 0; } @@ -250,25 +260,28 @@ twin_app_thread (void *closure) static void twin_start_app (twin_app_func_t func, twin_screen_t *screen, + const char *name, int x, int y, int w, int h) { - twin_app_args_t *a = malloc (sizeof (twin_app_args_t)); + twin_app_args_t *a = malloc (sizeof (twin_app_args_t) + strlen (name) + 1); pthread_t thread; a->func = func; a->screen = screen; + a->name = (char *) (a + 1); a->x = x; a->y = y; a->w = w; a->h = h; + strcpy (a->name, name); pthread_create (&thread, NULL, twin_app_thread, a); } static void -twin_start_clock (twin_screen_t *screen, int x, int y, int w, int h) +twin_start_clock (twin_screen_t *screen, const char *name, int x, int y, int w, int h) { ++nclock; - twin_start_app (twin_clock, screen, x, y, w, h); + twin_start_app (twin_clock, screen, name, x, y, w, h); } int styles[] = { @@ -328,9 +341,6 @@ main (int argc, char **argv) pen = twin_path_create (); twin_path_circle (pen, D (1)); - twin_fill (red, 0x00000000, TWIN_SOURCE, 0, 0, WIDTH, HEIGHT); - twin_fill (alpha, 0x00000000, TWIN_SOURCE, 0, 0, WIDTH, HEIGHT); - path = twin_path_create (); #if 0 twin_path_move (path, D(3), D(0)); @@ -494,8 +504,6 @@ main (int argc, char **argv) twin_composite (red, 0, 0, &source, 0, 0, &mask, 0, 0, TWIN_OVER, WIDTH, HEIGHT); - twin_fill (blue, 0x00000000, TWIN_SOURCE, 0, 0, 100, 100); - #if 0 path = twin_path_create (); @@ -636,12 +644,14 @@ main (int argc, char **argv) #endif if (!nclock) - twin_start_clock (x11->screen, 0, 0, WIDTH, HEIGHT); + twin_start_clock (x11->screen, "small clock", 10, 10, 200, 200); +#if 1 + twin_start_clock (x11->screen, "ul clock", 0, 0, 256, 256); +#endif #if 0 - twin_start_clock (x11->screen, 0, 0, 256, 256); - twin_start_clock (x11->screen, 256, 0, 256, 256); - twin_start_clock (x11->screen, 0, 256, 256, 256); - twin_start_clock (x11->screen, 256, 256, 256, 256); + twin_start_clock (x11->screen, "ur clock", 256, 0, 256, 256); + twin_start_clock (x11->screen, "ll clock", 0, 256, 256, 256); + twin_start_clock (x11->screen, "lr clock", 256, 256, 256, 256); #endif while (nclock) sleep (1); |