diff options
author | Keith Packard <keithp@keithp.com> | 2004-09-30 17:23:07 +0000 |
---|---|---|
committer | Keith Packard <keithp@keithp.com> | 2004-09-30 17:23:07 +0000 |
commit | 531d39cc7ae4333856661395b0d62f8f7b62c003 (patch) | |
tree | 16c51f9a3cbe10448076b9491a807c08b4efb0a1 | |
parent | c3b1b799fe346ef7211ba614bf6c44396e411590 (diff) |
Handle unhinted text.
Add helper functions
Lock pixmaps during drawing
Disable screen updates while applications are busy
Add threads to manage events and redisplay
Paint a clock
-rw-r--r-- | ChangeLog | 37 | ||||
-rw-r--r-- | Makefile.am | 1 | ||||
-rw-r--r-- | configure.ac | 36 | ||||
-rw-r--r-- | twin.h | 103 | ||||
-rw-r--r-- | twin_draw.c | 6 | ||||
-rw-r--r-- | twin_font.c | 152 | ||||
-rw-r--r-- | twin_path.c | 109 | ||||
-rw-r--r-- | twin_pixmap.c | 47 | ||||
-rw-r--r-- | twin_poly.c | 47 | ||||
-rw-r--r-- | twin_screen.c | 56 | ||||
-rw-r--r-- | twin_x11.c | 65 | ||||
-rw-r--r-- | twinint.h | 23 | ||||
-rw-r--r-- | xtwin.c | 147 |
13 files changed, 674 insertions, 155 deletions
@@ -1,3 +1,40 @@ +2004-09-30 Keith Packard <keithp@keithp.com> + + * Makefile.am: + * configure.ac: + * twin.h: + * twin_draw.c: (twin_composite), (twin_fill): + * twin_font.c: (_snap), (_twin_pen_size), (twin_text_metrics_ucs4), + (twin_path_ucs4), (twin_width_utf8): + Handle unhinted text. + + * twin_path.c: (twin_path_close), (twin_path_bounds), + (twin_composite_path), (twin_paint_path), (twin_composite_stroke), + (twin_paint_stroke): + Add helper functions + + * twin_pixmap.c: (twin_pixmap_create), (twin_pixmap_show), + (twin_pixmap_hide), (twin_pixmap_enable_update), + (twin_pixmap_disable_update), (twin_pixmap_lock), + (twin_pixmap_unlock): + Lock pixmaps during drawing + + * twin_poly.c: (_twin_edge_build), (twin_fill_path): + * twin_screen.c: (twin_screen_create), (twin_screen_lock), + (twin_screen_unlock), (twin_screen_register_damaged), + (twin_screen_enable_update), (twin_screen_disable_update), + (twin_screen_damage), (twin_screen_update): + Disable screen updates while applications are busy + + * twin_x11.c: (twin_x11_damage_thread), (twin_x11_event_thread), + (twin_x11_screen_damaged), (twin_x11_create), (twin_x11_destroy): + Add threads to manage events and redisplay + + * twinint.h: + * xtwin.c: (twin_clock_hand), (twin_clock_minute_angle), + (twin_clock_face), (twin_clock), (main): + Paint a clock + 2004-09-27 Keith Packard <keithp@keithp.com> * twin.h: diff --git a/Makefile.am b/Makefile.am index 31bdb92..4b7f8d7 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,6 +1,5 @@ CFLAGS=-g INCLUDES= @X_CFLAGS@ @WARN_CFLAGS@ -SUBDIRS=twin_ttf #libtwin_la_SOURCES = \ # twin.h \ diff --git a/configure.ac b/configure.ac index d0f7d57..ebe9981 100644 --- a/configure.ac +++ b/configure.ac @@ -29,7 +29,7 @@ AC_INIT(libtwin, 0.0.0, [keithp@keithp.com], libtwin) AM_INIT_AUTOMAKE() AM_MAINTAINER_MODE -AM_CONFIG_HEADER(config.h) +AM_CONFIG_HEADER(twin_def.h) AC_CONFIG_AUX_DIR(.) # Check for progs @@ -52,23 +52,27 @@ PKG_CHECK_MODULES(X, x11, AC_SUBST(X_CFLAGS) AC_SUBST(X_LIBS) -AC_ARG_WITH(freetype-config, [ --with-freetype-config=PROG Use FreeType configuration program PROG], freetype_config=$withval, freetype_config=yes) +AC_CHECK_LIB([pthread], [pthread_create]) -if test "$freetype_config" = "yes"; then - AC_PATH_PROG(ft_config,freetype-config,no) - if test "$ft_config" = "no"; then - AC_MSG_ERROR([You must have freetype installed; see http://www.freetype.org/]) - fi -else - ft_config="$freetype_config" -fi - -FREETYPE_CFLAGS="`$ft_config --cflags`" -FREETYPE_LIBS="`$ft_config --libs`" +AC_CHECK_HEADERS([pthread.h]) -AC_SUBST(FREETYPE_LIBS) -AC_SUBST(FREETYPE_CFLAGS) +# +#AC_ARG_WITH(freetype-config, [ --with-freetype-config=PROG Use FreeType configuration program PROG], freetype_config=$withval, freetype_config=yes) +# +#if test "$freetype_config" = "yes"; then +# AC_PATH_PROG(ft_config,freetype-config,no) +# if test "$ft_config" = "no"; then +# AC_MSG_ERROR([You must have freetype installed; see http://www.freetype.org/]) +# fi +#else +# ft_config="$freetype_config" +#fi +# +#FREETYPE_CFLAGS="`$ft_config --cflags`" +#FREETYPE_LIBS="`$ft_config --libs`" +# +#AC_SUBST(FREETYPE_LIBS) +#AC_SUBST(FREETYPE_CFLAGS) AC_OUTPUT([Makefile - twin_ttf/Makefile twin.pc]) @@ -27,6 +27,10 @@ #include <stdlib.h> #include <stdint.h> +#include <twin_def.h> +#if HAVE_PTHREAD_H +#include <pthread.h> +#endif typedef uint8_t twin_a8_t; typedef uint16_t twin_a16_t; @@ -79,6 +83,7 @@ typedef struct _twin_pixmap { * Screen showing these pixels */ struct _twin_screen *screen; + int disable; /* * List of displayed pixmaps */ @@ -125,6 +130,12 @@ typedef struct _twin_screen { * Damage */ twin_rect_t damage; + void (*damaged) (void *); + void *damaged_closure; + int disable; +#if HAVE_PTHREAD_H + pthread_mutex_t screen_mutex; +#endif /* * Repaint function */ @@ -314,6 +325,9 @@ void twin_path_empty (twin_path_t *path); void +twin_path_bounds (twin_path_t *path, twin_rect_t *rect); + +void twin_path_append (twin_path_t *dst, twin_path_t *src); twin_path_t * @@ -358,6 +372,33 @@ twin_path_save (twin_path_t *path); void twin_path_restore (twin_path_t *path, twin_state_t *state); +void +twin_composite_path (twin_pixmap_t *dst, + twin_operand_t *src, + int src_x, + int src_y, + twin_path_t *path, + twin_operator_t operator); +void +twin_paint_path (twin_pixmap_t *dst, + twin_argb32_t argb, + twin_path_t *path); + +void +twin_composite_stroke (twin_pixmap_t *dst, + twin_operand_t *src, + int src_x, + int src_y, + twin_path_t *stroke, + twin_fixed_t pen_width, + twin_operator_t operator); + +void +twin_paint_stroke (twin_pixmap_t *dst, + twin_argb32_t argb, + twin_path_t *stroke, + twin_fixed_t pen_width); + /* * twin_pixmap.c */ @@ -377,10 +418,22 @@ void twin_pixmap_hide (twin_pixmap_t *pixmap); void +twin_pixmap_enable_update (twin_pixmap_t *pixmap); + +void +twin_pixmap_disable_update (twin_pixmap_t *pixmap); + +void twin_pixmap_damage (twin_pixmap_t *pixmap, int x1, int y1, int x2, int y2); void +twin_pixmap_lock (twin_pixmap_t *pixmap); + +void +twin_pixmap_unlock (twin_pixmap_t *pixmap); + +void twin_pixmap_move (twin_pixmap_t *pixmap, int x, int y); twin_pointer_t @@ -390,7 +443,7 @@ twin_pixmap_pointer (twin_pixmap_t *pixmap, int x, int y); * twin_poly.c */ void -twin_fill_path (twin_pixmap_t *pixmap, twin_path_t *path); +twin_fill_path (twin_pixmap_t *pixmap, twin_path_t *path, int dx, int dy); /* * twin_screen.c @@ -406,10 +459,21 @@ void twin_screen_destroy (twin_screen_t *screen); void +twin_screen_enable_update (twin_screen_t *screen); + +void +twin_screen_disable_update (twin_screen_t *screen); + +void twin_screen_damage (twin_screen_t *screen, int x1, int y1, int x2, int y2); void +twin_screen_register_damaged (twin_screen_t *screen, + void (*damaged) (void *), + void *closure); + +void twin_screen_resize (twin_screen_t *screen, int width, int height); twin_bool_t @@ -418,6 +482,13 @@ twin_screen_damaged (twin_screen_t *screen); void twin_screen_update (twin_screen_t *screen); +void +twin_screen_lock (twin_screen_t *screen); + +void +twin_screen_unlock (twin_screen_t *screen); + + /* * twin_spline.c */ @@ -441,34 +512,4 @@ twin_cos (twin_angle_t a); twin_fixed_t twin_tan (twin_angle_t a); -/* - * twin_x11.c - */ - -#include <X11/Xlib.h> - -typedef struct _twin_x11 { - twin_screen_t *screen; - Display *dpy; - Window win; - GC gc; - Visual *visual; - int depth; -} twin_x11_t; - -twin_x11_t * -twin_x11_create (Display *dpy, int width, int height); - -void -twin_x11_destroy (twin_x11_t *tx); - -void -twin_x11_damage (twin_x11_t *tx, XExposeEvent *ev); - -void -twin_x11_configure (twin_x11_t *tx, XConfigureEvent *ev); - -void -twin_x11_update (twin_x11_t *tx); - #endif /* _TWIN_H_ */ diff --git a/twin_draw.c b/twin_draw.c index 00485a4..ee634da 100644 --- a/twin_draw.c +++ b/twin_draw.c @@ -256,6 +256,7 @@ static twin_src_msk_op comp3[2][4][4][3] = { } }; + #define operand_index(o) ((o)->source_kind == TWIN_SOLID ? 3 : o->u.pixmap->format) void @@ -275,6 +276,7 @@ twin_composite (twin_pixmap_t *dst, int iy; int left, right, top, bottom; + twin_pixmap_lock (dst); if (msk) { twin_src_msk_op op; @@ -353,6 +355,8 @@ twin_composite (twin_pixmap_t *dst, s, right - left); } } + twin_pixmap_damage (dst, left, top, right, bottom); + twin_pixmap_unlock (dst); } /* @@ -386,6 +390,7 @@ twin_fill (twin_pixmap_t *dst, int iy; int left, right, top, bottom; + twin_pixmap_lock (dst); src.c = pixel; left = x; right = x + width; @@ -402,4 +407,5 @@ twin_fill (twin_pixmap_t *dst, op = fill[operator][dst->format]; for (iy = top; iy < bottom; iy++) (*op) (twin_pixmap_pointer (dst, left, iy), src, right - left); + twin_pixmap_unlock (dst); } diff --git a/twin_font.c b/twin_font.c index 9309025..67d8ef2 100644 --- a/twin_font.c +++ b/twin_font.c @@ -38,6 +38,8 @@ #define ScaleX(x) Scale(x) #define ScaleY(y) Scale(y) +#define Hint(p) (((p)->state.font_style & TWIN_TEXT_UNHINTED) == 0) + twin_bool_t twin_has_ucs4 (twin_ucs4_t ucs4) { @@ -53,8 +55,8 @@ compare_snap (const void *av, const void *bv) return (int) (*a - *b); } -#define SNAPI(p) (((p) + 0x7fff) & ~0xffff) -#define SNAPH(p) (((p) + 0x3fff) & ~0x7fff) +#define SNAPI(path,p) (Hint(path) ? (((p) + 0x7fff) & ~0xffff) : (p)) +#define SNAPH(path,p) (Hint(path) ? (((p) + 0x3fff) & ~0x7fff) : (p)) static twin_fixed_t _snap (twin_path_t *path, twin_gfixed_t g, twin_gfixed_t *snap, int nsnap) @@ -70,8 +72,8 @@ _snap (twin_path_t *path, twin_gfixed_t g, twin_gfixed_t *snap, int nsnap) twin_fixed_t before = Scale(snap[s]); twin_fixed_t after = Scale(snap[s+1]); twin_fixed_t dist = after - before; - twin_fixed_t snap_before = SNAPI(before); - twin_fixed_t snap_after = SNAPI(after); + twin_fixed_t snap_before = SNAPI(path, before); + twin_fixed_t snap_after = SNAPI(path, after); twin_fixed_t move_before = snap_before - before; twin_fixed_t move_after = snap_after - after; twin_fixed_t dist_before = v - before; @@ -121,14 +123,14 @@ _twin_pen_size (twin_path_t *path) { twin_fixed_t pen_size; - pen_size = SNAPH(path->state.font_size / 24); - if (pen_size < TWIN_FIXED_HALF) + pen_size = SNAPH(path, path->state.font_size / 24); + if (Hint (path) && pen_size < TWIN_FIXED_HALF) pen_size = TWIN_FIXED_HALF; if (path->state.font_style & TWIN_TEXT_BOLD) { - twin_fixed_t pen_add = SNAPH(pen_size >> 1); - if (pen_add == 0) + twin_fixed_t pen_add = SNAPH(path, pen_size >> 1); + if (Hint (path) && pen_add == 0) pen_add = TWIN_FIXED_HALF; pen_size += pen_add; } @@ -145,7 +147,7 @@ twin_text_metrics_ucs4 (twin_path_t *path, twin_fixed_t left, right; twin_fixed_t top, bottom; twin_fixed_t pen_size = _twin_pen_size (path); - twin_fixed_t baseline = SNAPI(Scale(TWIN_FONT_BASELINE)); + twin_fixed_t baseline = SNAPI(path, Scale(TWIN_FONT_BASELINE)); int i; int skip_xi; int skip_yi; @@ -169,16 +171,16 @@ twin_text_metrics_ucs4 (twin_path_t *path, y = Scale (p[i].y); next_xi = skip_xi; next_yi = skip_yi; - if (p[i+1].y != -64 && p[i+1].x != -64) + if (Hint (path) && p[i+1].y != -64 && p[i+1].x != -64) { if (p[i].x == p[i+1].x) { - x = SNAPI(x); + x = SNAPI(path, x); skip_xi = i + 2; } if (p[i].y == p[i+1].y) { - y = SNAPI(y); + y = SNAPI(path, y); skip_yi = i + 2; } } @@ -208,13 +210,13 @@ twin_text_metrics_ucs4 (twin_path_t *path, right = Scale(p[0].y); } - m->left_side_bearing = SNAPI(-left); - m->right_side_bearing = SNAPI(right); + m->left_side_bearing = SNAPI(path, -left); + m->right_side_bearing = SNAPI(path,right); m->width = m->left_side_bearing + m->right_side_bearing; - m->ascent = baseline - SNAPI(top); - m->descent = SNAPI(bottom) - baseline; - m->font_descent = SNAPI(path->state.font_size / 3); - m->font_ascent = SNAPI(path->state.font_size) - m->font_descent; + m->ascent = baseline - SNAPI(path, top); + m->descent = SNAPI(path, bottom) - baseline; + m->font_descent = SNAPI(path, path->state.font_size / 3); + m->font_ascent = SNAPI(path,path->state.font_size) - m->font_descent; } void @@ -232,68 +234,74 @@ twin_path_ucs4 (twin_path_t *path, twin_ucs4_t ucs4) twin_fixed_t pen_size; twin_matrix_t pen_matrix; twin_fixed_t pen_adjust; - twin_gfixed_t *snap_x, *snap_y; + twin_gfixed_t *snap_x = 0, *snap_y = 0; twin_text_metrics_t metrics; - int nsnap_x, nsnap_y; + int nsnap_x = 0, nsnap_y = 0; int npoints; twin_text_metrics_ucs4 (path, ucs4, &metrics); origin = _twin_path_current_spoint (path); - for (i = 1; p[i].y != -64; i++) - ; - - npoints = i - 1 + 3; - - snap_x = malloc ((npoints * 2) * sizeof (twin_gfixed_t)); - snap_y = snap_x + npoints; + if (Hint (path)) + { + for (i = 1; p[i].y != -64; i++) + ; - nsnap_x = 0; - nsnap_y = 0; - - /* snap left and right boundaries */ + npoints = i - 1 + 3; + + snap_x = malloc ((npoints * 2) * sizeof (twin_gfixed_t)); + snap_y = snap_x + npoints; + + nsnap_x = 0; + nsnap_y = 0; - nsnap_x = _add_snap (snap_x, nsnap_x, p[0].x); - nsnap_x = _add_snap (snap_x, nsnap_x, p[0].y); + /* snap left and right boundaries */ + + nsnap_x = _add_snap (snap_x, nsnap_x, p[0].x); + nsnap_x = _add_snap (snap_x, nsnap_x, p[0].y); + + /* snap baseline, x height and cap height */ + nsnap_y = _add_snap (snap_y, nsnap_y, 9); + nsnap_y = _add_snap (snap_y, nsnap_y, -5); + nsnap_y = _add_snap (snap_y, nsnap_y, -12); + + /* + * Locate horizontal and vertical segments + */ + for (i = 1; p[i].y != -64 && p[i+1].y != -64; i++) + { + if (p[i].x == -64 || p[i+1].x == -64) + continue; + if (p[i].x == p[i+1].x) + nsnap_x = _add_snap (snap_x, nsnap_x, p[i].x); + if (p[i].y == p[i+1].y) + nsnap_y = _add_snap (snap_y, nsnap_y, p[i].y); + } - /* snap baseline, x height and cap height */ - nsnap_y = _add_snap (snap_y, nsnap_y, 9); - nsnap_y = _add_snap (snap_y, nsnap_y, -5); - nsnap_y = _add_snap (snap_y, nsnap_y, -12); + qsort (snap_x, nsnap_x, sizeof (twin_gfixed_t), compare_snap); + qsort (snap_y, nsnap_y, sizeof (twin_gfixed_t), compare_snap); - /* - * Locate horizontal and vertical segments - */ - for (i = 1; p[i].y != -64 && p[i+1].y != -64; i++) - { - if (p[i].x == -64 || p[i+1].x == -64) - continue; - if (p[i].x == p[i+1].x) - nsnap_x = _add_snap (snap_x, nsnap_x, p[i].x); - if (p[i].y == p[i+1].y) - nsnap_y = _add_snap (snap_y, nsnap_y, p[i].y); + DBGMSG (("snap_x:")); + for (i = 0; i < nsnap_x; i++) + DBGMSG ((" %d", snap_x[i])); + DBGMSG (("\n")); + + DBGMSG (("snap_y:")); + for (i = 0; i < nsnap_y; i++) + DBGMSG ((" %d", snap_y[i])); + DBGMSG (("\n")); } - qsort (snap_x, nsnap_x, sizeof (twin_gfixed_t), compare_snap); - qsort (snap_y, nsnap_y, sizeof (twin_gfixed_t), compare_snap); - - DBGMSG (("snap_x:")); - for (i = 0; i < nsnap_x; i++) - DBGMSG ((" %d", snap_x[i])); - DBGMSG (("\n")); - - DBGMSG (("snap_y:")); - for (i = 0; i < nsnap_y; i++) - DBGMSG ((" %d", snap_y[i])); - DBGMSG (("\n")); - stroke = twin_path_create (); twin_path_set_matrix (stroke, twin_path_current_matrix (path)); pen_size = _twin_pen_size (path); - pen_adjust = pen_size & TWIN_FIXED_HALF; + if (Hint (path)) + pen_adjust = pen_size & TWIN_FIXED_HALF; + else + pen_adjust = 0; pen = twin_path_create (); pen_matrix = twin_path_current_matrix (path); @@ -328,7 +336,8 @@ twin_path_ucs4 (twin_path_t *path, twin_ucs4_t ucs4) twin_path_destroy (stroke); twin_path_destroy (pen); - free (snap_x); + if (snap_x) + free (snap_x); w = metrics.width; @@ -337,7 +346,7 @@ twin_path_ucs4 (twin_path_t *path, twin_ucs4_t ucs4) origin.y + _twin_matrix_dy (&path->state.matrix, w, 0)); } -int +twin_fixed_t twin_width_ucs4 (twin_path_t *path, twin_ucs4_t ucs4) { twin_text_metrics_t metrics; @@ -427,3 +436,18 @@ twin_path_utf8 (twin_path_t *path, const char *string) } } +twin_fixed_t +twin_width_utf8 (twin_path_t *path, const char *string) +{ + int len; + twin_ucs4_t ucs4; + twin_fixed_t w = 0; + + while ((len = _twin_utf8_to_ucs4(string, &ucs4)) > 0) + { + w += twin_width_ucs4 (path, ucs4); + string += len; + } + return w; +} + diff --git a/twin_path.c b/twin_path.c index 5b2ecc5..7fd6f16 100644 --- a/twin_path.c +++ b/twin_path.c @@ -140,7 +140,7 @@ twin_path_close (twin_path_t *path) if (path->size_sublen > 0) size_sublen = path->size_sublen * 2; else - size_sublen = 16; + size_sublen = 1; if (path->sublen) sublen = realloc (path->sublen, size_sublen * sizeof (int)); else @@ -267,6 +267,32 @@ twin_path_empty (twin_path_t *path) } void +twin_path_bounds (twin_path_t *path, twin_rect_t *rect) +{ + twin_sfixed_t left = TWIN_SFIXED_MAX; + twin_sfixed_t top = TWIN_SFIXED_MAX; + twin_sfixed_t right = TWIN_SFIXED_MIN; + twin_sfixed_t bottom = TWIN_SFIXED_MIN; + int i; + + for (i = 0; i < path->npoints; i++) + { + twin_sfixed_t x = path->points[i].x; + twin_sfixed_t y = path->points[i].y; + if (x < left) left = x; + if (x > right) right = x; + if (y < top) top = y; + if (y > bottom) bottom = y; + } + if (left >= right || top >= bottom) + left = right = top = bottom = 0; + rect->left = twin_sfixed_trunc (left); + rect->top = twin_sfixed_trunc (top); + rect->right = twin_sfixed_trunc (twin_sfixed_ceil (right)); + rect->bottom = twin_sfixed_trunc (twin_sfixed_ceil (bottom)); +} + +void twin_path_append (twin_path_t *dst, twin_path_t *src) { int p; @@ -320,3 +346,84 @@ twin_path_destroy (twin_path_t *path) free (path->sublen); free (path); } + +void +twin_composite_path (twin_pixmap_t *dst, + twin_operand_t *src, + int src_x, + int src_y, + twin_path_t *path, + twin_operator_t operator) +{ + twin_rect_t bounds; + twin_pixmap_t *mask; + twin_operand_t msk; + int width, height; + + twin_path_bounds (path, &bounds); + if (bounds.left == bounds.right) + return; + width = bounds.right - bounds.left; + height = bounds.bottom - bounds.top; + mask = twin_pixmap_create (TWIN_A8, width, height); + + 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; + twin_composite (dst, bounds.left, bounds.top, + src, src_x + bounds.left, src_y + bounds.top, + &msk, 0, 0, operator, width, height); + twin_pixmap_destroy (mask); +} + +void +twin_paint_path (twin_pixmap_t *dst, + twin_argb32_t argb, + twin_path_t *path) +{ + twin_operand_t src; + + src.source_kind = TWIN_SOLID; + src.u.argb = argb; + twin_composite_path (dst, &src, 0, 0, path, TWIN_OVER); +} + +void +twin_composite_stroke (twin_pixmap_t *dst, + twin_operand_t *src, + int src_x, + int src_y, + twin_path_t *stroke, + twin_fixed_t pen_width, + twin_operator_t operator) +{ + twin_path_t *pen = twin_path_create (); + twin_path_t *path = twin_path_create (); + twin_matrix_t m = twin_path_current_matrix (stroke); + + m.m[2][0] = 0; + m.m[2][1] = 0; + twin_path_set_matrix (pen, m); + twin_path_circle (pen, pen_width / 2); + twin_path_convolve (path, stroke, pen); + twin_composite_path (dst, src, src_x, src_y, path, operator); + twin_path_destroy (path); + twin_path_destroy (pen); +} + +void +twin_paint_stroke (twin_pixmap_t *dst, + twin_argb32_t argb, + twin_path_t *stroke, + twin_fixed_t pen_width) +{ + twin_operand_t src; + + src.source_kind = TWIN_SOLID; + src.u.argb = argb; + twin_composite_stroke (dst, &src, 0, 0, stroke, pen_width, TWIN_OVER); +} + diff --git a/twin_pixmap.c b/twin_pixmap.c index 3610e01..83a9a95 100644 --- a/twin_pixmap.c +++ b/twin_pixmap.c @@ -39,6 +39,7 @@ twin_pixmap_create (twin_format_t format, int width, int height) pixmap->width = width; pixmap->height = height; pixmap->stride = stride; + pixmap->disable = 0; pixmap->p.v = pixmap + 1; return pixmap; } @@ -57,8 +58,15 @@ twin_pixmap_show (twin_pixmap_t *pixmap, twin_pixmap_t *lower) { twin_pixmap_t **higherp; + + twin_screen_lock (screen); + + if (pixmap->disable) + twin_screen_disable_update (screen); + if (pixmap->screen) twin_pixmap_hide (pixmap); + pixmap->screen = screen; if (lower) higherp = &lower->higher; @@ -67,6 +75,7 @@ twin_pixmap_show (twin_pixmap_t *pixmap, pixmap->higher = *higherp; *higherp = pixmap; twin_pixmap_damage (pixmap, 0, 0, pixmap->width, pixmap->height); + twin_screen_unlock (screen); } void @@ -77,12 +86,16 @@ twin_pixmap_hide (twin_pixmap_t *pixmap) 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; pixmap->screen = 0; pixmap->higher = 0; + if (pixmap->disable) + twin_screen_enable_update (screen); + twin_screen_unlock (screen); } twin_pointer_t @@ -97,6 +110,26 @@ twin_pixmap_pointer (twin_pixmap_t *pixmap, int x, int y) } void +twin_pixmap_enable_update (twin_pixmap_t *pixmap) +{ + if (--pixmap->disable == 0) + { + if (pixmap->screen) + twin_screen_enable_update (pixmap->screen); + } +} + +void +twin_pixmap_disable_update (twin_pixmap_t *pixmap) +{ + if (pixmap->disable++ == 0) + { + if (pixmap->screen) + twin_screen_disable_update (pixmap->screen); + } +} + +void twin_pixmap_damage (twin_pixmap_t *pixmap, int x1, int y1, int x2, int y2) { @@ -109,6 +142,20 @@ twin_pixmap_damage (twin_pixmap_t *pixmap, } void +twin_pixmap_lock (twin_pixmap_t *pixmap) +{ + if (pixmap->screen) + twin_screen_lock (pixmap->screen); +} + +void +twin_pixmap_unlock (twin_pixmap_t *pixmap) +{ + if (pixmap->screen) + twin_screen_unlock (pixmap->screen); +} + +void twin_pixmap_move (twin_pixmap_t *pixmap, int x, int y) { twin_pixmap_damage (pixmap, 0, 0, pixmap->width, pixmap->height); diff --git a/twin_poly.c b/twin_poly.c index d797c1e..e8aa7f2 100644 --- a/twin_poly.c +++ b/twin_poly.c @@ -24,6 +24,17 @@ #include "twinint.h" +typedef struct _twin_edge { + struct _twin_edge *next; + twin_sfixed_t top, bot; + twin_sfixed_t x; + twin_sfixed_t e; + twin_sfixed_t dx, dy; + twin_sfixed_t inc_x; + twin_sfixed_t step_x; + int winding; +} twin_edge_t; + #define TWIN_POLY_SHIFT 2 #define TWIN_POLY_FIXED_SHIFT (4 - TWIN_POLY_SHIFT) #define TWIN_POLY_SAMPLE (1 << TWIN_POLY_SHIFT) @@ -72,13 +83,14 @@ _twin_sfixed_grid_ceil (twin_sfixed_t f) #define DBGOUT(x...) #endif -int -_twin_edge_build (twin_spoint_t *vertices, int nvertices, twin_edge_t *edges) +static int +_twin_edge_build (twin_spoint_t *vertices, int nvertices, twin_edge_t *edges, + twin_sfixed_t dx, twin_sfixed_t dy) { int v, nv; int tv, bv; int e; - twin_sfixed_t y; + twin_sfixed_t y; e = 0; for (v = 0; v < nvertices; v++) @@ -107,12 +119,12 @@ _twin_edge_build (twin_spoint_t *vertices, int nvertices, twin_edge_t *edges) } /* snap top to first grid point in pixmap */ - y = _twin_sfixed_grid_ceil (vertices[tv].y); + y = _twin_sfixed_grid_ceil (vertices[tv].y + dy); if (y < TWIN_POLY_START) y = TWIN_POLY_START; /* skip vertices which don't span a sample row */ - if (y >= vertices[bv].y) + if (y >= vertices[bv].y + dy) continue; /* Compute bresenham terms */ @@ -128,10 +140,10 @@ _twin_edge_build (twin_spoint_t *vertices, int nvertices, twin_edge_t *edges) edges[e].step_x = edges[e].inc_x * (edges[e].dx / edges[e].dy); edges[e].dx = edges[e].dx % edges[e].dy; - edges[e].top = vertices[tv].y; - edges[e].bot = vertices[bv].y; + edges[e].top = vertices[tv].y + dy; + edges[e].bot = vertices[bv].y + dy; - edges[e].x = vertices[tv].x; + edges[e].x = vertices[tv].x + dx; edges[e].e = 0; /* step to first grid point */ @@ -254,7 +266,7 @@ _span_fill (twin_pixmap_t *pixmap, } } -void +static void _twin_edge_fill (twin_pixmap_t *pixmap, twin_edge_t *edges, int nedges) { twin_edge_t *active, *a, *n, **prev; @@ -336,13 +348,15 @@ _twin_edge_fill (twin_pixmap_t *pixmap, twin_edge_t *edges, int nedges) } void -twin_fill_path (twin_pixmap_t *pixmap, twin_path_t *path) +twin_fill_path (twin_pixmap_t *pixmap, twin_path_t *path, int dx, int dy) { - twin_edge_t *edges; - int nedges, n; - int nalloc; - int s; - int p; + twin_edge_t *edges; + int nedges, n; + int nalloc; + int s; + int p; + twin_sfixed_t sdx = twin_int_to_sfixed (dx); + twin_sfixed_t sdy = twin_int_to_sfixed (dy); nalloc = path->npoints + path->nsublen + 1; edges = malloc (sizeof (twin_edge_t) * nalloc); @@ -360,7 +374,8 @@ twin_fill_path (twin_pixmap_t *pixmap, twin_path_t *path) npoints = sublen - p; if (npoints > 1) { - n = _twin_edge_build (path->points + p, npoints, edges + nedges); + n = _twin_edge_build (path->points + p, npoints, edges + nedges, + sdx, sdy); p = sublen; nedges += n; } diff --git a/twin_screen.c b/twin_screen.c index 1662c9d..5510a52 100644 --- a/twin_screen.c +++ b/twin_screen.c @@ -38,12 +38,34 @@ twin_screen_create (int width, screen->height = height; screen->damage.left = screen->damage.right = 0; screen->damage.top = screen->damage.bottom = 0; + screen->damaged = NULL; + screen->damaged_closure = NULL; + screen->disable = 0; +#if HAVE_PTHREAD_H + pthread_mutex_init (&screen->screen_mutex, NULL); +#endif screen->put_span = put_span; screen->closure = closure; return screen; } void +twin_screen_lock (twin_screen_t *screen) +{ +#if HAVE_PTHREAD_H + pthread_mutex_lock (&screen->screen_mutex); +#endif +} + +void +twin_screen_unlock (twin_screen_t *screen) +{ +#if HAVE_PTHREAD_H + pthread_mutex_unlock (&screen->screen_mutex); +#endif +} + +void twin_screen_destroy (twin_screen_t *screen) { while (screen->bottom) @@ -52,6 +74,35 @@ twin_screen_destroy (twin_screen_t *screen) } void +twin_screen_register_damaged (twin_screen_t *screen, + void (*damaged) (void *), + void *closure) +{ + screen->damaged = damaged; + screen->damaged_closure = closure; +} + +void +twin_screen_enable_update (twin_screen_t *screen) +{ + if (--screen->disable == 0) + { + if (screen->damage.left < screen->damage.right && + screen->damage.top < screen->damage.bottom) + { + if (screen->damaged) + (*screen->damaged) (screen->damaged_closure); + } + } +} + +void +twin_screen_disable_update (twin_screen_t *screen) +{ + screen->disable++; +} + +void twin_screen_damage (twin_screen_t *screen, int left, int top, int right, int bottom) { @@ -73,6 +124,8 @@ twin_screen_damage (twin_screen_t *screen, if (screen->damage.bottom < bottom) screen->damage.bottom = bottom; } + if (screen->damaged && !screen->disable) + (*screen->damaged) (screen->damaged_closure); } void @@ -93,7 +146,8 @@ twin_screen_damaged (twin_screen_t *screen) void twin_screen_update (twin_screen_t *screen) { - if (screen->damage.left < screen->damage.right && + if (!screen->disable && + screen->damage.left < screen->damage.right && screen->damage.top < screen->damage.bottom) { int x = screen->damage.left; @@ -22,8 +22,8 @@ * PERFORMANCE OF THIS SOFTWARE. */ +#include "twin_x11.h" #include "twinint.h" -#include <X11/Xutil.h> static void _twin_x11_put_span (int x, @@ -55,6 +55,56 @@ _twin_x11_put_span (int x, XDestroyImage (image); } +static void * +twin_x11_damage_thread (void *arg) +{ + twin_x11_t *tx = arg; + + pthread_mutex_lock (&tx->screen->screen_mutex); + for (;;) + { + pthread_cond_wait (&tx->damage_cond, &tx->screen->screen_mutex); + if (!tx->win) + break; + if (twin_screen_damaged (tx->screen)) + { + twin_x11_update (tx); + XFlush (tx->dpy); + } + } + pthread_mutex_unlock (&tx->screen->screen_mutex); + return 0; +} + +static void * +twin_x11_event_thread (void *arg) +{ + twin_x11_t *tx = arg; + XEvent ev; + + for (;;) + { + XNextEvent (tx->dpy, &ev); + switch (ev.type) { + case Expose: + twin_x11_damage (tx, (XExposeEvent *) &ev); + break; + case DestroyNotify: + return 0; + } + } +} + +static void +twin_x11_screen_damaged (void *closure) +{ + twin_x11_t *tx = closure; + + pthread_mutex_unlock (&tx->screen->screen_mutex); + pthread_cond_broadcast (&tx->damage_cond); + pthread_mutex_unlock (&tx->screen->screen_mutex); +} + twin_x11_t * twin_x11_create (Display *dpy, int width, int height) { @@ -85,15 +135,26 @@ twin_x11_create (Display *dpy, int width, int height) tx->gc = XCreateGC (dpy, tx->win, 0, 0); tx->screen = twin_screen_create (width, height, _twin_x11_put_span, tx); + twin_screen_register_damaged (tx->screen, twin_x11_screen_damaged, tx); + XMapWindow (dpy, tx->win); + + pthread_cond_init (&tx->damage_cond, NULL); + + pthread_create (&tx->damage_thread, NULL, twin_x11_damage_thread, tx); + + pthread_create (&tx->event_thread, NULL, twin_x11_event_thread, tx); + return tx; } void twin_x11_destroy (twin_x11_t *tx) { - twin_screen_destroy (tx->screen); XDestroyWindow (tx->dpy, tx->win); + tx->win = 0; + pthread_cond_broadcast (&tx->damage_cond); + twin_screen_destroy (tx->screen); } void @@ -57,6 +57,8 @@ typedef int32_t twin_dfixed_t; /* 24.8 format (12.4 * 12.4) */ #define TWIN_SFIXED_ONE (0x10) #define TWIN_SFIXED_HALF (0x08) #define TWIN_SFIXED_TOLERANCE (TWIN_SFIXED_ONE >> 2) +#define TWIN_SFIXED_MIN (-0x7fff) +#define TWIN_SFIXED_MAX (0x7fff) /* * Glyph coordinates are stored in 2.6 fixed point @@ -285,27 +287,6 @@ _twin_distance_to_line_squared (twin_spoint_t *p, twin_spoint_t *p1, twin_spoint * Polygon stuff */ -typedef struct _twin_edge { - struct _twin_edge *next; - twin_sfixed_t top, bot; - twin_sfixed_t x; - twin_sfixed_t e; - twin_sfixed_t dx, dy; - twin_sfixed_t inc_x; - twin_sfixed_t step_x; - int winding; -} twin_edge_t; - -/* - * Pixmap must be in a8 format. - */ - -int -_twin_edge_build (twin_spoint_t *vertices, int nvertices, twin_edge_t *edges); - -void -_twin_edge_fill (twin_pixmap_t *pixmap, twin_edge_t *edges, int nedges); - /* * Fixed point helper functions */ @@ -22,13 +22,132 @@ * PERFORMANCE OF THIS SOFTWARE. */ -#include <X11/Xlib.h> -#include "twin.h" +#include "twin_x11.h" #include <string.h> #include <stdio.h> +#include <unistd.h> +#include <sys/time.h> +#include <time.h> +#include <assert.h> #define D(x) twin_double_to_fixed(x) +#define CLOCK_SIZE 256 + +#define TWIN_CLOCK_BACKGROUND 0xff3b80ae +#define TWIN_CLOCK_HOUR 0xffdedede +#define TWIN_CLOCK_MINUTE 0xffdedede +#define TWIN_CLOCK_SECOND 0x80808080 +#define TWIN_CLOCK_TIC 0xffbababa +#define TWIN_CLOCK_NUMBERS 0xffdedede + +static void +twin_clock_hand (twin_pixmap_t *clock, + twin_angle_t angle, + twin_fixed_t len, + twin_fixed_t width, + twin_argb32_t pixel) +{ + twin_path_t *stroke = twin_path_create (); + + twin_path_translate (stroke, D(CLOCK_SIZE) / 2, D(CLOCK_SIZE) / 2); + twin_path_scale (stroke, D(CLOCK_SIZE) / 2, D(CLOCK_SIZE) / 2); + + twin_path_rotate (stroke, angle); + twin_path_move (stroke, D(0), D(0)); + twin_path_draw (stroke, len, D(0)); + + twin_paint_stroke (clock, pixel, stroke, width); + + twin_path_destroy (stroke); +} + +static twin_angle_t +twin_clock_minute_angle (int min) +{ + return min * TWIN_ANGLE_360 / 60 - TWIN_ANGLE_90; +} + +static void +twin_clock_face (twin_pixmap_t *clock) +{ + twin_path_t *path = twin_path_create (); + int m; + + twin_path_translate (path, D(CLOCK_SIZE) / 2, D(CLOCK_SIZE) / 2); + twin_path_scale (path, D(CLOCK_SIZE) / 2, D(CLOCK_SIZE) / 2); + twin_path_set_font_size (path, D(0.2)); + twin_path_set_font_style (path, TWIN_TEXT_UNHINTED); + + twin_path_move (path, 0, 0); + twin_path_circle (path, TWIN_FIXED_ONE); + + twin_paint_path (clock, TWIN_CLOCK_BACKGROUND, path); + + for (m = 1; m <= 60; m++) + { + twin_state_t state = twin_path_save (path); + twin_path_rotate (path, twin_clock_minute_angle (m) + TWIN_ANGLE_90); + twin_path_empty (path); + if (m % 5 != 0) + { + 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)); + } + else + { + char hour[3]; + + twin_fixed_t w; + sprintf (hour, "%d", m / 5); + w = twin_width_utf8 (path, hour); + twin_path_move (path, -(w/2), -D(0.95)); + twin_path_utf8 (path, hour); + twin_paint_path (clock, TWIN_CLOCK_NUMBERS, path); + } + twin_path_restore (path, &state); + } + + twin_path_destroy (path); +} + +static void +twin_clock (twin_screen_t *screen) +{ + twin_pixmap_t *clock = twin_pixmap_create (TWIN_ARGB32, CLOCK_SIZE, CLOCK_SIZE); + struct timeval tv; + struct tm t; + twin_angle_t hour_angle, minute_angle, second_angle; + + printf ("twin clock\n"); + twin_pixmap_move (clock, 0, 0); + twin_pixmap_show (clock, screen, 0); + for (;;) + { + twin_pixmap_disable_update (clock); + twin_fill (clock, 0x00000000, TWIN_SOURCE, 0, 0, + CLOCK_SIZE, CLOCK_SIZE); + + gettimeofday (&tv, NULL); + + localtime_r(&tv.tv_sec, &t); + + second_angle = ((t.tm_sec * 100 + tv.tv_usec / 10000) * + TWIN_ANGLE_360) / 6000 - TWIN_ANGLE_90; + minute_angle = twin_clock_minute_angle (t.tm_min) + second_angle / 60; + hour_angle = t.tm_hour * TWIN_ANGLE_360 / 12 - TWIN_ANGLE_90 + minute_angle / 12; + + twin_clock_face (clock); + twin_clock_hand (clock, hour_angle, D(0.4), D(0.05), 0xffdedede); + twin_clock_hand (clock, minute_angle, D(0.8), D(0.03), 0xffdedede); + twin_clock_hand (clock, second_angle, D(0.6), D(0.01), 0x80808080); + + twin_pixmap_enable_update (clock); + usleep (1000000 - tv.tv_usec); + } +} + int styles[] = { TWIN_TEXT_ROMAN, TWIN_TEXT_OBLIQUE, @@ -42,6 +161,7 @@ int styles[] = { int main (int argc, char **argv) { + Status status = XInitThreads (); Display *dpy = XOpenDisplay (0); twin_x11_t *x11 = twin_x11_create (dpy, WIDTH, HEIGHT); twin_pixmap_t *red = twin_pixmap_create (TWIN_ARGB32, WIDTH, HEIGHT); @@ -59,12 +179,29 @@ main (int argc, char **argv) twin_fixed_t fx, fy; int g; + (void) ev; + (void) motion; + (void) had_motion; + (void) x; + (void) y; + (void) red; + (void) blue; + (void) status; + (void) alpha; + (void) source; + (void) mask; + (void) source; + (void) path; + extra = 0; stroke = 0; + pen = 0; s = 0; fx = 0; fy = 0; g = 0 ; + +#if 0 pen = twin_path_create (); twin_path_circle (pen, D (1)); @@ -337,6 +474,10 @@ main (int argc, char **argv) twin_pixmap_move (blue, 100, 100); twin_pixmap_show (red, x11->screen, 0); twin_pixmap_show (blue, x11->screen, 0); +#endif + twin_clock (x11->screen); + sleep (10000); +#if 0 had_motion = TWIN_FALSE; for (;;) { @@ -375,5 +516,7 @@ main (int argc, char **argv) } } while (QLength (dpy)); } +#endif + return 0; } |