summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKeith Packard <keithp@keithp.com>2004-09-30 17:23:07 +0000
committerKeith Packard <keithp@keithp.com>2004-09-30 17:23:07 +0000
commit531d39cc7ae4333856661395b0d62f8f7b62c003 (patch)
tree16c51f9a3cbe10448076b9491a807c08b4efb0a1
parentc3b1b799fe346ef7211ba614bf6c44396e411590 (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--ChangeLog37
-rw-r--r--Makefile.am1
-rw-r--r--configure.ac36
-rw-r--r--twin.h103
-rw-r--r--twin_draw.c6
-rw-r--r--twin_font.c152
-rw-r--r--twin_path.c109
-rw-r--r--twin_pixmap.c47
-rw-r--r--twin_poly.c47
-rw-r--r--twin_screen.c56
-rw-r--r--twin_x11.c65
-rw-r--r--twinint.h23
-rw-r--r--xtwin.c147
13 files changed, 674 insertions, 155 deletions
diff --git a/ChangeLog b/ChangeLog
index a844774..8fb013b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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])
diff --git a/twin.h b/twin.h
index 04215d1..b8f56e0 100644
--- a/twin.h
+++ b/twin.h
@@ -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;
diff --git a/twin_x11.c b/twin_x11.c
index 31797bc..b16bcc8 100644
--- a/twin_x11.c
+++ b/twin_x11.c
@@ -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
diff --git a/twinint.h b/twinint.h
index afb353c..ebdefd2 100644
--- a/twinint.h
+++ b/twinint.h
@@ -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
*/
diff --git a/xtwin.c b/xtwin.c
index c323406..bc7b639 100644
--- a/xtwin.c
+++ b/xtwin.c
@@ -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;
}