summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKeith Packard <keithp@neko.keithp.com>2006-11-25 10:05:58 -0800
committerKeith Packard <keithp@neko.keithp.com>2006-11-25 10:05:58 -0800
commitedfcd07f8c11d1eea81781d782f6840dfeec8013 (patch)
tree37ad7aeabdd67cf68fe25273af67c6c08d28e287
parent71a507fe21e135b98f6b43325c33e95220399024 (diff)
parentad435d8881c1a09d95d1895ecc11efe601413c2f (diff)
Merge branch 'master' of ssh://git.freedesktop.org/git/twin
-rw-r--r--Makefile.am30
-rw-r--r--ftwin.c105
-rw-r--r--ftwin.cursorbin0 -> 10004 bytes
-rw-r--r--twin.h22
-rw-r--r--twin_cursor.c238
-rw-r--r--twin_fbdev.c502
-rw-r--r--twin_fbdev.h96
-rw-r--r--twin_linux_mouse.c193
-rw-r--r--twin_linux_mouse.h67
-rw-r--r--twin_screen.c126
10 files changed, 1347 insertions, 32 deletions
diff --git a/Makefile.am b/Makefile.am
index ed2aa9c..99b2fc0 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -11,13 +11,14 @@ INCLUDES= @X_CFLAGS@ @WARN_CFLAGS@
#
#lib_LTLIBRARIES = libtwin.la
-bin_PROGRAMS = xtwin
+bin_PROGRAMS = xtwin ftwin
-xtwin_SOURCES = \
+base_SOURCES = \
twin.h \
twin_box.c \
twin_button.c \
twin_convolve.c \
+ twin_cursor.c \
twin_dispatch.c \
twin_draw.c \
twin_glyphs.c \
@@ -43,15 +44,17 @@ xtwin_SOURCES = \
twin_widget.c \
twin_window.c \
twin_work.c \
- twin_x11.c \
- twin_x11.h \
twinint.h \
twin_clock.c \
twin_clock.h \
twin_calc.c \
twin_calc.h \
twin_text.c \
- twin_text.h \
+ twin_text.h
+
+xtwin_SOURCES = $(base_SOURCES) \
+ twin_x11.c \
+ twin_x11.h \
twin_demo.c \
twin_demo.h \
twin_hello.c \
@@ -62,4 +65,21 @@ xtwin_SOURCES = \
twin_demospline.h \
xtwin.c
+ftwin_SOURCES = $(base_SOURCES) \
+ twin_fbdev.c \
+ twin_fbdev.h \
+ twin_linux_mouse.c \
+ twin_linux_mouse.h \
+ twin_demo.c \
+ twin_demo.h \
+ twin_hello.c \
+ twin_hello.h \
+ twin_demoline.c \
+ twin_demoline.h \
+ twin_demospline.c \
+ twin_demospline.h \
+ ftwin.c
+
xtwin_LDADD = @X_LIBS@ -lm
+
+ftwin_LDADD = -lm
diff --git a/ftwin.c b/ftwin.c
new file mode 100644
index 0000000..1d5c487
--- /dev/null
+++ b/ftwin.c
@@ -0,0 +1,105 @@
+/*
+ * Test shell for twin fbdev & linux mouse driver
+ *
+ * Copyright 2006 Benjamin Herrenschmidt <benh@kernel.crashing.org>
+ *
+ * This Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with the Twin Library; see the file COPYING. If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <time.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <signal.h>
+#include <unistd.h>
+#include <syscall.h>
+#include <twin_clock.h>
+#include <twin_text.h>
+#include <twin_demo.h>
+#include <twin_hello.h>
+#include <twin_calc.h>
+#include <twin_demoline.h>
+#include <twin_demospline.h>
+
+#include "twin_fbdev.h"
+#include "twin_linux_mouse.h"
+
+twin_fbdev_t *tf;
+
+static void exitfunc(void)
+{
+ if (tf)
+ twin_fbdev_destroy(tf);
+ tf = NULL;
+}
+
+static void sigint(int sig)
+{
+ exitfunc();
+ syscall(__NR_exit);
+}
+
+int main (int argc, char **argv)
+{
+ int hx, hy;
+ twin_pixmap_t *cur;
+
+ tf = twin_fbdev_create(-1, SIGUSR1);
+ if (tf == NULL)
+ return 1;
+
+ atexit(exitfunc);
+ signal(SIGINT, sigint);
+
+ twin_linux_mouse_create(NULL, tf->screen);
+
+ cur = twin_load_X_cursor("ftwin.cursor", 0, &hx, &hy);
+ if (cur == NULL)
+ cur = twin_get_default_cursor(&hx, &hy);
+ if (cur != NULL)
+ twin_screen_set_cursor(tf->screen, cur, hx, hy);
+ twin_screen_set_background (tf->screen, twin_make_pattern ());
+#if 0
+ twin_demo_start (tf->screen, "Demo", 100, 100, 400, 400);
+#endif
+#if 0
+ twin_text_start (tf->screen, "Gettysburg Address", 0, 0, 300, 300);
+#endif
+#if 0
+ twin_hello_start (tf->screen, "Hello, World", 0, 0, 200, 200);
+#endif
+#if 1
+ twin_clock_start (tf->screen, "Clock", 10, 10, 200, 200);
+#endif
+#if 1
+ twin_calc_start (tf->screen, "Calculator", 100, 100, 200, 200);
+#endif
+#if 1
+ twin_demoline_start (tf->screen, "Demo Line", 0, 0, 400, 400);
+#endif
+#if 1
+ twin_demospline_start (tf->screen, "Demo Spline", 20, 20, 400, 400);
+#endif
+
+ twin_fbdev_activate(tf);
+
+ twin_dispatch ();
+
+ return 0;
+}
diff --git a/ftwin.cursor b/ftwin.cursor
new file mode 100644
index 0000000..785a7e4
--- /dev/null
+++ b/ftwin.cursor
Binary files differ
diff --git a/twin.h b/twin.h
index befc478..bb30ad4 100644
--- a/twin.h
+++ b/twin.h
@@ -153,6 +153,15 @@ typedef struct _twin_screen {
*/
twin_pixmap_t *pointer;
/*
+ * mouse image (optional)
+ */
+ twin_pixmap_t *cursor;
+ twin_coord_t curs_hx;
+ twin_coord_t curs_hy;
+ twin_coord_t curs_x;
+ twin_coord_t curs_y;
+
+ /*
* Output size
*/
twin_coord_t width, height;
@@ -546,6 +555,15 @@ twin_fill (twin_pixmap_t *dst,
twin_coord_t bottom);
/*
+ * twin_cursor.c
+ */
+twin_pixmap_t *twin_get_default_cursor(int *hx, int *hy);
+
+twin_pixmap_t *twin_load_X_cursor(const char *file, int index,
+ int *hx, int *hy);
+
+
+/*
* twin_event.c
*/
@@ -970,6 +988,10 @@ twin_screen_set_background (twin_screen_t *screen, twin_pixmap_t *pixmap);
twin_pixmap_t *
twin_screen_get_background (twin_screen_t *screen);
+void
+twin_screen_set_cursor (twin_screen_t *screen, twin_pixmap_t *pixmap,
+ twin_fixed_t hotspot_x, twin_fixed_t hotspot_y);
+
twin_bool_t
twin_screen_dispatch (twin_screen_t *screen,
twin_event_t *event);
diff --git a/twin_cursor.c b/twin_cursor.c
new file mode 100644
index 0000000..f0e5fc3
--- /dev/null
+++ b/twin_cursor.c
@@ -0,0 +1,238 @@
+/*
+ * Manipulating twin cursor images
+ *
+ * Copyright 2006 Benjamin Herrenschmidt <benh@kernel.crashing.org>
+ *
+ * This Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with the Twin Library; see the file COPYING. If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <byteswap.h>
+#include <endian.h>
+
+#include "twin.h"
+
+/* Make something better here ! */
+
+static unsigned int twin_def_cursor_image[] = {
+ 0x00000000, 0x88ffffff, 0x88ffffff, 0x00000000,
+ 0x88ffffff, 0xff000000, 0xff000000, 0x88ffffff,
+ 0x88ffffff, 0xff000000, 0xff000000, 0x88ffffff,
+ 0x00000000, 0x88ffffff, 0x88ffffff, 0x00000000,
+};
+
+twin_pixmap_t *twin_get_default_cursor(int *hx, int *hy)
+{
+ twin_pixmap_t *cur;
+ twin_pointer_t data;
+
+ data.argb32 = twin_def_cursor_image;
+ cur = twin_pixmap_create_const(TWIN_ARGB32, 4, 4, 16, data);
+ if (cur == NULL)
+ return NULL;
+ *hx = *hy = 2;
+ return cur;
+}
+
+/*
+ * Bits extracted from Xcursor
+ */
+
+#define XCURSOR_MAGIC 0x72756358 /* "Xcur" LSBFirst */
+
+#define XCURSOR_FILE_MAJOR 1
+#define XCURSOR_FILE_MINOR 0
+#define XCURSOR_FILE_VERSION ((XCURSOR_FILE_MAJOR << 16) | (XCURSOR_FILE_MINOR))
+#define XCURSOR_FILE_HEADER_LEN (4 * 4)
+#define XCURSOR_FILE_TOC_LEN (3 * 4)
+
+/*
+ * Cursor files start with a header. The header
+ * contains a magic number, a version number and a
+ * table of contents which has type and offset information
+ * for the remaining tables in the file.
+ *
+ * File minor versions increment for compatible changes
+ * File major versions increment for incompatible changes (never, we hope)
+ *
+ * Chunks of the same type are always upward compatible. Incompatible
+ * changes are made with new chunk types; the old data can remain under
+ * the old type. Upward compatible changes can add header data as the
+ * header lengths are specified in the file.
+ *
+ * File:
+ * FileHeader
+ * LISTofChunk
+ *
+ * FileHeader:
+ * 0 CARD32 magic magic number
+ * 1 CARD32 header bytes in file header
+ * 2 CARD32 version file version
+ * 3 CARD32 ntoc number of toc entries
+ * LISTofFileToc toc table of contents
+ *
+ * FileToc:
+ * 0 CARD32 type entry type
+ * 1 CARD32 subtype entry subtype (size for images)
+ * 2 CARD32 position absolute file position
+ */
+
+
+/*
+ * The rest of the file is a list of chunks, each tagged by type
+ * and version.
+ *
+ * Chunk:
+ * ChunkHeader
+ * <extra type-specific header fields>
+ * <type-specific data>
+ *
+ * ChunkHeader:
+ * 0 CARD32 header bytes in chunk header + type header
+ * 1 CARD32 type chunk type
+ * 2 CARD32 subtype chunk subtype
+ * 3 CARD32 version chunk type version
+ */
+
+#define XCURSOR_CHUNK_HEADER_LEN (4 * 4)
+
+/*
+ * Each cursor image occupies a separate image chunk.
+ * The length of the image header follows the chunk header
+ * so that future versions can extend the header without
+ * breaking older applications
+ *
+ * Image:
+ * 0 ChunkHeader header chunk header
+ * 4 CARD32 width actual width
+ * 5 CARD32 height actual height
+ * 6 CARD32 xhot hot spot x
+ * 7 CARD32 yhot hot spot y
+ * 8 CARD32 delay animation delay
+ * LISTofCARD32 pixels ARGB pixels
+ */
+
+#define XCURSOR_IMAGE_TYPE 0xfffd0002
+#define XCURSOR_IMAGE_VERSION 1
+#define XCURSOR_IMAGE_HEADER_LEN (XCURSOR_CHUNK_HEADER_LEN + (5*4))
+#define XCURSOR_IMAGE_MAX_SIZE 0x7fff /* 32767x32767 max cursor size */
+
+static inline int twin_read_header(int fd, uint32_t *buf, int size)
+{
+ int i, len;
+
+ len = read(fd, buf, size);
+ if (len != size)
+ return 0;
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+ for (i = 0; i < (len / 4); i++)
+ buf[i] = bswap_32(buf[i]);
+#endif
+ return 1;
+}
+
+twin_pixmap_t *twin_load_X_cursor(const char *file, int index,
+ int *hx, int *hy)
+{
+ int fd, img, i, toccnt;
+ uint32_t buffer[32], filepos, size;
+ twin_pixmap_t *cur = NULL;
+
+ fd = open(file, O_RDONLY);
+ if (fd < 0)
+ return NULL;
+ if (!twin_read_header(fd, buffer, XCURSOR_FILE_HEADER_LEN))
+ goto bail;
+
+ /* check magic */
+ if (buffer[0] != XCURSOR_MAGIC)
+ goto bail;
+
+ /* check version. assume we support all minor versions */
+ if ((buffer[2] >> 16) != XCURSOR_FILE_MAJOR)
+ goto bail;
+
+ /* get number of TOC entries */
+ toccnt = buffer[3];
+
+ /* seek to first toc entry (header len) */
+ lseek(fd, buffer[1] , SEEK_SET);
+
+ /* look for the index'th image in TOC */
+ img = 0;
+ filepos = 0;
+ for (i = 0; filepos == 0 && i < toccnt; i++) {
+ if (!twin_read_header(fd, buffer, XCURSOR_FILE_TOC_LEN))
+ goto bail;
+ if (buffer[0] == XCURSOR_IMAGE_TYPE) {
+ if (img == index)
+ filepos = buffer[2];
+ img++;
+ }
+ }
+ /* check if found */
+ if (filepos == 0)
+ goto bail;
+
+ /* seek to image header and read it */
+ lseek(fd, filepos, SEEK_SET);
+ if (!twin_read_header(fd, buffer, XCURSOR_IMAGE_HEADER_LEN))
+ goto bail;
+
+ /* check chunk type */
+ if (buffer[1] != XCURSOR_IMAGE_TYPE)
+ goto bail;
+
+ /* check image version */
+ if (buffer[3] != XCURSOR_IMAGE_VERSION)
+ goto bail;
+
+ /* get hotspot */
+ *hx = buffer[6];
+ *hy = buffer[7];
+
+ /* create pixmap */
+ cur = twin_pixmap_create(TWIN_ARGB32, buffer[4], buffer[5]);
+ if (cur == NULL)
+ goto bail;
+
+ /* load pixels */
+ size = buffer[4] * buffer[5] * 4;
+ lseek(fd, filepos + buffer[0], SEEK_SET);
+ if (read(fd, cur->p.v, size) != size) {
+ twin_pixmap_destroy(cur);
+ goto bail;
+ }
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+ for (i = 0; i < (size / 4); i++)
+ cur->p.argb32[i] = bswap_32(cur->p.argb32[i]);
+#endif
+
+ bail:
+ close(fd);
+ return cur;
+}
+
diff --git a/twin_fbdev.c b/twin_fbdev.c
new file mode 100644
index 0000000..a1d9472
--- /dev/null
+++ b/twin_fbdev.c
@@ -0,0 +1,502 @@
+/*
+ * Linux fbdev driver for Twin
+ *
+ * Copyright 2006 Benjamin Herrenschmidt <benh@kernel.crashing.org>
+ *
+ * This Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with the Twin Library; see the file COPYING. If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+#include <sys/poll.h>
+#include <termios.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <stdarg.h>
+#include <byteswap.h>
+
+#include <linux/vt.h>
+#include <linux/kd.h>
+#include <linux/input.h>
+
+#include "twin_fbdev.h"
+
+/* We might want to have more error logging options */
+#define SERROR(fmt...) do { fprintf(stderr, fmt); \
+ fprintf(stderr, " : %s\n", strerror(errno)); \
+ } while(0)
+#define IERROR(fmt...) fprintf(stderr, fmt)
+
+#define DEBUG(fmt...) printf(fmt)
+//#define DEBUG(fmt...)
+
+/* Only one instance can exist */
+static twin_fbdev_t *twin_fb;
+static int vt_switch_pending;
+
+static void _twin_fbdev_put_span (twin_coord_t left,
+ twin_coord_t top,
+ twin_coord_t right,
+ twin_argb32_t *pixels,
+ void *closure)
+{
+ twin_fbdev_t *tf = closure;
+ twin_coord_t width = right - left;
+ unsigned int *dest;
+
+ if (!tf->active || tf->fb_base == MAP_FAILED)
+ return;
+
+ dest = (unsigned int *)(tf->fb_ptr + top * tf->fb_fix.line_length);
+ dest += left;
+ while(width--)
+ *(dest++) = *(pixels++);
+}
+
+static twin_bool_t twin_fbdev_apply_config(twin_fbdev_t *tf)
+{
+ off_t off, pgsize = getpagesize();
+ struct fb_cmap cmap;
+ size_t len;
+
+ /* Tweak fields to default to 32 bpp argb and virtual == phys */
+ tf->fb_var.xres_virtual = tf->fb_var.xres;
+ tf->fb_var.yres_virtual = tf->fb_var.yres;
+ tf->fb_var.bits_per_pixel = 32;
+ tf->fb_var.red.length = 8;
+ tf->fb_var.green.length = 8;
+ tf->fb_var.blue.length = 8;
+ tf->fb_var.transp.length = 8;
+ tf->fb_var.red.offset = 0;
+ tf->fb_var.green.offset = 0;
+ tf->fb_var.blue.offset = 0;
+ tf->fb_var.transp.offset = 0;
+
+ /* Apply fbdev settings */
+ if (ioctl(tf->fb_fd, FBIOPUT_VSCREENINFO, &tf->fb_var) < 0) {
+ SERROR("can't set fb mode");
+ return 0;
+ }
+
+ /* Get new fbdev configuration */
+ if (ioctl(tf->fb_fd, FBIOGET_VSCREENINFO, tf->fb_var) < 0) {
+ SERROR("can't get framebuffer config");
+ return 0;
+ }
+
+ DEBUG("fbdev set config set to:\n");
+ DEBUG(" xres = %d\n", tf->fb_var.xres);
+ DEBUG(" yres = %d\n", tf->fb_var.yres);
+ DEBUG(" xres_virtual = %d\n", tf->fb_var.xres_virtual);
+ DEBUG(" yres_virtual = %d\n", tf->fb_var.yres_virtual);
+ DEBUG(" bits_per_pix = %d\n", tf->fb_var.bits_per_pixel);
+ DEBUG(" red.len/off = %d/%d\n",
+ tf->fb_var.red.length, tf->fb_var.red.offset);
+ DEBUG(" green.len/off = %d/%d\n",
+ tf->fb_var.green.length, tf->fb_var.green.offset);
+ DEBUG(" blue.len/off = %d/%d\n",
+ tf->fb_var.blue.length, tf->fb_var.blue.offset);
+ DEBUG(" trans.len/off = %d/%d\n",
+ tf->fb_var.transp.length, tf->fb_var.transp.offset);
+
+ /* Check bits per pixel */
+ if (tf->fb_var.bits_per_pixel != 32) {
+ SERROR("can't set fb bpp to 32");
+ return 0;
+ }
+
+ /* Set colormap */
+ cmap.start = 0;
+ cmap.len = 256;
+ cmap.red = tf->cmap[0];
+ cmap.green = tf->cmap[1];
+ cmap.blue = tf->cmap[2];
+ cmap.transp = NULL;
+ ioctl(tf->fb_fd, FBIOPUTCMAP, &cmap);
+
+ /* Get remaining settings */
+ ioctl(tf->fb_fd, FBIOGET_FSCREENINFO, &tf->fb_fix);
+
+ DEBUG(" line_lenght = %d\n", tf->fb_fix.line_length);
+
+ /* Map the fb */
+ off = (off_t)tf->fb_fix.smem_start & (pgsize - 1);
+ len = (size_t)tf->fb_fix.smem_len + off + (pgsize - 1);
+ len &= ~(pgsize - 1);
+ tf->fb_len = len;
+
+ tf->fb_base = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED,
+ tf->fb_fd, 0);
+ if (tf->fb_base == MAP_FAILED) {
+ SERROR("can't mmap framebuffer");
+ return 0;
+ }
+ tf->fb_ptr = tf->fb_base + off;
+
+ return 1;
+}
+
+static void twin_fbdev_switch(twin_fbdev_t *tf, int activate)
+{
+ tf->vt_active = activate;
+
+ DEBUG("console switch: %sactivating\n", activate ? "" : "de");
+
+ /* Upon activation */
+ if (activate) {
+ /* Switch complete */
+ ioctl(tf->vt_fd, VT_RELDISP, VT_ACKACQ);
+
+ /* Restore fbdev settings */
+ if (twin_fbdev_apply_config(tf)) {
+ /* Mark entire screen for refresh */
+ if (tf->screen)
+ twin_screen_damage (tf->screen, 0, 0,
+ tf->screen->width,
+ tf->screen->height);
+ tf->active = 1;
+ }
+ } else {
+ /* Allow switch. Maybe we want to expose some option
+ * to disallow them ?
+ */
+ ioctl(tf->vt_fd, VT_RELDISP, 1);
+
+ tf->active = 0;
+
+ if (tf->fb_base != MAP_FAILED)
+ munmap(tf->fb_base, tf->fb_len);
+ tf->fb_base = MAP_FAILED;
+ }
+}
+
+static twin_bool_t twin_fbdev_work(void *closure)
+{
+ twin_fbdev_t *tf = closure;
+
+ if (vt_switch_pending) {
+ twin_fbdev_switch(tf, !tf->vt_active);
+ vt_switch_pending = 0;
+ }
+
+ if (tf->screen && tf->active &&
+ twin_screen_damaged (tf->screen))
+ twin_screen_update(tf->screen);
+ return TWIN_TRUE;
+}
+
+static void twin_fbdev_vtswitch(int sig)
+{
+ signal(sig, twin_fbdev_vtswitch);
+ vt_switch_pending = 1;
+}
+
+static twin_bool_t twin_fbdev_read_events(int file, twin_file_op_t ops,
+ void *closure)
+{
+ twin_fbdev_t *tf = closure;
+ unsigned char events[16];
+ int i, count;
+
+ count = read(file, events, 16);
+
+ for (i = 0; i < count; i++) {
+ unsigned char e = events[i];
+
+ /* Handle special keys */
+ switch(e) {
+ case KEY_F1...KEY_F10:
+ ioctl(tf->vt_fd, VT_ACTIVATE, e - KEY_F1 + 1);
+ break;
+ case KEY_ESC:
+ kill(0, SIGINT);
+ break;
+ }
+ }
+
+ return 1;
+}
+
+static twin_bool_t twin_fbdev_get_vt(twin_fbdev_t *tf, int wanted_vt)
+{
+ struct vt_stat vts;
+ int ttyfd;
+ char vtname[16];
+
+ /* Open tty0 and use it to look for a free vt */
+ ttyfd = open("/dev/tty0", O_WRONLY);
+ if (ttyfd < 0) {
+ SERROR("can't open /dev/tty0");
+ ttyfd = open("/dev/vc/0", O_WRONLY);
+ if (ttyfd < 0) {
+ SERROR("can't open /dev/vc/0");
+ return 0;
+ }
+ }
+ /* Get previous VT */
+ if (ioctl(ttyfd, VT_GETSTATE, &vts) < 0) {
+ SERROR("can't get current VT");
+ return 0;
+ }
+ tf->vt_prev = vts.v_active;
+
+ DEBUG("previous vt: %d\n", tf->vt_prev);
+
+ /* Sanity check wanted_vt and try to obtain a free VT. This is
+ * all somewhat racy but that's how everybody does it.
+ */
+ if (wanted_vt > 31)
+ wanted_vt = -1;
+ if (wanted_vt > 0 && (vts.v_state & (1 << wanted_vt))) {
+ IERROR("vt%d is busy\n", wanted_vt);
+ wanted_vt = -1;
+ }
+ if (wanted_vt < 0)
+ if (ioctl(ttyfd, VT_OPENQRY, &wanted_vt) < 0)
+ wanted_vt = -1;
+ if (wanted_vt < 0) {
+ IERROR("can't find a free VT");
+ return 0;
+ }
+
+ tf->vt_no = wanted_vt;
+
+ DEBUG("new vt: %d\n", tf->vt_no);
+
+
+ /* we don't need tty0 anymore, close it and open the target VT. */
+ close(ttyfd);
+
+ /* lose tty */
+ setpgrp();
+ if ((ttyfd = open("/dev/tty", O_RDWR)) >= 0) {
+ ioctl(ttyfd, TIOCNOTTY, 0);
+ close(ttyfd);
+ }
+
+ sprintf(vtname, "/dev/tty%d", tf->vt_no);
+ tf->vt_fd = open(vtname, O_RDWR | O_NONBLOCK);
+ if (tf->vt_fd < 0) {
+ sprintf(vtname, "/dev/vc/%d", tf->vt_no);
+ tf->vt_fd = open(vtname, O_RDWR | O_NONBLOCK);
+ }
+ if (tf->vt_fd < 0) {
+ SERROR("can't open tty %d", tf->vt_no);
+ return 0;
+ }
+
+ /* set new controlling terminal */
+ ioctl(tf->vt_fd, TIOCSCTTY, 1);
+
+ /* set keyboard mode */
+ ioctl(tf->vt_fd, KDSKBMODE, K_XLATE);
+
+ tf->vt_active = tf->active = 0;
+
+ return 1;
+}
+
+static twin_bool_t twin_fbdev_setup_vt(twin_fbdev_t *tf, int switch_sig)
+{
+ struct vt_mode vtm;
+ struct termios tio;
+
+ if (ioctl(tf->vt_fd, VT_GETMODE, &vtm) < 0) {
+ SERROR("can't get VT mode");
+ return 0;
+ }
+ vtm.mode = VT_PROCESS;
+ vtm.relsig = switch_sig;
+ vtm.acqsig = switch_sig;
+
+ signal(switch_sig, twin_fbdev_vtswitch);
+ tf->vt_swsig = switch_sig;
+
+ if (ioctl(tf->vt_fd, VT_SETMODE, &vtm) < 0) {
+ SERROR("can't set VT mode");
+ signal(switch_sig, SIG_IGN);
+ return 0;
+ }
+
+ tcgetattr(tf->vt_fd, &tf->old_tio);
+
+ ioctl(tf->vt_fd, KDGKBMODE, &tf->old_kbmode);
+ ioctl(tf->vt_fd, KDSKBMODE, K_MEDIUMRAW);
+
+ tio = tf->old_tio;
+ tio.c_iflag = (IGNPAR | IGNBRK) & (~PARMRK) & (~ISTRIP);
+ tio.c_oflag = 0;
+ tio.c_cflag = CREAD | CS8;
+ tio.c_lflag = 0;
+ tio.c_cc[VTIME]=0;
+ tio.c_cc[VMIN]=1;
+ cfsetispeed(&tio, 9600);
+ cfsetospeed(&tio, 9600);
+ tcsetattr(tf->vt_fd, TCSANOW, &tio);
+
+ ioctl(tf->vt_fd, KDSETMODE, KD_GRAPHICS);
+
+ return 1;
+}
+
+static twin_bool_t twin_fbdev_init_fb(twin_fbdev_t *tf)
+{
+ int i;
+
+ /* We always open /dev/fb0 for now. Might want fixing */
+ tf->fb_fd = open("/dev/fb0", O_RDWR);
+ if (tf->fb_fd < 0) {
+ SERROR("can't open /dev/fb0");
+ return 0;
+ }
+
+ /* Get initial fbdev configuration */
+ if (ioctl(tf->fb_fd, FBIOGET_VSCREENINFO, &tf->fb_var) < 0) {
+ SERROR("can't get framebuffer config");
+ return 0;
+ }
+
+ DEBUG("initial screen size: %dx%d\n",
+ tf->fb_var.xres, tf->fb_var.yres);
+
+ tf->fb_base = MAP_FAILED;
+
+ for (i = 0; i < 256; i++) {
+ unsigned short c = (i << 8) | i;
+ tf->cmap[0][i] = tf->cmap[1][i] = tf->cmap[2][i] = c;
+ }
+
+ return 1;
+}
+
+static twin_bool_t twin_fbdev_init_screen(twin_fbdev_t *tf)
+{
+ tf->screen = twin_screen_create(tf->fb_var.xres,
+ tf->fb_var.yres,
+ NULL,
+ _twin_fbdev_put_span, tf);
+ if (tf->screen == NULL) {
+ IERROR("can't create twin screen");
+ return 0;
+ }
+
+ return 1;
+}
+
+static void twin_fbdev_cleanup_vt(twin_fbdev_t *tf)
+{
+ struct vt_mode vtm;
+
+ ioctl(tf->vt_fd, VT_GETMODE, &vtm);
+ vtm.mode = VT_AUTO;
+ vtm.relsig = 0;
+ vtm.acqsig = 0;
+ ioctl(tf->vt_fd, VT_SETMODE, &vtm);
+
+ signal(tf->vt_swsig, SIG_DFL);
+
+ tcsetattr(tf->vt_fd, TCSANOW, &tf->old_tio);
+ ioctl(tf->vt_fd, KDSKBMODE, tf->old_kbmode);
+
+ ioctl(tf->vt_fd, KDSETMODE, KD_TEXT);
+ ioctl(tf->vt_fd, VT_ACTIVATE, tf->vt_prev);
+ ioctl(tf->vt_fd, VT_WAITACTIVE, tf->vt_prev);
+}
+
+twin_fbdev_t *twin_fbdev_create(int wanted_vt, int switch_sig)
+{
+ twin_fbdev_t *tf;
+
+ if (twin_fb != NULL) {
+ IERROR("twin_fbdev supports only one instance");
+ return NULL;
+ }
+
+ tf = calloc(1, sizeof(twin_fbdev_t));
+ if (tf == NULL)
+ return NULL;
+
+ if (!twin_fbdev_get_vt(tf, wanted_vt))
+ goto err_free;
+
+ if (!twin_fbdev_setup_vt(tf, switch_sig))
+ goto err_release;
+
+ if (!twin_fbdev_init_fb(tf))
+ goto err_reset_vt;
+
+ if (!twin_fbdev_init_screen(tf))
+ goto err_close_fb;
+
+ twin_set_work(twin_fbdev_work, TWIN_WORK_REDISPLAY, tf);
+
+ twin_set_file(twin_fbdev_read_events, tf->vt_fd, TWIN_READ, tf);
+
+ twin_fb = tf;
+ return tf;
+
+ err_close_fb:
+ close(tf->fb_fd);
+ err_reset_vt:
+ twin_fbdev_cleanup_vt(tf);
+ signal(switch_sig, SIG_DFL);
+ err_release:
+ close(tf->vt_fd);
+ err_free:
+ free(tf);
+ return NULL;
+}
+
+void twin_fbdev_destroy(twin_fbdev_t *tf)
+{
+ tf->active = 0;
+ twin_fbdev_cleanup_vt(tf);
+ close(tf->fb_fd);
+ close(tf->vt_fd);
+ free(tf);
+ twin_fb = NULL;
+}
+
+twin_bool_t twin_fbdev_activate(twin_fbdev_t *tf)
+{
+ /* If VT is not active, try to activate it. We don't deadlock
+ * here thanks to linux not waiting for VT_RELDISP on the target
+ * but we might want to be more careful
+ */
+ if (!tf->vt_active) {
+ if (ioctl(tf->vt_fd, VT_ACTIVATE, tf->vt_no) < 0)
+ return 0;
+ if (ioctl(tf->vt_fd, VT_WAITACTIVE, tf->vt_no) < 0)
+ return 0;
+ }
+
+ /* Run work to process the VT switch */
+ twin_fbdev_work(tf);
+
+ /* If the screen is not active, then we failed
+ * the fbdev configuration
+ */
+ return tf->active;
+}
+
diff --git a/twin_fbdev.h b/twin_fbdev.h
new file mode 100644
index 0000000..0b3bcb3
--- /dev/null
+++ b/twin_fbdev.h
@@ -0,0 +1,96 @@
+/*
+ * Linux fbdev driver for Twin
+ *
+ * Copyright 2006 Benjamin Herrenschmidt <benh@kernel.crashing.org>
+ *
+ * This Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with the Twin Library; see the file COPYING. If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#ifndef _TWIN_FBDEV_H_
+#define _TWIN_FBDEV_H_
+
+#include "twin.h"
+
+#include <termios.h>
+#include <linux/fb.h>
+
+typedef struct _twin_fbdev {
+ twin_screen_t *screen; /* twin screen */
+
+ int vt_no; /* my VT */
+ int vt_prev; /* previous VT */
+ int vt_fd; /* my tty fd */
+ int vt_active; /* vt is currently active */
+ int vt_swsig;
+
+ struct termios old_tio; /* old termios */
+ int old_kbmode;
+
+ int active; /* screen is active and useable */
+ int fb_fd; /* my fbdev fd */
+ int last_btn; /* last button state */
+
+ /* fbdev setup */
+ struct fb_var_screeninfo fb_var;
+ struct fb_fix_screeninfo fb_fix;
+ unsigned short cmap[3][256];
+ char *fb_base;
+ size_t fb_len;
+ char *fb_ptr;
+
+} twin_fbdev_t;
+
+/**
+ * twin_fbdev_create - create the fbdev backend
+ * @wanted_vt: which VT do you want ? pass -1 for auto-choose
+ * @switch_sig: signal for use internally for vt switch
+ *
+ * The new VT is not activated automatically. You can call
+ * twin_fbdev_activate() to do that. That way, you can setup your
+ * environment completely before you do the VT switch for smoother
+ * transitions.
+ *
+ * The fbdev is left to it's default settings. You can call functions
+ * to change them though they will only be applied if the fbdev is
+ * frontmost or when it is activated.
+ *
+ * Note that this implementation only supports 32bpp argb though it
+ * shouldn't be too hard to change that.
+ *
+ * Regarding the signal passed in switch_sig, it's the responsibility
+ * of the caller to make sure it's not blocked.
+ */
+
+twin_fbdev_t *twin_fbdev_create(int wanted_vt, int switch_sig);
+
+/**
+ * twin_fbdev_destroy - distroy the fbdev backend
+ * @tf: backend pointed returned by twin_fbdev_create
+ */
+void twin_fbdev_destroy(twin_fbdev_t *tf);
+
+/**
+ * twin_fbdev_activate - activate the fbdev
+ * @tf: backemd pointer
+ *
+ * This triggers a console switch to the VT allocated to the
+ * twin screen. It returns false if the activation failed
+ * due to unsupported framebuffer settings or the VT switch
+ * was refused.
+ */
+twin_bool_t twin_fbdev_activate(twin_fbdev_t *tf);
+
+
+#endif /* _TWIN_FBDEV_H_ */
diff --git a/twin_linux_mouse.c b/twin_linux_mouse.c
new file mode 100644
index 0000000..c755495
--- /dev/null
+++ b/twin_linux_mouse.c
@@ -0,0 +1,193 @@
+/*
+ * Linux mouse driver for Twin
+ *
+ * Copyright 2006 Benjamin Herrenschmidt <benh@kernel.crashing.org>
+ *
+ * This Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with the Twin Library; see the file COPYING. If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <math.h>
+
+#include "twin_linux_mouse.h"
+
+#define QUADRATIC_ACCELERATION 1
+#define DEFAULT_ACC_NUMERATOR 2
+#define DEFAULT_ACC_DENOMINATOR 1
+#define DEFAULT_ACC_THRESHOLD 4
+
+static void twin_linux_mouse_check_bounds(twin_linux_mouse_t *tm)
+{
+ if (tm->x < 0)
+ tm->x = 0;
+ if (tm->x > tm->screen->width)
+ tm->x = tm->screen->width;
+ if (tm->y < 0)
+ tm->y = 0;
+ if (tm->y > tm->screen->height)
+ tm->y = tm->screen->height;
+}
+
+/* This is directly copied from kdrive */
+static void twin_linux_mouse_accel(twin_linux_mouse_t *tm, int *dx, int *dy)
+{
+ double speed = sqrt (*dx * *dx + *dy * *dy);
+ double accel;
+#ifdef QUADRATIC_ACCELERATION
+ double m;
+
+ /*
+ * Ok, so we want it moving num/den times faster at threshold*2
+ *
+ * accel = m *threshold + b
+ * 1 = m * 0 + b -> b = 1
+ *
+ * num/den = m * (threshold * 2) + 1
+ *
+ * num / den - 1 = m * threshold * 2
+ * (num / den - 1) / threshold * 2 = m
+ */
+ m = (((double) tm->acc_num / (double) tm->acc_den - 1.0) /
+ ((double) tm->acc_threshold * 2.0));
+ accel = m * speed + 1;
+#else
+ accel = 1.0;
+ if (speed > tm->acc_threshold)
+ accel = (double) tm->acc_num / tm->acc_den;
+#endif
+ *dx = accel * *dx;
+ *dy = accel * *dy;
+}
+
+static twin_bool_t twin_linux_mouse_events(int file, twin_file_op_t ops,
+ void *closure)
+{
+ twin_linux_mouse_t *tm = closure;
+ char evts[34];
+ char *ep;
+ int n = tm->res_cnt;
+ twin_event_t tev;
+
+ if (n)
+ memcpy(evts, tm->residual, n);
+ n += read(file, evts + n, 32);
+
+ for(ep = evts; n >= 3; n -= 3, ep += 3) {
+ int dx, dy, btn;
+ dx = ep[1];
+ if (ep[0] & 0x10)
+ dx -= 256;
+ dy = ep[2];
+ if (ep[0] & 0x20)
+ dy -= 256;
+ dy = -dy;
+ /* we handle only one btn for now */
+ btn = ep[0] & 0x1;
+ if (dx || dy) {
+ twin_linux_mouse_accel(tm, &dx, &dy);
+ tm->x += dx;
+ tm->y += dy;
+ twin_linux_mouse_check_bounds(tm);
+ tev.kind = TwinEventMotion;
+ tev.u.pointer.screen_x = tm->x;
+ tev.u.pointer.screen_y = tm->y;
+ tev.u.pointer.button = tm->btns;
+ twin_screen_dispatch (tm->screen, &tev);
+ }
+ if (btn != tm->btns) {
+ tm->btns = btn;
+ tev.kind = (btn & 0x1) ?
+ TwinEventButtonDown : TwinEventButtonUp;
+ tev.u.pointer.screen_x = tm->x;
+ tev.u.pointer.screen_y = tm->y;
+ tev.u.pointer.button = tm->btns;
+ twin_screen_dispatch(tm->screen, &tev);
+ }
+ }
+ tm->res_cnt = n;
+ if (n)
+ memcpy(tm->residual, ep, n);
+
+ return 1;
+}
+
+twin_linux_mouse_t *twin_linux_mouse_create(const char *file,
+ twin_screen_t *screen)
+{
+ twin_linux_mouse_t *tm;
+
+ tm = calloc(1, sizeof(twin_linux_mouse_t));
+ if (tm == NULL)
+ return NULL;
+
+ if (file == NULL)
+ file = "/dev/input/mice";
+
+ tm->screen = screen;
+ tm->acc_num = DEFAULT_ACC_NUMERATOR;
+ tm->acc_den = DEFAULT_ACC_DENOMINATOR;
+ tm->acc_threshold =DEFAULT_ACC_THRESHOLD;
+ tm->x = screen->width / 2;
+ tm->y = screen->height / 2;
+ tm->fd = open(file, O_RDONLY);
+ if (tm->fd < 0) {
+ free(tm);
+ return NULL;
+ }
+
+ twin_set_file(twin_linux_mouse_events, tm->fd, TWIN_READ, tm);
+
+ return tm;
+}
+
+void twin_linux_mouse_destroy(twin_linux_mouse_t *tm)
+{
+ close(tm->fd);
+ free(tm);
+}
+
+void twin_linux_mouse_screen_changed(twin_linux_mouse_t *tm)
+{
+ int oldx, oldy;
+
+ oldx = tm->x;
+ oldy = tm->y;
+ twin_linux_mouse_check_bounds(tm);
+ if (tm->x != oldx || tm->y != oldy) {
+ twin_event_t tev;
+
+ tev.kind = TwinEventMotion;
+ tev.u.pointer.screen_x = tm->x;
+ tev.u.pointer.screen_y = tm->y;
+ tev.u.pointer.button = tm->btns;
+ twin_screen_dispatch (tm->screen, &tev);
+ }
+}
+
+void twin_linux_mouse_set_accel(twin_linux_mouse_t *tm,
+ int num, int den, int threshold)
+{
+ tm->acc_num = num;
+ tm->acc_den = den;
+ tm->acc_threshold = threshold;
+}
diff --git a/twin_linux_mouse.h b/twin_linux_mouse.h
new file mode 100644
index 0000000..1f6cc0c
--- /dev/null
+++ b/twin_linux_mouse.h
@@ -0,0 +1,67 @@
+/*
+ * Linux mouse driver for Twin
+ *
+ * Copyright 2006 Benjamin Herrenschmidt <benh@kernel.crashing.org>
+ *
+ * This Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with the Twin Library; see the file COPYING. If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#ifndef _TWIN_LINUX_MOUSE_H_
+#define _TWIN_LINUX_MOUSE_H_
+
+#include "twin.h"
+
+typedef struct _twin_linux_mouse {
+ twin_screen_t *screen;
+
+ /* acceleration settings */
+ int acc_num;
+ int acc_den;
+ int acc_threshold;
+
+ /* internals */
+ int fd;
+ char residual[2];
+ int res_cnt;
+ int btns;
+ int x,y;
+} twin_linux_mouse_t;
+
+/**
+ * twin_linux_mouse_create - create the linux mouse driver
+ * @file: device file to open, pass NULL for default
+ */
+twin_linux_mouse_t *twin_linux_mouse_create(const char *file,
+ twin_screen_t *screen);
+
+/**
+ * twin_linux_mouse_destroy - destroy the linux mouse driver
+ */
+void twin_linux_mouse_destroy(twin_linux_mouse_t *tm);
+
+/**
+ * twin_linux_mouse_set_bounds - set mouse boundaries
+ */
+void twin_linux_mouse_screen_changed(twin_linux_mouse_t *tm);
+
+
+/**
+ * twin_linux_mouse_set_accel - set mouse acceleration data
+ */
+
+void twin_linux_mouse_set_accel(twin_linux_mouse_t *tm,
+ int num, int den, int threshold);
+
+#endif /* _TWIN_LINUX_MOUSE_H_ */
diff --git a/twin_screen.c b/twin_screen.c
index c5e489a..8de8007 100644
--- a/twin_screen.c
+++ b/twin_screen.c
@@ -28,7 +28,7 @@ twin_screen_create (twin_coord_t width,
twin_put_span_t put_span,
void *closure)
{
- twin_screen_t *screen = malloc (sizeof (twin_screen_t));
+ twin_screen_t *screen = calloc (1, sizeof (twin_screen_t));
if (!screen)
return 0;
screen->top = 0;
@@ -93,6 +93,15 @@ twin_screen_damage (twin_screen_t *screen,
twin_coord_t left, twin_coord_t top,
twin_coord_t right, twin_coord_t bottom)
{
+ if (left < 0)
+ left = 0;
+ if (top < 0)
+ top = 0;
+ if (right > screen->width)
+ right = screen->width;
+ if (bottom > screen->height)
+ bottom = screen->height;
+
if (screen->damage.left == screen->damage.right)
{
screen->damage.left = left;
@@ -131,6 +140,37 @@ twin_screen_damaged (twin_screen_t *screen)
screen->damage.top < screen->damage.bottom);
}
+static void
+twin_screen_span_pixmap(twin_screen_t *screen, twin_argb32_t *span,
+ twin_pixmap_t *p, twin_coord_t y,
+ twin_coord_t left, twin_coord_t right)
+{
+ twin_pointer_t dst;
+ twin_source_u src;
+ twin_coord_t p_left, p_right;
+
+ /* bounds check in y */
+ if (y < p->y)
+ return;
+ if (p->y + p->height <= y)
+ return;
+ /* bounds check in x*/
+ 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)
+ return;
+ 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, p_right - p_left);
+ else
+ _twin_argb32_over_argb32 (dst, src, p_right - p_left);
+}
+
void
twin_screen_update (twin_screen_t *screen)
{
@@ -139,6 +179,11 @@ twin_screen_update (twin_screen_t *screen)
twin_coord_t right = screen->damage.right;
twin_coord_t bottom = screen->damage.bottom;
+ if (right > screen->width)
+ right = screen->width;
+ if (bottom > screen->height)
+ bottom = screen->height;
+
if (!screen->disable && left < right && top < bottom)
{
twin_argb32_t *span;
@@ -181,33 +226,14 @@ twin_screen_update (twin_screen_t *screen)
}
else
memset (span, 0xff, width * sizeof (twin_argb32_t));
+
for (p = screen->bottom; p; p = p->up)
- {
- twin_pointer_t dst;
- twin_source_u src;
- 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*/
- 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 + (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, p_right - p_left);
- else
- _twin_argb32_over_argb32 (dst, src, p_right - p_left);
- }
+ twin_screen_span_pixmap(screen, span, p, y, left, right);
+
+ if (screen->cursor)
+ twin_screen_span_pixmap(screen, span, screen->cursor,
+ y, left, right);
+
(*screen->put_span) (left, y, right, span, screen->closure);
}
free (span);
@@ -253,6 +279,50 @@ twin_screen_get_background (twin_screen_t *screen)
return screen->background;
}
+static void
+twin_screen_damage_cursor(twin_screen_t *screen)
+{
+ twin_screen_damage (screen,
+ screen->cursor->x,
+ screen->cursor->y,
+ screen->cursor->x + screen->cursor->width,
+ screen->cursor->y + screen->cursor->height);
+}
+
+void
+twin_screen_set_cursor (twin_screen_t *screen, twin_pixmap_t *pixmap,
+ twin_fixed_t hotspot_x, twin_fixed_t hotspot_y)
+{
+ if (screen->cursor) {
+ twin_screen_damage_cursor(screen);
+ twin_pixmap_destroy(screen->cursor);
+ }
+ screen->cursor = pixmap;
+ screen->curs_hx = hotspot_x;
+ screen->curs_hy = hotspot_y;
+ pixmap->x = screen->curs_x - hotspot_x;
+ pixmap->y = screen->curs_y - hotspot_y;
+ if (pixmap)
+ twin_screen_damage_cursor(screen);
+}
+
+static void
+twin_screen_update_cursor(twin_screen_t *screen,
+ twin_coord_t x, twin_coord_t y)
+{
+ if (screen->cursor)
+ twin_screen_damage_cursor(screen);
+
+ screen->curs_x = x;
+ screen->curs_y = y;
+
+ if (screen->cursor) {
+ screen->cursor->x = screen->curs_x - screen->curs_hx;
+ screen->cursor->y = screen->curs_y - screen->curs_hy;
+ twin_screen_damage_cursor(screen);
+ }
+}
+
twin_bool_t
twin_screen_dispatch (twin_screen_t *screen,
twin_event_t *event)
@@ -263,6 +333,8 @@ twin_screen_dispatch (twin_screen_t *screen,
case TwinEventMotion:
case TwinEventButtonDown:
case TwinEventButtonUp:
+ twin_screen_update_cursor(screen, event->u.pointer.screen_x,
+ event->u.pointer.screen_y);
pixmap = screen->pointer;
if (!pixmap)
{