Commit 5b4c8afa authored by Alexander Larsson's avatar Alexander Larsson

i2000-11-22 Alexander Larsson <alexl@redhat.com>

        * gdk/gdktypes.h:
	Add new type GdkSpan

	* docs/reference/gdk/gdk-sections.txt,
	docs/reference/gdk/tmpl/regions.sgml, gdk/gdkregion-generic.c,
	gdk/gdkregion.h:
	Implement and document gdk_region_spans_intersect_foreach.

	* gdk/linux-fb/Makefile.am, gdk/linux-fb/gdkrender-fb.c:
	Add new file gdkrender-fb.c which contains all core
	rendering code.
	Add gdk_fb_fill_rectangle_generic (old rectangle code) and
	gdk_fb_fill_rectangle_simple_16, gdk_fb_fill_rectangle_simple_32
	(optimized rectangle fillers).

	* gdk/linux-fb/gdkdrawable-fb2.c:
	Move all rendering code to gdkrender-fb.c.
	Change from using GdkRectangles and GdkSegments for spans to GdkSpan.
	Use the new span intersection functions in gdk_fb_fill_spans.
	gdk_fb_draw_rectangle() clips filled rectangles and calls
	gc->fill_rectangle with the result.
	gdk_fb_fill_spans() gets extra argument "sorted".

	* gdk/linux-fb/gdkevents-fb.c:
	Remove unused includes and defines.
	New function gdk_fb_get_time() to get correct time for events.

	* gdk/linux-fb/gdkinput-ps2.c:
	Use gdk method of generating multiple-clicks (gdk_event_button_generate)
	Make sure to set the time of all events.

	* gdk/linux-fb/gdkmain-fb.c:
	Use gdk_fb_get_time ().

	* gdk/linux-fb/gdkprivate-fb.h:
	New virtual GC calls: fill_span & fill_rectangle.
	Export gdk_fb_get_time().
	gdk_fb_fill_spans() gets extra argument "sorted".

	* gdk/linux-fb/mi*.c:
	Use GdkSpan instead of GdkRectangle.
	Pass correct sorted to gdk_fb_fill_spans. (sorted value taken
	from XFree 4 source)
parent c76c5f48
......@@ -620,6 +620,12 @@ gdk_region_intersect
gdk_region_union
gdk_region_subtract
gdk_region_xor
<SUBSECTION>
GdkSpan
GdkSpanFunc
gdk_region_spans_intersect_foreach
</SECTION>
<SECTION>
......
......@@ -6,8 +6,8 @@ simple graphical data types.
<!-- ##### SECTION Long_Description ##### -->
<para>
GDK provides the #GdkPoint, #GdkRectangle and #GdkRegion data types for
representing pixels and sets of pixels on the screen.
GDK provides the #GdkPoint, #GdkRectangle, #GdkRegion and #GdkSpan data types
for representing pixels and sets of pixels on the screen.
</para>
<para>
#GdkPoint is a simple structure containing an x and y coordinate of a point.
......@@ -22,6 +22,11 @@ gdk_rectangle_union().
#GdkRegion is an opaque data type holding a set of arbitrary pixels, and is
usually used for clipping graphical operations (see gdk_gc_set_clip_region()).
</para>
<para>
#GdkSpan is a structure holding a spanline. A spanline is a horizontal line that
is one pixel wide. It is mainly used when rasterizing other graphics primitives.
It can be intersected to regions by using gdk_region_spans_intersect_foreach().
</para>
<!-- ##### SECTION See_Also ##### -->
<para>
......@@ -261,3 +266,36 @@ Returns the union of a region and a rectangle.
@source2:
<!-- ##### STRUCT GdkSpan ##### -->
<para>
</para>
@x:
@y:
@width:
<!-- ##### USER_FUNCTION GdkSpanFunc ##### -->
<para>
</para>
@span: The intersected part of the span.
@data: Opaque data passed by user.
<!-- ##### FUNCTION gdk_region_spans_intersect_foreach ##### -->
<para>
Intersects a set of spans with a region and call a user specified
function for each resulting spanline. This function is a lot more effective
if the spans are sorted.
</para>
@region: The region to intersect against.
@spans: Array of spans to intersect.
@n_spans: Number of spans.
@sorted: True if the spans are sorted in increasing y order.
@function: The function to call for each intersected spanline.
@data: Opaque user data passed to function.
......@@ -1505,3 +1505,153 @@ gdk_region_rect_in (GdkRegion *region,
GDK_OVERLAP_RECTANGLE_PART : GDK_OVERLAP_RECTANGLE_IN) :
GDK_OVERLAP_RECTANGLE_OUT);
}
static void
gdk_region_unsorted_spans_intersect_foreach (GdkRegion *region,
GdkSpan *spans,
int n_spans,
GdkSpanFunc function,
gpointer data)
{
gint i, left, right, y;
gint clipped_left, clipped_right;
GdkRegionBox *pbox;
GdkRegionBox *pboxEnd;
GdkSpan out_span;
if (!region->numRects)
return;
for (i=0;i<n_spans;i++)
{
y = spans[i].y;
left = spans[i].x;
right = left + spans[i].width; /* right is not in the span! */
if (! ((region->extents.y1 <= y) &&
(region->extents.y2 > y) &&
(region->extents.x1 < right) &&
(region->extents.x2 > left)) )
continue;
/* can stop when we passed y */
for (pbox = region->rects, pboxEnd = pbox + region->numRects;
pbox < pboxEnd;
pbox++)
{
if (pbox->y2 <= y)
continue; /* Not quite there yet */
if (pbox->y1 > y)
break; /* passed the spanline */
if ((right > pbox->x1) && (left < pbox->x2))
{
clipped_left = MAX (left, pbox->x1);
clipped_right = MIN (right, pbox->x2);
out_span.y = y;
out_span.x = clipped_left;
out_span.width = clipped_right - clipped_left;
(*function) (&out_span, data);
}
}
}
}
void
gdk_region_spans_intersect_foreach (GdkRegion *region,
GdkSpan *spans,
int n_spans,
gboolean sorted,
GdkSpanFunc function,
gpointer data)
{
gint left, right, y;
gint clipped_left, clipped_right;
GdkRegionBox *pbox;
GdkRegionBox *pboxEnd;
GdkSpan *span, *tmpspan;
GdkSpan *end_span;
GdkSpan out_span;
if (!sorted)
{
gdk_region_unsorted_spans_intersect_foreach (region,
spans,
n_spans,
function,
data);
return;
}
if ((!region->numRects) || (n_spans == 0))
return;
y = span->y;
left = span->x;
right = span->x + span->width; /* right is not in the span! */
/* The main method here is to step along the
* sorted rectangles and spans in lock step, and
* clipping the spans that are in the current
* rectangle before going on to the next rectangle.
*/
span = spans;
end_span = spans + n_spans;
pbox = region->rects;
pboxEnd = pbox + region->numRects;
while (pbox < pboxEnd)
{
while ((pbox->y2 < span->y) || (span->y < pbox->y1))
{
/* Skip any rectangles that are above the current span */
if (pbox->y2 < span->y)
{
pbox++;
if (pbox == pboxEnd)
return;
}
/* Skip any spans that are above the current rectangle */
if (span->y < pbox->y1)
{
span++;
if (span == end_span)
return;
}
}
/* Ok, we got at least one span that might intersect this rectangle. */
tmpspan = span;
while ((tmpspan < end_span) &&
(tmpspan->y < pbox->y2))
{
y = tmpspan->y;
left = tmpspan->x;
right = left + tmpspan->width; /* right is not in the span! */
if ((right > pbox->x1) && (left < pbox->x2))
{
clipped_left = MAX (left, pbox->x1);
clipped_right = MIN (right, pbox->x2);
out_span.y = y;
out_span.x = clipped_left;
out_span.width = clipped_right - clipped_left;
(*function) (&out_span, data);
}
tmpspan++;
}
/* Finished this rectangle.
* The spans could still intersect the next one
*/
pbox++;
}
return spans;
}
......@@ -29,6 +29,9 @@ typedef enum
GDK_OVERLAP_RECTANGLE_PART
} GdkOverlapType;
typedef void (*GdkSpanFunc) (GdkSpan *span,
gpointer data);
GdkRegion *gdk_region_new (void);
GdkRegion *gdk_region_polygon (GdkPoint *points,
gint npoints,
......@@ -66,8 +69,16 @@ void gdk_region_subtract (GdkRegion *source1,
void gdk_region_xor (GdkRegion *source1,
GdkRegion *source2);
void gdk_region_spans_intersect_foreach (GdkRegion *region,
GdkSpan *spans,
int n_spans,
gboolean sorted,
GdkSpanFunc function,
gpointer data);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* __GDK_REGION_H__ */
......@@ -67,6 +67,7 @@ extern "C" {
typedef struct _GdkPoint GdkPoint;
typedef struct _GdkRectangle GdkRectangle;
typedef struct _GdkSegment GdkSegment;
typedef struct _GdkSpan GdkSpan;
/*
* Note that on some platforms the wchar_t type
......@@ -184,6 +185,13 @@ struct _GdkSegment
gint y2;
};
struct _GdkSpan
{
gint x;
gint y;
gint width;
};
#ifdef __cplusplus
}
#endif /* __cplusplus */
......
......@@ -50,6 +50,7 @@ libgdk_linux_fb_la_SOURCES = \
gdkinputprivate.h \
gdkinput-ps2.c \
gdkevents-fb.c \
gdkrender-fb.c \
mi.h \
miarc.c \
midash.c \
......
This diff is collapsed.
......@@ -29,63 +29,6 @@
#include "gdkinternals.h"
#include "gdkfb.h"
#include "gdkkeysyms.h"
#if HAVE_CONFIG_H
# include <config.h>
# if STDC_HEADERS
# include <string.h>
# endif
#endif
typedef struct _GdkIOClosure GdkIOClosure;
typedef struct _GdkEventPrivate GdkEventPrivate;
#define DOUBLE_CLICK_TIME 250
#define TRIPLE_CLICK_TIME 500
#define DOUBLE_CLICK_DIST 5
#define TRIPLE_CLICK_DIST 5
typedef enum
{
/* Following flag is set for events on the event queue during
* translation and cleared afterwards.
*/
GDK_EVENT_PENDING = 1 << 0
} GdkEventFlags;
struct _GdkIOClosure
{
GdkInputFunction function;
GdkInputCondition condition;
GdkDestroyNotify notify;
gpointer data;
};
struct _GdkEventPrivate
{
GdkEvent event;
guint flags;
};
/*
* Private function declarations
*/
/* Private variable declarations
*/
#if 0
static GList *client_filters; /* Filters for client messages */
static GSourceFuncs event_funcs = {
gdk_event_prepare,
gdk_event_check,
gdk_event_dispatch,
(GDestroyNotify)g_free
};
#endif
/*********************************************
* Functions for maintaining the event queue *
*********************************************/
......@@ -101,6 +44,15 @@ static gboolean fb_events_dispatch (gpointer source_data,
GTimeVal *dispatch_time,
gpointer user_data);
guint32
gdk_fb_get_time(void)
{
GTimeVal tv;
g_get_current_time (&tv);
return (guint32) tv.tv_sec * 1000 + tv.tv_usec / 1000;
}
void
gdk_events_init (void)
{
......
......@@ -76,9 +76,6 @@ static Keyboard * tty_keyboard_open(void);
static MouseDevice *gdk_fb_mouse = NULL;
static Keyboard *keyboard = NULL;
static guint multiclick_tag;
static GdkEvent *multiclick_event = NULL;
#ifndef VESA_NO_BLANKING
#define VESA_NO_BLANKING 0
#define VESA_VSYNC_SUSPEND 1
......@@ -110,33 +107,11 @@ input_activity (void)
#endif
}
static gboolean
click_event_timeout (gpointer x)
{
switch (multiclick_event->type)
{
case GDK_BUTTON_RELEASE:
gdk_event_free (multiclick_event);
break;
case GDK_2BUTTON_PRESS:
case GDK_3BUTTON_PRESS:
gdk_event_queue_append (multiclick_event);
break;
default:
break;
}
multiclick_event = NULL;
multiclick_tag = 0;
return FALSE;
}
static void
send_button_event (MouseDevice *mouse,
guint button,
gboolean press_event,
time_t the_time)
guint32 the_time)
{
GdkEvent *event;
gint x, y;
......@@ -152,35 +127,6 @@ send_button_event (MouseDevice *mouse,
x = mouse->x - x;
y = mouse->y - y;
if (!press_event &&
multiclick_event &&
multiclick_event->button.button == button &&
multiclick_event->button.window == window &&
ABS(multiclick_event->button.x - x) < 3 &&
ABS(multiclick_event->button.y - y) < 3)
{
multiclick_event->button.time = the_time;
/* Just change multiclick_event into a different event */
switch (multiclick_event->button.type)
{
default:
g_assert_not_reached ();
case GDK_BUTTON_RELEASE:
multiclick_event->button.type = GDK_2BUTTON_PRESS;
return;
case GDK_2BUTTON_PRESS:
multiclick_event->button.type = GDK_3BUTTON_PRESS;
return;
case GDK_3BUTTON_PRESS:
gdk_event_queue_append (multiclick_event); multiclick_event = NULL;
g_source_remove (multiclick_tag); multiclick_tag = 0;
}
}
event = gdk_event_make (window, press_event ? GDK_BUTTON_PRESS : GDK_BUTTON_RELEASE, FALSE);
if (!event)
......@@ -219,6 +165,8 @@ send_button_event (MouseDevice *mouse,
mouse->click_grab = FALSE;
}
event->button.time = the_time;
#if 0
g_message ("Button #%d %s [%d, %d] in %p",
button, press_event?"pressed":"released",
......@@ -237,11 +185,9 @@ send_button_event (MouseDevice *mouse,
}
#endif
if (!press_event && !multiclick_tag)
{
multiclick_tag = g_timeout_add (250, click_event_timeout, NULL);
multiclick_event = gdk_event_copy (event);
}
/* For double-clicks */
if (press_event)
gdk_event_button_generate (event);
gdk_event_queue_append (event);
}
......@@ -598,6 +544,7 @@ handle_mouse_input(MouseDevice *mouse,
event->motion.device = gdk_core_pointer;
event->motion.x_root = mouse->x;
event->motion.y_root = mouse->y;
event->motion.time = gdk_fb_get_time ();
}
if (win != mouse->prev_window)
......@@ -732,11 +679,10 @@ handle_input_fidmour (GIOChannel *gioc,
gdouble x, y, oldx, oldy;
gboolean got_motion = FALSE;
gboolean btn_down;
time_t the_time;
GTimeVal tv;
guint32 the_time;
g_get_current_time (&tv);
the_time = tv.tv_sec;
the_time = gdk_fb_get_time ();
oldx = mouse->x;
oldy = mouse->y;
while (pull_fidmour_packet (mouse, &btn_down, &x, &y))
......@@ -775,13 +721,11 @@ handle_input_ps2 (GIOChannel *gioc,
MouseDevice *mouse = data;
int n, dx=0, dy=0;
gboolean new_button1, new_button2, new_button3;
time_t the_time;
GTimeVal curtime;
guint32 the_time;
gboolean got_motion = FALSE;
guchar *buf;
g_get_current_time (&curtime);
the_time = curtime.tv_usec;
the_time = gdk_fb_get_time ();
while (1) /* Go through as many mouse events as we can */
{
......@@ -862,11 +806,9 @@ handle_input_ms (GIOChannel *gioc,
guchar byte1, byte2, byte3;
int n, dx=0, dy=0;
gboolean new_button1, new_button2, new_button3;
time_t the_time;
GTimeVal curtime;
guint32 the_time;
g_get_current_time (&curtime);
the_time = curtime.tv_usec;
the_time = gdk_fb_get_time ();
n = read (mouse->fd, &byte1, 1);
if ( (n!=1) || (byte1 & 0x40) != 0x40)
......@@ -1405,16 +1347,14 @@ handle_mediumraw_keyboard_input (GIOChannel *gioc,
guchar buf[128];
int i, n;
Keyboard *k = data;
time_t now;
GTimeVal curtime;
guint32 now;
n = read (k->fd, buf, sizeof(buf));
if (n <= 0)
g_error("Nothing from keyboard!");
/* Now turn this into a keyboard event */
g_get_current_time (&curtime);
now = curtime.tv_sec;
now = gdk_fb_get_time ();
for (i = 0; i < n; i++)
{
......@@ -1556,16 +1496,14 @@ handle_xlate_keyboard_input (GIOChannel *gioc,
guchar buf[128];
int i, n;
Keyboard *k = data;
time_t now;
GTimeVal curtime;
guint32 now;
n = read (k->fd, buf, sizeof(buf));
if (n <= 0)
g_error ("Nothing from keyboard!");
/* Now turn this into a keyboard event */
g_get_current_time (&curtime);
now = curtime.tv_sec;
now = gdk_fb_get_time ();
for (i = 0; i < n; i++)
{
......
......@@ -991,10 +991,9 @@ gdk_event_make (GdkWindow *window,
guint32 the_time = g_latest_time.tv_sec * 1000 + g_latest_time.tv_usec / 1000;
#else
guint32 the_time;
GTimeVal gcurtime;
g_get_current_time (&gcurtime);
the_time = gcurtime.tv_sec * 1000 + gcurtime.tv_usec / 1000;
the_time = gdk_fb_get_time ();
#endif
event->any.type = type;
......
......@@ -215,7 +215,7 @@ typedef struct {
/* These functions can only be called for drawables
* that have the same depth as the gc.
*/
void (*set_pixel) (GdkDrawable *drawable,
void (*set_pixel) (GdkDrawable *drawable,
GdkGC *gc,
int x,
int y,
......@@ -227,11 +227,16 @@ typedef struct {
int y,
GdkColor *color);
void (*fill_span) (GdkDrawable *drawable,
GdkGC *gc,
GdkSegment *cur,
GdkColor *color);
void (*fill_span) (GdkDrawable *drawable,
GdkGC *gc,
GdkSpan *span,
GdkColor *color);
void (*fill_rectangle) (GdkDrawable *drawable,
GdkGC *gc,
GdkRectangle *rect,
GdkColor *color);
gdk_fb_draw_drawable_func *draw_drawable[GDK_NUM_FB_SRCBPP];
} GdkGCFBData;
......@@ -301,51 +306,67 @@ struct _GdkFBDrawingContext {
gboolean handle_cursor : 1;
};
void gdk_fb_drawing_context_init(GdkFBDrawingContext *dc, GdkDrawable *drawable,
GdkGC *gc, gboolean draw_bg, gboolean do_clipping);
void gdk_fb_drawing_context_finalize(GdkFBDrawingContext *dc);
void gdk_fb_draw_drawable_3 (GdkDrawable *drawable,
GdkGC *gc,
GdkPixmap *src,
GdkFBDrawingContext *dc,
gint xsrc,
gint ysrc,
gint xdest,
gint ydest,
gint width,
gint height);
void gdk_fb_draw_drawable_2 (GdkDrawable *drawable,
GdkGC *gc,
GdkPixmap *src,
gint xsrc,
gint ysrc,
gint xdest,
gint ydest,
gint width,
gint height,
gboolean draw_bg,
gboolean do_clipping);
void gdk_fb_draw_rectangle (GdkDrawable *drawable,
GdkGC *gc,
gint filled,
gint x,
gint y,
gint width,
gint height);
void gdk_fb_fill_spans(GdkDrawable *real_drawable, GdkGC *gc, GdkRectangle *rects, int nrects);
GdkRegion *gdk_fb_clip_region(GdkDrawable *drawable, GdkGC *gc, gboolean do_clipping, gboolean do_children);
GdkGrabStatus
gdk_fb_pointer_grab (GdkWindow * window,
gint owner_events,
GdkEventMask event_mask,
GdkWindow * confine_to,
GdkCursor * cursor,
guint32 time,
gboolean implicit_grab);
void gdk_fb_pointer_ungrab (guint32 time, gboolean implicit_grab);
void gdk_fb_drawing_context_init (GdkFBDrawingContext *dc,
GdkDrawable *drawable,
GdkGC *gc,
gboolean draw_bg,
gboolean do_clipping);
void gdk_fb_drawing_context_finalize (GdkFBDrawingContext *dc);
void gdk_fb_draw_drawable_3 (GdkDrawable *drawable,
GdkGC *gc,
GdkPixmap *src,
GdkFBDrawingContext *dc,
gint xsrc,
gint ysrc,
gint xdest,
gint ydest,
gint width,
gint height);
void gdk_fb_draw_drawable_2 (GdkDrawable *drawable,
GdkGC *gc,
GdkPixmap *src,
gint xsrc,
gint ysrc,
gint xdest,
gint ydest,
gint width,
gint height,
gboolean draw_bg,
gboolean do_clipping);
void gdk_fb_draw_rectangle (GdkDrawable *drawable,
GdkGC *gc,
gint filled,
gint x,
gint y,
gint width,
gint height);
void gdk_fb_draw_lines (GdkDrawable *drawable,
GdkGC *gc,
GdkPoint *points,
gint npoints);
void gdk_fb_fill_spans (GdkDrawable *real_drawable,
GdkGC *gc,
GdkSpan *spans,
int nspans,
gboolean sorted);
GdkRegion *gdk_fb_clip_region (GdkDrawable *drawable,
GdkGC *gc,
gboolean do_clipping,
gboolean do_children);
GdkGrabStatus gdk_fb_pointer_grab (GdkWindow *window,
gint owner_events,
GdkEventMask event_mask,
GdkWindow *confine_to,
GdkCursor *cursor,
guint32 time,
gboolean implicit_grab);
void gdk_fb_pointer_ungrab (guint32 time,
gboolean implicit_grab);
guint32 gdk_fb_get_time (void);
extern GdkWindow *_gdk_fb_pointer_grab_window, *_gdk_fb_pointer_grab_window_events, *_gdk_fb_keyboard_grab_window, *_gdk_fb_pointer_grab_confine;
extern GdkEventMask _gdk_fb_pointer_grab_events, _gdk_fb_keyboard_grab_events;
......
This diff is collapsed.
......@@ -866,8 +866,8 @@ miComputeWideEllipse(int lw, miArc *parc, gboolean *mustFree)
static void
miFillWideEllipse(GdkDrawable *pDraw, GdkGC *pGC, miArc *parc)
{
GdkRectangle* points;
register GdkRectangle* pts;
GdkSpan* points;
register GdkSpan* pts;
miArcSpanData *spdata;
gboolean mustFree;
register miArcSpan *span;
......@@ -875,7 +875,7 @@ miFillWideEllipse(GdkDrawable *pDraw, GdkGC *pGC, miArc *parc)
register int n;
yorgu = parc->height + GDK_GC_FBDATA(pGC)->values.line_width;
points = ALLOCATE_LOCAL(sizeof(GdkRectangle) * yorgu * 2);
points = ALLOCATE_LOCAL(sizeof(GdkSpan) * yorgu * 2);
spdata = miComputeWideEllipse(GDK_GC_FBDATA(pGC)->values.line_width, parc, &mustFree);
if (!spdata)
{
......@@ -893,7 +893,7 @@ miFillWideEllipse(GdkDrawable *pDraw, GdkGC *pGC, miArc *parc)
{
pts->x = xorg;
pts->y = yorgu - 1;