fbui | Framebuffer-based graphical environment |
| download: https://git.y1.nz/archives/fbui.tar.gz | |
| README | Files | Log | Refs |
commit bc30ae8fbf9a807857cfcd0af12b21d01c679155 Author: Uriel <uriel@berlinblue.org> Date: Fri, 24 Jun 2016 07:39:38 +0900 CFOS Diffstat:
| A | drivers/char/n_tty.c | 1575 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | drivers/char/vt_ioctl.c | 1221 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | drivers/input/Kconfig | 165 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | drivers/input/Makefile | 21 | +++++++++++++++++++++ |
| A | drivers/input/fbui-input.c | 140 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | drivers/input/fbui-input.o | 0 | |
| A | drivers/video/Kconfig | 1054 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | drivers/video/Makefile | 102 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | drivers/video/console/fbcon.c | 2890 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | drivers/video/fbmem.c | 1449 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | drivers/video/fbui.c | 4379 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | drivers/video/vesafb.c | 457 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | drivers/video/vga16fb.c | 1490 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | include/linux/fb.h | 1209 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | include/linux/input.h | 999 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | libfbui/API.txt | 139 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | libfbui/BUGS | 12 | ++++++++++++ |
| A | libfbui/COPYING | 280 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | libfbui/Calc/COPYING | 280 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | libfbui/Calc/Makefile | 15 | +++++++++++++++ |
| A | libfbui/Calc/main.c | 512 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | libfbui/Clock/COPYING | 280 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | libfbui/Clock/Makefile | 15 | +++++++++++++++ |
| A | libfbui/Clock/main.c | 206 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | libfbui/Dump/COPYING | 280 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | libfbui/Dump/Makefile | 14 | ++++++++++++++ |
| A | libfbui/Dump/jpeg.c | 268 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | libfbui/Dump/main.c | 195 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | libfbui/FBUI.txt | 48 | ++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | libfbui/FONTS | 4 | ++++ |
| A | libfbui/Launcher/COPYING | 280 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | libfbui/Launcher/Makefile | 15 | +++++++++++++++ |
| A | libfbui/Launcher/README | 9 | +++++++++ |
| A | libfbui/Launcher/main.c | 366 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | libfbui/LoadMonitor/COPYING | 280 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | libfbui/LoadMonitor/Makefile | 15 | +++++++++++++++ |
| A | libfbui/LoadMonitor/main.c | 185 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | libfbui/MPEG/CHANGES | 95 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | libfbui/MPEG/EXAMPLES | 49 | +++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | libfbui/MPEG/IEEE1180 | 245 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | libfbui/MPEG/Makefile | 99 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | libfbui/MPEG/README | 59 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | libfbui/MPEG/README2 | 4 | ++++ |
| A | libfbui/MPEG/SPATIAL.DOC | 154 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | libfbui/MPEG/TODO | 73 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | libfbui/MPEG/config.h | 44 | ++++++++++++++++++++++++++++++++++++++++++++ |
| A | libfbui/MPEG/display.c | 1218 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | libfbui/MPEG/getbits.c | 202 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | libfbui/MPEG/getblk.c | 570 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | libfbui/MPEG/gethdr.c | 1077 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | libfbui/MPEG/getpic.c | 1225 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | libfbui/MPEG/getvlc.c | 799 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | libfbui/MPEG/getvlc.h | 491 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | libfbui/MPEG/global.h | 489 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | libfbui/MPEG/idct.c | 211 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | libfbui/MPEG/idctref.c | 108 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | libfbui/MPEG/motion.c | 236 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | libfbui/MPEG/mpeg2dec.c | 774 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | libfbui/MPEG/mpeg2dec.h | 129 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | libfbui/MPEG/recon.c | 467 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | libfbui/MPEG/spatscal.c | 331 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | libfbui/MPEG/store.c | 749 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | libfbui/MPEG/subspic.c | 392 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | libfbui/MPEG/systems.c | 200 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | libfbui/MPEG/verify.c | 303 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | libfbui/MailCheck/COPYING | 280 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | libfbui/MailCheck/Makefile | 15 | +++++++++++++++ |
| A | libfbui/MailCheck/check.c | 164 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | libfbui/MailCheck/main.c | 168 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | libfbui/Makefile | 13 | +++++++++++++ |
| A | libfbui/MultiTest/COPYING | 280 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | libfbui/MultiTest/Makefile | 15 | +++++++++++++++ |
| A | libfbui/MultiTest/fbmtest | 0 | |
| A | libfbui/MultiTest/main.c | 172 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | libfbui/PanelManager/COPYING | 280 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | libfbui/PanelManager/Makefile | 15 | +++++++++++++++ |
| A | libfbui/PanelManager/README | 19 | +++++++++++++++++++ |
| A | libfbui/PanelManager/TODO | 3 | +++ |
| A | libfbui/PanelManager/jpeg.c | 318 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | libfbui/PanelManager/main.c | 936 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | libfbui/PanelManager/rect.c | 389 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | libfbui/README | 42 | ++++++++++++++++++++++++++++++++++++++++++ |
| A | libfbui/Scribble/COPYING | 280 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | libfbui/Scribble/Makefile | 15 | +++++++++++++++ |
| A | libfbui/Scribble/fbscribble | 0 | |
| A | libfbui/Scribble/main.c | 365 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | libfbui/Start/COPYING | 280 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | libfbui/Start/Makefile | 15 | +++++++++++++++ |
| A | libfbui/Start/TODO | 3 | +++ |
| A | libfbui/Start/fbstart | 0 | |
| A | libfbui/Start/main.c | 145 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | libfbui/TODO | 32 | ++++++++++++++++++++++++++++++++ |
| A | libfbui/Term/COPYING | 280 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | libfbui/Term/Makefile | 14 | ++++++++++++++ |
| A | libfbui/Term/README | 24 | ++++++++++++++++++++++++ |
| A | libfbui/Term/ansi.c | 824 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | libfbui/Term/fbterm.c | 464 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | libfbui/Term/fbterm.h | 136 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | libfbui/Term/fbterm.termcap | 22 | ++++++++++++++++++++++ |
| A | libfbui/Term/fbterm.terminfo | 109 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | libfbui/Term/forkpty.c | 111 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | libfbui/Term/iswprint.c | 14 | ++++++++++++++ |
| A | libfbui/Term/main.c | 792 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | libfbui/Term/old-docs/AUTHORS | 37 | +++++++++++++++++++++++++++++++++++++ |
| A | libfbui/Term/old-docs/ChangeLog | 110 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | libfbui/Term/old-docs/INSTALL | 229 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | libfbui/Term/old-docs/TODO | 19 | +++++++++++++++++++ |
| A | libfbui/Term/old-docs/tmp | 0 | |
| A | libfbui/Test/COPYING | 280 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | libfbui/Test/Makefile | 15 | +++++++++++++++ |
| A | libfbui/Test/main.c | 398 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | libfbui/ToDo/COPYING | 280 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | libfbui/ToDo/Makefile | 15 | +++++++++++++++ |
| A | libfbui/ToDo/README | 4 | ++++ |
| A | libfbui/ToDo/main.c | 331 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | libfbui/Viewer/497_1031_3.tif | 0 | |
| A | libfbui/Viewer/COPYING | 280 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | libfbui/Viewer/Makefile | 15 | +++++++++++++++ |
| A | libfbui/Viewer/README | 14 | ++++++++++++++ |
| A | libfbui/Viewer/TODO | 11 | +++++++++++ |
| A | libfbui/Viewer/h_opportunity_rock0113_02.jpg | 0 | |
| A | libfbui/Viewer/jpeg.c | 187 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | libfbui/Viewer/main.c | 746 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | libfbui/Viewer/meander.jpg | 0 | |
| A | libfbui/WindowManager/COPYING | 280 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | libfbui/WindowManager/Makefile | 15 | +++++++++++++++ |
| A | libfbui/WindowManager/README | 5 | +++++ |
| A | libfbui/WindowManager/jpeg.c | 318 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | libfbui/WindowManager/main.c | 313 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | libfbui/WindowManager/rect.c | 389 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | libfbui/cleanall.sh | 13 | +++++++++++++ |
| A | libfbui/clouds.jpg | 0 | |
| A | libfbui/install.sh | 16 | ++++++++++++++++ |
| A | libfbui/libfbui.c | 2428 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | libfbui/libfbui.h | 217 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | libfbui/makeall.sh | 23 | +++++++++++++++++++++++ |
| A | libfbui/start-fbwm.sh | 21 | +++++++++++++++++++++ |
| A | libfbui/start.sh | 45 | +++++++++++++++++++++++++++++++++++++++++++++ |
138 files changed, 45730 insertions(+), 0 deletions(-)
diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c @@ -0,0 +1,1575 @@ +/* + * n_tty.c --- implements the N_TTY line discipline. + * + * This code used to be in tty_io.c, but things are getting hairy + * enough that it made sense to split things off. (The N_TTY + * processing has changed so much that it's hardly recognizable, + * anyway...) + * + * Note that the open routine for N_TTY is guaranteed never to return + * an error. This is because Linux will fall back to setting a line + * to N_TTY if it can not switch to any other line discipline. + * + * Written by Theodore Ts'o, Copyright 1994. + * + * This file also contains code originally written by Linus Torvalds, + * Copyright 1991, 1992, 1993, and by Julian Cowley, Copyright 1994. + * + * This file may be redistributed under the terms of the GNU General Public + * License. + * + * Reduced memory usage for older ARM systems - Russell King. + * + * 2000/01/20 Fixed SMP locking on put_tty_queue using bits of + * the patch by Andrew J. Kroll <ag784@freenet.buffalo.edu> + * who actually finally proved there really was a race. + * + * 2002/03/18 Implemented n_tty_wakeup to send SIGIO POLL_OUTs to + * waiting writing processes-Sapan Bhatia <sapan@corewars.org>. + * Also fixed a bug in BLOCKING mode where write_chan returns + * EAGAIN + * + * 2004/09/20 Z Smith (fbui@comcast.net): erase-after-read of read_buf + */ + +#include <linux/types.h> +#include <linux/major.h> +#include <linux/errno.h> +#include <linux/signal.h> +#include <linux/fcntl.h> +#include <linux/sched.h> +#include <linux/interrupt.h> +#include <linux/tty.h> +#include <linux/timer.h> +#include <linux/ctype.h> +#include <linux/mm.h> +#include <linux/string.h> +#include <linux/slab.h> +#include <linux/poll.h> + +#include <asm/uaccess.h> +#include <asm/system.h> +#include <asm/bitops.h> + +/* number of characters left in xmit buffer before select has we have room */ +#define WAKEUP_CHARS 256 + +/* + * This defines the low- and high-watermarks for throttling and + * unthrottling the TTY driver. These watermarks are used for + * controlling the space in the read buffer. + */ +#define TTY_THRESHOLD_THROTTLE 128 /* now based on remaining room */ +#define TTY_THRESHOLD_UNTHROTTLE 128 + +static inline unsigned char *alloc_buf(void) +{ + int prio = in_interrupt() ? GFP_ATOMIC : GFP_KERNEL; + + if (PAGE_SIZE != N_TTY_BUF_SIZE) + return kmalloc(N_TTY_BUF_SIZE, prio); + else + return (unsigned char *)__get_free_page(prio); +} + +static inline void free_buf(unsigned char *buf) +{ + if (PAGE_SIZE != N_TTY_BUF_SIZE) + kfree(buf); + else + free_page((unsigned long) buf); +} + +static inline void put_tty_queue_nolock(unsigned char c, struct tty_struct *tty) +{ + if (tty->read_cnt < N_TTY_BUF_SIZE) { + tty->read_buf[tty->read_head] = c; + tty->read_head = (tty->read_head + 1) & (N_TTY_BUF_SIZE-1); + tty->read_cnt++; + } +} + +static inline void put_tty_queue(unsigned char c, struct tty_struct *tty) +{ + unsigned long flags; + /* + * The problem of stomping on the buffers ends here. + * Why didn't anyone see this one coming? --AJK + */ + spin_lock_irqsave(&tty->read_lock, flags); + put_tty_queue_nolock(c, tty); + spin_unlock_irqrestore(&tty->read_lock, flags); +} + +/** + * check_unthrottle - allow new receive data + * @tty; tty device + * + * Check whether to call the driver.unthrottle function. + * We test the TTY_THROTTLED bit first so that it always + * indicates the current state. The decision about whether + * it is worth allowing more input has been taken by the caller. + * Can sleep, may be called under the atomic_read semaphore but + * this is not guaranteed. + */ + +static void check_unthrottle(struct tty_struct * tty) +{ + if (tty->count && + test_and_clear_bit(TTY_THROTTLED, &tty->flags) && + tty->driver->unthrottle) + tty->driver->unthrottle(tty); +} + +/** + * reset_buffer_flags - reset buffer state + * @tty: terminal to reset + * + * Reset the read buffer counters, clear the flags, + * and make sure the driver is unthrottled. Called + * from n_tty_open() and n_tty_flush_buffer(). + */ +static void reset_buffer_flags(struct tty_struct *tty) +{ + unsigned long flags; + + spin_lock_irqsave(&tty->read_lock, flags); + tty->read_head = tty->read_tail = tty->read_cnt = 0; + spin_unlock_irqrestore(&tty->read_lock, flags); + tty->canon_head = tty->canon_data = tty->erasing = 0; + memset(&tty->read_flags, 0, sizeof tty->read_flags); + check_unthrottle(tty); +} + +/** + * n_tty_flush_buffer - clean input queue + * @tty: terminal device + * + * Flush the input buffer. Called when the line discipline is + * being closed, when the tty layer wants the buffer flushed (eg + * at hangup) or when the N_TTY line discipline internally has to + * clean the pending queue (for example some signals). + * + * FIXME: tty->ctrl_status is not spinlocked and relies on + * lock_kernel() still. + */ + +void n_tty_flush_buffer(struct tty_struct * tty) +{ + /* clear everything and unthrottle the driver */ + reset_buffer_flags(tty); + + if (!tty->link) + return; + + if (tty->link->packet) { + tty->ctrl_status |= TIOCPKT_FLUSHREAD; + wake_up_interruptible(&tty->link->read_wait); + } +} + +/** + * n_tty_chars_in_buffer - report available bytes + * @tty: tty device + * + * Report the number of characters buffered to be delivered to user + * at this instant in time. + */ + +ssize_t n_tty_chars_in_buffer(struct tty_struct *tty) +{ + unsigned long flags; + ssize_t n = 0; + + spin_lock_irqsave(&tty->read_lock, flags); + if (!tty->icanon) { + n = tty->read_cnt; + } else if (tty->canon_data) { + n = (tty->canon_head > tty->read_tail) ? + tty->canon_head - tty->read_tail : + tty->canon_head + (N_TTY_BUF_SIZE - tty->read_tail); + } + spin_unlock_irqrestore(&tty->read_lock, flags); + return n; +} + +/** + * is_utf8_continuation - utf8 multibyte check + * @c: byte to check + * + * Returns true if the utf8 character 'c' is a multibyte continuation + * character. We use this to correctly compute the on screen size + * of the character when printing + */ + +static inline int is_utf8_continuation(unsigned char c) +{ + return (c & 0xc0) == 0x80; +} + +/** + * is_continuation - multibyte check + * @c: byte to check + * + * Returns true if the utf8 character 'c' is a multibyte continuation + * character and the terminal is in unicode mode. + */ + +static inline int is_continuation(unsigned char c, struct tty_struct *tty) +{ + return I_IUTF8(tty) && is_utf8_continuation(c); +} + +/** + * opost - output post processor + * @c: character (or partial unicode symbol) + * @tty: terminal device + * + * Perform OPOST processing. Returns -1 when the output device is + * full and the character must be retried. Note that Linux currently + * ignores TABDLY, CRDLY, VTDLY, FFDLY and NLDLY. They simply aren't + * relevant in the world today. If you ever need them, add them here. + * + * Called from both the receive and transmit sides and can be called + * re-entrantly. Relies on lock_kernel() still. + */ + +static int opost(unsigned char c, struct tty_struct *tty) +{ + int space, spaces; + + space = tty->driver->write_room(tty); + if (!space) + return -1; + + if (O_OPOST(tty)) { + switch (c) { + case '\n': + if (O_ONLRET(tty)) + tty->column = 0; + if (O_ONLCR(tty)) { + if (space < 2) + return -1; + tty->driver->put_char(tty, '\r'); + tty->column = 0; + } + tty->canon_column = tty->column; + break; + case '\r': + if (O_ONOCR(tty) && tty->column == 0) + return 0; + if (O_OCRNL(tty)) { + c = '\n'; + if (O_ONLRET(tty)) + tty->canon_column = tty->column = 0; + break; + } + tty->canon_column = tty->column = 0; + break; + case '\t': + spaces = 8 - (tty->column & 7); + if (O_TABDLY(tty) == XTABS) { + if (space < spaces) + return -1; + tty->column += spaces; + tty->driver->write(tty, 0, " ", spaces); + return 0; + } + tty->column += spaces; + break; + case '\b': + if (tty->column > 0) + tty->column--; + break; + default: + if (O_OLCUC(tty)) + c = toupper(c); + if (!iscntrl(c) && !is_continuation(c, tty)) + tty->column++; + break; + } + } + tty->driver->put_char(tty, c); + return 0; +} + +/** + * opost_block - block postprocess + * @tty: terminal device + * @inbuf: user buffer + * @nr: number of bytes + * + * This path is used to speed up block console writes, among other + * things when processing blocks of output data. It handles only + * the simple cases normally found and helps to generate blocks of + * symbols for the console driver and thus improve performance. + * + * Called from write_chan under the tty layer write lock. + */ + +static ssize_t opost_block(struct tty_struct * tty, + const unsigned char __user * inbuf, unsigned int nr) +{ + char buf[80]; + int space; + int i; + char *cp; + + space = tty->driver->write_room(tty); + if (!space) + return 0; + if (nr > space) + nr = space; + if (nr > sizeof(buf)) + nr = sizeof(buf); + + if (copy_from_user(buf, inbuf, nr)) + return -EFAULT; + + for (i = 0, cp = buf; i < nr; i++, cp++) { + switch (*cp) { + case '\n': + if (O_ONLRET(tty)) + tty->column = 0; + if (O_ONLCR(tty)) + goto break_out; + tty->canon_column = tty->column; + break; + case '\r': + if (O_ONOCR(tty) && tty->column == 0) + goto break_out; + if (O_OCRNL(tty)) { + *cp = '\n'; + if (O_ONLRET(tty)) + tty->canon_column = tty->column = 0; + break; + } + tty->canon_column = tty->column = 0; + break; + case '\t': + goto break_out; + case '\b': + if (tty->column > 0) + tty->column--; + break; + default: + if (O_OLCUC(tty)) + *cp = toupper(*cp); + if (!iscntrl(*cp)) + tty->column++; + break; + } + } +break_out: + if (tty->driver->flush_chars) + tty->driver->flush_chars(tty); + i = tty->driver->write(tty, 0, buf, i); + return i; +} + + +/** + * put_char - write character to driver + * @c: character (or part of unicode symbol) + * @tty: terminal device + * + * Queue a byte to the driver layer for output + */ + +static inline void put_char(unsigned char c, struct tty_struct *tty) +{ + tty->driver->put_char(tty, c); +} + +/** + * echo_char - echo characters + * @c: unicode byte to echo + * @tty: terminal device + * + * Echo user input back onto the screen. This must be called only when + * L_ECHO(tty) is true. Called from the driver receive_buf path. + */ + +static void echo_char(unsigned char c, struct tty_struct *tty) +{ + if (L_ECHOCTL(tty) && iscntrl(c) && c != '\t') { + put_char('^', tty); + put_char(c ^ 0100, tty); + tty->column += 2; + } else + opost(c, tty); +} + +static inline void finish_erasing(struct tty_struct *tty) +{ + if (tty->erasing) { + put_char('/', tty); + tty->column++; + tty->erasing = 0; + } +} + +/** + * eraser - handle erase function + * @c: character input + * @tty: terminal device + * + * Perform erase and neccessary output when an erase character is + * present in the stream from the driver layer. Handles the complexities + * of UTF-8 multibyte symbols. + */ + +static void eraser(unsigned char c, struct tty_struct *tty) +{ + enum { ERASE, WERASE, KILL } kill_type; + int head, seen_alnums, cnt; + unsigned long flags; + + if (tty->read_head == tty->canon_head) { + /* opost('\a', tty); */ /* what do you think? */ + return; + } + if (c == ERASE_CHAR(tty)) + kill_type = ERASE; + else if (c == WERASE_CHAR(tty)) + kill_type = WERASE; + else { + if (!L_ECHO(tty)) { + spin_lock_irqsave(&tty->read_lock, flags); + tty->read_cnt -= ((tty->read_head - tty->canon_head) & + (N_TTY_BUF_SIZE - 1)); + tty->read_head = tty->canon_head; + spin_unlock_irqrestore(&tty->read_lock, flags); + return; + } + if (!L_ECHOK(tty) || !L_ECHOKE(tty) || !L_ECHOE(tty)) { + spin_lock_irqsave(&tty->read_lock, flags); + tty->read_cnt -= ((tty->read_head - tty->canon_head) & + (N_TTY_BUF_SIZE - 1)); + tty->read_head = tty->canon_head; + spin_unlock_irqrestore(&tty->read_lock, flags); + finish_erasing(tty); + echo_char(KILL_CHAR(tty), tty); + /* Add a newline if ECHOK is on and ECHOKE is off. */ + if (L_ECHOK(tty)) + opost('\n', tty); + return; + } + kill_type = KILL; + } + + seen_alnums = 0; + while (tty->read_head != tty->canon_head) { + head = tty->read_head; + + /* erase a single possibly multibyte character */ + do { + head = (head - 1) & (N_TTY_BUF_SIZE-1); + c = tty->read_buf[head]; + tty->read_buf[head] = 0; /* ZS */ + } while (is_continuation(c, tty) && head != tty->canon_head); + + /* do not partially erase */ + if (is_continuation(c, tty)) + break; + + if (kill_type == WERASE) { + /* Equivalent to BSD's ALTWERASE. */ + if (isalnum(c) || c == '_') + seen_alnums++; + else if (seen_alnums) + break; + } + cnt = (tty->read_head - head) & (N_TTY_BUF_SIZE-1); + spin_lock_irqsave(&tty->read_lock, flags); + tty->read_head = head; + tty->read_cnt -= cnt; + spin_unlock_irqrestore(&tty->read_lock, flags); + if (L_ECHO(tty)) { + if (L_ECHOPRT(tty)) { + if (!tty->erasing) { + put_char('\\', tty); + tty->column++; + tty->erasing = 1; + } + /* if cnt > 1, output a multi-byte character */ + echo_char(c, tty); + while (--cnt > 0) { + head = (head+1) & (N_TTY_BUF_SIZE-1); + put_char(tty->read_buf[head], tty); + } + } else if (kill_type == ERASE && !L_ECHOE(tty)) { + echo_char(ERASE_CHAR(tty), tty); + } else if (c == '\t') { + unsigned int col = tty->canon_column; + unsigned long tail = tty->canon_head; + + /* Find the column of the last char. */ + while (tail != tty->read_head) { + c = tty->read_buf[tail]; + tty->read_buf[tail] = 0; /* ZS */ + if (c == '\t') + col = (col | 7) + 1; + else if (iscntrl(c)) { + if (L_ECHOCTL(tty)) + col += 2; + } else if (!is_continuation(c, tty)) + col++; + tail = (tail+1) & (N_TTY_BUF_SIZE-1); + } + + /* should never happen */ + if (tty->column > 0x80000000) + tty->column = 0; + + /* Now backup to that column. */ + while (tty->column > col) { + /* Can't use opost here. */ + put_char('\b', tty); + if (tty->column > 0) + tty->column--; + } + } else { + if (iscntrl(c) && L_ECHOCTL(tty)) { + put_char('\b', tty); + put_char(' ', tty); + put_char('\b', tty); + if (tty->column > 0) + tty->column--; + } + if (!iscntrl(c) || L_ECHOCTL(tty)) { + put_char('\b', tty); + put_char(' ', tty); + put_char('\b', tty); + if (tty->column > 0) + tty->column--; + } + } + } + if (kill_type == ERASE) + break; + } + if (tty->read_head == tty->canon_head) + finish_erasing(tty); +} + +/** + * isig - handle the ISIG optio + * @sig: signal + * @tty: terminal + * @flush: force flush + * + * Called when a signal is being sent due to terminal input. This + * may caus terminal flushing to take place according to the termios + * settings and character used. Called from the driver receive_buf + * path so serialized. + */ + +static inline void isig(int sig, struct tty_struct *tty, int flush) +{ + if (tty->pgrp > 0) + kill_pg(tty->pgrp, sig, 1); + if (flush || !L_NOFLSH(tty)) { + n_tty_flush_buffer(tty); + if (tty->driver->flush_buffer) + tty->driver->flush_buffer(tty); + } +} + +/** + * n_tty_receive_break - handle break + * @tty: terminal + * + * An RS232 break event has been hit in the incoming bitstream. This + * can cause a variety of events depending upon the termios settings. + * + * Called from the receive_buf path so single threaded. + */ + +static inline void n_tty_receive_break(struct tty_struct *tty) +{ + if (I_IGNBRK(tty)) + return; + if (I_BRKINT(tty)) { + isig(SIGINT, tty, 1); + return; + } + if (I_PARMRK(tty)) { + put_tty_queue('\377', tty); + put_tty_queue('\0', tty); + } + put_tty_queue('\0', tty); + wake_up_interruptible(&tty->read_wait); +} + +/** + * n_tty_receive_overrun - handle overrun reporting + * @tty: terminal + * + * Data arrived faster than we could process it. While the tty + * driver has flagged this the bits that were missed are gone + * forever. + * + * Called from the receive_buf path so single threaded. Does not + * need locking as num_overrun and overrun_time are function + * private. + */ + +static inline void n_tty_receive_overrun(struct tty_struct *tty) +{ + char buf[64]; + + tty->num_overrun++; + if (time_before(tty->overrun_time, jiffies - HZ)) { + printk(KERN_WARNING "%s: %d input overrun(s)\n", tty_name(tty, buf), + tty->num_overrun); + tty->overrun_time = jiffies; + tty->num_overrun = 0; + } +} + +/** + * n_tty_receive_parity_error - error notifier + * @tty: terminal device + * @c: character + * + * Process a parity error and queue the right data to indicate + * the error case if neccessary. Locking as per n_tty_receive_buf. + */ +static inline void n_tty_receive_parity_error(struct tty_struct *tty, + unsigned char c) +{ + if (I_IGNPAR(tty)) { + return; + } + if (I_PARMRK(tty)) { + put_tty_queue('\377', tty); + put_tty_queue('\0', tty); + put_tty_queue(c, tty); + } else if (I_INPCK(tty)) + put_tty_queue('\0', tty); + else + put_tty_queue(c, tty); + wake_up_interruptible(&tty->read_wait); +} + +/** + * n_tty_receive_char - perform processing + * @tty: terminal device + * @c: character + * + * Process an individual character of input received from the driver. + * This is serialized with respect to itself by the rules for the + * driver above. + */ + +static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c) +{ + unsigned long flags; + + if (tty->raw) { + put_tty_queue(c, tty); + return; + } + + if (tty->stopped && !tty->flow_stopped && + I_IXON(tty) && I_IXANY(tty)) { + start_tty(tty); + return; + } + + if (I_ISTRIP(tty)) + c &= 0x7f; + if (I_IUCLC(tty) && L_IEXTEN(tty)) + c=tolower(c); + + if (tty->closing) { + if (I_IXON(tty)) { + if (c == START_CHAR(tty)) + start_tty(tty); + else if (c == STOP_CHAR(tty)) + stop_tty(tty); + } + return; + } + + /* + * If the previous character was LNEXT, or we know that this + * character is not one of the characters that we'll have to + * handle specially, do shortcut processing to speed things + * up. + */ + if (!test_bit(c, tty->process_char_map) || tty->lnext) { + finish_erasing(tty); + tty->lnext = 0; + if (L_ECHO(tty)) { + if (tty->read_cnt >= N_TTY_BUF_SIZE-1) { + put_char('\a', tty); /* beep if no space */ + return; + } + /* Record the column of first canon char. */ + if (tty->canon_head == tty->read_head) + tty->canon_column = tty->column; + echo_char(c, tty); + } + if (I_PARMRK(tty) && c == (unsigned char) '\377') + put_tty_queue(c, tty); + put_tty_queue(c, tty); + return; + } + + if (c == '\r') { + if (I_IGNCR(tty)) + return; + if (I_ICRNL(tty)) + c = '\n'; + } else if (c == '\n' && I_INLCR(tty)) + c = '\r'; + if (I_IXON(tty)) { + if (c == START_CHAR(tty)) { + start_tty(tty); + return; + } + if (c == STOP_CHAR(tty)) { + stop_tty(tty); + return; + } + } + if (L_ISIG(tty)) { + int signal; + signal = SIGINT; + if (c == INTR_CHAR(tty)) + goto send_signal; + signal = SIGQUIT; + if (c == QUIT_CHAR(tty)) + goto send_signal; + signal = SIGTSTP; + if (c == SUSP_CHAR(tty)) { +send_signal: + isig(signal, tty, 0); + return; + } + } + if (tty->icanon) { + if (c == ERASE_CHAR(tty) || c == KILL_CHAR(tty) || + (c == WERASE_CHAR(tty) && L_IEXTEN(tty))) { + eraser(c, tty); + return; + } + if (c == LNEXT_CHAR(tty) && L_IEXTEN(tty)) { + tty->lnext = 1; + if (L_ECHO(tty)) { + finish_erasing(tty); + if (L_ECHOCTL(tty)) { + put_char('^', tty); + put_char('\b', tty); + } + } + return; + } + if (c == REPRINT_CHAR(tty) && L_ECHO(tty) && + L_IEXTEN(tty)) { + unsigned long tail = tty->canon_head; + + finish_erasing(tty); + echo_char(c, tty); + opost('\n', tty); + while (tail != tty->read_head) { + echo_char(tty->read_buf[tail], tty); + tail = (tail+1) & (N_TTY_BUF_SIZE-1); + } + return; + } + if (c == '\n') { + if (L_ECHO(tty) || L_ECHONL(tty)) { + if (tty->read_cnt >= N_TTY_BUF_SIZE-1) { + put_char('\a', tty); + return; + } + opost('\n', tty); + } + goto handle_newline; + } + if (c == EOF_CHAR(tty)) { + if (tty->canon_head != tty->read_head) + set_bit(TTY_PUSH, &tty->flags); + c = __DISABLED_CHAR; + goto handle_newline; + } + if ((c == EOL_CHAR(tty)) || + (c == EOL2_CHAR(tty) && L_IEXTEN(tty))) { + /* + * XXX are EOL_CHAR and EOL2_CHAR echoed?!? + */ + if (L_ECHO(tty)) { + if (tty->read_cnt >= N_TTY_BUF_SIZE-1) { + put_char('\a', tty); + return; + } + /* Record the column of first canon char. */ + if (tty->canon_head == tty->read_head) + tty->canon_column = tty->column; + echo_char(c, tty); + } + /* + * XXX does PARMRK doubling happen for + * EOL_CHAR and EOL2_CHAR? + */ + if (I_PARMRK(tty) && c == (unsigned char) '\377') + put_tty_queue(c, tty); + + handle_newline: + spin_lock_irqsave(&tty->read_lock, flags); + set_bit(tty->read_head, tty->read_flags); + put_tty_queue_nolock(c, tty); + tty->canon_head = tty->read_head; + tty->canon_data++; + spin_unlock_irqrestore(&tty->read_lock, flags); + kill_fasync(&tty->fasync, SIGIO, POLL_IN); + if (waitqueue_active(&tty->read_wait)) + wake_up_interruptible(&tty->read_wait); + return; + } + } + + finish_erasing(tty); + if (L_ECHO(tty)) { + if (tty->read_cnt >= N_TTY_BUF_SIZE-1) { + put_char('\a', tty); /* beep if no space */ + return; + } + if (c == '\n') + opost('\n', tty); + else { + /* Record the column of first canon char. */ + if (tty->canon_head == tty->read_head) + tty->canon_column = tty->column; + echo_char(c, tty); + } + } + + if (I_PARMRK(tty) && c == (unsigned char) '\377') + put_tty_queue(c, tty); + + put_tty_queue(c, tty); +} + +/** + * n_tty_receive_room - receive space + * @tty: terminal + * + * Called by the driver to find out how much data it is + * permitted to feed to the line discipline without any being lost + * and thus to manage flow control. Not serialized. Answers for the + * "instant". + */ + +static int n_tty_receive_room(struct tty_struct *tty) +{ + int left = N_TTY_BUF_SIZE - tty->read_cnt - 1; + + /* + * If we are doing input canonicalization, and there are no + * pending newlines, let characters through without limit, so + * that erase characters will be handled. Other excess + * characters will be beeped. + */ + if (tty->icanon && !tty->canon_data) + return N_TTY_BUF_SIZE; + + if (left > 0) + return left; + return 0; +} + +/** + * n_tty_write_wakeup - asynchronous I/O notifier + * @tty: tty device + * + * Required for the ptys, serial driver etc. since processes + * that attach themselves to the master and rely on ASYNC + * IO must be woken up + */ + +static void n_tty_write_wakeup(struct tty_struct *tty) +{ + if (tty->fasync) + { + set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); + kill_fasync(&tty->fasync, SIGIO, POLL_OUT); + } + return; +} + +/** + * n_tty_receive_buf - data receive + * @tty: terminal device + * @cp: buffer + * @fp: flag buffer + * @count: characters + * + * Called by the terminal driver when a block of characters has + * been received. This function must be called from soft contexts + * not from interrupt context. The driver is responsible for making + * calls one at a time and in order (or using flush_to_ldisc) + */ + +static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp, + char *fp, int count) +{ + const unsigned char *p; + char *f, flags = TTY_NORMAL; + int i; + char buf[64]; + unsigned long cpuflags; + + if (!tty->read_buf) + return; + + if (tty->real_raw) { + spin_lock_irqsave(&tty->read_lock, cpuflags); + i = min(N_TTY_BUF_SIZE - tty->read_cnt, + N_TTY_BUF_SIZE - tty->read_head); + i = min(count, i); + memcpy(tty->read_buf + tty->read_head, cp, i); + tty->read_head = (tty->read_head + i) & (N_TTY_BUF_SIZE-1); + tty->read_cnt += i; + cp += i; + count -= i; + + i = min(N_TTY_BUF_SIZE - tty->read_cnt, + N_TTY_BUF_SIZE - tty->read_head); + i = min(count, i); + memcpy(tty->read_buf + tty->read_head, cp, i); + tty->read_head = (tty->read_head + i) & (N_TTY_BUF_SIZE-1); + tty->read_cnt += i; + spin_unlock_irqrestore(&tty->read_lock, cpuflags); + } else { + for (i=count, p = cp, f = fp; i; i--, p++) { + if (f) + flags = *f++; + switch (flags) { + case TTY_NORMAL: + n_tty_receive_char(tty, *p); + break; + case TTY_BREAK: + n_tty_receive_break(tty); + break; + case TTY_PARITY: + case TTY_FRAME: + n_tty_receive_parity_error(tty, *p); + break; + case TTY_OVERRUN: + n_tty_receive_overrun(tty); + break; + default: + printk("%s: unknown flag %d\n", + tty_name(tty, buf), flags); + break; + } + } + if (tty->driver->flush_chars) + tty->driver->flush_chars(tty); + } + + if (!tty->icanon && (tty->read_cnt >= tty->minimum_to_wake)) { + kill_fasync(&tty->fasync, SIGIO, POLL_IN); + if (waitqueue_active(&tty->read_wait)) + wake_up_interruptible(&tty->read_wait); + } + + /* + * Check the remaining room for the input canonicalization + * mode. We don't want to throttle the driver if we're in + * canonical mode and don't have a newline yet! + */ + if (n_tty_receive_room(tty) < TTY_THRESHOLD_THROTTLE) { + /* check TTY_THROTTLED first so it indicates our state */ + if (!test_and_set_bit(TTY_THROTTLED, &tty->flags) && + tty->driver->throttle) + tty->driver->throttle(tty); + } +} + +int is_ignored(int sig) +{ + return (sigismember(¤t->blocked, sig) || + current->sighand->action[sig-1].sa.sa_handler == SIG_IGN); +} + +/** + * n_tty_set_termios - termios data changed + * @tty: terminal + * @old: previous data + * + * Called by the tty layer when the user changes termios flags so + * that the line discipline can plan ahead. This function cannot sleep + * and is protected from re-entry by the tty layer. The user is + * guaranteed that this function will not be re-entered or in progress + * when the ldisc is closed. + */ + +static void n_tty_set_termios(struct tty_struct *tty, struct termios * old) +{ + if (!tty) + return; + + tty->icanon = (L_ICANON(tty) != 0); + if (test_bit(TTY_HW_COOK_IN, &tty->flags)) { + tty->raw = 1; + tty->real_raw = 1; + return; + } + if (I_ISTRIP(tty) || I_IUCLC(tty) || I_IGNCR(tty) || + I_ICRNL(tty) || I_INLCR(tty) || L_ICANON(tty) || + I_IXON(tty) || L_ISIG(tty) || L_ECHO(tty) || + I_PARMRK(tty)) { + memset(tty->process_char_map, 0, 256/8); + + if (I_IGNCR(tty) || I_ICRNL(tty)) + set_bit('\r', tty->process_char_map); + if (I_INLCR(tty)) + set_bit('\n', tty->process_char_map); + + if (L_ICANON(tty)) { + set_bit(ERASE_CHAR(tty), tty->process_char_map); + set_bit(KILL_CHAR(tty), tty->process_char_map); + set_bit(EOF_CHAR(tty), tty->process_char_map); + set_bit('\n', tty->process_char_map); + set_bit(EOL_CHAR(tty), tty->process_char_map); + if (L_IEXTEN(tty)) { + set_bit(WERASE_CHAR(tty), + tty->process_char_map); + set_bit(LNEXT_CHAR(tty), + tty->process_char_map); + set_bit(EOL2_CHAR(tty), + tty->process_char_map); + if (L_ECHO(tty)) + set_bit(REPRINT_CHAR(tty), + tty->process_char_map); + } + } + if (I_IXON(tty)) { + set_bit(START_CHAR(tty), tty->process_char_map); + set_bit(STOP_CHAR(tty), tty->process_char_map); + } + if (L_ISIG(tty)) { + set_bit(INTR_CHAR(tty), tty->process_char_map); + set_bit(QUIT_CHAR(tty), tty->process_char_map); + set_bit(SUSP_CHAR(tty), tty->process_char_map); + } + clear_bit(__DISABLED_CHAR, tty->process_char_map); + tty->raw = 0; + tty->real_raw = 0; + } else { + tty->raw = 1; + if ((I_IGNBRK(tty) || (!I_BRKINT(tty) && !I_PARMRK(tty))) && + (I_IGNPAR(tty) || !I_INPCK(tty)) && + (tty->driver->flags & TTY_DRIVER_REAL_RAW)) + tty->real_raw = 1; + else + tty->real_raw = 0; + } +} + +/** + * n_tty_close - close the ldisc for this tty + * @tty: device + * + * Called from the terminal layer when this line discipline is + * being shut down, either because of a close or becsuse of a + * discipline change. The function will not be called while other + * ldisc methods are in progress. + */ + +static void n_tty_close(struct tty_struct *tty) +{ + n_tty_flush_buffer(tty); + if (tty->read_buf) { + free_buf(tty->read_buf); + tty->read_buf = NULL; + } +} + +/** + * n_tty_open - open an ldisc + * @tty: terminal to open + * + * Called when this line discipline is being attached to the + * terminal device. Can sleep. Called serialized so that no + * other events will occur in parallel. No further open will occur + * until a close. + */ + +static int n_tty_open(struct tty_struct *tty) +{ + if (!tty) + return -EINVAL; + + /* This one is ugly. Currently a malloc failure here can panic */ + if (!tty->read_buf) { + tty->read_buf = alloc_buf(); + if (!tty->read_buf) + return -ENOMEM; + } + memset(tty->read_buf, 0, N_TTY_BUF_SIZE); + reset_buffer_flags(tty); + tty->column = 0; + n_tty_set_termios(tty, NULL); + tty->minimum_to_wake = 1; + tty->closing = 0; + return 0; +} + +static inline int input_available_p(struct tty_struct *tty, int amt) +{ + if (tty->icanon) { + if (tty->canon_data) + return 1; + } else if (tty->read_cnt >= (amt ? amt : 1)) + return 1; + + return 0; +} + +/** + * copy_from_read_buf - copy read data directly + * @tty: terminal device + * @b: user data + * @nr: size of data + * + * Helper function to speed up read_chan. It is only called when + * ICANON is off; it copies characters straight from the tty queue to + * user space directly. It can be profitably called twice; once to + * drain the space from the tail pointer to the (physical) end of the + * buffer, and once to drain the space from the (physical) beginning of + * the buffer to head pointer. + * + * Called under the tty->atomic_read sem and with TTY_DONT_FLIP set + * + */ + +static inline int copy_from_read_buf(struct tty_struct *tty, + unsigned char __user **b, + size_t *nr) + +{ + int retval; + ssize_t n; + unsigned long flags; + + retval = 0; + spin_lock_irqsave(&tty->read_lock, flags); + n = min(tty->read_cnt, N_TTY_BUF_SIZE - tty->read_tail); + n = min((ssize_t)*nr, n); + spin_unlock_irqrestore(&tty->read_lock, flags); + if (n) { + mb(); + retval = copy_to_user(*b, &tty->read_buf[tty->read_tail], n); + n -= retval; + spin_lock_irqsave(&tty->read_lock, flags); + tty->read_tail = (tty->read_tail + n) & (N_TTY_BUF_SIZE-1); + tty->read_cnt -= n; + spin_unlock_irqrestore(&tty->read_lock, flags); + *b += n; + *nr -= n; + } + return retval; +} + +extern ssize_t redirected_tty_write(struct file *,const char *,size_t,loff_t *); + +/** + * job_control - check job control + * @tty: tty + * @file: file handle + * + * Perform job control management checks on this file/tty descriptor + * and if appropriate send any needed signals and return a negative + * error code if action should be taken. + */ + +static int job_control(struct tty_struct *tty, struct file *file) +{ + /* Job control check -- must be done at start and after + every sleep (POSIX.1 7.1.1.4). */ + /* NOTE: not yet done after every sleep pending a thorough + check of the logic of this change. -- jlc */ + /* don't stop on /dev/console */ + if (file->f_op->write != redirected_tty_write && + current->signal->tty == tty) { + if (tty->pgrp <= 0) + printk("read_chan: tty->pgrp <= 0!\n"); + else if (process_group(current) != tty->pgrp) { + if (is_ignored(SIGTTIN) || + is_orphaned_pgrp(process_group(current))) + return -EIO; + kill_pg(process_group(current), SIGTTIN, 1); + return -ERESTARTSYS; + } + } + return 0; +} + + +/** + * read_chan - read function for tty + * @tty: tty device + * @file: file object + * @buf: userspace buffer pointer + * @nr: size of I/O + * + * Perform reads for the line discipline. We are guaranteed that the + * line discipline will not be closed under us but we may get multiple + * parallel readers and must handle this ourselves. We may also get + * a hangup. Always called in user context, may sleep. + * + * This code must be sure never to sleep through a hangup. + */ + +static ssize_t read_chan(struct tty_struct *tty, struct file *file, + unsigned char __user *buf, size_t nr) +{ + unsigned char __user *b = buf; + DECLARE_WAITQUEUE(wait, current); + int c; + int minimum, time; + ssize_t retval = 0; + ssize_t size; + long timeout; + unsigned long flags; + +do_it_again: + + if (!tty->read_buf) { + printk("n_tty_read_chan: called with read_buf == NULL?!?\n"); + return -EIO; + } + + c = job_control(tty, file); + if(c < 0) + return c; + + minimum = time = 0; + timeout = MAX_SCHEDULE_TIMEOUT; + if (!tty->icanon) { + time = (HZ / 10) * TIME_CHAR(tty); + minimum = MIN_CHAR(tty); + if (minimum) { + if (time) + tty->minimum_to_wake = 1; + else if (!waitqueue_active(&tty->read_wait) || + (tty->minimum_to_wake > minimum)) + tty->minimum_to_wake = minimum; + } else { + timeout = 0; + if (time) { + timeout = time; + time = 0; + } + tty->minimum_to_wake = minimum = 1; + } + } + + /* + * Internal serialization of reads. + */ + if (file->f_flags & O_NONBLOCK) { + if (down_trylock(&tty->atomic_read)) + return -EAGAIN; + } + else { + if (down_interruptible(&tty->atomic_read)) + return -ERESTARTSYS; + } + + add_wait_queue(&tty->read_wait, &wait); + set_bit(TTY_DONT_FLIP, &tty->flags); + while (nr) { + /* First test for status change. */ + if (tty->packet && tty->link->ctrl_status) { + unsigned char cs; + if (b != buf) + break; + cs = tty->link->ctrl_status; + tty->link->ctrl_status = 0; + if (put_user(cs, b++)) { + retval = -EFAULT; + b--; + break; + } + nr--; + break; + } + /* This statement must be first before checking for input + so that any interrupt will set the state back to + TASK_RUNNING. */ + set_current_state(TASK_INTERRUPTIBLE); + + if (((minimum - (b - buf)) < tty->minimum_to_wake) && + ((minimum - (b - buf)) >= 1)) + tty->minimum_to_wake = (minimum - (b - buf)); + + if (!input_available_p(tty, 0)) { + if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) { + retval = -EIO; + break; + } + if (tty_hung_up_p(file)) + break; + if (!timeout) + break; + if (file->f_flags & O_NONBLOCK) { + retval = -EAGAIN; + break; + } + if (signal_pending(current)) { + retval = -ERESTARTSYS; + break; + } + clear_bit(TTY_DONT_FLIP, &tty->flags); + timeout = schedule_timeout(timeout); + set_bit(TTY_DONT_FLIP, &tty->flags); + continue; + } + __set_current_state(TASK_RUNNING); + + /* Deal with packet mode. */ + if (tty->packet && b == buf) { + if (put_user(TIOCPKT_DATA, b++)) { + retval = -EFAULT; + b--; + break; + } + nr--; + } + + if (tty->icanon) { + /* N.B. avoid overrun if nr == 0 */ + while (nr && tty->read_cnt) { + int eol; + + eol = test_and_clear_bit(tty->read_tail, + tty->read_flags); + c = tty->read_buf[tty->read_tail]; + tty->read_buf[tty->read_tail] = 0; /* ZS */ + spin_lock_irqsave(&tty->read_lock, flags); + tty->read_tail = ((tty->read_tail+1) & + (N_TTY_BUF_SIZE-1)); + tty->read_cnt--; + if (eol) { + /* this test should be redundant: + * we shouldn't be reading data if + * canon_data is 0 + */ + if (--tty->canon_data < 0) + tty->canon_data = 0; + } + spin_unlock_irqrestore(&tty->read_lock, flags); + + if (!eol || (c != __DISABLED_CHAR)) { + if (put_user(c, b++)) { + retval = -EFAULT; + b--; + break; + } + nr--; + } + if (eol) + break; + } + if (retval) + break; + } else { + int uncopied; + uncopied = copy_from_read_buf(tty, &b, &nr); + uncopied += copy_from_read_buf(tty, &b, &nr); + if (uncopied) { + retval = -EFAULT; + break; + } + } + + /* If there is enough space in the read buffer now, let the + * low-level driver know. We use n_tty_chars_in_buffer() to + * check the buffer, as it now knows about canonical mode. + * Otherwise, if the driver is throttled and the line is + * longer than TTY_THRESHOLD_UNTHROTTLE in canonical mode, + * we won't get any more characters. + */ + if (n_tty_chars_in_buffer(tty) <= TTY_THRESHOLD_UNTHROTTLE) + check_unthrottle(tty); + + if (b - buf >= minimum) + break; + if (time) + timeout = time; + } + clear_bit(TTY_DONT_FLIP, &tty->flags); + up(&tty->atomic_read); + remove_wait_queue(&tty->read_wait, &wait); + + if (!waitqueue_active(&tty->read_wait)) + tty->minimum_to_wake = minimum; + + __set_current_state(TASK_RUNNING); + size = b - buf; + if (size) { + retval = size; + if (nr) + clear_bit(TTY_PUSH, &tty->flags); + } else if (test_and_clear_bit(TTY_PUSH, &tty->flags)) + goto do_it_again; + + return retval; +} + +/** + * write_chan - write function for tty + * @tty: tty device + * @file: file object + * @buf: userspace buffer pointer + * @nr: size of I/O + * + * Write function of the terminal device. This is serialized with + * respect to other write callers but not to termios changes, reads + * and other such events. We must be careful with N_TTY as the receive + * code will echo characters, thus calling driver write methods. + * + * This code must be sure never to sleep through a hangup. + */ + +static ssize_t write_chan(struct tty_struct * tty, struct file * file, + const unsigned char __user * buf, size_t nr) +{ + const unsigned char __user *b = buf; + DECLARE_WAITQUEUE(wait, current); + int c; + ssize_t retval = 0; + + /* Job control check -- must be done at start (POSIX.1 7.1.1.4). */ + if (L_TOSTOP(tty) && file->f_op->write != redirected_tty_write) { + retval = tty_check_change(tty); + if (retval) + return retval; + } + + add_wait_queue(&tty->write_wait, &wait); + while (1) { + set_current_state(TASK_INTERRUPTIBLE); + if (signal_pending(current)) { + retval = -ERESTARTSYS; + break; + } + if (tty_hung_up_p(file) || (tty->link && !tty->link->count)) { + retval = -EIO; + break; + } + if (O_OPOST(tty) && !(test_bit(TTY_HW_COOK_OUT, &tty->flags))) { + while (nr > 0) { + ssize_t num = opost_block(tty, b, nr); + if (num < 0) { + if (num == -EAGAIN) + break; + retval = num; + goto break_out; + } + b += num; + nr -= num; + if (nr == 0) + break; + get_user(c, b); + if (opost(c, tty) < 0) + break; + b++; nr--; + } + if (tty->driver->flush_chars) + tty->driver->flush_chars(tty); + } else { + c = tty->driver->write(tty, 1, b, nr); + if (c < 0) { + retval = c; + goto break_out; + } + b += c; + nr -= c; + } + if (!nr) + break; + if (file->f_flags & O_NONBLOCK) { + retval = -EAGAIN; + break; + } + schedule(); + } +break_out: + __set_current_state(TASK_RUNNING); + remove_wait_queue(&tty->write_wait, &wait); + return (b - buf) ? b - buf : retval; +} + +/** + * normal_poll - poll method for N_TTY + * @tty: terminal device + * @file: file accessing it + * @wait: poll table + * + * Called when the line discipline is asked to poll() for data or + * for special events. This code is not serialized with respect to + * other events save open/close. + * + * This code must be sure never to sleep through a hangup. + * Called without the kernel lock held - fine + * + * FIXME: if someone changes the VMIN or discipline settings for the + * terminal while another process is in poll() the poll does not + * recompute the new limits. Possibly set_termios should issue + * a read wakeup to fix this bug. + */ + +static unsigned int normal_poll(struct tty_struct * tty, struct file * file, poll_table *wait) +{ + unsigned int mask = 0; + + poll_wait(file, &tty->read_wait, wait); + poll_wait(file, &tty->write_wait, wait); + if (input_available_p(tty, TIME_CHAR(tty) ? 0 : MIN_CHAR(tty))) + mask |= POLLIN | POLLRDNORM; + if (tty->packet && tty->link->ctrl_status) + mask |= POLLPRI | POLLIN | POLLRDNORM; + if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) + mask |= POLLHUP; + if (tty_hung_up_p(file)) + mask |= POLLHUP; + if (!(mask & (POLLHUP | POLLIN | POLLRDNORM))) { + if (MIN_CHAR(tty) && !TIME_CHAR(tty)) + tty->minimum_to_wake = MIN_CHAR(tty); + else + tty->minimum_to_wake = 1; + } + if (tty->driver->chars_in_buffer(tty) < WAKEUP_CHARS && + tty->driver->write_room(tty) > 0) + mask |= POLLOUT | POLLWRNORM; + return mask; +} + +struct tty_ldisc tty_ldisc_N_TTY = { + TTY_LDISC_MAGIC, /* magic */ + "n_tty", /* name */ + 0, /* num */ + 0, /* flags */ + n_tty_open, /* open */ + n_tty_close, /* close */ + n_tty_flush_buffer, /* flush_buffer */ + n_tty_chars_in_buffer, /* chars_in_buffer */ + read_chan, /* read */ + write_chan, /* write */ + n_tty_ioctl, /* ioctl */ + n_tty_set_termios, /* set_termios */ + normal_poll, /* poll */ + NULL, /* hangup */ + n_tty_receive_buf, /* receive_buf */ + n_tty_receive_room, /* receive_room */ + n_tty_write_wakeup /* write_wakeup */ +}; + diff --git a/drivers/char/vt_ioctl.c b/drivers/char/vt_ioctl.c @@ -0,0 +1,1221 @@ +/* + * linux/drivers/char/vt_ioctl.c + * + * Copyright (C) 1992 obz under the linux copyright + * + * Dynamic diacritical handling - aeb@cwi.nl - Dec 1993 + * Dynamic keymap and string allocation - aeb@cwi.nl - May 1994 + * Restrict VT switching via ioctl() - grif@cs.ucr.edu - Dec 1995 + * Some code moved for less code duplication - Andi Kleen - Mar 1997 + * Check put/get_user, cleanups - acme@conectiva.com.br - Jun 2001 + */ + +#include <linux/config.h> +#include <linux/types.h> +#include <linux/errno.h> +#include <linux/sched.h> +#include <linux/tty.h> +#include <linux/timer.h> +#include <linux/kernel.h> +#include <linux/kd.h> +#include <linux/vt.h> +#include <linux/string.h> +#include <linux/slab.h> +#include <linux/major.h> +#include <linux/fs.h> +#include <linux/console.h> + +#include <asm/io.h> +#include <asm/uaccess.h> + +#include <linux/kbd_kern.h> +#include <linux/vt_kern.h> +#include <linux/kbd_diacr.h> +#include <linux/selection.h> + +char vt_dont_switch; +extern struct tty_driver *console_driver; + +#define VT_IS_IN_USE(i) (console_driver->ttys[i] && console_driver->ttys[i]->count) +#define VT_BUSY(i) (VT_IS_IN_USE(i) || i == fg_console || i == sel_cons) + +/* + * Console (vt and kd) routines, as defined by USL SVR4 manual, and by + * experimentation and study of X386 SYSV handling. + * + * One point of difference: SYSV vt's are /dev/vtX, which X >= 0, and + * /dev/console is a separate ttyp. Under Linux, /dev/tty0 is /dev/console, + * and the vc start at /dev/ttyX, X >= 1. We maintain that here, so we will + * always treat our set of vt as numbered 1..MAX_NR_CONSOLES (corresponding to + * ttys 0..MAX_NR_CONSOLES-1). Explicitly naming VT 0 is illegal, but using + * /dev/tty0 (fg_console) as a target is legal, since an implicit aliasing + * to the current console is done by the main ioctl code. + */ + +struct vt_struct *vt_cons[MAX_NR_CONSOLES]; + +/* Keyboard type: Default is KB_101, but can be set by machine + * specific code. + */ +unsigned char keyboard_type = KB_101; + +#ifdef CONFIG_X86 +#include <linux/syscalls.h> +#endif + +/* + * these are the valid i/o ports we're allowed to change. they map all the + * video ports + */ +#define GPFIRST 0x3b4 +#define GPLAST 0x3df +#define GPNUM (GPLAST - GPFIRST + 1) + +#define i (tmp.kb_index) +#define s (tmp.kb_table) +#define v (tmp.kb_value) +static inline int +do_kdsk_ioctl(int cmd, struct kbentry __user *user_kbe, int perm, struct kbd_struct *kbd) +{ + struct kbentry tmp; + ushort *key_map, val, ov; + + if (copy_from_user(&tmp, user_kbe, sizeof(struct kbentry))) + return -EFAULT; + + switch (cmd) { + case KDGKBENT: + key_map = key_maps[s]; + if (key_map) { + val = U(key_map[i]); + if (kbd->kbdmode != VC_UNICODE && KTYP(val) >= NR_TYPES) + val = K_HOLE; + } else + val = (i ? K_HOLE : K_NOSUCHMAP); + return put_user(val, &user_kbe->kb_value); + case KDSKBENT: + if (!perm) + return -EPERM; + if (!i && v == K_NOSUCHMAP) { + /* disallocate map */ + key_map = key_maps[s]; + if (s && key_map) { + key_maps[s] = NULL; + if (key_map[0] == U(K_ALLOCATED)) { + kfree(key_map); + keymap_count--; + } + } + break; + } + + if (KTYP(v) < NR_TYPES) { + if (KVAL(v) > max_vals[KTYP(v)]) + return -EINVAL; + } else + if (kbd->kbdmode != VC_UNICODE) + return -EINVAL; + + /* ++Geert: non-PC keyboards may generate keycode zero */ +#if !defined(__mc68000__) && !defined(__powerpc__) + /* assignment to entry 0 only tests validity of args */ + if (!i) + break; +#endif + + if (!(key_map = key_maps[s])) { + int j; + + if (keymap_count >= MAX_NR_OF_USER_KEYMAPS && + !capable(CAP_SYS_RESOURCE)) + return -EPERM; + + key_map = (ushort *) kmalloc(sizeof(plain_map), + GFP_KERNEL); + if (!key_map) + return -ENOMEM; + key_maps[s] = key_map; + key_map[0] = U(K_ALLOCATED); + for (j = 1; j < NR_KEYS; j++) + key_map[j] = U(K_HOLE); + keymap_count++; + } + ov = U(key_map[i]); + if (v == ov) + break; /* nothing to do */ + /* + * Attention Key. + */ + if (((ov == K_SAK) || (v == K_SAK)) && !capable(CAP_SYS_ADMIN)) + return -EPERM; + key_map[i] = U(v); + if (!s && (KTYP(ov) == KT_SHIFT || KTYP(v) == KT_SHIFT)) + compute_shiftstate(); + break; + } + return 0; +} +#undef i +#undef s +#undef v + +static inline int +do_kbkeycode_ioctl(int cmd, struct kbkeycode __user *user_kbkc, int perm) +{ + struct kbkeycode tmp; + int kc = 0; + + if (copy_from_user(&tmp, user_kbkc, sizeof(struct kbkeycode))) + return -EFAULT; + switch (cmd) { + case KDGETKEYCODE: + kc = getkeycode(tmp.scancode); + if (kc >= 0) + kc = put_user(kc, &user_kbkc->keycode); + break; + case KDSETKEYCODE: + if (!perm) + return -EPERM; + kc = setkeycode(tmp.scancode, tmp.keycode); + break; + } + return kc; +} + +static inline int +do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm) +{ + struct kbsentry *kbs; + char *p; + u_char *q; + u_char __user *up; + int sz; + int delta; + char *first_free, *fj, *fnw; + int i, j, k; + int ret; + + kbs = kmalloc(sizeof(*kbs), GFP_KERNEL); + if (!kbs) { + ret = -ENOMEM; + goto reterr; + } + + /* we mostly copy too much here (512bytes), but who cares ;) */ + if (copy_from_user(kbs, user_kdgkb, sizeof(struct kbsentry))) { + ret = -EFAULT; + goto reterr; + } + kbs->kb_string[sizeof(kbs->kb_string)-1] = '\0'; + i = kbs->kb_func; + + switch (cmd) { + case KDGKBSENT: + sz = sizeof(kbs->kb_string) - 1; /* sz should have been + a struct member */ + up = user_kdgkb->kb_string; + p = func_table[i]; + if(p) + for ( ; *p && sz; p++, sz--) + if (put_user(*p, up++)) { + ret = -EFAULT; + goto reterr; + } + if (put_user('\0', up)) { + ret = -EFAULT; + goto reterr; + } + kfree(kbs); + return ((p && *p) ? -EOVERFLOW : 0); + case KDSKBSENT: + if (!perm) { + ret = -EPERM; + goto reterr; + } + + q = func_table[i]; + first_free = funcbufptr + (funcbufsize - funcbufleft); + for (j = i+1; j < MAX_NR_FUNC && !func_table[j]; j++) + ; + if (j < MAX_NR_FUNC) + fj = func_table[j]; + else + fj = first_free; + + delta = (q ? -strlen(q) : 1) + strlen(kbs->kb_string); + if (delta <= funcbufleft) { /* it fits in current buf */ + if (j < MAX_NR_FUNC) { + memmove(fj + delta, fj, first_free - fj); + for (k = j; k < MAX_NR_FUNC; k++) + if (func_table[k]) + func_table[k] += delta; + } + if (!q) + func_table[i] = fj; + funcbufleft -= delta; + } else { /* allocate a larger buffer */ + sz = 256; + while (sz < funcbufsize - funcbufleft + delta) + sz <<= 1; + fnw = (char *) kmalloc(sz, GFP_KERNEL); + if(!fnw) { + ret = -ENOMEM; + goto reterr; + } + + if (!q) + func_table[i] = fj; + if (fj > funcbufptr) + memmove(fnw, funcbufptr, fj - funcbufptr); + for (k = 0; k < j; k++) + if (func_table[k]) + func_table[k] = fnw + (func_table[k] - funcbufptr); + + if (first_free > fj) { + memmove(fnw + (fj - funcbufptr) + delta, fj, first_free - fj); + for (k = j; k < MAX_NR_FUNC; k++) + if (func_table[k]) + func_table[k] = fnw + (func_table[k] - funcbufptr) + delta; + } + if (funcbufptr != func_buf) + kfree(funcbufptr); + funcbufptr = fnw; + funcbufleft = funcbufleft - delta + sz - funcbufsize; + funcbufsize = sz; + } + strcpy(func_table[i], kbs->kb_string); + break; + } + ret = 0; +reterr: + kfree(kbs); + return ret; +} + +static inline int +do_fontx_ioctl(int cmd, struct consolefontdesc __user *user_cfd, int perm, struct console_font_op *op) +{ + struct consolefontdesc cfdarg; + int i; + + if (copy_from_user(&cfdarg, user_cfd, sizeof(struct consolefontdesc))) + return -EFAULT; + + switch (cmd) { + case PIO_FONTX: + if (!perm) + return -EPERM; + op->op = KD_FONT_OP_SET; + op->flags = KD_FONT_FLAG_OLD; + op->width = 8; + op->height = cfdarg.charheight; + op->charcount = cfdarg.charcount; + op->data = cfdarg.chardata; + return con_font_op(fg_console, op); + case GIO_FONTX: { + op->op = KD_FONT_OP_GET; + op->flags = KD_FONT_FLAG_OLD; + op->width = 8; + op->height = cfdarg.charheight; + op->charcount = cfdarg.charcount; + op->data = cfdarg.chardata; + i = con_font_op(fg_console, op); + if (i) + return i; + cfdarg.charheight = op->height; + cfdarg.charcount = op->charcount; + if (copy_to_user(user_cfd, &cfdarg, sizeof(struct consolefontdesc))) + return -EFAULT; + return 0; + } + } + return -EINVAL; +} + +static inline int +do_unimap_ioctl(int cmd, struct unimapdesc __user *user_ud, int perm, unsigned int console) +{ + struct unimapdesc tmp; + int i = 0; + + if (copy_from_user(&tmp, user_ud, sizeof tmp)) + return -EFAULT; + if (tmp.entries) { + i = verify_area(VERIFY_WRITE, tmp.entries, + tmp.entry_ct*sizeof(struct unipair)); + if (i) return i; + } + switch (cmd) { + case PIO_UNIMAP: + if (!perm) + return -EPERM; + return con_set_unimap(console, tmp.entry_ct, tmp.entries); + case GIO_UNIMAP: + if (!perm && fg_console != console) + return -EPERM; + return con_get_unimap(console, tmp.entry_ct, &(user_ud->entry_ct), tmp.entries); + } + return 0; +} + +/* + * We handle the console-specific ioctl's here. We allow the + * capability to modify any console, not just the fg_console. + */ +int vt_ioctl(struct tty_struct *tty, struct file * file, + unsigned int cmd, unsigned long arg) +{ + struct vt_struct *vt = (struct vt_struct *)tty->driver_data; + struct vc_data *vc = vc_cons[vt->vc_num].d; + struct console_font_op op; /* used in multiple places here */ + struct kbd_struct * kbd; + unsigned int console; + unsigned char ucval; + void __user *up = (void __user *)arg; + int i, perm; + + console = vt->vc_num; + + if (!vc_cons_allocated(console)) /* impossible? */ + return -ENOIOCTLCMD; + + /* + * To have permissions to do most of the vt ioctls, we either have + * to be the owner of the tty, or have CAP_SYS_TTY_CONFIG. + */ + perm = 0; + if (current->signal->tty == tty || capable(CAP_SYS_TTY_CONFIG)) + perm = 1; + + kbd = kbd_table + console; + switch (cmd) { + case KIOCSOUND: + if (!perm) + return -EPERM; + if (arg) + arg = 1193182 / arg; + kd_mksound(arg, 0); + return 0; + + case KDMKTONE: + if (!perm) + return -EPERM; + { + unsigned int ticks, count; + + /* + * Generate the tone for the appropriate number of ticks. + * If the time is zero, turn off sound ourselves. + */ + ticks = HZ * ((arg >> 16) & 0xffff) / 1000; + count = ticks ? (arg & 0xffff) : 0; + if (count) + count = 1193182 / count; + kd_mksound(count, ticks); + return 0; + } + + case KDGKBTYPE: + /* + * this is naive. + */ + ucval = keyboard_type; + goto setchar; + + /* + * These cannot be implemented on any machine that implements + * ioperm() in user level (such as Alpha PCs) or not at all. + * + * XXX: you should never use these, just call ioperm directly.. + */ +#ifdef CONFIG_X86 + case KDADDIO: + case KDDELIO: + /* + * KDADDIO and KDDELIO may be able to add ports beyond what + * we reject here, but to be safe... + */ + if (arg < GPFIRST || arg > GPLAST) + return -EINVAL; + return sys_ioperm(arg, 1, (cmd == KDADDIO)) ? -ENXIO : 0; + + case KDENABIO: + case KDDISABIO: + return sys_ioperm(GPFIRST, GPNUM, + (cmd == KDENABIO)) ? -ENXIO : 0; +#endif + + /* Linux m68k/i386 interface for setting the keyboard delay/repeat rate */ + + case KDKBDREP: + { + struct kbd_repeat kbrep; + int err; + + if (!capable(CAP_SYS_TTY_CONFIG)) + return -EPERM; + + if (copy_from_user(&kbrep, up, sizeof(struct kbd_repeat))) + return -EFAULT; + err = kbd_rate(&kbrep); + if (err) + return err; + if (copy_to_user(up, &kbrep, sizeof(struct kbd_repeat))) + return -EFAULT; + return 0; + } + + case KDSETMODE: + /* + * currently, setting the mode from KD_TEXT to KD_GRAPHICS + * doesn't do a whole lot. i'm not sure if it should do any + * restoration of modes or what... + * + * XXX It should at least call into the driver, fbdev's definitely + * need to restore their engine state. --BenH + */ + if (!perm) + return -EPERM; + switch (arg) { + case KD_GRAPHICS: + break; + case KD_TEXT0: + case KD_TEXT1: + arg = KD_TEXT; + case KD_TEXT: + break; + default: + return -EINVAL; + } + if (vt_cons[console]->vc_mode == (unsigned char) arg) + return 0; + vt_cons[console]->vc_mode = (unsigned char) arg; + if (console != fg_console) + return 0; + /* + * explicitly blank/unblank the screen if switching modes + */ + acquire_console_sem(); + if (arg == KD_TEXT) + do_unblank_screen(1); + else + do_blank_screen(1); + release_console_sem(); + return 0; + + case KDGETMODE: + ucval = vt_cons[console]->vc_mode; + goto setint; + + case KDMAPDISP: + case KDUNMAPDISP: + /* + * these work like a combination of mmap and KDENABIO. + * this could be easily finished. + */ + return -EINVAL; + + case KDSKBMODE: + if (!perm) + return -EPERM; + switch(arg) { + case K_RAW: + kbd->kbdmode = VC_RAW; + break; + case K_MEDIUMRAW: + kbd->kbdmode = VC_MEDIUMRAW; + break; + case K_XLATE: + kbd->kbdmode = VC_XLATE; + compute_shiftstate(); + break; + case K_UNICODE: + kbd->kbdmode = VC_UNICODE; + compute_shiftstate(); + break; + default: + return -EINVAL; + } + tty_ldisc_flush(tty); + return 0; + + case KDGKBMODE: + ucval = ((kbd->kbdmode == VC_RAW) ? K_RAW : + (kbd->kbdmode == VC_MEDIUMRAW) ? K_MEDIUMRAW : + (kbd->kbdmode == VC_UNICODE) ? K_UNICODE : + K_XLATE); + goto setint; + + /* this could be folded into KDSKBMODE, but for compatibility + reasons it is not so easy to fold KDGKBMETA into KDGKBMODE */ + case KDSKBMETA: + switch(arg) { + case K_METABIT: + clr_vc_kbd_mode(kbd, VC_META); + break; + case K_ESCPREFIX: + set_vc_kbd_mode(kbd, VC_META); + break; + default: + return -EINVAL; + } + return 0; + + case KDGKBMETA: + ucval = (vc_kbd_mode(kbd, VC_META) ? K_ESCPREFIX : K_METABIT); + setint: + return put_user(ucval, (int __user *)arg); + + case KDGETKEYCODE: + case KDSETKEYCODE: + if(!capable(CAP_SYS_TTY_CONFIG)) + perm=0; + return do_kbkeycode_ioctl(cmd, up, perm); + + case KDGKBENT: + case KDSKBENT: + return do_kdsk_ioctl(cmd, up, perm, kbd); + + case KDGKBSENT: + case KDSKBSENT: + return do_kdgkb_ioctl(cmd, up, perm); + + case KDGKBDIACR: + { + struct kbdiacrs __user *a = up; + + if (put_user(accent_table_size, &a->kb_cnt)) + return -EFAULT; + if (copy_to_user(a->kbdiacr, accent_table, accent_table_size*sizeof(struct kbdiacr))) + return -EFAULT; + return 0; + } + + case KDSKBDIACR: + { + struct kbdiacrs __user *a = up; + unsigned int ct; + + if (!perm) + return -EPERM; + if (get_user(ct,&a->kb_cnt)) + return -EFAULT; + if (ct >= MAX_DIACR) + return -EINVAL; + accent_table_size = ct; + if (copy_from_user(accent_table, a->kbdiacr, ct*sizeof(struct kbdiacr))) + return -EFAULT; + return 0; + } + + /* the ioctls below read/set the flags usually shown in the leds */ + /* don't use them - they will go away without warning */ + case KDGKBLED: + ucval = kbd->ledflagstate | (kbd->default_ledflagstate << 4); + goto setchar; + + case KDSKBLED: + if (!perm) + return -EPERM; + if (arg & ~0x77) + return -EINVAL; + kbd->ledflagstate = (arg & 7); + kbd->default_ledflagstate = ((arg >> 4) & 7); + set_leds(); + return 0; + + /* the ioctls below only set the lights, not the functions */ + /* for those, see KDGKBLED and KDSKBLED above */ + case KDGETLED: + ucval = getledstate(); + setchar: + return put_user(ucval, (char __user *)arg); + + case KDSETLED: + if (!perm) + return -EPERM; + setledstate(kbd, arg); + return 0; + + /* + * A process can indicate its willingness to accept signals + * generated by pressing an appropriate key combination. + * Thus, one can have a daemon that e.g. spawns a new console + * upon a keypress and then changes to it. + * See also the kbrequest field of inittab(5). + */ + case KDSIGACCEPT: + { + extern int spawnpid, spawnsig; + if (!perm || !capable(CAP_KILL)) + return -EPERM; + if (arg < 1 || arg > _NSIG || arg == SIGKILL) + return -EINVAL; + spawnpid = current->pid; + spawnsig = arg; + return 0; + } + + case VT_SETMODE: + { + struct vt_mode tmp; + + if (!perm) + return -EPERM; + if (copy_from_user(&tmp, up, sizeof(struct vt_mode))) + return -EFAULT; + if (tmp.mode != VT_AUTO && tmp.mode != VT_PROCESS) + return -EINVAL; + acquire_console_sem(); + vt_cons[console]->vt_mode = tmp; + /* the frsig is ignored, so we set it to 0 */ + vt_cons[console]->vt_mode.frsig = 0; + vt_cons[console]->vt_pid = current->pid; + /* no switch is required -- saw@shade.msu.ru */ + vt_cons[console]->vt_newvt = -1; + release_console_sem(); + return 0; + } + + case VT_GETMODE: + { + struct vt_mode tmp; + int rc; + + acquire_console_sem(); + memcpy(&tmp, &vt_cons[console]->vt_mode, sizeof(struct vt_mode)); + release_console_sem(); + + rc = copy_to_user(up, &tmp, sizeof(struct vt_mode)); + return rc ? -EFAULT : 0; + } + + /* + * Returns global vt state. Note that VT 0 is always open, since + * it's an alias for the current VT, and people can't use it here. + * We cannot return state for more than 16 VTs, since v_state is short. + */ + case VT_GETSTATE: + { + struct vt_stat __user *vtstat = up; + unsigned short state, mask; + + if (put_user(fg_console + 1, &vtstat->v_active)) + return -EFAULT; + state = 1; /* /dev/tty0 is always open */ + for (i = 0, mask = 2; i < MAX_NR_CONSOLES && mask; ++i, mask <<= 1) + if (VT_IS_IN_USE(i)) + state |= mask; + return put_user(state, &vtstat->v_state); + } + + /* + * Returns the first available (non-opened) console. + */ + case VT_OPENQRY: + for (i = 0; i < MAX_NR_CONSOLES; ++i) + if (! VT_IS_IN_USE(i)) + break; + ucval = i < MAX_NR_CONSOLES ? (i+1) : -1; + goto setint; + + /* + * ioctl(fd, VT_ACTIVATE, num) will cause us to switch to vt # num, + * with num >= 1 (switches to vt 0, our console, are not allowed, just + * to preserve sanity). + */ + case VT_ACTIVATE: + if (!perm) + return -EPERM; + if (arg == 0 || arg > MAX_NR_CONSOLES) + return -ENXIO; + arg--; + acquire_console_sem(); + i = vc_allocate(arg); + release_console_sem(); + if (i) + return i; + set_console(arg); + return 0; + + /* + * wait until the specified VT has been activated + */ + case VT_WAITACTIVE: + if (!perm) + return -EPERM; + if (arg == 0 || arg > MAX_NR_CONSOLES) + return -ENXIO; + return vt_waitactive(arg-1); + + /* + * If a vt is under process control, the kernel will not switch to it + * immediately, but postpone the operation until the process calls this + * ioctl, allowing the switch to complete. + * + * According to the X sources this is the behavior: + * 0: pending switch-from not OK + * 1: pending switch-from OK + * 2: completed switch-to OK + */ + case VT_RELDISP: + if (!perm) + return -EPERM; + if (vt_cons[console]->vt_mode.mode != VT_PROCESS) + return -EINVAL; + + /* + * Switching-from response + */ + if (vt_cons[console]->vt_newvt >= 0) + { + if (arg == 0) + /* + * Switch disallowed, so forget we were trying + * to do it. + */ + vt_cons[console]->vt_newvt = -1; + + else + { + /* + * The current vt has been released, so + * complete the switch. + */ + int newvt; + acquire_console_sem(); + newvt = vt_cons[console]->vt_newvt; + vt_cons[console]->vt_newvt = -1; + i = vc_allocate(newvt); + if (i) { + release_console_sem(); + return i; + } + /* + * When we actually do the console switch, + * make sure we are atomic with respect to + * other console switches.. + */ + complete_change_console(newvt); + release_console_sem(); + } + } + + /* + * Switched-to response + */ + else + { + /* + * If it's just an ACK, ignore it + */ + if (arg != VT_ACKACQ) + return -EINVAL; + } + + return 0; + + /* + * Disallocate memory associated to VT (but leave VT1) + */ + case VT_DISALLOCATE: + if (arg > MAX_NR_CONSOLES) + return -ENXIO; + if (arg == 0) { + /* disallocate all unused consoles, but leave 0 */ + acquire_console_sem(); + for (i=1; i<MAX_NR_CONSOLES; i++) + if (! VT_BUSY(i)) + vc_disallocate(i); + release_console_sem(); + } else { + /* disallocate a single console, if possible */ + arg--; + if (VT_BUSY(arg)) + return -EBUSY; + if (arg) { /* leave 0 */ + acquire_console_sem(); + vc_disallocate(arg); + release_console_sem(); + } + } + return 0; + + case VT_RESIZE: + { + struct vt_sizes __user *vtsizes = up; + ushort ll,cc; + if (!perm) + return -EPERM; + if (get_user(ll, &vtsizes->v_rows) || + get_user(cc, &vtsizes->v_cols)) + return -EFAULT; + for (i = 0; i < MAX_NR_CONSOLES; i++) { + acquire_console_sem(); + vc_resize(i, cc, ll); + release_console_sem(); + } + return 0; + } + + case VT_RESIZEX: + { + struct vt_consize __user *vtconsize = up; + ushort ll,cc,vlin,clin,vcol,ccol; + if (!perm) + return -EPERM; + if (verify_area(VERIFY_READ, vtconsize, + sizeof(struct vt_consize))) + return -EFAULT; + __get_user(ll, &vtconsize->v_rows); + __get_user(cc, &vtconsize->v_cols); + __get_user(vlin, &vtconsize->v_vlin); + __get_user(clin, &vtconsize->v_clin); + __get_user(vcol, &vtconsize->v_vcol); + __get_user(ccol, &vtconsize->v_ccol); + vlin = vlin ? vlin : vc->vc_scan_lines; + if (clin) { + if (ll) { + if (ll != vlin/clin) + return -EINVAL; /* Parameters don't add up */ + } else + ll = vlin/clin; + } + if (vcol && ccol) { + if (cc) { + if (cc != vcol/ccol) + return -EINVAL; + } else + cc = vcol/ccol; + } + + if (clin > 32) + return -EINVAL; + + for (i = 0; i < MAX_NR_CONSOLES; i++) { + if (!vc_cons[i].d) + continue; + acquire_console_sem(); + if (vlin) + vc_cons[i].d->vc_scan_lines = vlin; + if (clin) + vc_cons[i].d->vc_font.height = clin; + vc_resize(i, cc, ll); + release_console_sem(); + } + return 0; + } + + case PIO_FONT: { + if (!perm) + return -EPERM; + op.op = KD_FONT_OP_SET; + op.flags = KD_FONT_FLAG_OLD | KD_FONT_FLAG_DONT_RECALC; /* Compatibility */ + op.width = 8; + op.height = 0; + op.charcount = 256; + op.data = up; + return con_font_op(fg_console, &op); + } + + case GIO_FONT: { + op.op = KD_FONT_OP_GET; + op.flags = KD_FONT_FLAG_OLD; + op.width = 8; + op.height = 32; + op.charcount = 256; + op.data = up; + return con_font_op(fg_console, &op); + } + + case PIO_CMAP: + if (!perm) + return -EPERM; + return con_set_cmap(up); + + case GIO_CMAP: + return con_get_cmap(up); + + case PIO_FONTX: + case GIO_FONTX: + return do_fontx_ioctl(cmd, up, perm, &op); + + case PIO_FONTRESET: + { + if (!perm) + return -EPERM; + +#ifdef BROKEN_GRAPHICS_PROGRAMS + /* With BROKEN_GRAPHICS_PROGRAMS defined, the default + font is not saved. */ + return -ENOSYS; +#else + { + op.op = KD_FONT_OP_SET_DEFAULT; + op.data = NULL; + i = con_font_op(fg_console, &op); + if (i) return i; + con_set_default_unimap(fg_console); + return 0; + } +#endif + } + + case KDFONTOP: { + if (copy_from_user(&op, up, sizeof(op))) + return -EFAULT; + if (!perm && op.op != KD_FONT_OP_GET) + return -EPERM; + i = con_font_op(console, &op); + if (i) return i; + if (copy_to_user(up, &op, sizeof(op))) + return -EFAULT; + return 0; + } + + case PIO_SCRNMAP: + if (!perm) + return -EPERM; + return con_set_trans_old(up); + + case GIO_SCRNMAP: + return con_get_trans_old(up); + + case PIO_UNISCRNMAP: + if (!perm) + return -EPERM; + return con_set_trans_new(up); + + case GIO_UNISCRNMAP: + return con_get_trans_new(up); + + case PIO_UNIMAPCLR: + { struct unimapinit ui; + if (!perm) + return -EPERM; + i = copy_from_user(&ui, up, sizeof(struct unimapinit)); + if (i) return -EFAULT; + con_clear_unimap(console, &ui); + return 0; + } + + case PIO_UNIMAP: + case GIO_UNIMAP: + return do_unimap_ioctl(cmd, up, perm, console); + + case VT_LOCKSWITCH: + if (!capable(CAP_SYS_TTY_CONFIG)) + return -EPERM; + vt_dont_switch = 1; + return 0; + case VT_UNLOCKSWITCH: + if (!capable(CAP_SYS_TTY_CONFIG)) + return -EPERM; + vt_dont_switch = 0; + return 0; + default: + return -ENOIOCTLCMD; + } +} + +/* + * Sometimes we want to wait until a particular VT has been activated. We + * do it in a very simple manner. Everybody waits on a single queue and + * get woken up at once. Those that are satisfied go on with their business, + * while those not ready go back to sleep. Seems overkill to add a wait + * to each vt just for this - usually this does nothing! + */ +static DECLARE_WAIT_QUEUE_HEAD(vt_activate_queue); + +/* + * Sleeps until a vt is activated, or the task is interrupted. Returns + * 0 if activation, -EINTR if interrupted. + */ +int vt_waitactive(int vt) +{ + int retval; + DECLARE_WAITQUEUE(wait, current); + + add_wait_queue(&vt_activate_queue, &wait); + for (;;) { + set_current_state(TASK_INTERRUPTIBLE); + retval = 0; + if (vt == fg_console) + break; + retval = -EINTR; + if (signal_pending(current)) + break; + schedule(); + } + remove_wait_queue(&vt_activate_queue, &wait); + current->state = TASK_RUNNING; + return retval; +} + +#define vt_wake_waitactive() wake_up(&vt_activate_queue) + +void reset_vc(unsigned int new_console) +{ + vt_cons[new_console]->vc_mode = KD_TEXT; + kbd_table[new_console].kbdmode = VC_XLATE; + vt_cons[new_console]->vt_mode.mode = VT_AUTO; + vt_cons[new_console]->vt_mode.waitv = 0; + vt_cons[new_console]->vt_mode.relsig = 0; + vt_cons[new_console]->vt_mode.acqsig = 0; + vt_cons[new_console]->vt_mode.frsig = 0; + vt_cons[new_console]->vt_pid = -1; + vt_cons[new_console]->vt_newvt = -1; + if (!in_interrupt()) /* Via keyboard.c:SAK() - akpm */ + reset_palette(new_console) ; +} + +/* + * Performs the back end of a vt switch + */ +void complete_change_console(unsigned int new_console) +{ + unsigned char old_vc_mode; + + last_console = fg_console; + + /* + * If we're switching, we could be going from KD_GRAPHICS to + * KD_TEXT mode or vice versa, which means we need to blank or + * unblank the screen later. + */ + old_vc_mode = vt_cons[fg_console]->vc_mode; + switch_screen(new_console); + + /* + * This can't appear below a successful kill_proc(). If it did, + * then the *blank_screen operation could occur while X, having + * received acqsig, is waking up on another processor. This + * condition can lead to overlapping accesses to the VGA range + * and the framebuffer (causing system lockups). + * + * To account for this we duplicate this code below only if the + * controlling process is gone and we've called reset_vc. + */ + if (old_vc_mode != vt_cons[new_console]->vc_mode) + { + if (vt_cons[new_console]->vc_mode == KD_TEXT) + do_unblank_screen(1); + else + do_blank_screen(1); + } + + /* + * If this new console is under process control, send it a signal + * telling it that it has acquired. Also check if it has died and + * clean up (similar to logic employed in change_console()) + */ + if (vt_cons[new_console]->vt_mode.mode == VT_PROCESS) + { + /* + * Send the signal as privileged - kill_proc() will + * tell us if the process has gone or something else + * is awry + */ + if (kill_proc(vt_cons[new_console]->vt_pid, + vt_cons[new_console]->vt_mode.acqsig, + 1) != 0) + { + /* + * The controlling process has died, so we revert back to + * normal operation. In this case, we'll also change back + * to KD_TEXT mode. I'm not sure if this is strictly correct + * but it saves the agony when the X server dies and the screen + * remains blanked due to KD_GRAPHICS! It would be nice to do + * this outside of VT_PROCESS but there is no single process + * to account for and tracking tty count may be undesirable. + */ + reset_vc(new_console); + + if (old_vc_mode != vt_cons[new_console]->vc_mode) + { + if (vt_cons[new_console]->vc_mode == KD_TEXT) + do_unblank_screen(1); + else + do_blank_screen(1); + } + } + } + + /* + * Wake anyone waiting for their VT to activate + */ + vt_wake_waitactive(); + return; +} + +/* + * Performs the front-end of a vt switch + */ +void change_console(unsigned int new_console) +{ + if ((new_console == fg_console) || (vt_dont_switch)) + return; + if (!vc_cons_allocated(new_console)) + return; + + /* + * If this vt is in process mode, then we need to handshake with + * that process before switching. Essentially, we store where that + * vt wants to switch to and wait for it to tell us when it's done + * (via VT_RELDISP ioctl). + * + * We also check to see if the controlling process still exists. + * If it doesn't, we reset this vt to auto mode and continue. + * This is a cheap way to track process control. The worst thing + * that can happen is: we send a signal to a process, it dies, and + * the switch gets "lost" waiting for a response; hopefully, the + * user will try again, we'll detect the process is gone (unless + * the user waits just the right amount of time :-) and revert the + * vt to auto control. + */ + if (vt_cons[fg_console]->vt_mode.mode == VT_PROCESS) + { + /* + * Send the signal as privileged - kill_proc() will + * tell us if the process has gone or something else + * is awry + */ + if (kill_proc(vt_cons[fg_console]->vt_pid, + vt_cons[fg_console]->vt_mode.relsig, + 1) == 0) + { + /* + * It worked. Mark the vt to switch to and + * return. The process needs to send us a + * VT_RELDISP ioctl to complete the switch. + */ + vt_cons[fg_console]->vt_newvt = new_console; + return; + } + + /* + * The controlling process has died, so we revert back to + * normal operation. In this case, we'll also change back + * to KD_TEXT mode. I'm not sure if this is strictly correct + * but it saves the agony when the X server dies and the screen + * remains blanked due to KD_GRAPHICS! It would be nice to do + * this outside of VT_PROCESS but there is no single process + * to account for and tracking tty count may be undesirable. + */ + reset_vc(fg_console); + + /* + * Fall through to normal (VT_AUTO) handling of the switch... + */ + } + + /* + * Ignore all switches in KD_GRAPHICS+VT_AUTO mode + */ +#ifndef CONFIG_FB_UI + if (vt_cons[fg_console]->vc_mode == KD_GRAPHICS) + return; +#endif + + complete_change_console(new_console); +} diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig @@ -0,0 +1,165 @@ +# +# Input device configuration +# + +menu "Input device support" + +config INPUT + tristate "Input devices (needed for keyboard, mouse, ...)" if EMBEDDED + default y + ---help--- + Say Y here if you have any input device (mouse, keyboard, tablet, + joystick, steering wheel ...) connected to your system and want + it to be available to applications. This includes standard PS/2 + keyboard and mouse. + + Say N here if you have a headless (no monitor, no keyboard) system. + + More information is available: <file:Documentation/input/input.txt> + + If unsure, say Y. + + To compile this driver as a module, choose M here: the + module will be called input. + +comment "Userland interfaces" + +config INPUT_MOUSEDEV + tristate "Mouse interface" if EMBEDDED + default y + depends on INPUT + ---help--- + Say Y here if you want your mouse to be accessible as char devices + 13:32+ - /dev/input/mouseX and 13:63 - /dev/input/mice as an + emulated IntelliMouse Explorer PS/2 mouse. That way, all user space + programs (includung SVGAlib, GPM and X) will be able to use your + mouse. + + If unsure, say Y. + + To compile this driver as a module, choose M here: the + module will be called mousedev. + +config INPUT_MOUSEDEV_PSAUX + bool "Provide legacy /dev/psaux device" + default y + depends on INPUT_MOUSEDEV + ---help--- + Say Y here if you want your mouse also be accessible as char device + 10:1 - /dev/psaux. The data available through /dev/psaux is exactly + the same as the data from /dev/input/mice. + + If unsure, say Y. + + +config INPUT_MOUSEDEV_SCREEN_X + int "Horizontal screen resolution" + depends on INPUT_MOUSEDEV + default "1024" + help + If you're using a digitizer, or a graphic tablet, and want to use + it as a mouse then the mousedev driver needs to know the X window + screen resolution you are using to correctly scale the data. If + you're not using a digitizer, this value is ignored. + +config INPUT_MOUSEDEV_SCREEN_Y + int "Vertical screen resolution" + depends on INPUT_MOUSEDEV + default "768" + help + If you're using a digitizer, or a graphic tablet, and want to use + it as a mouse then the mousedev driver needs to know the X window + screen resolution you are using to correctly scale the data. If + you're not using a digitizer, this value is ignored. + +config INPUT_JOYDEV + tristate "Joystick interface" + depends on INPUT + ---help--- + Say Y here if you want your joystick or gamepad to be + accessible as char device 13:0+ - /dev/input/jsX device. + + If unsure, say Y. + + More information is available: <file:Documentation/input/joystick.txt> + + To compile this driver as a module, choose M here: the + module will be called joydev. + +config INPUT_TSDEV + tristate "Touchscreen interface" + depends on INPUT + ---help--- + Say Y here if you have an application that only can understand the + Compaq touchscreen protocol for absolute pointer data. This is + useful namely for embedded configurations. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called tsdev. + +config INPUT_TSDEV_SCREEN_X + int "Horizontal screen resolution" + depends on INPUT_TSDEV + default "240" + +config INPUT_TSDEV_SCREEN_Y + int "Vertical screen resolution" + depends on INPUT_TSDEV + default "320" + +config INPUT_EVDEV + tristate "Event interface" + depends on INPUT + help + Say Y here if you want your input device events be accessible + under char device 13:64+ - /dev/input/eventX in a generic way. + + To compile this driver as a module, choose M here: the + module will be called evdev. + +config INPUT_EVBUG + tristate "Event debugging" + depends on INPUT + ---help--- + Say Y here if you have a problem with the input subsystem and + want all events (keypresses, mouse movements), to be output to + the system log. While this is useful for debugging, it's also + a security threat - your keypresses include your passwords, of + course. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called evbug. + +config INPUT_FBUI + tristate "FBUI input handling" + default y + depends on INPUT + ---help--- + Say Y here if you will also enable FBUI, which is the + in-kernel framebuffer-based graphical user interface. + + +comment "Input I/O drivers" + +source "drivers/input/gameport/Kconfig" + +source "drivers/input/serio/Kconfig" + +comment "Input Device Drivers" + +source "drivers/input/keyboard/Kconfig" + +source "drivers/input/mouse/Kconfig" + +source "drivers/input/joystick/Kconfig" + +source "drivers/input/touchscreen/Kconfig" + +source "drivers/input/misc/Kconfig" + +endmenu + diff --git a/drivers/input/Makefile b/drivers/input/Makefile @@ -0,0 +1,21 @@ +# +# Makefile for the input core drivers. +# + +# Each configuration option enables a list of files. + +obj-$(CONFIG_INPUT) += input.o +obj-$(CONFIG_INPUT_MOUSEDEV) += mousedev.o +obj-$(CONFIG_INPUT_JOYDEV) += joydev.o +obj-$(CONFIG_INPUT_EVDEV) += evdev.o +obj-$(CONFIG_INPUT_TSDEV) += tsdev.o +obj-$(CONFIG_INPUT_POWER) += power.o +obj-$(CONFIG_INPUT_EVBUG) += evbug.o + +obj-$(CONFIG_INPUT_FBUI) += fbui-input.o + +obj-$(CONFIG_INPUT_KEYBOARD) += keyboard/ +obj-$(CONFIG_INPUT_MOUSE) += mouse/ +obj-$(CONFIG_INPUT_JOYSTICK) += joystick/ +obj-$(CONFIG_INPUT_TOUCHSCREEN) += touchscreen/ +obj-$(CONFIG_INPUT_MISC) += misc/ diff --git a/drivers/input/fbui-input.c b/drivers/input/fbui-input.c @@ -0,0 +1,140 @@ +/* + * FBUI input event snagging + * Code for relaying input events to FBUI. + * + * Modification for FBUI by Zachary Smith, copyright (C) 2004. + * Based on evbug, which is copyright (c) 1999-2001 Vojtech Pavlik + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to <fbui@comcast.net>. + */ + +#include <linux/slab.h> +#include <linux/module.h> +#include <linux/input.h> +#include <linux/init.h> +#include <linux/device.h> +#include <linux/input.h> +#include <linux/spinlock.h> + + + +MODULE_AUTHOR("Zachary Smith <fbui@comcast.net>"); +MODULE_DESCRIPTION("Input-driver-event besnagger module"); +MODULE_LICENSE("GPL"); + + +#ifdef CONFIG_INPUT_FBUI + +static char fbui_input_name[] = "fbui_input"; + +static spinlock_t mylock = SPIN_LOCK_UNLOCKED; + +static FBUIInputEventHandler *handler = NULL; +static u32 handlerparam = 0; + + +void fbui_input_register_handler (FBUIInputEventHandler *h, u32 param) +{ + if (h) { + handler = h; + handlerparam = param; + } +} + +static void fbui_input_event(struct input_handle *handle, unsigned int type, unsigned int code, int value) +{ + unsigned long flags; + + // printk(KERN_INFO "fbui_input.c: Event. Dev: %s, Type: %d, Code: %d, Value: %d\n", handle->dev->phys, type, code, value); + + if (!handler) + return; + + spin_lock_irqsave(&mylock, flags); + + struct input_event e; + e.type = type; + e.code = code; + e.value= value; + do_gettimeofday(&e.time); + (handler) (handlerparam, &e); + + spin_unlock_irqrestore(&mylock, flags); +} + +static struct input_handle *fbui_input_connect(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id) +{ + struct input_handle *handle; + + if (!(handle = kmalloc(sizeof(struct input_handle), GFP_KERNEL))) + return NULL; + memset(handle, 0, sizeof(struct input_handle)); + + handle->dev = dev; + handle->handler = handler; + handle->name = fbui_input_name; + + input_open_device(handle); + + return handle; +} + +static void fbui_input_disconnect(struct input_handle *handle) +{ + input_close_device(handle); + kfree(handle); +} + +static struct input_device_id fbui_input_ids[] = { + { .driver_info = 1 }, /* Matches all devices */ + { }, /* Terminating zero entry */ +}; + +MODULE_DEVICE_TABLE(input, fbui_input_ids); + +static struct input_handler fbui_input_handler = { + .event = fbui_input_event, + .connect = fbui_input_connect, + .disconnect = fbui_input_disconnect, + .name = "fbui_input", + .id_table = fbui_input_ids, +}; + +int __init fbui_input_init(void) +{ + handler = NULL; + + printk(KERN_INFO "FBUI input module: initializing\n"); + + input_register_handler(&fbui_input_handler); + return 0; +} + +void __exit fbui_input_exit(void) +{ + handler = NULL; + + input_unregister_handler(&fbui_input_handler); +} + +EXPORT_SYMBOL(fbui_input_register_handler); + +module_init(fbui_input_init); +module_exit(fbui_input_exit); + +#endif diff --git a/drivers/input/fbui-input.o b/drivers/input/fbui-input.o Binary files differ. diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig @@ -0,0 +1,1054 @@ +# +# Video configuration +# + +menu "Graphics support" + +config FB + bool "Support for frame buffer devices" + ---help--- + The frame buffer device provides an abstraction for the graphics + hardware. It represents the frame buffer of some video hardware and + allows application software to access the graphics hardware through + a well-defined interface, so the software doesn't need to know + anything about the low-level (hardware register) stuff. + + Frame buffer devices work identically across the different + architectures supported by Linux and make the implementation of + application programs easier and more portable; at this point, an X + server exists which uses the frame buffer device exclusively. + On several non-X86 architectures, the frame buffer device is the + only way to use the graphics hardware. + + The device is accessed through special device nodes, usually located + in the /dev directory, i.e. /dev/fb*. + + You need an utility program called fbset to make full use of frame + buffer devices. Please read <file:Documentation/fb/framebuffer.txt> + and the Framebuffer-HOWTO at + <http://www.tahallah.demon.co.uk/programming/prog.html> for more + information. + + Say Y here and to the driver for your graphics board below if you + are compiling a kernel for a non-x86 architecture. + + If you are compiling for the x86 architecture, you can say Y if you + want to play with it, but it is not essential. Please note that + running graphical applications that directly touch the hardware + (e.g. an accelerated X server) and that are not frame buffer + device-aware may cause unexpected results. If unsure, say N. + +config FB_UI + bool "Framebuffer UI: in-kernel graphical user interface" + depends on FB + default y + help + FBUI is a small (25kB) GUI. + It was placed in the kernel in order to prevent that + it will ever become bloated, as X and other GUIs have. + + FBUI currently allows each process to have one window, and + windows may not overlap. Each virtual console may have windows. + One process per VC may request to be a window manager. + + Graphics functions include + draw point, read point, draw line, draw rectangle, + fill rectangle, clear window, clear area, draw inverted line, + put pixels, put RGB pixels, copy area, get event, draw string. + + Fonts supported are monochrome PCF format and they reside in userspace. + + Both keyboard and mouse input are supported, but you must + compile in the event interface (/dev/input/event*) and + the fbui_input module. + + Current sample programs include: + load monitor, jpeg viewer, analog clock, two window managers, + screen dump, and terminal. + +config FB_UI_WINDOWSPERVC + int "Maximum windows per virtual console" + depends on FB_UI + default "24" + +config FB_UI_EVENTQUEUELEN + int "Per-process event queue length" + depends on FB_UI + default "16" + +config FB_MODE_HELPERS + bool "Enable Video Mode Handling Helpers" + depends on FB + default y + ---help--- + This enables functions for handling video modes using the + Generalized Timing Formula and the EDID parser. A few drivers rely + on this feature such as the radeonfb, rivafb, and the i810fb. If + your driver does not take advantage of this feature, choosing Y will + just increase the kernel size by about 5K. + +config FB_CIRRUS + tristate "Cirrus Logic support" + depends on FB && (ZORRO || PCI) + ---help--- + This enables support for Cirrus Logic GD542x/543x based boards on + Amiga: SD64, Piccolo, Picasso II/II+, Picasso IV, or EGS Spectrum. + + If you have a PCI-based system, this enables support for these + chips: GD-543x, GD-544x, GD-5480. + + Please read the file <file:Documentation/fb/cirrusfb.txt>. + + Say N unless you have such a graphics board or plan to get one + before you next recompile the kernel. + +config FB_PM2 + tristate "Permedia2 support" + depends on FB && ((AMIGA && BROKEN) || PCI) + help + This is the frame buffer device driver for the Permedia2 AGP frame + buffer card from ASK, aka `Graphic Blaster Exxtreme'. There is a + product page at + <http://www.ask.com.hk/product/Permedia%202/permedia2.htm>. + +config FB_PM2_FIFO_DISCONNECT + bool "enable FIFO disconnect feature" + depends on FB_PM2 && PCI + help + Support the Permedia2 FIFO disconnect feature (see CONFIG_FB_PM2). + +config FB_ARMCLCD + tristate "ARM PrimeCell PL110 support" + depends on FB && ARM && ARM_AMBA + help + This framebuffer device driver is for the ARM PrimeCell PL110 + Colour LCD controller. ARM PrimeCells provide the building + blocks for System on a Chip devices. + + If you want to compile this as a module (=code which can be + inserted into and removed from the running kernel), say M + here and read <file:Documentation/modules.txt>. The module + will be called amba-clcd. + +config FB_ACORN + bool "Acorn VIDC support" + depends on FB && ARM && ARCH_ACORN + help + This is the frame buffer device driver for the Acorn VIDC graphics + hardware found in Acorn RISC PCs and other ARM-based machines. If + unsure, say N. + +config FB_CLPS711X + bool "CLPS711X LCD support" + depends on FB && ARM && ARCH_CLPS711X + +config FB_SA1100 + bool "SA-1100 LCD support" + depends on FB && ARM && ARCH_SA1100 + help + This is a framebuffer device for the SA-1100 LCD Controller. + See <http://www.linux-fbdev.org/> for information on framebuffer + devices. + + If you plan to use the LCD display with your SA-1100 system, say + Y here. + +config FB_CYBER2000 + tristate "CyberPro 2000/2010/5000 support" + depends on FB && PCI && (BROKEN || !SPARC64) + help + This enables support for the Integraphics CyberPro 20x0 and 5000 + VGA chips used in the Rebel.com Netwinder and other machines. + Say Y if you have a NetWinder or a graphics card containing this + device, otherwise say N. + +config FB_APOLLO + bool + depends on FB && APOLLO + default y + +config FB_Q40 + bool + depends on FB && Q40 + default y + +config FB_AMIGA + tristate "Amiga native chipset support" + depends on FB && AMIGA + help + This is the frame buffer device driver for the builtin graphics + chipset found in Amigas. + + To compile this driver as a module, choose M here: the + module will be called amifb. + +config FB_AMIGA_OCS + bool "Amiga OCS chipset support" + depends on FB_AMIGA + help + This enables support for the original Agnus and Denise video chips, + found in the Amiga 1000 and most A500's and A2000's. If you intend + to run Linux on any of these systems, say Y; otherwise say N. + +config FB_AMIGA_ECS + bool "Amiga ECS chipset support" + depends on FB_AMIGA + help + This enables support for the Enhanced Chip Set, found in later + A500's, later A2000's, the A600, the A3000, the A3000T and CDTV. If + you intend to run Linux on any of these systems, say Y; otherwise + say N. + +config FB_AMIGA_AGA + bool "Amiga AGA chipset support" + depends on FB_AMIGA + help + This enables support for the Advanced Graphics Architecture (also + known as the AGA or AA) Chip Set, found in the A1200, A4000, A4000T + and CD32. If you intend to run Linux on any of these systems, say Y; + otherwise say N. + +config FB_CYBER + tristate "Amiga CyberVision 64 support" + depends on FB && ZORRO && BROKEN + help + This enables support for the Cybervision 64 graphics card from + Phase5. Please note that its use is not all that intuitive (i.e. if + you have any questions, be sure to ask!). Say N unless you have a + Cybervision 64 or plan to get one before you next recompile the + kernel. Please note that this driver DOES NOT support the + Cybervision 64/3D card, as they use incompatible video chips. + +config FB_VIRGE + bool "Amiga CyberVision 64/3D support " + depends on FB && ZORRO && BROKEN + help + This enables support for the Cybervision 64/3D graphics card from + Phase5. Please note that its use is not all that intuitive (i.e. if + you have any questions, be sure to ask!). Say N unless you have a + Cybervision 64/3D or plan to get one before you next recompile the + kernel. Please note that this driver DOES NOT support the older + Cybervision 64 card, as they use incompatible video chips. + +config FB_RETINAZ3 + tristate "Amiga Retina Z3 support" + depends on FB && ZORRO && BROKEN + help + This enables support for the Retina Z3 graphics card. Say N unless + you have a Retina Z3 or plan to get one before you next recompile + the kernel. + +config FB_FM2 + bool "Amiga FrameMaster II/Rainbow II support" + depends on FB && ZORRO + help + This is the frame buffer device driver for the Amiga FrameMaster + card from BSC (exhibited 1992 but not shipped as a CBM product). + +config FB_ATARI + bool "Atari native chipset support" + depends on FB && ATARI && BROKEN + help + This is the frame buffer device driver for the builtin graphics + chipset found in Ataris. + +config FB_OF + bool "Open Firmware frame buffer device support" + depends on FB && (PPC64 || PPC_OF) + help + Say Y if you want support with Open Firmware for your graphics + board. + +config FB_CONTROL + bool "Apple \"control\" display support" + depends on FB && PPC_PMAC + help + This driver supports a frame buffer for the graphics adapter in the + Power Macintosh 7300 and others. + +config FB_PLATINUM + bool "Apple \"platinum\" display support" + depends on FB && PPC_PMAC + help + This driver supports a frame buffer for the "platinum" graphics + adapter in some Power Macintoshes. + +config FB_VALKYRIE + bool "Apple \"valkyrie\" display support" + depends on FB && (MAC || PPC_PMAC) + help + This driver supports a frame buffer for the "valkyrie" graphics + adapter in some Power Macintoshes. + +config FB_CT65550 + bool "Chips 65550 display support" + depends on FB && PPC + help + This is the frame buffer device driver for the Chips & Technologies + 65550 graphics chip in PowerBooks. + +config FB_ASILIANT + bool "Chips 69000 display support" + depends on FB && PCI + +config FB_IMSTT + bool "IMS Twin Turbo display support" + depends on FB && PCI + help + The IMS Twin Turbo is a PCI-based frame buffer card bundled with + many Macintosh and compatible computers. + +config FB_S3TRIO + bool "S3 Trio display support" + depends on FB && PPC && BROKEN + help + If you have a S3 Trio say Y. Say N for S3 Virge. + +config FB_VGA16 + tristate "VGA 16-color graphics support" + depends on FB && (X86 || PPC) + help + This is the frame buffer device driver for VGA 16 color graphic + cards. Say Y if you have such a card. + + To compile this driver as a module, choose M here: the + module will be called vga16fb. + +config FB_STI + tristate "HP STI frame buffer device support" + depends on FB && PARISC + default y + ---help--- + STI refers to the HP "Standard Text Interface" which is a set of + BIOS routines contained in a ROM chip in HP PA-RISC based machines. + Enabling this option will implement the linux framebuffer device + using calls to the STI BIOS routines for initialisation. + + If you enable this option, you will get a planar framebuffer device + /dev/fb which will work on the most common HP graphic cards of the + NGLE family, including the artist chips (in the 7xx and Bxxx series), + HCRX, HCRX24, CRX, CRX24 and VisEG series. + + It is safe to enable this option, so you should probably say "Y". + +config FB_MAC + bool "Generic Macintosh display support" + depends on FB && MAC + +# bool ' Apple DAFB display support' CONFIG_FB_DAFB +config FB_HP300 + bool + depends on FB && HP300 + default y + +config FB_TGA + tristate "TGA framebuffer support" + depends on FB && ALPHA + help + This is the frame buffer device driver for generic TGA graphic + cards. Say Y if you have one of those. + +config FB_VESA + bool "VESA VGA graphics support" + depends on FB && (X86 || X86_64) + help + This is the frame buffer device driver for generic VESA 2.0 + compliant graphic cards. The older VESA 1.2 cards are not supported. + You will get a boot time penguin logo at no additional cost. Please + read <file:Documentation/fb/vesafb.txt>. If unsure, say Y. + +config VIDEO_SELECT + bool + depends on FB_VESA + default y + +config FB_HGA + tristate "Hercules mono graphics support" + depends on FB && X86 + help + Say Y here if you have a Hercules mono graphics card. + + To compile this driver as a module, choose M here: the + module will be called hgafb. + + As this card technology is 15 years old, most people will answer N + here. + +config FB_HGA_ACCEL + bool "Hercules mono Acceleration functions (EXPERIMENTAL)" + depends on FB_HGA && EXPERIMENTAL + ---help--- + This will compile the Hercules mono graphics with + acceleration functions. + + +config VIDEO_SELECT + bool + depends on FB && X86 + default y + +config FB_SGIVW + tristate "SGI Visual Workstation framebuffer support" + depends on FB && X86_VISWS + help + SGI Visual Workstation support for framebuffer graphics. + +config FB_GBE + bool "SGI Graphics Backend frame buffer support" + depends on FB && (SGI_IP32 || X86_VISWS) + help + This is the frame buffer device driver for SGI Graphics Backend. + This chip is used in SGI O2 and Visual Workstation 320/540. + +config FB_GBE_MEM + int "Video memory size in MB" + depends on FB_GBE + default 8 + help + This is the amount of memory reserved for the framebuffer, + which can be any value between 1MB and 8MB. + +config BUS_I2C + bool + depends on FB && VISWS + default y + +config FB_SUN3 + bool "Sun3 framebuffer support" + depends on FB && (SUN3 || SUN3X) && BROKEN + +config FB_BW2 + bool "BWtwo support" + depends on FB && ((SPARC32 || SPARC64) && FB_SBUS || (SUN3 || SUN3X) && FB_SUN3) + help + This is the frame buffer device driver for the BWtwo frame buffer. + +config FB_CG3 + bool "CGthree support" + depends on FB && ((SPARC32 || SPARC64) && FB_SBUS || (SUN3 || SUN3X) && FB_SUN3) + help + This is the frame buffer device driver for the CGthree frame buffer. + +config FB_CG6 + bool "CGsix (GX,TurboGX) support" + depends on FB && ((SPARC32 || SPARC64) && FB_SBUS || (SUN3 || SUN3X) && FB_SUN3) + help + This is the frame buffer device driver for the CGsix (GX, TurboGX) + frame buffer. + +config FB_PVR2 + tristate "NEC PowerVR 2 display support" + depends on FB && SH_DREAMCAST + ---help--- + Say Y here if you have a PowerVR 2 card in your box. If you plan to + run linux on your Dreamcast, you will have to say Y here. + This driver may or may not work on other PowerVR 2 cards, but is + totally untested. Use at your own risk. If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called pvr2fb. + + You can pass several parameters to the driver at boot time or at + module load time. The parameters look like "video=pvr2:XXX", where + the meaning of XXX can be found at the end of the main source file + (<file:drivers/video/pvr2fb.c>). Please see the file + <file:Documentation/fb/pvr2fb.txt>. + +config FB_EPSON1355 + bool "Epson 1355 framebuffer support" + depends on FB && (SUPERH || ARCH_CEIVA) + help + Build in support for the SED1355 Epson Research Embedded RAMDAC + LCD/CRT Controller (since redesignated as the S1D13505) as a + framebuffer. Product specs at + <http://www.erd.epson.com/vdc/html/products.htm>. + +config FB_RIVA + tristate "nVidia Riva support" + depends on FB && PCI + select I2C_ALGOBIT if FB_RIVA_I2C + select I2C if FB_RIVA_I2C + select FB_MODE_HELPERS + help + This driver supports graphics boards with the nVidia Riva/Geforce + chips. + Say Y if you have such a graphics board. + + To compile this driver as a module, choose M here: the + module will be called rivafb. + +config FB_RIVA_I2C + bool "Enable DDC Support" + depends on FB_RIVA + help + This enables I2C support for nVidia Chipsets. This is used + only for getting EDID information from the attached display + allowing for robust video mode handling and switching. + + Because fbdev-2.6 requires that drivers must be able to + independently validate video mode parameters, you should say Y + here. + +config FB_RIVA_DEBUG + bool "Lots of debug output from Riva(nVidia) driver" + depends on FB_RIVA + default n + help + Say Y here if you want the Riva driver to output all sorts + of debugging informations to provide to the maintainer when + something goes wrong. + +config FB_I810 + tristate "Intel 810/815 support (EXPERIMENTAL)" + depends on FB && EXPERIMENTAL && PCI && X86 && !X86_64 + select AGP + select AGP_INTEL + select FB_MODE_HELPERS + help + This driver supports the on-board graphics built in to the Intel 810 + and 815 chipsets. Say Y if you have and plan to use such a board. + + To compile this driver as a module, choose M here: the + module will be called i810fb. + + For more information, please read + <file:Documentation/fb/intel810.txt> + +config FB_I810_GTF + bool "use VESA Generalized Timing Formula" + depends on FB_I810 + help + If you say Y, then the VESA standard, Generalized Timing Formula + or GTF, will be used to calculate the required video timing values + per video mode. Since the GTF allows nondiscrete timings + (nondiscrete being a range of values as opposed to discrete being a + set of values), you'll be able to use any combination of horizontal + and vertical resolutions, and vertical refresh rates without having + to specify your own timing parameters. This is especially useful + to maximize the performance of an aging display, or if you just + have a display with nonstandard dimensions. A VESA compliant + monitor is recommended, but can still work with non-compliant ones. + If you need or want this, then select this option. The timings may + not be compliant with Intel's recommended values. Use at your own + risk. + + If you say N, the driver will revert to discrete video timings + using a set recommended by Intel in their documentation. + + If unsure, say N. + +config FB_MATROX + tristate "Matrox acceleration" + depends on FB && PCI + ---help--- + Say Y here if you have a Matrox Millennium, Matrox Millennium II, + Matrox Mystique, Matrox Mystique 220, Matrox Productiva G100, Matrox + Mystique G200, Matrox Millennium G200, Matrox Marvel G200 video, + Matrox G400, G450 or G550 card in your box. + + To compile this driver as a module, choose M here: the + module will be called matroxfb. + + You can pass several parameters to the driver at boot time or at + module load time. The parameters look like "video=matrox:XXX", and + are described in <file:Documentation/fb/matroxfb.txt>. + +config FB_MATROX_MILLENIUM + bool "Millennium I/II support" + depends on FB_MATROX + help + Say Y here if you have a Matrox Millennium or Matrox Millennium II + video card. If you select "Advanced lowlevel driver options" below, + you should check 4 bpp packed pixel, 8 bpp packed pixel, 16 bpp + packed pixel, 24 bpp packed pixel and 32 bpp packed pixel. You can + also use font widths different from 8. + +config FB_MATROX_MYSTIQUE + bool "Mystique support" + depends on FB_MATROX + help + Say Y here if you have a Matrox Mystique or Matrox Mystique 220 + video card. If you select "Advanced lowlevel driver options" below, + you should check 8 bpp packed pixel, 16 bpp packed pixel, 24 bpp + packed pixel and 32 bpp packed pixel. You can also use font widths + different from 8. + +config FB_MATROX_G450 + bool "G100/G200/G400/G450/G550 support" + depends on FB_MATROX + ---help--- + Say Y here if you have a Matrox G100, G200, G400, G450 or G550 based + video card. If you select "Advanced lowlevel driver options", you + should check 8 bpp packed pixel, 16 bpp packed pixel, 24 bpp packed + pixel and 32 bpp packed pixel. You can also use font widths + different from 8. + + If you need support for G400 secondary head, you must first say Y to + "I2C support" and "I2C bit-banging support" in the character devices + section, and then to "Matrox I2C support" and "G400 second head + support" here in the framebuffer section. G450/G550 secondary head + and digital output are supported without additional modules. + + The driver starts in monitor mode. You must use the matroxset tool + (available at <ftp://platan.vc.cvut.cz/pub/linux/matrox-latest/>) to + swap primary and secondary head outputs, or to change output mode. + Secondary head driver always start in 640x480 resolution and you + must use fbset to change it. + + Do not forget that second head supports only 16 and 32 bpp + packed pixels, so it is a good idea to compile them into the kernel + too. You can use only some font widths, as the driver uses generic + painting procedures (the secondary head does not use acceleration + engine). + + G450/G550 hardware can display TV picture only from secondary CRTC, + and it performs no scaling, so picture must have 525 or 625 lines. + +config FB_MATROX_G100A + bool "G100/G200/G400 support" + depends on FB_MATROX && !FB_MATROX_G450 + ---help--- + Say Y here if you have a Matrox G100, G200 or G400 based + video card. If you select "Advanced lowlevel driver options", you + should check 8 bpp packed pixel, 16 bpp packed pixel, 24 bpp packed + pixel and 32 bpp packed pixel. You can also use font widths + different from 8. + + If you need support for G400 secondary head, you must first say Y to + "I2C support" and "I2C bit-banging support" in the character devices + section, and then to "Matrox I2C support" and "G400 second head + support" here in the framebuffer section. + +config FB_MATROX_G100 + bool + depends on FB_MATROX && (FB_MATROX_G450 || FB_MATROX_G100A) + default y + +config FB_MATROX_I2C + tristate "Matrox I2C support" + depends on FB_MATROX && I2C + select I2C_ALGOBIT + ---help--- + This drivers creates I2C buses which are needed for accessing the + DDC (I2C) bus present on all Matroxes, an I2C bus which + interconnects Matrox optional devices, like MGA-TVO on G200 and + G400, and the secondary head DDC bus, present on G400 only. + + You can say Y or M here if you want to experiment with monitor + detection code. You must say Y or M here if you want to use either + second head of G400 or MGA-TVO on G200 or G400. + + If you compile it as module, it will create a module named + i2c-matroxfb. + +config FB_MATROX_MAVEN + tristate "G400 second head support" + depends on FB_MATROX_G100 && FB_MATROX_I2C + ---help--- + WARNING !!! This support does not work with G450 !!! + + Say Y or M here if you want to use a secondary head (meaning two + monitors in parallel) on G400 or MGA-TVO add-on on G200. Secondary + head is not compatible with accelerated XFree 3.3.x SVGA servers - + secondary head output is blanked while you are in X. With XFree + 3.9.17 preview you can use both heads if you use SVGA over fbdev or + the fbdev driver on first head and the fbdev driver on second head. + + If you compile it as module, two modules are created, + matroxfb_crtc2 and matroxfb_maven. Matroxfb_maven is needed for + both G200 and G400, matroxfb_crtc2 is needed only by G400. You must + also load i2c-matroxfb to get it to run. + + The driver starts in monitor mode and you must use the matroxset + tool (available at + <ftp://platan.vc.cvut.cz/pub/linux/matrox-latest/>) to switch it to + PAL or NTSC or to swap primary and secondary head outputs. + Secondary head driver also always start in 640x480 resolution, you + must use fbset to change it. + + Also do not forget that second head supports only 16 and 32 bpp + packed pixels, so it is a good idea to compile them into the kernel + too. You can use only some font widths, as the driver uses generic + painting procedures (the secondary head does not use acceleration + engine). + +config FB_MATROX_MULTIHEAD + bool "Multihead support" + depends on FB_MATROX + ---help--- + Say Y here if you have more than one (supported) Matrox device in + your computer and you want to use all of them for different monitors + ("multihead"). If you have only one device, you should say N because + the driver compiled with Y is larger and a bit slower, especially on + ia32 (ix86). + + If you said M to "Matrox unified accelerated driver" and N here, you + will still be able to use several Matrox devices simultaneously: + insert several instances of the module matroxfb into the kernel + with insmod, supplying the parameter "dev=N" where N is 0, 1, etc. + for the different Matrox devices. This method is slightly faster but + uses 40 KB of kernel memory per Matrox card. + + There is no need for enabling 'Matrox multihead support' if you have + only one Matrox card in the box. + +config FB_RADEON_OLD + tristate "ATI Radeon display support (Old driver)" + depends on FB && PCI + help + Choose this option if you want to use an ATI Radeon graphics card as + a framebuffer device. There are both PCI and AGP versions. You + don't need to choose this to run the Radeon in plain VGA mode. + There is a product page at + <http://www.ati.com/na/pages/products/pc/radeon32/index.html>. + +config FB_RADEON + tristate "ATI Radeon display support" + depends on FB && PCI + select I2C_ALGOBIT if FB_RADEON_I2C + select I2C if FB_RADEON_I2C + select FB_MODE_HELPERS + help + Choose this option if you want to use an ATI Radeon graphics card as + a framebuffer device. There are both PCI and AGP versions. You + don't need to choose this to run the Radeon in plain VGA mode. + + If you say Y here and want DDC/I2C support you must first say Y to + "I2C support" and "I2C bit-banging support" in the character devices + section. + + If you say M here then "I2C support" and "I2C bit-banging support" + can be build either as modules or built-in. + + There is a product page at + <http://www.ati.com/na/pages/products/pc/radeon32/index.html>. + +config FB_RADEON_I2C + bool "DDC/I2C for ATI Radeon support" + depends on FB_RADEON + default y + help + Say Y here if you want DDC/I2C support for your Radeon board. + +config FB_RADEON_DEBUG + bool "Lots of debug output from Radeon driver" + depends on FB_RADEON + default n + help + Say Y here if you want the Radeon driver to output all sorts + of debugging informations to provide to the maintainer when + something goes wrong. + +config FB_ATY128 + tristate "ATI Rage128 display support" + depends on FB && PCI + help + This driver supports graphics boards with the ATI Rage128 chips. + Say Y if you have such a graphics board and read + <file:Documentation/fb/aty128fb.txt>. + + To compile this driver as a module, choose M here: the + module will be called aty128fb. + +config FB_ATY + tristate "ATI Mach64 display support" if PCI || ATARI + depends on FB + help + This driver supports graphics boards with the ATI Mach64 chips. + Say Y if you have such a graphics board. + + To compile this driver as a module, choose M here: the + module will be called atyfb. + +config FB_ATY_CT + bool "Mach64 CT/VT/GT/LT (incl. 3D RAGE) support" + depends on PCI && FB_ATY + default y if SPARC64 && FB_PCI + help + Say Y here to support use of ATI's 64-bit Rage boards (or other + boards based on the Mach64 CT, VT, GT, and LT chipsets) as a + framebuffer device. The ATI product support page for these boards + is at <http://support.ati.com/products/pc/mach64/>. + +config FB_ATY_GX + bool "Mach64 GX support" if PCI + depends on FB_ATY + default y if ATARI + help + Say Y here to support use of the ATI Mach64 Graphics Expression + board (or other boards based on the Mach64 GX chipset) as a + framebuffer device. The ATI product support page for these boards + is at + <http://support.ati.com/products/pc/mach64/graphics_xpression.html>. + +config FB_ATY_XL_INIT + bool " Rage XL No-BIOS Init support" if FB_ATY_CT + depends on FB_ATY + help + Say Y here to support booting a Rage XL without BIOS support. + +config FB_SIS + tristate "SiS acceleration" + depends on FB && PCI + help + This is the frame buffer device driver for the SiS 300, 315 and + 330 series VGA chipsets. Specs available at http://www.sis.com + + To compile this driver as a module, choose M here; the module + will be called sisfb. + +config FB_SIS_300 + bool "SiS 300 series support" + depends on FB_SIS + help + Say Y here to support use of the SiS 300/305, 540, 630 and 730. + +config FB_SIS_315 + bool "SiS 315/330 series support" + depends on FB_SIS + help + Say Y here to support use of the SiS 315 and 330 series + (315/H/PRO, 55x, 650, 651, 740, 330, 661, 741, 760). + +config FB_NEOMAGIC + tristate "NeoMagic display support" + depends on FB && PCI + select FB_MODE_HELPERS + help + This driver supports notebooks with NeoMagic PCI chips. + Say Y if you have such a graphics card. + + To compile this driver as a module, choose M here: the + module will be called neofb. + +config FB_KYRO + tristate "IMG Kyro support" + depends on FB && PCI + help + Say Y here if you have a STG4000 / Kyro / PowerVR 3 based + graphics board. + + To compile this driver as a module, choose M here: the + module will be called kyrofb. + +config FB_3DFX + tristate "3Dfx Banshee/Voodoo3 display support" + depends on FB && PCI + help + This driver supports graphics boards with the 3Dfx Banshee/Voodoo3 + chips. Say Y if you have such a graphics board. + + To compile this driver as a module, choose M here: the + module will be called tdfxfb. + +config FB_3DFX_ACCEL + bool "3Dfx Banshee/Voodoo3 Acceleration functions (EXPERIMENTAL)" + depends on FB_3DFX && EXPERIMENTAL + ---help--- + This will compile the 3Dfx Banshee/Voodoo3 frame buffer device + with acceleration functions. + + +config FB_VOODOO1 + tristate "3Dfx Voodoo Graphics (sst1) support" + depends on FB && PCI + ---help--- + Say Y here if you have a 3Dfx Voodoo Graphics (Voodoo1/sst1) or + Voodoo2 (cvg) based graphics card. + + To compile this driver as a module, choose M here: the + module will be called sstfb. + + WARNING: Do not use any application that uses the 3D engine + (namely glide) while using this driver. + Please read the file Documentation/fb/README-sstfb.txt for supported + options and other important info support. + +config FB_TRIDENT + tristate "Trident support" + depends on FB && PCI + ---help--- + This driver is supposed to support graphics boards with the + Trident CyberXXXX/Image/CyberBlade chips mostly found in laptops + but also on some motherboards. For more information, read + <file:Documentation/fb/tridentfb.txt> + + Say Y if you have such a graphics board. + + To compile this driver as a module, choose M here: the + module will be called tridentfb. + +config FB_TRIDENT_ACCEL + bool "Trident Acceleration functions (EXPERIMENTAL)" + depends on FB_TRIDENT && EXPERIMENTAL + ---help--- + This will compile the Trident frame buffer device with + acceleration functions. + + +config FB_PM3 + tristate "Permedia3 support" + depends on FB && PCI && BROKEN + help + This is the frame buffer device driver for the 3DLabs Permedia3 + chipset, used in Formac ProFormance III, 3DLabs Oxygen VX1 & + similar boards, 3DLabs Permedia3 Create!, Appian Jeronimo 2000 + and maybe other boards. + +config FB_SBUS + bool "SBUS and UPA framebuffers" + depends on FB && (SPARC32 || SPARC64) + help + Say Y if you want support for SBUS or UPA based frame buffer device. + +config FB_FFB + bool "Creator/Creator3D/Elite3D support" + depends on FB_SBUS && SPARC64 + help + This is the frame buffer device driver for the Creator, Creator3D, + and Elite3D graphics boards. + +config FB_TCX + bool "TCX (SS4/SS5 only) support" + depends on FB_SBUS + help + This is the frame buffer device driver for the TCX 24/8bit frame + buffer. + +config FB_CG14 + bool "CGfourteen (SX) support" + depends on FB_SBUS + help + This is the frame buffer device driver for the CGfourteen frame + buffer on Desktop SPARCsystems with the SX graphics option. + +config FB_P9100 + bool "P9100 (Sparcbook 3 only) support" + depends on FB_SBUS + help + This is the frame buffer device driver for the P9100 card + supported on Sparcbook 3 machines. + +config FB_LEO + bool "Leo (ZX) support" + depends on FB_SBUS + help + This is the frame buffer device driver for the SBUS-based Sun ZX + (leo) frame buffer cards. + +config FB_PCI + bool "PCI framebuffers" + depends on FB && PCI && (SPARC64 || SPARC32) + +config FB_IGA + bool "IGA 168x display support" + depends on SPARC32 && FB_PCI + help + This is the framebuffer device for the INTERGRAPHICS 1680 and + successor frame buffer cards. + +config FB_HIT + tristate "HD64461 Frame Buffer support" + depends on FB && HD64461 + help + This is the frame buffer device driver for the Hitachi HD64461 LCD + frame buffer card. + +config FB_PMAG_BA + bool "PMAG-BA TURBOchannel framebuffer support" + depends on FB && DECSTATION && TC + help + Say Y here to directly support the on-board PMAG-BA framebuffer in + the 5000/1xx versions of the DECstation. There is a page dedicated + to Linux on DECstations at <http://decstation.unix-ag.org/>. + +config FB_PMAGB_B + bool "PMAGB-B TURBOchannel framebuffer spport" + depends on FB && DECSTATION && TC + help + Say Y here to directly support the on-board PMAGB-B framebuffer in + the 5000/1xx versions of the DECstation. There is a page dedicated + to Linux on DECstations at <http://decstation.unix-ag.org/>. + +config FB_MAXINE + bool "Maxine (Personal DECstation) onboard framebuffer spport" + depends on FB && DECSTATION && TC + help + Say Y here to directly support the on-board framebuffer in the + Maxine (5000/20, /25, /33) version of the DECstation. There is a + page dedicated to Linux on DECstations at <http://decstation.unix-ag.org/>. + +config FB_TX3912 + bool "TMPTX3912/PR31700 frame buffer support" + depends on FB && NINO + help + The TX3912 is a Toshiba RISC processor based on the MIPS 3900 core + see <http://www.toshiba.com/taec/components/Generic/risc/tx3912.htm>. + + Say Y here to enable kernel support for the on-board framebuffer. + +config FB_68328 + bool "Motorola 68328 native frame buffer support" + depends on (M68328 || M68EZ328 || M68VZ328) + help + Say Y here if you want to support the built-in frame buffer of + the Motorola 68328 CPU family. + +config FB_PXA + tristate "PXA LCD framebuffer support" + depends on FB && ARCH_PXA + ---help--- + Frame buffer driver for the built-in LCD controller in the Intel + PXA2x0 processor. + + This driver is also available as a module ( = code which can be + inserted and removed from the running kernel whenever you want). The + module will be called vfb. If you want to compile it as a module, + say M here and read <file:Documentation/modules.txt>. + + If unsure, say N. + +config FB_PXA_PARAMETERS + bool "PXA LCD command line parameters" + default n + depends on FB_PXA + ---help--- + Enable the use of kernel command line or module parameters + to configure the physical properties of the LCD panel when + using the PXA LCD driver. + + This option allows you to override the panel parameters + supplied by the platform in order to support multiple + different models of flatpanel. If you will only be using a + single model of flatpanel then you can safely leave this + option disabled. + + Documentation/fb/pxafb.txt describes the available parameters. + +config FB_VIRTUAL + tristate "Virtual Frame Buffer support (ONLY FOR TESTING!)" + depends on FB + ---help--- + This is a `virtual' frame buffer device. It operates on a chunk of + unswappable kernel memory instead of on the memory of a graphics + board. This means you cannot see any output sent to this frame + buffer device, while it does consume precious memory. The main use + of this frame buffer device is testing and debugging the frame + buffer subsystem. Do NOT enable it for normal systems! To protect + the innocent, it has to be enabled explicitly at boot time using the + kernel option `video=vfb:'. + + To compile this driver as a module, choose M here: the + module will be called vfb. + + If unsure, say N. +if VT + source "drivers/video/console/Kconfig" +endif + +if FB || SGI_NEWPORT_CONSOLE + source "drivers/video/logo/Kconfig" +endif + +endmenu + diff --git a/drivers/video/Makefile b/drivers/video/Makefile @@ -0,0 +1,102 @@ +# Makefile for the Linux video drivers. +# 5 Aug 1999, James Simmons, <mailto:jsimmons@users.sf.net> +# Rewritten to use lists instead of if-statements. + +# Each configuration option enables a list of files. + +obj-$(CONFIG_VT) += console/ +obj-$(CONFIG_LOGO) += logo/ + +obj-$(CONFIG_FB) += fbmem.o fbmon.o fbcmap.o fbsysfs.o modedb.o softcursor.o +# Only include macmodes.o if we have FB support and are PPC +ifeq ($(CONFIG_FB),y) +obj-$(CONFIG_PPC) += macmodes.o +endif + +obj-$(CONFIG_FB_UI) += fbui.o + +# Hardware specific drivers go first +obj-$(CONFIG_FB_RETINAZ3) += retz3fb.o +obj-$(CONFIG_FB_AMIGA) += amifb.o c2p.o +obj-$(CONFIG_FB_CLPS711X) += clps711xfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o +obj-$(CONFIG_FB_CYBER) += cyberfb.o +obj-$(CONFIG_FB_CYBER2000) += cyber2000fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o +obj-$(CONFIG_FB_PM2) += pm2fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o +obj-$(CONFIG_FB_PM3) += pm3fb.o + +obj-$(CONFIG_FB_MATROX) += matrox/ cfbfillrect.o cfbcopyarea.o cfbimgblt.o +obj-$(CONFIG_FB_RIVA) += riva/ cfbimgblt.o vgastate.o +obj-$(CONFIG_FB_ATY) += aty/ cfbcopyarea.o cfbfillrect.o cfbimgblt.o +obj-$(CONFIG_FB_ATY128) += aty/ cfbcopyarea.o cfbfillrect.o cfbimgblt.o +obj-$(CONFIG_FB_RADEON) += aty/ cfbcopyarea.o cfbfillrect.o cfbimgblt.o +obj-$(CONFIG_FB_SIS) += sis/ cfbcopyarea.o cfbfillrect.o cfbimgblt.o +obj-$(CONFIG_FB_KYRO) += kyro/ cfbfillrect.o cfbcopyarea.o cfbimgblt.o + +obj-$(CONFIG_FB_I810) += cfbcopyarea.o cfbfillrect.o cfbimgblt.o \ + vgastate.o +obj-$(CONFIG_FB_RADEON_OLD) += radeonfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o +obj-$(CONFIG_FB_NEOMAGIC) += neofb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o vgastate.o +obj-$(CONFIG_FB_VIRGE) += virgefb.o +obj-$(CONFIG_FB_3DFX) += tdfxfb.o cfbimgblt.o +ifneq ($(CONFIG_FB_3DFX_ACCEL),y) +obj-$(CONFIG_FB_3DFX) += cfbfillrect.o cfbcopyarea.o +endif +obj-$(CONFIG_FB_CONTROL) += controlfb.o macmodes.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o +obj-$(CONFIG_FB_PLATINUM) += platinumfb.o macmodes.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o +obj-$(CONFIG_FB_VALKYRIE) += valkyriefb.o macmodes.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o +obj-$(CONFIG_FB_CT65550) += chipsfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o +obj-$(CONFIG_FB_IMSTT) += imsttfb.o cfbimgblt.o +obj-$(CONFIG_FB_S3TRIO) += S3triofb.o +obj-$(CONFIG_FB_FM2) += fm2fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o +obj-$(CONFIG_FB_TRIDENT) += tridentfb.o cfbfillrect.o cfbimgblt.o cfbcopyarea.o +obj-$(CONFIG_FB_STI) += stifb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o +obj-$(CONFIG_FB_FFB) += ffb.o sbuslib.o cfbimgblt.o cfbcopyarea.o +obj-$(CONFIG_FB_CG6) += cg6.o sbuslib.o cfbimgblt.o cfbcopyarea.o +obj-$(CONFIG_FB_CG3) += cg3.o sbuslib.o cfbimgblt.o cfbcopyarea.o \ + cfbfillrect.o +obj-$(CONFIG_FB_BW2) += bw2.o sbuslib.o cfbimgblt.o cfbcopyarea.o \ + cfbfillrect.o +obj-$(CONFIG_FB_CG14) += cg14.o sbuslib.o cfbimgblt.o cfbcopyarea.o \ + cfbfillrect.o +obj-$(CONFIG_FB_P9100) += p9100.o sbuslib.o cfbimgblt.o cfbcopyarea.o \ + cfbfillrect.o +obj-$(CONFIG_FB_TCX) += tcx.o sbuslib.o cfbimgblt.o cfbcopyarea.o \ + cfbfillrect.o +obj-$(CONFIG_FB_LEO) += leo.o sbuslib.o cfbimgblt.o cfbcopyarea.o \ + cfbfillrect.o +obj-$(CONFIG_FB_SGIVW) += sgivwfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o +obj-$(CONFIG_FB_ACORN) += acornfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o +obj-$(CONFIG_FB_ATARI) += atafb.o +obj-$(CONFIG_FB_MAC) += macfb.o macmodes.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o +obj-$(CONFIG_FB_HGA) += hgafb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o +obj-$(CONFIG_FB_IGA) += igafb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o +obj-$(CONFIG_FB_APOLLO) += dnfb.o cfbfillrect.o cfbimgblt.o +obj-$(CONFIG_FB_Q40) += q40fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o +obj-$(CONFIG_FB_TGA) += tgafb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o +obj-$(CONFIG_FB_HP300) += hpfb.o cfbfillrect.o cfbimgblt.o +obj-$(CONFIG_FB_G364) += g364fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o +obj-$(CONFIG_FB_SA1100) += sa1100fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o +obj-$(CONFIG_FB_SUN3) += sun3fb.o +obj-$(CONFIG_FB_HIT) += hitfb.o cfbfillrect.o cfbimgblt.o +obj-$(CONFIG_FB_TX3912) += tx3912fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o +obj-$(CONFIG_FB_EPSON1355) += epson1355fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o +obj-$(CONFIG_FB_PVR2) += pvr2fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o +obj-$(CONFIG_FB_PMAG_BA) += pmag-ba-fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o +obj-$(CONFIG_FB_PMAGB_B) += pmagb-b-fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o +obj-$(CONFIG_FB_MAXINE) += maxinefb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o +obj-$(CONFIG_FB_VOODOO1) += sstfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o +obj-$(CONFIG_FB_ARMCLCD) += amba-clcd.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o +obj-$(CONFIG_FB_68328) += 68328fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o +obj-$(CONFIG_FB_GBE) += gbefb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o +obj-$(CONFIG_FB_CIRRUS) += cirrusfb.o cfbfillrect.o cfbimgblt.o cfbcopyarea.o +obj-$(CONFIG_FB_ASILIANT) += asiliantfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o +obj-$(CONFIG_FB_PXA) += pxafb.o cfbimgblt.o cfbcopyarea.o cfbfillrect.o + +# Platform or fallback drivers go here +obj-$(CONFIG_FB_VESA) += vesafb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o +obj-$(CONFIG_FB_VGA16) += vga16fb.o cfbfillrect.o cfbcopyarea.o \ + cfbimgblt.o vgastate.o +obj-$(CONFIG_FB_OF) += offb.o cfbfillrect.o cfbimgblt.o cfbcopyarea.o + +# the test framebuffer is last +obj-$(CONFIG_FB_VIRTUAL) += vfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c @@ -0,0 +1,2890 @@ +/* + * linux/drivers/video/fbcon.c -- Low level frame buffer based console driver + * + * Copyright (C) 1995 Geert Uytterhoeven + * + * + * This file is based on the original Amiga console driver (amicon.c): + * + * Copyright (C) 1993 Hamish Macdonald + * Greg Harp + * Copyright (C) 1994 David Carter [carter@compsci.bristol.ac.uk] + * + * with work by William Rucklidge (wjr@cs.cornell.edu) + * Geert Uytterhoeven + * Jes Sorensen (jds@kom.auc.dk) + * Martin Apel + * + * and on the original Atari console driver (atacon.c): + * + * Copyright (C) 1993 Bjoern Brauel + * Roman Hodek + * + * with work by Guenther Kelleter + * Martin Schaller + * Andreas Schwab + * + * Hardware cursor support added by Emmanuel Marty (core@ggi-project.org) + * Smart redraw scrolling, arbitrary font width support, 512char font support + * and software scrollback added by + * Jakub Jelinek (jj@ultra.linux.cz) + * + * Random hacking by Martin Mares <mj@ucw.cz> + * + * 2001 - Documented with DocBook + * - Brad Douglas <brad@neruo.com> + * + * The low level operations for the various display memory organizations are + * now in separate source files. + * + * Currently the following organizations are supported: + * + * o afb Amiga bitplanes + * o cfb{2,4,8,16,24,32} Packed pixels + * o ilbm Amiga interleaved bitplanes + * o iplan2p[248] Atari interleaved bitplanes + * o mfb Monochrome + * o vga VGA characters/attributes + * + * To do: + * + * - Implement 16 plane mode (iplan2p16) + * + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + */ + +#undef FBCONDEBUG + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/types.h> +#include <linux/sched.h> +#include <linux/fs.h> +#include <linux/kernel.h> +#include <linux/delay.h> /* MSch: for IRQ probe */ +#include <linux/tty.h> +#include <linux/console.h> +#include <linux/string.h> +#include <linux/kd.h> +#include <linux/slab.h> +#include <linux/fb.h> +#include <linux/vt_kern.h> +#include <linux/selection.h> +#include <linux/font.h> +#include <linux/smp.h> +#include <linux/init.h> +#include <linux/interrupt.h> + +#include <asm/irq.h> +#include <asm/system.h> +#include <asm/uaccess.h> +#ifdef CONFIG_ATARI +#include <asm/atariints.h> +#endif +#ifdef CONFIG_MAC +#include <asm/macints.h> +#endif +#if defined(__mc68000__) || defined(CONFIG_APUS) +#include <asm/machdep.h> +#include <asm/setup.h> +#endif + +#include "fbcon.h" + +#ifdef FBCONDEBUG +# define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args) +#else +# define DPRINTK(fmt, args...) +#endif + +struct display fb_display[MAX_NR_CONSOLES]; +signed char con2fb_map[MAX_NR_CONSOLES]; +static int logo_height; +static int logo_lines; +static int logo_shown = -1; +/* Software scrollback */ +int fbcon_softback_size = 32768; +static unsigned long softback_buf, softback_curr; +static unsigned long softback_in; +static unsigned long softback_top, softback_end; +static int softback_lines; +/* console mappings */ +static int first_fb_vc; +static int last_fb_vc = MAX_NR_CONSOLES - 1; +static int fbcon_is_default = 1; +/* font data */ +static char fontname[40]; + +/* current fb_info */ +static int info_idx = -1; + +#define REFCOUNT(fd) (((int *)(fd))[-1]) +#define FNTSIZE(fd) (((int *)(fd))[-2]) +#define FNTCHARCNT(fd) (((int *)(fd))[-3]) +#define FNTSUM(fd) (((int *)(fd))[-4]) +#define FONT_EXTRA_WORDS 4 + +#define CM_SOFTBACK (8) + +#define advance_row(p, delta) (unsigned short *)((unsigned long)(p) + (delta) * vc->vc_size_row) + +static void fbcon_free_font(struct display *); +static int fbcon_set_origin(struct vc_data *); + +#define CURSOR_DRAW_DELAY (1) + +/* # VBL ints between cursor state changes */ +#define ARM_CURSOR_BLINK_RATE (10) +#define ATARI_CURSOR_BLINK_RATE (42) +#define MAC_CURSOR_BLINK_RATE (32) +#define DEFAULT_CURSOR_BLINK_RATE (20) + +static int vbl_cursor_cnt; + +#define divides(a, b) ((!(a) || (b)%(a)) ? 0 : 1) + +/* + * Interface used by the world + */ + +static const char *fbcon_startup(void); +static void fbcon_init(struct vc_data *vc, int init); +static void fbcon_deinit(struct vc_data *vc); +static void fbcon_clear(struct vc_data *vc, int sy, int sx, int height, + int width); +static void fbcon_putc(struct vc_data *vc, int c, int ypos, int xpos); +static void fbcon_putcs(struct vc_data *vc, const unsigned short *s, + int count, int ypos, int xpos); +static void fbcon_cursor(struct vc_data *vc, int mode); +static int fbcon_scroll(struct vc_data *vc, int t, int b, int dir, + int count); +static void fbcon_bmove(struct vc_data *vc, int sy, int sx, int dy, int dx, + int height, int width); +static int fbcon_switch(struct vc_data *vc); +static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch); +static int fbcon_set_palette(struct vc_data *vc, unsigned char *table); +static int fbcon_scrolldelta(struct vc_data *vc, int lines); +void accel_clear_margins(struct vc_data *vc, struct fb_info *info, + int bottom_only); + + +/* + * Internal routines + */ +static __inline__ int real_y(struct display *p, int ypos); +static __inline__ void ywrap_up(struct vc_data *vc, int count); +static __inline__ void ywrap_down(struct vc_data *vc, int count); +static __inline__ void ypan_up(struct vc_data *vc, int count); +static __inline__ void ypan_down(struct vc_data *vc, int count); +static void fbcon_bmove_rec(struct vc_data *vc, struct display *p, int sy, int sx, + int dy, int dx, int height, int width, u_int y_break); +static void fbcon_set_disp(struct fb_info *info, struct vc_data *vc); +static void fbcon_redraw_move(struct vc_data *vc, struct display *p, + int line, int count, int dy); + +#ifdef CONFIG_MAC +/* + * On the Macintoy, there may or may not be a working VBL int. We need to probe + */ +static int vbl_detected; + +static irqreturn_t fb_vbl_detect(int irq, void *dummy, struct pt_regs *fp) +{ + vbl_detected++; + return IRQ_HANDLED; +} +#endif + +static void fb_flashcursor(void *private) +{ + struct fb_info *info = (struct fb_info *) private; + struct vc_data *vc = NULL; + + if (info->currcon != -1) + vc = vc_cons[info->currcon].d; + + if (info->state != FBINFO_STATE_RUNNING || + info->cursor.rop == ROP_COPY || !vc || !CON_IS_VISIBLE(vc) + || registered_fb[(int) con2fb_map[vc->vc_num]] != info) + return; + acquire_console_sem(); + info->cursor.enable ^= 1; + info->fbops->fb_cursor(info, &info->cursor); + release_console_sem(); +} + +#if (defined(__arm__) && defined(IRQ_VSYNCPULSE)) || defined(CONFIG_ATARI) || defined(CONFIG_MAC) +static int cursor_blink_rate; +static irqreturn_t fb_vbl_handler(int irq, void *dev_id, struct pt_regs *fp) +{ + struct fb_info *info = dev_id; + + if (vbl_cursor_cnt && --vbl_cursor_cnt == 0) { + schedule_work(&info->queue); + vbl_cursor_cnt = cursor_blink_rate; + } + return IRQ_HANDLED; +} +#endif + +static void cursor_timer_handler(unsigned long dev_addr) +{ + struct fb_info *info = (struct fb_info *) dev_addr; + + schedule_work(&info->queue); + mod_timer(&info->cursor_timer, jiffies + HZ/5); +} + +int __init fb_console_setup(char *this_opt) +{ + char *options; + int i, j; + + if (!this_opt || !*this_opt) + return 0; + + while ((options = strsep(&this_opt, ",")) != NULL) { + if (!strncmp(options, "font:", 5)) + strcpy(fontname, options + 5); + + if (!strncmp(options, "scrollback:", 11)) { + options += 11; + if (*options) { + fbcon_softback_size = simple_strtoul(options, &options, 0); + if (*options == 'k' || *options == 'K') { + fbcon_softback_size *= 1024; + options++; + } + if (*options != ',') + return 0; + options++; + } else + return 0; + } + + if (!strncmp(options, "map:", 4)) { + options += 4; + if (*options) + for (i = 0, j = 0; i < MAX_NR_CONSOLES; i++) { + if (!options[j]) + j = 0; + con2fb_map[i] = (options[j++]-'0') % FB_MAX; + } + return 0; + } + + if (!strncmp(options, "vc:", 3)) { + options += 3; + if (*options) + first_fb_vc = simple_strtoul(options, &options, 10) - 1; + if (first_fb_vc < 0) + first_fb_vc = 0; + if (*options++ == '-') + last_fb_vc = simple_strtoul(options, &options, 10) - 1; + fbcon_is_default = 0; + } + } + return 0; +} + +__setup("fbcon=", fb_console_setup); + +static int search_fb_in_map(int idx) +{ + int i; + + for (i = 0; i < MAX_NR_CONSOLES; i++) { + if (con2fb_map[i] == idx) + return 1; + } + return 0; +} + +static int search_for_mapped_con(void) +{ + int i; + + for (i = 0; i < MAX_NR_CONSOLES; i++) { + if (con2fb_map[i] != -1) + return 1; + } + return 0; +} + +static int fbcon_takeover(void) +{ + int err, i; + + if (!num_registered_fb) + return -ENODEV; + + for (i = first_fb_vc; i <= last_fb_vc; i++) + con2fb_map[i] = info_idx; + + err = take_over_console(&fb_con, first_fb_vc, last_fb_vc, + fbcon_is_default); + if (err) { + for (i = first_fb_vc; i <= last_fb_vc; i++) { + con2fb_map[i] = -1; + } + info_idx = -1; + } + + return err; +} + +/** + * set_con2fb_map - map console to frame buffer device + * @unit: virtual console number to map + * @newidx: frame buffer index to map virtual console to + * + * Maps a virtual console @unit to a frame buffer device + * @newidx. + */ +static int set_con2fb_map(int unit, int newidx) +{ + struct vc_data *vc = vc_cons[unit].d; + int oldidx = con2fb_map[unit]; + struct fb_info *info = registered_fb[newidx]; + struct fb_info *oldinfo = NULL; + int found; + + if (oldidx == newidx) + return 0; + + if (!vc) + return -ENODEV; + + if (!search_for_mapped_con()) { + info_idx = newidx; + return fbcon_takeover(); + } + + if (oldidx != -1) + oldinfo = registered_fb[oldidx]; + + found = search_fb_in_map(newidx); + + acquire_console_sem(); + con2fb_map[unit] = newidx; + if (!found) { + if (!try_module_get(info->fbops->owner)) { + con2fb_map[unit] = oldidx; + release_console_sem(); + return -ENODEV; + } + if (info->fbops->fb_open && info->fbops->fb_open(info, 0)) { + module_put(info->fbops->owner); + con2fb_map[unit] = oldidx; + release_console_sem(); + return -ENODEV; + } + } + + /* + * If old fb is not mapped to any of the consoles, + * fbcon should release it. + */ + if (oldinfo && !search_fb_in_map(oldidx)) { + if (oldinfo->fbops->fb_release && + oldinfo->fbops->fb_release(oldinfo, 0)) { + con2fb_map[unit] = oldidx; + if (!found && info->fbops->fb_release) + info->fbops->fb_release(info, 0); + if (!found) + module_put(info->fbops->owner); + release_console_sem(); + return -ENODEV; + } + if (oldinfo->queue.func == fb_flashcursor) + del_timer_sync(&oldinfo->cursor_timer); + module_put(oldinfo->fbops->owner); + } + info->currcon = -1; + if (!found) { + if (!info->queue.func || info->queue.func == fb_flashcursor) { + if (!info->queue.func) + INIT_WORK(&info->queue, fb_flashcursor, info); + + init_timer(&info->cursor_timer); + info->cursor_timer.function = cursor_timer_handler; + info->cursor_timer.expires = jiffies + HZ / 5; + info->cursor_timer.data = (unsigned long ) info; + add_timer(&info->cursor_timer); + } + } + if (info->fbops->fb_set_par) + info->fbops->fb_set_par(info); + fbcon_set_disp(info, vc); + release_console_sem(); + return 0; +} + +/* + * Accelerated handlers. + */ +static inline int get_color(struct vc_data *vc, struct fb_info *info, + u16 c, int is_fg) +{ + int depth = fb_get_color_depth(info); + int color = 0; + + if (depth != 1) + color = (is_fg) ? attr_fgcol((vc->vc_hi_font_mask) ? 9 : 8, c) + : attr_bgcol((vc->vc_hi_font_mask) ? 13 : 12, c); + + switch (depth) { + case 1: + { + /* 0 or 1 */ + int fg = (info->fix.visual != FB_VISUAL_MONO01) ? 1 : 0; + int bg = (info->fix.visual != FB_VISUAL_MONO01) ? 0 : 1; + + color = (is_fg) ? fg : bg; + break; + } + case 2: + /* + * Scale down 16-colors to 4 colors. Default 4-color palette + * is grayscale. + */ + color /= 4; + break; + case 3: + /* + * Last 8 entries of default 16-color palette is a more intense + * version of the first 8 (i.e., same chrominance, different + * luminance). + */ + color &= 7; + break; + } + + return color; +} + +#define FBCON_ATTRIBUTE_UNDERLINE 1 +#define FBCON_ATTRIBUTE_REVERSE 2 +#define FBCON_ATTRIBUTE_BOLD 4 + +static inline int get_attribute(struct fb_info *info, u16 c) +{ + int attribute = 0; + + if (fb_get_color_depth(info) == 1) { + if (attr_underline(c)) + attribute |= FBCON_ATTRIBUTE_UNDERLINE; + if (attr_reverse(c)) + attribute |= FBCON_ATTRIBUTE_REVERSE; + if (attr_bold(c)) + attribute |= FBCON_ATTRIBUTE_BOLD; + } + + return attribute; +} + +static inline void update_attr(u8 *dst, u8 *src, int attribute, + struct vc_data *vc) +{ + int i, offset = (vc->vc_font.height < 10) ? 1 : 2; + int width = (vc->vc_font.width + 7) >> 3; + unsigned int cellsize = vc->vc_font.height * width; + u8 c; + + offset = cellsize - (offset * width); + for (i = 0; i < cellsize; i++) { + c = src[i]; + if (attribute & FBCON_ATTRIBUTE_UNDERLINE && i >= offset) + c = 0xff; + if (attribute & FBCON_ATTRIBUTE_BOLD) + c |= c >> 1; + if (attribute & FBCON_ATTRIBUTE_REVERSE) + c = ~c; + dst[i] = c; + } +} + +void accel_bmove(struct vc_data *vc, struct fb_info *info, int sy, + int sx, int dy, int dx, int height, int width) +{ + struct fb_copyarea area; + + area.sx = sx * vc->vc_font.width; + area.sy = sy * vc->vc_font.height; + area.dx = dx * vc->vc_font.width; + area.dy = dy * vc->vc_font.height; + area.height = height * vc->vc_font.height; + area.width = width * vc->vc_font.width; + + info->fbops->fb_copyarea(info, &area); +} + +void accel_clear(struct vc_data *vc, struct fb_info *info, int sy, + int sx, int height, int width) +{ + int bgshift = (vc->vc_hi_font_mask) ? 13 : 12; + struct fb_fillrect region; + + region.color = attr_bgcol_ec(bgshift, vc); + region.dx = sx * vc->vc_font.width; + region.dy = sy * vc->vc_font.height; + region.width = width * vc->vc_font.width; + region.height = height * vc->vc_font.height; + region.rop = ROP_COPY; + + info->fbops->fb_fillrect(info, ®ion); +} + +void accel_putcs(struct vc_data *vc, struct fb_info *info, + const unsigned short *s, int count, int yy, int xx) +{ + void (*move_unaligned)(struct fb_info *info, struct fb_pixmap *buf, + u8 *dst, u32 d_pitch, u8 *src, u32 idx, + u32 height, u32 shift_high, u32 shift_low, + u32 mod); + void (*move_aligned)(struct fb_info *info, struct fb_pixmap *buf, + u8 *dst, u32 d_pitch, u8 *src, u32 s_pitch, + u32 height); + unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff; + unsigned int width = (vc->vc_font.width + 7) >> 3; + unsigned int cellsize = vc->vc_font.height * width; + unsigned int maxcnt = info->pixmap.size/cellsize; + unsigned int scan_align = info->pixmap.scan_align - 1; + unsigned int buf_align = info->pixmap.buf_align - 1; + unsigned int shift_low = 0, mod = vc->vc_font.width % 8; + unsigned int shift_high = 8, pitch, cnt, size, k; + unsigned int idx = vc->vc_font.width >> 3; + unsigned int attribute = get_attribute(info, scr_readw(s)); + struct fb_image image; + u8 *src, *dst, *buf = NULL; + + if (attribute) { + buf = kmalloc(cellsize, GFP_KERNEL); + if (!buf) + return; + } + + image.fg_color = get_color(vc, info, scr_readw(s), 1); + image.bg_color = get_color(vc, info, scr_readw(s), 0); + + image.dx = xx * vc->vc_font.width; + image.dy = yy * vc->vc_font.height; + image.height = vc->vc_font.height; + image.depth = 1; + + if (info->pixmap.outbuf && info->pixmap.inbuf) { + move_aligned = fb_iomove_buf_aligned; + move_unaligned = fb_iomove_buf_unaligned; + } else { + move_aligned = fb_sysmove_buf_aligned; + move_unaligned = fb_sysmove_buf_unaligned; + } + while (count) { + if (count > maxcnt) + cnt = k = maxcnt; + else + cnt = k = count; + + image.width = vc->vc_font.width * cnt; + pitch = ((image.width + 7) >> 3) + scan_align; + pitch &= ~scan_align; + size = pitch * image.height + buf_align; + size &= ~buf_align; + dst = fb_get_buffer_offset(info, &info->pixmap, size); + image.data = dst; + if (mod) { + while (k--) { + src = vc->vc_font.data + (scr_readw(s++)& + charmask)*cellsize; + + if (attribute) { + update_attr(buf, src, attribute, vc); + src = buf; + } + + move_unaligned(info, &info->pixmap, dst, pitch, + src, idx, image.height, + shift_high, shift_low, mod); + shift_low += mod; + dst += (shift_low >= 8) ? width : width - 1; + shift_low &= 7; + shift_high = 8 - shift_low; + } + } else { + while (k--) { + src = vc->vc_font.data + (scr_readw(s++)& + charmask)*cellsize; + + if (attribute) { + update_attr(buf, src, attribute, vc); + src = buf; + } + + move_aligned(info, &info->pixmap, dst, pitch, + src, idx, image.height); + dst += width; + } + } + info->fbops->fb_imageblit(info, &image); + image.dx += cnt * vc->vc_font.width; + count -= cnt; + } + + if (buf) + kfree(buf); +} + +void accel_clear_margins(struct vc_data *vc, struct fb_info *info, + int bottom_only) +{ + int bgshift = (vc->vc_hi_font_mask) ? 13 : 12; + unsigned int cw = vc->vc_font.width; + unsigned int ch = vc->vc_font.height; + unsigned int rw = info->var.xres - (vc->vc_cols*cw); + unsigned int bh = info->var.yres - (vc->vc_rows*ch); + unsigned int rs = info->var.xres - rw; + unsigned int bs = info->var.yres - bh; + struct fb_fillrect region; + + region.color = attr_bgcol_ec(bgshift, vc); + region.rop = ROP_COPY; + + if (rw && !bottom_only) { + region.dx = info->var.xoffset + rs; + region.dy = 0; + region.width = rw; + region.height = info->var.yres_virtual; + info->fbops->fb_fillrect(info, ®ion); + } + + if (bh) { + region.dx = info->var.xoffset; + region.dy = info->var.yoffset + bs; + region.width = rs; + region.height = bh; + info->fbops->fb_fillrect(info, ®ion); + } +} + +/* + * Low Level Operations + */ +/* NOTE: fbcon cannot be __init: it may be called from take_over_console later */ +static int var_to_display(struct display *disp, + struct fb_var_screeninfo *var, + struct fb_info *info) +{ + disp->xres_virtual = var->xres_virtual; + disp->yres_virtual = var->yres_virtual; + disp->bits_per_pixel = var->bits_per_pixel; + disp->grayscale = var->grayscale; + disp->nonstd = var->nonstd; + disp->accel_flags = var->accel_flags; + disp->height = var->height; + disp->width = var->width; + disp->red = var->red; + disp->green = var->green; + disp->blue = var->blue; + disp->transp = var->transp; + disp->mode = fb_match_mode(var, &info->modelist); + if (disp->mode == NULL) + /* This should not happen */ + return -EINVAL; + return 0; +} + +static void display_to_var(struct fb_var_screeninfo *var, + struct display *disp) +{ + fb_videomode_to_var(var, disp->mode); + var->xres_virtual = disp->xres_virtual; + var->yres_virtual = disp->yres_virtual; + var->bits_per_pixel = disp->bits_per_pixel; + var->grayscale = disp->grayscale; + var->nonstd = disp->nonstd; + var->accel_flags = disp->accel_flags; + var->height = disp->height; + var->width = disp->width; + var->red = disp->red; + var->green = disp->green; + var->blue = disp->blue; + var->transp = disp->transp; +} + +static const char *fbcon_startup(void) +{ + const char *display_desc = "frame buffer device"; + struct display *p = &fb_display[fg_console]; + struct vc_data *vc = vc_cons[fg_console].d; + struct font_desc *font = NULL; + struct module *owner; + struct fb_info *info = NULL; + int rows, cols; + int irqres; + + irqres = 1; + /* + * If num_registered_fb is zero, this is a call for the dummy part. + * The frame buffer devices weren't initialized yet. + */ + if (!num_registered_fb || info_idx == -1) + return display_desc; + /* + * Instead of blindly using registered_fb[0], we use info_idx, set by + * fb_console_init(); + */ + info = registered_fb[info_idx]; + if (!info) + return NULL; + info->currcon = -1; + + owner = info->fbops->owner; + if (!try_module_get(owner)) + return NULL; + if (info->fbops->fb_open && info->fbops->fb_open(info, 0)) { + module_put(owner); + return NULL; + } + if (info->fix.type != FB_TYPE_TEXT) { + if (fbcon_softback_size) { + if (!softback_buf) { + softback_buf = + (unsigned long) + kmalloc(fbcon_softback_size, + GFP_KERNEL); + if (!softback_buf) { + fbcon_softback_size = 0; + softback_top = 0; + } + } + } else { + if (softback_buf) { + kfree((void *) softback_buf); + softback_buf = 0; + softback_top = 0; + } + } + if (softback_buf) + softback_in = softback_top = softback_curr = + softback_buf; + softback_lines = 0; + } + + /* Setup default font */ + if (!p->fontdata) { + if (!fontname[0] || !(font = find_font(fontname))) + font = get_default_font(info->var.xres, + info->var.yres); + vc->vc_font.width = font->width; + vc->vc_font.height = font->height; + vc->vc_font.data = p->fontdata = font->data; + vc->vc_font.charcount = 256; /* FIXME Need to support more fonts */ + } + + cols = info->var.xres / vc->vc_font.width; + rows = info->var.yres / vc->vc_font.height; + vc_resize(vc->vc_num, cols, rows); + + DPRINTK("mode: %s\n", info->fix.id); + DPRINTK("visual: %d\n", info->fix.visual); + DPRINTK("res: %dx%d-%d\n", info->var.xres, + info->var.yres, + info->var.bits_per_pixel); + con_set_default_unimap(vc->vc_num); + +#ifdef CONFIG_ATARI + if (MACH_IS_ATARI) { + cursor_blink_rate = ATARI_CURSOR_BLINK_RATE; + irqres = + request_irq(IRQ_AUTO_4, fb_vbl_handler, + IRQ_TYPE_PRIO, "framebuffer vbl", + info); + } +#endif /* CONFIG_ATARI */ + +#ifdef CONFIG_MAC + /* + * On a Macintoy, the VBL interrupt may or may not be active. + * As interrupt based cursor is more reliable and race free, we + * probe for VBL interrupts. + */ + if (MACH_IS_MAC) { + int ct = 0; + /* + * Probe for VBL: set temp. handler ... + */ + irqres = request_irq(IRQ_MAC_VBL, fb_vbl_detect, 0, + "framebuffer vbl", info); + vbl_detected = 0; + + /* + * ... and spin for 20 ms ... + */ + while (!vbl_detected && ++ct < 1000) + udelay(20); + + if (ct == 1000) + printk + ("fbcon_startup: No VBL detected, using timer based cursor.\n"); + + free_irq(IRQ_MAC_VBL, fb_vbl_detect); + + if (vbl_detected) { + /* + * interrupt based cursor ok + */ + cursor_blink_rate = MAC_CURSOR_BLINK_RATE; + irqres = + request_irq(IRQ_MAC_VBL, fb_vbl_handler, 0, + "framebuffer vbl", info); + } else { + /* + * VBL not detected: fall through, use timer based cursor + */ + irqres = 1; + } + } +#endif /* CONFIG_MAC */ + +#if defined(__arm__) && defined(IRQ_VSYNCPULSE) + cursor_blink_rate = ARM_CURSOR_BLINK_RATE; + irqres = request_irq(IRQ_VSYNCPULSE, fb_vbl_handler, SA_SHIRQ, + "framebuffer vbl", info); +#endif + /* Initialize the work queue. If the driver provides its + * own work queue this means it will use something besides + * default timer to flash the cursor. */ + if (!info->queue.func) { + INIT_WORK(&info->queue, fb_flashcursor, info); + + init_timer(&info->cursor_timer); + info->cursor_timer.function = cursor_timer_handler; + info->cursor_timer.expires = jiffies + HZ / 5; + info->cursor_timer.data = (unsigned long ) info; + add_timer(&info->cursor_timer); + } + return display_desc; +} + +static void fbcon_init(struct vc_data *vc, int init) +{ + struct fb_info *info = registered_fb[(int) con2fb_map[vc->vc_num]]; + struct vc_data **default_mode = vc->vc_display_fg; + struct display *t, *p = &fb_display[vc->vc_num]; + int display_fg = (*default_mode)->vc_num; + int logo = 1, new_rows, new_cols, rows, cols, charcnt = 256; + unsigned short *save = NULL, *r, *q; + int cap = info->flags; + + if (info_idx == -1 || info == NULL) + return; + if (vc->vc_num != display_fg || (info->flags & FBINFO_MODULE) || + (info->fix.type == FB_TYPE_TEXT)) + logo = 0; + + info->var.xoffset = info->var.yoffset = p->yscroll = 0; /* reset wrap/pan */ + + if (var_to_display(p, &info->var, info)) + return; + + /* If we are not the first console on this + fb, copy the font from that console */ + t = &fb_display[display_fg]; + if (!vc->vc_font.data) { + vc->vc_font.data = p->fontdata = t->fontdata; + vc->vc_font.width = (*default_mode)->vc_font.width; + vc->vc_font.height = (*default_mode)->vc_font.height; + p->userfont = t->userfont; + if (p->userfont) + REFCOUNT(p->fontdata)++; + con_copy_unimap(vc->vc_num, display_fg); + } + if (p->userfont) + charcnt = FNTCHARCNT(p->fontdata); + vc->vc_can_do_color = (fb_get_color_depth(info) != 1); + vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800; + if (charcnt == 256) { + vc->vc_hi_font_mask = 0; + } else { + vc->vc_hi_font_mask = 0x100; + if (vc->vc_can_do_color) + vc->vc_complement_mask <<= 1; + } + cols = vc->vc_cols; + rows = vc->vc_rows; + new_cols = info->var.xres / vc->vc_font.width; + new_rows = info->var.yres / vc->vc_font.height; + vc_resize(vc->vc_num, new_cols, new_rows); + /* + * We must always set the mode. The mode of the previous console + * driver could be in the same resolution but we are using different + * hardware so we have to initialize the hardware. + * + * We need to do it in fbcon_init() to prevent screen corruption. + */ + if (CON_IS_VISIBLE(vc) && info->fbops->fb_set_par) + info->fbops->fb_set_par(info); + + + if ((cap & FBINFO_HWACCEL_COPYAREA) && + !(cap & FBINFO_HWACCEL_DISABLED)) + p->scrollmode = SCROLL_MOVE; + else /* default to something safe */ + p->scrollmode = SCROLL_REDRAW; + + /* + * ++guenther: console.c:vc_allocate() relies on initializing + * vc_{cols,rows}, but we must not set those if we are only + * resizing the console. + */ + if (!init) { + vc->vc_cols = new_cols; + vc->vc_rows = new_rows; + } + + if (logo) { + /* Need to make room for the logo */ + int cnt, erase = vc->vc_video_erase_char; + int step; + + /* + * remove underline attribute from erase character + * if black and white framebuffer. + */ + if (fb_get_color_depth(info) == 1) + erase &= ~0x400; + logo_height = fb_prepare_logo(info); + logo_lines = (logo_height + vc->vc_font.height - 1) / + vc->vc_font.height; + q = (unsigned short *) (vc->vc_origin + + vc->vc_size_row * rows); + step = logo_lines * cols; + for (r = q - logo_lines * cols; r < q; r++) + if (scr_readw(r) != vc->vc_video_erase_char) + break; + if (r != q && new_rows >= rows + logo_lines) { + save = kmalloc(logo_lines * new_cols * 2, GFP_KERNEL); + if (save) { + int i = cols < new_cols ? cols : new_cols; + scr_memsetw(save, erase, logo_lines * new_cols * 2); + r = q - step; + for (cnt = 0; cnt < logo_lines; cnt++, r += i) + scr_memcpyw(save + cnt * new_cols, r, 2 * i); + r = q; + } + } + if (r == q) { + /* We can scroll screen down */ + r = q - step - cols; + for (cnt = rows - logo_lines; cnt > 0; cnt--) { + scr_memcpyw(r + step, r, vc->vc_size_row); + r -= cols; + } + if (!save) { + vc->vc_y += logo_lines; + vc->vc_pos += logo_lines * vc->vc_size_row; + } + } + scr_memsetw((unsigned short *) vc->vc_origin, + erase, + vc->vc_size_row * logo_lines); + + if (CON_IS_VISIBLE(vc) && vt_cons[vc->vc_num]->vc_mode == KD_TEXT) { + accel_clear_margins(vc, info, 0); + update_screen(vc->vc_num); + } + if (save) { + q = (unsigned short *) (vc->vc_origin + + vc->vc_size_row * + rows); + scr_memcpyw(q, save, logo_lines * new_cols * 2); + vc->vc_y += logo_lines; + vc->vc_pos += logo_lines * vc->vc_size_row; + kfree(save); + } + if (logo_lines > vc->vc_bottom) { + logo_shown = -1; + printk(KERN_INFO + "fbcon_init: disable boot-logo (boot-logo bigger than screen).\n"); + } else { + logo_shown = -2; + vc->vc_top = logo_lines; + } + } + + if (vc->vc_num == display_fg && softback_buf) { + int l = fbcon_softback_size / vc->vc_size_row; + if (l > 5) + softback_end = softback_buf + l * vc->vc_size_row; + else { + /* Smaller scrollback makes no sense, and 0 would screw + the operation totally */ + softback_top = 0; + } + } +} + +static void fbcon_deinit(struct vc_data *vc) +{ + struct display *p = &fb_display[vc->vc_num]; + + if (info_idx != -1) + return; + fbcon_free_font(p); +} + +/* ====================================================================== */ + +/* fbcon_XXX routines - interface used by the world + * + * This system is now divided into two levels because of complications + * caused by hardware scrolling. Top level functions: + * + * fbcon_bmove(), fbcon_clear(), fbcon_putc() + * + * handles y values in range [0, scr_height-1] that correspond to real + * screen positions. y_wrap shift means that first line of bitmap may be + * anywhere on this display. These functions convert lineoffsets to + * bitmap offsets and deal with the wrap-around case by splitting blits. + * + * fbcon_bmove_physical_8() -- These functions fast implementations + * fbcon_clear_physical_8() -- of original fbcon_XXX fns. + * fbcon_putc_physical_8() -- (font width != 8) may be added later + * + * WARNING: + * + * At the moment fbcon_putc() cannot blit across vertical wrap boundary + * Implies should only really hardware scroll in rows. Only reason for + * restriction is simplicity & efficiency at the moment. + */ + +static __inline__ int real_y(struct display *p, int ypos) +{ + int rows = p->vrows; + + ypos += p->yscroll; + return ypos < rows ? ypos : ypos - rows; +} + + +static void fbcon_clear(struct vc_data *vc, int sy, int sx, int height, + int width) +{ + struct fb_info *info = registered_fb[(int) con2fb_map[vc->vc_num]]; + + struct display *p = &fb_display[vc->vc_num]; + u_int y_break; + + if (!info->fbops->fb_blank && console_blanked) + return; + if (info->state != FBINFO_STATE_RUNNING) + return; + + if (!height || !width) + return; + + /* Split blits that cross physical y_wrap boundary */ + + y_break = p->vrows - p->yscroll; + if (sy < y_break && sy + height - 1 >= y_break) { + u_int b = y_break - sy; + accel_clear(vc, info, real_y(p, sy), sx, b, width); + accel_clear(vc, info, real_y(p, sy + b), sx, height - b, + width); + } else + accel_clear(vc, info, real_y(p, sy), sx, height, width); +} + +static void fbcon_putcs(struct vc_data *vc, const unsigned short *s, + int count, int ypos, int xpos) +{ + struct fb_info *info = registered_fb[(int) con2fb_map[vc->vc_num]]; + struct display *p = &fb_display[vc->vc_num]; + + if (!info->fbops->fb_blank && console_blanked) + return; + if (info->state != FBINFO_STATE_RUNNING) + return; + + if (vt_cons[vc->vc_num]->vc_mode != KD_TEXT) + return; + + accel_putcs(vc, info, s, count, real_y(p, ypos), xpos); +} + +static void fbcon_putc(struct vc_data *vc, int c, int ypos, int xpos) +{ + fbcon_putcs(vc, (const unsigned short *) &c, 1, ypos, xpos); +} + +static void fbcon_cursor(struct vc_data *vc, int mode) +{ + struct fb_cursor cursor; + struct fb_info *info = registered_fb[(int) con2fb_map[vc->vc_num]]; + unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff; + struct display *p = &fb_display[vc->vc_num]; + int w = (vc->vc_font.width + 7) >> 3, c; + int y = real_y(p, vc->vc_y), fg, bg; + int attribute; + u8 *src; + + if (mode & CM_SOFTBACK) { + mode &= ~CM_SOFTBACK; + if (softback_lines) { + if (y + softback_lines >= vc->vc_rows) + mode = CM_ERASE; + else + y += softback_lines; + } + } else if (softback_lines) + fbcon_set_origin(vc); + + c = scr_readw((u16 *) vc->vc_pos); + attribute = get_attribute(info, c); + src = vc->vc_font.data + ((c & charmask) * (w * vc->vc_font.height)); + if (attribute) { + u8 *dst; + + dst = kmalloc(w * vc->vc_font.height, GFP_ATOMIC); + if (!dst) + return; + if (info->cursor.data) + kfree(info->cursor.data); + info->cursor.data = dst; + update_attr(dst, src, attribute, vc); + src = dst; + } + + cursor.image.data = src; + cursor.set = FB_CUR_SETCUR; + cursor.image.depth = 1; + + switch (mode) { + case CM_ERASE: + if (info->cursor.rop == ROP_XOR) { + info->cursor.enable = 0; + info->cursor.rop = ROP_COPY; + info->fbops->fb_cursor(info, &cursor); + } + break; + case CM_MOVE: + case CM_DRAW: + info->cursor.enable = 1; + fg = get_color(vc, info, c, 1); + bg = get_color(vc, info, c, 0); + + if (info->cursor.image.fg_color != fg || + info->cursor.image.bg_color != bg) { + cursor.image.fg_color = fg; + cursor.image.bg_color = bg; + cursor.set |= FB_CUR_SETCMAP; + } + + if ((info->cursor.image.dx != (vc->vc_font.width * vc->vc_x)) || + (info->cursor.image.dy != (vc->vc_font.height * y))) { + cursor.image.dx = vc->vc_font.width * vc->vc_x; + cursor.image.dy = vc->vc_font.height * y; + cursor.set |= FB_CUR_SETPOS; + } + + if (info->cursor.image.height != vc->vc_font.height || + info->cursor.image.width != vc->vc_font.width) { + cursor.image.height = vc->vc_font.height; + cursor.image.width = vc->vc_font.width; + cursor.set |= FB_CUR_SETSIZE; + } + + if (info->cursor.hot.x || info->cursor.hot.y) { + cursor.hot.x = cursor.hot.y = 0; + cursor.set |= FB_CUR_SETHOT; + } + + if ((cursor.set & FB_CUR_SETSIZE) || + ((vc->vc_cursor_type & 0x0f) != p->cursor_shape) + || info->cursor.mask == NULL) { + char *mask = kmalloc(w*vc->vc_font.height, GFP_ATOMIC); + int cur_height, size, i = 0; + u8 msk = 0xff; + + if (!mask) + return; + + if (info->cursor.mask) + kfree(info->cursor.mask); + info->cursor.mask = mask; + p->cursor_shape = vc->vc_cursor_type & 0x0f; + cursor.set |= FB_CUR_SETSHAPE; + + switch (vc->vc_cursor_type & 0x0f) { + case CUR_NONE: + cur_height = 0; + break; + case CUR_UNDERLINE: + cur_height = (vc->vc_font.height < 10) ? 1 : 2; + break; + case CUR_LOWER_THIRD: + cur_height = vc->vc_font.height/3; + break; + case CUR_LOWER_HALF: + cur_height = vc->vc_font.height >> 1; + break; + case CUR_TWO_THIRDS: + cur_height = (vc->vc_font.height << 1)/3; + break; + case CUR_BLOCK: + default: + cur_height = vc->vc_font.height; + break; + } + size = (vc->vc_font.height - cur_height) * w; + while (size--) + mask[i++] = ~msk; + size = cur_height * w; + while (size--) + mask[i++] = msk; + } + info->cursor.rop = ROP_XOR; + info->fbops->fb_cursor(info, &cursor); + vbl_cursor_cnt = CURSOR_DRAW_DELAY; + break; + } +} + +static int scrollback_phys_max = 0; +static int scrollback_max = 0; +static int scrollback_current = 0; + +int update_var(int con, struct fb_info *info) +{ + if (con == info->currcon) + return fb_pan_display(info, &info->var); + return 0; +} + +static void fbcon_set_disp(struct fb_info *info, struct vc_data *vc) +{ + struct display *p = &fb_display[vc->vc_num], *t; + struct vc_data **default_mode = vc->vc_display_fg; + int display_fg = (*default_mode)->vc_num; + int rows, cols, charcnt = 256; + + info->var.xoffset = info->var.yoffset = p->yscroll = 0; + if (var_to_display(p, &info->var, info)) + return; + t = &fb_display[display_fg]; + if (!vc->vc_font.data) { + vc->vc_font.data = p->fontdata = t->fontdata; + vc->vc_font.width = (*default_mode)->vc_font.width; + vc->vc_font.height = (*default_mode)->vc_font.height; + p->userfont = t->userfont; + if (p->userfont) + REFCOUNT(p->fontdata)++; + con_copy_unimap(vc->vc_num, display_fg); + } + if (p->userfont) + charcnt = FNTCHARCNT(p->fontdata); + + vc->vc_can_do_color = (fb_get_color_depth(info) != 1); + vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800; + if (charcnt == 256) { + vc->vc_hi_font_mask = 0; + } else { + vc->vc_hi_font_mask = 0x100; + if (vc->vc_can_do_color) + vc->vc_complement_mask <<= 1; + } + cols = info->var.xres / vc->vc_font.width; + rows = info->var.yres / vc->vc_font.height; + vc_resize(vc->vc_num, cols, rows); + if (CON_IS_VISIBLE(vc)) { + update_screen(vc->vc_num); + if (softback_buf) { + int l = fbcon_softback_size / vc->vc_size_row; + + if (l > 5) + softback_end = softback_buf + l * + vc->vc_size_row; + else { + /* Smaller scrollback makes no sense, and 0 + would screw the operation totally */ + softback_top = 0; + } + } + } + switch_screen(fg_console); +} + +static __inline__ void ywrap_up(struct vc_data *vc, int count) +{ + struct fb_info *info = registered_fb[(int) con2fb_map[vc->vc_num]]; + struct display *p = &fb_display[vc->vc_num]; + + p->yscroll += count; + if (p->yscroll >= p->vrows) /* Deal with wrap */ + p->yscroll -= p->vrows; + info->var.xoffset = 0; + info->var.yoffset = p->yscroll * vc->vc_font.height; + info->var.vmode |= FB_VMODE_YWRAP; + update_var(vc->vc_num, info); + scrollback_max += count; + if (scrollback_max > scrollback_phys_max) + scrollback_max = scrollback_phys_max; + scrollback_current = 0; +} + +static __inline__ void ywrap_down(struct vc_data *vc, int count) +{ + struct fb_info *info = registered_fb[(int) con2fb_map[vc->vc_num]]; + struct display *p = &fb_display[vc->vc_num]; + + p->yscroll -= count; + if (p->yscroll < 0) /* Deal with wrap */ + p->yscroll += p->vrows; + info->var.xoffset = 0; + info->var.yoffset = p->yscroll * vc->vc_font.height; + info->var.vmode |= FB_VMODE_YWRAP; + update_var(vc->vc_num, info); + scrollback_max -= count; + if (scrollback_max < 0) + scrollback_max = 0; + scrollback_current = 0; +} + +static __inline__ void ypan_up(struct vc_data *vc, int count) +{ + struct fb_info *info = registered_fb[(int) con2fb_map[vc->vc_num]]; + struct display *p = &fb_display[vc->vc_num]; + + p->yscroll += count; + if (p->yscroll > p->vrows - vc->vc_rows) { + accel_bmove(vc, info, p->vrows - vc->vc_rows, + 0, 0, 0, vc->vc_rows, vc->vc_cols); + p->yscroll -= p->vrows - vc->vc_rows; + } + info->var.xoffset = 0; + info->var.yoffset = p->yscroll * vc->vc_font.height; + info->var.vmode &= ~FB_VMODE_YWRAP; + update_var(vc->vc_num, info); + accel_clear_margins(vc, info, 1); + scrollback_max += count; + if (scrollback_max > scrollback_phys_max) + scrollback_max = scrollback_phys_max; + scrollback_current = 0; +} + +static __inline__ void ypan_up_redraw(struct vc_data *vc, int t, int count) +{ + struct fb_info *info = registered_fb[(int) con2fb_map[vc->vc_num]]; + struct display *p = &fb_display[vc->vc_num]; + int redraw = 0; + + p->yscroll += count; + if (p->yscroll > p->vrows - vc->vc_rows) { + p->yscroll -= p->vrows - vc->vc_rows; + redraw = 1; + } + + info->var.xoffset = 0; + info->var.yoffset = p->yscroll * vc->vc_font.height; + info->var.vmode &= ~FB_VMODE_YWRAP; + if (redraw) + fbcon_redraw_move(vc, p, t + count, vc->vc_rows - count, t); + update_var(vc->vc_num, info); + accel_clear_margins(vc, info, 1); + scrollback_max += count; + if (scrollback_max > scrollback_phys_max) + scrollback_max = scrollback_phys_max; + scrollback_current = 0; +} + +static __inline__ void ypan_down(struct vc_data *vc, int count) +{ + struct fb_info *info = registered_fb[(int) con2fb_map[vc->vc_num]]; + struct display *p = &fb_display[vc->vc_num]; + + p->yscroll -= count; + if (p->yscroll < 0) { + accel_bmove(vc, info, 0, 0, p->vrows - vc->vc_rows, + 0, vc->vc_rows, vc->vc_cols); + p->yscroll += p->vrows - vc->vc_rows; + } + info->var.xoffset = 0; + info->var.yoffset = p->yscroll * vc->vc_font.height; + info->var.vmode &= ~FB_VMODE_YWRAP; + update_var(vc->vc_num, info); + accel_clear_margins(vc, info, 1); + scrollback_max -= count; + if (scrollback_max < 0) + scrollback_max = 0; + scrollback_current = 0; +} + +static __inline__ void ypan_down_redraw(struct vc_data *vc, int t, int count) +{ + struct fb_info *info = registered_fb[(int) con2fb_map[vc->vc_num]]; + struct display *p = &fb_display[vc->vc_num]; + int redraw = 0; + + p->yscroll -= count; + if (p->yscroll < 0) { + p->yscroll += p->vrows - vc->vc_rows; + redraw = 1; + } + info->var.xoffset = 0; + info->var.yoffset = p->yscroll * vc->vc_font.height; + info->var.vmode &= ~FB_VMODE_YWRAP; + if (redraw) + fbcon_redraw_move(vc, p, t, vc->vc_rows - count, t + count); + update_var(vc->vc_num, info); + accel_clear_margins(vc, info, 1); + scrollback_max -= count; + if (scrollback_max < 0) + scrollback_max = 0; + scrollback_current = 0; +} + +static void fbcon_redraw_softback(struct vc_data *vc, struct display *p, + long delta) +{ + struct fb_info *info = registered_fb[(int) con2fb_map[vc->vc_num]]; + int count = vc->vc_rows; + unsigned short *d, *s; + unsigned long n; + int line = 0; + + d = (u16 *) softback_curr; + if (d == (u16 *) softback_in) + d = (u16 *) vc->vc_origin; + n = softback_curr + delta * vc->vc_size_row; + softback_lines -= delta; + if (delta < 0) { + if (softback_curr < softback_top && n < softback_buf) { + n += softback_end - softback_buf; + if (n < softback_top) { + softback_lines -= + (softback_top - n) / vc->vc_size_row; + n = softback_top; + } + } else if (softback_curr >= softback_top + && n < softback_top) { + softback_lines -= + (softback_top - n) / vc->vc_size_row; + n = softback_top; + } + } else { + if (softback_curr > softback_in && n >= softback_end) { + n += softback_buf - softback_end; + if (n > softback_in) { + n = softback_in; + softback_lines = 0; + } + } else if (softback_curr <= softback_in && n > softback_in) { + n = softback_in; + softback_lines = 0; + } + } + if (n == softback_curr) + return; + softback_curr = n; + s = (u16 *) softback_curr; + if (s == (u16 *) softback_in) + s = (u16 *) vc->vc_origin; + while (count--) { + unsigned short *start; + unsigned short *le; + unsigned short c; + int x = 0; + unsigned short attr = 1; + + start = s; + le = advance_row(s, 1); + do { + c = scr_readw(s); + if (attr != (c & 0xff00)) { + attr = c & 0xff00; + if (s > start) { + accel_putcs(vc, info, start, s - start, + real_y(p, line), x); + x += s - start; + start = s; + } + } + if (c == scr_readw(d)) { + if (s > start) { + accel_putcs(vc, info, start, s - start, + real_y(p, line), x); + x += s - start + 1; + start = s + 1; + } else { + x++; + start++; + } + } + s++; + d++; + } while (s < le); + if (s > start) + accel_putcs(vc, info, start, s - start, + real_y(p, line), x); + line++; + if (d == (u16 *) softback_end) + d = (u16 *) softback_buf; + if (d == (u16 *) softback_in) + d = (u16 *) vc->vc_origin; + if (s == (u16 *) softback_end) + s = (u16 *) softback_buf; + if (s == (u16 *) softback_in) + s = (u16 *) vc->vc_origin; + } +} + +static void fbcon_redraw_move(struct vc_data *vc, struct display *p, + int line, int count, int dy) +{ + struct fb_info *info = registered_fb[(int) con2fb_map[vc->vc_num]]; + unsigned short *s = (unsigned short *) + (vc->vc_origin + vc->vc_size_row * line); + + while (count--) { + unsigned short *start = s; + unsigned short *le = advance_row(s, 1); + unsigned short c; + int x = 0; + unsigned short attr = 1; + + do { + c = scr_readw(s); + if (attr != (c & 0xff00)) { + attr = c & 0xff00; + if (s > start) { + accel_putcs(vc, info, start, s - start, + real_y(p, dy), x); + x += s - start; + start = s; + } + } + console_conditional_schedule(); + s++; + } while (s < le); + if (s > start) + accel_putcs(vc, info, start, s - start, + real_y(p, dy), x); + console_conditional_schedule(); + dy++; + } +} + +static void fbcon_redraw(struct vc_data *vc, struct display *p, + int line, int count, int offset) +{ + unsigned short *d = (unsigned short *) + (vc->vc_origin + vc->vc_size_row * line); + struct fb_info *info = registered_fb[(int) con2fb_map[vc->vc_num]]; + unsigned short *s = d + offset; + + while (count--) { + unsigned short *start = s; + unsigned short *le = advance_row(s, 1); + unsigned short c; + int x = 0; + unsigned short attr = 1; + + do { + c = scr_readw(s); + if (attr != (c & 0xff00)) { + attr = c & 0xff00; + if (s > start) { + accel_putcs(vc, info, start, s - start, + real_y(p, line), x); + x += s - start; + start = s; + } + } + if (c == scr_readw(d)) { + if (s > start) { + accel_putcs(vc, info, start, s - start, + real_y(p, line), x); + x += s - start + 1; + start = s + 1; + } else { + x++; + start++; + } + } + scr_writew(c, d); + console_conditional_schedule(); + s++; + d++; + } while (s < le); + if (s > start) + accel_putcs(vc, info, start, s - start, + real_y(p, line), x); + console_conditional_schedule(); + if (offset > 0) + line++; + else { + line--; + /* NOTE: We subtract two lines from these pointers */ + s -= vc->vc_size_row; + d -= vc->vc_size_row; + } + } +} + +static inline void fbcon_softback_note(struct vc_data *vc, int t, + int count) +{ + unsigned short *p; + + if (vc->vc_num != fg_console) + return; + p = (unsigned short *) (vc->vc_origin + t * vc->vc_size_row); + + while (count) { + scr_memcpyw((u16 *) softback_in, p, vc->vc_size_row); + count--; + p = advance_row(p, 1); + softback_in += vc->vc_size_row; + if (softback_in == softback_end) + softback_in = softback_buf; + if (softback_in == softback_top) { + softback_top += vc->vc_size_row; + if (softback_top == softback_end) + softback_top = softback_buf; + } + } + softback_curr = softback_in; +} + +static int fbcon_scroll(struct vc_data *vc, int t, int b, int dir, + int count) +{ + struct fb_info *info = registered_fb[(int) con2fb_map[vc->vc_num]]; + struct display *p = &fb_display[vc->vc_num]; + int scroll_partial = info->flags & FBINFO_PARTIAL_PAN_OK; + + if (!info->fbops->fb_blank && console_blanked) + return 0; + + if (!count || vt_cons[vc->vc_num]->vc_mode != KD_TEXT) + return 0; + + fbcon_cursor(vc, CM_ERASE); + + /* + * ++Geert: Only use ywrap/ypan if the console is in text mode + * ++Andrew: Only use ypan on hardware text mode when scrolling the + * whole screen (prevents flicker). + */ + + switch (dir) { + case SM_UP: + if (count > vc->vc_rows) /* Maximum realistic size */ + count = vc->vc_rows; + if (softback_top) + fbcon_softback_note(vc, t, count); + if (logo_shown >= 0) + goto redraw_up; + switch (p->scrollmode) { + case SCROLL_MOVE: + accel_bmove(vc, info, t + count, 0, t, 0, + b - t - count, vc->vc_cols); + accel_clear(vc, info, b - count, 0, count, + vc->vc_cols); + break; + + case SCROLL_WRAP_MOVE: + if (b - t - count > 3 * vc->vc_rows >> 2) { + if (t > 0) + fbcon_bmove(vc, 0, 0, count, 0, t, + vc->vc_cols); + ywrap_up(vc, count); + if (vc->vc_rows - b > 0) + fbcon_bmove(vc, b - count, 0, b, 0, + vc->vc_rows - b, + vc->vc_cols); + } else if (info->flags & FBINFO_READS_FAST) + fbcon_bmove(vc, t + count, 0, t, 0, + b - t - count, vc->vc_cols); + else + goto redraw_up; + fbcon_clear(vc, b - count, 0, count, vc->vc_cols); + break; + + case SCROLL_PAN_REDRAW: + if ((p->yscroll + count <= + 2 * (p->vrows - vc->vc_rows)) + && ((!scroll_partial && (b - t == vc->vc_rows)) + || (scroll_partial + && (b - t - count > + 3 * vc->vc_rows >> 2)))) { + if (t > 0) + fbcon_redraw_move(vc, p, 0, t, count); + ypan_up_redraw(vc, t, count); + if (vc->vc_rows - b > 0) + fbcon_redraw_move(vc, p, b - count, + vc->vc_rows - b, b); + } else + fbcon_redraw_move(vc, p, t + count, b - t - count, t); + fbcon_clear(vc, b - count, 0, count, vc->vc_cols); + break; + + case SCROLL_PAN_MOVE: + if ((p->yscroll + count <= + 2 * (p->vrows - vc->vc_rows)) + && ((!scroll_partial && (b - t == vc->vc_rows)) + || (scroll_partial + && (b - t - count > + 3 * vc->vc_rows >> 2)))) { + if (t > 0) + fbcon_bmove(vc, 0, 0, count, 0, t, + vc->vc_cols); + ypan_up(vc, count); + if (vc->vc_rows - b > 0) + fbcon_bmove(vc, b - count, 0, b, 0, + vc->vc_rows - b, + vc->vc_cols); + } else if (info->flags & FBINFO_READS_FAST) + fbcon_bmove(vc, t + count, 0, t, 0, + b - t - count, vc->vc_cols); + else + goto redraw_up; + fbcon_clear(vc, b - count, 0, count, vc->vc_cols); + break; + + case SCROLL_REDRAW: + redraw_up: + fbcon_redraw(vc, p, t, b - t - count, + count * vc->vc_cols); + accel_clear(vc, info, real_y(p, b - count), 0, + count, vc->vc_cols); + scr_memsetw((unsigned short *) (vc->vc_origin + + vc->vc_size_row * + (b - count)), + vc->vc_video_erase_char, + vc->vc_size_row * count); + return 1; + } + break; + + case SM_DOWN: + if (count > vc->vc_rows) /* Maximum realistic size */ + count = vc->vc_rows; + switch (p->scrollmode) { + case SCROLL_MOVE: + accel_bmove(vc, info, t, 0, t + count, 0, + b - t - count, vc->vc_cols); + accel_clear(vc, info, t, 0, count, vc->vc_cols); + break; + + case SCROLL_WRAP_MOVE: + if (b - t - count > 3 * vc->vc_rows >> 2) { + if (vc->vc_rows - b > 0) + fbcon_bmove(vc, b, 0, b - count, 0, + vc->vc_rows - b, + vc->vc_cols); + ywrap_down(vc, count); + if (t > 0) + fbcon_bmove(vc, count, 0, 0, 0, t, + vc->vc_cols); + } else if (info->flags & FBINFO_READS_FAST) + fbcon_bmove(vc, t, 0, t + count, 0, + b - t - count, vc->vc_cols); + else + goto redraw_down; + fbcon_clear(vc, t, 0, count, vc->vc_cols); + break; + + case SCROLL_PAN_MOVE: + if ((count - p->yscroll <= p->vrows - vc->vc_rows) + && ((!scroll_partial && (b - t == vc->vc_rows)) + || (scroll_partial + && (b - t - count > + 3 * vc->vc_rows >> 2)))) { + if (vc->vc_rows - b > 0) + fbcon_bmove(vc, b, 0, b - count, 0, + vc->vc_rows - b, + vc->vc_cols); + ypan_down(vc, count); + if (t > 0) + fbcon_bmove(vc, count, 0, 0, 0, t, + vc->vc_cols); + } else if (info->flags & FBINFO_READS_FAST) + fbcon_bmove(vc, t, 0, t + count, 0, + b - t - count, vc->vc_cols); + else + goto redraw_down; + fbcon_clear(vc, t, 0, count, vc->vc_cols); + break; + + case SCROLL_PAN_REDRAW: + if ((count - p->yscroll <= p->vrows - vc->vc_rows) + && ((!scroll_partial && (b - t == vc->vc_rows)) + || (scroll_partial + && (b - t - count > + 3 * vc->vc_rows >> 2)))) { + if (vc->vc_rows - b > 0) + fbcon_redraw_move(vc, p, b, vc->vc_rows - b, + b - count); + ypan_down_redraw(vc, t, count); + if (t > 0) + fbcon_redraw_move(vc, p, count, t, 0); + } else + fbcon_redraw_move(vc, p, t, b - t - count, t + count); + fbcon_clear(vc, t, 0, count, vc->vc_cols); + break; + + case SCROLL_REDRAW: + redraw_down: + fbcon_redraw(vc, p, b - 1, b - t - count, + -count * vc->vc_cols); + accel_clear(vc, info, real_y(p, t), 0, count, + vc->vc_cols); + scr_memsetw((unsigned short *) (vc->vc_origin + + vc->vc_size_row * + t), + vc->vc_video_erase_char, + vc->vc_size_row * count); + return 1; + } + } + return 0; +} + + +static void fbcon_bmove(struct vc_data *vc, int sy, int sx, int dy, int dx, + int height, int width) +{ + struct fb_info *info = registered_fb[(int) con2fb_map[vc->vc_num]]; + struct display *p = &fb_display[vc->vc_num]; + + if (!info->fbops->fb_blank && console_blanked) + return; + + if (!width || !height) + return; + + /* Split blits that cross physical y_wrap case. + * Pathological case involves 4 blits, better to use recursive + * code rather than unrolled case + * + * Recursive invocations don't need to erase the cursor over and + * over again, so we use fbcon_bmove_rec() + */ + fbcon_bmove_rec(vc, p, sy, sx, dy, dx, height, width, + p->vrows - p->yscroll); +} + +static void fbcon_bmove_rec(struct vc_data *vc, struct display *p, int sy, int sx, + int dy, int dx, int height, int width, u_int y_break) +{ + struct fb_info *info = registered_fb[(int) con2fb_map[vc->vc_num]]; + u_int b; + + if (sy < y_break && sy + height > y_break) { + b = y_break - sy; + if (dy < sy) { /* Avoid trashing self */ + fbcon_bmove_rec(vc, p, sy, sx, dy, dx, b, width, + y_break); + fbcon_bmove_rec(vc, p, sy + b, sx, dy + b, dx, + height - b, width, y_break); + } else { + fbcon_bmove_rec(vc, p, sy + b, sx, dy + b, dx, + height - b, width, y_break); + fbcon_bmove_rec(vc, p, sy, sx, dy, dx, b, width, + y_break); + } + return; + } + + if (dy < y_break && dy + height > y_break) { + b = y_break - dy; + if (dy < sy) { /* Avoid trashing self */ + fbcon_bmove_rec(vc, p, sy, sx, dy, dx, b, width, + y_break); + fbcon_bmove_rec(vc, p, sy + b, sx, dy + b, dx, + height - b, width, y_break); + } else { + fbcon_bmove_rec(vc, p, sy + b, sx, dy + b, dx, + height - b, width, y_break); + fbcon_bmove_rec(vc, p, sy, sx, dy, dx, b, width, + y_break); + } + return; + } + accel_bmove(vc, info, real_y(p, sy), sx, real_y(p, dy), dx, + height, width); +} + +static __inline__ void updatescrollmode(struct display *p, struct fb_info *info, + struct vc_data *vc) +{ + int fh = vc->vc_font.height; + int cap = info->flags; + int good_pan = (cap & FBINFO_HWACCEL_YPAN) + && divides(info->fix.ypanstep, vc->vc_font.height) + && info->var.yres_virtual > info->var.yres; + int good_wrap = (cap & FBINFO_HWACCEL_YWRAP) + && divides(info->fix.ywrapstep, vc->vc_font.height) + && divides(vc->vc_font.height, info->var.yres_virtual); + int reading_fast = cap & FBINFO_READS_FAST; + int fast_copyarea = (cap & FBINFO_HWACCEL_COPYAREA) && !(cap & FBINFO_HWACCEL_DISABLED); + int fast_imageblit = (cap & FBINFO_HWACCEL_IMAGEBLIT) && !(cap & FBINFO_HWACCEL_DISABLED); + + p->vrows = info->var.yres_virtual/fh; + if (info->var.yres > (fh * (vc->vc_rows + 1))) + p->vrows -= (info->var.yres - (fh * vc->vc_rows)) / fh; + if ((info->var.yres % fh) && (info->var.yres_virtual % fh < + info->var.yres % fh)) + p->vrows--; + + if (good_wrap || good_pan) { + if (reading_fast || fast_copyarea) + p->scrollmode = good_wrap ? SCROLL_WRAP_MOVE : SCROLL_PAN_MOVE; + else + p->scrollmode = good_wrap ? SCROLL_REDRAW : + SCROLL_PAN_REDRAW; + } else { + if (reading_fast || (fast_copyarea && !fast_imageblit)) + p->scrollmode = SCROLL_MOVE; + else + p->scrollmode = SCROLL_REDRAW; + } +} + +static int fbcon_resize(struct vc_data *vc, unsigned int width, + unsigned int height) +{ + struct fb_info *info = registered_fb[(int) con2fb_map[vc->vc_num]]; + struct display *p = &fb_display[vc->vc_num]; + struct fb_var_screeninfo var = info->var; + int x_diff, y_diff; + int fw = vc->vc_font.width; + int fh = vc->vc_font.height; + + var.xres = width * fw; + var.yres = height * fh; + x_diff = info->var.xres - var.xres; + y_diff = info->var.yres - var.yres; + if (x_diff < 0 || x_diff > fw || (y_diff < 0 || y_diff > fh)) { + struct fb_videomode *mode; + + DPRINTK("attempting resize %ix%i\n", var.xres, var.yres); + mode = fb_find_best_mode(&var, &info->modelist); + if (mode == NULL) + return -EINVAL; + fb_videomode_to_var(&var, mode); + if (width > var.xres/fw || height > var.yres/fh) + return -EINVAL; + /* + * The following can probably have any value... Do we need to + * set all of them? + */ + var.bits_per_pixel = p->bits_per_pixel; + var.xres_virtual = p->xres_virtual; + var.yres_virtual = p->yres_virtual; + var.accel_flags = p->accel_flags; + var.width = p->width; + var.height = p->height; + var.red = p->red; + var.green = p->green; + var.blue = p->blue; + var.transp = p->transp; + var.nonstd = p->nonstd; + + DPRINTK("resize now %ix%i\n", var.xres, var.yres); + if (CON_IS_VISIBLE(vc)) { + var.activate = FB_ACTIVATE_NOW | + FB_ACTIVATE_FORCE; + fb_set_var(info, &var); + info->flags &= ~FBINFO_MISC_MODESWITCH; + } + var_to_display(p, &info->var, info); + } + updatescrollmode(p, info, vc); + return 0; +} + +static int fbcon_switch(struct vc_data *vc) +{ + struct fb_info *info = registered_fb[(int) con2fb_map[vc->vc_num]]; + struct display *p = &fb_display[vc->vc_num]; + struct fb_var_screeninfo var; + int i; + + if (softback_top) { + int l = fbcon_softback_size / vc->vc_size_row; + if (softback_lines) + fbcon_set_origin(vc); + softback_top = softback_curr = softback_in = softback_buf; + softback_lines = 0; + + if (l > 5) + softback_end = softback_buf + l * vc->vc_size_row; + else { + /* Smaller scrollback makes no sense, and 0 would screw + the operation totally */ + softback_top = 0; + } + } + if (logo_shown >= 0) { + struct vc_data *conp2 = vc_cons[logo_shown].d; + + if (conp2->vc_top == logo_lines + && conp2->vc_bottom == conp2->vc_rows) + conp2->vc_top = 0; + logo_shown = -1; + } + +#ifdef CONFIG_FB_UI + fbui_switch (info, vc->vc_num); +#endif + + /* + * FIXME: If we have multiple fbdev's loaded, we need to + * update all info->currcon. Perhaps, we can place this + * in a centralized structure, but this might break some + * drivers. + * + * info->currcon = vc->vc_num; + */ + for (i = 0; i < FB_MAX; i++) { + if (registered_fb[i] != NULL) + registered_fb[i]->currcon = vc->vc_num; + } + + memset(&var, 0, sizeof(struct fb_var_screeninfo)); + fb_videomode_to_var(&var, p->mode); + display_to_var(&var, p); + var.activate = FB_ACTIVATE_NOW; + + /* + * make sure we don't unnecessarily trip the memcmp() + * in fb_set_var() + */ + info->var.activate = var.activate; + info->var.yoffset = info->var.xoffset = p->yscroll = 0; + fb_set_var(info, &var); + + if (info->flags & FBINFO_MISC_MODESWITCH) { + if (info->fbops->fb_set_par) + info->fbops->fb_set_par(info); + info->flags &= ~FBINFO_MISC_MODESWITCH; + } + + vc->vc_can_do_color = (fb_get_color_depth(info) != 1); + vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800; + updatescrollmode(p, info, vc); + + switch (p->scrollmode) { + case SCROLL_WRAP_MOVE: + scrollback_phys_max = p->vrows - vc->vc_rows; + break; + case SCROLL_PAN_MOVE: + case SCROLL_PAN_REDRAW: + scrollback_phys_max = p->vrows - 2 * vc->vc_rows; + if (scrollback_phys_max < 0) + scrollback_phys_max = 0; + break; + default: + scrollback_phys_max = 0; + break; + } + scrollback_max = 0; + scrollback_current = 0; + + update_var(vc->vc_num, info); + fbcon_set_palette(vc, color_table); + + if (vt_cons[vc->vc_num]->vc_mode == KD_TEXT) + accel_clear_margins(vc, info, 0); + if (logo_shown == -2) { + logo_shown = fg_console; + /* This is protected above by initmem_freed */ + fb_show_logo(info); + update_region(fg_console, + vc->vc_origin + vc->vc_size_row * vc->vc_top, + vc->vc_size_row * (vc->vc_bottom - + vc->vc_top) / 2); + return 0; + } + return 1; +} + +static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch) +{ + unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff; + struct fb_info *info = registered_fb[(int) con2fb_map[vc->vc_num]]; + struct display *p = &fb_display[vc->vc_num]; + + if (mode_switch) { + struct fb_var_screeninfo var = info->var; + +/* + * HACK ALERT: Some hardware will require reinitializion at this stage, + * others will require it to be done as late as possible. + * For now, we differentiate this with the + * FBINFO_MISC_MODESWITCHLATE bitflag. Worst case will be + * hardware that requires it here and another one later. + * A definitive solution may require fixing X or the VT + * system. + */ + if (info->flags & FBINFO_MISC_MODESWITCHLATE) + info->flags |= FBINFO_MISC_MODESWITCH; + + if (blank) { + fbcon_cursor(vc, CM_ERASE); + return 0; + } + + if (!(info->flags & FBINFO_MISC_MODESWITCHLATE)) { + var.activate = FB_ACTIVATE_NOW | FB_ACTIVATE_FORCE; + fb_set_var(info, &var); + } + } + + fbcon_cursor(vc, blank ? CM_ERASE : CM_DRAW); + + if (!info->fbops->fb_blank) { + if (blank) { + unsigned short oldc; + u_int height; + u_int y_break; + + oldc = vc->vc_video_erase_char; + vc->vc_video_erase_char &= charmask; + height = vc->vc_rows; + y_break = p->vrows - p->yscroll; + if (height > y_break) { + accel_clear(vc, info, real_y(p, 0), + 0, y_break, vc->vc_cols); + accel_clear(vc, info, real_y(p, y_break), + 0, height - y_break, + vc->vc_cols); + } else + accel_clear(vc, info, real_y(p, 0), + 0, height, vc->vc_cols); + vc->vc_video_erase_char = oldc; + } else + update_screen(vc->vc_num); + return 0; + } else + return fb_blank(info, blank); +} + +static void fbcon_free_font(struct display *p) +{ + if (p->userfont && p->fontdata && (--REFCOUNT(p->fontdata) == 0)) + kfree(p->fontdata - FONT_EXTRA_WORDS * sizeof(int)); + p->fontdata = NULL; + p->userfont = 0; +} + +static int fbcon_get_font(struct vc_data *vc, struct console_font *font) +{ + u8 *fontdata = vc->vc_font.data; + u8 *data = font->data; + int i, j; + + font->width = vc->vc_font.width; + font->height = vc->vc_font.height; + font->charcount = vc->vc_hi_font_mask ? 512 : 256; + if (!font->data) + return 0; + + if (font->width <= 8) { + j = vc->vc_font.height; + for (i = 0; i < font->charcount; i++) { + memcpy(data, fontdata, j); + memset(data + j, 0, 32 - j); + data += 32; + fontdata += j; + } + } else if (font->width <= 16) { + j = vc->vc_font.height * 2; + for (i = 0; i < font->charcount; i++) { + memcpy(data, fontdata, j); + memset(data + j, 0, 64 - j); + data += 64; + fontdata += j; + } + } else if (font->width <= 24) { + for (i = 0; i < font->charcount; i++) { + for (j = 0; j < vc->vc_font.height; j++) { + *data++ = fontdata[0]; + *data++ = fontdata[1]; + *data++ = fontdata[2]; + fontdata += sizeof(u32); + } + memset(data, 0, 3 * (32 - j)); + data += 3 * (32 - j); + } + } else { + j = vc->vc_font.height * 4; + for (i = 0; i < font->charcount; i++) { + memcpy(data, fontdata, j); + memset(data + j, 0, 128 - j); + data += 128; + fontdata += j; + } + } + return 0; +} + +static int fbcon_do_set_font(struct vc_data *vc, int w, int h, + u8 * data, int userfont) +{ + struct fb_info *info = registered_fb[(int) con2fb_map[vc->vc_num]]; + struct display *p = &fb_display[vc->vc_num]; + int resize; + int cnt; + char *old_data = NULL; + + if (CON_IS_VISIBLE(vc) && softback_lines) + fbcon_set_origin(vc); + + resize = (w != vc->vc_font.width) || (h != vc->vc_font.height); + if (p->userfont) + old_data = vc->vc_font.data; + if (userfont) + cnt = FNTCHARCNT(data); + else + cnt = 256; + vc->vc_font.data = p->fontdata = data; + if ((p->userfont = userfont)) + REFCOUNT(data)++; + vc->vc_font.width = w; + vc->vc_font.height = h; + if (vc->vc_hi_font_mask && cnt == 256) { + vc->vc_hi_font_mask = 0; + if (vc->vc_can_do_color) { + vc->vc_complement_mask >>= 1; + vc->vc_s_complement_mask >>= 1; + } + + /* ++Edmund: reorder the attribute bits */ + if (vc->vc_can_do_color) { + unsigned short *cp = + (unsigned short *) vc->vc_origin; + int count = vc->vc_screenbuf_size / 2; + unsigned short c; + for (; count > 0; count--, cp++) { + c = scr_readw(cp); + scr_writew(((c & 0xfe00) >> 1) | + (c & 0xff), cp); + } + c = vc->vc_video_erase_char; + vc->vc_video_erase_char = + ((c & 0xfe00) >> 1) | (c & 0xff); + vc->vc_attr >>= 1; + } + } else if (!vc->vc_hi_font_mask && cnt == 512) { + vc->vc_hi_font_mask = 0x100; + if (vc->vc_can_do_color) { + vc->vc_complement_mask <<= 1; + vc->vc_s_complement_mask <<= 1; + } + + /* ++Edmund: reorder the attribute bits */ + { + unsigned short *cp = + (unsigned short *) vc->vc_origin; + int count = vc->vc_screenbuf_size / 2; + unsigned short c; + for (; count > 0; count--, cp++) { + unsigned short newc; + c = scr_readw(cp); + if (vc->vc_can_do_color) + newc = + ((c & 0xff00) << 1) | (c & + 0xff); + else + newc = c & ~0x100; + scr_writew(newc, cp); + } + c = vc->vc_video_erase_char; + if (vc->vc_can_do_color) { + vc->vc_video_erase_char = + ((c & 0xff00) << 1) | (c & 0xff); + vc->vc_attr <<= 1; + } else + vc->vc_video_erase_char = c & ~0x100; + } + + } + + if (resize) { + /* reset wrap/pan */ + info->var.xoffset = info->var.yoffset = p->yscroll = 0; + vc_resize(vc->vc_num, info->var.xres / w, info->var.yres / h); + if (CON_IS_VISIBLE(vc) && softback_buf) { + int l = fbcon_softback_size / vc->vc_size_row; + if (l > 5) + softback_end = + softback_buf + l * vc->vc_size_row; + else { + /* Smaller scrollback makes no sense, and 0 would screw + the operation totally */ + softback_top = 0; + } + } + } else if (CON_IS_VISIBLE(vc) + && vt_cons[vc->vc_num]->vc_mode == KD_TEXT) { + accel_clear_margins(vc, info, 0); + update_screen(vc->vc_num); + } + + if (old_data && (--REFCOUNT(old_data) == 0)) + kfree(old_data - FONT_EXTRA_WORDS * sizeof(int)); + return 0; +} + +static int fbcon_copy_font(struct vc_data *vc, int con) +{ + struct display *od = &fb_display[con]; + struct console_font *f = &vc->vc_font; + + if (od->fontdata == f->data) + return 0; /* already the same font... */ + return fbcon_do_set_font(vc, f->width, f->height, od->fontdata, od->userfont); +} + +/* + * User asked to set font; we are guaranteed that + * a) width and height are in range 1..32 + * b) charcount does not exceed 512 + */ + +static int fbcon_set_font(struct vc_data *vc, struct console_font *font, unsigned flags) +{ + unsigned charcount = font->charcount; + int w = font->width; + int h = font->height; + int size = h; + int i, k; + u8 *new_data, *data = font->data, *p; + + if (charcount != 256 && charcount != 512) + return -EINVAL; + + if (w > 8) { + if (w <= 16) + size *= 2; + else + size *= 4; + } + size *= charcount; + + new_data = kmalloc(FONT_EXTRA_WORDS * sizeof(int) + size, GFP_USER); + + if (!new_data) + return -ENOMEM; + + new_data += FONT_EXTRA_WORDS * sizeof(int); + FNTSIZE(new_data) = size; + FNTCHARCNT(new_data) = charcount; + REFCOUNT(new_data) = 0; /* usage counter */ + p = new_data; + if (w <= 8) { + for (i = 0; i < charcount; i++) { + memcpy(p, data, h); + data += 32; + p += h; + } + } else if (w <= 16) { + h *= 2; + for (i = 0; i < charcount; i++) { + memcpy(p, data, h); + data += 64; + p += h; + } + } else if (w <= 24) { + for (i = 0; i < charcount; i++) { + int j; + for (j = 0; j < h; j++) { + memcpy(p, data, 3); + p[3] = 0; + data += 3; + p += sizeof(u32); + } + data += 3 * (32 - h); + } + } else { + h *= 4; + for (i = 0; i < charcount; i++) { + memcpy(p, data, h); + data += 128; + p += h; + } + } + /* we can do it in u32 chunks because of charcount is 256 or 512, so + font length must be multiple of 256, at least. And 256 is multiple + of 4 */ + k = 0; + while (p > new_data) { + p = (u8 *)((u32 *)p - 1); + k += *(u32 *) p; + } + FNTSUM(new_data) = k; + /* Check if the same font is on some other console already */ + for (i = 0; i < MAX_NR_CONSOLES; i++) { + struct vc_data *tmp = vc_cons[i].d; + + if (fb_display[i].userfont && + fb_display[i].fontdata && + FNTSUM(fb_display[i].fontdata) == k && + FNTSIZE(fb_display[i].fontdata) == size && + tmp->vc_font.width == w && + !memcmp(fb_display[i].fontdata, new_data, size)) { + kfree(new_data - FONT_EXTRA_WORDS * sizeof(int)); + new_data = fb_display[i].fontdata; + break; + } + } + return fbcon_do_set_font(vc, font->width, font->height, new_data, 1); +} + +static int fbcon_set_def_font(struct vc_data *vc, struct console_font *font, char *name) +{ + struct fb_info *info = registered_fb[(int) con2fb_map[vc->vc_num]]; + struct font_desc *f; + + if (!name) + f = get_default_font(info->var.xres, info->var.yres); + else if (!(f = find_font(name))) + return -ENOENT; + + font->width = f->width; + font->height = f->height; + return fbcon_do_set_font(vc, f->width, f->height, f->data, 0); +} + +static u16 palette_red[16]; +static u16 palette_green[16]; +static u16 palette_blue[16]; + +static struct fb_cmap palette_cmap = { + 0, 16, palette_red, palette_green, palette_blue, NULL +}; + +static int fbcon_set_palette(struct vc_data *vc, unsigned char *table) +{ + struct fb_info *info = registered_fb[(int) con2fb_map[vc->vc_num]]; + int i, j, k, depth; + u8 val; + + if (!info->fbops->fb_blank && console_blanked) + return -EINVAL; + depth = fb_get_color_depth(info); + if (depth > 3) { + for (i = j = 0; i < 16; i++) { + k = table[i]; + val = vc->vc_palette[j++]; + palette_red[k] = (val << 8) | val; + val = vc->vc_palette[j++]; + palette_green[k] = (val << 8) | val; + val = vc->vc_palette[j++]; + palette_blue[k] = (val << 8) | val; + } + palette_cmap.len = 16; + palette_cmap.start = 0; + /* + * If framebuffer is capable of less than 16 colors, + * use default palette of fbcon. + */ + } else + fb_copy_cmap(fb_default_cmap(1 << depth), &palette_cmap); + + return fb_set_cmap(&palette_cmap, info); +} + +static u16 *fbcon_screen_pos(struct vc_data *vc, int offset) +{ + unsigned long p; + int line; + + if (vc->vc_num != fg_console || !softback_lines) + return (u16 *) (vc->vc_origin + offset); + line = offset / vc->vc_size_row; + if (line >= softback_lines) + return (u16 *) (vc->vc_origin + offset - + softback_lines * vc->vc_size_row); + p = softback_curr + offset; + if (p >= softback_end) + p += softback_buf - softback_end; + return (u16 *) p; +} + +static unsigned long fbcon_getxy(struct vc_data *vc, unsigned long pos, + int *px, int *py) +{ + unsigned long ret; + int x, y; + + if (pos >= vc->vc_origin && pos < vc->vc_scr_end) { + unsigned long offset = (pos - vc->vc_origin) / 2; + + x = offset % vc->vc_cols; + y = offset / vc->vc_cols; + if (vc->vc_num == fg_console) + y += softback_lines; + ret = pos + (vc->vc_cols - x) * 2; + } else if (vc->vc_num == fg_console && softback_lines) { + unsigned long offset = pos - softback_curr; + + if (pos < softback_curr) + offset += softback_end - softback_buf; + offset /= 2; + x = offset % vc->vc_cols; + y = offset / vc->vc_cols; + ret = pos + (vc->vc_cols - x) * 2; + if (ret == softback_end) + ret = softback_buf; + if (ret == softback_in) + ret = vc->vc_origin; + } else { + /* Should not happen */ + x = y = 0; + ret = vc->vc_origin; + } + if (px) + *px = x; + if (py) + *py = y; + return ret; +} + +/* As we might be inside of softback, we may work with non-contiguous buffer, + that's why we have to use a separate routine. */ +static void fbcon_invert_region(struct vc_data *vc, u16 * p, int cnt) +{ + while (cnt--) { + u16 a = scr_readw(p); + if (!vc->vc_can_do_color) + a ^= 0x0800; + else if (vc->vc_hi_font_mask == 0x100) + a = ((a) & 0x11ff) | (((a) & 0xe000) >> 4) | + (((a) & 0x0e00) << 4); + else + a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) | + (((a) & 0x0700) << 4); + scr_writew(a, p++); + if (p == (u16 *) softback_end) + p = (u16 *) softback_buf; + if (p == (u16 *) softback_in) + p = (u16 *) vc->vc_origin; + } +} + +static int fbcon_scrolldelta(struct vc_data *vc, int lines) +{ + struct fb_info *info = registered_fb[(int) con2fb_map[fg_console]]; + struct display *p = &fb_display[fg_console]; + int offset, limit, scrollback_old; + + if (softback_top) { + if (vc->vc_num != fg_console) + return 0; + if (vt_cons[vc->vc_num]->vc_mode != KD_TEXT || !lines) + return 0; + if (logo_shown >= 0) { + struct vc_data *conp2 = vc_cons[logo_shown].d; + + if (conp2->vc_top == logo_lines + && conp2->vc_bottom == conp2->vc_rows) + conp2->vc_top = 0; + if (logo_shown == vc->vc_num) { + unsigned long p, q; + int i; + + p = softback_in; + q = vc->vc_origin + + logo_lines * vc->vc_size_row; + for (i = 0; i < logo_lines; i++) { + if (p == softback_top) + break; + if (p == softback_buf) + p = softback_end; + p -= vc->vc_size_row; + q -= vc->vc_size_row; + scr_memcpyw((u16 *) q, (u16 *) p, + vc->vc_size_row); + } + softback_in = p; + update_region(vc->vc_num, vc->vc_origin, + logo_lines * vc->vc_cols); + } + logo_shown = -1; + } + fbcon_cursor(vc, CM_ERASE | CM_SOFTBACK); + fbcon_redraw_softback(vc, p, lines); + fbcon_cursor(vc, CM_DRAW | CM_SOFTBACK); + return 0; + } + + if (!scrollback_phys_max) + return -ENOSYS; + + scrollback_old = scrollback_current; + scrollback_current -= lines; + if (scrollback_current < 0) + scrollback_current = 0; + else if (scrollback_current > scrollback_max) + scrollback_current = scrollback_max; + if (scrollback_current == scrollback_old) + return 0; + + if (!info->fbops->fb_blank && + (console_blanked || vt_cons[vc->vc_num]->vc_mode != KD_TEXT + || !lines)) + return 0; + fbcon_cursor(vc, CM_ERASE); + + offset = p->yscroll - scrollback_current; + limit = p->vrows; + switch (p->scrollmode) { + case SCROLL_WRAP_MOVE: + info->var.vmode |= FB_VMODE_YWRAP; + break; + case SCROLL_PAN_MOVE: + case SCROLL_PAN_REDRAW: + limit -= vc->vc_rows; + info->var.vmode &= ~FB_VMODE_YWRAP; + break; + } + if (offset < 0) + offset += limit; + else if (offset >= limit) + offset -= limit; + info->var.xoffset = 0; + info->var.yoffset = offset * vc->vc_font.height; + update_var(vc->vc_num, info); + if (!scrollback_current) + fbcon_cursor(vc, CM_DRAW); + return 0; +} + +static int fbcon_set_origin(struct vc_data *vc) +{ + if (softback_lines && !console_blanked) + fbcon_scrolldelta(vc, softback_lines); + return 0; +} + +static void fbcon_suspended(struct fb_info *info) +{ + /* Clear cursor, restore saved data */ + info->cursor.enable = 0; + info->fbops->fb_cursor(info, &info->cursor); +} + +static void fbcon_resumed(struct fb_info *info) +{ + struct vc_data *vc; + + if (info->currcon < 0) + return; + vc = vc_cons[info->currcon].d; + + update_screen(vc->vc_num); +} + +static void fbcon_modechanged(struct fb_info *info) +{ + struct vc_data *vc = vc_cons[info->currcon].d; + struct display *p; + int rows, cols; + + if (info->currcon < 0 || vt_cons[info->currcon]->vc_mode != + KD_TEXT) + return; + p = &fb_display[vc->vc_num]; + + info->var.xoffset = info->var.yoffset = p->yscroll = 0; + + if (CON_IS_VISIBLE(vc)) { + var_to_display(p, &info->var, info); + cols = info->var.xres / vc->vc_font.width; + rows = info->var.yres / vc->vc_font.height; + vc_resize(vc->vc_num, cols, rows); + updatescrollmode(p, info, vc); + scrollback_max = 0; + scrollback_current = 0; + update_var(vc->vc_num, info); + fbcon_set_palette(vc, color_table); + update_screen(vc->vc_num); + if (softback_buf) { + int l = fbcon_softback_size / vc->vc_size_row; + if (l > 5) + softback_end = softback_buf + l * vc->vc_size_row; + else { + /* Smaller scrollback makes no sense, and 0 + would screw the operation totally */ + softback_top = 0; + } + } + } +} + +static int fbcon_mode_deleted(struct fb_info *info, + struct fb_videomode *mode) +{ + struct fb_info *fb_info; + struct display *p; + int i, j, found = 0; + + /* before deletion, ensure that mode is not in use */ + for (i = first_fb_vc; i <= last_fb_vc; i++) { + j = (int) con2fb_map[i]; + if (j == -1) + continue; + fb_info = registered_fb[j]; + if (fb_info != info) + continue; + p = &fb_display[i]; + if (!p || !p->mode) + continue; + if (fb_mode_is_equal(p->mode, mode)) { + found = 1; + break; + } + } + return found; +} + +static int fbcon_fb_registered(int idx) +{ + int ret = 0; + + if (info_idx == -1) { + info_idx = idx; + ret = fbcon_takeover(); + } + + return ret; +} + +static int fbcon_event_notify(struct notifier_block *self, + unsigned long action, void *data) +{ + struct fb_event *event = (struct fb_event *) data; + struct fb_info *info = event->info; + struct fb_videomode *mode; + struct fb_con2fbmap *con2fb; + int ret = 0; + + switch(action) { + case FB_EVENT_SUSPEND: + fbcon_suspended(info); + break; + case FB_EVENT_RESUME: + fbcon_resumed(info); + break; + case FB_EVENT_MODE_CHANGE: + fbcon_modechanged(info); + break; + case FB_EVENT_MODE_DELETE: + mode = (struct fb_videomode *) event->data; + ret = fbcon_mode_deleted(info, mode); + break; + case FB_EVENT_FB_REGISTERED: + ret = fbcon_fb_registered(info->node); + break; + case FB_EVENT_SET_CONSOLE_MAP: + con2fb = (struct fb_con2fbmap *) event->data; + ret = set_con2fb_map(con2fb->console - 1, con2fb->framebuffer); + break; + case FB_EVENT_GET_CONSOLE_MAP: + con2fb = (struct fb_con2fbmap *) event->data; + con2fb->framebuffer = con2fb_map[con2fb->console - 1]; + break; + } + + return ret; +} + +/* + * The console `switch' structure for the frame buffer based console + */ + +const struct consw fb_con = { + .owner = THIS_MODULE, + .con_startup = fbcon_startup, + .con_init = fbcon_init, + .con_deinit = fbcon_deinit, + .con_clear = fbcon_clear, + .con_putc = fbcon_putc, + .con_putcs = fbcon_putcs, + .con_cursor = fbcon_cursor, + .con_scroll = fbcon_scroll, + .con_bmove = fbcon_bmove, + .con_switch = fbcon_switch, + .con_blank = fbcon_blank, + .con_font_set = fbcon_set_font, + .con_font_get = fbcon_get_font, + .con_font_default = fbcon_set_def_font, + .con_font_copy = fbcon_copy_font, + .con_set_palette = fbcon_set_palette, + .con_scrolldelta = fbcon_scrolldelta, + .con_set_origin = fbcon_set_origin, + .con_invert_region = fbcon_invert_region, + .con_screen_pos = fbcon_screen_pos, + .con_getxy = fbcon_getxy, + .con_resize = fbcon_resize, +}; + +static struct notifier_block fbcon_event_notifier = { + .notifier_call = fbcon_event_notify, +}; + +int __init fb_console_init(void) +{ + int i; + + acquire_console_sem(); + fb_register_client(&fbcon_event_notifier); + release_console_sem(); + + for (i = 0; i < MAX_NR_CONSOLES; i++) + con2fb_map[i] = -1; + + if (num_registered_fb) { + for (i = 0; i < FB_MAX; i++) { + if (registered_fb[i] != NULL) { + info_idx = i; + break; + } + } + fbcon_takeover(); + } + + return 0; +} + +module_init(fb_console_init); + +#ifdef MODULE + +void __exit fb_console_exit(void) +{ + acquire_console_sem(); + fb_unregister_client(&fbcon_event_notifier); + release_console_sem(); + give_up_console(&fb_con); +} + +module_exit(fb_console_exit); + +#endif + +/* + * Visible symbols for modules + */ + +EXPORT_SYMBOL(fb_display); +EXPORT_SYMBOL(fb_con); + +MODULE_LICENSE("GPL"); diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c @@ -0,0 +1,1449 @@ +/* + * linux/drivers/video/fbmem.c + * + * Copyright (C) 1994 Martin Schaller + * + * 2001 - Documented with DocBook + * - Brad Douglas <brad@neruo.com> + * 2004 - Updated for fbui + * - Zack T Smith <fbui@comcast.net> + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ + +#include <linux/config.h> +#include <linux/module.h> + +#include <linux/types.h> +#include <linux/errno.h> +#include <linux/sched.h> +#include <linux/smp_lock.h> +#include <linux/kernel.h> +#include <linux/major.h> +#include <linux/slab.h> +#include <linux/mm.h> +#include <linux/mman.h> +#include <linux/tty.h> +#include <linux/init.h> +#include <linux/linux_logo.h> +#include <linux/proc_fs.h> +#include <linux/console.h> +#ifdef CONFIG_KMOD +#include <linux/kmod.h> +#endif +#include <linux/devfs_fs_kernel.h> +#include <linux/err.h> +#include <linux/kernel.h> +#include <linux/device.h> + +#if defined(__mc68000__) || defined(CONFIG_APUS) +#include <asm/setup.h> +#endif + +#include <asm/io.h> +#include <asm/uaccess.h> +#include <asm/page.h> +#include <asm/pgtable.h> + +#include <linux/fb.h> + + /* + * Frame buffer device initialization and setup routines + */ + +#define FBPIXMAPSIZE 16384 + +static struct notifier_block *fb_notifier_list; +struct fb_info *registered_fb[FB_MAX]; +int num_registered_fb; + +/* + * Helpers + */ + +int fb_get_color_depth(struct fb_info *info) +{ + struct fb_var_screeninfo *var = &info->var; + + if (var->green.length == var->blue.length && + var->green.length == var->red.length && + !var->green.offset && !var->blue.offset && + !var->red.offset) + return var->green.length; + else + return (var->green.length + var->red.length + + var->blue.length); +} +EXPORT_SYMBOL(fb_get_color_depth); + +/* + * Drawing helpers. + */ +void fb_iomove_buf_aligned(struct fb_info *info, struct fb_pixmap *buf, + u8 *dst, u32 d_pitch, u8 *src, u32 s_pitch, + u32 height) +{ + int i; + + for (i = height; i--; ) { + buf->outbuf(info, dst, src, s_pitch); + src += s_pitch; + dst += d_pitch; + } +} + +void fb_sysmove_buf_aligned(struct fb_info *info, struct fb_pixmap *buf, + u8 *dst, u32 d_pitch, u8 *src, u32 s_pitch, + u32 height) +{ + int i, j; + + for (i = height; i--; ) { + for (j = 0; j < s_pitch; j++) + dst[j] = src[j]; + src += s_pitch; + dst += d_pitch; + } +} + +void fb_iomove_buf_unaligned(struct fb_info *info, struct fb_pixmap *buf, + u8 *dst, u32 d_pitch, u8 *src, u32 idx, + u32 height, u32 shift_high, u32 shift_low, + u32 mod) +{ + u8 mask = (u8) (0xfff << shift_high), tmp; + int i, j; + + for (i = height; i--; ) { + for (j = 0; j < idx; j++) { + tmp = buf->inbuf(info, dst+j); + tmp &= mask; + tmp |= *src >> shift_low; + buf->outbuf(info, dst+j, &tmp, 1); + tmp = *src << shift_high; + buf->outbuf(info, dst+j+1, &tmp, 1); + src++; + } + tmp = buf->inbuf(info, dst+idx); + tmp &= mask; + tmp |= *src >> shift_low; + buf->outbuf(info, dst+idx, &tmp, 1); + if (shift_high < mod) { + tmp = *src << shift_high; + buf->outbuf(info, dst+idx+1, &tmp, 1); + } + src++; + dst += d_pitch; + } +} + +void fb_sysmove_buf_unaligned(struct fb_info *info, struct fb_pixmap *buf, + u8 *dst, u32 d_pitch, u8 *src, u32 idx, + u32 height, u32 shift_high, u32 shift_low, + u32 mod) +{ + u8 mask = (u8) (0xfff << shift_high), tmp; + int i, j; + + for (i = height; i--; ) { + for (j = 0; j < idx; j++) { + tmp = dst[j]; + tmp &= mask; + tmp |= *src >> shift_low; + dst[j] = tmp; + tmp = *src << shift_high; + dst[j+1] = tmp; + src++; + } + tmp = dst[idx]; + tmp &= mask; + tmp |= *src >> shift_low; + dst[idx] = tmp; + if (shift_high < mod) { + tmp = *src << shift_high; + dst[idx+1] = tmp; + } + src++; + dst += d_pitch; + } +} + +/* + * we need to lock this section since fb_cursor + * may use fb_imageblit() + */ +char* fb_get_buffer_offset(struct fb_info *info, struct fb_pixmap *buf, u32 size) +{ + u32 align = buf->buf_align - 1, offset; + char *addr = buf->addr; + + /* If IO mapped, we need to sync before access, no sharing of + * the pixmap is done + */ + if (buf->flags & FB_PIXMAP_IO) { + if (info->fbops->fb_sync && (buf->flags & FB_PIXMAP_SYNC)) + info->fbops->fb_sync(info); + return addr; + } + + /* See if we fit in the remaining pixmap space */ + offset = buf->offset + align; + offset &= ~align; + if (offset + size > buf->size) { + /* We do not fit. In order to be able to re-use the buffer, + * we must ensure no asynchronous DMA'ing or whatever operation + * is in progress, we sync for that. + */ + if (info->fbops->fb_sync && (buf->flags & FB_PIXMAP_SYNC)) + info->fbops->fb_sync(info); + offset = 0; + } + buf->offset = offset + size; + addr += offset; + + return addr; +} + +#ifdef CONFIG_LOGO +#include <linux/linux_logo.h> + +static inline unsigned safe_shift(unsigned d, int n) +{ + return n < 0 ? d >> -n : d << n; +} + +static void fb_set_logocmap(struct fb_info *info, + const struct linux_logo *logo) +{ + struct fb_cmap palette_cmap; + u16 palette_green[16]; + u16 palette_blue[16]; + u16 palette_red[16]; + int i, j, n; + const unsigned char *clut = logo->clut; + + palette_cmap.start = 0; + palette_cmap.len = 16; + palette_cmap.red = palette_red; + palette_cmap.green = palette_green; + palette_cmap.blue = palette_blue; + palette_cmap.transp = NULL; + + for (i = 0; i < logo->clutsize; i += n) { + n = logo->clutsize - i; + /* palette_cmap provides space for only 16 colors at once */ + if (n > 16) + n = 16; + palette_cmap.start = 32 + i; + palette_cmap.len = n; + for (j = 0; j < n; ++j) { + palette_cmap.red[j] = clut[0] << 8 | clut[0]; + palette_cmap.green[j] = clut[1] << 8 | clut[1]; + palette_cmap.blue[j] = clut[2] << 8 | clut[2]; + clut += 3; + } + fb_set_cmap(&palette_cmap, info); + } +} + +static void fb_set_logo_truepalette(struct fb_info *info, + const struct linux_logo *logo, + u32 *palette) +{ + unsigned char mask[9] = { 0,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff }; + unsigned char redmask, greenmask, bluemask; + int redshift, greenshift, blueshift; + int i; + const unsigned char *clut = logo->clut; + + /* + * We have to create a temporary palette since console palette is only + * 16 colors long. + */ + /* Bug: Doesn't obey msb_right ... (who needs that?) */ + redmask = mask[info->var.red.length < 8 ? info->var.red.length : 8]; + greenmask = mask[info->var.green.length < 8 ? info->var.green.length : 8]; + bluemask = mask[info->var.blue.length < 8 ? info->var.blue.length : 8]; + redshift = info->var.red.offset - (8 - info->var.red.length); + greenshift = info->var.green.offset - (8 - info->var.green.length); + blueshift = info->var.blue.offset - (8 - info->var.blue.length); + + for ( i = 0; i < logo->clutsize; i++) { + palette[i+32] = (safe_shift((clut[0] & redmask), redshift) | + safe_shift((clut[1] & greenmask), greenshift) | + safe_shift((clut[2] & bluemask), blueshift)); + clut += 3; + } +} + +static void fb_set_logo_directpalette(struct fb_info *info, + const struct linux_logo *logo, + u32 *palette) +{ + int redshift, greenshift, blueshift; + int i; + + redshift = info->var.red.offset; + greenshift = info->var.green.offset; + blueshift = info->var.blue.offset; + + for (i = 32; i < logo->clutsize; i++) + palette[i] = i << redshift | i << greenshift | i << blueshift; +} + +static void fb_set_logo(struct fb_info *info, + const struct linux_logo *logo, u8 *dst, + int depth) +{ + int i, j, k, fg = 1; + const u8 *src = logo->data; + u8 d, xor = (info->fix.visual == FB_VISUAL_MONO01) ? 0xff : 0; + + if (fb_get_color_depth(info) == 3) + fg = 7; + + switch (depth) { + case 4: + for (i = 0; i < logo->height; i++) + for (j = 0; j < logo->width; src++) { + *dst++ = *src >> 4; + j++; + if (j < logo->width) { + *dst++ = *src & 0x0f; + j++; + } + } + break; + case 1: + for (i = 0; i < logo->height; i++) { + for (j = 0; j < logo->width; src++) { + d = *src ^ xor; + for (k = 7; k >= 0; k--) { + *dst++ = ((d >> k) & 1) ? fg : 0; + j++; + } + } + } + break; + } +} + +/* + * Three (3) kinds of logo maps exist. linux_logo_clut224 (>16 colors), + * linux_logo_vga16 (16 colors) and linux_logo_mono (2 colors). Depending on + * the visual format and color depth of the framebuffer, the DAC, the + * pseudo_palette, and the logo data will be adjusted accordingly. + * + * Case 1 - linux_logo_clut224: + * Color exceeds the number of console colors (16), thus we set the hardware DAC + * using fb_set_cmap() appropriately. The "needs_cmapreset" flag will be set. + * + * For visuals that require color info from the pseudo_palette, we also construct + * one for temporary use. The "needs_directpalette" or "needs_truepalette" flags + * will be set. + * + * Case 2 - linux_logo_vga16: + * The number of colors just matches the console colors, thus there is no need + * to set the DAC or the pseudo_palette. However, the bitmap is packed, ie, + * each byte contains color information for two pixels (upper and lower nibble). + * To be consistent with fb_imageblit() usage, we therefore separate the two + * nibbles into separate bytes. The "depth" flag will be set to 4. + * + * Case 3 - linux_logo_mono: + * This is similar with Case 2. Each byte contains information for 8 pixels. + * We isolate each bit and expand each into a byte. The "depth" flag will + * be set to 1. + */ +static struct logo_data { + int depth; + int needs_directpalette; + int needs_truepalette; + int needs_cmapreset; + const struct linux_logo *logo; +} fb_logo; + +int fb_prepare_logo(struct fb_info *info) +{ + int depth = fb_get_color_depth(info); + + memset(&fb_logo, 0, sizeof(struct logo_data)); + + if (info->fix.visual == FB_VISUAL_DIRECTCOLOR) { + depth = info->var.blue.length; + if (info->var.red.length < depth) + depth = info->var.red.length; + if (info->var.green.length < depth) + depth = info->var.green.length; + } + + if (depth >= 8) { + switch (info->fix.visual) { + case FB_VISUAL_TRUECOLOR: + fb_logo.needs_truepalette = 1; + break; + case FB_VISUAL_DIRECTCOLOR: + fb_logo.needs_directpalette = 1; + fb_logo.needs_cmapreset = 1; + break; + case FB_VISUAL_PSEUDOCOLOR: + fb_logo.needs_cmapreset = 1; + break; + } + } + + /* Return if no suitable logo was found */ + fb_logo.logo = fb_find_logo(depth); + + if (!fb_logo.logo || fb_logo.logo->height > info->var.yres) { + fb_logo.logo = NULL; + return 0; + } + /* What depth we asked for might be different from what we get */ + if (fb_logo.logo->type == LINUX_LOGO_CLUT224) + fb_logo.depth = 8; + else if (fb_logo.logo->type == LINUX_LOGO_VGA16) + fb_logo.depth = 4; + else + fb_logo.depth = 1; + return fb_logo.logo->height; +} + +int fb_show_logo(struct fb_info *info) +{ + u32 *palette = NULL, *saved_pseudo_palette = NULL; + unsigned char *logo_new = NULL; + struct fb_image image; + int x; + + /* Return if the frame buffer is not mapped or suspended */ + if (fb_logo.logo == NULL || info->state != FBINFO_STATE_RUNNING) + return 0; + + image.depth = 8; + image.data = fb_logo.logo->data; + + if (fb_logo.needs_cmapreset) + fb_set_logocmap(info, fb_logo.logo); + + if (fb_logo.needs_truepalette || + fb_logo.needs_directpalette) { + palette = kmalloc(256 * 4, GFP_KERNEL); + if (palette == NULL) + return 0; + + if (fb_logo.needs_truepalette) + fb_set_logo_truepalette(info, fb_logo.logo, palette); + else + fb_set_logo_directpalette(info, fb_logo.logo, palette); + + saved_pseudo_palette = info->pseudo_palette; + info->pseudo_palette = palette; + } + + if (fb_logo.depth <= 4) { + logo_new = kmalloc(fb_logo.logo->width * fb_logo.logo->height, + GFP_KERNEL); + if (logo_new == NULL) { + if (palette) + kfree(palette); + if (saved_pseudo_palette) + info->pseudo_palette = saved_pseudo_palette; + return 0; + } + image.data = logo_new; + fb_set_logo(info, fb_logo.logo, logo_new, fb_logo.depth); + } + + image.width = fb_logo.logo->width; + image.height = fb_logo.logo->height; + image.dy = 0; + + for (x = 0; x < num_online_cpus() * (fb_logo.logo->width + 8) && + x <= info->var.xres-fb_logo.logo->width; x += (fb_logo.logo->width + 8)) { + image.dx = x; + info->fbops->fb_imageblit(info, &image); + } + + if (palette != NULL) + kfree(palette); + if (saved_pseudo_palette != NULL) + info->pseudo_palette = saved_pseudo_palette; + if (logo_new != NULL) + kfree(logo_new); + return fb_logo.logo->height; +} +#else +int fb_prepare_logo(struct fb_info *info) { return 0; } +int fb_show_logo(struct fb_info *info) { return 0; } +#endif /* CONFIG_LOGO */ + +static int fbmem_read_proc(char *buf, char **start, off_t offset, + int len, int *eof, void *private) +{ + struct fb_info **fi; + int clen; + + clen = 0; + for (fi = registered_fb; fi < ®istered_fb[FB_MAX] && len < 4000; fi++) + if (*fi) + clen += sprintf(buf + clen, "%d %s\n", + (*fi)->node, + (*fi)->fix.id); + *start = buf + offset; + if (clen > offset) + clen -= offset; + else + clen = 0; + return clen < len ? clen : len; +} + +static ssize_t +fb_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) +{ + unsigned long p = *ppos; + struct inode *inode = file->f_dentry->d_inode; + int fbidx = iminor(inode); + struct fb_info *info = registered_fb[fbidx]; + u32 *buffer, *dst, *src; + int c, i, cnt = 0, err = 0; + unsigned long total_size; + + if (!info || ! info->screen_base) + return -ENODEV; + + if (info->state != FBINFO_STATE_RUNNING) + return -EPERM; + + if (info->fbops->fb_read) + return info->fbops->fb_read(file, buf, count, ppos); + + total_size = info->screen_size; + if (total_size == 0) + total_size = info->fix.smem_len; + + if (p >= total_size) + return 0; + if (count >= total_size) + count = total_size; + if (count + p > total_size) + count = total_size - p; + + cnt = 0; + buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count, + GFP_KERNEL); + if (!buffer) + return -ENOMEM; + + src = (u32 *) (info->screen_base + p); + + if (info->fbops->fb_sync) + info->fbops->fb_sync(info); + + while (count) { + c = (count > PAGE_SIZE) ? PAGE_SIZE : count; + dst = buffer; + for (i = c >> 2; i--; ) + *dst++ = fb_readl(src++); + if (c & 3) { + u8 *dst8 = (u8 *) dst; + u8 *src8 = (u8 *) src; + + for (i = c & 3; i--;) + *dst8++ = fb_readb(src8++); + + src = (u32 *) src8; + } + + if (copy_to_user(buf, buffer, c)) { + err = -EFAULT; + break; + } + *ppos += c; + buf += c; + cnt += c; + count -= c; + } + + kfree(buffer); + return (err) ? err : cnt; +} + +static ssize_t +fb_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) +{ + unsigned long p = *ppos; + struct inode *inode = file->f_dentry->d_inode; + int fbidx = iminor(inode); + struct fb_info *info = registered_fb[fbidx]; + u32 *buffer, *dst, *src; + int c, i, cnt = 0, err; + unsigned long total_size; + + if (!info || !info->screen_base) + return -ENODEV; + + if (info->state != FBINFO_STATE_RUNNING) + return -EPERM; + + if (info->fbops->fb_write) + return info->fbops->fb_write(file, buf, count, ppos); + + total_size = info->screen_size; + if (total_size == 0) + total_size = info->fix.smem_len; + + if (p > total_size) + return -ENOSPC; + if (count >= total_size) + count = total_size; + err = 0; + if (count + p > total_size) { + count = total_size - p; + err = -ENOSPC; + } + cnt = 0; + buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count, + GFP_KERNEL); + if (!buffer) + return -ENOMEM; + + dst = (u32 *) (info->screen_base + p); + + if (info->fbops->fb_sync) + info->fbops->fb_sync(info); + + while (count) { + c = (count > PAGE_SIZE) ? PAGE_SIZE : count; + src = buffer; + if (copy_from_user(src, buf, c)) { + err = -EFAULT; + break; + } + for (i = c >> 2; i--; ) + fb_writel(*src++, dst++); + if (c & 3) { + u8 *src8 = (u8 *) src; + u8 *dst8 = (u8 *) dst; + + for (i = c & 3; i--; ) + fb_writeb(*src8++, dst8++); + + dst = (u32 *) dst8; + } + *ppos += c; + buf += c; + cnt += c; + count -= c; + } + kfree(buffer); + + return (err) ? err : cnt; +} + +#ifdef CONFIG_KMOD +static void try_to_load(int fb) +{ + request_module("fb%d", fb); +} +#endif /* CONFIG_KMOD */ + +void +fb_load_cursor_image(struct fb_info *info) +{ + unsigned int width = (info->cursor.image.width + 7) >> 3; + u8 *data = (u8 *) info->cursor.image.data; + + if (info->sprite.outbuf) + info->sprite.outbuf(info, info->sprite.addr, data, width); + else + memcpy(info->sprite.addr, data, width); +} + +int +fb_cursor(struct fb_info *info, struct fb_cursor_user __user *sprite) +{ + struct fb_cursor_user cursor_user; + struct fb_cursor cursor; + char *data = NULL, *mask = NULL, *info_mask = NULL; + u16 *red = NULL, *green = NULL, *blue = NULL, *transp = NULL; + int err = -EINVAL; + + if (copy_from_user(&cursor_user, sprite, sizeof(struct fb_cursor_user))) + return -EFAULT; + + memcpy(&cursor, &cursor_user, sizeof(cursor_user)); + cursor.mask = info->cursor.mask; + cursor.image.data = info->cursor.image.data; + cursor.image.cmap.red = info->cursor.image.cmap.red; + cursor.image.cmap.green = info->cursor.image.cmap.green; + cursor.image.cmap.blue = info->cursor.image.cmap.blue; + cursor.image.cmap.transp = info->cursor.image.cmap.transp; + cursor.data = NULL; + + if (cursor.set & FB_CUR_SETCUR) + info->cursor.enable = 1; + + if (cursor.set & FB_CUR_SETCMAP) { + unsigned len = cursor.image.cmap.len; + if ((int)len <= 0) + goto out; + len *= 2; + err = -ENOMEM; + red = kmalloc(len, GFP_USER); + green = kmalloc(len, GFP_USER); + blue = kmalloc(len, GFP_USER); + if (!red || !green || !blue) + goto out; + if (cursor_user.image.cmap.transp) { + transp = kmalloc(len, GFP_USER); + if (!transp) + goto out; + } + err = -EFAULT; + if (copy_from_user(red, cursor_user.image.cmap.red, len)) + goto out; + if (copy_from_user(green, cursor_user.image.cmap.green, len)) + goto out; + if (copy_from_user(blue, cursor_user.image.cmap.blue, len)) + goto out; + if (transp) { + if (copy_from_user(transp, + cursor_user.image.cmap.transp, len)) + goto out; + } + cursor.image.cmap.red = red; + cursor.image.cmap.green = green; + cursor.image.cmap.blue = blue; + cursor.image.cmap.transp = transp; + } + + if (cursor.set & FB_CUR_SETSHAPE) { + int size = ((cursor.image.width + 7) >> 3) * cursor.image.height; + + if ((cursor.image.height != info->cursor.image.height) || + (cursor.image.width != info->cursor.image.width)) + cursor.set |= FB_CUR_SETSIZE; + + err = -ENOMEM; + data = kmalloc(size, GFP_USER); + mask = kmalloc(size, GFP_USER); + if (!mask || !data) + goto out; + + err = -EFAULT; + if (copy_from_user(data, cursor_user.image.data, size) || + copy_from_user(mask, cursor_user.mask, size)) + goto out; + + cursor.image.data = data; + cursor.mask = mask; + info_mask = (char *) info->cursor.mask; + info->cursor.mask = mask; + } + info->cursor.set = cursor.set; + info->cursor.rop = cursor.rop; + err = info->fbops->fb_cursor(info, &cursor); +out: + kfree(data); + kfree(mask); + kfree(red); + kfree(green); + kfree(blue); + kfree(transp); + if (info_mask) + info->cursor.mask = info_mask; + return err; +} + +int +fb_pan_display(struct fb_info *info, struct fb_var_screeninfo *var) +{ + int xoffset = var->xoffset; + int yoffset = var->yoffset; + int err; + + if (xoffset < 0 || yoffset < 0 || !info->fbops->fb_pan_display || + xoffset + info->var.xres > info->var.xres_virtual || + yoffset + info->var.yres > info->var.yres_virtual) + return -EINVAL; + if ((err = info->fbops->fb_pan_display(var, info))) + return err; + info->var.xoffset = var->xoffset; + info->var.yoffset = var->yoffset; + if (var->vmode & FB_VMODE_YWRAP) + info->var.vmode |= FB_VMODE_YWRAP; + else + info->var.vmode &= ~FB_VMODE_YWRAP; + return 0; +} + +int +fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var) +{ + int err; + + if (var->activate & FB_ACTIVATE_INV_MODE) { + struct fb_videomode mode1, mode2; + int ret = 0; + + fb_var_to_videomode(&mode1, var); + fb_var_to_videomode(&mode2, &info->var); + /* make sure we don't delete the videomode of current var */ + ret = fb_mode_is_equal(&mode1, &mode2); + + if (!ret) { + struct fb_event event; + + event.info = info; + event.data = &mode1; + ret = notifier_call_chain(&fb_notifier_list, + FB_EVENT_MODE_DELETE, &event); + } + + if (!ret) + fb_delete_videomode(&mode1, &info->modelist); + + return ret; + } + + if ((var->activate & FB_ACTIVATE_FORCE) || + memcmp(&info->var, var, sizeof(struct fb_var_screeninfo))) { + if (!info->fbops->fb_check_var) { + *var = info->var; + return 0; + } + + if ((err = info->fbops->fb_check_var(var, info))) + return err; + + if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) { + struct fb_videomode mode; + info->var = *var; + + if (info->fbops->fb_set_par) + info->fbops->fb_set_par(info); + + fb_pan_display(info, &info->var); + + fb_set_cmap(&info->cmap, info); + + fb_var_to_videomode(&mode, &info->var); + fb_add_videomode(&mode, &info->modelist); + + if (info->flags & FBINFO_MISC_MODECHANGEUSER) { + struct fb_event event; + + info->flags &= ~FBINFO_MISC_MODECHANGEUSER; + event.info = info; + notifier_call_chain(&fb_notifier_list, + FB_EVENT_MODE_CHANGE, &event); + } + } + } + return 0; +} + +int +fb_blank(struct fb_info *info, int blank) +{ + /* ??? Variable sized stack allocation. */ + u16 black[info->cmap.len]; + struct fb_cmap cmap; + + if (info->fbops->fb_blank && !info->fbops->fb_blank(blank, info)) + return 0; + if (blank) { + memset(black, 0, info->cmap.len * sizeof(u16)); + cmap.red = cmap.green = cmap.blue = black; + cmap.transp = info->cmap.transp ? black : NULL; + cmap.start = info->cmap.start; + cmap.len = info->cmap.len; + } else + cmap = info->cmap; + return fb_set_cmap(&cmap, info); +} + +static int +fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg) +{ + int fbidx = iminor(inode); + struct fb_info *info = registered_fb[fbidx]; + struct fb_ops *fb = info->fbops; + struct fb_var_screeninfo var; + struct fb_fix_screeninfo fix; + struct fb_con2fbmap con2fb; + struct fb_cmap_user cmap; + struct fb_event event; + void __user *argp = (void __user *)arg; + int i; + + if (!fb) + return -ENODEV; + switch (cmd) { + case FBIOGET_VSCREENINFO: + return copy_to_user(argp, &info->var, + sizeof(var)) ? -EFAULT : 0; + case FBIOPUT_VSCREENINFO: + if (copy_from_user(&var, argp, sizeof(var))) + return -EFAULT; + acquire_console_sem(); + info->flags |= FBINFO_MISC_MODECHANGEUSER; + i = fb_set_var(info, &var); + info->flags &= ~FBINFO_MISC_MODECHANGEUSER; + release_console_sem(); + if (i) return i; + if (copy_to_user(argp, &var, sizeof(var))) + return -EFAULT; + return 0; + case FBIOGET_FSCREENINFO: + return copy_to_user(argp, &info->fix, + sizeof(fix)) ? -EFAULT : 0; + case FBIOPUTCMAP: + if (copy_from_user(&cmap, argp, sizeof(cmap))) + return -EFAULT; + return (fb_set_user_cmap(&cmap, info)); + case FBIOGETCMAP: + if (copy_from_user(&cmap, argp, sizeof(cmap))) + return -EFAULT; + return fb_cmap_to_user(&info->cmap, &cmap); + case FBIOPAN_DISPLAY: + if (copy_from_user(&var, argp, sizeof(var))) + return -EFAULT; + acquire_console_sem(); + i = fb_pan_display(info, &var); + release_console_sem(); + if (i) + return i; + if (copy_to_user(argp, &var, sizeof(var))) + return -EFAULT; + return 0; + case FBIO_CURSOR: + acquire_console_sem(); + i = fb_cursor(info, argp); + release_console_sem(); + return i; + case FBIOGET_CON2FBMAP: + if (copy_from_user(&con2fb, argp, sizeof(con2fb))) + return -EFAULT; + if (con2fb.console < 1 || con2fb.console > MAX_NR_CONSOLES) + return -EINVAL; + con2fb.framebuffer = -1; + event.info = info; + event.data = &con2fb; + notifier_call_chain(&fb_notifier_list, + FB_EVENT_GET_CONSOLE_MAP, &event); + return copy_to_user(argp, &con2fb, + sizeof(con2fb)) ? -EFAULT : 0; + case FBIOPUT_CON2FBMAP: + if (copy_from_user(&con2fb, argp, sizeof(con2fb))) + return - EFAULT; + if (con2fb.console < 0 || con2fb.console > MAX_NR_CONSOLES) + return -EINVAL; + if (con2fb.framebuffer < 0 || con2fb.framebuffer >= FB_MAX) + return -EINVAL; +#ifdef CONFIG_KMOD + if (!registered_fb[con2fb.framebuffer]) + try_to_load(con2fb.framebuffer); +#endif /* CONFIG_KMOD */ + if (!registered_fb[con2fb.framebuffer]) + return -EINVAL; + if (con2fb.console > 0 && con2fb.console < MAX_NR_CONSOLES) { + event.info = info; + event.data = &con2fb; + return notifier_call_chain(&fb_notifier_list, + FB_EVENT_SET_CONSOLE_MAP, + &event); + } + return -EINVAL; + case FBIOBLANK: + acquire_console_sem(); + i = fb_blank(info, arg); + release_console_sem(); + return i; + +#ifdef CONFIG_FB_UI + case FBIO_UI_OPEN: { + if (access_ok (VERIFY_READ, (char*) arg, sizeof(struct fbui_openparams))) + return fbui_open (info, (struct fbui_openparams*) arg); + else + return -EFAULT; + } + + case FBIO_UI_CLOSE: + return fbui_close (info, arg); + + case FBIO_UI_EXEC: { + short win_id=-1; + short nwords=0; + short *ptr=(short*) arg; + if (access_ok (VERIFY_READ, (char*) arg, 4)) { + if (get_user (win_id, ptr)) + return -EFAULT; + if (win_id < 0 || win_id >= FBUI_MAXWINDOWSPERVC*FBUI_MAXCONSOLES) + return FBUI_ERR_BADWIN; + ptr++; + if (get_user (nwords, ptr)) + return -EFAULT; + arg += 4; + if (access_ok (VERIFY_READ, (char*) (arg), 2*nwords)) + return fbui_exec (info, win_id, nwords, + (unsigned char*) (arg)); + else + return -EFAULT; + } + else + return -EFAULT; + } + + case FBIO_UI_CONTROL: + if (access_ok (VERIFY_READ, (char*) arg, sizeof(struct fbui_ctrlparams))) + { + struct fbui_ctrlparams ctl; + if (!copy_from_user (&ctl, (void*)arg, sizeof(struct fbui_ctrlparams))){ + return fbui_control (info, &ctl); + } else { + return -EFAULT; + } + } else { + return -EFAULT; +} +#endif + + default: + if (fb->fb_ioctl == NULL) + return -EINVAL; + return fb->fb_ioctl(inode, file, cmd, arg, info); + } +} + +static int +fb_mmap(struct file *file, struct vm_area_struct * vma) +{ + int fbidx = iminor(file->f_dentry->d_inode); + struct fb_info *info = registered_fb[fbidx]; + struct fb_ops *fb = info->fbops; + unsigned long off; +#if !defined(__sparc__) || defined(__sparc_v9__) + unsigned long start; + u32 len; +#endif + + if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) + return -EINVAL; + off = vma->vm_pgoff << PAGE_SHIFT; + if (!fb) + return -ENODEV; + if (fb->fb_mmap) { + int res; + lock_kernel(); + res = fb->fb_mmap(info, file, vma); + unlock_kernel(); + return res; + } + +#if defined(__sparc__) && !defined(__sparc_v9__) + /* Should never get here, all fb drivers should have their own + mmap routines */ + return -EINVAL; +#else + /* !sparc32... */ + lock_kernel(); + + /* frame buffer memory */ + start = info->fix.smem_start; + len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.smem_len); + if (off >= len) { + /* memory mapped io */ + off -= len; + if (info->var.accel_flags) { + unlock_kernel(); + return -EINVAL; + } + start = info->fix.mmio_start; + len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.mmio_len); + } + unlock_kernel(); + start &= PAGE_MASK; + if ((vma->vm_end - vma->vm_start + off) > len) + return -EINVAL; + off += start; + vma->vm_pgoff = off >> PAGE_SHIFT; + /* This is an IO map - tell maydump to skip this VMA */ + vma->vm_flags |= VM_IO; +#if defined(__sparc_v9__) + vma->vm_flags |= (VM_SHM | VM_LOCKED); + if (io_remap_page_range(vma, vma->vm_start, off, + vma->vm_end - vma->vm_start, vma->vm_page_prot, 0)) + return -EAGAIN; +#else +#if defined(__mc68000__) +#if defined(CONFIG_SUN3) + pgprot_val(vma->vm_page_prot) |= SUN3_PAGE_NOCACHE; +#elif defined(CONFIG_MMU) + if (CPU_IS_020_OR_030) + pgprot_val(vma->vm_page_prot) |= _PAGE_NOCACHE030; + if (CPU_IS_040_OR_060) { + pgprot_val(vma->vm_page_prot) &= _CACHEMASK040; + /* Use no-cache mode, serialized */ + pgprot_val(vma->vm_page_prot) |= _PAGE_NOCACHE_S; + } +#endif +#elif defined(__powerpc__) + pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE|_PAGE_GUARDED; +#elif defined(__alpha__) + /* Caching is off in the I/O space quadrant by design. */ +#elif defined(__i386__) || defined(__x86_64__) + if (boot_cpu_data.x86 > 3) + pgprot_val(vma->vm_page_prot) |= _PAGE_PCD; +#elif defined(__mips__) + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); +#elif defined(__hppa__) + pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE; +#elif defined(__ia64__) || defined(__arm__) || defined(__sh__) + vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); +#else +#warning What do we have to do here?? +#endif + if (io_remap_page_range(vma, vma->vm_start, off, + vma->vm_end - vma->vm_start, vma->vm_page_prot)) + return -EAGAIN; +#endif /* !__sparc_v9__ */ + return 0; +#endif /* !sparc32 */ +} + +static int +fb_open(struct inode *inode, struct file *file) +{ + int fbidx = iminor(inode); + struct fb_info *info; + int res = 0; + + if (fbidx >= FB_MAX) + return -ENODEV; +#ifdef CONFIG_KMOD + if (!(info = registered_fb[fbidx])) + try_to_load(fbidx); +#endif /* CONFIG_KMOD */ + if (!(info = registered_fb[fbidx])) + return -ENODEV; + if (!try_module_get(info->fbops->owner)) + return -ENODEV; + if (info->fbops->fb_open) { + res = info->fbops->fb_open(info,1); + if (res) + module_put(info->fbops->owner); + } + return res; +} + +static int +fb_release(struct inode *inode, struct file *file) +{ + int fbidx = iminor(inode); + struct fb_info *info; + + lock_kernel(); + info = registered_fb[fbidx]; + if (info->fbops->fb_release) + info->fbops->fb_release(info,1); + module_put(info->fbops->owner); + unlock_kernel(); + return 0; +} + +static struct file_operations fb_fops = { + .owner = THIS_MODULE, + .read = fb_read, + .write = fb_write, + .ioctl = fb_ioctl, + .mmap = fb_mmap, + .open = fb_open, + .release = fb_release, +#ifdef HAVE_ARCH_FB_UNMAPPED_AREA + .get_unmapped_area = get_fb_unmapped_area, +#endif +}; + +static struct class_simple *fb_class; + +/** + * register_framebuffer - registers a frame buffer device + * @fb_info: frame buffer info structure + * + * Registers a frame buffer device @fb_info. + * + * Returns negative errno on error, or zero for success. + * + */ + +int +register_framebuffer(struct fb_info *fb_info) +{ + int i; + struct class_device *c; + struct fb_event event; + + if (num_registered_fb == FB_MAX) + return -ENXIO; + num_registered_fb++; + for (i = 0 ; i < FB_MAX; i++) + if (!registered_fb[i]) + break; + fb_info->node = i; + + c = class_simple_device_add(fb_class, MKDEV(FB_MAJOR, i), NULL, "fb%d", i); + if (IS_ERR(c)) { + /* Not fatal */ + printk(KERN_WARNING "Unable to create class_device for framebuffer %d; errno = %ld\n", i, PTR_ERR(c)); + } + + if (fb_info->pixmap.addr == NULL) { + fb_info->pixmap.addr = kmalloc(FBPIXMAPSIZE, GFP_KERNEL); + if (fb_info->pixmap.addr) { + fb_info->pixmap.size = FBPIXMAPSIZE; + fb_info->pixmap.buf_align = 1; + fb_info->pixmap.scan_align = 1; + fb_info->pixmap.access_align = 4; + fb_info->pixmap.flags = FB_PIXMAP_DEFAULT; + } + } + fb_info->pixmap.offset = 0; + + if (fb_info->sprite.addr == NULL) { + fb_info->sprite.addr = kmalloc(FBPIXMAPSIZE, GFP_KERNEL); + if (fb_info->sprite.addr) { + fb_info->sprite.size = FBPIXMAPSIZE; + fb_info->sprite.buf_align = 1; + fb_info->sprite.scan_align = 1; + fb_info->sprite.access_align = 4; + fb_info->sprite.flags = FB_PIXMAP_DEFAULT; + } + } + fb_info->sprite.offset = 0; + + if (!fb_info->modelist.prev || + !fb_info->modelist.next || + list_empty(&fb_info->modelist)) { + struct fb_videomode mode; + + INIT_LIST_HEAD(&fb_info->modelist); + fb_var_to_videomode(&mode, &fb_info->var); + fb_add_videomode(&mode, &fb_info->modelist); + } + + registered_fb[i] = fb_info; + + devfs_mk_cdev(MKDEV(FB_MAJOR, i), + S_IFCHR | S_IRUGO | S_IWUGO, "fb/%d", i); + event.info = fb_info; + notifier_call_chain(&fb_notifier_list, + FB_EVENT_FB_REGISTERED, &event); + return 0; +} + + +/** + * unregister_framebuffer - releases a frame buffer device + * @fb_info: frame buffer info structure + * + * Unregisters a frame buffer device @fb_info. + * + * Returns negative errno on error, or zero for success. + * + */ + +int +unregister_framebuffer(struct fb_info *fb_info) +{ + int i; + + i = fb_info->node; + if (!registered_fb[i]) + return -EINVAL; + devfs_remove("fb/%d", i); + + if (fb_info->pixmap.addr && (fb_info->pixmap.flags & FB_PIXMAP_DEFAULT)) + kfree(fb_info->pixmap.addr); + if (fb_info->sprite.addr && (fb_info->sprite.flags & FB_PIXMAP_DEFAULT)) + kfree(fb_info->sprite.addr); + fb_destroy_modelist(&fb_info->modelist); + registered_fb[i]=NULL; + num_registered_fb--; + class_simple_device_remove(MKDEV(FB_MAJOR, i)); + return 0; +} + +/** + * fb_register_client - register a client notifier + * @nb: notifier block to callback on events + */ +int fb_register_client(struct notifier_block *nb) +{ + return notifier_chain_register(&fb_notifier_list, nb); +} + +/** + * fb_unregister_client - unregister a client notifier + * @nb: notifier block to callback on events + */ +int fb_unregister_client(struct notifier_block *nb) +{ + return notifier_chain_unregister(&fb_notifier_list, nb); +} + +/** + * fb_set_suspend - low level driver signals suspend + * @info: framebuffer affected + * @state: 0 = resuming, !=0 = suspending + * + * This is meant to be used by low level drivers to + * signal suspend/resume to the core & clients. + * It must be called with the console semaphore held + */ +void fb_set_suspend(struct fb_info *info, int state) +{ + struct fb_event event; + + event.info = info; + if (state) { + notifier_call_chain(&fb_notifier_list, FB_EVENT_SUSPEND, &event); + info->state = FBINFO_STATE_SUSPENDED; + } else { + info->state = FBINFO_STATE_RUNNING; + notifier_call_chain(&fb_notifier_list, FB_EVENT_RESUME, &event); + } +} + +/** + * fbmem_init - init frame buffer subsystem + * + * Initialize the frame buffer subsystem. + * + * NOTE: This function is _only_ to be called by drivers/char/mem.c. + * + */ + +int __init +fbmem_init(void) +{ + create_proc_read_entry("fb", 0, NULL, fbmem_read_proc, NULL); + + devfs_mk_dir("fb"); + if (register_chrdev(FB_MAJOR,"fb",&fb_fops)) + printk("unable to get major %d for fb devs\n", FB_MAJOR); + + fb_class = class_simple_create(THIS_MODULE, "graphics"); + if (IS_ERR(fb_class)) { + printk(KERN_WARNING "Unable to create fb class; errno = %ld\n", PTR_ERR(fb_class)); + fb_class = NULL; + } + return 0; +} +module_init(fbmem_init); + +#define NR_FB_DRIVERS 64 +static char *video_options[NR_FB_DRIVERS]; +static int ofonly; + +/** + * fb_get_options - get kernel boot parameters + * @name - framebuffer name as it would appear in + * the boot parameter line + * (video=<name>:<options>) + * + * NOTE: Needed to maintain backwards compatibility + */ +int fb_get_options(char *name, char **option) +{ + char *opt, *options = NULL; + int opt_len, retval = 0; + int name_len = strlen(name), i; + + if (name_len && ofonly && strncmp(name, "offb", 4)) + retval = 1; + + if (name_len && !retval) { + for (i = 0; i < NR_FB_DRIVERS; i++) { + if (video_options[i] == NULL) + continue; + opt_len = strlen(video_options[i]); + if (!opt_len) + continue; + opt = video_options[i]; + if (!strncmp(name, opt, name_len) && + opt[name_len] == ':') + options = opt + name_len + 1; + } + } + if (options && !strncmp(options, "off", 3)) + retval = 1; + + if (option) + *option = options; + + return retval; +} + +/** + * video_setup - process command line options + * @options: string of options + * + * Process command line options for frame buffer subsystem. + * + * NOTE: This function is a __setup and __init function. + * It only stores the options. Drivers have to call + * fb_get_options() as necessary. + * + * Returns zero. + * + */ + +int __init video_setup(char *options) +{ + int i; + + if (!options || !*options) + return 0; + + for (i = 0; i < NR_FB_DRIVERS; i++) { + if (!strncmp(options, "ofonly", 6)) + ofonly = 1; + if (video_options[i] == NULL) { + video_options[i] = options; + break; + } + } + + return 0; +} +__setup("video=", video_setup); + + /* + * Visible symbols for modules + */ + +EXPORT_SYMBOL(register_framebuffer); +EXPORT_SYMBOL(unregister_framebuffer); +EXPORT_SYMBOL(num_registered_fb); +EXPORT_SYMBOL(registered_fb); +EXPORT_SYMBOL(fb_prepare_logo); +EXPORT_SYMBOL(fb_show_logo); +EXPORT_SYMBOL(fb_set_var); +EXPORT_SYMBOL(fb_blank); +EXPORT_SYMBOL(fb_pan_display); +EXPORT_SYMBOL(fb_get_buffer_offset); +EXPORT_SYMBOL(fb_iomove_buf_unaligned); +EXPORT_SYMBOL(fb_iomove_buf_aligned); +EXPORT_SYMBOL(fb_sysmove_buf_unaligned); +EXPORT_SYMBOL(fb_sysmove_buf_aligned); +EXPORT_SYMBOL(fb_load_cursor_image); +EXPORT_SYMBOL(fb_set_suspend); +EXPORT_SYMBOL(fb_register_client); +EXPORT_SYMBOL(fb_unregister_client); +EXPORT_SYMBOL(fb_get_options); + +MODULE_LICENSE("GPL"); diff --git a/drivers/video/fbui.c b/drivers/video/fbui.c @@ -0,0 +1,4379 @@ + +/*========================================================================= + * + * Module name: fbui + * Module purpose: Provides in-kernel drawing routines to userland, + * supporting 8/16/24/32 bit packed pixels. + * Module originator: Zachary T Smith (fbui@comcast.net) + * + *========================================================================= + * + * FBUI, an in-kernel graphical user interface for applications + * Copyright (C) 2003-2005 Zachary T Smith, fbui@comcast.net + * + * This module is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This module 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this module; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * (See the file COPYING in the main directory of this archive for + * more details.) + * + *========================================================================= + * + * Changes: + * + * Sep 12, 2004, fbui@comcast.net: added fbui_copy_area + * Sep 13, 2004, fbui@comcast.net: added fbui_draw_string + * Sep 13, 2004, fbui@comcast.net: added sharing of fbui between processes + * Sep 14, 2004, fbui@comcast.net: added fbui_switch + * Sep 16, 2004, fbui@comcast.net: added fbui_open/close + * Sep 16, 2004, fbui@comcast.net: use of KD_GRAPHICS + * Sep 16, 2004, fbui@comcast.net: return to KD_TEXT after all closed + * Sep 18, 2004, fbui@comcast.net: added event types + * Sep 20, 2004, fbui@comcast.net: added window-data semaphore + * Sep 21, 2004, fbui@comcast.net: added keyboard focus concept + * Sep 22, 2004, fbui@comcast.net: keyboard reading via tty->read_buf + * Sep 22, 2004, fbui@comcast.net: keyboard mode set to XLATE + * Sep 22, 2004, fbui@comcast.net: simple keyboard behavior achieved + * Sep 23, 2004, fbui@comcast.net: added implicit keyfocus when only 1 win + * Sep 24, 2004, fbui@comcast.net: fbui_open() now accepts target console# + * Sep 25, 2004, fbui@comcast.net: added read_point + * Sep 25, 2004, fbui@comcast.net: expanded role of window manager + * Sep 25, 2004, fbui@comcast.net: added fbui_put_rgb3 + * Sep 25, 2004, fbui@comcast.net: coordinates now truly window-relative + * Sep 26, 2004, fbui@comcast.net: added per-console winlists + * Sep 27, 2004, fbui@comcast.net: keyfocus_stack + * Sep 28, 2004, fbui@comcast.net: control ioctl + * Sep 29, 2004, fbui@comcast.net: window semaphore; window resize, move + * Oct 01, 2004, fbui@comcast.net: all drawing commands now atomic + * Oct 01, 2004, fbui@comcast.net: fixed put_rgb bug + * Oct 02, 2004, fbui@comcast.net: added fbui_window_info() + * Oct 04, 2004, fbui@comcast.net: structural changes + * Oct 05, 2004, fbui@comcast.net: keyboard focus working + * Oct 05, 2004, fbui@comcast.net: added fbui_winptrs_change() + * Oct 05, 2004, fbui@comcast.net: added keyboard accelerators + * Oct 06, 2004, fbui@comcast.net: moved code to pixel_from_rgb + * Oct 06, 2004, fbui@comcast.net: removed read_point (mmap replaces it) + * Oct 06, 2004, fbui@comcast.net: created fb_hline + * Oct 06, 2004, fbui@comcast.net: fb_clear now supports info->bgcolor + * Oct 10, 2004, fbui@comcast.net: added support for retrieving mouse info + * Oct 12, 2004, fbui@comcast.net: resolved bug to do with multiple down's + * Oct 12, 2004, fbui@comcast.net: switched to rw_semaphores + * Oct 14, 2004, fbui@comcast.net: got fbui_input module working + * Oct 14, 2004, fbui@comcast.net: mouse data now available as events + * Oct 14, 2004, fbui@comcast.net: key data now available as events + * Oct 15, 2004, fbui@comcast.net: put in basic mouse-pointer logic + * Oct 16, 2004, fbui@comcast.net: fbui-inp now calls fbui to provide events + * Oct 17, 2004, fbui@comcast.net: perfected software mouse-pointer logic + * Oct 17, 2004, fbui@comcast.net: restructuring: now only fb_* in fbops. + * Oct 17, 2004, fbui@comcast.net: added window-moved event. + * Oct 18, 2004, fbui@comcast.net: fixed keyboard accelerators post inp-hand + * Oct 20, 2004, fbui@comcast.net: wait-for-event working + * Oct 20, 2004, fbui@comcast.net: accelerators are now for chars [32,128) + * Oct 21, 2004, fbui@comcast.net: revisions to support panel manager + * Oct 22, 2004, fbui@comcast.net: removed keyfocus stack + * Oct 23, 2004, fbui@comcast.net: fixed tty: NULL is now used + * Oct 25, 2004, fbui@comcast.net: key queue is now per-console + * Oct 26, 2004, fbui@comcast.net: putpixels now takes in-kernel data + * Oct 26, 2004, fbui@comcast.net: putpixels_rgb takes 0% & 100% transparency + * Oct 26, 2004, fbui@comcast.net: added fb_getpixels_rgb + * Oct 26, 2004, fbui@comcast.net: mouse pointer now drawn using putpixels + * Oct 26, 2004, fbui@comcast.net: conversion to multiple windows per process + * Oct 26, 2004, fbui@comcast.net: added cut/paste logic + * Nov 11, 2004, fbui@comcast.net: left-bearing for drawn characters! + * Nov 18, 2004, fbui@comcast.net: added mouse-motion event + * Nov 24, 2004, fbui@comcast.net: added fbui-specific logfile + * Nov 29, 2004, fbui@comcast.net: added proper event queues for windows. + * Dec 12, 2004, fbui@comcast.net: added ability to open hidden window + * Dec 13, 2004, fbui@comcast.net: event queues are now per-process + * Dec 13, 2004, fbui@comcast.net: Enter event now generated after switch + * Dec 13, 2004, fbui@comcast.net: added fbui_tinyblit + * Dec 14, 2004, fbui@comcast.net: Enter/Leave after ptr hide/unhide + * Dec 15, 2004, fbui@comcast.net: wait-for-event checks all pid's windows + * Dec 16, 2004, fbui@comcast.net: processentry nwindows now correct + * Dec 18, 2004, fbui@comcast.net: processentry now has event mask + * Dec 21, 2004, fbui@comcast.net: optimization for tinyblit + * Dec 28, 2004, fbui@comcast.net: added fbui_clean to remove zombie data + * Dec 31, 2004, fbui@comcast.net: added process_exists + * Jan 01, 2005, fbui@comcast.net: added PrtSc accelerator + * Jan 01, 2005, fbui@comcast.net: added SUBTITLE and SETFONT cmds + * Jan 02, 2005, fbui@comcast.net: unhide now performs overlap check + * Jan 03, 2005, fbui@comcast.net: added mode24 for slight speedup + * Jan 03, 2005, fbui@comcast.net: added pointerfocus and receive_all_motion + * Jan 04, 2005, fbui@comcast.net: fixed tinyblit bug + * Jan 05, 2005, fbui@comcast.net: separated button events from keys + * Jan 13, 2005, fbui@comcast.net: minor tweaks + */ + + +/* + * Note: + * + * This code currently works for 8/16/24/32 little endian packed pixels only. + * I have some 4-bit VGA code which I may add later. + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/string.h> +#include <linux/fb.h> +#include <asm/types.h> +#include <asm/uaccess.h> +#include <linux/spinlock.h> +#include <linux/tty.h> +#include <linux/console.h> +#include <linux/kbd_kern.h> +#include <linux/vt_kern.h> +#include <linux/ctype.h> +#include <linux/input.h> /* struct input_event */ +#include <linux/sem.h> +#include <linux/delay.h> +#include <linux/pid.h> /* find_pid */ + +/* Variables for input_handler */ +static char fbui_handler_regd = 0; +static char got_rel_x = 0; +static char got_rel_y = 0; +static short incoming_x = 0; +static short incoming_y = 0; +static char altdown = 0; +static char intercepting_accel = 0; + + + +#define FBUI_VERSION "0.9.14" + + + +/* Mouse-pointer */ +#define PTRWID 10 +#define PTRHT 16 +static unsigned long pointer_saveunder[256]; /* max 16x16 */ + + +static void fbui_enable_pointer (struct fb_info *info); +static int fbui_clear (struct fb_info *info, struct fbui_window *win); +static int fbui_clear_area (struct fb_info *info, struct fbui_window *win, + short x0, short y0, short x1, short y1); +static int fbui_fill_area (struct fb_info *info, struct fbui_window *win, + short x0, short y0, short x1, short y1, u32 color); +static int fbui_draw_point (struct fb_info *info, struct fbui_window *win, + short x, short y, u32 color); +static int fbui_draw_line (struct fb_info *info, struct fbui_window *win, + short x0, short y0, short x1, short y1, u32 color); +static int fbui_copy_area (struct fb_info *info, struct fbui_window *win, + short xsrc,short ysrc,short w, short h, short xdest,short ydest); +static int fbui_draw_vline (struct fb_info *info, struct fbui_window *win, + short x, short y0, short y1, u32 color); +static int fbui_draw_hline (struct fb_info *info, struct fbui_window *win, + short x0, short x1, short y, u32 color); +static int fbui_draw_rect (struct fb_info *info, struct fbui_window *win, + short x0, short y0, short x1, short y1, u32 color); +static int fbui_put_rgb (struct fb_info *info, struct fbui_window *win, + short x, short y,short n, unsigned long *src); +static int fbui_put_rgb3 (struct fb_info *info, struct fbui_window *win, + short x,short y, short n, unsigned char *src); +static int fbui_put (struct fb_info *info, struct fbui_window *win, + short x,short y, short n, unsigned char *src); +static int fbui_copy_area (struct fb_info *info, struct fbui_window *win, + short xsrc,short ysrc,short w, short h, + short xdest,short ydest); +static int fbui_draw_string (struct fb_info *info, struct fbui_window *win, + struct fbui_font *font, + short x, short y, unsigned char *str, u32 color); +static int fbui_tinyblit (struct fb_info *info, struct fbui_window *win, + short x, short y, short width, u32 color, u32 bgcolor, u32 bitmap); +static struct fbui_processentry *alloc_processentry (struct fb_info *info, int pid, int cons); +static void free_processentry (struct fb_info *info, struct fbui_processentry *pre); +static struct fbui_window *get_pointer_window (struct fb_info *info); +static struct fbui_window * + accelerator_test (struct fb_info *info, int cons, unsigned char); +static int fbui_clean (struct fb_info *info, int cons); +static int fbui_remove_win (struct fb_info *info, short win_id, int); + + + + +static int process_exists (int pid) +{ + struct pid *pidptr; + read_lock_irq(&tasklist_lock); + pidptr = find_pid (PIDTYPE_PID, pid); + read_unlock_irq(&tasklist_lock); + return pidptr != NULL; +} + + +#if 0 +static struct fbui_processentry *lookup_processentry_by_pid (struct fb_info *info,int pid) +{ + int i=0; + struct fbui_processentry *pre; + + if (!info) + return NULL; + /*----------*/ + + while (i < FBUI_MAXCONSOLES * FBUI_MAXWINDOWSPERVC) { + pre = &info->processentries[i]; + if (pre->in_use && pid == pre->pid) + return pre; + i++; + } + return NULL; +} +#endif + + +static void fbui_enqueue_event (struct fb_info *info, struct fbui_window *win, + struct fbui_event *ev, int inside_IH) +{ + struct fbui_processentry *pre; + unsigned long flags = 0; + short head; + spinlock_t mylock = SPIN_LOCK_UNLOCKED; + + if (!info || !win || !ev) + return; + pre = win->processentry; + if (!pre) { + printk (KERN_INFO "fbui_enqueue_event: no processentry\n"); + return; + } + if (!pre->in_use) { + printk (KERN_INFO "fbui_enqueue_event: processentry not in use\n"); + return; + } + if (pre->events_pending >= FBUI_MAXEVENTSPERPROCESS) { + /*printk (KERN_INFO "fbui_enqueue_event: event buffer overflow for process %d, event type %d\n", pre->pid, ev->type);*/ + return; + } + /*----------*/ + + if (!inside_IH) { + down (&pre->queuesem); + spin_lock_irqsave(&mylock, flags); + } + + ev->id = win->id; + ev->pid = win->pid; + head = pre->events_head; + memcpy (&pre->events[head], ev, sizeof (struct fbui_event)); + pre->events_head = (head + 1) % FBUI_MAXEVENTSPERPROCESS; + pre->events_pending++; + +/*printk(KERN_INFO "enqueue: window %d event %d pending=%d, enqueue at head %d\n", win->id, ev->type, pre->events_pending, head); */ + + if (!inside_IH) { + spin_unlock_irqrestore(&mylock, flags); + up (&pre->queuesem); + } + + if (pre->waiting) { + pre->waiting = 0; + wake_up_interruptible (&pre->waitqueue); + } +} + + +static int fbui_dequeue_event (struct fb_info *info, struct fbui_processentry *pre, + struct fbui_event *ev) +{ + short tail; + unsigned long flags; + + if (!info || !pre || !ev) + return 0; + + if (pre->events_pending <= 0) { +/* printk(KERN_INFO "fbui_dequeue_event: no events pending\n"); */ + return 0; + } + /*----------*/ + + /* Remove an event from the event queue for this process, + * locking out input_handler which writes to the queue, + * and locking out via a semaphore any other process + * either reading or writing the queue. + */ + down (&pre->queuesem); + spin_lock_irqsave(&pre->queuelock, flags); + + tail = pre->events_tail; + memcpy (ev, &pre->events[tail], sizeof (struct fbui_event)); +/* printk(KERN_INFO "dequeue for window %d: pending %d, tail %d\n", ev->id,pre->events_pending, tail); */ + pre->events_tail = (tail + 1) % FBUI_MAXEVENTSPERPROCESS; + --pre->events_pending; + + spin_unlock_irqrestore (&pre->queuelock, flags); + up (&pre->queuesem); + +/* printk (KERN_INFO "dequeue: ev { type %d key %d pid %d id %d } current->pid %d pre { pid %d ix %d}\n",ev->type,ev->key,ev->pid,ev->id,current->pid,pre->pid,pre->index); */ + + return 1; +} + + +u32 pixel_from_rgb (struct fb_info *info, u32 value) +{ + u32 r,g,b; + if (!info->mode24) { + unsigned char tmp = 0xff; + b = tmp & value; + value >>= 8; + g = tmp & value; + value >>= 8; + r = tmp & value; + tmp = 8; + r >>= (tmp - info->redsize); + g >>= (tmp - info->greensize); + b >>= (tmp - info->bluesize); + r <<= info->redshift; + g <<= info->greenshift; + b <<= info->blueshift; + return r | g | b; + } else { + return value & 0xffffff; + } +} + +u32 pixel_to_rgb (struct fb_info *info, u32 value) +{ + u32 r,g,b; + if (!info->mode24) { + unsigned char tmp = 8; + r = value >> info->redshift; + g = value >> info->greenshift; + b = value >> info->blueshift; + r &= (1 << info->redsize) - 1; + g &= (1 << info->bluesize) - 1; + b &= (1 << info->greensize) - 1; + r <<= (tmp - info->redsize); + g <<= (tmp - info->greensize); + b <<= (tmp - info->bluesize); + r <<= 16; + g <<= 8; + return r | g | b; + } else { + return value & 0xffffff; + } +} + + +void fb_point (struct fb_info *info, short x, short y, u32 color, char do_invert) +{ + short xres, yres; + u32 bytes_per_pixel, offset; + unsigned char *ptr; + + if (!info) + return; + xres = info->var.xres; + yres = info->var.yres; + if (x < 0 || y < 0 || x >= xres || y >= yres) + return; + /*----------*/ + + bytes_per_pixel = (info->var.bits_per_pixel + 7) >> 3; + offset = y * info->fix.line_length + x * bytes_per_pixel; + ptr = ((unsigned char*)info->screen_base); + if (!ptr) + return; + + ptr += offset; + + if (do_invert) + { + switch (bytes_per_pixel) + { + case 1: fb_writeb(0xff ^ fb_readb (ptr), ptr); break; + case 2: fb_writew(0xffff ^ fb_readw (ptr), ptr); break; + case 4: fb_writel(0xffffffff ^ fb_readl (ptr), ptr); break; + case 3: + fb_writeb(0xff ^ fb_readb (ptr), ptr); ptr++; + fb_writeb(0xff ^ fb_readb (ptr), ptr); ptr++; + fb_writeb(0xff ^ fb_readb (ptr), ptr); + break; + } + } + else + { + u32 c = pixel_from_rgb (info, color); + switch (bytes_per_pixel) + { + case 1: fb_writeb (c, ptr); break; + case 2: fb_writew (c, ptr); break; + case 4: fb_writel (c, ptr); break; + case 3: + fb_writeb (c, ptr); ptr++; c >>= 8; + fb_writeb (c, ptr); ptr++; c >>= 8; + fb_writeb (c, ptr); + break; + } + } +} + + +void fb_hline (struct fb_info *info, short x0, short x1, short y, u32 color) +{ + u32 pixel, bytes_per_pixel, offset; + unsigned char *ptr; + int i; + + if (!info) + return; + + if (x0 > x1) { + short tmp = x0; + x0 = x1; + x1 = tmp; + } + + bytes_per_pixel = (info->var.bits_per_pixel + 7) >> 3; + offset = y * info->fix.line_length + x0 * bytes_per_pixel; + ptr = ((unsigned char*)info->screen_base); + if (!ptr) + return; + ptr += offset; + + i= x1-x0+1; + pixel = pixel_from_rgb (info, color); + switch (bytes_per_pixel) { + case 4: { + register unsigned long* ptr2 = (unsigned long*) ptr; + register u32 pix = pixel; + while (i) { + if (i > 8) { + /* useful on older processors */ + fb_writel (pix, ptr2); ptr2++; + fb_writel (pix, ptr2); ptr2++; + fb_writel (pix, ptr2); ptr2++; + fb_writel (pix, ptr2); ptr2++; + fb_writel (pix, ptr2); ptr2++; + fb_writel (pix, ptr2); ptr2++; + fb_writel (pix, ptr2); ptr2++; + fb_writel (pix, ptr2); ptr2++; + i -= 8; + } else { + fb_writel (pix, ptr2); ptr2++; + i--; + } + } + break; + } + + case 3: { + u32 r = 0xff & pixel; + u32 g = 0xff & (pixel >> 8); + u32 b = 0xff & (pixel >> 16); + register u32 long1,long2,long3; + register unsigned char third = x0 % 3; + + long1 = r | (g<<8) | (b<<16) | (r<<24); + long2 = g | (b<<8) | (r<<16) | (g<<24); + long3 = b | (r<<8) | (g<<16) | (b<<24); + while (i) { + if (!third && i>=4) { + unsigned long *ptr2 = (unsigned long*) ptr; + while (i>=12) { + /* useful on older processors */ + fb_writel (long1, ptr2); ptr2++; + fb_writel (long2, ptr2); ptr2++; + fb_writel (long3, ptr2); ptr2++; + fb_writel (long1, ptr2); ptr2++; + fb_writel (long2, ptr2); ptr2++; + fb_writel (long3, ptr2); ptr2++; + fb_writel (long1, ptr2); ptr2++; + fb_writel (long2, ptr2); ptr2++; + fb_writel (long3, ptr2); ptr2++; + i -= 12; + ptr += 36; + } + while (i>=4) { + fb_writel (long1, ptr2); ptr2++; + fb_writel (long2, ptr2); ptr2++; + fb_writel (long3, ptr2); ptr2++; + i -= 4; + ptr += 12; + } + } else { + u32 c = pixel; + fb_writeb (c, ptr); ptr++; c >>= 8; + fb_writeb (c, ptr); ptr++; c >>= 8; + fb_writeb (c, ptr); ptr++; + i--; + third++; + if (third==3) third=0; + } + } + break; + } + + case 2: { + u32 c32 = (pixel & 0xffff) | (pixel << 16); + while (i) { + if (i>=2 && !(3 & (u32)ptr)) { + if (i>=16) { + u32 *ptr2 = (u32*)ptr; + /* useful on older processors */ + fb_writel (c32, ptr2); ptr2++; + fb_writel (c32, ptr2); ptr2++; + fb_writel (c32, ptr2); ptr2++; + fb_writel (c32, ptr2); ptr2++; + fb_writel (c32, ptr2); ptr2++; + fb_writel (c32, ptr2); ptr2++; + fb_writel (c32, ptr2); ptr2++; + fb_writel (c32, ptr2); ptr2++; + ptr += 32; + i -= 16; + } + if (i>=2) { + fb_writel (c32, ptr); + ptr += 4; + i -= 2; + } + } else { + u32 c = pixel; + fb_writeb (c, ptr); ptr++; c >>= 8; + fb_writeb (c, ptr); ptr++; + i--; + } + } + break; + } + + case 1: { + u32 c32; + pixel &= 0xff; + c32 = pixel | (pixel<<8) | (pixel<<16) || (pixel<<24); + while (i) { + if (!(3 & (u32)ptr)) { + if (i>=32) { + u32 *ptr2 = (u32 *)ptr; + /* useful on older processors */ + fb_writel (c32, ptr2); ptr2++; + fb_writel (c32, ptr2); ptr2++; + fb_writel (c32, ptr2); ptr2++; + fb_writel (c32, ptr2); ptr2++; + fb_writel (c32, ptr2); ptr2++; + fb_writel (c32, ptr2); ptr2++; + fb_writel (c32, ptr2); ptr2++; + fb_writel (c32, ptr2); ptr2++; + ptr += 32; + i -= 32; + } + if (i>=4) { + fb_writel (c32, ptr); + ptr += 4; + i -= 4; + } + } else { + fb_writel (pixel, ptr); ptr++; + i--; + } + } + break; + } + + }/*switch*/ +} + + +void fb_vline (struct fb_info *info, short x, short y0, short y1, u32 color) +{ + u32 pixel, linelen, bytes_per_pixel, offset; + unsigned char *ptr; + short i; + short xres,yres; + + if (!info) + return; + xres = info->var.xres; + if (x < 0 || x >= xres) + return; + if (y0 > y1) { + short tmp = y0; + y0 = y1; + y1 = tmp; + } + if (y1 < 0) + return; + yres = info->var.yres; + if (y0 >= yres) + return; + if (y0 < 0) + y0 = 0; + if (y1 >= yres) + y1 = yres-1; + /*----------*/ + + linelen = info->fix.line_length; + bytes_per_pixel = (info->var.bits_per_pixel + 7) >> 3; + offset = y0 * linelen + x * bytes_per_pixel; + ptr = info->screen_base; + ptr += offset; + + i = y1-y0+1; + pixel = pixel_from_rgb (info, color); + + switch (bytes_per_pixel) { + case 4: + while (i--) { + fb_writel (pixel, ptr); + ptr += linelen; + } + break; + + case 3: + while (i--) { + register u32 c = pixel; + fb_writeb (c, ptr); ptr++; c >>= 8; + fb_writeb (c, ptr); ptr++; c >>= 8; + fb_writeb (c, ptr); + ptr += linelen; + ptr -= 2; + } + break; + + case 2: + while (i--) { + fb_writew (pixel, ptr); + ptr += linelen; + } + break; + + case 1: + while (i--) { + fb_writeb (pixel, ptr); + ptr += linelen; + } + break; + } + + return; +} + + +void fb_clear (struct fb_info *info, u32 color_) +{ + u32 color = color_; + short y, ylim, xlim; + + if (!info) + return; + if (info->state != FBINFO_STATE_RUNNING) + return; + /*----------*/ + + y = 0; + ylim = info->var.yres; + xlim = info->var.xres - 1; + + while (y < ylim) + fb_hline (info, 0, xlim, y++, color); +} + + +/* Parameter cons is the VC we are switching to; + * info->currcon is the VC we are switching from. + */ +int fbui_switch (struct fb_info *info, int cons) +{ + struct fbui_window *win; + struct fbui_event ev; + int i,lim; + + if (!info) + return 0; + if (cons < 0 || cons >= FBUI_MAXCONSOLES) + return FBUI_ERR_BADVC; + if (!vc_cons_allocated (cons)) + return 0; + /*----------*/ + + info->pointer_active = 0; + intercepting_accel = 0; + altdown = 0; + + /* Clean up the new console + */ + fbui_clean (info, cons); + + /* Send Leave event to whichever window had gotten an Enter. + */ + down_read (&info->winptrSem); + win = info->pointer_window [info->currcon]; + up_read (&info->winptrSem); + if (win) { + memset (&ev, 0, sizeof (struct fbui_event)); + ev.type = FBUI_EVENT_LEAVE; + + win->pointer_inside = 0; + down_write (&info->winptrSem); + info->pointer_window [info->currcon] = NULL; + up_write (&info->winptrSem); + + fbui_enqueue_event (info, win, &ev, 0); + } + + info->currcon = cons; + + /* This routine is called whenever there's a switch, + * not just when we're switching to a graphics console. + */ + if (vt_cons[cons]->vc_mode != KD_GRAPHICS) + return 1; + + /* Former value no longer valid */ + down_write (&info->winptrSem); + info->pointer_window [cons] = NULL; + up_write (&info->winptrSem); + + fb_clear (info, info->bgcolor[cons]); + + /* Firstly perform the clears + */ + i = cons * FBUI_MAXWINDOWSPERVC; + lim = i + FBUI_MAXWINDOWSPERVC; + down_read (&info->winptrSem); + for (; i < lim; i++) { + struct fbui_window *ptr = + info->windows [i]; + + if (ptr && !ptr->is_wm && !ptr->is_hidden) + fbui_clear (info, ptr); + } + up_read (&info->winptrSem); + + /* Secondly sent the expose events + */ + memset (&ev, 0, sizeof (struct fbui_event)); + i = cons * FBUI_MAXWINDOWSPERVC; + lim = i + FBUI_MAXWINDOWSPERVC; + down_read (&info->winptrSem); + for (; i < lim; i++) { + struct fbui_window *ptr = + info->windows [i]; + + if (ptr) { + ev.type = FBUI_EVENT_EXPOSE; + + ptr->pointer_inside = 0; + + /* No need to expose if hidden */ + if (!ptr->is_hidden) + fbui_enqueue_event (info, ptr, &ev, 0); + } + } + up_read (&info->winptrSem); + + info->pointer_active = 0; + fbui_enable_pointer (info); + + /* If the pointer is on top of a window, + * send that window an Enter event. + */ + down_read (&info->winptrSem); + win = get_pointer_window (info); + up_read (&info->winptrSem); + if (win) { + struct fbui_event ev; + memset (&ev, 0, sizeof (struct fbui_event)); + ev.type = FBUI_EVENT_ENTER; + fbui_enqueue_event (info, win, &ev, 0); + } + + return 1; +} + + +static int pointer_in_window (struct fb_info *info, struct fbui_window *win, char just_tip) +{ + register short mx,my,mx1,my1; + short x0,y0,x1,y1; + + if (!info || !win) + return 0; + if (!info->pointer_active || info->pointer_hidden) + return 0; + /*----------*/ + if (win->console != info->currcon) + return 0; + if (win->is_hidden) + return 0; + mx = info->curr_mouse_x; + my = info->curr_mouse_y; + mx1 = mx + PTRWID - 1; + my1 = my + PTRHT - 1; + x0 = win->x0; + y0 = win->y0; + x1 = win->x1; + y1 = win->y1; + if (!just_tip) { + if ((mx >= x0 && mx <= x1) || (mx1 >= x0 && mx1 <= x1)) + if ((my >= y0 && my <= y1) || (my1 >= y0 && my1 <= y1)) + return 1; + } else { + if ((mx >= x0 && mx <= x1) && (my >= y0 && my <= y1)) + return 1; + } + + return 0; +} + + +/* XX -- Currently the mouse pointer is a fixed pattern */ +static unsigned long ptrpixels [] = { +#define T___ 0xff000000 +#define BORD RGB_BLACK +#define X___ RGB_WHITE +BORD,BORD,T___,T___,T___,T___,T___,T___,T___,T___, +BORD,X___,BORD,T___,T___,T___,T___,T___,T___,T___, +BORD,X___,X___,BORD,T___,T___,T___,T___,T___,T___, +BORD,X___,X___,X___,BORD,T___,T___,T___,T___,T___, +BORD,X___,X___,X___,X___,BORD,T___,T___,T___,T___, +BORD,X___,X___,X___,X___,X___,BORD,T___,T___,T___, +BORD,X___,X___,X___,X___,X___,X___,BORD,T___,T___, +BORD,X___,X___,X___,X___,X___,X___,X___,BORD,T___, +BORD,X___,X___,X___,X___,X___,X___,X___,X___,BORD, +BORD,X___,X___,X___,X___,X___,BORD,BORD,BORD,BORD, +BORD,X___,X___,BORD,X___,X___,BORD,T___,T___,T___, +BORD,X___,BORD,T___,BORD,X___,X___,BORD,T___,T___, +BORD,BORD,T___,T___,BORD,X___,X___,BORD,T___,T___, +T___,T___,T___,T___,T___,BORD,X___,X___,BORD,T___, +T___,T___,T___,T___,T___,BORD,X___,X___,BORD,T___, +T___,T___,T___,T___,T___,T___,BORD,BORD,T___,T___ +}; + + +static void fbui_pointer_save (struct fb_info *info) +{ + short j,x,y; + unsigned long *p = pointer_saveunder; + + if (!info) + return; + /*----------*/ + + x = info->mouse_x0; + y = info->mouse_y0; + j = PTRHT; + while (j--) { + if (info->fbops->fb_getpixels_rgb) + info->fbops->fb_getpixels_rgb (info, x, y++, PTRWID, p, 1); + p += PTRWID; + } +} + +static void fbui_pointer_restore (struct fb_info *info) +{ + short j,x,y; + unsigned long *p = pointer_saveunder; + + if (!info) + return; + /*----------*/ + + x = info->mouse_x0; + y = info->mouse_y0; + j = PTRHT; + while (j--) { + if (info->fbops->fb_putpixels_rgb) + info->fbops->fb_putpixels_rgb (info, x, y++, PTRWID, p, 1); + p += PTRWID; + } +} + +static void fbui_pointer_draw (struct fb_info *info) +{ + short j, x, y; + unsigned long *p = ptrpixels; + + if (!info) + return; + /*----------*/ + + x = info->mouse_x0; + y = info->mouse_y0; + j = PTRHT; + while (j--) { + if (info->fbops->fb_putpixels_rgb) + info->fbops->fb_putpixels_rgb (info, x, y++, PTRWID, p, 1); + p += PTRWID; + } +} + +static void fbui_enable_pointer (struct fb_info *info) +{ + if (!info) + return; + if (info->pointer_active) + return; + /*----------*/ + + fbui_pointer_save (info); + fbui_pointer_draw (info); + + info->pointer_active = 1; + info->pointer_hidden = 0; +} + +#if 0 +static void fbui_disable_pointer (struct fb_info *info) +{ + if (!info) + return; + if (!info->pointer_active) + return; + /*----------*/ + + // fbui_pointer_restore (info, win); + info->pointer_active = 0; + info->pointer_hidden = 0; +} +#endif + +static void fbui_hide_pointer (struct fb_info *info) +{ + if (!info) + return; + if (!info->pointer_active) + return; + if (info->pointer_hidden) + return; + /*----------*/ + + if (!info->have_hardware_pointer) { + fbui_pointer_restore (info); + } + info->pointer_hidden = 1; +} + +static void fbui_unhide_pointer (struct fb_info *info) +{ + if (!info) + return; + if (!info->pointer_active) + return; + if (!info->pointer_hidden) + return; + /*----------*/ + + if (!info->have_hardware_pointer) { + fbui_pointer_save (info); + fbui_pointer_draw (info); + } + info->pointer_hidden = 0; +} + + +static struct fbui_window *get_pointer_window (struct fb_info *info) +{ + struct fbui_window *win=NULL; + int i,lim; + int cons; + + if (!info) + return NULL; + /*----------*/ + + cons = info->currcon; + i = cons * FBUI_MAXWINDOWSPERVC; + lim = i + FBUI_MAXWINDOWSPERVC; + while (i < lim) { + win = info->windows [i]; + if (win && !win->is_wm && pointer_in_window (info,win,1)) + break; + + i++; + } + if (i >= lim) + return NULL; + return win; +} + + + +static struct fbui_window *fbui_lookup_wm (struct fb_info *info, int cons) +{ + struct fbui_window *ptr; + struct rw_semaphore *sem; + + if (!info) + return NULL; + if (cons < 0 || cons >= FBUI_MAXCONSOLES) + return NULL; + /*----------*/ + + sem = &info->winptrSem; + down_read (sem); + ptr = info->window_managers [cons]; + up_read (sem); + + /* Since the wm is a critical window, let's + * just make sure that its process still exists. + */ + if (ptr) { + if (!process_exists (ptr->pid)) { + fbui_remove_win (info, ptr->id, 0); + ptr = NULL; + down_write (sem); + ptr = info->window_managers [cons]; + up_write (sem); + } + } + + return ptr; +} + +void input_handler (u32 param, struct input_event *ev) +{ + struct fb_info *info; + int type, code, value; + short xlim, ylim; + int cons; + char event_is_altkey=0; + + if (!fbui_handler_regd) + return; + + info = (struct fb_info*) param; + if (!info || !ev) + return; + + cons = info->currcon; + if (cons < 0 || cons >= FBUI_MAXCONSOLES) + return; + if (vt_cons[cons]->vc_mode != KD_GRAPHICS) + return; + /*----------*/ + + type = ev->type; + code = ev->code; + value = ev->value; + + /* Intercept Alt-keys at all times. + */ + if (type == EV_KEY && (code == KEY_LEFTALT || code == KEY_RIGHTALT)) { + altdown = value > 0; + event_is_altkey=1; + } + + switch (type) { + case EV_SYN: + return; + + case EV_KEY: + if (altdown && !event_is_altkey) { + if (value==1) { + unsigned char ia = 0; + struct fbui_window *match; + + switch (code) { + case KEY_1: ia = '1'; break; + case KEY_2: ia = '2'; break; + case KEY_3: ia = '3'; break; + case KEY_4:ia = '4'; break; + case KEY_5: ia = '5'; break; + case KEY_6: ia = '6'; break; + case KEY_7: ia = '7'; break; + case KEY_8:ia = '8'; break; + case KEY_9: ia = '9'; break; + case KEY_0: ia = '0'; break; + case KEY_TAB:ia = '\t'; break; + case KEY_ENTER:ia = '\n'; break; + case KEY_SYSRQ:ia = FBUI_ACCEL_PRTSC; break; + case KEY_HOME:ia = FBUI_ACCEL_HOME; break; + case KEY_END:ia = FBUI_ACCEL_END; break; + case KEY_PAGEUP:ia = FBUI_ACCEL_PGUP; break; + case KEY_PAGEDOWN:ia = FBUI_ACCEL_PGDN; break; + case KEY_A: ia = 'a'; break; + case KEY_B: ia = 'b'; break; + case KEY_C: ia = 'c'; break; + case KEY_D: ia = 'd'; break; + case KEY_E: ia = 'e'; break; + case KEY_F: ia = 'f'; break; + case KEY_G: ia = 'g'; break; + case KEY_H: ia = 'h'; break; + case KEY_I: ia = 'i'; break; + case KEY_J: ia = 'j'; break; + case KEY_K: ia = 'k'; break; + case KEY_L: ia = 'l'; break; + case KEY_M: ia = 'm'; break; + case KEY_N: ia = 'n'; break; + case KEY_O: ia = 'o'; break; + case KEY_P: ia = 'p'; break; + case KEY_Q: ia = 'q'; break; + case KEY_R: ia = 'r'; break; + case KEY_S: ia = 's'; break; + case KEY_T: ia = 't'; break; + case KEY_U: ia = 'u'; break; + case KEY_V: ia = 'v'; break; + case KEY_W: ia = 'w'; break; + case KEY_X: ia = 'x'; break; + case KEY_Y: ia = 'y'; break; + case KEY_Z: ia = 'z'; break; + case KEY_BACKSPACE: ia = '\b'; break; + } + + match = accelerator_test (info, info->currcon, ia); + if (match) { + struct fbui_event ev; + memset (&ev, 0, sizeof (struct fbui_event)); + ev.type = FBUI_EVENT_ACCEL; + ev.key = ia; + fbui_enqueue_event (info, match, &ev, 1); + } + + intercepting_accel = 1; + return; + } + } + + if (intercepting_accel && code!=KEY_LEFTALT && code!=KEY_RIGHTALT) { + intercepting_accel = 0; + return; + } + + if (!intercepting_accel) { + if (down_read_trylock (&info->winptrSem)) { + if ((code & 0xfff0) == BTN_MOUSE) { + struct fbui_window *win; + + win = get_pointer_window (info); + up_read (&info->winptrSem); + + if (win) { + struct fbui_event ev; + short tmp=0; + + memset (&ev, 0, sizeof (struct fbui_event)); + ev.type = FBUI_EVENT_BUTTON; + ev.key = value ? 1 : 0; + + switch (code) { + case BTN_LEFT: + tmp = FBUI_BUTTON_LEFT; + break; + case BTN_MIDDLE: + tmp = FBUI_BUTTON_MIDDLE; + break; + case BTN_RIGHT: + tmp = FBUI_BUTTON_RIGHT; + break; + } + ev.key |= tmp; + fbui_enqueue_event (info, win, &ev, 1); + } + } + else + { + struct fbui_window *recipient=info->keyfocus_window [cons]; + up_read (&info->winptrSem); + + if (recipient) { + struct fbui_event ev; + memset (&ev, 0, sizeof (struct fbui_event)); + + ev.type = FBUI_EVENT_KEY; + ev.key = (code << 2) | (value & 3); + fbui_enqueue_event (info, recipient, &ev, 1); + } +#if 0 + else + printk (KERN_INFO "key %d,%d discarded\n",code,value); +#endif + } + } + else /* XX need workaround */ + printk (KERN_INFO "key %d,%d INADVERTENTLY discarded\n",code,value); + } + break; + + case EV_REL: + /* We don't receive both x and y at once; + * we must wait for both to arrive. + */ + xlim = info->var.xres; + ylim = info->var.yres; + if (!got_rel_x && !got_rel_y) { + incoming_x = info->curr_mouse_x; + incoming_y = info->curr_mouse_y; + } + if (code == REL_X) { + short x = incoming_x; + if (got_rel_x && !got_rel_y) + got_rel_y = 1; + xlim--; + x += value; + if (x<0) + x = 0; + if (x>xlim) + x = xlim; + incoming_x = x; + got_rel_x = 1; + } else + if (code == REL_Y) { + short y = incoming_y; + if (got_rel_y && !got_rel_x) + got_rel_x = 1; + ylim--; + y += value; + if (y<0) + y = 0; + if (y>ylim) + y = ylim; + incoming_y = y; + got_rel_y = 1; + } + + if (got_rel_x && got_rel_y) { + int cons = info->currcon; + + if (!info->pointer_active || info->pointer_hidden) + return; + + /* Even if the new coords cannot affect the + * display due to drawing that is happening, + * we at least need to record them. + */ + info->curr_mouse_x = incoming_x; + info->curr_mouse_y = incoming_y; + + if (down_read_trylock (&info->winptrSem)) { + struct fbui_window *win = NULL; + struct fbui_window *wm = NULL; + struct fbui_window *pf = NULL; + struct fbui_window *oldwin = + info->pointer_window [cons]; + char drawing=0; + struct fbui_processentry *pre = NULL; + struct fbui_processentry *oldpre = NULL; + + win = get_pointer_window (info); + if (win) { + drawing = win->drawing; + pre = win->processentry; + } + + if (oldwin) + oldpre = oldwin->processentry; + + /* generate Leave */ + if (oldwin && oldpre && win != oldwin && + (oldpre->wait_event_mask & FBUI_EVENTMASK_LEAVE)) { + struct fbui_event ev; + memset (&ev, 0, sizeof (struct fbui_event)); + ev.type = FBUI_EVENT_LEAVE; + fbui_enqueue_event (info, oldwin, &ev, 1); + + oldwin->pointer_inside = 0; + info->pointer_window [cons] = NULL; + } + + /* generate Enter */ + if (win && pre && !win->pointer_inside && + (pre->wait_event_mask & FBUI_EVENTMASK_ENTER)) { + struct fbui_event ev; + memset (&ev, 0, sizeof (struct fbui_event)); + ev.type = FBUI_EVENT_ENTER; + fbui_enqueue_event (info, win, &ev, 1); + + win->pointer_inside = 1; + info->pointer_window [cons] = win; + } + + /* If possible draw the pointer */ + if (!win || !drawing) { + fbui_pointer_restore (info); + info->mouse_x0 = incoming_x; + info->mouse_y0 = incoming_y; + info->mouse_x1 = info->mouse_x0 + PTRWID - 1; + info->mouse_y1 = info->mouse_y0 + PTRHT - 1; + fbui_pointer_save (info); + fbui_pointer_draw (info); + } + + /* generate Motion for appropriate window */ + if (win && pre && + (pre->wait_event_mask & FBUI_EVENTMASK_MOTION)) + { + struct fbui_event ev; + memset (&ev, 0, sizeof (struct fbui_event)); + ev.type = FBUI_EVENT_MOTION; + ev.x = info->mouse_x0 - win->x0; + ev.y = info->mouse_y0 - win->y0; + fbui_enqueue_event (info, win, &ev, 1); + } + + /* generate Motion for the window that has pointer focus*/ + pf = info->pointerfocus_window[cons]; + if (pf && pf->processentry) { + struct fbui_event ev; + memset (&ev, 0, sizeof (struct fbui_event)); + ev.type = FBUI_EVENT_MOTION; + ev.x = info->mouse_x0 - pf->x0; + ev.y = info->mouse_y0 - pf->y0; + fbui_enqueue_event (info, pf, &ev, 1); + } + + wm = info->window_managers [cons]; + if (wm && wm->receive_all_motion) { + struct fbui_event ev; + memset (&ev, 0, sizeof (struct fbui_event)); + ev.type = FBUI_EVENT_MOTION; + ev.x = info->mouse_x0; + ev.y = info->mouse_y0; + fbui_enqueue_event (info, wm, &ev, 1); + } + up_read (&info->winptrSem); + } + + got_rel_x = 0; + got_rel_y = 0; + } + break; + } +} + + +int fbui_init (struct fb_info *info) +{ + int i; + + if (!info) + return 0; + /*----------*/ + +#ifdef FBUI_DEBUG + init_MUTEX (&logsem); +#endif + + for (i=0; i < FBUI_TOTALACCELS * FBUI_MAXCONSOLES; i++) + info->accelerators [i] = NULL; + + for (i=0; i < (FBUI_MAXCONSOLES * FBUI_MAXWINDOWSPERVC); i++) { + info->windows [i] = NULL; + init_MUTEX (&info->windowSems [i]); + } + + init_MUTEX (&info->preSem); + + for (i=0; i<FBUI_MAXCONSOLES; i++) { + info->force_placement [i] = 0; + info->bgcolor[i] = 0; + info->pointer_window [i] = NULL; + info->keyfocus_window [i] = NULL; + info->pointerfocus_window [i] = NULL; + info->window_managers [i] = NULL; + } + + init_rwsem (&info->winptrSem); + info->mouse_x0 = info->var.xres >> 1; + info->mouse_y0 = info->var.yres >> 1; + info->curr_mouse_x = info->mouse_x0; + info->curr_mouse_y = info->mouse_y0; + info->mouse_x1 = info->mouse_x0 + PTRWID - 1; + info->mouse_y1 = info->mouse_y0 + PTRHT - 1; + info->pointer_active = 0; + + info->have_hardware_pointer = 0; + + init_rwsem (&info->cutpaste_sem); + info->cutpaste_buffer = NULL; + + info->redsize = info->var.red.length; + info->greensize = info->var.green.length; + info->bluesize = info->var.blue.length; + info->redshift = info->var.red.offset; + info->greenshift = info->var.green.offset; + info->blueshift = info->var.blue.offset; + + info->mode24 = (info->redsize == 8 && info->greensize == 8 && + info->bluesize == 8 && info->redshift == 16 && + info->greenshift == 8 && !info->blueshift); + + intercepting_accel = 0; + altdown = 0; + + printk(KERN_INFO "FrameBuffer UI (%s) by Zack T Smith: operational on fb%d\n", FBUI_VERSION,info->node); + +/* + printk(KERN_INFO "sizeof (struct fbui_window)=%d\n", sizeof (struct fbui_window)); + printk(KERN_INFO "sizeof (struct fbui_processentry)=%d\n",sizeof(struct fbui_processentry)); + printk(KERN_INFO "sizeof (struct fbui_font)=%d\n", sizeof (struct fbui_font)); +*/ + + return 1; +} + + +static inline struct fbui_window *fbui_lookup_win (struct fb_info *info, int win_id) +{ + struct fbui_window *win; + + if (!info) + return NULL; + if (win_id < 0 || win_id >= (FBUI_MAXWINDOWSPERVC * FBUI_MAXCONSOLES)) + return NULL; + /*----------*/ + + down_read (&info->winptrSem); + win = info->windows [win_id]; + up_read (&info->winptrSem); + + return win; +} + + + + +static int fbui_overlap_check (struct fb_info *info, + short x0, short y0, short x1, short y1, + int cons, struct fbui_window *self) +{ + struct fbui_window *ptr; + struct rw_semaphore *sem; + int i,lim; + + if (!info) + return -1; + if (cons < 0 || cons >= FBUI_MAXCONSOLES) + return -1; + /*----------*/ + + sem = &info->winptrSem; + down_read (sem); + i = cons * FBUI_MAXWINDOWSPERVC; + lim = i + FBUI_MAXWINDOWSPERVC; + while (i < lim) { + ptr = info->windows [i]; + + if (ptr && !ptr->is_hidden && ptr->console == cons && !ptr->is_wm + && ptr != self) + { + short x2, y2, x3, y3; + + x2 = ptr->x0; + x3 = ptr->x1; + y2 = ptr->y0; + y3 = ptr->y1; + + if ((x2 >= x0 && x2 <= x1) || + (x3 >= x0 && x3 <= x1)) { + if ((y2 >= y0 && y2 <= y1) || + (y3 >= y0 && y3 <= y1)) { + up_read (sem); + return 1; + } + } + } + i++; + } + up_read (sem); + + return 0; +} + + +static void restore_vc (struct fb_info *info, int cons) +{ + if (cons < 0 || cons >= FBUI_MAXCONSOLES) + return; + /*----------*/ + + if (cons != info->currcon) { + vc_cons[cons].d->vc_tty = info->ttysave[cons]; + vt_cons[cons]->vc_mode = KD_TEXT; + } else { + acquire_console_sem(); + vc_cons[cons].d->vc_tty = info->ttysave[cons]; + vt_cons[cons]->vc_mode = KD_TEXT; + do_unblank_screen(1); + redraw_screen (cons,0); + release_console_sem(); + } +} + + + + +static void fbui_winptrs_change (struct fb_info *info, int cons) +{ + struct fbui_window *ptr; + + if (!info) + return; + if (cons < 0 || cons >= FBUI_MAXCONSOLES) + return; + /*----------*/ + + ptr = fbui_lookup_wm (info, cons); + if (ptr) { + struct fbui_event ev; + memset (&ev, 0, sizeof (struct fbui_event)); + ev.type = FBUI_EVENT_WINCHANGE; + fbui_enqueue_event (info, ptr, &ev, 0); + } +} + + +static int get_total_windows (struct fb_info *info, int cons) +{ + int i,lim,total; + + if (!info) + return 0; + + total=0; + i = FBUI_MAXWINDOWSPERVC * cons; + lim = i + FBUI_MAXWINDOWSPERVC; + down_read (&info->winptrSem); + for ( ; i < lim; i++) { + if (NULL != info->windows [i]) + total++; + } + up_read (&info->winptrSem); + return total; +} + +static int fbui_remove_win (struct fb_info *info, short win_id, int force) +{ + struct fbui_window *win; + struct fbui_processentry *pre; + struct rw_semaphore *sem; + int cons = 0; + int i, lim; + + if (!info) + return FBUI_ERR_NULLPTR; + if (win_id < 0 || win_id >= (FBUI_MAXWINDOWSPERVC * FBUI_MAXCONSOLES)) + return FBUI_ERR_BADWIN; + /*----------*/ + + sem = &info->winptrSem; + down_read (sem); + win = info->windows [win_id]; + up_read (sem); + + if (!win) + return FBUI_ERR_BADWIN; + + /* Verify that we're allowed to remove this window */ + if (!force && current->pid != win->pid) { + struct fbui_window *wm = fbui_lookup_wm (info, win->console); + if (!wm) + return FBUI_ERR_BADWIN; + + if (current->pid != wm->pid) + return FBUI_ERR_BADWIN; + } + + /* XX */ + if (win->drawing) + printk(KERN_INFO "DRAWING DURING REMOVEWIN\n"); + + down_write (sem); + cons = win->console; + if (win == info->windows[win_id]) + info->windows [win_id] = NULL; + else { + printk (KERN_INFO "fbui_remove_win: window[win->id] != win\n"); + } + if (win->is_wm) + info->window_managers [cons] = NULL; + + if (info->pointerfocus_window[cons] == win) + info->pointerfocus_window[cons] = NULL; + + /* XX need to search window list for another window that wants + * focus + */ + if (info->keyfocus_window[cons] == win) + info->keyfocus_window[cons] = NULL; + + if (info->pointer_window [cons] == win) + info->pointer_window[cons] = NULL; + + /* Clear any accelerators tied to this window */ + i = FBUI_TOTALACCELS * cons; + lim = i + FBUI_TOTALACCELS; + for ( ; i < lim; i++) { + if (info->accelerators[i] == win) + info->accelerators[i] = NULL; + } + up_write (sem); + + /* Reduce the window count for this pid */ + pre = win->processentry; + if (!pre) + printk (KERN_INFO "fbui_remove_win: window is missing processentry\n"); + else { + if (pre->nwindows <= 0) + printk (KERN_INFO "fbui_remove_win: processentry has invalid #windows=%d\n", + pre->nwindows); + else + pre->nwindows--; + + if (pre->nwindows <= 0) + free_processentry (info,pre); + else + printk(KERN_INFO "fbui_remove_win: processentry %d has #wins=%d\n",pre->index, + pre->nwindows); + } + + /* Clear window to display's bgcolor */ + win->bgcolor = info->bgcolor[cons]; + if (!win->is_wm) + fbui_clear (info, win); + kfree(win); + + /* console empty? if so, restore textmode + */ + if (!get_total_windows (info, cons)) { + printk (KERN_INFO "fbui: restoring to text mode on VC %d\n", cons); + restore_vc (info,cons); + } else + if (!force) { + fbui_winptrs_change (info,cons); + } + + return FBUI_SUCCESS; +} + +static inline struct fbui_window * + fbui_add_win (struct fb_info *info, + int cons, + char autoplacement, + char hidden) +{ + struct fbui_window *nu = NULL; + struct fbui_processentry *pre = NULL; + struct semaphore *sem = NULL; + int pid = current->pid; + short win_id; + short i, lim; + + if (!info) + return NULL; + if (cons < 0 || cons >= FBUI_MAXCONSOLES) + return NULL; + /*----------*/ + + /* Find an empty window array entry + */ + down_write (&info->winptrSem); + i = cons * FBUI_MAXWINDOWSPERVC; + lim = i + FBUI_MAXWINDOWSPERVC; + win_id = -1; + while (i < lim) { + if (!info->windows [i]) { + nu = kmalloc (sizeof(struct fbui_window), GFP_KERNEL); + if (!nu) { + /* XX kprint ... */ + up_write (&info->winptrSem); + return NULL; + } + win_id = i; + info->windows [i] = nu; + break; + } + i++; + } + up_write (&info->winptrSem); + + if (i >= lim) + return NULL; + + memset ((void*) nu, 0, sizeof(struct fbui_window)); + + nu->id = win_id; + + nu->pid = pid; + nu->console = cons; + + nu->mouse_x = -1; + nu->mouse_y = -1; + + nu->font_valid = 0; + + /* Lookup the appropriate processentry, or allocate one + * if necessary. + */ + sem = &info->preSem; + down (sem); + pre = NULL; + i=0; + while (i < FBUI_MAXCONSOLES * FBUI_MAXWINDOWSPERVC) { + pre = &info->processentries[i]; + if (pre->in_use && pre->pid == pid) { + nu->processentry = pre; + + /* Rule: each process' windows are limited to one VC + */ + if (pre->console != cons) + nu->console = cons = pre->console; + break; + } + pre = NULL; + i++; + } + up (sem); + + if (!pre) { + pre = alloc_processentry (info, pid, cons); + if (pre) + nu->processentry = pre; + } + + if (!pre) { + printk (KERN_INFO "fbui_add_win: cannot even allocate a processentry\n"); + info->windows [nu->id] = NULL; + kfree (nu); + return NULL; + } + else + ++pre->nwindows; + + nu->is_hidden = hidden; + nu->need_placement = autoplacement; + + if (!autoplacement && !hidden) { + struct fbui_event ev; + memset (&ev, 0, sizeof (struct fbui_event)); + ev.type = FBUI_EVENT_EXPOSE; + fbui_enqueue_event (info, nu, &ev, 0); + } + + fbui_winptrs_change (info,cons); + + return nu; +} + + +static inline void +backup_vc (struct fb_info *info, int cons) +{ + struct tty_struct *tty; + + if (!info || cons < 0 || cons >= FBUI_MAXCONSOLES) + return; + /*----------*/ + + acquire_console_sem(); + vt_cons[cons]->vc_mode = KD_GRAPHICS; + tty = vc_cons[cons].d->vc_tty; + info->ttysave[cons] = tty; + vc_cons[cons].d->vc_tty = NULL; + info->cursor.enable = 0; + do_blank_screen(1); + release_console_sem(); + + if (cons == info->currcon) { + fb_clear (info, info->bgcolor[cons]); + info->pointer_active = 0; + fbui_enable_pointer(info); + } +} + + +static int fbui_set_geometry (struct fb_info *info, struct fbui_window *win, + short x0, short y0, short x1, short y1); + +int fbui_open (struct fb_info *info, struct fbui_openparams *p) +{ + struct fbui_window *win; + struct fbui_window *wm; + short cons; + char auto_placed=0; + char initially_hidden; + short tmp1, tmp2, max; + + /* Extra bulletproofing! */ + if (!info || !p) + return FBUI_ERR_NULLPTR; + if (p->need_keys & 0xfe) + return FBUI_ERR_BADPARAM; + if (p->need_motion & 0xfe) + return FBUI_ERR_BADPARAM; + if (p->desired_vc < -1 || p->desired_vc >= FBUI_MAXCONSOLES) + return FBUI_ERR_BADPARAM; + if (p->req_control & 0xfe) + return FBUI_ERR_BADPARAM; + if (p->receive_all_motion & 0xfe) + return FBUI_ERR_BADPARAM; + if (p->doing_autoposition & 0xfe) + return FBUI_ERR_BADPARAM; + if (p->initially_hidden & 0xfe) + return FBUI_ERR_BADPARAM; + if (p->program_type < 0 || p->program_type >= FBUI_PROGTYPE_LAST) + return FBUI_ERR_BADPARAM; + tmp1 = p->x0; + tmp2 = p->x1; + max = info->var.xres; + if (tmp1 < 0) + tmp1 = 0; + if (tmp1 >= max) + tmp1 = max-1; + if (tmp2 < 0) + tmp2 = 0; + if (tmp2 >= max) + tmp2 = max-1; + if (tmp1 > tmp2) { + p->x0 = tmp2; + p->x1 = tmp1; + } + tmp1 = p->y0; + tmp2 = p->y1; + max = info->var.yres; + if (tmp1 < 0) + tmp1 = 0; + if (tmp1 >= max) + tmp1 = max-1; + if (tmp2 < 0) + tmp2 = 0; + if (tmp2 >= max) + tmp2 = max-1; + if (tmp1 > tmp2) { + p->y0 = tmp2; + p->y1 = tmp1; + } + /*----------*/ + + if (!fbui_handler_regd) { + fbui_input_register_handler (&input_handler, (u32) info); + fbui_handler_regd = 1; + } + + initially_hidden = p->initially_hidden; + + cons = p->desired_vc; + if (cons >= FBUI_MAXCONSOLES) + return FBUI_ERR_BADVC; + if (!vc_cons_allocated (cons)) { + if (!vc_allocate (cons)) + return FBUI_ERR_BADVC; + } + if (cons < 0) + cons = info->currcon; + + wm = fbui_lookup_wm (info, cons); + + if (p->req_control) { + if (wm) + return FBUI_ERR_HAVEWM; + + /* the window-manager process gets the full screen area */ + p->x0 = 0; + p->y0 = 0; + p->x1 = info->var.xres - 1; + p->y1 = info->var.yres - 1; + info->bgcolor[cons] = p->bgcolor; + } else { + if (p->program_type) + auto_placed = 1; + if (info->force_placement[cons]) + auto_placed = 1; + if (!wm) + auto_placed = 0; + if (wm && !wm->doing_autopos) + auto_placed = 0; + + if (!auto_placed && !initially_hidden) { + if (fbui_overlap_check (info, p->x0, p->y0, p->x1, p->y1, + cons, NULL)) + return FBUI_ERR_OVERLAP; + } + } + + win = fbui_add_win (info, cons, auto_placed, + initially_hidden | auto_placed); + if (!win) + return FBUI_ERR_NOMEM; + +/* printk(KERN_INFO "fbui_open: window %s/%d successfully added, location %d %d, %dx%d\n", win->name,win->id,win->x0,win->y0,win->width,win->height); */ + win->program_type = p->program_type; + win->need_keys = p->need_keys; + win->need_motion = p->need_motion; + win->receive_all_motion = p->receive_all_motion; + win->need_placement = auto_placed; + + strncpy (win->name, p->name, FBUI_NAMELEN); + strncpy (win->subtitle, p->subtitle, FBUI_NAMELEN); + + win->max_width = p->max_width; + win->max_height = p->max_height; + + if (p->req_control) { + win->is_wm = 1; + if (p->doing_autoposition) + win->doing_autopos = 1; + + down_write (&info->winptrSem); + info->window_managers [cons] = win; + up_write (&info->winptrSem); + } + + if (vt_cons[cons]->vc_mode != KD_GRAPHICS) { + backup_vc (info, cons); + intercepting_accel = 0; + } + + if (!auto_placed && !initially_hidden && !p->req_control) + fbui_set_geometry (info, win, p->x0,p->y0,p->x1,p->y1); + else { + /* Copy the numbers over verbatim since the wm may find them useful*/ + win->x0 = p->x0; + win->y0 = p->y0; + win->x1 = p->x1; + win->y1 = p->y1; + win->width = p->x1 - p->x0 + 1; + win->height = p->y1 - p->y0 + 1; + } + + win->bgcolor = p->bgcolor; + + if (!win->is_wm && !auto_placed && !initially_hidden) + fbui_clear (info, win); + + down_write (&info->winptrSem); +{struct fbui_window *p = info->keyfocus_window[cons]; +printk(KERN_INFO "fbui_open: cons=%d needkeys=%d keyfocus=%08lx %s %d\n", cons, win->need_keys, (unsigned long)p, p?p->name:"(none)", p?p->id:-1); +} + if (!info->keyfocus_window[cons] && win->need_keys) + info->keyfocus_window[cons] = win; + if (!info->pointerfocus_window[cons] && win->need_motion) + info->pointerfocus_window[cons] = win; + up_write (&info->winptrSem); + + return win->id; +} + + +int fbui_close (struct fb_info *info, short id) +{ + struct fbui_window *win; + + if (!info) + return FBUI_ERR_NULLPTR; + if (id < 0 || id >= (FBUI_MAXWINDOWSPERVC * FBUI_MAXCONSOLES)) + return FBUI_ERR_BADWIN; + /*----------*/ + + win = fbui_lookup_win (info, id); + if (!win) + return FBUI_ERR_NOTOPEN; + + return fbui_remove_win (info, id, 0); +} + + +/* "redraw" forced by window-manager process + */ +int fbui_redraw (struct fb_info *info, struct fbui_window *self, + struct fbui_window *win) +{ + struct fbui_event ev; + + if (!info || !self || !win) + return 0; + if (!self->is_wm) + return FBUI_ERR_NOTWM; + /*----------*/ + + fbui_clear (info, win); + + memset (&ev, 0, sizeof (struct fbui_event)); + ev.type = FBUI_EVENT_EXPOSE; + fbui_enqueue_event (info, win, &ev, 0); + + return FBUI_SUCCESS; +} + + +/* Verify that the process entry array doesn't contain killed processes, + * remove any such entries. + * Verify that the windows on the system are for processes that exist. + * remove any such windows. + */ +static int fbui_clean (struct fb_info *info, int cons) +{ + struct semaphore *sem; + struct rw_semaphore *rwsem; + int i, lim; + + if (!fbui_handler_regd) + return FBUI_SUCCESS; + if (!info) + return FBUI_ERR_NULLPTR; + if (cons < 0 || cons >= FBUI_MAXCONSOLES) + return FBUI_ERR_BADPARAM; + /*----------*/ + + /* Process entry check */ + sem = &info->preSem; + down(sem); + i=0; + while (i < FBUI_MAXCONSOLES * FBUI_MAXWINDOWSPERVC) { + struct fbui_processentry *pre = &info->processentries[i]; + + if (pre->in_use) { + if (!process_exists (pre->pid)) { + printk (KERN_INFO "fbui_clean: removing zombie process entry %d\n", i); + pre->in_use = 0; + pre->waiting = 0; + pre->pid = 0; + pre->nwindows = 0; + } + } + i++; + } + up(sem); + + /* Window struct check */ + rwsem = &info->winptrSem; + i = cons * FBUI_MAXWINDOWSPERVC; + lim = i + FBUI_MAXWINDOWSPERVC; + while (i < lim) { + struct fbui_window *win; + + down_read (rwsem); + win = info->windows [i]; + up_read (rwsem); + + if (win) { + if (!process_exists (win->pid)) { + short id = win->id; + + if (id == i) { + printk (KERN_INFO "fbui_clean: removing zombie window %d\n", i); + fbui_remove_win (info, i, 1); + } else + printk (KERN_INFO "fbui_clean: invalid window entry for window %d\n", id); + } + } + i++; + } + + return FBUI_SUCCESS; +} + + +/* Return the process ids of all windows for this console + * npids initially tells the maximum we can return. + */ +int fbui_window_info (struct fb_info *info, int cons, + /*user*/ struct fbui_wininfo *ary, int ninfo) +{ + struct fbui_window *win; + int i, j, lim; + + if (!info || !ary || ninfo <= 0) + return FBUI_ERR_NULLPTR; + if (!access_ok (VERIFY_WRITE, (void*)ary, + ninfo * sizeof(struct fbui_wininfo))) + return FBUI_ERR_BADADDR; + if (cons < 0 || cons >= FBUI_MAXCONSOLES) + return FBUI_ERR_BADPARAM; + /*----------*/ + + /* Clean up the console */ + fbui_clean (info, cons); + +/*printk(KERN_INFO "fbui_window_info: cons=%d\n", cons);*/ + i = 0; + j = cons * FBUI_MAXWINDOWSPERVC; + lim = j + FBUI_MAXWINDOWSPERVC; + down_read (&info->winptrSem); + while (i < ninfo && j < lim) { + win = info->windows [j]; + if (win && !win->is_wm) { + struct fbui_wininfo wi; + char *ptr; +#if 0 +printk(KERN_INFO " : window %d/%s ", win->id,win->name); +printk(KERN_INFO " : %s %s type=%d\n", win->is_hidden?"hidden":"",win->need_keys?"need_keys","",win->program_type); +#endif + wi.id = win->id; + wi.pid = win->pid; + wi.program_type = win->program_type; + wi.hidden = win->is_hidden; + wi.need_placement = win->need_placement; + wi.need_keys = win->need_keys; + wi.need_motion = win->need_motion; + wi.x = win->x0; + wi.y = win->y0; + wi.width = win->width; + wi.height = win->height; + wi.max_width = win->max_width; + wi.max_height = win->max_height; +/* printk(KERN_INFO "inside wininfo: x %d y %d w %d h %d\n",(int)wi.x,(int)wi.y,(int)wi.width, (int)wi.height); */ + strcpy (wi.name, win->name); + strcpy (wi.subtitle, win->subtitle); + + ptr = (char*) &ary[i]; + + if (copy_to_user (ptr, &wi, sizeof(struct fbui_wininfo))) { + up_read (&info->winptrSem); + return FBUI_ERR_BADADDR; + } + + i++; + } + j++; + } + up_read (&info->winptrSem); + + return i; +} + + +/* Delete the window belonging to a given process, + * as identified by its process id. + */ +int fbui_delete (struct fb_info *info, struct fbui_window *self, + struct fbui_window *win) +{ + int rv; + short id; + struct semaphore *sem; + + if (!info || !self || !win) + return 0; + if (!self->is_wm) + return FBUI_ERR_NOTWM; + /*----------*/ + + id = win->id; + sem = &info->windowSems [id]; + down (sem); + rv = fbui_remove_win (info, win->id, 0); + up (sem); + return FBUI_SUCCESS; +} + + + +static struct fbui_window * + accelerator_test (struct fb_info *info, int cons, unsigned char ch) +{ + if (!info) + return NULL; + if (ch >= FBUI_TOTALACCELS) + return NULL; + if (cons < 0 || cons >= FBUI_MAXCONSOLES) + return NULL; + /*----------*/ + + return info->accelerators [ch + FBUI_TOTALACCELS*cons]; +} + + +/* op==1 to register an accelerator (Alt-key sequence), 0 to unregister + */ +static int fbui_accel (struct fb_info *info, struct fbui_window *win, + short which, short op) +{ + int ix; + + if (!info || !win) + return FBUI_ERR_NULLPTR; + if (which < 0 || which > 127 || op < 0 || op > 1) + return FBUI_ERR_BADPARAM; + /*----------*/ + + ix = which + FBUI_TOTALACCELS * win->console; + + if (op==1) { + if (accelerator_test (info, win->console, which)) + return FBUI_ERR_ACCELBUSY; + + info->accelerators[ix] = win; + } else + info->accelerators[ix] = NULL; + + return FBUI_SUCCESS; +} + + +/* Does not generate WinChange event */ +int fbui_move_resize (struct fb_info *info, struct fbui_window *self, + struct fbui_window *win, + short x, short y, short width, short height) +{ + char result=FBUI_SUCCESS; + short x1, y1; + struct semaphore *sem; + + if (!info || !self || !win) + return 0; + if (!self->is_wm) + return FBUI_ERR_NOTWM; + /*----------*/ + + x1 = x+width-1; + y1 = y+height-1; + + sem = &info->windowSems [win->id]; + down (sem); + + /* If the window is not hidden, verify no overlap. + * If hidden, we don't care. + */ + if (!win->is_hidden) + result = fbui_overlap_check (info, x, y, x1, y1, self->console, win); + + if (!result) { + result = fbui_set_geometry (info, win, x, y, x1, y1); + + if (!result) { + struct fbui_event ev; + + fbui_clear (info, win); + + memset (&ev, 0, sizeof (struct fbui_event)); + ev.type = FBUI_EVENT_MOVE_RESIZE; + ev.x = x; + ev.y = y; + ev.width = x1-x+1; + ev.height = y1-y+1; + fbui_enqueue_event (info, win, &ev, 0); + + /*ev.type = FBUI_EVENT_EXPOSE; + fbui_enqueue_event (info, win, &ev, 0); + */ + + win->need_placement = 0; + } + else + printk (KERN_INFO "set geometry failed -- %s\n",win->name); + } else + printk (KERN_INFO "overlap check failed -- %s\n",win->name); + up (sem); + return result; +} + + + +/* Does not generate WinChange event */ +int fbui_hide (struct fb_info *info, struct fbui_window *self, + struct fbui_window *win) +{ + struct semaphore *sem; + int cons; + + if (!info || !self || !win) + return FBUI_ERR_NULLPTR; + if (!self->is_wm) + return FBUI_ERR_NOTWM; + if (self == win) + return FBUI_ERR_BADPARAM; + cons = self->console; + if (cons != win->console) + return FBUI_ERR_BADPARAM; + /*----------*/ + + if (!win->is_hidden) { + struct fbui_event ev; + struct fbui_window *win2, *wm; + + wm = fbui_lookup_wm (info, cons); + +/* printk(KERN_INFO "Entered fbui_hide: hiding unhidden window %s/%d\n", win->name,win->id); */ + sem = &info->windowSems [win->id]; + down (sem); + if (!wm) { + /* Rule: if there is a window manager running, + * let it decide whether to perform a window clear. + */ + u32 c = win->bgcolor; + win->bgcolor = info->bgcolor [cons]; + fbui_clear (info, win); /* clear to display bgcolor */ + win->bgcolor = c; + } + win->is_hidden = 1; + up (sem); + + memset (&ev, 0, sizeof (struct fbui_event)); + ev.type = FBUI_EVENT_HIDE; + fbui_enqueue_event (info, win, &ev, 0); + + down_read (&info->winptrSem); + win2 = info->pointer_window [info->currcon]; + up_read (&info->winptrSem); + + if (win2 == win) { + memset (&ev, 0, sizeof (struct fbui_event)); + ev.type = FBUI_EVENT_LEAVE; + fbui_enqueue_event (info, win, &ev, 0); + } + } + + return FBUI_SUCCESS; +} + + +/* Does not generate WinChange event */ +int fbui_unhide (struct fb_info *info, struct fbui_window *self, + struct fbui_window *win) +{ + struct semaphore *sem; + struct fbui_event ev; + struct fbui_window *win2; + int cons; + + if (!info || !self || !win) + return 0; + if (!self->is_wm) + return 0; + if (self == win) + return FBUI_ERR_BADPARAM; + cons = self->console; + if (cons != win->console) + return FBUI_ERR_BADPARAM; + if (!win->is_hidden) + return FBUI_SUCCESS; + /*----------*/ + + /* Rule: Don't allow unhide if the window will overlap. + */ + if (fbui_overlap_check (info, win->x0, win->y0, win->x1, win->y1, + cons, win)) + return FBUI_ERR_OVERLAP; + + sem = &info->windowSems [win->id]; + down (sem); + win->is_hidden = 0; + fbui_clear (info, win); + up (sem); + + memset (&ev, 0, sizeof (struct fbui_event)); + ev.type = FBUI_EVENT_UNHIDE; + fbui_enqueue_event (info, win, &ev, 0); + ev.type = FBUI_EVENT_EXPOSE; + fbui_enqueue_event (info, win, &ev, 0); + + down_read (&info->winptrSem); + win2 = get_pointer_window (info); + up_read (&info->winptrSem); + if (win2 == win) { + memset (&ev, 0, sizeof (struct fbui_event)); + ev.type = FBUI_EVENT_ENTER; + fbui_enqueue_event (info, win, &ev, 0); + } + + return FBUI_SUCCESS; +} + + +static struct fbui_processentry *alloc_processentry (struct fb_info *info, + int pid, int cons) +{ + int i; + struct fbui_processentry *pre; + struct semaphore *sem; + + if (!info) + return NULL; + /*----------*/ + + sem = &info->preSem; + down(sem); + i=0; + while (i < FBUI_MAXCONSOLES * FBUI_MAXWINDOWSPERVC) { + pre = &info->processentries[i]; + if (!pre->in_use) { + pre->index = i; + pre->waiting = 0; + pre->pid = pid; + pre->console = cons; + pre->nwindows = 0; + pre->events_head = 0; + pre->events_tail = 0; + pre->events_pending = 0; + init_waitqueue_head(&pre->waitqueue); + pre->window_num = -1; + pre->queuelock = SPIN_LOCK_UNLOCKED; + init_MUTEX (&pre->queuesem); + pre->in_use = 1; + up (sem); + return pre; + } + i++; + } + up (sem); + return NULL; +} + +static void free_processentry (struct fb_info *info, struct fbui_processentry *pre) +{ + struct semaphore *sem; + if (!pre) + return; + /*----------*/ + + sem = &info->preSem; + down (sem); + pre->in_use = 0; + pre->waiting = 0; + pre->pid = 0; + pre->nwindows = 0; + pre->events_head = 0; + pre->events_tail = 0; + pre->events_pending = 0; + up (sem); +} + + + + +int fbui_control (struct fb_info *info, struct fbui_ctrlparams *ctl) +{ + struct fbui_window *self=NULL; + struct fbui_window *win=NULL; + struct fbui_processentry *pre=NULL; + int cons = -1; + char cmd; + short id; + short x, y; + short width, height; + struct fbui_event *event; + unsigned char *pointer; + u32 cutlen; + + if (!info || !ctl) + return FBUI_ERR_NULLPTR; + /*----------*/ + + cmd = ctl->op; + x = ctl->x; + y = ctl->y; + width = ctl->width; + height = ctl->height; + id = ctl->id; + event = ctl->event; + pointer = ctl->pointer; + cutlen = ctl->cutpaste_length; + + if (id < 0) + return FBUI_ERR_BADPARAM; + + if (!(self = fbui_lookup_win (info, id))) + return FBUI_ERR_MISSINGWIN; + + pre = self->processentry; + if (pre->pid != current->pid) + return FBUI_ERR_BADPID; + + if (!pre) + return FBUI_ERR_MISSINGPROCENT; + + cons = pre->console; + if (cons < 0 || cons >= FBUI_MAXCONSOLES) + return FBUI_ERR_BADVC; + if (cons != id / FBUI_MAXWINDOWSPERVC) + return FBUI_ERR_BADVC; + + /* Only poll and wait do not take a window param + */ + if (!self && (cmd != FBUI_POLLEVENT && cmd != FBUI_WAITEVENT)) + return FBUI_ERR_INVALIDCMD; + + if (cmd >= FBUI_CTL_TAKESWIN) { + if (!self->is_wm) + return FBUI_ERR_NOTWM; + if (!(win = fbui_lookup_win (info, ctl->id2))) + return FBUI_ERR_BADPID; + if (win->console != cons) + return FBUI_ERR_WRONGWM; + } + + switch (cmd) { + case FBUI_REDRAW: + return fbui_redraw (info, self, win); + + case FBUI_DELETE: + return fbui_delete (info, self, win); + + case FBUI_MOVE_RESIZE: + return fbui_move_resize (info, self, win, x, y, width, height); + + case FBUI_HIDE: + return fbui_hide (info, self, win); + + case FBUI_UNHIDE: + return fbui_unhide (info, self, win); + + case FBUI_WININFO: + return fbui_window_info (info, cons, ctl->info, ctl->ninfo); + + case FBUI_ACCEL: + return fbui_accel (info, self, ctl->x, ctl->y); + + case FBUI_GETDIMS: { + long value; + if (self->need_placement) + value = FBUI_ERR_NOTPLACED; + else { + value = self->width; + value <<= 16; + value |= self->height; + } + return value; + } + + case FBUI_READMOUSE: { + long value; + value = self->mouse_x; + value <<= 16; + value |= self->mouse_y; + return value; + } + + case FBUI_GETPOSN: { + u32 value; + if (self->need_placement) { + value = FBUI_ERR_NOTPLACED; + } else { + value = self->x0; + value <<= 16; + value |= self->y0; + } + return value; + } + + case FBUI_ASSIGN_KEYFOCUS: + if (!win->is_hidden && win->need_keys && !win->is_wm) { + down_write (&info->winptrSem); + info->keyfocus_window [cons] = win; + up_write (&info->winptrSem); + } + return FBUI_SUCCESS; + + case FBUI_ASSIGN_PTRFOCUS: + if (!win->is_hidden && win->need_motion && !win->is_wm) { + down_write (&info->winptrSem); + info->pointerfocus_window [cons] = win; + up_write (&info->winptrSem); + } + return FBUI_SUCCESS; + + case FBUI_SUBTITLE: + strncpy (self->subtitle, ctl->string, FBUI_NAMELEN); + fbui_winptrs_change (info, self->console); + return FBUI_SUCCESS; + + case FBUI_SETFONT: + if (!access_ok (VERIFY_READ, pointer, FBUI_FONTSIZE)) + return FBUI_ERR_BADADDR; + + if (copy_from_user ((char*) &self->font, pointer, FBUI_FONTSIZE)) + return FBUI_ERR_BADADDR; + + self->font_valid = 1; + return FBUI_SUCCESS; + + case FBUI_POLLEVENT: + case FBUI_WAITEVENT: { + struct fbui_event ev; + + if (!event) + return FBUI_ERR_NULLPTR; + + if (!access_ok (VERIFY_WRITE, (void*)event, sizeof(struct fbui_event))) + return -EFAULT; + + /* Rule: all windows for a process use the same event mask */ + pre->wait_event_mask = x; + + memset (&ev, 0, sizeof (struct fbui_event)); + ev.type = FBUI_EVENT_NONE; + + if (fbui_dequeue_event (info, pre, &ev)) { + if (copy_to_user (event, &ev, sizeof(struct fbui_event))) + return -EFAULT; + else + return FBUI_SUCCESS; + } + + /* No event & polling means exit here */ + if (cmd == FBUI_POLLEVENT) { + pre->waiting = 0; + return FBUI_ERR_NOEVENT; + } + + pre->waiting = 1; + wait_event_interruptible (pre->waitqueue, + pre->events_pending > 0); + + if (fbui_dequeue_event (info, pre, &ev)) { + if (copy_to_user (event, &ev, sizeof(struct fbui_event))) + return -EFAULT; + else + return FBUI_SUCCESS; + } else { +printk (KERN_INFO "XXXXXXXXXX process (pid %d) woken up but no event pending! (pre->nwindows=%d)\n",pre->pid,pre->nwindows); + return FBUI_ERR_NOEVENT; + } + } + + case FBUI_READPOINT: + if (!self->is_wm) + return RGB_NOCOLOR; + else + return info->fbops->fb_read_point ? + info->fbops->fb_read_point (info, x, y) : + RGB_NOCOLOR; + + case FBUI_PLACEMENT: + if (self->is_wm) { + info->force_placement[cons] = x?1:0; + return FBUI_SUCCESS; + } + else + return FBUI_ERR_NOTWM; + + case FBUI_CUT: { /* write to kernel buf */ + unsigned char *ptr; + char err=0; + if (!pointer) + return FBUI_ERR_NULLPTR; + + if (cutlen <= 0) + return FBUI_ERR_BADPARAM; + + if (!access_ok (VERIFY_READ, pointer, cutlen)) + return FBUI_ERR_BADADDR; + + down_write (&info->cutpaste_sem); + ptr = kmalloc (cutlen, GFP_KERNEL); + if (!ptr) + err = 1; + else { + if (copy_from_user (ptr, pointer, cutlen)) { + err = 1; + kfree (ptr); + } else { + /* success */ + if (info->cutpaste_buffer) + kfree (info->cutpaste_buffer); + info->cutpaste_buffer = ptr; + info->cutpaste_length = cutlen; + } + } + up_write (&info->cutpaste_sem); + if (err) + return FBUI_ERR_CUTFAIL; + else + return FBUI_SUCCESS; + } + + case FBUI_CUTLENGTH: + return info->cutpaste_length; + + case FBUI_PASTE: { /* read from kernel buf */ + unsigned char *ptr; + char err = 0; + + if (!pointer) + return FBUI_ERR_NULLPTR; + + if (cutlen <= 0) + return FBUI_ERR_BADPARAM; + + if (!access_ok (VERIFY_WRITE, pointer, cutlen)) + return FBUI_ERR_BADADDR; + + if (info->cutpaste_buffer) + kfree (info->cutpaste_buffer); + down_read (&info->cutpaste_sem); + ptr = info->cutpaste_buffer; + if (ptr) { + u32 len = sizeof(struct fbui_wininfo); + if (cutlen < len) + len = cutlen; + if (copy_to_user (pointer, ptr, len)) + err = 1; + } else + err = 1; + up_read (&info->cutpaste_sem); + if (err) + return FBUI_ERR_PASTEFAIL; + + /* return byte count */ + if (!ptr) + return 0; + else + return cutlen; + } /* paste */ + + default: + return FBUI_ERR_INVALIDCMD; + } +} + + +static char cmdinfo[] = +{ + 0, /* none */ +192+ 6, /* copy area x0,y0,x1,y1,w,h*/ +32+128+ 4, /* point x,y,color lo,hi*/ +32+192+ 6, /* line x0,y0,x1,y1,color lo,hi*/ +32+128+ 5, /* hline x0,x1,color lo,hi,y*/ +32+128+ 5, /* vline y0,y1,color lo,hi,x*/ +32+192+ 6, /* rect x0,y0,x1,y1,color lo,hi*/ +32+192+ 6, /* fill_area x0,y0,x1,y1,color lo,hi*/ + 0, /* clear */ +192+ 4, /* invertline x0,y0,x1,y1*/ +32+128+ 9, /* string x,y,font lo,hi,len, string lo,hi, fgcolor lo,hi*/ +32+128+ 5, /* put pixels x,y,ptr lo,hi,len*/ +32+128+ 5, /* put pixels RGB x,y,ptr lo,hi,len */ +32+128+ 5, /* put pixels RGB 3-byte x,y,ptr lo,hi,len */ +192+ 4, /* clear area x0,y0,x1,y1*/ +32+128+ 9, /* tinyblit x,y,color lo,hi,bgcolor lo,hi,width, bitmap lo,hi */ +}; + + +/* This routine executes commands which can be + * safely ignored when a window is hidden, suspended, or + * not in the foreground console. + */ +int fbui_exec (struct fb_info *info, short win_id, short n, unsigned char *arg) +{ + struct fbui_window *win=NULL; + unsigned char *argmax = arg + n * 2; + int result = FBUI_SUCCESS; + char initial_hide=0; + + if (!info || !arg) + return FBUI_ERR_NULLPTR; + if (win_id < 0 || win_id >= (FBUI_MAXWINDOWSPERVC * FBUI_MAXCONSOLES)) + return FBUI_ERR_BADWIN; + if (info->fix.visual != FB_VISUAL_TRUECOLOR && + info->fix.visual != FB_VISUAL_DIRECTCOLOR) + return FBUI_ERR_WRONGVISUAL; + if (n < 0) + return FBUI_ERR_INVALIDCMD; /* XX */ + /*----------*/ + + if (!(win = fbui_lookup_win (info, win_id))) + return FBUI_ERR_BADWIN; + if (win->pid != current->pid) + return FBUI_ERR_BADWIN; + if (win->is_hidden) + return FBUI_SUCCESS; + + down (&info->windowSems [win->id]); + win->drawing = 1; + + initial_hide = info->pointer_hidden; + + while (!result && arg < argmax && !win->is_hidden) + { + unsigned short ary [20]; + short len; + short a=0, b=0, c=0, d=0, wid=0, ht=0; + u32 ptr=0; + unsigned short cmd; + unsigned char flags; + unsigned short ix; + u32 param32=0; + + if (get_user (cmd, arg)) { + result = FBUI_ERR_BADADDR; + break; + } + arg += 2; + + if (cmd > sizeof (cmdinfo)) { + result = FBUI_ERR_INVALIDCMD; + break; + } + + flags = cmdinfo[cmd]; + if ((len = 2 * (flags & 31))) { + if (copy_from_user (ary, arg, len)) { + result = FBUI_ERR_BADADDR; + break; + } + } + arg += len; + + ix = 0; + if (flags & 128) { + a = ary[ix++]; + b = ary[ix++]; + } + if (flags & 64) { + c = ary[ix++]; + d = ary[ix++]; + } + if (flags & 32) { + param32 = ary[ix+1]; + param32 <<= 16; + param32 |= ary[ix]; + ix+=2; + } + + switch(cmd) { + case FBUI_CLEAR: + result = fbui_clear (info,win); + if (result) + goto finished; + break; + + case FBUI_POINT: + result = fbui_draw_point (info,win, a,b,param32); + if (result) + goto finished; + break; + + case FBUI_INVERTLINE: + win->do_invert = 1; + result = fbui_draw_line (info,win, a,b,c,d,0); + win->do_invert = 0; + if (result) + goto finished; + break; + + case FBUI_LINE: + result = fbui_draw_line (info,win, a,b,c,d,param32); + if (result) + goto finished; + break; + + case FBUI_HLINE: + c = ary[ix++]; + result = fbui_draw_hline (info,win,a,b,c,param32); + if (result) + goto finished; + break; + + case FBUI_TINYBLIT: { + u32 bits; + u32 bgcolor; + short width; + + /* a = x + * b = y + * param32 = fgcolor + */ + bgcolor = ary[ix+1]; + bgcolor <<= 16; + bgcolor |= ary[ix]; + ix += 2; + + width = ary[ix++]; + + bits = ary[ix+1]; + bits <<= 16; + bits |= ary[ix]; + ix += 2; + +/* printk(KERN_INFO "FBUI_TINYBLIT: x=%d y=%d width=%d fgcolor=%08lx bgcolor=%08lx bits=%08lx\n", a,b,width,param32,bgcolor,bits); */ + + result = fbui_tinyblit (info,win,a,b,width,param32,bgcolor,bits); + if (result) + goto finished; + break; + } + + case FBUI_VLINE: + c = ary[ix++]; + result = fbui_draw_vline (info,win,c,a,b,param32); + if (result) + goto finished; + break; + + case FBUI_RECT: + result = fbui_draw_rect (info,win,a,b,c,d,param32); + if (result) + goto finished; + break; + + case FBUI_FILLAREA: + result = fbui_fill_area (info,win,a,b,c,d,param32); + if (result) + goto finished; + break; + + case FBUI_CLEARAREA: + result = fbui_clear_area (info,win,a,b,c,d); + if (result) + goto finished; + break; + + case FBUI_PUT: + wid = ary[ix++]; + result= fbui_put (info,win, a,b,wid, (unsigned char*)param32); + if (result) + goto finished; + break; + + case FBUI_PUTRGB: + wid = ary[ix++]; + result= fbui_put_rgb (info,win,a,b,wid, (unsigned long*)param32); + if (result) + goto finished; + break; + + case FBUI_PUTRGB3: + wid = ary[ix++]; + result= fbui_put_rgb3 (info,win, a,b,wid, (unsigned char*)param32); + if (result) + goto finished; + break; + + case FBUI_COPYAREA: + wid = ary[ix++]; + ht = ary[ix++]; + result = fbui_copy_area (info,win,a,b, wid,ht,c,d); + if (result) + goto finished; + break; + + case FBUI_STRING: { + struct fbui_font *font = &win->font; + u32 color; + wid = ary[ix++]; + + ptr = ary[ix+1]; + ptr <<= 16; + ptr |= ary[ix]; + ix += 2; + + if (!ptr) { + result = FBUI_ERR_NULLPTR; + goto finished; + } + + color = ary[ix+1]; + color <<= 16; + color |= ary[ix]; + ix += 2; + + if (!param32) { + if (!win->font_valid) { + result = FBUI_ERR_NOFONT; + goto finished; + } + } else { + if (!access_ok (VERIFY_READ, (void*)param32, FBUI_FONTSIZE)) { + result = FBUI_ERR_BADADDR; + goto finished; + } + if (copy_from_user ((char*)font,(char*)param32,FBUI_FONTSIZE)) { + result = FBUI_ERR_BADADDR; + goto finished; + } + + win->font_valid = 1; + } + + if (!access_ok (VERIFY_READ, (void*)ptr, wid)) { + result = FBUI_ERR_BADADDR; + goto finished; + } + result = fbui_draw_string (info,win,font,a,b, + (unsigned char*) ptr, color); + if (result) + goto finished; + break; + } + + } /* switch */ + } +finished: + if (!initial_hide && info->pointer_hidden) + fbui_unhide_pointer (info); + + win->drawing = 0; + up (&info->windowSems [win->id]); + return result; +} + + +/* This is provided for completeness sake. + * The current fbdump actually uses mmap(). + */ +u32 fb_read_point (struct fb_info *info, short x, short y) +{ + u32 bytes_per_pixel, offset, value; + unsigned char *ptr; + + if (!info || info->state != FBINFO_STATE_RUNNING) + return RGB_NOCOLOR; + if (x < 0 || y < 0 || x >= info->var.xres || y >= info->var.yres) + return RGB_NOCOLOR; + /*----------*/ + + bytes_per_pixel = (info->var.bits_per_pixel + 7) >> 3; + offset = y * info->fix.line_length + x * bytes_per_pixel; + ptr = offset + ((unsigned char*)info->screen_base); + + value = 0; + switch (bytes_per_pixel) { + case 4: + value = fb_readl (ptr); + break; + case 3: { + u32 tmp; + value = 0xff & fb_readb (ptr); + ptr++; + tmp = 0xff & fb_readb (ptr); + ptr++; + tmp <<= 8; + value |= tmp; + tmp = 0xff & fb_readb (ptr); + tmp <<= 16; + value |= tmp; + break; + } + case 2: + value = fb_readw (ptr); + break; + case 1: + value = fb_readb (ptr); + break; + } + + return pixel_to_rgb (info, value); +} + + +short fb_getpixels_rgb (struct fb_info *info, short x, short y, short n, + unsigned long *dest, char in_kernel) +{ + short xres, yres; + short i; + + if (!info || !dest) + return FBUI_ERR_NULLPTR; + if (n <= 0 || x < 0 || y < 0) + return 0; + xres = info->var.xres; + yres = info->var.yres; + if (x >= xres) + return 0; + if (y >= yres) + return 0; + if (x+n >= xres) + n = xres-x; + /*----------*/ + + i=n; + while (i > 0) { + u32 rgb = fb_read_point (info, x, y); + if (in_kernel) { + *dest++ = rgb; + } else { + /* not needed? */ + } + x++; + i--; + } + return n; +} + + +static int fbui_draw_point (struct fb_info *info, struct fbui_window *win, + short x, short y, u32 color) +{ + short mx,my; + if (!info || !win) + return FBUI_ERR_NULLPTR; + if (info->state != FBINFO_STATE_RUNNING) + return FBUI_ERR_NOTRUNNING; + if (win->console != info->currcon) + return FBUI_SUCCESS; + if (win->is_hidden) + return FBUI_SUCCESS; + if (x < 0 || y < 0 || x >= win->width || y >= win->height) + return 0; + /*----------*/ + x += win->x0; + y += win->y0; + + if (!info->have_hardware_pointer && info->pointer_active && !info->pointer_hidden) { + short mx1; + short my1; + mx = info->mouse_x0; + my = info->mouse_y0; + mx1 = info->mouse_x1; + my1 = info->mouse_y1; + + if (x >= mx && y >= my && x <= mx1 && y <= my1) + fbui_hide_pointer (info); + } + + if (info->fbops->fb_point) + info->fbops->fb_point (info, x, y, color, win->do_invert); + + return FBUI_SUCCESS; +} + + +static int fbui_draw_line (struct fb_info *info, struct fbui_window *win, + short x0, short y0, short x1, short y1, u32 color) +{ + int dx, dy, e, j, xchange; + char s1, s2; + short x, y; + + if (!info || !win) + return FBUI_ERR_NULLPTR; + if (info->state != FBINFO_STATE_RUNNING) + return FBUI_ERR_NOTRUNNING; + if (win->console != info->currcon) + return FBUI_SUCCESS; + if (win->is_hidden) + return FBUI_SUCCESS; + if (x0 < 0 && x1 < 0) + return 0; + if (y0 < 0 && y1 < 0) + return 0; + j = win->width; + if (x0 >= j && x1 >= j) + return 0; + j = win->height; + if (y0 >= j && y1 >= j) + return 0; + /*----------*/ + + if (!win->do_invert) { + if (x0==x1) { + if (y0==y1) + return fbui_draw_point (info,win,x0,y0,color); + else + return fbui_draw_vline (info,win,x0,y0,y1,color); + } + else + if (y0==y1) { + return fbui_draw_hline (info,win,x0,x1,y0,color); + } + } + + /* Bresenham */ + s1 = 1; + s2 = 1; + x = x0; + y = y0; + + dx = x1-x0; + if (dx < 0) { + dx = -dx; + s1 = -1; + } + + dy = y1-y0; + if (dy < 0) { + dy = -dy; + s2 = -1; + } + + xchange = 0; + + if (dy>dx) { + int tmp = dx; + dx = dy; + dy = tmp; + xchange = 1; + } + + e = (dy<<1) - dx; + for (j=0; j <= dx; j++) + { + fbui_draw_point (info,win,x,y,color); + + if (e >= 0) { + if (xchange) + x += s1; + else + y += s2; + e -= (dx << 1); + } + if (xchange) + y += s2; + else + x += s1; + e += (dy << 1); + } + + return FBUI_SUCCESS; +} + + +static int fbui_tinyblit (struct fb_info *info, struct fbui_window *win, + short x_, short y, short width_, u32 fg, u32 bg, u32 bitmap_) +{ + u32 native_fg=0; + u32 native_bg=0; + u32 bytes_per_pixel; + u32 offset; + u32 bitmap = bitmap_; + unsigned char *ptr; + unsigned char do_bg, width=width_; + short x1; + short x, x0; + + if (!info || !win) + return FBUI_ERR_NULLPTR; + if (x_ >= win->width) + return 0; + if (y < 0 || y >= win->height) + return 0; + if (width > 32) + width = 32; + x0 = win->x0; + x1 = x0 + win->width; + x = x0 + x_; + if (x0 + width <= 0) + return 0; + /*----------*/ + + y += win->y0; + + if (!info->have_hardware_pointer && info->pointer_active && !info->pointer_hidden) { + short x2 = x + width - 1; + short mx = info->mouse_x0; + short my = info->mouse_y0; + short mx1 = info->mouse_x1; + short my1 = info->mouse_y1; + if (y >= my && y <= my1) { + if ((mx >= x && mx <= x2) || (mx1 >= x && mx1 <= x2) || + (x >= mx && x <= mx1)) + fbui_hide_pointer (info); + } + } + + bytes_per_pixel = (info->var.bits_per_pixel + 7) >> 3; + offset = y * info->fix.line_length + x * bytes_per_pixel; + ptr = ((unsigned char*)info->screen_base); + ptr += offset; + + bitmap <<= (32 - width); + + native_fg = pixel_from_rgb (info, fg); + do_bg = !(bg & 0xff000000); + if (do_bg) + native_bg = pixel_from_rgb (info, bg); + + while (width--) { + if (x >= x1) + break; + if (x >= x0) { + u32 c = native_fg; + u32 bit = bitmap >> 31; + if (!bit) + c = native_bg; + + if (bit || (!bit && do_bg)) + { + switch (bytes_per_pixel) + { + case 1: fb_writeb (c, ptr); break; + case 2: fb_writew (c, ptr); break; + case 4: fb_writel (c, ptr); break; + case 3: + fb_writeb (c, ptr); ptr++; c >>= 8; + fb_writeb (c, ptr); ptr++; c >>= 8; + fb_writeb (c, ptr); + ptr -= 2; + break; + } + } + } + + bitmap <<= 1; + ptr += bytes_per_pixel; + x++; + + if (!do_bg && !bitmap) + break; + } + + return FBUI_SUCCESS; +} + + +static int fbui_draw_hline (struct fb_info *info, struct fbui_window *win, + short x0, short x1, short y, u32 color) +{ + int i; + short mx,my; + short mx1,my1; + + if (!info || !win) + return FBUI_ERR_NULLPTR; + if (info->state != FBINFO_STATE_RUNNING) + return FBUI_ERR_NOTRUNNING; + if (win->console != info->currcon) + return FBUI_SUCCESS; + if (win->is_hidden) + return FBUI_SUCCESS; + if (x0>x1) { + short tmp=x0; x0=x1; x1=tmp; + } + if (y < 0 || y >= win->height) + return 0; + i = win->width; + if (x0 >= i || x1 < 0) + return 0; + if (x0 < 0) + x0 = 0; + if (x1 >= i) + x1 = i-1; + /*----------*/ + + x0 += win->x0; + x1 += win->x0; + y += win->y0; + + if (!info->have_hardware_pointer && info->pointer_active && !info->pointer_hidden) { + mx = info->mouse_x0; + my = info->mouse_y0; + mx1 = info->mouse_x1; + my1 = info->mouse_y1; + if (y >= my && y <= my1) { + if ((mx >= x0 && mx <= x1) || (mx1 >= x0 && mx1 <= x1) || + (x0 >= mx && x0 <= mx1)) + fbui_hide_pointer (info); + } + } + + if (info->fbops->fb_hline) + info->fbops->fb_hline (info, x0, x1, y, color); + + return FBUI_SUCCESS; +} + + +static int fbui_draw_vline (struct fb_info *info, struct fbui_window *win, + short x, short y0, short y1, u32 color) +{ + short i; + short mx,my; + short mx1,my1; + + if (!info || !win) + return FBUI_ERR_NULLPTR; + if (info->state != FBINFO_STATE_RUNNING) + return FBUI_ERR_NOTRUNNING; + if (win->console != info->currcon) + return FBUI_SUCCESS; + if (win->is_hidden) + return FBUI_SUCCESS; + if (y0>y1) { + short tmp=y0; y0=y1; y1=tmp; + } + if (x < 0 || x >= win->width) + return 0; + i = win->height; + if (y1 < 0 || y0 >= i) + return 0; + if (y0 < 0) + y0 = 0; + if (y1 >= i) + y1 = i-1; + /*----------*/ + + x += win->x0; + y0 += win->y0; + y1 += win->y0; + + if (!info->have_hardware_pointer && info->pointer_active && !info->pointer_hidden) { + mx = info->mouse_x0; + my = info->mouse_y0; + mx1 = info->mouse_x1; + my1 = info->mouse_y1; + if (x >= mx && x < mx1) { + if ((my >= y0 && my <= y1) || (my1 >= y0 && my1 <= y1) || + (y0 >= my && y0 <= my1)) + fbui_hide_pointer (info); + } + } + + if (info->fbops->fb_vline) + info->fbops->fb_vline (info, x, y0, y1, color); + + return FBUI_SUCCESS; +} + + +static int fbui_draw_rect (struct fb_info *info, struct fbui_window *win, + short x0, short y0, short x1, short y1, u32 color) +{ + int retval; + + if (!info || !win) + return FBUI_ERR_NULLPTR; + if (info->state != FBINFO_STATE_RUNNING) + return FBUI_ERR_NOTRUNNING; + if (win->console != info->currcon) + return FBUI_SUCCESS; + if (win->is_hidden) + return FBUI_SUCCESS; + /*----------*/ + + if ((retval = fbui_draw_hline (info, win, x0, x1, y0, color))) + return retval; + if ((retval = fbui_draw_hline (info, win, x0, x1, y1, color))) + return retval; + if ((retval = fbui_draw_vline (info, win, x0, y0, y1, color))) + return retval; + if ((retval = fbui_draw_vline (info, win, x1, y0, y1, color))) + return retval; + + return FBUI_SUCCESS; +} + + +static int fbui_clear_area (struct fb_info *info, struct fbui_window *win, + short x0, short y0, short x1, short y1) +{ + if (!info || !win) + return FBUI_ERR_NULLPTR; + /*----------*/ + + return fbui_fill_area (info,win,x0,y0,x1,y1, win->bgcolor); +} + + +static int fbui_fill_area (struct fb_info *info, struct fbui_window *win, + short x0, short y0, short x1, short y1, u32 color) +{ + int i; + + if (!info || !win) + return FBUI_ERR_NULLPTR; + if (info->state != FBINFO_STATE_RUNNING) + return FBUI_ERR_NOTRUNNING; + if (win->console != info->currcon) + return FBUI_SUCCESS; + if (win->is_hidden) + return FBUI_SUCCESS; + if (x0>x1) { + short tmp=x0; x0=x1; x1=tmp; + } + if (y0>y1) { + short tmp=y0; y0=y1; y1=tmp; + } + /*----------*/ + + i = y0; + while (i <= y1) + fbui_draw_hline (info, win, x0, x1, i++, color); + + return FBUI_SUCCESS; +} + + +int fbui_clear (struct fb_info *info, struct fbui_window *win) +{ + if (!info || !win) + return FBUI_ERR_NULLPTR; + if (info->state != FBINFO_STATE_RUNNING) + return FBUI_ERR_NOTRUNNING; + if (win->console != info->currcon) + return FBUI_SUCCESS; + if (win->is_hidden) + return FBUI_SUCCESS; + if (win->is_wm) + return FBUI_SUCCESS; + /*----------*/ + +/* printk(KERN_INFO "Entered fbui_clear, window %s %d\n", win->name,win->id); */ + + fbui_clear_area (info, win, 0,0, win->width-1,win->height-1); + + /* Following is needed since fbui_clear called from many places, + * not just fbui_exec which does its own unhide + */ + fbui_unhide_pointer (info); + + return FBUI_SUCCESS; +} + + +static unsigned char leftshift[4] = { + 24, 16, 8, 0 +}; + + + +/* Returns width of string if > 0, else an error code + */ +static int fbui_draw_string (struct fb_info *info, struct fbui_window *win, + struct fbui_font *font, + short x, short y, unsigned char *str, u32 color) +{ + unsigned char *bitmap, bitwidth, bitheight; + short ytop, total_width = 0; + short j; + + if (!info || !win || !font || !str) + return FBUI_ERR_NULLPTR; + if (win->console != info->currcon) + return FBUI_SUCCESS; + if (win->is_hidden) + return FBUI_SUCCESS; + if (info->state != FBINFO_STATE_RUNNING) + return FBUI_ERR_NOTRUNNING; + if (x >= win->width) + return 0; + if (y + (font->ascent + font->descent) <= 0) + return 0; + if (y >= win->height) + return 0; + /*----------*/ + + while (x < win->width) + { + char left, descent; + unsigned char ch; + unsigned char width; + + if (get_user (ch, str)) + return FBUI_ERR_BADADDR; + if (!ch) + break; + str++; + + if (ch < font->first_char || ch > font->last_char) + continue; + + ch -= font->first_char; + if (ch >= 128 && ch < 160) { + /* our PCF Fonts move [128,159] to end */ + ch &= 31; + ch |= 240; + } + else if (ch >= 160) + ch -= 32; + + if (get_user (bitmap, &font->bitmaps[ch]) + || get_user (bitwidth, &font->bitwidths[ch]) + || get_user (bitheight, &font->heights[ch]) + || get_user (width, &font->widths[ch]) + || get_user (left, &font->lefts[ch]) + || get_user (descent, &font->descents[ch])) + return FBUI_ERR_BADADDR; + + if (!bitmap || !bitwidth || !bitheight || !width) + continue; + + ytop = font->ascent + descent; + ytop -= bitheight; + + /* Draw loop */ + j = 0; + while (j < bitheight) + { + unsigned long bits; + short current_x; + short current_y = y + j + ytop; + unsigned char datum; + unsigned char bytes_per_row; + + bytes_per_row = (bitwidth+7)/8; + if (current_y < 0) { + bitmap += bytes_per_row; + goto ds_inner_skip; + } + if (current_y >= win->height) + break; + + current_x = x + left; + bits = 0; + + switch (bytes_per_row) { + case 4: + if (get_user (datum, bitmap)) + return FBUI_ERR_BADADDR; + bitmap++; + bits |= datum; + case 3: + bits <<= 8; + if (get_user (datum, bitmap)) + return FBUI_ERR_BADADDR; + bitmap++; + bits |= datum; + case 2: + bits <<= 8; + if (get_user (datum, bitmap)) + return FBUI_ERR_BADADDR; + bitmap++; + bits |= datum; + case 1: + bits <<= 8; + if (get_user (datum, bitmap)) + return FBUI_ERR_BADADDR; + bitmap++; + bits |= datum; + } + + bits <<= leftshift [bytes_per_row-1]; + + fbui_tinyblit (info, win, current_x, current_y, bitwidth, + color, RGB_NOCOLOR, + bits); + +ds_inner_skip: + j++; + } + + x += width; + total_width += width; + + } /* char loop */ + + return total_width; +} + + + +static int fbui_set_geometry (struct fb_info *info, struct fbui_window *win, + short x0, short y0, short x1, short y1) +{ + short xres, yres; + short w,h; + + if (!info || !win) + return FBUI_ERR_NULLPTR; + xres=info->var.xres; + yres=info->var.yres; + if (x0>x1) { + int tmp=x0; x0=x1; x1=tmp; + } + if (y0>y1) { + int tmp=y0; y0=y1; y1=tmp; + } + if (x1<0 || x0>=xres) + return FBUI_ERR_OFFSCREEN; + if (y1<0 || y0>=yres) + return FBUI_ERR_OFFSCREEN; + if (x0<0) + x0=0; + if (y0<0) + y0=0; + if (x1>=xres) + x1=xres-1; + if (y1>=yres) + y1=yres-1; + /*----------*/ + + w = x1-x0+1; + h = y1-y0+1; + if (win->max_width && w > win->max_width) + w = win->max_width; + if (win->max_height && h > win->max_height) + h = win->max_height; + + win->x0 = x0; + win->y0 = y0; + win->x1 = x0 + w - 1; + win->y1 = y0 + h - 1; + win->width = w; + win->height = h; +/* printk (KERN_INFO "fbui_set_geometry: %s (id=%d) is now at %d %d %d %d , wh = %d %d\n",win->name,win->id,x0,y0,x0+w-1,y0+h-1,w,h); */ + + return FBUI_SUCCESS; +} + + +/* Each pixel is 4 bytes, with 4th being transparency (!=0 => 100% transparent) + */ +void fb_putpixels_rgb (struct fb_info *info, short x, short y, + short n, unsigned long *src, char in_kernel) +{ + int offset; + u32 bytes_per_pixel; + unsigned char *ptr; + int i; + u32 *src2; + short xres, yres; + + if (!info || !src || n<=0) + return; + if (n <= 0 || y < 0) + return; + yres = info->var.yres; + if (y >= yres) + return; + xres = info->var.xres; + if (x < 0) { + n += x; + x = 0; + } + if (x+n < 0) + return; + if (x >= xres) + return; + if ((x+n) >= xres) + n = xres - x; + /*----------*/ + + bytes_per_pixel = (info->var.bits_per_pixel + 7) >> 3; + offset = y * info->fix.line_length + x * bytes_per_pixel; + ptr = info->screen_base; + if (!ptr) { + return; + } + ptr += offset; + + src2 = (u32*) src; + i=n; + while (i > 0) { + u32 value; + if (in_kernel) { + value = *src2++; + } else { + if (get_user(value, src2)) + return; + src2++; + } + + /* XX real transparency is for later */ + if (!(0xff000000 & value)) { + value = pixel_from_rgb (info, value); + + switch (bytes_per_pixel) + { + case 4: + fb_writel (value, ptr); + ptr += 4; + break; + + case 3: + fb_writeb (value, ptr); ptr++; value >>= 8; + fb_writeb (value, ptr); ptr++; value >>= 8; + fb_writeb (value, ptr); ptr++; + break; + + case 2: + fb_writew (value, ptr); + ptr += 2; + break; + + case 1: + fb_writeb (value, ptr); + *ptr++ = value; + break; + + default: + break; + } + } else { + ptr += bytes_per_pixel; + } + i--; + } +} + +void fb_putpixels_native (struct fb_info *info, short x,short y, + short n, unsigned char *src, char in_kernel) +{ + short bytes_per_pixel; + u32 offset; + unsigned char *ptr; + int i; + + if (!info || !src || n<=0) + return; + /*----------*/ + + bytes_per_pixel = (info->var.bits_per_pixel + 7) >> 3; + offset = y * info->fix.line_length + x * bytes_per_pixel; + ptr = info->screen_base; + if (!ptr) + return; + ptr += offset; + + n *= bytes_per_pixel; + i=n; + while (i > 0) { + unsigned char value; + if (in_kernel) { + value = *src++; + } else { + if (get_user(value, src)) + return; + src++; + } + fb_writeb (value, ptr); + ptr++; + i--; + } +} + +void fb_putpixels_rgb3 (struct fb_info *info, short x,short y, + short n, unsigned char *src, char in_kernel) +{ + u32 bytes_per_pixel; + u8 *src2; + int offset; + unsigned char *ptr; + int i; + + if (!info || !src || n<=0) + return; + /*----------*/ + + bytes_per_pixel = (info->var.bits_per_pixel + 7) >> 3; + offset = y * info->fix.line_length + x * bytes_per_pixel; + ptr = info->screen_base; + if (!ptr) + return; + + ptr += offset; + + src2 = (u8*) src; + i=n; + while (i > 0) { + u32 value; + u32 r,g,b; + u8 byte; + if (in_kernel) { + r = *src2++; + g = *src2++; + b = *src2++; + } else { + if (get_user(byte, src2)) { + return; + } + src2++; + r = byte; + if (get_user(byte, src2)) { + return; + } + g = byte; + src2++; + if (get_user(byte, src2)) { + return; + } + b = byte; + src2++; + } + + r >>= (8 - info->var.red.length); + g >>= (8 - info->var.green.length); + b >>= (8 - info->var.blue.length); + r <<= info->var.red.offset; + g <<= info->var.green.offset; + b <<= info->var.blue.offset; + value = r | g | b; + + switch (bytes_per_pixel) + { + case 4: + fb_writel (value, ptr); + ptr += 4; + break; + + case 3: + fb_writeb (value, ptr); ptr++; value >>= 8; + fb_writeb (value, ptr); ptr++; value >>= 8; + fb_writeb (value, ptr); ptr++; + break; + + case 2: + fb_writew (value, ptr); + ptr += 2; + break; + + case 1: + fb_writeb (value, ptr); + *ptr++ = value; + break; + + default: + break; + } + i--; + } +} + + +static int fbui_put (struct fb_info *info, struct fbui_window *win, + short x,short y, short n, unsigned char *src) +{ + u32 length; + int bytes_per_pixel; + short mx,my; + int i; + + if (!info || !win || !src) + return FBUI_ERR_NULLPTR; + if (info->state != FBINFO_STATE_RUNNING) + return FBUI_ERR_NOTRUNNING; + if (win->console != info->currcon) + return FBUI_SUCCESS; + if (win->is_hidden) + return FBUI_SUCCESS; + + bytes_per_pixel = (info->var.bits_per_pixel + 7) >> 3; + length = bytes_per_pixel * n; + if (!access_ok (VERIFY_READ,(void*)src, length)) + return FBUI_ERR_BADADDR; + if (x >= win->width || y<0 || y >= win->height || (x+n-1) < 0) + return 0; + if (x < 0) { + x = -x; + n -= x; + src += x * bytes_per_pixel; + x = 0; + } + i = x+n-1; + if (i >= win->width) { + short dif = i - win->width; + n -= dif; + n--; + } + if (info->var.red.length > 8 || + info->var.green.length > 8 || + info->var.blue.length > 8) + return FBUI_ERR_BIGENDIAN; + /*----------*/ + + x += win->x0; + y += win->y0; + + if (!info->have_hardware_pointer && info->pointer_active && !info->pointer_hidden) { + short mx1,my1; + mx = info->mouse_x0; + my = info->mouse_y0; + mx1 = info->mouse_x1; + my1 = info->mouse_y1; + if (y >= my && y <= my1) { + if ((mx >= x && mx < x+n) || (mx1 >= x && mx1 < x+n)) + fbui_hide_pointer (info); + } + } + + if (info->fbops->fb_putpixels_native) + info->fbops->fb_putpixels_native (info, x, y, n, src, 0); + + return FBUI_SUCCESS; +} + + +/* Source data are supposed to be ulong aligned, + * and stored as RGBxRGBx... where x is unused. + * + * XX perhaps later, transparency would be nice. + */ +static int fbui_put_rgb (struct fb_info *info, struct fbui_window *win, + short x, short y,short n, unsigned long *src) +{ + u32 length; + short mx,my; + short mx1,my1; + int i; + + if (!info || !win || !src) + return FBUI_ERR_NULLPTR; + if (info->state != FBINFO_STATE_RUNNING) + return FBUI_ERR_NOTRUNNING; + if (win->console != info->currcon) + return FBUI_SUCCESS; + if (win->is_hidden) + return FBUI_SUCCESS; + length = n << 2; + if (!access_ok (VERIFY_READ,(void*)src, length)) + return FBUI_ERR_BADADDR; + if (x >= win->width || y<0 || y >= win->height || (x+n-1) < 0) + return 0; + if (x < 0) { + n += x; + src -= x; + x = 0; + } + i = x+n-1; + if (i >= win->width) { + short dif = i - win->width; + n -= dif; + n--; + } + if (info->var.red.length > 8 || + info->var.green.length > 8 || + info->var.blue.length > 8) + return FBUI_ERR_BIGENDIAN; + /*----------*/ + + x += win->x0; + y += win->y0; + + if (!info->have_hardware_pointer && info->pointer_active && !info->pointer_hidden) { + mx = info->mouse_x0; + my = info->mouse_y0; + mx1 = info->mouse_x1; + my1 = info->mouse_y1; + if (y >= my && y <= my1) { + if ((mx >= x && mx < x+n) || (mx1 >= x && mx1 <= x+n)) + fbui_hide_pointer (info); + } + } + + if (info->fbops->fb_putpixels_rgb) + info->fbops->fb_putpixels_rgb (info, x, y, n, src, 0); + + return FBUI_SUCCESS; +} + + + + +/* same as fbui_put_rgb, except the source data are RGBRGBRGB... */ + +static int fbui_put_rgb3 (struct fb_info *info, struct fbui_window *win, + short x,short y, short n, unsigned char *src) +{ + u32 length; + int i; + + if (!info || !win || !src) + return FBUI_ERR_NULLPTR; + if (info->state != FBINFO_STATE_RUNNING) + return FBUI_ERR_NOTRUNNING; + if (win->console != info->currcon) + return FBUI_SUCCESS; + if (win->is_hidden) + return FBUI_SUCCESS; + if (!src) + return FBUI_ERR_NULLPTR; + length = n * 3; + if (!access_ok (VERIFY_READ,(void*)src, length)) + return FBUI_ERR_BADADDR; + if (x >= win->width || y<0 || y >= win->height || (x+n-1) < 0) + return 0; + if (x < 0) { + x = -x; + n -= x; + src += x * 3; + x = 0; + } + i = x+n-1; + if (i >= win->width) { + short dif = i - win->width; + n -= dif; + n--; + } + if (info->var.red.length > 8 || + info->var.green.length > 8 || + info->var.blue.length > 8) + return FBUI_ERR_BIGENDIAN; + /*----------*/ + + x += win->x0; + y += win->y0; + + if (!info->have_hardware_pointer && info->pointer_active && !info->pointer_hidden) { + short mx,my; + short mx1, my1; + mx = info->mouse_x0; + my = info->mouse_y0; + mx1 = info->mouse_x1; + my1 = info->mouse_y1; + if (y >= my && y <= my1) { + if ((mx >= x && mx < x+n) || (mx1 >= x && mx1 <= x+n)) + fbui_hide_pointer (info); + } + } + + if (info->fbops->fb_putpixels_rgb3) + info->fbops->fb_putpixels_rgb3 (info, x, y, n, src, 0); + + return FBUI_SUCCESS; +} + + + +static void fbui_copy_within (unsigned char *dest, unsigned char *src, u32 n) +{ + int dif = dest < src ? src - dest : dest - src; + while (n) { + if (dif >= 4 && n >= 64 && !(3 & (u32)src) && !(3 & (u32)dest)){ + fb_writel (fb_readl (src), dest); src+=4; dest+=4; + fb_writel (fb_readl (src), dest); src+=4; dest+=4; + fb_writel (fb_readl (src), dest); src+=4; dest+=4; + fb_writel (fb_readl (src), dest); src+=4; dest+=4; + fb_writel (fb_readl (src), dest); src+=4; dest+=4; + fb_writel (fb_readl (src), dest); src+=4; dest+=4; + fb_writel (fb_readl (src), dest); src+=4; dest+=4; + fb_writel (fb_readl (src), dest); src+=4; dest+=4; + fb_writel (fb_readl (src), dest); src+=4; dest+=4; + fb_writel (fb_readl (src), dest); src+=4; dest+=4; + fb_writel (fb_readl (src), dest); src+=4; dest+=4; + fb_writel (fb_readl (src), dest); src+=4; dest+=4; + fb_writel (fb_readl (src), dest); src+=4; dest+=4; + fb_writel (fb_readl (src), dest); src+=4; dest+=4; + fb_writel (fb_readl (src), dest); src+=4; dest+=4; + fb_writel (fb_readl (src), dest); src+=4; dest+=4; + n -= 64; + } else { + fb_writeb (fb_readb (src), dest); src++; dest++; + n--; + } + } +} + + +/* XX Would be nice to be able to halt the copy prematurely when window gets hidden. + */ +void fb_copyarea (struct fb_info *info, + short xsrc,short ysrc,short w, short h, + short xdest,short ydest) +{ + u32 bytes_per_pixel, offset, linelen; + unsigned char *src; + unsigned char *dest; + int n; + + if (!info || w<=0 || h<=0) + return; + /*----------*/ + + bytes_per_pixel = (info->var.bits_per_pixel + 7) >> 3; + linelen = info->fix.line_length; + offset = ysrc * linelen + xsrc * bytes_per_pixel; + src = info->screen_base; + if (!src) + return; + + dest = src; + src += offset; + offset = ydest * linelen + xdest * bytes_per_pixel; + dest += offset; + n = w * bytes_per_pixel; + + if (ydest < ysrc) { + int j=0; + while (j < h) { + fbui_copy_within (dest,src,n); + dest += linelen; + src += linelen; + j++; + } + } else + if (ydest > ysrc) { + int j=h-1; + dest += linelen * h; + src += linelen * h; + while (j >= 0) { + dest -= linelen; + src -= linelen; + fbui_copy_within (dest,src,n); + j--; + } + } else { + /* y equal */ + int dif = xsrc > xdest ? xsrc-xdest : xdest-xsrc; + + /* leftgoing */ + if (xdest < xsrc) { + int j=0; + while (j < h) { + register unsigned char *d = dest; + register unsigned char *s = src; + register int i = w * bytes_per_pixel; + while (i) { + if (dif>3 && !(3 & (u32) s) && i>3) { + u32 v = fb_readl (s); s+= 4; + if (!(3 & (u32) d)) { + fb_writel (v, d); + d += 4; + i -= 4; + + while (i >= 4) { + v= fb_readl (s); + s += 4; + fb_writel(v, d); + d += 4; + i -= 4; + } + } else { + fb_writeb (v, d); + d++; v >>= 8; + fb_writeb (v, d); + d++; v >>= 8; + fb_writeb (v, d); + d++; v >>= 8; + fb_writeb (v, d); + d++; + i -= 4; + } + } else { + fb_writeb (fb_readb (s), d); + s++; + d++; + i--; + } + } + dest += linelen; + src += linelen; + j++; + } + + } else { + /* rightgoing */ + int j=0; + while (j < h) { + int i = w * bytes_per_pixel; + unsigned char *d = dest + i; + unsigned char *s = src + i; + while (i) { + if (dif>3 && !(3 & (u32) s) && i>3) + { + u32 v; + s -= 4; + v = fb_readl (s); + if (!(3 & (u32) d)) { + d -= 4; + fb_writel (v, d); + i -= 4; + + while (i >= 4) { + v=fb_readl(s-3); + s -= 4; + fb_writel(v,d-3); + d -= 4; + i -= 4; + } + } else { + d--; + fb_writeb (v>>24, d); + d--; + fb_writeb (v>>16, d); + d--; + fb_writeb (v>>8, d); + d--; + fb_writeb (v, d); + i -= 4; + } + } else { + s--; + d--; + fb_writeb (fb_readb (s), d); + i--; + } + } + dest += linelen; + src += linelen; + j++; + } + } + } +} + +int fbui_copy_area (struct fb_info *info, struct fbui_window *win, + short xsrc,short ysrc,short w, short h, short xdest,short ydest) +{ + short win_w, win_h; + + if (!info || !win) + return FBUI_ERR_NULLPTR; + if (info->state != FBINFO_STATE_RUNNING) + return FBUI_ERR_NOTRUNNING; + if (win->console != info->currcon) + return FBUI_SUCCESS; + if (win->is_hidden) + return FBUI_SUCCESS; + if (xsrc==xdest && ysrc==ydest) + return 0; + win_w = win->width; + win_h = win->height; + if ((xsrc+w-1) < 0 || (ysrc+h-1) < 0) + return 0; + if (xsrc >= win_w || ysrc >= win_h) + return 0; + if ((xdest+w-1) < 0 || (ydest+h-1) < 0) + return 0; + if (xdest >= win_w || ydest >= win_h) + return 0; + if (xsrc < 0) { + xdest -= xsrc; + w += xsrc; + xsrc=0; + } + if (ysrc < 0) { + ydest -= ysrc; + h += ysrc; + ysrc=0; + } + if ((xsrc+w-1) >= win_w) { + short dif=(xsrc+w) - win_w; + w -= dif; + } + if ((ysrc+h-1) >= win_h) { + short dif=(ysrc+h) - win_h; + h -= dif; + } + if ((xdest+w-1) > win_w) { + short dif=(xdest+w) - win_w; + w -= dif; + } + if ((ydest+h-1) > win_h) { + short dif=(ydest+h) - win_h; + h -= dif; + } + /*----------*/ + + xsrc += win->x0; + ysrc += win->y0; + xdest += win->x0; + ydest += win->y0; + + if (!info->have_hardware_pointer && info->pointer_active && + !info->pointer_hidden && pointer_in_window (info, win, 0)) + fbui_hide_pointer (info); + + if (info->fbops->fb_copyarea2) + info->fbops->fb_copyarea2 (info, xsrc,ysrc,w,h,xdest,ydest); + + return FBUI_SUCCESS; +} + + +int fbui_release (struct fb_info *info, int user) +{ + if (!info) + return 0; + + return 0; +} + +EXPORT_SYMBOL(fbui_init); +EXPORT_SYMBOL(fbui_release); +EXPORT_SYMBOL(fbui_control); +EXPORT_SYMBOL(fbui_open); +EXPORT_SYMBOL(fbui_switch); +EXPORT_SYMBOL(fbui_close); +EXPORT_SYMBOL(fbui_exec); + +EXPORT_SYMBOL(fb_clear); +EXPORT_SYMBOL(fb_hline); +EXPORT_SYMBOL(fb_vline); +EXPORT_SYMBOL(fb_point); +EXPORT_SYMBOL(fb_read_point); +EXPORT_SYMBOL(fb_copyarea); +EXPORT_SYMBOL(fb_putpixels_native); +EXPORT_SYMBOL(fb_putpixels_rgb); +EXPORT_SYMBOL(fb_getpixels_rgb); +EXPORT_SYMBOL(fb_putpixels_rgb3); +EXPORT_SYMBOL(pixel_from_rgb); +EXPORT_SYMBOL(pixel_to_rgb); + +MODULE_AUTHOR("Zachary T Smith <fbui@comcast.net>") +MODULE_DESCRIPTION("In-kernel graphical user interface for applications"); +MODULE_LICENSE("GPL"); + diff --git a/drivers/video/vesafb.c b/drivers/video/vesafb.c @@ -0,0 +1,457 @@ +/* + * framebuffer driver for VBE 2.0 compliant graphic boards + * + * switching to graphics mode happens at boot time (while + * running in real mode, see arch/i386/boot/video.S). + * + * (c) 1998 Gerd Knorr <kraxel@goldbach.in-berlin.de> + * + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/mm.h> +#include <linux/tty.h> +#include <linux/slab.h> +#include <linux/delay.h> +#include <linux/fb.h> +#include <linux/ioport.h> +#include <linux/init.h> +#ifdef __i386__ +#include <video/edid.h> +#endif +#include <asm/io.h> +#include <asm/mtrr.h> + +#define dac_reg (0x3c8) +#define dac_val (0x3c9) + +/* --------------------------------------------------------------------- */ + +static struct fb_var_screeninfo vesafb_defined __initdata = { + .activate = FB_ACTIVATE_NOW, + .height = -1, + .width = -1, + .right_margin = 32, + .upper_margin = 16, + .lower_margin = 4, + .vsync_len = 4, + .vmode = FB_VMODE_NONINTERLACED, +}; + +static struct fb_fix_screeninfo vesafb_fix __initdata = { + .id = "VESA VGA", + .type = FB_TYPE_PACKED_PIXELS, + .accel = FB_ACCEL_NONE, +}; + +static int inverse = 0; +static int mtrr = 1; +static int vram __initdata = 0; /* Set amount of memory to be used */ +static int pmi_setpal = 0; /* pmi for palette changes ??? */ +static int ypan = 0; /* 0..nothing, 1..ypan, 2..ywrap */ +static unsigned short *pmi_base = NULL; +static void (*pmi_start)(void); +static void (*pmi_pal)(void); + +/* --------------------------------------------------------------------- */ + +static int vesafb_pan_display(struct fb_var_screeninfo *var, + struct fb_info *info) +{ +#ifdef __i386__ + int offset; + + if (!ypan) + return -EINVAL; + if (var->xoffset) + return -EINVAL; + if (var->yoffset > var->yres_virtual) + return -EINVAL; + if ((ypan==1) && var->yoffset+var->yres > var->yres_virtual) + return -EINVAL; + + offset = (var->yoffset * info->fix.line_length + var->xoffset) / 4; + + __asm__ __volatile__( + "call *(%%edi)" + : /* no return value */ + : "a" (0x4f07), /* EAX */ + "b" (0), /* EBX */ + "c" (offset), /* ECX */ + "d" (offset >> 16), /* EDX */ + "D" (&pmi_start)); /* EDI */ +#endif + return 0; +} + +static void vesa_setpalette(int regno, unsigned red, unsigned green, + unsigned blue, struct fb_var_screeninfo *var) +{ +#ifdef __i386__ + struct { u_char blue, green, red, pad; } entry; + int shift = 16 - var->green.length; + + if (pmi_setpal) { + entry.red = red >> shift; + entry.green = green >> shift; + entry.blue = blue >> shift; + entry.pad = 0; + __asm__ __volatile__( + "call *(%%esi)" + : /* no return value */ + : "a" (0x4f09), /* EAX */ + "b" (0), /* EBX */ + "c" (1), /* ECX */ + "d" (regno), /* EDX */ + "D" (&entry), /* EDI */ + "S" (&pmi_pal)); /* ESI */ + } else { + /* without protected mode interface, try VGA registers... */ + outb_p(regno, dac_reg); + outb_p(red >> shift, dac_val); + outb_p(green >> shift, dac_val); + outb_p(blue >> shift, dac_val); + } +#endif +} + +static int vesafb_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, + struct fb_info *info) +{ + /* + * Set a single color register. The values supplied are + * already rounded down to the hardware's capabilities + * (according to the entries in the `var' structure). Return + * != 0 for invalid regno. + */ + + if (regno >= info->cmap.len) + return 1; + + switch (info->var.bits_per_pixel) { + case 8: + vesa_setpalette(regno,red,green,blue, &info->var); + break; + case 16: + if (info->var.red.offset == 10) { + /* 1:5:5:5 */ + ((u32*) (info->pseudo_palette))[regno] = + ((red & 0xf800) >> 1) | + ((green & 0xf800) >> 6) | + ((blue & 0xf800) >> 11); + } else { + /* 0:5:6:5 */ + ((u32*) (info->pseudo_palette))[regno] = + ((red & 0xf800) ) | + ((green & 0xfc00) >> 5) | + ((blue & 0xf800) >> 11); + } + break; + case 24: + red >>= 8; + green >>= 8; + blue >>= 8; + ((u32 *)(info->pseudo_palette))[regno] = + (red << info->var.red.offset) | + (green << info->var.green.offset) | + (blue << info->var.blue.offset); + break; + case 32: + red >>= 8; + green >>= 8; + blue >>= 8; + ((u32 *)(info->pseudo_palette))[regno] = + (red << info->var.red.offset) | + (green << info->var.green.offset) | + (blue << info->var.blue.offset); + break; + } + return 0; +} + +static struct fb_ops vesafb_ops = { + .owner = THIS_MODULE, + .fb_setcolreg = vesafb_setcolreg, + .fb_pan_display = vesafb_pan_display, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_cursor = soft_cursor, + +#ifdef CONFIG_FB_UI + /* Assign routines from fbui.c */ + .fb_release = fbui_release, + .fb_point = fb_point, + .fb_hline = fb_hline, + .fb_vline = fb_vline, + .fb_clear = fb_clear, + .fb_read_point = fb_read_point, + .fb_putpixels_native = fb_putpixels_native, + .fb_putpixels_rgb = fb_putpixels_rgb, + .fb_putpixels_rgb3 = fb_putpixels_rgb3, + .fb_getpixels_rgb = fb_getpixels_rgb, + .fb_copyarea2 = fb_copyarea, +#endif +}; + +int __init vesafb_setup(char *options) +{ + char *this_opt; + + if (!options || !*options) + return 0; + + while ((this_opt = strsep(&options, ",")) != NULL) { + if (!*this_opt) continue; + + if (! strcmp(this_opt, "inverse")) + inverse=1; + else if (! strcmp(this_opt, "redraw")) + ypan=0; + else if (! strcmp(this_opt, "ypan")) + ypan=1; + else if (! strcmp(this_opt, "ywrap")) + ypan=2; + else if (! strcmp(this_opt, "vgapal")) + pmi_setpal=0; + else if (! strcmp(this_opt, "pmipal")) + pmi_setpal=1; + else if (! strcmp(this_opt, "mtrr")) + mtrr=1; + else if (! strcmp(this_opt, "nomtrr")) + mtrr=0; + else if (! strncmp(this_opt, "vram:", 5)) + vram = simple_strtoul(this_opt+5, NULL, 0); + } + return 0; +} + +static int __init vesafb_probe(struct device *device) +{ + struct platform_device *dev = to_platform_device(device); + struct fb_info *info; + int i, err; + + if (screen_info.orig_video_isVGA != VIDEO_TYPE_VLFB) + return -ENXIO; + + vesafb_fix.smem_start = screen_info.lfb_base; + vesafb_defined.bits_per_pixel = screen_info.lfb_depth; + if (15 == vesafb_defined.bits_per_pixel) + vesafb_defined.bits_per_pixel = 16; + vesafb_defined.xres = screen_info.lfb_width; + vesafb_defined.yres = screen_info.lfb_height; + vesafb_fix.line_length = screen_info.lfb_linelength; + + /* Allocate enough memory for double buffering */ + vesafb_fix.smem_len = screen_info.lfb_width * screen_info.lfb_height * vesafb_defined.bits_per_pixel >> 2; + + /* check that we don't remap more memory than old cards have */ + if (vesafb_fix.smem_len > (screen_info.lfb_size * 65536)) + vesafb_fix.smem_len = screen_info.lfb_size * 65536; + + /* Set video size according to vram boot option */ + if (vram) + vesafb_fix.smem_len = vram * 1024 * 1024; + + vesafb_fix.visual = (vesafb_defined.bits_per_pixel == 8) ? + FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; + + /* limit framebuffer size to 16 MB. Otherwise we'll eat tons of + * kernel address space for nothing if the gfx card has alot of + * memory (>= 128 MB isn't uncommon these days ...) */ + if (vesafb_fix.smem_len > 16 * 1024 * 1024) + vesafb_fix.smem_len = 16 * 1024 * 1024; + +#ifndef __i386__ + screen_info.vesapm_seg = 0; +#endif + + if (!request_mem_region(vesafb_fix.smem_start, vesafb_fix.smem_len, "vesafb")) { + printk(KERN_WARNING + "vesafb: abort, cannot reserve video memory at 0x%lx\n", + vesafb_fix.smem_start); + /* We cannot make this fatal. Sometimes this comes from magic + spaces our resource handlers simply don't know about */ + } + + info = framebuffer_alloc(sizeof(u32) * 256, &dev->dev); + if (!info) { + release_mem_region(vesafb_fix.smem_start, vesafb_fix.smem_len); + return -ENOMEM; + } + info->pseudo_palette = info->par; + info->par = NULL; + + info->screen_base = ioremap(vesafb_fix.smem_start, vesafb_fix.smem_len); + if (!info->screen_base) { + printk(KERN_ERR + "vesafb: abort, cannot ioremap video memory 0x%x @ 0x%lx\n", + vesafb_fix.smem_len, vesafb_fix.smem_start); + err = -EIO; + goto err; + } + + printk(KERN_INFO "vesafb: framebuffer at 0x%lx, mapped to 0x%p, size %dk\n", + vesafb_fix.smem_start, info->screen_base, vesafb_fix.smem_len/1024); + printk(KERN_INFO "vesafb: mode is %dx%dx%d, linelength=%d, pages=%d\n", + vesafb_defined.xres, vesafb_defined.yres, vesafb_defined.bits_per_pixel, vesafb_fix.line_length, screen_info.pages); + + if (screen_info.vesapm_seg) { + printk(KERN_INFO "vesafb: protected mode interface info at %04x:%04x\n", + screen_info.vesapm_seg,screen_info.vesapm_off); + } + + if (screen_info.vesapm_seg < 0xc000) + ypan = pmi_setpal = 0; /* not available or some DOS TSR ... */ + + if (ypan || pmi_setpal) { + pmi_base = (unsigned short*)phys_to_virt(((unsigned long)screen_info.vesapm_seg << 4) + screen_info.vesapm_off); + pmi_start = (void*)((char*)pmi_base + pmi_base[1]); + pmi_pal = (void*)((char*)pmi_base + pmi_base[2]); + printk(KERN_INFO "vesafb: pmi: set display start = %p, set palette = %p\n",pmi_start,pmi_pal); + if (pmi_base[3]) { + printk(KERN_INFO "vesafb: pmi: ports = "); + for (i = pmi_base[3]/2; pmi_base[i] != 0xffff; i++) + printk("%x ",pmi_base[i]); + printk("\n"); + if (pmi_base[i] != 0xffff) { + /* + * memory areas not supported (yet?) + * + * Rules are: we have to set up a descriptor for the requested + * memory area and pass it in the ES register to the BIOS function. + */ + printk(KERN_INFO "vesafb: can't handle memory requests, pmi disabled\n"); + ypan = pmi_setpal = 0; + } + } + } + + vesafb_defined.xres_virtual = vesafb_defined.xres; + vesafb_defined.yres_virtual = vesafb_fix.smem_len / vesafb_fix.line_length; + if (ypan && vesafb_defined.yres_virtual > vesafb_defined.yres) { + printk(KERN_INFO "vesafb: scrolling: %s using protected mode interface, yres_virtual=%d\n", + (ypan > 1) ? "ywrap" : "ypan",vesafb_defined.yres_virtual); + } else { + printk(KERN_INFO "vesafb: scrolling: redraw\n"); + vesafb_defined.yres_virtual = vesafb_defined.yres; + ypan = 0; + } + + /* some dummy values for timing to make fbset happy */ + vesafb_defined.pixclock = 10000000 / vesafb_defined.xres * 1000 / vesafb_defined.yres; + vesafb_defined.left_margin = (vesafb_defined.xres / 8) & 0xf8; + vesafb_defined.hsync_len = (vesafb_defined.xres / 8) & 0xf8; + + vesafb_defined.red.offset = screen_info.red_pos; + vesafb_defined.red.length = screen_info.red_size; + vesafb_defined.green.offset = screen_info.green_pos; + vesafb_defined.green.length = screen_info.green_size; + vesafb_defined.blue.offset = screen_info.blue_pos; + vesafb_defined.blue.length = screen_info.blue_size; + vesafb_defined.transp.offset = screen_info.rsvd_pos; + vesafb_defined.transp.length = screen_info.rsvd_size; + printk(KERN_INFO "vesafb: %s: " + "size=%d:%d:%d:%d, shift=%d:%d:%d:%d\n", + (vesafb_defined.bits_per_pixel > 8) ? + "Truecolor" : "Pseudocolor", + screen_info.rsvd_size, + screen_info.red_size, + screen_info.green_size, + screen_info.blue_size, + screen_info.rsvd_pos, + screen_info.red_pos, + screen_info.green_pos, + screen_info.blue_pos); + + vesafb_fix.ypanstep = ypan ? 1 : 0; + vesafb_fix.ywrapstep = (ypan>1) ? 1 : 0; + + /* request failure does not faze us, as vgacon probably has this + * region already (FIXME) */ + request_region(0x3c0, 32, "vesafb"); + + if (mtrr) { + int temp_size = vesafb_fix.smem_len; + /* Find the largest power-of-two */ + while (temp_size & (temp_size - 1)) + temp_size &= (temp_size - 1); + + /* Try and find a power of two to add */ + while (temp_size && mtrr_add(vesafb_fix.smem_start, temp_size, MTRR_TYPE_WRCOMB, 1)==-EINVAL) { + temp_size >>= 1; + } + } + + info->fbops = &vesafb_ops; + info->var = vesafb_defined; + info->fix = vesafb_fix; + info->flags = FBINFO_FLAG_DEFAULT | + (ypan) ? FBINFO_HWACCEL_YPAN : 0; + + if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) { + err = -ENXIO; + goto err; + } + if (register_framebuffer(info)<0) { + err = -EINVAL; + fb_dealloc_cmap(&info->cmap); + goto err; + } + printk(KERN_INFO "fb%d: %s frame buffer device\n", + info->node, info->fix.id); + +#ifdef CONFIG_FB_UI + fbui_init (info); +#endif + + return 0; +err: + framebuffer_release(info); + release_mem_region(vesafb_fix.smem_start, vesafb_fix.smem_len); + return err; +} + +static struct device_driver vesafb_driver = { + .name = "vesafb", + .bus = &platform_bus_type, + .probe = vesafb_probe, +}; + +static struct platform_device vesafb_device = { + .name = "vesafb", +}; + +int __init vesafb_init(void) +{ + int ret; + char *option = NULL; + + /* ignore error return of fb_get_options */ + fb_get_options("vesafb", &option); + vesafb_setup(option); + ret = driver_register(&vesafb_driver); + + if (!ret) { + ret = platform_device_register(&vesafb_device); + if (ret) + driver_unregister(&vesafb_driver); + } + return ret; +} +module_init(vesafb_init); + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * --------------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ + +MODULE_LICENSE("GPL"); diff --git a/drivers/video/vga16fb.c b/drivers/video/vga16fb.c @@ -0,0 +1,1490 @@ +/* + * linux/drivers/video/vga16.c -- VGA 16-color framebuffer driver + * + * Copyright 1999 Ben Pfaff <pfaffben@debian.org> and Petr Vandrovec <VANDROVE@vc.cvut.cz> + * Based on VGA info at http://www.goodnet.com/~tinara/FreeVGA/home.htm + * Based on VESA framebuffer (c) 1998 Gerd Knorr <kraxel@goldbach.in-berlin.de> + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/mm.h> +#include <linux/tty.h> +#include <linux/slab.h> +#include <linux/delay.h> +#include <linux/fb.h> +#include <linux/ioport.h> +#include <linux/init.h> + +#include <asm/io.h> +#include <video/vga.h> + +#define GRAPHICS_ADDR_REG VGA_GFX_I /* Graphics address register. */ +#define GRAPHICS_DATA_REG VGA_GFX_D /* Graphics data register. */ + +#define SET_RESET_INDEX VGA_GFX_SR_VALUE /* Set/Reset Register index. */ +#define ENABLE_SET_RESET_INDEX VGA_GFX_SR_ENABLE /* Enable Set/Reset Register index. */ +#define DATA_ROTATE_INDEX VGA_GFX_DATA_ROTATE /* Data Rotate Register index. */ +#define GRAPHICS_MODE_INDEX VGA_GFX_MODE /* Graphics Mode Register index. */ +#define BIT_MASK_INDEX VGA_GFX_BIT_MASK /* Bit Mask Register index. */ + +#define dac_reg (VGA_PEL_IW) +#define dac_val (VGA_PEL_D) + +#define VGA_FB_PHYS 0xA0000 +#define VGA_FB_PHYS_LEN 65536 + +#define MODE_SKIP4 1 +#define MODE_8BPP 2 +#define MODE_CFB 4 +#define MODE_TEXT 8 + +/* --------------------------------------------------------------------- */ + +/* + * card parameters + */ + +static struct fb_info vga16fb; + +static struct vga16fb_par { + /* structure holding original VGA register settings when the + screen is blanked */ + struct { + unsigned char SeqCtrlIndex; /* Sequencer Index reg. */ + unsigned char CrtCtrlIndex; /* CRT-Contr. Index reg. */ + unsigned char CrtMiscIO; /* Miscellaneous register */ + unsigned char HorizontalTotal; /* CRT-Controller:00h */ + unsigned char HorizDisplayEnd; /* CRT-Controller:01h */ + unsigned char StartHorizRetrace; /* CRT-Controller:04h */ + unsigned char EndHorizRetrace; /* CRT-Controller:05h */ + unsigned char Overflow; /* CRT-Controller:07h */ + unsigned char StartVertRetrace; /* CRT-Controller:10h */ + unsigned char EndVertRetrace; /* CRT-Controller:11h */ + unsigned char ModeControl; /* CRT-Controller:17h */ + unsigned char ClockingMode; /* Seq-Controller:01h */ + } vga_state; + struct vgastate state; + atomic_t ref_count; + int palette_blanked, vesa_blanked, mode, isVGA; + u8 misc, pel_msk, vss, clkdiv; + u8 crtc[VGA_CRT_C]; +} vga16_par; + +/* --------------------------------------------------------------------- */ + +static struct fb_var_screeninfo vga16fb_defined = { + .xres = 640, + .yres = 480, + .xres_virtual = 640, + .yres_virtual = 480, + .bits_per_pixel = 4, + .activate = FB_ACTIVATE_TEST, + .height = -1, + .width = -1, + .pixclock = 39721, + .left_margin = 48, + .right_margin = 16, + .upper_margin = 39, + .lower_margin = 8, + .hsync_len = 96, + .vsync_len = 2, + .vmode = FB_VMODE_NONINTERLACED, +}; + +/* name should not depend on EGA/VGA */ +static struct fb_fix_screeninfo vga16fb_fix __initdata = { + .id = "VGA16 VGA", + .smem_start = VGA_FB_PHYS, + .smem_len = VGA_FB_PHYS_LEN, + .type = FB_TYPE_VGA_PLANES, + .type_aux = FB_AUX_VGA_PLANES_VGA4, + .visual = FB_VISUAL_PSEUDOCOLOR, + .xpanstep = 8, + .ypanstep = 1, + .line_length = 640/8, + .accel = FB_ACCEL_NONE +}; + +/* The VGA's weird architecture often requires that we read a byte and + write a byte to the same location. It doesn't matter *what* byte + we write, however. This is because all the action goes on behind + the scenes in the VGA's 32-bit latch register, and reading and writing + video memory just invokes latch behavior. + + To avoid race conditions (is this necessary?), reading and writing + the memory byte should be done with a single instruction. One + suitable instruction is the x86 bitwise OR. The following + read-modify-write routine should optimize to one such bitwise + OR. */ +static inline void rmw(volatile char *p) +{ + readb(p); + writeb(1, p); +} + +/* Set the Graphics Mode Register, and return its previous value. + Bits 0-1 are write mode, bit 3 is read mode. */ +static inline int setmode(int mode) +{ + int oldmode; + + vga_io_w(GRAPHICS_ADDR_REG, GRAPHICS_MODE_INDEX); + oldmode = vga_io_r(GRAPHICS_DATA_REG); + vga_io_w(GRAPHICS_DATA_REG, mode); + return oldmode; +} + +/* Select the Bit Mask Register and return its value. */ +static inline int selectmask(void) +{ + return vga_io_rgfx(BIT_MASK_INDEX); +} + +/* Set the value of the Bit Mask Register. It must already have been + selected with selectmask(). */ +static inline void setmask(int mask) +{ + vga_io_w(GRAPHICS_DATA_REG, mask); +} + +/* Set the Data Rotate Register and return its old value. + Bits 0-2 are rotate count, bits 3-4 are logical operation + (0=NOP, 1=AND, 2=OR, 3=XOR). */ +static inline int setop(int op) +{ + int oldop; + + vga_io_w(GRAPHICS_ADDR_REG, DATA_ROTATE_INDEX); + oldop = vga_io_r(GRAPHICS_DATA_REG); + vga_io_w(GRAPHICS_DATA_REG, op); + return oldop; +} + +/* Set the Enable Set/Reset Register and return its old value. + The code here always uses value 0xf for thsi register. */ +static inline int setsr(int sr) +{ + int oldsr; + + vga_io_w(GRAPHICS_ADDR_REG, ENABLE_SET_RESET_INDEX); + oldsr = vga_io_r(GRAPHICS_DATA_REG); + vga_io_w(GRAPHICS_DATA_REG, sr); + return oldsr; +} + +/* Set the Set/Reset Register and return its old value. */ +static inline int setcolor(int color) +{ + int oldcolor; + + vga_io_w(GRAPHICS_ADDR_REG, SET_RESET_INDEX); + oldcolor = vga_io_r(GRAPHICS_DATA_REG); + vga_io_w(GRAPHICS_DATA_REG, color); + return oldcolor; +} + +/* Return the value in the Graphics Address Register. */ +static inline int getindex(void) +{ + return vga_io_r(GRAPHICS_ADDR_REG); +} + +/* Set the value in the Graphics Address Register. */ +static inline void setindex(int index) +{ + vga_io_w(GRAPHICS_ADDR_REG, index); +} + +static void vga16fb_pan_var(struct fb_info *info, + struct fb_var_screeninfo *var) +{ + struct vga16fb_par *par = (struct vga16fb_par *) info->par; + u32 xoffset, pos; + + xoffset = var->xoffset; + if (info->var.bits_per_pixel == 8) { + pos = (info->var.xres_virtual * var->yoffset + xoffset) >> 2; + } else if (par->mode & MODE_TEXT) { + int fh = 16; // FIXME !!! font height. Fugde for now. + pos = (info->var.xres_virtual * (var->yoffset / fh) + xoffset) >> 3; + } else { + if (info->var.nonstd) + xoffset--; + pos = (info->var.xres_virtual * var->yoffset + xoffset) >> 3; + } + vga_io_wcrt(VGA_CRTC_START_HI, pos >> 8); + vga_io_wcrt(VGA_CRTC_START_LO, pos & 0xFF); + /* if we support CFB4, then we must! support xoffset with pixel + * granularity if someone supports xoffset in bit resolution */ + vga_io_r(VGA_IS1_RC); /* reset flip-flop */ + vga_io_w(VGA_ATT_IW, VGA_ATC_PEL); + if (var->bits_per_pixel == 8) + vga_io_w(VGA_ATT_IW, (xoffset & 3) << 1); + else + vga_io_w(VGA_ATT_IW, xoffset & 7); + vga_io_r(VGA_IS1_RC); + vga_io_w(VGA_ATT_IW, 0x20); +} + +static void vga16fb_update_fix(struct fb_info *info) +{ + if (info->var.bits_per_pixel == 4) { + if (info->var.nonstd) { + info->fix.type = FB_TYPE_PACKED_PIXELS; + info->fix.line_length = info->var.xres_virtual / 2; + } else { + info->fix.type = FB_TYPE_VGA_PLANES; + info->fix.type_aux = FB_AUX_VGA_PLANES_VGA4; + info->fix.line_length = info->var.xres_virtual / 8; + } + } else if (info->var.bits_per_pixel == 0) { + info->fix.type = FB_TYPE_TEXT; + info->fix.type_aux = FB_AUX_TEXT_CGA; + info->fix.line_length = info->var.xres_virtual / 4; + } else { /* 8bpp */ + if (info->var.nonstd) { + info->fix.type = FB_TYPE_VGA_PLANES; + info->fix.type_aux = FB_AUX_VGA_PLANES_CFB8; + info->fix.line_length = info->var.xres_virtual / 4; + } else { + info->fix.type = FB_TYPE_PACKED_PIXELS; + info->fix.line_length = info->var.xres_virtual; + } + } +} + +static void vga16fb_clock_chip(struct vga16fb_par *par, + unsigned int pixclock, + const struct fb_info *info, + int mul, int div) +{ + static struct { + u32 pixclock; + u8 misc; + u8 seq_clock_mode; + } *ptr, *best, vgaclocks[] = { + { 79442 /* 12.587 */, 0x00, 0x08}, + { 70616 /* 14.161 */, 0x04, 0x08}, + { 39721 /* 25.175 */, 0x00, 0x00}, + { 35308 /* 28.322 */, 0x04, 0x00}, + { 0 /* bad */, 0x00, 0x00}}; + int err; + + pixclock = (pixclock * mul) / div; + best = vgaclocks; + err = pixclock - best->pixclock; + if (err < 0) err = -err; + for (ptr = vgaclocks + 1; ptr->pixclock; ptr++) { + int tmp; + + tmp = pixclock - ptr->pixclock; + if (tmp < 0) tmp = -tmp; + if (tmp < err) { + err = tmp; + best = ptr; + } + } + par->misc |= best->misc; + par->clkdiv = best->seq_clock_mode; + pixclock = (best->pixclock * div) / mul; +} + +#define FAIL(X) return -EINVAL + +static int vga16fb_open(struct fb_info *info, int user) +{ + struct vga16fb_par *par = (struct vga16fb_par *) info->par; + int cnt = atomic_read(&par->ref_count); + + if (!cnt) { + memset(&par->state, 0, sizeof(struct vgastate)); + par->state.flags = VGA_SAVE_FONTS | VGA_SAVE_MODE | + VGA_SAVE_CMAP; + save_vga(&par->state); + } + atomic_inc(&par->ref_count); + return 0; +} + +static int vga16fb_release(struct fb_info *info, int user) +{ + struct vga16fb_par *par = (struct vga16fb_par *) info->par; + int cnt = atomic_read(&par->ref_count); + + if (!cnt) + return -EINVAL; + if (cnt == 1) + restore_vga(&par->state); + atomic_dec(&par->ref_count); + + return 0; +} + +static int vga16fb_check_var(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + struct vga16fb_par *par = (struct vga16fb_par *) info->par; + u32 xres, right, hslen, left, xtotal; + u32 yres, lower, vslen, upper, ytotal; + u32 vxres, xoffset, vyres, yoffset; + u32 pos; + u8 r7, rMode; + int shift; + int mode; + u32 maxmem; + + par->pel_msk = 0xFF; + + if (var->bits_per_pixel == 4) { + if (var->nonstd) { + if (!par->isVGA) + return -EINVAL; + shift = 3; + mode = MODE_SKIP4 | MODE_CFB; + maxmem = 16384; + par->pel_msk = 0x0F; + } else { + shift = 3; + mode = 0; + maxmem = 65536; + } + } else if (var->bits_per_pixel == 8) { + if (!par->isVGA) + return -EINVAL; /* no support on EGA */ + shift = 2; + if (var->nonstd) { + mode = MODE_8BPP | MODE_CFB; + maxmem = 65536; + } else { + mode = MODE_SKIP4 | MODE_8BPP | MODE_CFB; + maxmem = 16384; + } + } else + return -EINVAL; + + xres = (var->xres + 7) & ~7; + vxres = (var->xres_virtual + 0xF) & ~0xF; + xoffset = (var->xoffset + 7) & ~7; + left = (var->left_margin + 7) & ~7; + right = (var->right_margin + 7) & ~7; + hslen = (var->hsync_len + 7) & ~7; + + if (vxres < xres) + vxres = xres; + if (xres + xoffset > vxres) + xoffset = vxres - xres; + + var->xres = xres; + var->right_margin = right; + var->hsync_len = hslen; + var->left_margin = left; + var->xres_virtual = vxres; + var->xoffset = xoffset; + + xres >>= shift; + right >>= shift; + hslen >>= shift; + left >>= shift; + vxres >>= shift; + xtotal = xres + right + hslen + left; + if (xtotal >= 256) + FAIL("xtotal too big"); + if (hslen > 32) + FAIL("hslen too big"); + if (right + hslen + left > 64) + FAIL("hblank too big"); + par->crtc[VGA_CRTC_H_TOTAL] = xtotal - 5; + par->crtc[VGA_CRTC_H_BLANK_START] = xres - 1; + par->crtc[VGA_CRTC_H_DISP] = xres - 1; + pos = xres + right; + par->crtc[VGA_CRTC_H_SYNC_START] = pos; + pos += hslen; + par->crtc[VGA_CRTC_H_SYNC_END] = pos & 0x1F; + pos += left - 2; /* blank_end + 2 <= total + 5 */ + par->crtc[VGA_CRTC_H_BLANK_END] = (pos & 0x1F) | 0x80; + if (pos & 0x20) + par->crtc[VGA_CRTC_H_SYNC_END] |= 0x80; + + yres = var->yres; + lower = var->lower_margin; + vslen = var->vsync_len; + upper = var->upper_margin; + vyres = var->yres_virtual; + yoffset = var->yoffset; + + if (yres > vyres) + vyres = yres; + if (vxres * vyres > maxmem) { + vyres = maxmem / vxres; + if (vyres < yres) + return -ENOMEM; + } + if (yoffset + yres > vyres) + yoffset = vyres - yres; + var->yres = yres; + var->lower_margin = lower; + var->vsync_len = vslen; + var->upper_margin = upper; + var->yres_virtual = vyres; + var->yoffset = yoffset; + + if (var->vmode & FB_VMODE_DOUBLE) { + yres <<= 1; + lower <<= 1; + vslen <<= 1; + upper <<= 1; + } + ytotal = yres + lower + vslen + upper; + if (ytotal > 1024) { + ytotal >>= 1; + yres >>= 1; + lower >>= 1; + vslen >>= 1; + upper >>= 1; + rMode = 0x04; + } else + rMode = 0x00; + if (ytotal > 1024) + FAIL("ytotal too big"); + if (vslen > 16) + FAIL("vslen too big"); + par->crtc[VGA_CRTC_V_TOTAL] = ytotal - 2; + r7 = 0x10; /* disable linecompare */ + if (ytotal & 0x100) r7 |= 0x01; + if (ytotal & 0x200) r7 |= 0x20; + par->crtc[VGA_CRTC_PRESET_ROW] = 0; + par->crtc[VGA_CRTC_MAX_SCAN] = 0x40; /* 1 scanline, no linecmp */ + if (var->vmode & FB_VMODE_DOUBLE) + par->crtc[VGA_CRTC_MAX_SCAN] |= 0x80; + par->crtc[VGA_CRTC_CURSOR_START] = 0x20; + par->crtc[VGA_CRTC_CURSOR_END] = 0x00; + if ((mode & (MODE_CFB | MODE_8BPP)) == MODE_CFB) + xoffset--; + pos = yoffset * vxres + (xoffset >> shift); + par->crtc[VGA_CRTC_START_HI] = pos >> 8; + par->crtc[VGA_CRTC_START_LO] = pos & 0xFF; + par->crtc[VGA_CRTC_CURSOR_HI] = 0x00; + par->crtc[VGA_CRTC_CURSOR_LO] = 0x00; + pos = yres - 1; + par->crtc[VGA_CRTC_V_DISP_END] = pos & 0xFF; + par->crtc[VGA_CRTC_V_BLANK_START] = pos & 0xFF; + if (pos & 0x100) + r7 |= 0x0A; /* 0x02 -> DISP_END, 0x08 -> BLANK_START */ + if (pos & 0x200) { + r7 |= 0x40; /* 0x40 -> DISP_END */ + par->crtc[VGA_CRTC_MAX_SCAN] |= 0x20; /* BLANK_START */ + } + pos += lower; + par->crtc[VGA_CRTC_V_SYNC_START] = pos & 0xFF; + if (pos & 0x100) + r7 |= 0x04; + if (pos & 0x200) + r7 |= 0x80; + pos += vslen; + par->crtc[VGA_CRTC_V_SYNC_END] = (pos & 0x0F) & ~0x10; /* disabled IRQ */ + pos += upper - 1; /* blank_end + 1 <= ytotal + 2 */ + par->crtc[VGA_CRTC_V_BLANK_END] = pos & 0xFF; /* 0x7F for original VGA, + but some SVGA chips requires all 8 bits to set */ + if (vxres >= 512) + FAIL("vxres too long"); + par->crtc[VGA_CRTC_OFFSET] = vxres >> 1; + if (mode & MODE_SKIP4) + par->crtc[VGA_CRTC_UNDERLINE] = 0x5F; /* 256, cfb8 */ + else + par->crtc[VGA_CRTC_UNDERLINE] = 0x1F; /* 16, vgap */ + par->crtc[VGA_CRTC_MODE] = rMode | ((mode & MODE_TEXT) ? 0xA3 : 0xE3); + par->crtc[VGA_CRTC_LINE_COMPARE] = 0xFF; + par->crtc[VGA_CRTC_OVERFLOW] = r7; + + par->vss = 0x00; /* 3DA */ + + par->misc = 0xE3; /* enable CPU, ports 0x3Dx, positive sync */ + if (var->sync & FB_SYNC_HOR_HIGH_ACT) + par->misc &= ~0x40; + if (var->sync & FB_SYNC_VERT_HIGH_ACT) + par->misc &= ~0x80; + + par->mode = mode; + + if (mode & MODE_8BPP) + /* pixel clock == vga clock / 2 */ + vga16fb_clock_chip(par, var->pixclock, info, 1, 2); + else + /* pixel clock == vga clock */ + vga16fb_clock_chip(par, var->pixclock, info, 1, 1); + + var->red.offset = var->green.offset = var->blue.offset = + var->transp.offset = 0; + var->red.length = var->green.length = var->blue.length = + (par->isVGA) ? 6 : 2; + var->transp.length = 0; + var->activate = FB_ACTIVATE_NOW; + var->height = -1; + var->width = -1; + var->accel_flags = 0; + return 0; +} +#undef FAIL + +static int vga16fb_set_par(struct fb_info *info) +{ + struct vga16fb_par *par = (struct vga16fb_par *) info->par; + u8 gdc[VGA_GFX_C]; + u8 seq[VGA_SEQ_C]; + u8 atc[VGA_ATT_C]; + int fh, i; + + seq[VGA_SEQ_CLOCK_MODE] = 0x01 | par->clkdiv; + if (par->mode & MODE_TEXT) + seq[VGA_SEQ_PLANE_WRITE] = 0x03; + else + seq[VGA_SEQ_PLANE_WRITE] = 0x0F; + seq[VGA_SEQ_CHARACTER_MAP] = 0x00; + if (par->mode & MODE_TEXT) + seq[VGA_SEQ_MEMORY_MODE] = 0x03; + else if (par->mode & MODE_SKIP4) + seq[VGA_SEQ_MEMORY_MODE] = 0x0E; + else + seq[VGA_SEQ_MEMORY_MODE] = 0x06; + + gdc[VGA_GFX_SR_VALUE] = 0x00; + gdc[VGA_GFX_SR_ENABLE] = 0x00; + gdc[VGA_GFX_COMPARE_VALUE] = 0x00; + gdc[VGA_GFX_DATA_ROTATE] = 0x00; + gdc[VGA_GFX_PLANE_READ] = 0; + if (par->mode & MODE_TEXT) { + gdc[VGA_GFX_MODE] = 0x10; + gdc[VGA_GFX_MISC] = 0x06; + } else { + if (par->mode & MODE_CFB) + gdc[VGA_GFX_MODE] = 0x40; + else + gdc[VGA_GFX_MODE] = 0x00; + gdc[VGA_GFX_MISC] = 0x05; + } + gdc[VGA_GFX_COMPARE_MASK] = 0x0F; + gdc[VGA_GFX_BIT_MASK] = 0xFF; + + for (i = 0x00; i < 0x10; i++) + atc[i] = i; + if (par->mode & MODE_TEXT) + atc[VGA_ATC_MODE] = 0x04; + else if (par->mode & MODE_8BPP) + atc[VGA_ATC_MODE] = 0x41; + else + atc[VGA_ATC_MODE] = 0x81; + atc[VGA_ATC_OVERSCAN] = 0x00; /* 0 for EGA, 0xFF for VGA */ + atc[VGA_ATC_PLANE_ENABLE] = 0x0F; + if (par->mode & MODE_8BPP) + atc[VGA_ATC_PEL] = (info->var.xoffset & 3) << 1; + else + atc[VGA_ATC_PEL] = info->var.xoffset & 7; + atc[VGA_ATC_COLOR_PAGE] = 0x00; + + if (par->mode & MODE_TEXT) { + fh = 16; // FIXME !!! Fudge font height. + par->crtc[VGA_CRTC_MAX_SCAN] = (par->crtc[VGA_CRTC_MAX_SCAN] + & ~0x1F) | (fh - 1); + } + + vga_io_w(VGA_MIS_W, vga_io_r(VGA_MIS_R) | 0x01); + + /* Enable graphics register modification */ + if (!par->isVGA) { + vga_io_w(EGA_GFX_E0, 0x00); + vga_io_w(EGA_GFX_E1, 0x01); + } + + /* update misc output register */ + vga_io_w(VGA_MIS_W, par->misc); + + /* synchronous reset on */ + vga_io_wseq(0x00, 0x01); + + if (par->isVGA) + vga_io_w(VGA_PEL_MSK, par->pel_msk); + + /* write sequencer registers */ + vga_io_wseq(VGA_SEQ_CLOCK_MODE, seq[VGA_SEQ_CLOCK_MODE] | 0x20); + for (i = 2; i < VGA_SEQ_C; i++) { + vga_io_wseq(i, seq[i]); + } + + /* synchronous reset off */ + vga_io_wseq(0x00, 0x03); + + /* deprotect CRT registers 0-7 */ + vga_io_wcrt(VGA_CRTC_V_SYNC_END, par->crtc[VGA_CRTC_V_SYNC_END]); + + /* write CRT registers */ + for (i = 0; i < VGA_CRTC_REGS; i++) { + vga_io_wcrt(i, par->crtc[i]); + } + + /* write graphics controller registers */ + for (i = 0; i < VGA_GFX_C; i++) { + vga_io_wgfx(i, gdc[i]); + } + + /* write attribute controller registers */ + for (i = 0; i < VGA_ATT_C; i++) { + vga_io_r(VGA_IS1_RC); /* reset flip-flop */ + vga_io_wattr(i, atc[i]); + } + + /* Wait for screen to stabilize. */ + mdelay(50); + + vga_io_wseq(VGA_SEQ_CLOCK_MODE, seq[VGA_SEQ_CLOCK_MODE]); + + vga_io_r(VGA_IS1_RC); + vga_io_w(VGA_ATT_IW, 0x20); + + vga16fb_update_fix(info); + return 0; +} + +static void ega16_setpalette(int regno, unsigned red, unsigned green, unsigned blue) +{ + static unsigned char map[] = { 000, 001, 010, 011 }; + int val; + + if (regno >= 16) + return; + val = map[red>>14] | ((map[green>>14]) << 1) | ((map[blue>>14]) << 2); + vga_io_r(VGA_IS1_RC); /* ! 0x3BA */ + vga_io_wattr(regno, val); + vga_io_r(VGA_IS1_RC); /* some clones need it */ + vga_io_w(VGA_ATT_IW, 0x20); /* unblank screen */ +} + +static void vga16_setpalette(int regno, unsigned red, unsigned green, unsigned blue) +{ + outb(regno, dac_reg); + outb(red >> 10, dac_val); + outb(green >> 10, dac_val); + outb(blue >> 10, dac_val); +} + +static int vga16fb_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, + struct fb_info *info) +{ + struct vga16fb_par *par = (struct vga16fb_par *) info->par; + int gray; + + /* + * Set a single color register. The values supplied are + * already rounded down to the hardware's capabilities + * (according to the entries in the `var' structure). Return + * != 0 for invalid regno. + */ + + if (regno >= 256) + return 1; + + gray = info->var.grayscale; + + if (gray) { + /* gray = 0.30*R + 0.59*G + 0.11*B */ + red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8; + } + if (par->isVGA) + vga16_setpalette(regno,red,green,blue); + else + ega16_setpalette(regno,red,green,blue); + return 0; +} + +static int vga16fb_pan_display(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + if (var->xoffset + info->var.xres > info->var.xres_virtual || + var->yoffset + info->var.yres > info->var.yres_virtual) + return -EINVAL; + + vga16fb_pan_var(info, var); + + info->var.xoffset = var->xoffset; + info->var.yoffset = var->yoffset; + info->var.vmode &= ~FB_VMODE_YWRAP; + return 0; +} + +/* The following VESA blanking code is taken from vgacon.c. The VGA + blanking code was originally by Huang shi chao, and modified by + Christoph Rimek (chrimek@toppoint.de) and todd j. derr + (tjd@barefoot.org) for Linux. */ +#define attrib_port VGA_ATC_IW +#define seq_port_reg VGA_SEQ_I +#define seq_port_val VGA_SEQ_D +#define gr_port_reg VGA_GFX_I +#define gr_port_val VGA_GFX_D +#define video_misc_rd VGA_MIS_R +#define video_misc_wr VGA_MIS_W +#define vga_video_port_reg VGA_CRT_IC +#define vga_video_port_val VGA_CRT_DC + +static void vga_vesa_blank(struct vga16fb_par *par, int mode) +{ + unsigned char SeqCtrlIndex; + unsigned char CrtCtrlIndex; + + //cli(); + SeqCtrlIndex = vga_io_r(seq_port_reg); + CrtCtrlIndex = vga_io_r(vga_video_port_reg); + + /* save original values of VGA controller registers */ + if(!par->vesa_blanked) { + par->vga_state.CrtMiscIO = vga_io_r(video_misc_rd); + //sti(); + + par->vga_state.HorizontalTotal = vga_io_rcrt(0x00); /* HorizontalTotal */ + par->vga_state.HorizDisplayEnd = vga_io_rcrt(0x01); /* HorizDisplayEnd */ + par->vga_state.StartHorizRetrace = vga_io_rcrt(0x04); /* StartHorizRetrace */ + par->vga_state.EndHorizRetrace = vga_io_rcrt(0x05); /* EndHorizRetrace */ + par->vga_state.Overflow = vga_io_rcrt(0x07); /* Overflow */ + par->vga_state.StartVertRetrace = vga_io_rcrt(0x10); /* StartVertRetrace */ + par->vga_state.EndVertRetrace = vga_io_rcrt(0x11); /* EndVertRetrace */ + par->vga_state.ModeControl = vga_io_rcrt(0x17); /* ModeControl */ + par->vga_state.ClockingMode = vga_io_rseq(0x01); /* ClockingMode */ + } + + /* assure that video is enabled */ + /* "0x20" is VIDEO_ENABLE_bit in register 01 of sequencer */ + //cli(); + vga_io_wseq(0x01, par->vga_state.ClockingMode | 0x20); + + /* test for vertical retrace in process.... */ + if ((par->vga_state.CrtMiscIO & 0x80) == 0x80) + vga_io_w(video_misc_wr, par->vga_state.CrtMiscIO & 0xef); + + /* + * Set <End of vertical retrace> to minimum (0) and + * <Start of vertical Retrace> to maximum (incl. overflow) + * Result: turn off vertical sync (VSync) pulse. + */ + if (mode & VESA_VSYNC_SUSPEND) { + outb_p(0x10,vga_video_port_reg); /* StartVertRetrace */ + outb_p(0xff,vga_video_port_val); /* maximum value */ + outb_p(0x11,vga_video_port_reg); /* EndVertRetrace */ + outb_p(0x40,vga_video_port_val); /* minimum (bits 0..3) */ + outb_p(0x07,vga_video_port_reg); /* Overflow */ + outb_p(par->vga_state.Overflow | 0x84,vga_video_port_val); /* bits 9,10 of vert. retrace */ + } + + if (mode & VESA_HSYNC_SUSPEND) { + /* + * Set <End of horizontal retrace> to minimum (0) and + * <Start of horizontal Retrace> to maximum + * Result: turn off horizontal sync (HSync) pulse. + */ + outb_p(0x04,vga_video_port_reg); /* StartHorizRetrace */ + outb_p(0xff,vga_video_port_val); /* maximum */ + outb_p(0x05,vga_video_port_reg); /* EndHorizRetrace */ + outb_p(0x00,vga_video_port_val); /* minimum (0) */ + } + + /* restore both index registers */ + outb_p(SeqCtrlIndex,seq_port_reg); + outb_p(CrtCtrlIndex,vga_video_port_reg); + //sti(); +} + +static void vga_vesa_unblank(struct vga16fb_par *par) +{ + unsigned char SeqCtrlIndex; + unsigned char CrtCtrlIndex; + + //cli(); + SeqCtrlIndex = vga_io_r(seq_port_reg); + CrtCtrlIndex = vga_io_r(vga_video_port_reg); + + /* restore original values of VGA controller registers */ + vga_io_w(video_misc_wr, par->vga_state.CrtMiscIO); + + /* HorizontalTotal */ + vga_io_wcrt(0x00, par->vga_state.HorizontalTotal); + /* HorizDisplayEnd */ + vga_io_wcrt(0x01, par->vga_state.HorizDisplayEnd); + /* StartHorizRetrace */ + vga_io_wcrt(0x04, par->vga_state.StartHorizRetrace); + /* EndHorizRetrace */ + vga_io_wcrt(0x05, par->vga_state.EndHorizRetrace); + /* Overflow */ + vga_io_wcrt(0x07, par->vga_state.Overflow); + /* StartVertRetrace */ + vga_io_wcrt(0x10, par->vga_state.StartVertRetrace); + /* EndVertRetrace */ + vga_io_wcrt(0x11, par->vga_state.EndVertRetrace); + /* ModeControl */ + vga_io_wcrt(0x17, par->vga_state.ModeControl); + /* ClockingMode */ + vga_io_wseq(0x01, par->vga_state.ClockingMode); + + /* restore index/control registers */ + vga_io_w(seq_port_reg, SeqCtrlIndex); + vga_io_w(vga_video_port_reg, CrtCtrlIndex); + //sti(); +} + +static void vga_pal_blank(void) +{ + int i; + + for (i=0; i<16; i++) { + outb_p (i, dac_reg) ; + outb_p (0, dac_val) ; + outb_p (0, dac_val) ; + outb_p (0, dac_val) ; + } +} + +/* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */ +static int vga16fb_blank(int blank, struct fb_info *info) +{ + struct vga16fb_par *par = (struct vga16fb_par *) info->par; + + switch (blank) { + case 0: /* Unblank */ + if (par->vesa_blanked) { + vga_vesa_unblank(par); + par->vesa_blanked = 0; + } + if (par->palette_blanked) { + //do_install_cmap(info->currcon, info); + par->palette_blanked = 0; + } + break; + case 1: /* blank */ + vga_pal_blank(); + par->palette_blanked = 1; + break; + default: /* VESA blanking */ + vga_vesa_blank(par, blank-1); + par->vesa_blanked = 1; + break; + } + return 0; +} + +void vga_8planes_fillrect(struct fb_info *info, const struct fb_fillrect *rect) +{ + u32 dx = rect->dx, width = rect->width; + char oldindex = getindex(); + char oldmode = setmode(0x40); + char oldmask = selectmask(); + int line_ofs, height; + char oldop, oldsr; + char *where; + + dx /= 4; + where = info->screen_base + dx + rect->dy * info->fix.line_length; + + if (rect->rop == ROP_COPY) { + oldop = setop(0); + oldsr = setsr(0); + + width /= 4; + line_ofs = info->fix.line_length - width; + setmask(0xff); + + height = rect->height; + + while (height--) { + int x; + + /* we can do memset... */ + for (x = width; x > 0; --x) { + writeb(rect->color, where); + where++; + } + where += line_ofs; + } + } else { + char oldcolor = setcolor(0xf); + int y; + + oldop = setop(0x18); + oldsr = setsr(0xf); + setmask(0x0F); + for (y = 0; y < rect->height; y++) { + rmw(where); + rmw(where+1); + where += info->fix.line_length; + } + setcolor(oldcolor); + } + setmask(oldmask); + setsr(oldsr); + setop(oldop); + setmode(oldmode); + setindex(oldindex); +} + +void vga16fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) +{ + int x, x2, y2, vxres, vyres, width, height, line_ofs; + char *dst; + + vxres = info->var.xres_virtual; + vyres = info->var.yres_virtual; + + if (!rect->width || !rect->height || rect->dx > vxres || rect->dy > vyres) + return; + + /* We could use hardware clipping but on many cards you get around + * hardware clipping by writing to framebuffer directly. */ + + x2 = rect->dx + rect->width; + y2 = rect->dy + rect->height; + x2 = x2 < vxres ? x2 : vxres; + y2 = y2 < vyres ? y2 : vyres; + width = x2 - rect->dx; + + switch (info->fix.type) { + case FB_TYPE_VGA_PLANES: + if (info->fix.type_aux == FB_AUX_VGA_PLANES_VGA4) { + + height = y2 - rect->dy; + width = rect->width/8; + + line_ofs = info->fix.line_length - width; + dst = info->screen_base + (rect->dx/8) + rect->dy * info->fix.line_length; + + switch (rect->rop) { + case ROP_COPY: + setmode(0); + setop(0); + setsr(0xf); + setcolor(rect->color); + selectmask(); + + setmask(0xff); + + while (height--) { + for (x = 0; x < width; x++) { + writeb(0, dst); + dst++; + } + dst += line_ofs; + } + break; + case ROP_XOR: + setmode(0); + setop(0x18); + setsr(0xf); + setcolor(0xf); + selectmask(); + + setmask(0xff); + while (height--) { + for (x = 0; x < width; x++) { + rmw(dst); + dst++; + } + dst += line_ofs; + } + break; + } + } else + vga_8planes_fillrect(info, rect); + break; + case FB_TYPE_PACKED_PIXELS: + default: + cfb_fillrect(info, rect); + break; + } +} + +void vga_8planes_copyarea(struct fb_info *info, const struct fb_copyarea *area) +{ + char oldindex = getindex(); + char oldmode = setmode(0x41); + char oldop = setop(0); + char oldsr = setsr(0xf); + int height, line_ofs, x; + u32 sx, dx, width; + char *dest, *src; + + height = area->height; + + sx = area->sx / 4; + dx = area->dx / 4; + width = area->width / 4; + + if (area->dy < area->sy || (area->dy == area->sy && dx < sx)) { + line_ofs = info->fix.line_length - width; + dest = info->screen_base + dx + area->dy * info->fix.line_length; + src = info->screen_base + sx + area->sy * info->fix.line_length; + while (height--) { + for (x = 0; x < width; x++) { + readb(src); + writeb(0, dest); + src++; + dest++; + } + src += line_ofs; + dest += line_ofs; + } + } else { + line_ofs = info->fix.line_length - width; + dest = info->screen_base + dx + width + + (area->dy + height - 1) * info->fix.line_length; + src = info->screen_base + sx + width + + (area->sy + height - 1) * info->fix.line_length; + while (height--) { + for (x = 0; x < width; x++) { + --src; + --dest; + readb(src); + writeb(0, dest); + } + src -= line_ofs; + dest -= line_ofs; + } + } + + setsr(oldsr); + setop(oldop); + setmode(oldmode); + setindex(oldindex); +} + +void vga16fb_copyarea(struct fb_info *info, const struct fb_copyarea *area) +{ + u32 dx = area->dx, dy = area->dy, sx = area->sx, sy = area->sy; + int x, x2, y2, old_dx, old_dy, vxres, vyres; + int height, width, line_ofs; + char *dst = NULL, *src = NULL; + + vxres = info->var.xres_virtual; + vyres = info->var.yres_virtual; + + if (area->dx > vxres || area->sx > vxres || area->dy > vyres || + area->sy > vyres) + return; + + /* clip the destination */ + old_dx = area->dx; + old_dy = area->dy; + + /* + * We could use hardware clipping but on many cards you get around + * hardware clipping by writing to framebuffer directly. + */ + x2 = area->dx + area->width; + y2 = area->dy + area->height; + dx = area->dx > 0 ? area->dx : 0; + dy = area->dy > 0 ? area->dy : 0; + x2 = x2 < vxres ? x2 : vxres; + y2 = y2 < vyres ? y2 : vyres; + width = x2 - dx; + height = y2 - dy; + + /* update sx1,sy1 */ + sx += (dx - old_dx); + sy += (dy - old_dy); + + /* the source must be completely inside the virtual screen */ + if (sx < 0 || sy < 0 || (sx + width) > vxres || (sy + height) > vyres) + return; + + switch (info->fix.type) { + case FB_TYPE_VGA_PLANES: + if (info->fix.type_aux == FB_AUX_VGA_PLANES_VGA4) { + width = width/8; + height = height; + line_ofs = info->fix.line_length - width; + + setmode(1); + setop(0); + setsr(0xf); + + if (dy < sy || (dy == sy && dx < sx)) { + dst = info->screen_base + (dx/8) + dy * info->fix.line_length; + src = info->screen_base + (sx/8) + sy * info->fix.line_length; + while (height--) { + for (x = 0; x < width; x++) { + readb(src); + writeb(0, dst); + dst++; + src++; + } + src += line_ofs; + dst += line_ofs; + } + } else { + dst = info->screen_base + (dx/8) + width + + (dy + height - 1) * info->fix.line_length; + src = info->screen_base + (sx/8) + width + + (sy + height - 1) * info->fix.line_length; + while (height--) { + for (x = 0; x < width; x++) { + dst--; + src--; + readb(src); + writeb(0, dst); + } + src -= line_ofs; + dst -= line_ofs; + } + } + } else + vga_8planes_copyarea(info, area); + break; + case FB_TYPE_PACKED_PIXELS: + default: + cfb_copyarea(info, area); + break; + } +} + +#ifdef __LITTLE_ENDIAN +static unsigned int transl_l[] = +{0x0,0x8,0x4,0xC,0x2,0xA,0x6,0xE,0x1,0x9,0x5,0xD,0x3,0xB,0x7,0xF}; +static unsigned int transl_h[] = +{0x000, 0x800, 0x400, 0xC00, 0x200, 0xA00, 0x600, 0xE00, + 0x100, 0x900, 0x500, 0xD00, 0x300, 0xB00, 0x700, 0xF00}; +#else +#ifdef __BIG_ENDIAN +static unsigned int transl_h[] = +{0x0,0x8,0x4,0xC,0x2,0xA,0x6,0xE,0x1,0x9,0x5,0xD,0x3,0xB,0x7,0xF}; +static unsigned int transl_l[] = +{0x000, 0x800, 0x400, 0xC00, 0x200, 0xA00, 0x600, 0xE00, + 0x100, 0x900, 0x500, 0xD00, 0x300, 0xB00, 0x700, 0xF00}; +#else +#error "Only __BIG_ENDIAN and __LITTLE_ENDIAN are supported in vga-planes" +#endif +#endif + +void vga_8planes_imageblit(struct fb_info *info, const struct fb_image *image) +{ + char oldindex = getindex(); + char oldmode = setmode(0x40); + char oldop = setop(0); + char oldsr = setsr(0); + char oldmask = selectmask(); + const char *cdat = image->data; + u32 dx = image->dx; + char *where; + int y; + + dx /= 4; + where = info->screen_base + dx + image->dy * info->fix.line_length; + + setmask(0xff); + writeb(image->bg_color, where); + readb(where); + selectmask(); + setmask(image->fg_color ^ image->bg_color); + setmode(0x42); + setop(0x18); + for (y = 0; y < image->height; y++, where += info->fix.line_length) + writew(transl_h[cdat[y]&0xF] | transl_l[cdat[y] >> 4], where); + setmask(oldmask); + setsr(oldsr); + setop(oldop); + setmode(oldmode); + setindex(oldindex); +} + +void vga_imageblit_expand(struct fb_info *info, const struct fb_image *image) +{ + char *where = info->screen_base + (image->dx/8) + + image->dy * info->fix.line_length; + struct vga16fb_par *par = (struct vga16fb_par *) info->par; + char *cdat = (char *) image->data, *dst; + int x, y; + + switch (info->fix.type) { + case FB_TYPE_VGA_PLANES: + if (info->fix.type_aux == FB_AUX_VGA_PLANES_VGA4) { + if (par->isVGA) { + setmode(2); + setop(0); + setsr(0xf); + setcolor(image->fg_color); + selectmask(); + + setmask(0xff); + writeb(image->bg_color, where); + rmb(); + readb(where); /* fill latches */ + setmode(3); + wmb(); + for (y = 0; y < image->height; y++) { + dst = where; + for (x = image->width/8; x--;) + writeb(*cdat++, dst++); + where += info->fix.line_length; + } + wmb(); + } else { + setmode(0); + setop(0); + setsr(0xf); + setcolor(image->bg_color); + selectmask(); + + setmask(0xff); + for (y = 0; y < image->height; y++) { + dst = where; + for (x=image->width/8; x--;){ + rmw(dst); + setcolor(image->fg_color); + selectmask(); + if (*cdat) { + setmask(*cdat++); + rmw(dst++); + } + } + where += info->fix.line_length; + } + } + } else + vga_8planes_imageblit(info, image); + break; + case FB_TYPE_PACKED_PIXELS: + default: + cfb_imageblit(info, image); + break; + } +} + +void vga_imageblit_color(struct fb_info *info, const struct fb_image *image) +{ + /* + * Draw logo + */ + struct vga16fb_par *par = (struct vga16fb_par *) info->par; + char *where = info->screen_base + image->dy * info->fix.line_length + + image->dx/8; + const char *cdat = image->data, *dst; + int x, y; + + switch (info->fix.type) { + case FB_TYPE_VGA_PLANES: + if (info->fix.type_aux == FB_AUX_VGA_PLANES_VGA4 && + par->isVGA) { + setsr(0xf); + setop(0); + setmode(0); + + for (y = 0; y < image->height; y++) { + for (x = 0; x < image->width; x++) { + dst = where + x/8; + + setcolor(*cdat); + selectmask(); + setmask(1 << (7 - (x % 8))); + fb_readb(dst); + fb_writeb(0, dst); + + cdat++; + } + where += info->fix.line_length; + } + } + break; + case FB_TYPE_PACKED_PIXELS: + cfb_imageblit(info, image); + break; + default: + break; + } +} + +void vga16fb_imageblit(struct fb_info *info, const struct fb_image *image) +{ + if (image->depth == 1) + vga_imageblit_expand(info, image); + else if (image->depth <= info->var.bits_per_pixel) + vga_imageblit_color(info, image); +} + +#ifdef CONFIG_FB_UI +static void vga16fb_point (struct fb_info *info, short x, short y, u32 rgb) +{ +} +static void vga16fb_hline (struct fb_info *info, short x0, short x1, short y, u32 rgb) +{ +} +static void vga16fb_vline (struct fb_info *info, short x, short y0, short y1, u32 rgb) +{ +} +static u32 vga16fb_read_point (struct fb_info *info, short x, short y) +{ +} +static u32 vga16fb_putpixels_native (struct fb_info *info, short x, short y, + short n, unsigned char *src, char in_kernel) +{ +} +static u32 vga16fb_getpixels_rgb (struct fb_info *info, short x, short y, + short n, unsigned char *src, char in_kernel) +{ +} +static u32 vga16fb_putpixels_rgb (struct fb_info *info, short x, short y, + short n, unsigned char *src, char in_kernel) +{ +} +static u32 vga16fb_putpixels_rgb3 (struct fb_info *info, short x, short y, + short n, unsigned char *src, char in_kernel) +{ +} +static u32 vga16fb_copyarea2 (struct fb_info *info, short xsrc, short ysrc, + short w, short h, short xdest, short ydest) +{ +} +#endif + +static struct fb_ops vga16fb_ops = { + .owner = THIS_MODULE, + .fb_open = vga16fb_open, + .fb_release = vga16fb_release, + .fb_check_var = vga16fb_check_var, + .fb_set_par = vga16fb_set_par, + .fb_setcolreg = vga16fb_setcolreg, + .fb_pan_display = vga16fb_pan_display, + .fb_blank = vga16fb_blank, + .fb_fillrect = vga16fb_fillrect, + .fb_copyarea = vga16fb_copyarea, + .fb_imageblit = vga16fb_imageblit, + .fb_cursor = soft_cursor, + +#ifdef CONFIG_FB_UI + .fb_point = vga16fb_point, + .fb_hline = vga16fb_hline, + .fb_vline = vga16fb_vline, + .fb_clear = vga16fb_clear, + .fb_hline = vga16fb_hline, + .fb_read_point = vga16fb_read_point, + .fb_putpixels_native = vga16fb_putpixels_native, + .fb_putpixels_rgb = vga16fb_putpixels_rgb, + .fb_getpixels_rgb = vga16fb_getpixels_rgb, + .fb_putpixels_rgb3 = vga16fb_putpixels_rgb3, + .fb_copyarea2 = vga16fb_copyarea2, +#endif +}; + + +int vga16fb_setup(char *options) +{ + char *this_opt; + + if (!options || !*options) + return 0; + + while ((this_opt = strsep(&options, ",")) != NULL) { + if (!*this_opt) continue; + } + return 0; +} + +int __init vga16fb_init(void) +{ + int i; + int ret; +#ifndef MODULE + char *option = NULL; + + if (fb_get_options("vga16fb", &option)) + return -ENODEV; + + vga16fb_setup(option); +#endif + printk(KERN_DEBUG "vga16fb: initializing\n"); + + /* XXX share VGA_FB_PHYS and I/O region with vgacon and others */ + + vga16fb.screen_base = (void *)VGA_MAP_MEM(VGA_FB_PHYS); + if (!vga16fb.screen_base) { + printk(KERN_ERR "vga16fb: unable to map device\n"); + ret = -ENOMEM; + goto err_ioremap; + } + printk(KERN_INFO "vga16fb: mapped to 0x%p\n", vga16fb.screen_base); + + vga16_par.isVGA = ORIG_VIDEO_ISVGA; + vga16_par.palette_blanked = 0; + vga16_par.vesa_blanked = 0; + + i = vga16_par.isVGA? 6 : 2; + + vga16fb_defined.red.length = i; + vga16fb_defined.green.length = i; + vga16fb_defined.blue.length = i; + + /* name should not depend on EGA/VGA */ + vga16fb.fbops = &vga16fb_ops; + vga16fb.var = vga16fb_defined; + vga16fb.fix = vga16fb_fix; + vga16fb.par = &vga16_par; + vga16fb.flags = FBINFO_FLAG_DEFAULT | + FBINFO_HWACCEL_YPAN; + + i = (vga16fb_defined.bits_per_pixel == 8) ? 256 : 16; + ret = fb_alloc_cmap(&vga16fb.cmap, i, 0); + if (ret) { + printk(KERN_ERR "vga16fb: unable to allocate colormap\n"); + ret = -ENOMEM; + goto err_alloc_cmap; + } + + if (vga16fb_check_var(&vga16fb.var, &vga16fb)) { + printk(KERN_ERR "vga16fb: unable to validate variable\n"); + ret = -EINVAL; + goto err_check_var; + } + + vga16fb_update_fix(&vga16fb); + + if (register_framebuffer(&vga16fb) < 0) { + printk(KERN_ERR "vga16fb: unable to register framebuffer\n"); + ret = -EINVAL; + goto err_check_var; + } + + printk(KERN_INFO "fb%d: %s frame buffer device\n", + vga16fb.node, vga16fb.fix.id); + + return 0; + + err_check_var: + fb_dealloc_cmap(&vga16fb.cmap); + err_alloc_cmap: + iounmap(vga16fb.screen_base); + err_ioremap: + return ret; +} + +static void __exit vga16fb_exit(void) +{ + unregister_framebuffer(&vga16fb); + iounmap(vga16fb.screen_base); + fb_dealloc_cmap(&vga16fb.cmap); + /* XXX unshare VGA regions */ +} + +#ifdef MODULE +MODULE_LICENSE("GPL"); +#endif +module_init(vga16fb_init); +module_exit(vga16fb_exit); + + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * --------------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ + diff --git a/include/linux/fb.h b/include/linux/fb.h @@ -0,0 +1,1209 @@ +#ifndef _LINUX_FB_H +#define _LINUX_FB_H + +#include <asm/types.h> + +/* Definitions of frame buffers */ + +#define FB_MAJOR 29 +#define FB_MAX 32 /* sufficient for now */ + +/* ioctls + 0x46 is 'F' */ +#define FBIOGET_VSCREENINFO 0x4600 +#define FBIOPUT_VSCREENINFO 0x4601 +#define FBIOGET_FSCREENINFO 0x4602 +#define FBIOGETCMAP 0x4604 +#define FBIOPUTCMAP 0x4605 +#define FBIOPAN_DISPLAY 0x4606 +#ifdef __KERNEL__ +#define FBIO_CURSOR _IOWR('F', 0x08, struct fb_cursor_user) +#else +#define FBIO_CURSOR _IOWR('F', 0x08, struct fb_cursor) +#endif +/* 0x4607-0x460B are defined below */ +/* #define FBIOGET_MONITORSPEC 0x460C */ +/* #define FBIOPUT_MONITORSPEC 0x460D */ +/* #define FBIOSWITCH_MONIBIT 0x460E */ +#define FBIOGET_CON2FBMAP 0x460F +#define FBIOPUT_CON2FBMAP 0x4610 +#define FBIOBLANK 0x4611 /* arg: 0 or vesa level + 1 */ +#define FBIOGET_VBLANK _IOR('F', 0x12, struct fb_vblank) +#define FBIO_ALLOC 0x4613 +#define FBIO_FREE 0x4614 +#define FBIOGET_GLYPH 0x4615 +#define FBIOGET_HWCINFO 0x4616 +#define FBIOPUT_MODEINFO 0x4617 +#define FBIOGET_DISPINFO 0x4618 + + +/* ==========================================================================*/ +/* FBUI ioctls */ +/* FBUI additions by Zachary T Smith, fbui@comcast.net */ + +#define FBIO_UI_OPEN 0x4619 /* arg = ptr to fb_ui_open */ +#define FBIO_UI_CLOSE 0x461a /* no arg */ + /* Exec commands are queued and are not executed if window + * is not visible. */ +#define FBIO_UI_EXEC 0x461b /* arg = ptr to array of shorts (1st=count) */ + /* Control commands are _not_ queued and are always executed*/ +#define FBIO_UI_CONTROL 0x461c /* arg = ptr to fbui_ctrlparams struct */ +#define FBUI_NAMELEN 32 +typedef unsigned long RGB; + +/* FBUI program type hints for fbui_openparams */ +#define FBUI_PROGTYPE_NONE 0 +#define FBUI_PROGTYPE_APP 1 /* e.g. takes main area */ +#define FBUI_PROGTYPE_LAUNCHER 2 /* e.g. takes bottom row area */ +#define FBUI_PROGTYPE_TOOL 3 /* e.g. fbclock: takes right area permanently */ +#define FBUI_PROGTYPE_EPHEMERAL 4 /* e.g. calculator */ +#define FBUI_PROGTYPE_WM 5 /* window mgr, panel mgr */ +#define FBUI_PROGTYPE_LAST 6 /* not for use */ + +/* A few accelerator keys encoded into 0..31 */ +#define FBUI_ACCEL_PRTSC 1 +#define FBUI_ACCEL_HOME 2 +#define FBUI_ACCEL_END 3 +#define FBUI_ACCEL_PGUP 4 +#define FBUI_ACCEL_PGDN 5 + +#define FBUI_BUTTON_LEFT 2 +#define FBUI_BUTTON_RIGHT 4 +#define FBUI_BUTTON_MIDDLE 8 + + +/* Passed _in_ to FBIO_UI_OPEN ioctl */ +struct fbui_openparams { + char desired_vc; /* -1 = current */ + char req_control; /* maximum one window manager per vc */ + char doing_autoposition; /* used to differentiate btw fbwm & fbpm */ + char program_type; /* if !0, window is hidden upon creation, wm informed */ + char need_keys; /* key focus */ + char need_motion; /* pointer focus */ + char receive_all_motion; /* supported for window manager only */ + char initially_hidden; + short x0; + short y0; + short x1; + short y1; + short max_width; + short max_height; + __u32 bgcolor; + char name [FBUI_NAMELEN]; + char subtitle [FBUI_NAMELEN]; +}; + +/* Data passed _out_ kernel via FBUI_WININFO command */ +struct fbui_wininfo { + short id; + int pid; + char program_type; + char hidden; + char need_placement; + char need_keys; + char need_motion; + short x, y; + short width, height; + short max_width; + short max_height; + char name [FBUI_NAMELEN]; + char subtitle [FBUI_NAMELEN]; +}; + +/* Data passed _out_ kernel via FBUI_POLLEVENT & FBUI_WAITEVENT commands */ +struct fbui_event { + char type; + short id; + int pid; + short x, y; + short width, height; + short key; +}; + +/* Passed _in_ to FBIO_UI_CONTROL + */ +struct fbui_ctrlparams { + char op; + short id; + short id2; /* used by wm */ + short x,y; + short width,height; + struct fbui_wininfo *info; /* passed _out_ */ + int ninfo; + unsigned char *pointer; + unsigned long cutpaste_length; + struct fbui_event *event; /* passed _out_ */ + char string [FBUI_NAMELEN]; +}; + +#define FBUI_EVENTMASK_KEY 1 +#define FBUI_EVENTMASK_EXPOSE 2 +#define FBUI_EVENTMASK_HIDE 4 +#define FBUI_EVENTMASK_UNHIDE 8 +#define FBUI_EVENTMASK_ENTER 16 +#define FBUI_EVENTMASK_LEAVE 32 +#define FBUI_EVENTMASK_MR 64 +#define FBUI_EVENTMASK_ACCEL 128 +#define FBUI_EVENTMASK_WC 256 +#define FBUI_EVENTMASK_MOTION 512 +#define FBUI_EVENTMASK_BUTTON 1024 +#define FBUI_EVENTMASK_ALL 0x7fff + +/* Commands for FBIO_UI_CONTROL ioctl */ +#define FBUI_GETDIMS 0 +#define FBUI_POLLEVENT 1 +#define FBUI_READMOUSE 2 +#define FBUI_READPOINT 3 /* wm only */ +#define FBUI_ACCEL 4 +#define FBUI_WININFO 5 /* wm only */ +#define FBUI_SUSPEND 6 /* wm only */ +#define FBUI_RESUME 7 +#define FBUI_GETPOSN 8 +#define FBUI_WAITEVENT 9 +#define FBUI_PLACEMENT 10 /* wm only */ +#define FBUI_CUT 11 +#define FBUI_PASTE 12 +#define FBUI_CUTLENGTH 13 +#define FBUI_SUBTITLE 14 +#define FBUI_SETFONT 15 + +#define FBUI_CTL_TAKESWIN 32 +/* Numbers >= FBUI_CTL_TAKESWIN take a window argument */ +#define FBUI_REDRAW (FBUI_CTL_TAKESWIN+1) /* wm only */ +#define FBUI_DELETE (FBUI_CTL_TAKESWIN+2) /* wm only */ +#define FBUI_HIDE (FBUI_CTL_TAKESWIN+3) /* wm only */ +#define FBUI_UNHIDE (FBUI_CTL_TAKESWIN+4) /* wm only */ +#define FBUI_ASSIGN_KEYFOCUS (FBUI_CTL_TAKESWIN+5) /* wm only */ +#define FBUI_ASSIGN_PTRFOCUS (FBUI_CTL_TAKESWIN+7) /* wm only */ +#define FBUI_MOVE_RESIZE (FBUI_CTL_TAKESWIN+6) /* wm only */ + +/* FBUI font weight */ +#define FB_FONTWEIGHT_LIGHT (0) +#define FB_FONTWEIGHT_MEDIUM (1) +#define FB_FONTWEIGHT_BOLD (2) +#define FB_FONTWEIGHT_BLACK (3) + +/* FBUI font */ +struct fbui_font { + unsigned char ascent; + unsigned char descent; + unsigned char first_char; + unsigned char last_char; + unsigned char nchars; + unsigned char *lefts; + unsigned char *heights; + unsigned char *widths; /* # of bits used for pixels */ + unsigned char *bitwidths; /* # bits actually used.. e.g. 32 */ + unsigned char *descents; + unsigned char *bitmap_buffer; + unsigned char **bitmaps; +}; +#define FBUI_FONTSIZE sizeof(struct fbui_font) + +/* Some useful colors */ +#define RGB_NOCOLOR 0xff000000 +#define RGB_TRANSP 0xff000000 +#define RGB_BLACK 0 +#define RGB_GRAY 0xa0a0a0 +#define RGB_WHITE 0xffffff +#define RGB_RED 0xff0000 +#define RGB_GREEN 0xff00 +#define RGB_BLUE 0xff +#define RGB_CYAN 0xffff +#define RGB_YELLOW 0xffff00 +#define RGB_MAGENTA 0xff00ff +#define RGB_ORANGE 0xffa000 +#define RGB_PURPLE 0xa030ff +#define RGB_LTBROWN 0xb54c4c +#define RGB_BROWN 0xa52c2c +#define RGB_STEELBLUE 0x4682B4 +#define RGB_SIENNA 0x605230 + +/* FBUI event types. Events are 31-bit values; type is lower 4 bits */ +#define FBUI_EVENT_NONE 0 +#define FBUI_EVENT_EXPOSE 1 +#define FBUI_EVENT_HIDE 2 +#define FBUI_EVENT_UNHIDE 3 +#define FBUI_EVENT_ENTER 4 /* future... mouse pointer enter */ +#define FBUI_EVENT_LEAVE 5 /* future... mouse pointer leave */ +#define FBUI_EVENT_KEY 6 +#define FBUI_EVENT_MOVE_RESIZE 7 /* window was moved by wm */ +#define FBUI_EVENT_ACCEL 8 /* keyboard accelerator (Alt-) key */ +#define FBUI_EVENT_WINCHANGE 9 /* recv'd only by window manager */ +#define FBUI_EVENT_MOTION 10 /* mouse pointer moved */ +#define FBUI_EVENT_BUTTON 11 /* mouse button activity */ + +/* FBUI queued commands: for use with FBIO_UI_EXEC ioctl */ +#define FBUI_NONE 0 +#define FBUI_COPYAREA 1 +#define FBUI_POINT 2 +#define FBUI_LINE 3 +#define FBUI_HLINE 4 +#define FBUI_VLINE 5 +#define FBUI_RECT 6 +#define FBUI_FILLAREA 7 +#define FBUI_CLEAR 8 +#define FBUI_INVERTLINE 9 +#define FBUI_STRING 10 +#define FBUI_PUT 11 +#define FBUI_PUTRGB 12 +#define FBUI_PUTRGB3 13 +#define FBUI_CLEARAREA 14 +#define FBUI_TINYBLIT 15 + +/* FBUI ioctl return values */ +#define FBUI_SUCCESS 0 +#define FBUI_ERR_BADADDR -254 +#define FBUI_ERR_NULLPTR -253 +#define FBUI_ERR_OFFSCREEN -252 +#define FBUI_ERR_NOTRUNNING -251 +#define FBUI_ERR_WRONGVISUAL -250 +#define FBUI_ERR_NOTPLACED -249 +#define FBUI_ERR_BIGENDIAN -248 +#define FBUI_ERR_INVALIDCMD -247 +#define FBUI_ERR_BADPID -246 +#define FBUI_ERR_ACCELBUSY -245 +#define FBUI_ERR_NOFONT -244 +#define FBUI_ERR_NOMEM -243 +#define FBUI_ERR_NOTOPEN -242 +#define FBUI_ERR_OVERLAP -241 +#define FBUI_ERR_ALREADYOPEN -240 +#define FBUI_ERR_MISSINGWIN -239 +#define FBUI_ERR_NOTWM -238 +#define FBUI_ERR_WRONGWM -237 +#define FBUI_ERR_HAVEWM -236 +#define FBUI_ERR_KEYFOCUSDENIED -235 +#define FBUI_ERR_KEYFOCUSERR -234 +#define FBUI_ERR_BADPARAM -233 +#define FBUI_ERR_NOMOUSE -232 +#define FBUI_ERR_MOUSEREAD -231 +#define FBUI_ERR_OVERLARGECUT -230 +#define FBUI_ERR_BADWIN -229 +#define FBUI_ERR_PASTEFAIL -228 +#define FBUI_ERR_CUTFAIL -227 +#define FBUI_ERR_NOEVENT -226 +#define FBUI_ERR_DRAWING -225 +#define FBUI_ERR_MISSINGPROCENT -224 +#define FBUI_ERR_BADVC -223 + +/* ==========================================================================*/ + +#define FB_TYPE_PACKED_PIXELS 0 /* Packed Pixels */ +#define FB_TYPE_PLANES 1 /* Non interleaved planes */ +#define FB_TYPE_INTERLEAVED_PLANES 2 /* Interleaved planes */ +#define FB_TYPE_TEXT 3 /* Text/attributes */ +#define FB_TYPE_VGA_PLANES 4 /* EGA/VGA planes */ + +#define FB_AUX_TEXT_MDA 0 /* Monochrome text */ +#define FB_AUX_TEXT_CGA 1 /* CGA/EGA/VGA Color text */ +#define FB_AUX_TEXT_S3_MMIO 2 /* S3 MMIO fasttext */ +#define FB_AUX_TEXT_MGA_STEP16 3 /* MGA Millenium I: text, attr, 14 reserved bytes */ +#define FB_AUX_TEXT_MGA_STEP8 4 /* other MGAs: text, attr, 6 reserved bytes */ + +#define FB_AUX_VGA_PLANES_VGA4 0 /* 16 color planes (EGA/VGA) */ +#define FB_AUX_VGA_PLANES_CFB4 1 /* CFB4 in planes (VGA) */ +#define FB_AUX_VGA_PLANES_CFB8 2 /* CFB8 in planes (VGA) */ + +#define FB_VISUAL_MONO01 0 /* Monochr. 1=Black 0=White */ +#define FB_VISUAL_MONO10 1 /* Monochr. 1=White 0=Black */ +#define FB_VISUAL_TRUECOLOR 2 /* True color */ +#define FB_VISUAL_PSEUDOCOLOR 3 /* Pseudo color (like atari) */ +#define FB_VISUAL_DIRECTCOLOR 4 /* Direct color */ +#define FB_VISUAL_STATIC_PSEUDOCOLOR 5 /* Pseudo color readonly */ + +#define FB_ACCEL_NONE 0 /* no hardware accelerator */ +#define FB_ACCEL_ATARIBLITT 1 /* Atari Blitter */ +#define FB_ACCEL_AMIGABLITT 2 /* Amiga Blitter */ +#define FB_ACCEL_S3_TRIO64 3 /* Cybervision64 (S3 Trio64) */ +#define FB_ACCEL_NCR_77C32BLT 4 /* RetinaZ3 (NCR 77C32BLT) */ +#define FB_ACCEL_S3_VIRGE 5 /* Cybervision64/3D (S3 ViRGE) */ +#define FB_ACCEL_ATI_MACH64GX 6 /* ATI Mach 64GX family */ +#define FB_ACCEL_DEC_TGA 7 /* DEC 21030 TGA */ +#define FB_ACCEL_ATI_MACH64CT 8 /* ATI Mach 64CT family */ +#define FB_ACCEL_ATI_MACH64VT 9 /* ATI Mach 64CT family VT class */ +#define FB_ACCEL_ATI_MACH64GT 10 /* ATI Mach 64CT family GT class */ +#define FB_ACCEL_SUN_CREATOR 11 /* Sun Creator/Creator3D */ +#define FB_ACCEL_SUN_CGSIX 12 /* Sun cg6 */ +#define FB_ACCEL_SUN_LEO 13 /* Sun leo/zx */ +#define FB_ACCEL_IMS_TWINTURBO 14 /* IMS Twin Turbo */ +#define FB_ACCEL_3DLABS_PERMEDIA2 15 /* 3Dlabs Permedia 2 */ +#define FB_ACCEL_MATROX_MGA2064W 16 /* Matrox MGA2064W (Millenium) */ +#define FB_ACCEL_MATROX_MGA1064SG 17 /* Matrox MGA1064SG (Mystique) */ +#define FB_ACCEL_MATROX_MGA2164W 18 /* Matrox MGA2164W (Millenium II) */ +#define FB_ACCEL_MATROX_MGA2164W_AGP 19 /* Matrox MGA2164W (Millenium II) */ +#define FB_ACCEL_MATROX_MGAG100 20 /* Matrox G100 (Productiva G100) */ +#define FB_ACCEL_MATROX_MGAG200 21 /* Matrox G200 (Myst, Mill, ...) */ +#define FB_ACCEL_SUN_CG14 22 /* Sun cgfourteen */ +#define FB_ACCEL_SUN_BWTWO 23 /* Sun bwtwo */ +#define FB_ACCEL_SUN_CGTHREE 24 /* Sun cgthree */ +#define FB_ACCEL_SUN_TCX 25 /* Sun tcx */ +#define FB_ACCEL_MATROX_MGAG400 26 /* Matrox G400 */ +#define FB_ACCEL_NV3 27 /* nVidia RIVA 128 */ +#define FB_ACCEL_NV4 28 /* nVidia RIVA TNT */ +#define FB_ACCEL_NV5 29 /* nVidia RIVA TNT2 */ +#define FB_ACCEL_CT_6555x 30 /* C&T 6555x */ +#define FB_ACCEL_3DFX_BANSHEE 31 /* 3Dfx Banshee */ +#define FB_ACCEL_ATI_RAGE128 32 /* ATI Rage128 family */ +#define FB_ACCEL_IGS_CYBER2000 33 /* CyberPro 2000 */ +#define FB_ACCEL_IGS_CYBER2010 34 /* CyberPro 2010 */ +#define FB_ACCEL_IGS_CYBER5000 35 /* CyberPro 5000 */ +#define FB_ACCEL_SIS_GLAMOUR 36 /* SiS 300/630/540 */ +#define FB_ACCEL_3DLABS_PERMEDIA3 37 /* 3Dlabs Permedia 3 */ +#define FB_ACCEL_ATI_RADEON 38 /* ATI Radeon family */ +#define FB_ACCEL_I810 39 /* Intel 810/815 */ +#define FB_ACCEL_SIS_GLAMOUR_2 40 /* SiS 315, 650, 740 */ +#define FB_ACCEL_SIS_XABRE 41 /* SiS 330 ("Xabre") */ + +#define FB_ACCEL_NEOMAGIC_NM2070 90 /* NeoMagic NM2070 */ +#define FB_ACCEL_NEOMAGIC_NM2090 91 /* NeoMagic NM2090 */ +#define FB_ACCEL_NEOMAGIC_NM2093 92 /* NeoMagic NM2093 */ +#define FB_ACCEL_NEOMAGIC_NM2097 93 /* NeoMagic NM2097 */ +#define FB_ACCEL_NEOMAGIC_NM2160 94 /* NeoMagic NM2160 */ +#define FB_ACCEL_NEOMAGIC_NM2200 95 /* NeoMagic NM2200 */ +#define FB_ACCEL_NEOMAGIC_NM2230 96 /* NeoMagic NM2230 */ +#define FB_ACCEL_NEOMAGIC_NM2360 97 /* NeoMagic NM2360 */ +#define FB_ACCEL_NEOMAGIC_NM2380 98 /* NeoMagic NM2380 */ + + +struct fb_fix_screeninfo { + char id[16]; /* identification string eg "TT Builtin" */ + unsigned long smem_start; /* Start of frame buffer mem */ + /* (physical address) */ + __u32 smem_len; /* Length of frame buffer mem */ + __u32 type; /* see FB_TYPE_* */ + __u32 type_aux; /* Interleave for interleaved Planes */ + __u32 visual; /* see FB_VISUAL_* */ + __u16 xpanstep; /* zero if no hardware panning */ + __u16 ypanstep; /* zero if no hardware panning */ + __u16 ywrapstep; /* zero if no hardware ywrap */ + __u32 line_length; /* length of a line in bytes */ + unsigned long mmio_start; /* Start of Memory Mapped I/O */ + /* (physical address) */ + __u32 mmio_len; /* Length of Memory Mapped I/O */ + __u32 accel; /* Indicate to driver which */ + /* specific chip/card we have */ + __u16 reserved[3]; /* Reserved for future compatibility */ +}; + +/* Interpretation of offset for color fields: All offsets are from the right, + * inside a "pixel" value, which is exactly 'bits_per_pixel' wide (means: you + * can use the offset as right argument to <<). A pixel afterwards is a bit + * stream and is written to video memory as that unmodified. This implies + * big-endian byte order if bits_per_pixel is greater than 8. + */ +struct fb_bitfield { + __u32 offset; /* beginning of bitfield */ + __u32 length; /* length of bitfield */ + __u32 msb_right; /* != 0 : Most significant bit is */ + /* right */ +}; + +#define FB_NONSTD_HAM 1 /* Hold-And-Modify (HAM) */ + +#define FB_ACTIVATE_NOW 0 /* set values immediately (or vbl)*/ +#define FB_ACTIVATE_NXTOPEN 1 /* activate on next open */ +#define FB_ACTIVATE_TEST 2 /* don't set, round up impossible */ +#define FB_ACTIVATE_MASK 15 + /* values */ +#define FB_ACTIVATE_VBL 16 /* activate values on next vbl */ +#define FB_CHANGE_CMAP_VBL 32 /* change colormap on vbl */ +#define FB_ACTIVATE_ALL 64 /* change all VCs on this fb */ +#define FB_ACTIVATE_FORCE 128 /* force apply even when no change*/ +#define FB_ACTIVATE_INV_MODE 256 /* invalidate videomode */ + +#define FB_ACCELF_TEXT 1 /* (OBSOLETE) see fb_info.flags and vc_mode */ + +#define FB_SYNC_HOR_HIGH_ACT 1 /* horizontal sync high active */ +#define FB_SYNC_VERT_HIGH_ACT 2 /* vertical sync high active */ +#define FB_SYNC_EXT 4 /* external sync */ +#define FB_SYNC_COMP_HIGH_ACT 8 /* composite sync high active */ +#define FB_SYNC_BROADCAST 16 /* broadcast video timings */ + /* vtotal = 144d/288n/576i => PAL */ + /* vtotal = 121d/242n/484i => NTSC */ +#define FB_SYNC_ON_GREEN 32 /* sync on green */ + +#define FB_VMODE_NONINTERLACED 0 /* non interlaced */ +#define FB_VMODE_INTERLACED 1 /* interlaced */ +#define FB_VMODE_DOUBLE 2 /* double scan */ +#define FB_VMODE_MASK 255 + +#define FB_VMODE_YWRAP 256 /* ywrap instead of panning */ +#define FB_VMODE_SMOOTH_XPAN 512 /* smooth xpan possible (internally used) */ +#define FB_VMODE_CONUPDATE 512 /* don't update x/yoffset */ + +#define PICOS2KHZ(a) (1000000000UL/(a)) +#define KHZ2PICOS(a) (1000000000UL/(a)) + +struct fb_var_screeninfo { + __u32 xres; /* visible resolution */ + __u32 yres; + __u32 xres_virtual; /* virtual resolution */ + __u32 yres_virtual; + __u32 xoffset; /* offset from virtual to visible */ + __u32 yoffset; /* resolution */ + + __u32 bits_per_pixel; /* guess what */ + __u32 grayscale; /* != 0 Graylevels instead of colors */ + + struct fb_bitfield red; /* bitfield in fb mem if true color, */ + struct fb_bitfield green; /* else only length is significant */ + struct fb_bitfield blue; + struct fb_bitfield transp; /* transparency */ + + __u32 nonstd; /* != 0 Non standard pixel format */ + + __u32 activate; /* see FB_ACTIVATE_* */ + + __u32 height; /* height of picture in mm */ + __u32 width; /* width of picture in mm */ + + __u32 accel_flags; /* (OBSOLETE) see fb_info.flags */ + + /* Timing: All values in pixclocks, except pixclock (of course) */ + __u32 pixclock; /* pixel clock in ps (pico seconds) */ + __u32 left_margin; /* time from sync to picture */ + __u32 right_margin; /* time from picture to sync */ + __u32 upper_margin; /* time from sync to picture */ + __u32 lower_margin; + __u32 hsync_len; /* length of horizontal sync */ + __u32 vsync_len; /* length of vertical sync */ + __u32 sync; /* see FB_SYNC_* */ + __u32 vmode; /* see FB_VMODE_* */ + __u32 rotate; /* angle we rotate counter clockwise */ + __u32 reserved[5]; /* Reserved for future compatibility */ +}; + +struct fb_cmap { + __u32 start; /* First entry */ + __u32 len; /* Number of entries */ + __u16 *red; /* Red values */ + __u16 *green; + __u16 *blue; + __u16 *transp; /* transparency, can be NULL */ +}; + +struct fb_con2fbmap { + __u32 console; + __u32 framebuffer; +}; + +/* VESA Blanking Levels */ +#define VESA_NO_BLANKING 0 +#define VESA_VSYNC_SUSPEND 1 +#define VESA_HSYNC_SUSPEND 2 +#define VESA_POWERDOWN 3 + +#define FB_VBLANK_VBLANKING 0x001 /* currently in a vertical blank */ +#define FB_VBLANK_HBLANKING 0x002 /* currently in a horizontal blank */ +#define FB_VBLANK_HAVE_VBLANK 0x004 /* vertical blanks can be detected */ +#define FB_VBLANK_HAVE_HBLANK 0x008 /* horizontal blanks can be detected */ +#define FB_VBLANK_HAVE_COUNT 0x010 /* global retrace counter is available */ +#define FB_VBLANK_HAVE_VCOUNT 0x020 /* the vcount field is valid */ +#define FB_VBLANK_HAVE_HCOUNT 0x040 /* the hcount field is valid */ +#define FB_VBLANK_VSYNCING 0x080 /* currently in a vsync */ +#define FB_VBLANK_HAVE_VSYNC 0x100 /* verical syncs can be detected */ + +struct fb_vblank { + __u32 flags; /* FB_VBLANK flags */ + __u32 count; /* counter of retraces since boot */ + __u32 vcount; /* current scanline position */ + __u32 hcount; /* current scandot position */ + __u32 reserved[4]; /* reserved for future compatibility */ +}; + +/* Internal HW accel */ +#define ROP_COPY 0 +#define ROP_XOR 1 + +struct fb_copyarea { + __u32 dx; + __u32 dy; + __u32 width; + __u32 height; + __u32 sx; + __u32 sy; +}; + +struct fb_fillrect { + __u32 dx; /* screen-relative */ + __u32 dy; + __u32 width; + __u32 height; + __u32 color; + __u32 rop; +}; + +struct fb_image { + __u32 dx; /* Where to place image */ + __u32 dy; + __u32 width; /* Size of image */ + __u32 height; + __u32 fg_color; /* Only used when a mono bitmap */ + __u32 bg_color; + __u8 depth; /* Depth of the image */ + const char *data; /* Pointer to image data */ + struct fb_cmap cmap; /* color map info */ +}; + +/* + * hardware cursor control + */ + +#define FB_CUR_SETCUR 0x01 +#define FB_CUR_SETPOS 0x02 +#define FB_CUR_SETHOT 0x04 +#define FB_CUR_SETCMAP 0x08 +#define FB_CUR_SETSHAPE 0x10 +#define FB_CUR_SETSIZE 0x20 +#define FB_CUR_SETALL 0xFF + +struct fbcurpos { + __u16 x, y; +}; + +struct fb_cursor { + __u16 set; /* what to set */ + __u16 enable; /* cursor on/off */ + __u16 rop; /* bitop operation */ + const char *mask; /* cursor mask bits */ + struct fbcurpos hot; /* cursor hot spot */ + struct fb_image image; /* Cursor image */ +/* all fields below are for fbcon use only */ + char *data; /* copy of bitmap */ +}; + +#ifdef __KERNEL__ + +#include <linux/fs.h> +#include <linux/init.h> +#include <linux/tty.h> +#include <linux/device.h> +#include <linux/workqueue.h> +#include <linux/devfs_fs_kernel.h> +#include <linux/notifier.h> +#include <linux/list.h> +#include <asm/io.h> + +struct vm_area_struct; +struct fb_info; +struct device; +struct file; + +/* Definitions below are used in the parsed monitor specs */ +#define FB_DPMS_ACTIVE_OFF 1 +#define FB_DPMS_SUSPEND 2 +#define FB_DPMS_STANDBY 4 + +#define FB_DISP_DDI 1 +#define FB_DISP_ANA_700_300 2 +#define FB_DISP_ANA_714_286 4 +#define FB_DISP_ANA_1000_400 8 +#define FB_DISP_ANA_700_000 16 + +#define FB_DISP_MONO 32 +#define FB_DISP_RGB 64 +#define FB_DISP_MULTI 128 +#define FB_DISP_UNKNOWN 256 + +#define FB_SIGNAL_NONE 0 +#define FB_SIGNAL_BLANK_BLANK 1 +#define FB_SIGNAL_SEPARATE 2 +#define FB_SIGNAL_COMPOSITE 4 +#define FB_SIGNAL_SYNC_ON_GREEN 8 +#define FB_SIGNAL_SERRATION_ON 16 + +#define FB_MISC_PRIM_COLOR 1 +#define FB_MISC_1ST_DETAIL 2 /* First Detailed Timing is preferred */ +struct fb_chroma { + __u32 redx; /* in fraction of 1024 */ + __u32 greenx; + __u32 bluex; + __u32 whitex; + __u32 redy; + __u32 greeny; + __u32 bluey; + __u32 whitey; +}; + +struct fb_monspecs { + struct fb_chroma chroma; + struct fb_videomode *modedb; /* mode database */ + __u8 manufacturer[4]; /* Manufacturer */ + __u8 monitor[14]; /* Monitor String */ + __u8 serial_no[14]; /* Serial Number */ + __u8 ascii[14]; /* ? */ + __u32 modedb_len; /* mode database length */ + __u32 model; /* Monitor Model */ + __u32 serial; /* Serial Number - Integer */ + __u32 year; /* Year manufactured */ + __u32 week; /* Week Manufactured */ + __u32 hfmin; /* hfreq lower limit (Hz) */ + __u32 hfmax; /* hfreq upper limit (Hz) */ + __u32 dclkmin; /* pixelclock lower limit (Hz) */ + __u32 dclkmax; /* pixelclock upper limit (Hz) */ + __u16 input; /* display type - see FB_DISP_* */ + __u16 dpms; /* DPMS support - see FB_DPMS_ */ + __u16 signal; /* Signal Type - see FB_SIGNAL_* */ + __u16 vfmin; /* vfreq lower limit (Hz) */ + __u16 vfmax; /* vfreq upper limit (Hz) */ + __u16 gamma; /* Gamma - in fractions of 100 */ + __u16 gtf : 1; /* supports GTF */ + __u16 misc; /* Misc flags - see FB_MISC_* */ + __u8 version; /* EDID version... */ + __u8 revision; /* ...and revision */ + __u8 max_x; /* Maximum horizontal size (cm) */ + __u8 max_y; /* Maximum vertical size (cm) */ +}; + +struct fb_cmap_user { + __u32 start; /* First entry */ + __u32 len; /* Number of entries */ + __u16 __user *red; /* Red values */ + __u16 __user *green; + __u16 __user *blue; + __u16 __user *transp; /* transparency, can be NULL */ +}; + +struct fb_image_user { + __u32 dx; /* Where to place image */ + __u32 dy; + __u32 width; /* Size of image */ + __u32 height; + __u32 fg_color; /* Only used when a mono bitmap */ + __u32 bg_color; + __u8 depth; /* Depth of the image */ + const char __user *data; /* Pointer to image data */ + struct fb_cmap_user cmap; /* color map info */ +}; + +struct fb_cursor_user { + __u16 set; /* what to set */ + __u16 enable; /* cursor on/off */ + __u16 rop; /* bitop operation */ + const char __user *mask; /* cursor mask bits */ + struct fbcurpos hot; /* cursor hot spot */ + struct fb_image_user image; /* Cursor image */ +}; + +/* + * Register/unregister for framebuffer events + */ + +/* The resolution of the passed in fb_info about to change */ +#define FB_EVENT_MODE_CHANGE 0x01 +/* The display on this fb_info is beeing suspended, no access to the + * framebuffer is allowed any more after that call returns + */ +#define FB_EVENT_SUSPEND 0x02 +/* The display on this fb_info was resumed, you can restore the display + * if you own it + */ +#define FB_EVENT_RESUME 0x03 +/* An entry from the modelist was removed */ +#define FB_EVENT_MODE_DELETE 0x04 +/* A driver registered itself */ +#define FB_EVENT_FB_REGISTERED 0x05 +/* get console to framebuffer mapping */ +#define FB_EVENT_GET_CONSOLE_MAP 0x06 +/* set console to framebuffer mapping */ +#define FB_EVENT_SET_CONSOLE_MAP 0x07 + + +struct fb_event { + struct fb_info *info; + void *data; +}; + + +extern int fb_register_client(struct notifier_block *nb); +extern int fb_unregister_client(struct notifier_block *nb); + +/* + * Pixmap structure definition + * + * The purpose of this structure is to translate data + * from the hardware independent format of fbdev to what + * format the hardware needs. + */ + +#define FB_PIXMAP_DEFAULT 1 /* used internally by fbcon */ +#define FB_PIXMAP_SYSTEM 2 /* memory is in system RAM */ +#define FB_PIXMAP_IO 4 /* memory is iomapped */ +#define FB_PIXMAP_SYNC 256 /* set if GPU can DMA */ + +struct fb_pixmap { + u8 *addr; /* pointer to memory */ + u32 size; /* size of buffer in bytes */ + u32 offset; /* current offset to buffer */ + u32 buf_align; /* byte alignment of each bitmap */ + u32 scan_align; /* alignment per scanline */ + u32 access_align; /* alignment per read/write */ + u32 flags; /* see FB_PIXMAP_* */ + /* access methods */ + void (*outbuf)(struct fb_info *info, u8 *addr, u8 *src, unsigned int size); + u8 (*inbuf) (struct fb_info *info, u8 *addr); +}; + + +/*=====================================================*/ +struct fbui_window { + short id; /* window id */ + int pid; /* process id */ + int console; /* virtual console in which window appears */ + u32 bgcolor; /* background */ + short x0, y0, x1, y1; /* absolute coordinates */ + short width, height; + short max_width; + short max_height; + + short mouse_x, mouse_y; + + char program_type; + unsigned int need_placement : 1; + unsigned int drawing : 1; /* 1 => don't allow input_handler to draw ptr */ + unsigned int pointer_inside : 1; + unsigned int is_wm : 1; + unsigned int doing_autopos : 1; /* used by wm only; {0:fbwm, 1:fbpm} */ + unsigned int is_hidden: 1; + unsigned int do_invert : 1; + unsigned int need_keys : 1; + unsigned int need_motion : 1; + unsigned int receive_all_motion : 1; + unsigned int font_valid : 1; + + struct fbui_font font; /* default font, used if font ptr NULL */ + + struct fbui_processentry *processentry; + + char name[FBUI_NAMELEN]; + char subtitle[FBUI_NAMELEN]; + + u32 accelerators[8]; /* supporting only 8-bit chars now */ + short pending_accel; + + struct fbui_window *next; +}; + +extern int fbui_init (struct fb_info *info); +extern int fbui_switch (struct fb_info *info, int con); +extern int fbui_release (struct fb_info *info, int user); +extern int fbui_exec (struct fb_info *info, short win_id, short n, unsigned char *arg); +extern int fbui_control (struct fb_info *info, struct fbui_ctrlparams*); +extern int fbui_open (struct fb_info *info, struct fbui_openparams*); +extern int fbui_close (struct fb_info *info, short); + +extern void fb_clear (struct fb_info *, u32); +extern void fb_point (struct fb_info *, short,short, u32, char); +extern u32 fb_read_point (struct fb_info *, short,short); +extern void fb_hline (struct fb_info *,short,short,short,u32); +extern void fb_vline (struct fb_info *,short,short,short,u32); +extern void fb_putpixels_native (struct fb_info *, short,short,short,unsigned char*,char); +extern void fb_putpixels_rgb (struct fb_info *, short,short,short,unsigned long*,char); +extern void fb_putpixels_rgb3 (struct fb_info *, short,short,short,unsigned char*,char); +extern short fb_getpixels_rgb (struct fb_info *, short x,short y,short n,unsigned long*,char); +extern void fb_copyarea (struct fb_info *, short,short,short,short,short,short); + + +/* Per-process event queue data + */ +struct fbui_processentry { + unsigned int in_use : 1; + unsigned int waiting : 1; + char console; + char nwindows; + char window_num; /* which window to check next for event */ + short index; + int pid; + wait_queue_head_t waitqueue; + unsigned short wait_event_mask; + +#define FBUI_MAXEVENTSPERPROCESS (CONFIG_FB_UI_EVENTQUEUELEN) + struct fbui_event events [FBUI_MAXEVENTSPERPROCESS]; + short events_head; + short events_tail; + short events_pending; + spinlock_t queuelock; + struct semaphore queuesem; +}; + +#define FBUI_MAXCONSOLES 12 +#define FBUI_TOTALACCELS 128 +#define FBUI_MAXINCOMINGKEYS 32 +#define FBUI_CUTPASTE_LIMIT 0x10000 +#define FBUI_MAXWINDOWSPERVC (CONFIG_FB_UI_WINDOWSPERVC) + + +struct fbui_focus_stack { + struct rw_semaphore sem; + short top; + short ids [FBUI_MAXWINDOWSPERVC]; /* window ids */ +}; + + +/*=====================================================*/ + +/* + * Frame buffer operations + * + * LOCKING NOTE: those functions must _ALL_ be called with the console + * semaphore held, this is the only suitable locking mecanism we have + * in 2.6. Some may be called at interrupt time at this point though. + */ + +struct fb_ops { + /* open/release and usage marking */ + struct module *owner; + int (*fb_open)(struct fb_info *info, int user); + int (*fb_release)(struct fb_info *info, int user); + + /* For framebuffers with strange non linear layouts or that do not + * work with normal memory mapped access + */ + ssize_t (*fb_read)(struct file *file, char __user *buf, size_t count, loff_t *ppos); + ssize_t (*fb_write)(struct file *file, const char __user *buf, size_t count, loff_t *ppos); + + /* checks var and eventually tweaks it to something supported, + * DO NOT MODIFY PAR */ + int (*fb_check_var)(struct fb_var_screeninfo *var, struct fb_info *info); + + /* set the video mode according to info->var */ + int (*fb_set_par)(struct fb_info *info); + + /* set color register */ + int (*fb_setcolreg)(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, struct fb_info *info); + + /* blank display */ + int (*fb_blank)(int blank, struct fb_info *info); + + /* pan display */ + int (*fb_pan_display)(struct fb_var_screeninfo *var, struct fb_info *info); + + /* Draws a rectangle */ + void (*fb_fillrect) (struct fb_info *info, const struct fb_fillrect *rect); + /* Copy data from area to another */ + void (*fb_copyarea) (struct fb_info *info, const struct fb_copyarea *region); + /* Draws a image to the display */ + void (*fb_imageblit) (struct fb_info *info, const struct fb_image *image); + + /* Draws cursor */ + int (*fb_cursor) (struct fb_info *info, struct fb_cursor *cursor); + + /* Rotates the display */ + void (*fb_rotate)(struct fb_info *info, int angle); + + /* wait for blit idle, optional */ + int (*fb_sync)(struct fb_info *info); + + /* perform fb specific ioctl (optional) */ + int (*fb_ioctl)(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg, struct fb_info *info); + + /* perform fb specific mmap */ + int (*fb_mmap)(struct fb_info *info, struct file *file, struct vm_area_struct *vma); + +#ifdef CONFIG_FB_UI + void (*fb_clear) (struct fb_info *info, u32); + u32 (*fb_read_point) (struct fb_info *info, short x, short y); + void (*fb_point) (struct fb_info *info, short,short,u32,char); + void (*fb_hline) (struct fb_info *info, short,short,short,u32); + void (*fb_vline) (struct fb_info *info, short,short,short,u32); + void (*fb_putpixels_native) (struct fb_info *, short,short,short,unsigned char*,char); + short (*fb_getpixels_rgb) (struct fb_info *, short x,short y,short n,unsigned long*,char); + void (*fb_putpixels_rgb) (struct fb_info *, short,short,short,unsigned long*,char); + void (*fb_putpixels_rgb3) (struct fb_info *, short,short,short,unsigned char*,char); + void (*fb_copyarea2) (struct fb_info *, short,short,short,short,short,short); +#endif +}; + +/* FBINFO_* = fb_info.flags bit flags */ +#define FBINFO_MODULE 0x0001 /* Low-level driver is a module */ +#define FBINFO_HWACCEL_DISABLED 0x0002 + /* When FBINFO_HWACCEL_DISABLED is set: + * Hardware acceleration is turned off. Software implementations + * of required functions (copyarea(), fillrect(), and imageblit()) + * takes over; acceleration engine should be in a quiescent state */ + +/* hints */ +#define FBINFO_PARTIAL_PAN_OK 0x0040 /* otw use pan only for double-buffering */ +#define FBINFO_READS_FAST 0x0080 /* soft-copy faster than rendering */ + +/* hardware supported ops */ +/* semantics: when a bit is set, it indicates that the operation is + * accelerated by hardware. + * required functions will still work even if the bit is not set. + * optional functions may not even exist if the flag bit is not set. + */ +#define FBINFO_HWACCEL_NONE 0x0000 +#define FBINFO_HWACCEL_COPYAREA 0x0100 /* required */ +#define FBINFO_HWACCEL_FILLRECT 0x0200 /* required */ +#define FBINFO_HWACCEL_IMAGEBLIT 0x0400 /* required */ +#define FBINFO_HWACCEL_ROTATE 0x0800 /* optional */ +#define FBINFO_HWACCEL_XPAN 0x1000 /* optional */ +#define FBINFO_HWACCEL_YPAN 0x2000 /* optional */ +#define FBINFO_HWACCEL_YWRAP 0x4000 /* optional */ + +#define FBINFO_MISC_MODECHANGEUSER 0x10000 /* mode change request + from userspace */ +#define FBINFO_MISC_MODESWITCH 0x20000 /* mode switch */ +#define FBINFO_MISC_MODESWITCHLATE 0x40000 /* init hardware later */ + +struct fb_info { + int node; + int flags; + struct fb_var_screeninfo var; /* Current var */ + struct fb_fix_screeninfo fix; /* Current fix */ + struct fb_monspecs monspecs; /* Current Monitor specs */ + struct fb_cursor cursor; /* Current cursor */ + struct work_struct queue; /* Framebuffer event queue */ + struct timer_list cursor_timer; /* Cursor timer */ + struct fb_pixmap pixmap; /* Image hardware mapper */ + struct fb_pixmap sprite; /* Cursor hardware mapper */ + struct fb_cmap cmap; /* Current cmap */ + struct list_head modelist; /* mode list */ + struct fb_ops *fbops; + char __iomem *screen_base; /* Virtual address */ + unsigned long screen_size; /* Amount of ioremapped VRAM or 0 */ + int currcon; /* Current VC. */ + void *pseudo_palette; /* Fake palette of 16 colors */ +#define FBINFO_STATE_RUNNING 0 +#define FBINFO_STATE_SUSPENDED 1 + u32 state; /* Hardware state i.e suspend */ + +/*------------FBUI data in fb_info--------------*/ +#ifdef CONFIG_FB_UI + + struct fbui_window *keyfocus_window [FBUI_MAXCONSOLES]; + struct fbui_window *pointerfocus_window [FBUI_MAXCONSOLES]; + + char total_wins [FBUI_MAXCONSOLES]; + + unsigned char redsize, greensize, bluesize; + unsigned char redshift, greenshift, blueshift; + + struct fbui_window *window_managers [FBUI_MAXCONSOLES]; + struct fbui_window *windows [FBUI_MAXCONSOLES * FBUI_MAXWINDOWSPERVC]; + struct rw_semaphore winptrSem; + + /* protection for each fbui_window struct */ + struct semaphore windowSems [FBUI_MAXCONSOLES * FBUI_MAXWINDOWSPERVC]; + + struct semaphore preSem; + struct fbui_processentry processentries [FBUI_MAXCONSOLES * FBUI_MAXWINDOWSPERVC]; + + u32 bgcolor[FBUI_MAXCONSOLES]; /* from window manager */ + void *accelerators [FBUI_TOTALACCELS * FBUI_MAXCONSOLES]; + unsigned char force_placement [FBUI_MAXCONSOLES]; + struct tty_struct *ttysave [FBUI_MAXCONSOLES]; + struct fbui_window *pointer_window [FBUI_MAXCONSOLES]; + unsigned int pointer_active : 1; + unsigned int pointer_hidden : 1; + unsigned int have_hardware_pointer: 1; + unsigned int mode24 : 1; + short curr_mouse_x, curr_mouse_y; /* <--primary */ + short mouse_x0, mouse_y0, mouse_x1, mouse_y1; + + struct rw_semaphore cutpaste_sem; + unsigned char *cutpaste_buffer; + u32 cutpaste_length; +#endif + + /* From here on everything is device dependent */ + void *par; +}; + +#ifdef MODULE +#define FBINFO_DEFAULT FBINFO_MODULE +#else +#define FBINFO_DEFAULT 0 +#endif + +// This will go away +#define FBINFO_FLAG_MODULE FBINFO_MODULE +#define FBINFO_FLAG_DEFAULT FBINFO_DEFAULT + +/* This will go away + * fbset currently hacks in FB_ACCELF_TEXT into var.accel_flags + * when it wants to turn the acceleration engine on. This is + * really a separate operation, and should be modified via sysfs. + * But for now, we leave it broken with the following define + */ +#define STUPID_ACCELF_TEXT_SHIT + +// This will go away +#if defined(__sparc__) + +/* We map all of our framebuffers such that big-endian accesses + * are what we want, so the following is sufficient. + */ + +// This will go away +#define fb_readb sbus_readb +#define fb_readw sbus_readw +#define fb_readl sbus_readl +#define fb_readq sbus_readq +#define fb_writeb sbus_writeb +#define fb_writew sbus_writew +#define fb_writel sbus_writel +#define fb_writeq sbus_writeq +#define fb_memset sbus_memset_io + +#elif defined(__i386__) || defined(__alpha__) || defined(__x86_64__) || defined(__hppa__) || (defined(__sh__) && !defined(__SH5__)) || defined(__powerpc__) + +#define fb_readb __raw_readb +#define fb_readw __raw_readw +#define fb_readl __raw_readl +#define fb_readq __raw_readq +#define fb_writeb __raw_writeb +#define fb_writew __raw_writew +#define fb_writel __raw_writel +#define fb_writeq __raw_writeq +#define fb_memset memset_io + +#else + +#define fb_readb(addr) (*(volatile u8 *) (addr)) +#define fb_readw(addr) (*(volatile u16 *) (addr)) +#define fb_readl(addr) (*(volatile u32 *) (addr)) +#define fb_readq(addr) (*(volatile u64 *) (addr)) +#define fb_writeb(b,addr) (*(volatile u8 *) (addr) = (b)) +#define fb_writew(b,addr) (*(volatile u16 *) (addr) = (b)) +#define fb_writel(b,addr) (*(volatile u32 *) (addr) = (b)) +#define fb_writeq(b,addr) (*(volatile u64 *) (addr) = (b)) +#define fb_memset memset + +#endif + + /* + * `Generic' versions of the frame buffer device operations + */ + +extern int fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var); +extern int fb_pan_display(struct fb_info *info, struct fb_var_screeninfo *var); +extern int fb_blank(struct fb_info *info, int blank); +extern int soft_cursor(struct fb_info *info, struct fb_cursor *cursor); +extern void cfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect); +extern void cfb_copyarea(struct fb_info *info, const struct fb_copyarea *area); +extern void cfb_imageblit(struct fb_info *info, const struct fb_image *image); + +/* drivers/video/fbmem.c */ +extern int register_framebuffer(struct fb_info *fb_info); +extern int unregister_framebuffer(struct fb_info *fb_info); +extern int fb_prepare_logo(struct fb_info *fb_info); +extern int fb_show_logo(struct fb_info *fb_info); +extern char* fb_get_buffer_offset(struct fb_info *info, struct fb_pixmap *buf, u32 size); +extern void fb_iomove_buf_unaligned(struct fb_info *info, struct fb_pixmap *buf, + u8 *dst, u32 d_pitch, u8 *src, u32 idx, + u32 height, u32 shift_high, u32 shift_low, u32 mod); +extern void fb_iomove_buf_aligned(struct fb_info *info, struct fb_pixmap *buf, + u8 *dst, u32 d_pitch, u8 *src, u32 s_pitch, + u32 height); +extern void fb_sysmove_buf_unaligned(struct fb_info *info, struct fb_pixmap *buf, + u8 *dst, u32 d_pitch, u8 *src, u32 idx, + u32 height, u32 shift_high, u32 shift_low, u32 mod); +extern void fb_sysmove_buf_aligned(struct fb_info *info, struct fb_pixmap *buf, + u8 *dst, u32 d_pitch, u8 *src, u32 s_pitch, + u32 height); +extern void fb_load_cursor_image(struct fb_info *); +extern void fb_set_suspend(struct fb_info *info, int state); +extern int fb_get_color_depth(struct fb_info *info); +extern int fb_get_options(char *name, char **option); + +extern struct fb_info *registered_fb[FB_MAX]; +extern int num_registered_fb; + +/* drivers/video/fbsysfs.c */ +extern struct fb_info *framebuffer_alloc(size_t size, struct device *dev); +extern void framebuffer_release(struct fb_info *info); + +/* drivers/video/fbmon.c */ +#define FB_MAXTIMINGS 0 +#define FB_VSYNCTIMINGS 1 +#define FB_HSYNCTIMINGS 2 +#define FB_DCLKTIMINGS 3 +#define FB_IGNOREMON 0x100 + +#define FB_MODE_IS_UNKNOWN 0 +#define FB_MODE_IS_DETAILED 1 +#define FB_MODE_IS_STANDARD 2 +#define FB_MODE_IS_VESA 4 +#define FB_MODE_IS_CALCULATED 8 +#define FB_MODE_IS_FIRST 16 +#define FB_MODE_IS_FROM_VAR 32 + +extern int fbmon_valid_timings(u_int pixclock, u_int htotal, u_int vtotal, + const struct fb_info *fb_info); +extern int fbmon_dpms(const struct fb_info *fb_info); +extern int fb_get_mode(int flags, u32 val, struct fb_var_screeninfo *var, + struct fb_info *info); +extern int fb_validate_mode(const struct fb_var_screeninfo *var, + struct fb_info *info); +extern int fb_parse_edid(unsigned char *edid, struct fb_var_screeninfo *var); +extern int fb_get_monitor_limits(unsigned char *edid, struct fb_monspecs *specs); +extern void fb_edid_to_monspecs(unsigned char *edid, struct fb_monspecs *specs); +extern int fb_get_monitor_limits(unsigned char *edid, struct fb_monspecs *specs); +extern struct fb_videomode *fb_create_modedb(unsigned char *edid, int *dbsize); +extern void fb_destroy_modedb(struct fb_videomode *modedb); + +/* drivers/video/modedb.c */ +#define VESA_MODEDB_SIZE 34 +extern const struct fb_videomode vesa_modes[]; +extern void fb_var_to_videomode(struct fb_videomode *mode, + struct fb_var_screeninfo *var); +extern void fb_videomode_to_var(struct fb_var_screeninfo *var, + struct fb_videomode *mode); +extern int fb_mode_is_equal(struct fb_videomode *mode1, + struct fb_videomode *mode2); +extern int fb_add_videomode(struct fb_videomode *mode, struct list_head *head); +extern void fb_delete_videomode(struct fb_videomode *mode, + struct list_head *head); +extern struct fb_videomode *fb_match_mode(struct fb_var_screeninfo *var, + struct list_head *head); +extern struct fb_videomode *fb_find_best_mode(struct fb_var_screeninfo *var, + struct list_head *head); +extern void fb_destroy_modelist(struct list_head *head); +extern void fb_videomode_to_modelist(struct fb_videomode *modedb, int num, + struct list_head *head); + +/* drivers/video/fbcmap.c */ +extern int fb_alloc_cmap(struct fb_cmap *cmap, int len, int transp); +extern void fb_dealloc_cmap(struct fb_cmap *cmap); +extern int fb_copy_cmap(struct fb_cmap *from, struct fb_cmap *to); +extern int fb_cmap_to_user(struct fb_cmap *from, struct fb_cmap_user *to); +extern int fb_set_cmap(struct fb_cmap *cmap, struct fb_info *fb_info); +extern int fb_set_user_cmap(struct fb_cmap_user *cmap, struct fb_info *fb_info); +extern struct fb_cmap *fb_default_cmap(int len); +extern void fb_invert_cmaps(void); + +struct fb_videomode { + const char *name; /* optional */ + u32 refresh; /* optional */ + u32 xres; + u32 yres; + u32 pixclock; + u32 left_margin; + u32 right_margin; + u32 upper_margin; + u32 lower_margin; + u32 hsync_len; + u32 vsync_len; + u32 sync; + u32 vmode; + u32 flag; +}; + +struct fb_modelist { + struct list_head list; + struct fb_videomode mode; +}; + +extern int fb_find_mode(struct fb_var_screeninfo *var, + struct fb_info *info, const char *mode_option, + const struct fb_videomode *db, + unsigned int dbsize, + const struct fb_videomode *default_mode, + unsigned int default_bpp); + +#endif /* __KERNEL__ */ + +#endif /* _LINUX_FB_H */ diff --git a/include/linux/input.h b/include/linux/input.h @@ -0,0 +1,999 @@ +#ifndef _INPUT_H +#define _INPUT_H + +/* + * Copyright (c) 1999-2002 Vojtech Pavlik + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + */ + +#ifdef __KERNEL__ +#include <linux/time.h> +#include <linux/list.h> +#else +#include <sys/time.h> +#include <sys/ioctl.h> +#include <asm/types.h> +#endif + +/* + * The event structure itself + */ + +struct input_event { + struct timeval time; + __u16 type; + __u16 code; + __s32 value; +}; + +/* + * Protocol version. + */ + +#define EV_VERSION 0x010000 + +/* + * IOCTLs (0x00 - 0x7f) + */ + +struct input_id { + __u16 bustype; + __u16 vendor; + __u16 product; + __u16 version; +}; + +struct input_absinfo { + __s32 value; + __s32 minimum; + __s32 maximum; + __s32 fuzz; + __s32 flat; +}; + +#define EVIOCGVERSION _IOR('E', 0x01, int) /* get driver version */ +#define EVIOCGID _IOR('E', 0x02, struct input_id) /* get device ID */ +#define EVIOCGKEYCODE _IOR('E', 0x04, int[2]) /* get keycode */ +#define EVIOCSKEYCODE _IOW('E', 0x04, int[2]) /* set keycode */ + +#define EVIOCGNAME(len) _IOC(_IOC_READ, 'E', 0x06, len) /* get device name */ +#define EVIOCGPHYS(len) _IOC(_IOC_READ, 'E', 0x07, len) /* get physical location */ +#define EVIOCGUNIQ(len) _IOC(_IOC_READ, 'E', 0x08, len) /* get unique identifier */ + +#define EVIOCGKEY(len) _IOC(_IOC_READ, 'E', 0x18, len) /* get global keystate */ +#define EVIOCGLED(len) _IOC(_IOC_READ, 'E', 0x19, len) /* get all LEDs */ +#define EVIOCGSND(len) _IOC(_IOC_READ, 'E', 0x1a, len) /* get all sounds status */ + +#define EVIOCGBIT(ev,len) _IOC(_IOC_READ, 'E', 0x20 + ev, len) /* get event bits */ +#define EVIOCGABS(abs) _IOR('E', 0x40 + abs, struct input_absinfo) /* get abs value/limits */ +#define EVIOCSABS(abs) _IOW('E', 0xc0 + abs, struct input_absinfo) /* set abs value/limits */ + +#define EVIOCSFF _IOC(_IOC_WRITE, 'E', 0x80, sizeof(struct ff_effect)) /* send a force effect to a force feedback device */ +#define EVIOCRMFF _IOW('E', 0x81, int) /* Erase a force effect */ +#define EVIOCGEFFECTS _IOR('E', 0x84, int) /* Report number of effects playable at the same time */ + +#define EVIOCGRAB _IOW('E', 0x90, int) /* Grab/Release device */ + +/* + * Event types + */ + +#define EV_SYN 0x00 +#define EV_KEY 0x01 +#define EV_REL 0x02 +#define EV_ABS 0x03 +#define EV_MSC 0x04 +#define EV_LED 0x11 +#define EV_SND 0x12 +#define EV_REP 0x14 +#define EV_FF 0x15 +#define EV_PWR 0x16 +#define EV_FF_STATUS 0x17 +#define EV_MAX 0x1f + +/* + * Synchronization events. + */ + +#define SYN_REPORT 0 +#define SYN_CONFIG 1 + +/* + * Keys and buttons + */ + +#define KEY_RESERVED 0 +#define KEY_ESC 1 +#define KEY_1 2 +#define KEY_2 3 +#define KEY_3 4 +#define KEY_4 5 +#define KEY_5 6 +#define KEY_6 7 +#define KEY_7 8 +#define KEY_8 9 +#define KEY_9 10 +#define KEY_0 11 +#define KEY_MINUS 12 +#define KEY_EQUAL 13 +#define KEY_BACKSPACE 14 +#define KEY_TAB 15 +#define KEY_Q 16 +#define KEY_W 17 +#define KEY_E 18 +#define KEY_R 19 +#define KEY_T 20 +#define KEY_Y 21 +#define KEY_U 22 +#define KEY_I 23 +#define KEY_O 24 +#define KEY_P 25 +#define KEY_LEFTBRACE 26 +#define KEY_RIGHTBRACE 27 +#define KEY_ENTER 28 +#define KEY_LEFTCTRL 29 +#define KEY_A 30 +#define KEY_S 31 +#define KEY_D 32 +#define KEY_F 33 +#define KEY_G 34 +#define KEY_H 35 +#define KEY_J 36 +#define KEY_K 37 +#define KEY_L 38 +#define KEY_SEMICOLON 39 +#define KEY_APOSTROPHE 40 +#define KEY_GRAVE 41 +#define KEY_LEFTSHIFT 42 +#define KEY_BACKSLASH 43 +#define KEY_Z 44 +#define KEY_X 45 +#define KEY_C 46 +#define KEY_V 47 +#define KEY_B 48 +#define KEY_N 49 +#define KEY_M 50 +#define KEY_COMMA 51 +#define KEY_DOT 52 +#define KEY_SLASH 53 +#define KEY_RIGHTSHIFT 54 +#define KEY_KPASTERISK 55 +#define KEY_LEFTALT 56 +#define KEY_SPACE 57 +#define KEY_CAPSLOCK 58 +#define KEY_F1 59 +#define KEY_F2 60 +#define KEY_F3 61 +#define KEY_F4 62 +#define KEY_F5 63 +#define KEY_F6 64 +#define KEY_F7 65 +#define KEY_F8 66 +#define KEY_F9 67 +#define KEY_F10 68 +#define KEY_NUMLOCK 69 +#define KEY_SCROLLLOCK 70 +#define KEY_KP7 71 +#define KEY_KP8 72 +#define KEY_KP9 73 +#define KEY_KPMINUS 74 +#define KEY_KP4 75 +#define KEY_KP5 76 +#define KEY_KP6 77 +#define KEY_KPPLUS 78 +#define KEY_KP1 79 +#define KEY_KP2 80 +#define KEY_KP3 81 +#define KEY_KP0 82 +#define KEY_KPDOT 83 + +#define KEY_ZENKAKUHANKAKU 85 +#define KEY_102ND 86 +#define KEY_F11 87 +#define KEY_F12 88 +#define KEY_RO 89 +#define KEY_KATAKANA 90 +#define KEY_HIRAGANA 91 +#define KEY_HENKAN 92 +#define KEY_KATAKANAHIRAGANA 93 +#define KEY_MUHENKAN 94 +#define KEY_KPJPCOMMA 95 +#define KEY_KPENTER 96 +#define KEY_RIGHTCTRL 97 +#define KEY_KPSLASH 98 +#define KEY_SYSRQ 99 +#define KEY_RIGHTALT 100 +#define KEY_LINEFEED 101 +#define KEY_HOME 102 +#define KEY_UP 103 +#define KEY_PAGEUP 104 +#define KEY_LEFT 105 +#define KEY_RIGHT 106 +#define KEY_END 107 +#define KEY_DOWN 108 +#define KEY_PAGEDOWN 109 +#define KEY_INSERT 110 +#define KEY_DELETE 111 +#define KEY_MACRO 112 +#define KEY_MUTE 113 +#define KEY_VOLUMEDOWN 114 +#define KEY_VOLUMEUP 115 +#define KEY_POWER 116 +#define KEY_KPEQUAL 117 +#define KEY_KPPLUSMINUS 118 +#define KEY_PAUSE 119 + +#define KEY_KPCOMMA 121 +#define KEY_HANGUEL 122 +#define KEY_HANJA 123 +#define KEY_YEN 124 +#define KEY_LEFTMETA 125 +#define KEY_RIGHTMETA 126 +#define KEY_COMPOSE 127 + +#define KEY_STOP 128 +#define KEY_AGAIN 129 +#define KEY_PROPS 130 +#define KEY_UNDO 131 +#define KEY_FRONT 132 +#define KEY_COPY 133 +#define KEY_OPEN 134 +#define KEY_PASTE 135 +#define KEY_FIND 136 +#define KEY_CUT 137 +#define KEY_HELP 138 +#define KEY_MENU 139 +#define KEY_CALC 140 +#define KEY_SETUP 141 +#define KEY_SLEEP 142 +#define KEY_WAKEUP 143 +#define KEY_FILE 144 +#define KEY_SENDFILE 145 +#define KEY_DELETEFILE 146 +#define KEY_XFER 147 +#define KEY_PROG1 148 +#define KEY_PROG2 149 +#define KEY_WWW 150 +#define KEY_MSDOS 151 +#define KEY_COFFEE 152 +#define KEY_DIRECTION 153 +#define KEY_CYCLEWINDOWS 154 +#define KEY_MAIL 155 +#define KEY_BOOKMARKS 156 +#define KEY_COMPUTER 157 +#define KEY_BACK 158 +#define KEY_FORWARD 159 +#define KEY_CLOSECD 160 +#define KEY_EJECTCD 161 +#define KEY_EJECTCLOSECD 162 +#define KEY_NEXTSONG 163 +#define KEY_PLAYPAUSE 164 +#define KEY_PREVIOUSSONG 165 +#define KEY_STOPCD 166 +#define KEY_RECORD 167 +#define KEY_REWIND 168 +#define KEY_PHONE 169 +#define KEY_ISO 170 +#define KEY_CONFIG 171 +#define KEY_HOMEPAGE 172 +#define KEY_REFRESH 173 +#define KEY_EXIT 174 +#define KEY_MOVE 175 +#define KEY_EDIT 176 +#define KEY_SCROLLUP 177 +#define KEY_SCROLLDOWN 178 +#define KEY_KPLEFTPAREN 179 +#define KEY_KPRIGHTPAREN 180 + +#define KEY_F13 183 +#define KEY_F14 184 +#define KEY_F15 185 +#define KEY_F16 186 +#define KEY_F17 187 +#define KEY_F18 188 +#define KEY_F19 189 +#define KEY_F20 190 +#define KEY_F21 191 +#define KEY_F22 192 +#define KEY_F23 193 +#define KEY_F24 194 + +#define KEY_PLAYCD 200 +#define KEY_PAUSECD 201 +#define KEY_PROG3 202 +#define KEY_PROG4 203 +#define KEY_SUSPEND 205 +#define KEY_CLOSE 206 +#define KEY_PLAY 207 +#define KEY_FASTFORWARD 208 +#define KEY_BASSBOOST 209 +#define KEY_PRINT 210 +#define KEY_HP 211 +#define KEY_CAMERA 212 +#define KEY_SOUND 213 +#define KEY_QUESTION 214 +#define KEY_EMAIL 215 +#define KEY_CHAT 216 +#define KEY_SEARCH 217 +#define KEY_CONNECT 218 +#define KEY_FINANCE 219 +#define KEY_SPORT 220 +#define KEY_SHOP 221 +#define KEY_ALTERASE 222 +#define KEY_CANCEL 223 +#define KEY_BRIGHTNESSDOWN 224 +#define KEY_BRIGHTNESSUP 225 +#define KEY_MEDIA 226 + +#define KEY_UNKNOWN 240 + +#define BTN_MISC 0x100 +#define BTN_0 0x100 +#define BTN_1 0x101 +#define BTN_2 0x102 +#define BTN_3 0x103 +#define BTN_4 0x104 +#define BTN_5 0x105 +#define BTN_6 0x106 +#define BTN_7 0x107 +#define BTN_8 0x108 +#define BTN_9 0x109 + +#define BTN_MOUSE 0x110 +#define BTN_LEFT 0x110 +#define BTN_RIGHT 0x111 +#define BTN_MIDDLE 0x112 +#define BTN_SIDE 0x113 +#define BTN_EXTRA 0x114 +#define BTN_FORWARD 0x115 +#define BTN_BACK 0x116 +#define BTN_TASK 0x117 + +#define BTN_JOYSTICK 0x120 +#define BTN_TRIGGER 0x120 +#define BTN_THUMB 0x121 +#define BTN_THUMB2 0x122 +#define BTN_TOP 0x123 +#define BTN_TOP2 0x124 +#define BTN_PINKIE 0x125 +#define BTN_BASE 0x126 +#define BTN_BASE2 0x127 +#define BTN_BASE3 0x128 +#define BTN_BASE4 0x129 +#define BTN_BASE5 0x12a +#define BTN_BASE6 0x12b +#define BTN_DEAD 0x12f + +#define BTN_GAMEPAD 0x130 +#define BTN_A 0x130 +#define BTN_B 0x131 +#define BTN_C 0x132 +#define BTN_X 0x133 +#define BTN_Y 0x134 +#define BTN_Z 0x135 +#define BTN_TL 0x136 +#define BTN_TR 0x137 +#define BTN_TL2 0x138 +#define BTN_TR2 0x139 +#define BTN_SELECT 0x13a +#define BTN_START 0x13b +#define BTN_MODE 0x13c +#define BTN_THUMBL 0x13d +#define BTN_THUMBR 0x13e + +#define BTN_DIGI 0x140 +#define BTN_TOOL_PEN 0x140 +#define BTN_TOOL_RUBBER 0x141 +#define BTN_TOOL_BRUSH 0x142 +#define BTN_TOOL_PENCIL 0x143 +#define BTN_TOOL_AIRBRUSH 0x144 +#define BTN_TOOL_FINGER 0x145 +#define BTN_TOOL_MOUSE 0x146 +#define BTN_TOOL_LENS 0x147 +#define BTN_TOUCH 0x14a +#define BTN_STYLUS 0x14b +#define BTN_STYLUS2 0x14c +#define BTN_TOOL_DOUBLETAP 0x14d +#define BTN_TOOL_TRIPLETAP 0x14e + +#define BTN_WHEEL 0x150 +#define BTN_GEAR_DOWN 0x150 +#define BTN_GEAR_UP 0x151 + +#define KEY_OK 0x160 +#define KEY_SELECT 0x161 +#define KEY_GOTO 0x162 +#define KEY_CLEAR 0x163 +#define KEY_POWER2 0x164 +#define KEY_OPTION 0x165 +#define KEY_INFO 0x166 +#define KEY_TIME 0x167 +#define KEY_VENDOR 0x168 +#define KEY_ARCHIVE 0x169 +#define KEY_PROGRAM 0x16a +#define KEY_CHANNEL 0x16b +#define KEY_FAVORITES 0x16c +#define KEY_EPG 0x16d +#define KEY_PVR 0x16e +#define KEY_MHP 0x16f +#define KEY_LANGUAGE 0x170 +#define KEY_TITLE 0x171 +#define KEY_SUBTITLE 0x172 +#define KEY_ANGLE 0x173 +#define KEY_ZOOM 0x174 +#define KEY_MODE 0x175 +#define KEY_KEYBOARD 0x176 +#define KEY_SCREEN 0x177 +#define KEY_PC 0x178 +#define KEY_TV 0x179 +#define KEY_TV2 0x17a +#define KEY_VCR 0x17b +#define KEY_VCR2 0x17c +#define KEY_SAT 0x17d +#define KEY_SAT2 0x17e +#define KEY_CD 0x17f +#define KEY_TAPE 0x180 +#define KEY_RADIO 0x181 +#define KEY_TUNER 0x182 +#define KEY_PLAYER 0x183 +#define KEY_TEXT 0x184 +#define KEY_DVD 0x185 +#define KEY_AUX 0x186 +#define KEY_MP3 0x187 +#define KEY_AUDIO 0x188 +#define KEY_VIDEO 0x189 +#define KEY_DIRECTORY 0x18a +#define KEY_LIST 0x18b +#define KEY_MEMO 0x18c +#define KEY_CALENDAR 0x18d +#define KEY_RED 0x18e +#define KEY_GREEN 0x18f +#define KEY_YELLOW 0x190 +#define KEY_BLUE 0x191 +#define KEY_CHANNELUP 0x192 +#define KEY_CHANNELDOWN 0x193 +#define KEY_FIRST 0x194 +#define KEY_LAST 0x195 +#define KEY_AB 0x196 +#define KEY_NEXT 0x197 +#define KEY_RESTART 0x198 +#define KEY_SLOW 0x199 +#define KEY_SHUFFLE 0x19a +#define KEY_BREAK 0x19b +#define KEY_PREVIOUS 0x19c +#define KEY_DIGITS 0x19d +#define KEY_TEEN 0x19e +#define KEY_TWEN 0x19f + +#define KEY_DEL_EOL 0x1c0 +#define KEY_DEL_EOS 0x1c1 +#define KEY_INS_LINE 0x1c2 +#define KEY_DEL_LINE 0x1c3 + +#define KEY_MAX 0x1ff + +/* + * Relative axes + */ + +#define REL_X 0x00 +#define REL_Y 0x01 +#define REL_Z 0x02 +#define REL_HWHEEL 0x06 +#define REL_DIAL 0x07 +#define REL_WHEEL 0x08 +#define REL_MISC 0x09 +#define REL_MAX 0x0f + +/* + * Absolute axes + */ + +#define ABS_X 0x00 +#define ABS_Y 0x01 +#define ABS_Z 0x02 +#define ABS_RX 0x03 +#define ABS_RY 0x04 +#define ABS_RZ 0x05 +#define ABS_THROTTLE 0x06 +#define ABS_RUDDER 0x07 +#define ABS_WHEEL 0x08 +#define ABS_GAS 0x09 +#define ABS_BRAKE 0x0a +#define ABS_HAT0X 0x10 +#define ABS_HAT0Y 0x11 +#define ABS_HAT1X 0x12 +#define ABS_HAT1Y 0x13 +#define ABS_HAT2X 0x14 +#define ABS_HAT2Y 0x15 +#define ABS_HAT3X 0x16 +#define ABS_HAT3Y 0x17 +#define ABS_PRESSURE 0x18 +#define ABS_DISTANCE 0x19 +#define ABS_TILT_X 0x1a +#define ABS_TILT_Y 0x1b +#define ABS_TOOL_WIDTH 0x1c +#define ABS_VOLUME 0x20 +#define ABS_MISC 0x28 +#define ABS_MAX 0x3f + +/* + * Misc events + */ + +#define MSC_SERIAL 0x00 +#define MSC_PULSELED 0x01 +#define MSC_GESTURE 0x02 +#define MSC_RAW 0x03 +#define MSC_SCAN 0x04 +#define MSC_MAX 0x07 + +/* + * LEDs + */ + +#define LED_NUML 0x00 +#define LED_CAPSL 0x01 +#define LED_SCROLLL 0x02 +#define LED_COMPOSE 0x03 +#define LED_KANA 0x04 +#define LED_SLEEP 0x05 +#define LED_SUSPEND 0x06 +#define LED_MUTE 0x07 +#define LED_MISC 0x08 +#define LED_MAX 0x0f + +/* + * Autorepeat values + */ + +#define REP_DELAY 0x00 +#define REP_PERIOD 0x01 +#define REP_MAX 0x01 + +/* + * Sounds + */ + +#define SND_CLICK 0x00 +#define SND_BELL 0x01 +#define SND_TONE 0x02 +#define SND_MAX 0x07 + +/* + * IDs. + */ + +#define ID_BUS 0 +#define ID_VENDOR 1 +#define ID_PRODUCT 2 +#define ID_VERSION 3 + +#define BUS_PCI 0x01 +#define BUS_ISAPNP 0x02 +#define BUS_USB 0x03 +#define BUS_HIL 0x04 +#define BUS_BLUETOOTH 0x05 + +#define BUS_ISA 0x10 +#define BUS_I8042 0x11 +#define BUS_XTKBD 0x12 +#define BUS_RS232 0x13 +#define BUS_GAMEPORT 0x14 +#define BUS_PARPORT 0x15 +#define BUS_AMIGA 0x16 +#define BUS_ADB 0x17 +#define BUS_I2C 0x18 +#define BUS_HOST 0x19 + +/* + * Values describing the status of an effect + */ +#define FF_STATUS_STOPPED 0x00 +#define FF_STATUS_PLAYING 0x01 +#define FF_STATUS_MAX 0x01 + +/* + * Structures used in ioctls to upload effects to a device + * The first structures are not passed directly by using ioctls. + * They are sub-structures of the actually sent structure (called ff_effect) + */ + +struct ff_replay { + __u16 length; /* Duration of an effect in ms. All other times are also expressed in ms */ + __u16 delay; /* Time to wait before to start playing an effect */ +}; + +struct ff_trigger { + __u16 button; /* Number of button triggering an effect */ + __u16 interval; /* Time to wait before an effect can be re-triggered (ms) */ +}; + +struct ff_envelope { + __u16 attack_length; /* Duration of attack (ms) */ + __u16 attack_level; /* Level at beginning of attack */ + __u16 fade_length; /* Duration of fade (ms) */ + __u16 fade_level; /* Level at end of fade */ +}; + +/* FF_CONSTANT */ +struct ff_constant_effect { + __s16 level; /* Strength of effect. Negative values are OK */ + struct ff_envelope envelope; +}; + +/* FF_RAMP */ +struct ff_ramp_effect { + __s16 start_level; + __s16 end_level; + struct ff_envelope envelope; +}; + +/* FF_SPRING of FF_FRICTION */ +struct ff_condition_effect { + __u16 right_saturation; /* Max level when joystick is on the right */ + __u16 left_saturation; /* Max level when joystick in on the left */ + + __s16 right_coeff; /* Indicates how fast the force grows when the + joystick moves to the right */ + __s16 left_coeff; /* Same for left side */ + + __u16 deadband; /* Size of area where no force is produced */ + __s16 center; /* Position of dead zone */ + +}; + +/* FF_PERIODIC */ +struct ff_periodic_effect { + __u16 waveform; /* Kind of wave (sine, square...) */ + __u16 period; /* in ms */ + __s16 magnitude; /* Peak value */ + __s16 offset; /* Mean value of wave (roughly) */ + __u16 phase; /* 'Horizontal' shift */ + + struct ff_envelope envelope; + +/* Only used if waveform == FF_CUSTOM */ + __u32 custom_len; /* Number of samples */ + __s16 *custom_data; /* Buffer of samples */ +/* Note: the data pointed by custom_data is copied by the driver. You can + * therefore dispose of the memory after the upload/update */ +}; + +/* FF_RUMBLE */ +/* Some rumble pads have two motors of different weight. + strong_magnitude represents the magnitude of the vibration generated + by the heavy motor. +*/ +struct ff_rumble_effect { + __u16 strong_magnitude; /* Magnitude of the heavy motor */ + __u16 weak_magnitude; /* Magnitude of the light one */ +}; + +/* + * Structure sent through ioctl from the application to the driver + */ +struct ff_effect { + __u16 type; +/* Following field denotes the unique id assigned to an effect. + * If user sets if to -1, a new effect is created, and its id is returned in the same field + * Else, the user sets it to the effect id it wants to update. + */ + __s16 id; + + __u16 direction; /* Direction. 0 deg -> 0x0000 (down) + 90 deg -> 0x4000 (left) + 180 deg -> 0x8000 (up) + 270 deg -> 0xC000 (right) + */ + + struct ff_trigger trigger; + struct ff_replay replay; + + union { + struct ff_constant_effect constant; + struct ff_ramp_effect ramp; + struct ff_periodic_effect periodic; + struct ff_condition_effect condition[2]; /* One for each axis */ + struct ff_rumble_effect rumble; + } u; +}; + +/* + * Force feedback effect types + */ + +#define FF_RUMBLE 0x50 +#define FF_PERIODIC 0x51 +#define FF_CONSTANT 0x52 +#define FF_SPRING 0x53 +#define FF_FRICTION 0x54 +#define FF_DAMPER 0x55 +#define FF_INERTIA 0x56 +#define FF_RAMP 0x57 + +/* + * Force feedback periodic effect types + */ + +#define FF_SQUARE 0x58 +#define FF_TRIANGLE 0x59 +#define FF_SINE 0x5a +#define FF_SAW_UP 0x5b +#define FF_SAW_DOWN 0x5c +#define FF_CUSTOM 0x5d + +/* + * Set ff device properties + */ + +#define FF_GAIN 0x60 +#define FF_AUTOCENTER 0x61 + +#define FF_MAX 0x7f + +#ifdef __KERNEL__ + +/* + * In-kernel definitions. + */ + +#include <linux/fs.h> +#include <linux/timer.h> + +#define NBITS(x) ((((x)-1)/BITS_PER_LONG)+1) +#define BIT(x) (1UL<<((x)%BITS_PER_LONG)) +#define LONG(x) ((x)/BITS_PER_LONG) + +#define INPUT_KEYCODE(dev, scancode) ((dev->keycodesize == 1) ? ((u8*)dev->keycode)[scancode] : \ + ((dev->keycodesize == 2) ? ((u16*)dev->keycode)[scancode] : (((u32*)dev->keycode)[scancode]))) + +#define SET_INPUT_KEYCODE(dev, scancode, val) \ + ({ unsigned __old; \ + switch (dev->keycodesize) { \ + case 1: { \ + u8 *k = (u8 *)dev->keycode; \ + __old = k[scancode]; \ + k[scancode] = val; \ + break; \ + } \ + case 2: { \ + u16 *k = (u16 *)dev->keycode; \ + __old = k[scancode]; \ + k[scancode] = val; \ + break; \ + } \ + default: { \ + u32 *k = (u32 *)dev->keycode; \ + __old = k[scancode]; \ + k[scancode] = val; \ + break; \ + } \ + } \ + __old; }) + +struct input_dev { + + void *private; + + char *name; + char *phys; + char *uniq; + struct input_id id; + + unsigned long evbit[NBITS(EV_MAX)]; + unsigned long keybit[NBITS(KEY_MAX)]; + unsigned long relbit[NBITS(REL_MAX)]; + unsigned long absbit[NBITS(ABS_MAX)]; + unsigned long mscbit[NBITS(MSC_MAX)]; + unsigned long ledbit[NBITS(LED_MAX)]; + unsigned long sndbit[NBITS(SND_MAX)]; + unsigned long ffbit[NBITS(FF_MAX)]; + int ff_effects_max; + + unsigned int keycodemax; + unsigned int keycodesize; + void *keycode; + + unsigned int repeat_key; + struct timer_list timer; + + struct pm_dev *pm_dev; + struct pt_regs *regs; + int state; + + int sync; + + int abs[ABS_MAX + 1]; + int rep[REP_MAX + 1]; + + unsigned long key[NBITS(KEY_MAX)]; + unsigned long led[NBITS(LED_MAX)]; + unsigned long snd[NBITS(SND_MAX)]; + + int absmax[ABS_MAX + 1]; + int absmin[ABS_MAX + 1]; + int absfuzz[ABS_MAX + 1]; + int absflat[ABS_MAX + 1]; + + int (*open)(struct input_dev *dev); + void (*close)(struct input_dev *dev); + int (*accept)(struct input_dev *dev, struct file *file); + int (*flush)(struct input_dev *dev, struct file *file); + int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value); + int (*upload_effect)(struct input_dev *dev, struct ff_effect *effect); + int (*erase_effect)(struct input_dev *dev, int effect_id); + + struct input_handle *grab; + struct device *dev; + + struct list_head h_list; + struct list_head node; +}; + +/* + * Structure for hotplug & device<->driver matching. + */ + +#define INPUT_DEVICE_ID_MATCH_BUS 1 +#define INPUT_DEVICE_ID_MATCH_VENDOR 2 +#define INPUT_DEVICE_ID_MATCH_PRODUCT 4 +#define INPUT_DEVICE_ID_MATCH_VERSION 8 + +#define INPUT_DEVICE_ID_MATCH_EVBIT 0x010 +#define INPUT_DEVICE_ID_MATCH_KEYBIT 0x020 +#define INPUT_DEVICE_ID_MATCH_RELBIT 0x040 +#define INPUT_DEVICE_ID_MATCH_ABSBIT 0x080 +#define INPUT_DEVICE_ID_MATCH_MSCIT 0x100 +#define INPUT_DEVICE_ID_MATCH_LEDBIT 0x200 +#define INPUT_DEVICE_ID_MATCH_SNDBIT 0x400 +#define INPUT_DEVICE_ID_MATCH_FFBIT 0x800 + +#define INPUT_DEVICE_ID_MATCH_DEVICE\ + (INPUT_DEVICE_ID_MATCH_BUS | INPUT_DEVICE_ID_MATCH_VENDOR | INPUT_DEVICE_ID_MATCH_PRODUCT) +#define INPUT_DEVICE_ID_MATCH_DEVICE_AND_VERSION\ + (INPUT_DEVICE_ID_MATCH_DEVICE | INPUT_DEVICE_ID_MATCH_VERSION) + +struct input_device_id { + + unsigned long flags; + + struct input_id id; + + unsigned long evbit[NBITS(EV_MAX)]; + unsigned long keybit[NBITS(KEY_MAX)]; + unsigned long relbit[NBITS(REL_MAX)]; + unsigned long absbit[NBITS(ABS_MAX)]; + unsigned long mscbit[NBITS(MSC_MAX)]; + unsigned long ledbit[NBITS(LED_MAX)]; + unsigned long sndbit[NBITS(SND_MAX)]; + unsigned long ffbit[NBITS(FF_MAX)]; + + unsigned long driver_info; +}; + +struct input_handle; + +struct input_handler { + + void *private; + + void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value); + struct input_handle* (*connect)(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id); + void (*disconnect)(struct input_handle *handle); + + struct file_operations *fops; + int minor; + char *name; + + struct input_device_id *id_table; + struct input_device_id *blacklist; + + struct list_head h_list; + struct list_head node; +}; + +struct input_handle { + + void *private; + + int open; + char *name; + + struct input_dev *dev; + struct input_handler *handler; + + struct list_head d_node; + struct list_head h_node; +}; + +#define to_dev(n) container_of(n,struct input_dev,node) +#define to_handler(n) container_of(n,struct input_handler,node); +#define to_handle(n) container_of(n,struct input_handle,d_node) +#define to_handle_h(n) container_of(n,struct input_handle,h_node) + +static inline void init_input_dev(struct input_dev *dev) +{ + INIT_LIST_HEAD(&dev->h_list); + INIT_LIST_HEAD(&dev->node); +} + +void input_register_device(struct input_dev *); +void input_unregister_device(struct input_dev *); + +void input_register_handler(struct input_handler *); +void input_unregister_handler(struct input_handler *); + +int input_grab_device(struct input_handle *); +void input_release_device(struct input_handle *); + +int input_open_device(struct input_handle *); +void input_close_device(struct input_handle *); + +int input_accept_process(struct input_handle *handle, struct file *file); +int input_flush_device(struct input_handle* handle, struct file* file); + +void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value); + +static inline void input_report_key(struct input_dev *dev, unsigned int code, int value) +{ + input_event(dev, EV_KEY, code, !!value); +} + +static inline void input_report_rel(struct input_dev *dev, unsigned int code, int value) +{ + input_event(dev, EV_REL, code, value); +} + +static inline void input_report_abs(struct input_dev *dev, unsigned int code, int value) +{ + input_event(dev, EV_ABS, code, value); +} + +static inline void input_report_ff(struct input_dev *dev, unsigned int code, int value) +{ + input_event(dev, EV_FF, code, value); +} + +static inline void input_report_ff_status(struct input_dev *dev, unsigned int code, int value) +{ + input_event(dev, EV_FF_STATUS, code, value); +} + +static inline void input_regs(struct input_dev *dev, struct pt_regs *regs) +{ + dev->regs = regs; +} + +static inline void input_sync(struct input_dev *dev) +{ + input_event(dev, EV_SYN, SYN_REPORT, 0); + dev->regs = NULL; +} + +static inline void input_set_abs_params(struct input_dev *dev, int axis, int min, int max, int fuzz, int flat) +{ + dev->absmin[axis] = min; + dev->absmax[axis] = max; + dev->absfuzz[axis] = fuzz; + dev->absflat[axis] = flat; + + dev->absbit[LONG(axis)] |= BIT(axis); +} + +extern struct class_simple *input_class; + +#ifdef CONFIG_INPUT_FBUI +/* FBUI additions by Zachary T Smith, fbui@comcast.net */ +extern void fbui_input_enable(void); +extern void fbui_input_disable(void); +typedef void FBUIInputEventHandler (u32 , struct input_event *); +extern void fbui_input_register_handler (FBUIInputEventHandler*, u32 param); +#endif + + +#endif +#endif diff --git a/libfbui/API.txt b/libfbui/API.txt @@ -0,0 +1,139 @@ + +The FBUI library +Copyright (C) 2004 by Zachary Smith. +_________________________________________________________________ + +Using the library is actually not necessary since any program +can operate the FBUI ioctls itself. However the library +is helpful in that it saves time and effort and provides some +abstractions. + +Display struct +-------------- +With FBUI version 0.9 and above, each application can multiple +windows. However you still must open the display by calling +fbui_display_open(), which generates the Display struct. +Before exiting, you should call fbui_display_close(). + +Window struct +------------- +Each application can only many windows. There is a limit on the +number of windows per virtual console however that in theory +can be changed before compiling the kernel. + +Queueing +-------- +The FBUI library implements queueing of drawing commands since +doing this makes more efficient use of the ioctl interface. +Therefore you periodically need to call fbui_flush to make +drawing happen. However some commands cause a flush to occur +anyway because they involve data that might change before the +queue is flushed. For instance fbui_draw_string does this. + +Fonts +----- +FBUI does not cache font metrics or bitmaps in kernel space. +Therefore each application must load the fonts it needs into +its own memory. FBUI library does not yet cache font info +nor does it allow any single process to act as a font server. + +Using FBUI Library +------------------ +It is best to look at a sample application to get an idea of how +to use FBUI library. However here is a quick overview. + +In main you want to: + +1. load any fonts, perhaps exit if unavailable +2. call fbui_display_open to get the Display +3. call fbui_window_open for any windows with desired arguments +4. request any Alt-key accelerators if you need them; be sparing. +5. event loop: break out of it when done +6. optionally call fbui_window_close for each window +7. call fbui_display_close (which also calls fbui_window_close) +8. free up any Font objcts + +In the event loop you must: + +1. either wait for events, or poll for events e.g. 2-10 times + per second +2. process events, e.g. mouse motion, keypresses, expose; + the Event struct should have all the event data you need. + +Expose +------ +In windowing systems that have overlapping windows, +expose events are for parts of windows. In FBUI, Expose +covers the entire window. + +fbui_display_open +----------------- +This routine produces the Display struct and opens +the framebuffer. + +fbui_window_open +---------------- +This routine opens a single window for the process. +You can specify a window location and size, but these can be +overridden using command line arguments. + +You can call fbui_open many times, but keep in mind +there is an upper limit per VC on the number of windows. + +You can specify a program type, which is a hint to the +window manager as to where the window should be placed. +fbwm ignores this, but for fbpm it is vital. + +Another parameter is the desired virtual console. A value +of -1 means the current one. Otherwise 0..5 are the consoles +available. + +Drawing +------- +Drawing is easy. As previously stated, commands are +queued until a flush. You can draw lines, points, +rectangles, horizontal lines, vertical lines. You can +fill areas, clear the window. Later I will add +arcs and maybe, just maybe, anti-aliased lines. +You can also draw text if you're read in a font. + +Window Manager, Panel Manager +----------------------------- +Programs fbwm and fbpm are optional. But they are useful, +especially the Panel Manager fbpm which is the focus +of my window manager development. + +The Panel Manager's purpose is to organize the user interface +into standard functional areas and thereby make work with the +computer easier and quicker. + +Program Type Hint +----------------- +If no window manager is yet running, this datum will be +ignored. If there is a wm, the program type will result +in a window being hidden upon creation and its need_placement +flag set. The window manager will get word of the window's +creation and resize/position it. + +Errors +------ +If your program needs to exit rapidly, use the FATAL +macro, which takes a string argument. This macro +closes all windows and the display. + +If you need to print an FBUI error code, call +fbui_print_error. + +Signals +------- +Several common error-related signals are caught by +libfbui and should result in all windows being closed. + +Zombie Windows +-------------- +If by chance an FBUI program dies without its window(s) +being closed, FBUI will eventually remove such windows +automagically. + +-end- + diff --git a/libfbui/BUGS b/libfbui/BUGS @@ -0,0 +1,12 @@ + +* fbview doesn't always receive its MoveResize event from fbpm + +* Sometimes, when the mouse pointer is over a window or the + background after a VC switch, its background bits are invalid. + +* Call to allocate_vc is not working. + +* Sometimes keyfocus isn't initially active for solo windows. + +* Multi-window test not working? + diff --git a/libfbui/COPYING b/libfbui/COPYING @@ -0,0 +1,280 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS diff --git a/libfbui/Calc/COPYING b/libfbui/Calc/COPYING @@ -0,0 +1,280 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS diff --git a/libfbui/Calc/Makefile b/libfbui/Calc/Makefile @@ -0,0 +1,15 @@ + +EXE= fbcalc +SRC= main.c + +${EXE}: ${SRC} + gcc -I.. ${CFLAGS} ${SRC} -lm ../libfbui.a -g -o ${EXE} + strip ${EXE} + +clean: + rm -f ${EXE} + +install: ${EXE} + cp ${EXE} /usr/bin + chmod 755 /usr/bin/${EXE} + diff --git a/libfbui/Calc/main.c b/libfbui/Calc/main.c @@ -0,0 +1,512 @@ + +/*========================================================================= + * + * fbcalc, a simple calculator for FBUI (in-kernel framebuffer UI) + * Copyright (C) 2004 Zachary T Smith, fbui@comcast.net + * + * This module is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This module 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this module; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * (See the file COPYING in the main directory of this archive for + * more details.) + * + *=======================================================================*/ + + +#define VERSION "0.2" + + +#include <stdio.h> +#include <time.h> +#include <unistd.h> +#include <math.h> + +#include "libfbui.h" + + +static short win_w; +static short win_h; + +static short button_width; +static short button_height; + +static int rows = 6; +static int cols = 4; + +static Display *dpy = NULL; +static Window *win = NULL; +static Font *font = NULL; + +static unsigned long fgcolor = RGB_BLACK; +static unsigned long bgcolor = 0xC0C0C0; + +static char diverr = false; + +static char *keystring[] = { + "STO", "RCL", "CLR", "CE", + "1/x", "sqrt", "x^2", "/", + "7", "8", "9", "*", + "4", "5", "6", "-", + "1", "2", "3", "+", + "0", ".", "-", "=", + NULL + +}; + +static char begin_new_value = false; + +static double stored = 0.0; +static double result = 0.0; +static double value = 0.0; + +static char got_point = 0; +static char rightgoing_place = 0; + +static int operation = 0; + + +int whichbutton (short x, short y) +{ + int i,j; + + for (j=0; j<rows; j++) { + for (i=0; i<cols; i++) { + int x0 = i*button_width + (i+1) * button_width/2; + int y0 = (j+1)*button_height + (j+2) * button_height/2; + int x1 = x0 + button_width - 1; + int y1 = y0 + button_height - 1; + + if (x >= x0 && x <= x1 && y >= y0 && y <= y1) + return i + j*cols; + } + } + return -1; +} + + +void draw_button (Display *dpy, Window *win, int i, int j, char highlight) +{ + if (!dpy || !win) + return; + if (i<0 || j<0 || i>=cols || j>=rows) + return; + + int x0 = i*button_width + (i+1) * button_width/2; + int y0 = (j+1)*button_height + (j+2) * button_height/2; + int x1 = x0 + button_width - 1; + int y1 = y0 + button_height - 1; + + if (highlight) + fbui_fill_area (dpy, win, x0,y0,x1,y1, RGB_CYAN); + + fbui_draw_rect (dpy, win, x0,y0,x1,y1, RGB_BLACK); + + char *str = keystring [i + j*cols]; + + short w,a,d,h; + font_string_dims (font,str,&w,&a,&d); + h = a+d; + w = (button_width-w)/2; + h = (button_height-h)/2; + + fbui_draw_string (dpy,win,NULL, + w+x0+1,h+y0+1, str, fgcolor); +} + + +void update_value () +{ + int x0 = button_width/2; + int y0 = button_height/2; + int x1 = win_w - 1 - x0; + int y1 = y0 + button_height - 1; + fbui_fill_area (dpy,win,x0,y0,x1,y1,RGB_WHITE); + fbui_draw_rect (dpy,win,x0,y0,x1,y1,fgcolor); + char valstr[100]; + + if (diverr) + sprintf (valstr, "Divide Error"); + else + sprintf (valstr, "%.12g", value); + + short w,a,d,h; + font_string_dims (font,valstr,&w,&a,&d); + h = a+d; + w = (win_w - w - button_width); + h = (button_height-h)/2; + fbui_draw_string (dpy,win,NULL, + w+x0,h+y0+1, valstr, fgcolor); +} + + +void +insert_digit (char ch) +{ + if (ch < '0' || ch > '9') + return; + + if (begin_new_value) + value = 0.0; + begin_new_value = false; + + ch -= '0'; + + if (!got_point) { + value *= 10.0; + value += ch; + update_value (); + } else { + int i = rightgoing_place; + double tmp = ch; + while(i--) + tmp /= 10.0; + tmp /= 10.0; + ++rightgoing_place; + value += tmp; + } + update_value(); +} + +enum { + + ADD = 1, + SUBTRACT = 2, + MULTIPLY = 3, + DIVIDE = 4 + +}; + + +void perform_equals () +{ +printf ("____________\n"); +printf ("value=%g\n", value); +printf ("result=%g\n", result); +printf ("operation=%d\n", operation); + switch (operation) { + case ADD: + result += value; + break; + case SUBTRACT: + result -= value; + break; + case MULTIPLY: + result *= value; + break; + case DIVIDE: + if (value != 0) + result /= value; + else + diverr = true; + break; + } + operation = 0; + value = result; + update_value(); + begin_new_value = true; +} + +void perform_neg() +{ + value = -value; + update_value(); +} + +void perform_ix() +{ + if (!value) + diverr=true; + else + value = 1.0/value; + update_value(); +} + +void perform_sqrt() +{ + value = sqrt(value); + update_value(); +} + +void perform_square() +{ + value = value*value; + update_value(); +} + +void perform_point() +{ + if (!got_point) { + got_point = true; + rightgoing_place = 0; + } +} + +void perform_store() +{ + stored = value; + got_point = false; + begin_new_value = true; +} + +void perform_recall() +{ + value = stored; + got_point = false; + begin_new_value = true; + update_value(); +} + +void perform_clear() +{ + value = 0.0; + got_point = false; + diverr = false; + update_value(); +} +void perform_clearall() +{ + value = result = stored = 0.0; + got_point = false; + diverr = false; + update_value(); +} + +void perform_div() +{ + operation = DIVIDE; + got_point = false; + result = value; + begin_new_value = true; +} + +void perform_sub() +{ + operation = SUBTRACT; + got_point = false; + result = value; + begin_new_value = true; +} + +void perform_mult() +{ + operation = MULTIPLY; + got_point = false; + result = value; + begin_new_value = true; +} + +void perform_add() +{ + operation = ADD; + got_point = false; + result = value; + begin_new_value = true; +} + +int +main(int argc, char** argv) +{ + int i; + + dpy = fbui_display_open (); + if (!dpy) + FATAL("cannot open display"); + + win_w = 200; + win_h = 180; + win = fbui_window_open (dpy, win_w,win_h, &win_w, &win_h, 9999,9999, 0, -1, + &fgcolor, + &bgcolor, + "fbcalc", VERSION, + FBUI_PROGTYPE_EPHEMERAL, + false, false, + -1, + true, // need keys + false, + false, + argc,argv); + if (!win) + FATAL ("cannot create window"); + + font = font_new (); + + if (win_w < 200) { + if (!pcf_read (font, "courR10.pcf")) { + font_free (font); + FATAL ("cannot load font"); + } + } else { + if (!pcf_read (font, "courR12.pcf")) { + font_free (font); + FATAL ("cannot load font"); + } + } + + fbui_set_font (dpy,win,font); + + double tmp1,tmp2; + tmp1 = cols + (cols + 1.0)/2.0; + tmp2 = 1.0 + rows + (rows + 2.0)/2.0; + button_width = win_w / tmp1; + button_height = win_h / tmp2; + + got_point = false; + + short current_x = -1, current_y = -1; + + while(1) { + char need_draw=0; + char full_draw=0; + + Event ev; + int err; + if (err = fbui_wait_event (dpy, &ev, FBUI_EVENTMASK_ALL )) + { + if (err != FBUI_ERR_NOEVENT) + fbui_print_error (err); + continue; + } + + Window *win2; + + int num= ev.type; + + win2 = ev.win; + if (win2 != win) + FATAL ("event's window is not ours"); + + if (num == FBUI_EVENT_EXPOSE) { + need_draw=1; + full_draw=1; + } else + if (num == FBUI_EVENT_MOTION) { + current_x = ev.x; + current_y = ev.y; + } else + if (num == FBUI_EVENT_ENTER) { + fbui_draw_rect (dpy, win, 0,0, win_w-1, win_h-1, RGB_RED); + fbui_draw_rect (dpy, win, 1,1, win_w-2, win_h-2, RGB_RED); + fbui_flush (dpy, win); + continue; + } + else + if (num == FBUI_EVENT_LEAVE) { + fbui_draw_rect (dpy, win, 0,0, win_w-1, win_h-1, bgcolor); + fbui_draw_rect (dpy, win, 1,1, win_w-2, win_h-2, bgcolor); + fbui_flush (dpy, win); + continue; + } + else + if (num == FBUI_EVENT_MOVE_RESIZE) { + win_w = ev.width; + win_h = ev.height; + need_draw=1; + } + else + if (num == FBUI_EVENT_KEY) { + short key = fbui_convert_key (dpy, ev.key); + if (!key) + continue; + + if (key=='q') + break; + + switch (key) { + case '.': perform_point(); break; + case '/': perform_div(); break; + case '=': perform_equals(); break; + case '*': perform_mult(); break; + case '+': perform_add(); break; + case '-': perform_sub(); break; + case 'c': perform_clear(); break; + case 's': perform_store(); break; + case 'r': perform_recall(); break; + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + insert_digit (key); + continue; + } + + } + else + if (num == FBUI_EVENT_BUTTON) { + if (ev.key & FBUI_BUTTON_LEFT) { + if (ev.key & 1) { + int n = whichbutton (current_x, current_y); + switch (n) { + case 0: perform_store(); break; + case 1: perform_recall(); break; + case 2: perform_clearall(); break; + case 3: perform_clear(); break; + + case 4: perform_ix(); break; + case 5: perform_sqrt(); break; + case 6: perform_square(); break; + case 7: perform_div(); break; + + case 8: insert_digit ('7'); break; + case 9: insert_digit ('8'); break; + case 10: insert_digit ('9'); break; + case 11: perform_mult(); break; + + case 12: insert_digit ('4'); break; + case 13: insert_digit ('5'); break; + case 14: insert_digit ('6'); break; + case 15: perform_sub(); break; + + case 16: insert_digit ('1'); break; + case 17: insert_digit ('2'); break; + case 18: insert_digit ('3'); break; + case 19: perform_add(); break; + + case 20: insert_digit ('0'); break; + case 21: perform_point(); break; + case 22: perform_neg(); break; + case 23: perform_equals (); break; + + } + } + } + } + + if (!need_draw) + continue; + + if (need_draw) { + update_value (); + + if (full_draw) { + int i,j; + for (j=0; j<rows; j++) + for (i=0; i<cols; i++) + draw_button (dpy,win,i,j, false); + } + } + + fbui_flush (dpy, win); + } + + fbui_window_close(dpy, win); + fbui_display_close(dpy); + return 0; +} diff --git a/libfbui/Clock/COPYING b/libfbui/Clock/COPYING @@ -0,0 +1,280 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS diff --git a/libfbui/Clock/Makefile b/libfbui/Clock/Makefile @@ -0,0 +1,15 @@ + +EXE=fbclock +SRC= main.c + +${EXE}: ${SRC} + gcc -I.. ${CFLAGS} ${SRC} -lm ../libfbui.a -g -o ${EXE} + strip ${EXE} + +clean: + rm -f ${EXE} + +install: ${EXE} + cp ${EXE} /usr/bin + chmod 755 /usr/bin/${EXE} + diff --git a/libfbui/Clock/main.c b/libfbui/Clock/main.c @@ -0,0 +1,206 @@ + +/*========================================================================= + * + * fbclock, an analog clock for FBUI (in-kernel framebuffer UI) + * Copyright (C) 2004 Zachary T Smith, fbui@comcast.net + * + * This module is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This module 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this module; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * (See the file COPYING in the main directory of this archive for + * more details.) + * + *=======================================================================*/ + + +/* Changes + * + * Sept 26, 2004: responds to geometry changes. + * Sept 30, 2004: lib changes. + */ + +#include <stdio.h> +#include <time.h> +#include <unistd.h> +#include <math.h> + +#include "libfbui.h" + + +static short w = 200; +static short h = 200; + +int getpos (int deg, int *xp, int *yp, int border) +{ + double radians; + double x,y,xradius,yradius; + + radians = deg; + radians /= 360.0; + radians *= 2.0 * 3.14159265; + + xradius = w / 2 - border; + yradius = h / 2 - border; + x = sin (radians) * xradius; + y = cos (radians) * yradius; + x += w/2; + y = h/2 - y; + + *xp = x; + *yp = y; +} + +int +main(int argc, char** argv) +{ + int i; + Display *dpy; + Window *win; + + unsigned long markercolor = 0x00ff00; + unsigned long centercolor = 0xffff00; + unsigned long handcolor = 0x00ffff; + unsigned long gemcolor = 0xffffff; + unsigned long bgcolor = 0x2000; + + dpy = fbui_display_open (); + if (!dpy) + FATAL("cannot open display"); + + w = 120; + h = 120; + win = fbui_window_open (dpy, w,h, &w, &h, 9999,9999, 0, -1, + &handcolor, + &bgcolor, + "fbclock", "", + FBUI_PROGTYPE_TOOL, false, false, -1, false,false,false, argc,argv); + if (!win) + FATAL ("cannot create window"); + +printf ("our window is id %d\n", win->id); + + time_t t0 = time(0); + while(1) { + time_t t; + int need=0, mustclear=0; + int size; + usleep (500000); + + t = time(0); + int tdiff = t - t0; + if (tdiff >= 1) { + need=1; + mustclear=1; + t0 = t; + } + + if (!need) { + Event ev; + Window *win2; + int err; + + if (err = fbui_poll_event (dpy, &ev, + FBUI_EVENTMASK_ALL & + ~(FBUI_EVENTMASK_KEY | FBUI_EVENTMASK_MOTION))) + { + if (err != FBUI_ERR_NOEVENT) + fbui_print_error (err); + continue; + } + + int num= ev.type; +printf ("%s got event %s\n", argv[0], fbui_get_event_name (ev.type)); + + win2 = ev.win; + if (win2 != win) { +printf ("ev.win=%08lx\n", (unsigned long)win2); + FATAL ("event's window is not ours"); + } + + if (num == FBUI_EVENT_EXPOSE) + need=1; + else + if (num == FBUI_EVENT_ENTER) { + printf ("fbclock got Enter\n"); + continue; + } + else + if (num == FBUI_EVENT_LEAVE) { + printf ("fbclock got Leave\n"); + continue; + } + else + if (num == FBUI_EVENT_MOVE_RESIZE) { + w = ev.width; + h = ev.height; + need=1; + } + } + + if (!need) + continue; + + struct tm *tmp = localtime (&t); + int hour = tmp->tm_hour; + int minute = tmp->tm_min; + int second = tmp->tm_sec; + + if (mustclear) + fbui_clear (dpy, win); + + int shorter_side = w < h ? w : h; + + int deg; + for (deg=0; deg < 360; deg += 6) { + int x,y; + getpos (deg, &x,&y, 5); + + int size=0; + if ((deg % 90) == 0) + size=2; + else + if ((deg % 30) == 0) + size=1; + fbui_fill_area (dpy, win, x-size, y-size, x+size, y+size, markercolor); + } + + int x,y; + float p = minute; + p /= 60.0; + p *= 30; + getpos ((hour%12)*30 + (int)p, &x,&y, shorter_side/4); + fbui_draw_line (dpy, win, w/2,h/2,x,y, handcolor); + fbui_draw_line (dpy, win, w/2+1,h/2,x+1,y, handcolor); + fbui_draw_line (dpy, win, w/2,h/2+1,x+1,y+1, handcolor); + + getpos (minute*6, &x,&y, 15); + fbui_draw_line (dpy, win, w/2,h/2,x,y, handcolor); + + getpos (second*6, &x,&y, 10); + fbui_draw_point (dpy, win, x,y-2, gemcolor); + fbui_draw_hline (dpy, win, x-1,x+1,y-1, gemcolor); + fbui_draw_hline (dpy, win, x-2,x+2,y, gemcolor); + fbui_draw_hline (dpy, win, x-1,x+1,y+1, gemcolor); + fbui_draw_point (dpy, win, x,y+2, gemcolor); + + size=3; + fbui_fill_area (dpy, win, w/2-size, h/2-size, w/2+size, h/2+size, centercolor); + + fbui_flush (dpy, win); + } + + fbui_window_close(dpy, win); + fbui_display_close(dpy); + return 0; +} diff --git a/libfbui/Dump/COPYING b/libfbui/Dump/COPYING @@ -0,0 +1,280 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS diff --git a/libfbui/Dump/Makefile b/libfbui/Dump/Makefile @@ -0,0 +1,14 @@ + +EXE=fbdump +SRC= main.c jpeg.c + +${EXE}: ${SRC} + gcc -lm -I.. -g ${SRC} -o ${EXE} -ljpeg + strip ${EXE} + +clean: + rm -f ${EXE} + +install: ${EXE} + cp ${EXE} /usr/bin + chmod 755 /usr/bin/${EXE} diff --git a/libfbui/Dump/jpeg.c b/libfbui/Dump/jpeg.c @@ -0,0 +1,268 @@ + +/* + * example.c + * + * This file illustrates how to use the IJG code as a subroutine library + * to read or write JPEG image files. You should look at this code in + * conjunction with the documentation file libjpeg.doc. + * + * This code will not do anything useful as-is, but it may be helpful as a + * skeleton for constructing routines that call the JPEG library. + * + * We present these routines in the same coding style used in the JPEG code + * (ANSI function definitions, etc); but you are of course free to code your + * routines in a different style if you prefer. + */ + +#include <stdio.h> + +/* + * Include file for users of JPEG library. + * You will need to have included system headers that define at least + * the typedefs FILE and size_t before you can include jpeglib.h. + * (stdio.h is sufficient on ANSI-conforming systems.) + * You may also wish to include "jerror.h". + */ + +#include <jpeglib.h> + +/* + * <setjmp.h> is used for the optional error recovery mechanism shown in + * the second part of the example. + */ + +#include <setjmp.h> + +/******************** JPEG COMPRESSION SAMPLE INTERFACE *******************/ + +/* This half of the example shows how to feed data into the JPEG compressor. + * We present a minimal version that does not worry about refinements such + * as error recovery (the JPEG code will just exit() if it gets an error). + */ + +/* + * IMAGE DATA FORMATS: + * + * The standard input image format is a rectangular array of pixels, with + * each pixel having the same number of "component" values (color channels). + * Each pixel row is an array of JSAMPLEs (which typically are unsigned chars). + * If you are working with color data, then the color values for each pixel + * must be adjacent in the row; for example, R,G,B,R,G,B,R,G,B,... for 24-bit + * RGB color. + * + * For this example, we'll assume that this data structure matches the way + * our application has stored the image in memory, so we can just pass a + * pointer to our image buffer. In particular, let's say that the image is + * RGB color and is described by: + */ + +extern JSAMPLE * image_buffer; /* Points to large array of R,G,B-order data */ +extern int image_height; /* Number of rows in image */ +extern int image_width; /* Number of columns in image */ + +/* + * Sample routine for JPEG compression. We assume that the target file name + * and a compression quality factor are passed in. + */ + +GLOBAL(void) +write_JPEG_file (char * filename, int quality) +{ + /* This struct contains the JPEG compression parameters and pointers to + * working space (which is allocated as needed by the JPEG library). + * It is possible to have several such structures, representing multiple + * compression/decompression processes, in existence at once. We refer + * to any one struct (and its associated working data) as a "JPEG object". + */ + struct jpeg_compress_struct cinfo; + /* This struct represents a JPEG error handler. It is declared separately + * because applications often want to supply a specialized error handler + * (see the second half of this file for an example). But here we just + * take the easy way out and use the standard error handler, which will + * print a message on stderr and call exit() if compression fails. + * Note that this struct must live as long as the main JPEG parameter + * struct, to avoid dangling-pointer problems. + */ + struct jpeg_error_mgr jerr; + /* More stuff */ + FILE * outfile; /* target file */ + JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */ + int row_stride; /* physical row width in image buffer */ + + /* Step 1: allocate and initialize JPEG compression object */ + + /* We have to set up the error handler first, in case the initialization + * step fails. (Unlikely, but it could happen if you are out of memory.) + * This routine fills in the contents of struct jerr, and returns jerr's + * address which we place into the link field in cinfo. + */ + cinfo.err = jpeg_std_error(&jerr); + /* Now we can initialize the JPEG compression object. */ + jpeg_create_compress(&cinfo); + + /* Step 2: specify data destination (eg, a file) */ + /* Note: steps 2 and 3 can be done in either order. */ + + /* Here we use the library-supplied code to send compressed data to a + * stdio stream. You can also write your own code to do something else. + * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that + * requires it in order to write binary files. + */ + if ((outfile = fopen(filename, "wb")) == NULL) { + fprintf(stderr, "can't open %s\n", filename); + exit(1); + } + jpeg_stdio_dest(&cinfo, outfile); + + /* Step 3: set parameters for compression */ + + /* First we supply a description of the input image. + * Four fields of the cinfo struct must be filled in: + */ + cinfo.image_width = image_width; /* image width and height, in pixels */ + cinfo.image_height = image_height; + cinfo.input_components = 3; /* # of color components per pixel */ + cinfo.in_color_space = JCS_RGB; /* colorspace of input image */ + /* Now use the library's routine to set default compression parameters. + * (You must set at least cinfo.in_color_space before calling this, + * since the defaults depend on the source color space.) + */ + jpeg_set_defaults(&cinfo); + /* Now you can set any non-default parameters you wish to. + * Here we just illustrate the use of quality (quantization table) scaling: + */ + jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */); + + /* Step 4: Start compressor */ + + /* TRUE ensures that we will write a complete interchange-JPEG file. + * Pass TRUE unless you are very sure of what you're doing. + */ + jpeg_start_compress(&cinfo, TRUE); + + /* Step 5: while (scan lines remain to be written) */ + /* jpeg_write_scanlines(...); */ + + /* Here we use the library's state variable cinfo.next_scanline as the + * loop counter, so that we don't have to keep track ourselves. + * To keep things simple, we pass one scanline per call; you can pass + * more if you wish, though. + */ + row_stride = image_width * 3; /* JSAMPLEs per row in image_buffer */ + + while (cinfo.next_scanline < cinfo.image_height) { + /* jpeg_write_scanlines expects an array of pointers to scanlines. + * Here the array is only one element long, but you could pass + * more than one scanline at a time if that's more convenient. + */ + row_pointer[0] = & image_buffer[cinfo.next_scanline * row_stride]; + (void) jpeg_write_scanlines(&cinfo, row_pointer, 1); + } + + /* Step 6: Finish compression */ + + jpeg_finish_compress(&cinfo); + /* After finish_compress, we can close the output file. */ + fclose(outfile); + + /* Step 7: release JPEG compression object */ + + /* This is an important step since it will release a good deal of memory. */ + jpeg_destroy_compress(&cinfo); + + /* And we're done! */ +} + +/* + * SOME FINE POINTS: + * + * In the above loop, we ignored the return value of jpeg_write_scanlines, + * which is the number of scanlines actually written. We could get away + * with this because we were only relying on the value of cinfo.next_scanline, + * which will be incremented correctly. If you maintain additional loop + * variables then you should be careful to increment them properly. + * Actually, for output to a stdio stream you needn't worry, because + * then jpeg_write_scanlines will write all the lines passed (or else exit + * with a fatal error). Partial writes can only occur if you use a data + * destination module that can demand suspension of the compressor. + * (If you don't know what that's for, you don't need it.) + * + * If the compressor requires full-image buffers (for entropy-coding + * optimization or a multi-scan JPEG file), it will create temporary + * files for anything that doesn't fit within the maximum-memory setting. + * (Note that temp files are NOT needed if you use the default parameters.) + * On some systems you may need to set up a signal handler to ensure that + * temporary files are deleted if the program is interrupted. See libjpeg.doc. + * + * Scanlines MUST be supplied in top-to-bottom order if you want your JPEG + * files to be compatible with everyone else's. If you cannot readily read + * your data in that order, you'll need an intermediate array to hold the + * image. See rdtarga.c or rdbmp.c for examples of handling bottom-to-top + * source data using the JPEG code's internal virtual-array mechanisms. + */ + +/******************** JPEG DECOMPRESSION SAMPLE INTERFACE *******************/ + +/* This half of the example shows how to read data from the JPEG decompressor. + * It's a bit more refined than the above, in that we show: + * (a) how to modify the JPEG library's standard error-reporting behavior; + * (b) how to allocate workspace using the library's memory manager. + * + * Just to make this example a little different from the first one, we'll + * assume that we do not intend to put the whole image into an in-memory + * buffer, but to send it line-by-line someplace else. We need a one- + * scanline-high JSAMPLE array as a work buffer, and we will let the JPEG + * memory manager allocate it for us. This approach is actually quite useful + * because we don't need to remember to deallocate the buffer separately: it + * will go away automatically when the JPEG object is cleaned up. + */ + +/* + * ERROR HANDLING: + * + * The JPEG library's standard error handler (jerror.c) is divided into + * several "methods" which you can override individually. This lets you + * adjust the behavior without duplicating a lot of code, which you might + * have to update with each future release. + * + * Our example here shows how to override the "error_exit" method so that + * control is returned to the library's caller when a fatal error occurs, + * rather than calling exit() as the standard error_exit method does. + * + * We use C's setjmp/longjmp facility to return control. This means that the + * routine which calls the JPEG library must first execute a setjmp() call to + * establish the return point. We want the replacement error_exit to do a + * longjmp(). But we need to make the setjmp buffer accessible to the + * error_exit routine. To do this, we make a private extension of the + * standard JPEG error handler object. (If we were using C++, we'd say we + * were making a subclass of the regular error handler.) + * + * Here's the extended error handler struct: + */ + +struct my_error_mgr { + struct jpeg_error_mgr pub; /* "public" fields */ + + jmp_buf setjmp_buffer; /* for return to caller */ +}; + +typedef struct my_error_mgr * my_error_ptr; + +/* + * Here's the routine that will replace the standard error_exit method: + */ + +METHODDEF(void) +my_error_exit (j_common_ptr cinfo) +{ + /* cinfo->err really points to a my_error_mgr struct, so coerce pointer */ + my_error_ptr myerr = (my_error_ptr) cinfo->err; + + /* Always display the message. */ + /* We could postpone this until after returning, if we chose. */ + (*cinfo->err->output_message) (cinfo); + + /* Return control to the setjmp point */ + longjmp(myerr->setjmp_buffer, 1); +} + diff --git a/libfbui/Dump/main.c b/libfbui/Dump/main.c @@ -0,0 +1,195 @@ + +/*========================================================================= + * + * fbdump, a screen dumper for FBUI (in-kernel framebuffer UI) + * Copyright (C) 2004 Zachary T Smith, fbui@comcast.net + * + * This module is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This module 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this module; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * (See the file COPYING in the main directory of this archive for + * more details.) + * + *=======================================================================*/ + + +/* Copyright (C) 2004 by Zack T Smith */ + +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <sys/ioctl.h> +#include <linux/fb.h> +#include <sys/mman.h> + +#include <linux/fb.h> +#include <jpeglib.h> + + +JSAMPLE * image_buffer; +int image_height; +int image_width; + +static struct fb_fix_screeninfo fi; +static struct fb_var_screeninfo vi; + + +extern int read_JPEG_file (char*); + +int +main(int argc, char** argv) +{ + int i,j; + char *path="dump.jpg"; + int fd; + unsigned char *buf = NULL; + unsigned long buflen = 0; + int bpp; + int bytes_per_pixel; + + image_buffer=NULL; + image_height=0; + image_width=0; + + i=1; + while(i<argc) { + if ('-' != *argv[i]) { + path=argv[i]; + break; + } + i++; + } + + fd = open ("/dev/fb0", O_RDWR ); + if (fd == -1) + fd = open ("/dev/fb/0", O_RDWR ); + if (fd == -1) + { + perror("open"); + exit(1); + } + else + { + if (ioctl (fd, FBIOGET_FSCREENINFO, &fi)) + { + perror("ioctl"); + exit(1); + } + else + if (ioctl (fd, FBIOGET_VSCREENINFO, &vi)) + { + perror("ioctl"); + exit(1); + } + else + { + if (fi.visual != FB_VISUAL_TRUECOLOR && + fi.visual != FB_VISUAL_DIRECTCOLOR ) + { + fprintf (stderr, "error: need direct/truecolor display\n"); + exit(1); + } + else + { + buf = (unsigned char*) fi.smem_start; + buflen = fi.smem_len; + buf = mmap (buf, buflen, + PROT_WRITE | PROT_READ, + MAP_SHARED, fd, 0); + if (buf == MAP_FAILED) + { + perror ("mmap"); + exit(1); + } + } + } + } + + printf ("Framebuffer resolution: %dx%d, %dbpp\n", + vi.xres, vi.yres, vi.bits_per_pixel); + + image_width = vi.xres; + image_height = vi.yres; + bpp = vi.bits_per_pixel; + bytes_per_pixel = (bpp+7)>>3; + + image_buffer = (JSAMPLE*) malloc (image_width * image_height * 3); + if (!image_buffer) { + fprintf (stderr,"error: cannot allocate pixel buffer\n"); + exit(1); + } + + unsigned char ro = vi.red.offset; + unsigned char go = vi.green.offset; + unsigned char bo = vi.blue.offset; + unsigned char rl = vi.red.length; + unsigned char gl = vi.green.length; + unsigned char bl = vi.blue.length; + + unsigned long ix = 0; + + for (j=0; j<image_height; j++) { + unsigned char *ptr = buf + fi.line_length * j; + unsigned long value=0; + int x=0; + + while (x < image_width) { + unsigned long value=0; + unsigned long a0,a1=0,a2=0,a3=0; + switch (bytes_per_pixel) { + case 4: + a0 = *ptr++; + a1 = *ptr++; + a2 = *ptr++; + a3 = *ptr++; + break; + case 3: + a0 = *ptr++; + a1 = *ptr++; + a2 = *ptr++; + break; + case 2: + a0 = *ptr++; + a1 = *ptr++; + break; + case 1: + a0 = *ptr++; + break; + } + a1 <<= 8; + a2 <<= 16; + a3 <<= 24; + value = a0|a1|a2|a3; + + unsigned long r,g,b; + r = value >> ro; + g = value >> go; + b = value >> bo; + r <<= (8 - rl); + g <<= (8 - gl); + b <<= (8 - bl); + + image_buffer[ix++] = r; + image_buffer[ix++] = g; + image_buffer[ix++] = b; + x++; + } + } + + write_JPEG_file (path,999); + close(fd); + + return 0; +} diff --git a/libfbui/FBUI.txt b/libfbui/FBUI.txt @@ -0,0 +1,48 @@ + +FBUI +Copyright 2004 by Zack Smith. + +------ ~ ------ + +FBUI is based on several vital ideas: + +1. bloated programs are hideous, wasteful, stupid and avoidable. + +2. a windowing system should never use 20 megabytes, + as XFree86 does; it is bloated. + +3. by putting the GUI into the kernel, an upper limit + is imposed on bloat in the core GUI code since all + kernel code must be small and fast. + +4. incidentally overlapping windows were always a bad idea; + nobody really enjoy shuffling and resizing windows, + any more than they enjoy shuffling papers. + +5. it's not a good idea to put drivers in userspace, + which is what X and some framebuffer programs do. + +6. having direct fb access may nevertheless be useful + +FBUI addresses these ideas in the following ways: + +1. abandon X + +2. abandon X + +3. keep FBUI tiny : it will always be < 32kB for 2-D graphics + +4. two solutions: + a. FBUI allows windows on any virtual console + b. an OPTIONAL "window manager" process is permitted + to move windows around, resize them, and + in particular: flip them in and out. + +5. FBUI implements basic drawing and allows + implementation of accelerated routines; however + even the basic drawing routines are quite fast. + +6. FBUI does not impede any application from mmapping + the framebuffer anyway. + + diff --git a/libfbui/FONTS b/libfbui/FONTS @@ -0,0 +1,4 @@ + +Fonts should be in /usr/X11/lib/fonts/75dpi, and they should NOT +be gzipped. + diff --git a/libfbui/Launcher/COPYING b/libfbui/Launcher/COPYING @@ -0,0 +1,280 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS diff --git a/libfbui/Launcher/Makefile b/libfbui/Launcher/Makefile @@ -0,0 +1,15 @@ + +EXE=fblauncher +SRC= main.c + +${EXE}: ${SRC} + gcc -I.. ${CFLAGS} ${SRC} -lm ../libfbui.a -g -o ${EXE} + strip ${EXE} + +clean: + rm -f ${EXE} + +install: ${EXE} + cp ${EXE} /usr/bin + chmod 755 /usr/bin/${EXE} + diff --git a/libfbui/Launcher/README b/libfbui/Launcher/README @@ -0,0 +1,9 @@ + +Launcher program. + +Based on ToDo, this program displays a list. + +Unlike ToDo, clicking on a list item starts a program, and exits the launcher. + +Launcher is an Ephemeral program i.e. intended to be used only for a new moments. + diff --git a/libfbui/Launcher/main.c b/libfbui/Launcher/main.c @@ -0,0 +1,366 @@ + +/*========================================================================= + * + * fblauncher, a launcher for FBUI (in-kernel framebuffer UI) + * Copyright (C) 2004 Zachary T Smith, fbui@comcast.net + * + * This module is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This module 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this module; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * (See the file COPYING in the main directory of this archive for + * more details.) + * + *=======================================================================*/ + + +/* Changes + * + */ + +#include <stdio.h> +#include <sys/param.h> +#include <time.h> +#include <unistd.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <string.h> + + +#include "libfbui.h" + + +#define VERSION "0.1" + + +Font *titlefont, *listfont; +short titlefontheight, listfontheight; + + +short total_items; +typedef struct item { + char *s1, *s2; + struct item *next; +} Item; + +Item *items; + +Item *Item_new(char *s1, char *s2) +{ + if (!s1 || !s2) return NULL; + + struct item *nu = (struct item*)malloc(sizeof(struct item)); + if (!nu) + FATAL("cannot allocate list item"); + + nu->next=NULL; + nu->s1 = strdup(s1); + nu->s2 = strdup(s2); + if (!nu->s1 || !nu->s2) + FATAL("cannot allocate string for item"); + return nu; +} + +Item *Item_append_pair (char *s1, char *s2) +{ + struct item *nu = Item_new (s1,s2); + if (nu) { + struct item *i = items; + if (!i) { + items = nu; + } else { + while (i->next) + i = i->next; + i->next = nu; + } + ++total_items; + } + return nu; +} + +int readline (FILE *f, char *line) +{ + int ix=0; + short ch; + while (EOF != (ch = fgetc (f))) { + if (ch == '\r') + continue; + if (ch == '\n') + break; + line[ix++] = ch; + if (ix==249) break; + } + line[ix]=0; + if (!ix && ch == EOF) + return -1; + else + return ix; +} + + +int readfile (char *path) +{ + short ch; + char line[250]; + if (!path) + return 0; + FILE *f = fopen (path, "r"); + if (!f) + return 0; + + int count; + if (readline (f, line) < 1) + return 0; + + count = atoi (line); + + while(count--) { + if (-1 == readline (f, line)) + break; + + char *s = strchr (line, ' '); + if (s) { + *s = 0; + s++; + + if (line[0]) + Item_append_pair (line, s); + } + } + + fclose (f); + return 1; +} + +char *Item_lookup_n (int n) +{ + Item *im = items; + + while (im && n--) + im = im->next; + + return im? im->s2 : NULL; +} + + +static short w = 200; +static short h = 200; + +int +main(int argc, char** argv) +{ + int i; + Display *dpy; + Window *win; + char path[MAXPATHLEN]; + struct stat st; + FILE *f; + int highlight_which = 0; + + total_items = 0; + items=NULL; + + strcpy (path, getenv ("HOME")); + strcat (path, "/.launcher"); + i = stat (path, &st); + if (i) { + WARNING ("can't open ~/.launcher; creating..."); + f = fopen (path, "w"); + fprintf (f, "3\n"); + fprintf (f, "Terminal fbterm\n"); + fprintf (f, "Calculator fbcalc\n"); + fprintf (f, "Scribble fbscribble\n"); + fclose (f); + } + + f = fopen (path, "r"); + if (!f) + FATAL ("can't open ~/.launcher"); + fclose (f); + + if (!readfile (path)) + FATAL ("error reading ~/.launcher"); + + titlefont = font_new (); + listfont = font_new (); + if (!titlefont || !listfont) + FATAL ("cannot allocate Font"); + + if (!pcf_read (titlefont, "helvR12.pcf")) + FATAL ("cannot read Helv bold 12 point"); + if (!pcf_read (listfont, "timR10.pcf")) + FATAL ("cannot read Times 12 point"); + + short indent,a,d; + font_string_dims (listfont, "88. ", &indent, &a, &d); + + listfontheight = listfont->ascent + listfont->descent; + titlefontheight = titlefont->ascent + titlefont->descent; + + unsigned long titlecolor = RGB_RED; + unsigned long listcolor = RGB_BROWN; + unsigned long titlefontcolor = RGB_YELLOW; + unsigned long listfontcolor = RGB_ORANGE; + unsigned long sepcolor = RGB_WHITE; + unsigned long listhighlightcolor = RGB_LTBROWN; + + dpy = fbui_display_open (); + if (!dpy) + FATAL("cannot open display"); + + w = 150; + h = 150; + win = fbui_window_open (dpy, w,h, &w, &h, 9999,9999, 0, -50, + &listfontcolor, + &listcolor, + "fblauncher", VERSION, + FBUI_PROGTYPE_EPHEMERAL, + false,false, + -1, + true, // need keys + false, + false, + argc,argv); + if (!win) + FATAL ("cannot create window"); + + short x=-1, y=-1; + short whichlaunch = -1; + + char done=0; + while(!done) { + char needdraw=0; + char fulldraw=0; + Event ev; + int err; + + if (err = fbui_wait_event (dpy, &ev, FBUI_EVENTMASK_ALL)) { + fbui_print_error (err); + continue; + } + + int type = ev.type; + Window *win2 = ev.win; + + if (win2 != win) + FATAL ("event's window is not ours"); + + switch(type) { + case FBUI_EVENT_MOTION: + x = ev.x; + y = ev.y; + if (y >= (titlefontheight + 1)) { + int which = (y - titlefontheight - 1) / listfontheight; + if (which > total_items) + which = total_items; + if (which != highlight_which) { + highlight_which = which; + needdraw = 1; + } + } + break; + + case FBUI_EVENT_EXPOSE: + needdraw=1; + fulldraw=1; + break; + + case FBUI_EVENT_ENTER: + break; + + case FBUI_EVENT_BUTTON: + if (y < titlefontheight) { + if (x >= (w - 10)) + done=true; + continue; + } + + if ((ev.key & FBUI_BUTTON_LEFT) && (ev.key & 1)) { + whichlaunch = (y - titlefontheight) / listfontheight; + done=true; + continue; + } + break; + + case FBUI_EVENT_LEAVE: + if (highlight_which != -1) { + highlight_which = -1; + needdraw=1; + } + break; + case FBUI_EVENT_MOVE_RESIZE: + w = ev.width; + h = ev.height; + break; + } + + if (!needdraw) + continue; + + if (fulldraw) { + char title[200]; + sprintf (title, "Launcher %s",VERSION); + + short wid,a,d; + font_string_dims (titlefont, title, &wid,&a,&d); + short title_pos = (w - wid) / 2; + + fbui_fill_area (dpy, win, 0, 0, w-1, titlefontheight, titlecolor); + fbui_draw_hline (dpy, win, 0, w-1, titlefontheight, sepcolor); + fbui_draw_string (dpy, win, titlefont, title_pos, 0, + title, titlefontcolor); + } + + fbui_fill_area (dpy, win, 0, titlefontheight+1, w-1, h, listcolor); + + fbui_draw_line (dpy, win, w-10, 2, w-3, 9, RGB_WHITE); + fbui_draw_line (dpy, win, w-10, 9, w-3, 2, RGB_WHITE); + + struct item *im = items; + int ix=0; + while (im) { + char numstr[5]; + sprintf (numstr, "%d.", ix+1); + + short y = titlefontheight+1+ix*listfontheight; + + if (ix == highlight_which) + fbui_fill_area (dpy, win, 0, y, w, y + listfontheight, + listhighlightcolor); + + fbui_draw_string (dpy, win, listfont, + 0, titlefontheight+1+ix*listfontheight, + numstr, listfontcolor); + + fbui_draw_string (dpy, win, listfont, + indent, y, im->s1, listfontcolor); + + im = im->next; + ix++; + } + + fbui_flush (dpy, win); + } + + fbui_window_close (dpy, win); + fbui_display_close (dpy); + + if (-1 != whichlaunch) { + char *launch = Item_lookup_n (whichlaunch); + if (launch) + system (launch); + } + + return 0; +} diff --git a/libfbui/LoadMonitor/COPYING b/libfbui/LoadMonitor/COPYING @@ -0,0 +1,280 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS diff --git a/libfbui/LoadMonitor/Makefile b/libfbui/LoadMonitor/Makefile @@ -0,0 +1,15 @@ + +EXE=fbload +SRC= main.c + +${EXE}: ${SRC} + gcc -I.. -g ${SRC} ../libfbui.a -lm -o ${EXE} + strip ${EXE} + +clean: + rm -f ${EXE} + +install: ${EXE} + cp ${EXE} /usr/bin + chmod 755 /usr/bin/${EXE} + diff --git a/libfbui/LoadMonitor/main.c b/libfbui/LoadMonitor/main.c @@ -0,0 +1,185 @@ + +/*========================================================================= + * + * fbload, a load monitor for FBUI (in-kernel framebuffer UI) + * Copyright (C) 2004 Zachary T Smith, fbui@comcast.net + * + * This module is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This module 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this module; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * (See the file COPYING in the main directory of this archive for + * more details.) + * + *=======================================================================*/ + + +/* Changes + * + * Sept 26, 2004: responds to geo changes. + */ + +#include <stdio.h> +#include <time.h> +#include <unistd.h> + +#include "libfbui.h" + + + +float getload () +{ + float a,b,c; + FILE *f = fopen ("/proc/loadavg", "r"); + if (3 != fscanf (f, "%f %f %f", &a, &b, &c)) + a = 0.0; + fclose (f); + return a; +} + + +int +main(int argc, char** argv) +{ + int i; + Display *dpy; + Window *win; + int seconds_per = 5; + + if (argc >= 2 && isdigit(*argv[1]) && '0'!=isdigit(*argv[1])) + seconds_per = atoi (argv[1]); + + short w = 50; + short h = 120; + float *values; + unsigned long fgcolor = RGB_GREEN; + unsigned long bgcolor = 0x2000; + + dpy = fbui_display_open (); + if (!dpy) + FATAL ("cannot open display"); + + win = fbui_window_open (dpy, w,h, &w,&h, 9999,9999, -1, -1, + &fgcolor, &bgcolor, "fbload", "", + FBUI_PROGTYPE_TOOL,false,false, -1,false, + false, false, argc,argv); + if (!win) + FATAL ("cannot create window"); + + int last_x = w - 1; + int last_y = h - 1; + + values = (float*) malloc (w * sizeof(float)); + if (!values) + FATAL("out of memory"); + + for (i=0; i<w; i++) + values[i] = 0.0; + + unsigned long barcolor = fgcolor; + + int range=0; + time_t t0 = time(NULL); + while(1) { + time_t t; + int need=0; + int need_redraw=0; + usleep (50000); + + t = time(NULL); + int tdiff = t - t0; + if (tdiff >= seconds_per) { + need=1; + t0 = t; + } + + if (!need) { + Event ev; + int err; + if (err = fbui_poll_event (dpy, &ev, + FBUI_EVENTMASK_ALL & ~FBUI_EVENTMASK_KEY)) + { + if (err != FBUI_ERR_NOEVENT) + fbui_print_error (err); + continue; + } +printf ("%s got event %s\n", argv[0], fbui_get_event_name (ev.type)); + + int num = ev.type; + char key = ev.key; + + if (ev.win != win) + FATAL ("event for wrong window"); + + if (num == FBUI_EVENT_EXPOSE) + need_redraw = need = 1; + else if (num == FBUI_EVENT_MOVE_RESIZE) { + w = ev.width; + h = ev.height; + need = 1; + } + if (num == FBUI_EVENT_ENTER) { + printf ("fbload got Enter\n"); + continue; + } + if (num == FBUI_EVENT_LEAVE) { + printf ("fbload got Leave\n"); + continue; + } + + } + + if (!need) + continue; + + /* shift values to left */ + for (i=1; i<w; i++) + values[i-1] = values[i]; + + int nu = values[w-1] = getload(); + nu++; + if (nu > range) + need_redraw = 1; + + /* get max value */ + float max = 0; + for (i=0; i<w; i++) { + if (max < values[i]) + max = values[i]; + } + + range = max; + range++; + if (!range) + range = 1; + + fbui_clear (dpy, win); + for (i=0; i<w; i++) + fbui_draw_vline (dpy, win, i, + h - ((float)h/range) * values[i], h, barcolor); + + if (range > 1) { + for (i=0; i<range; i++) { + int y = h/range; + y *= i; + y = h - y; + fbui_draw_hline (dpy, win, 0, last_x, y, RGB_YELLOW); + } + } + fbui_flush(dpy, win); + } + + fbui_window_close (dpy, win); + fbui_display_close (dpy); + return 0; +} diff --git a/libfbui/MPEG/CHANGES b/libfbui/MPEG/CHANGES @@ -0,0 +1,95 @@ +CHANGES +---------- + +January 9, 1996 to July 17, 1996 +- cleaned up some code which gave warnings. +- altered some code to be compatible with Sun CC compiler. + However, support in the makefile for non-ansi C compilers + has been dropped (this is a stupid thing to support). + +December 20, 1995 to January 9, 1996: + +verified on HHI #22, TCEH #23 bitstreams. + + 1. new arguments format. Got to be so many argument fields that + a new more consistent format was devised. + + 2. Frame_Store_Flag (-f) option now controls lower layer prediciton + picture format (field or framewise) + + 3. getpic() structural changes + + +Since December 18, 1995: + +1. added special case for current B pictures subsframe.c which + loads entire reference frame for buffer substitution. + +2. fixed -l omission (-lXext) in Makefile that drives Tristan nuts everytime. + + +Since December 14, 1995: + + 1. organized frame buffer substitution routines into subspic.c + 2. added "big file" -b mode for Tristan ;-) + + +Since July 4, 1994: + +1. Concatenated elementary sequences within same bitstream + + Decode can now handle concatenated elementary video sequences of + arbitrary parameters. + +2. TRACE and VERBOSE #ifdef flags + +3. More disciplined naming convention + + normative variables and bitstream elements defined in 13818 are + verbatim, lower case. Implementation specific routines and variables + are capitolized. + +4. Spatial scalability corrections + - see Carsten's document (spatscal.doc) + +5. D-pictures (picture_coding_type==D_TYPE) + + Only two small changes were necessary to accomodate D-pictures: + + a. in Decode_MPEG1_Intra_Block() added line which termines + subroutine after DC coefficient has been processed. + + b. in picture_data(), added line which parses marker bit. + + + 6. forced decoder to display frame progressively (regardless of whether + the picture is frame structured or field structured) when -f flag + is invoked in the command line arguements. + + also: progressive_frame now decides whether a frame is to be displayed + as a frame picture to two field pictures, rather than the older convention + of testing progressive_sequence. + + 7. Adapted systems parser from Stefan's mpeg2play to mpeg2decode. + The major changes are: + + mpeg2dec.c: + - fseek() called twice + + gethdr.c, getpic.c: + instances of Flush_Bits(par,32) changed to Flush_Bits32(par) + + gethdr.c + Get_Bits(par,32) changed to Get_32_Bits(par) + + global.h + added rdmax, sysstream, and bfr[] to parameters struct. + + 8. Restructuring of getpic.c: + + a. moved picture pointer rotation into Update_Picture_Buffers() + b. moved picture output logic into Output_Current_Frame() to + in anticipation of 3:2 pulldown + + + diff --git a/libfbui/MPEG/EXAMPLES b/libfbui/MPEG/EXAMPLES @@ -0,0 +1,49 @@ +EXAMPLES: + +1. to decode a bitstream with double precision IDCT, such as + to create a reference reconstruction set of frames: + + mpeg2decode -r -f -o0 rec%d -b bitstream.mpg + +2. to decode a bitstream with fast integer IDCT, such as + to create a test reconstruction set of frames: + + mpeg2decode -f -o0 rec%d -b bitstream.mpg + +3. To substitute reference pictures with external reference + pictures (ref%d): + + mpeg2decode -f -x ref%d -b bitstream.mpg -o0 rec%d + + +4. Same as 3. only using a single large concatenated file for the + sequence of reconstruction frames. + + mpeg2decode -f -g -x ref%d bitstream.mpg -o0 rec%d + +5. Decode an SNR enhancement bitstream at the same time as base layer + stream: + + mpeg2decode -o0 rec%d -e snr_bitstream.mpg -b base_bitstream.mpg + +6. Decode a Spatially scalable bitstream + + Step 1: create lower layer reconstruction + + mpeg2decode -f -o0 llrec%d -b base_layer.mpg + + Step 2: decode enhancement bitstream, combined reconstruction. + + mpeg2decode -f -l llrec%d -b enhancement_layer.mpg -o0 rec%d + +------------ + where: + -o0 specifies .Y, .U, .V input + -f specifies field interleaved format + -b is the bitstream flag + -g specifies substitute file is a large concatendated one. + -e substitution flag + ref.pic filename of substitution sequence + bitstream.mpg bitstream + test%d output file pattern + diff --git a/libfbui/MPEG/IEEE1180 b/libfbui/MPEG/IEEE1180 @@ -0,0 +1,245 @@ +IEEE 1180 report for mpeg2decode fast integer IDCT: + +From stefan@lis.e-technik.tu-muenchen.de Thu May 26 08:18:36 1994 + +IEEE test conditions: -L = -256, +H = 255, sign = 1, #iters = 10000 +Peak absolute values of errors: + 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 +Worst peak error = 1 (meets spec limit 1) + +Mean square errors: + 0.0058 0.0118 0.0097 0.0057 0.0055 0.0117 0.0120 0.0063 + 0.0106 0.0157 0.0142 0.0099 0.0115 0.0168 0.0154 0.0123 + 0.0128 0.0156 0.0152 0.0095 0.0115 0.0147 0.0173 0.0096 + 0.0055 0.0115 0.0103 0.0078 0.0069 0.0092 0.0113 0.0071 + 0.0057 0.0134 0.0123 0.0067 0.0050 0.0109 0.0128 0.0065 + 0.0101 0.0172 0.0159 0.0093 0.0097 0.0148 0.0163 0.0130 + 0.0113 0.0171 0.0148 0.0103 0.0110 0.0153 0.0149 0.0093 + 0.0064 0.0123 0.0104 0.0065 0.0064 0.0111 0.0099 0.0066 +Worst pmse = 0.017300 (meets spec limit 0.06) +Overall mse = 0.010998 (meets spec limit 0.02) + +Mean errors: + 0.0014 0.0004 0.0003 0.0017 0.0003 0.0011 0.0010 -0.0001 + 0.0000 0.0003 0.0010 0.0003 0.0007 -0.0006 0.0004 0.0033 + 0.0000 -0.0008 -0.0006 0.0009 -0.0015 -0.0013 -0.0017 -0.0008 + -0.0017 0.0019 -0.0005 0.0010 0.0005 0.0000 -0.0017 -0.0001 + 0.0007 0.0034 0.0015 0.0021 0.0016 0.0007 -0.0006 0.0011 + -0.0007 0.0004 -0.0001 0.0003 0.0003 0.0004 0.0031 -0.0010 + 0.0009 -0.0005 -0.0004 0.0003 0.0008 -0.0015 -0.0007 -0.0007 + 0.0024 0.0001 0.0018 -0.0003 -0.0006 -0.0001 0.0009 0.0018 +Worst mean error = 0.003400 (meets spec limit 0.015) +Overall mean error = 0.000352 (meets spec limit 0.0015) + +0 elements of IDCT(0) were not zero + + +25.8u 0.1s 0:27 95% 0+216k 0+2io 0pf+0w +IEEE test conditions: -L = -5, +H = 5, sign = 1, #iters = 10000 +Peak absolute values of errors: + 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 +Worst peak error = 1 (meets spec limit 1) + +Mean square errors: + 0.0008 0.0008 0.0006 0.0006 0.0006 0.0006 0.0007 0.0005 + 0.0005 0.0003 0.0005 0.0001 0.0003 0.0007 0.0007 0.0004 + 0.0004 0.0012 0.0011 0.0007 0.0010 0.0008 0.0010 0.0003 + 0.0004 0.0004 0.0001 0.0002 0.0004 0.0007 0.0009 0.0004 + 0.0005 0.0005 0.0004 0.0002 0.0006 0.0004 0.0012 0.0003 + 0.0008 0.0006 0.0007 0.0007 0.0003 0.0012 0.0011 0.0004 + 0.0006 0.0002 0.0001 0.0002 0.0005 0.0005 0.0007 0.0005 + 0.0008 0.0004 0.0006 0.0003 0.0008 0.0006 0.0002 0.0003 +Worst pmse = 0.001200 (meets spec limit 0.06) +Overall mse = 0.000561 (meets spec limit 0.02) + +Mean errors: + 0.0008 0.0006 0.0000 0.0006 0.0006 0.0002 0.0005 0.0003 + 0.0005 0.0003 0.0003 0.0001 0.0001 0.0001 0.0005 0.0002 + 0.0004 0.0006 0.0005 0.0007 0.0006 0.0004 0.0002 -0.0001 + 0.0002 0.0002 0.0001 0.0002 0.0004 0.0005 0.0003 0.0002 + 0.0003 0.0003 0.0004 0.0002 0.0006 0.0000 0.0002 0.0003 + -0.0002 0.0004 0.0007 0.0005 0.0001 0.0010 0.0005 -0.0002 + 0.0004 0.0000 0.0001 0.0000 0.0001 0.0003 0.0005 0.0003 + 0.0006 0.0000 0.0002 0.0003 0.0004 0.0002 0.0002 0.0001 +Worst mean error = 0.001000 (meets spec limit 0.015) +Overall mean error = 0.000311 (meets spec limit 0.0015) + +0 elements of IDCT(0) were not zero + + +25.7u 0.1s 0:27 95% 0+216k 0+3io 0pf+0w +IEEE test conditions: -L = -300, +H = 300, sign = 1, #iters = 10000 +Peak absolute values of errors: + 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 +Worst peak error = 1 (meets spec limit 1) + +Mean square errors: + 0.0068 0.0097 0.0119 0.0064 0.0065 0.0105 0.0112 0.0050 + 0.0088 0.0130 0.0128 0.0088 0.0111 0.0152 0.0139 0.0109 + 0.0114 0.0127 0.0157 0.0099 0.0114 0.0137 0.0153 0.0109 + 0.0052 0.0097 0.0120 0.0060 0.0067 0.0114 0.0099 0.0065 + 0.0062 0.0096 0.0091 0.0064 0.0076 0.0092 0.0111 0.0058 + 0.0096 0.0139 0.0166 0.0112 0.0092 0.0141 0.0122 0.0103 + 0.0121 0.0138 0.0131 0.0089 0.0108 0.0172 0.0127 0.0104 + 0.0070 0.0109 0.0092 0.0055 0.0057 0.0128 0.0102 0.0069 +Worst pmse = 0.017200 (meets spec limit 0.06) +Overall mse = 0.010316 (meets spec limit 0.02) + +Mean errors: + -0.0010 0.0015 0.0001 -0.0004 0.0005 -0.0001 0.0008 0.0000 + 0.0004 0.0016 0.0006 0.0000 -0.0001 0.0004 0.0011 0.0001 + -0.0008 0.0013 0.0015 0.0003 0.0010 0.0005 -0.0005 0.0021 + 0.0006 0.0013 -0.0004 0.0000 0.0007 -0.0002 -0.0009 0.0003 + 0.0004 0.0004 -0.0001 -0.0004 0.0014 0.0018 0.0017 -0.0002 + 0.0024 0.0007 -0.0002 -0.0018 0.0004 0.0001 0.0010 0.0009 + 0.0001 -0.0002 0.0005 0.0003 -0.0016 0.0004 0.0013 -0.0006 + -0.0012 -0.0017 -0.0008 0.0003 0.0001 0.0018 0.0008 -0.0005 +Worst mean error = 0.002400 (meets spec limit 0.015) +Overall mean error = 0.000309 (meets spec limit 0.0015) + +0 elements of IDCT(0) were not zero + + +25.8u 0.0s 0:27 95% 0+216k 0+4io 0pf+0w +IEEE test conditions: -L = -256, +H = 255, sign = -1, #iters = 10000 +Peak absolute values of errors: + 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 +Worst peak error = 1 (meets spec limit 1) + +Mean square errors: + 0.0061 0.0118 0.0097 0.0057 0.0058 0.0113 0.0115 0.0061 + 0.0105 0.0159 0.0138 0.0097 0.0113 0.0166 0.0149 0.0123 + 0.0129 0.0155 0.0152 0.0095 0.0112 0.0145 0.0173 0.0094 + 0.0059 0.0112 0.0105 0.0076 0.0071 0.0091 0.0113 0.0073 + 0.0061 0.0130 0.0128 0.0066 0.0051 0.0108 0.0126 0.0067 + 0.0099 0.0168 0.0161 0.0095 0.0100 0.0149 0.0166 0.0132 + 0.0113 0.0171 0.0150 0.0101 0.0110 0.0157 0.0152 0.0094 + 0.0062 0.0121 0.0102 0.0065 0.0061 0.0112 0.0099 0.0065 +Worst pmse = 0.017300 (meets spec limit 0.06) +Overall mse = 0.010980 (meets spec limit 0.02) + +Mean errors: + -0.0005 0.0006 0.0001 -0.0007 0.0006 -0.0003 -0.0003 0.0011 + 0.0011 0.0003 -0.0002 0.0005 -0.0001 0.0008 0.0001 -0.0027 + 0.0013 0.0015 0.0010 -0.0001 0.0020 0.0019 0.0025 0.0016 + 0.0023 -0.0008 0.0011 -0.0002 0.0007 0.0003 0.0019 0.0009 + -0.0003 -0.0030 -0.0002 -0.0012 -0.0009 0.0000 0.0010 -0.0005 + 0.0009 0.0002 0.0015 0.0007 0.0002 0.0001 -0.0026 0.0018 + 0.0001 0.0011 0.0010 0.0005 -0.0004 0.0023 0.0014 0.0014 + -0.0014 0.0007 -0.0014 0.0009 0.0013 0.0006 -0.0007 -0.0007 +Worst mean error = 0.003000 (meets spec limit 0.015) +Overall mean error = 0.000355 (meets spec limit 0.0015) + +0 elements of IDCT(0) were not zero + + +25.8u 0.1s 0:27 95% 0+216k 0+3io 0pf+0w +IEEE test conditions: -L = -5, +H = 5, sign = -1, #iters = 10000 +Peak absolute values of errors: + 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 +Worst peak error = 1 (meets spec limit 1) + +Mean square errors: + 0.0010 0.0007 0.0008 0.0004 0.0008 0.0004 0.0005 0.0007 + 0.0005 0.0007 0.0005 0.0004 0.0006 0.0005 0.0005 0.0003 + 0.0003 0.0011 0.0009 0.0007 0.0008 0.0006 0.0011 0.0006 + 0.0003 0.0004 0.0002 0.0002 0.0003 0.0006 0.0008 0.0006 + 0.0004 0.0005 0.0006 0.0006 0.0003 0.0007 0.0007 0.0003 + 0.0013 0.0006 0.0008 0.0005 0.0004 0.0006 0.0008 0.0004 + 0.0003 0.0003 0.0003 0.0002 0.0005 0.0004 0.0006 0.0005 + 0.0005 0.0003 0.0006 0.0005 0.0011 0.0007 0.0005 0.0003 +Worst pmse = 0.001300 (meets spec limit 0.06) +Overall mse = 0.000561 (meets spec limit 0.02) + +Mean errors: + 0.0002 0.0005 0.0008 0.0000 0.0002 0.0004 0.0003 0.0007 + 0.0001 0.0003 0.0003 0.0002 0.0006 0.0003 0.0001 0.0003 + -0.0001 0.0007 0.0003 0.0001 0.0002 0.0006 0.0005 0.0006 + 0.0001 0.0004 0.0002 0.0002 0.0001 0.0002 0.0004 0.0004 + 0.0002 0.0005 0.0006 0.0004 0.0001 0.0005 0.0005 0.0003 + 0.0009 0.0002 0.0000 0.0001 0.0004 0.0000 0.0006 0.0004 + 0.0003 0.0003 0.0003 0.0002 0.0003 0.0000 0.0004 0.0003 + 0.0003 0.0003 0.0004 0.0003 0.0007 0.0005 0.0005 0.0003 +Worst mean error = 0.000900 (meets spec limit 0.015) +Overall mean error = 0.000333 (meets spec limit 0.0015) + +0 elements of IDCT(0) were not zero + + +25.7u 0.1s 0:27 95% 0+216k 0+0io 0pf+0w +IEEE test conditions: -L = -300, +H = 300, sign = -1, #iters = 10000 +Peak absolute values of errors: + 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 +Worst peak error = 1 (meets spec limit 1) + +Mean square errors: + 0.0067 0.0097 0.0118 0.0060 0.0066 0.0107 0.0113 0.0049 + 0.0082 0.0132 0.0128 0.0088 0.0110 0.0152 0.0140 0.0109 + 0.0122 0.0125 0.0156 0.0098 0.0113 0.0139 0.0152 0.0106 + 0.0054 0.0097 0.0121 0.0064 0.0067 0.0110 0.0096 0.0062 + 0.0064 0.0099 0.0090 0.0067 0.0078 0.0089 0.0112 0.0057 + 0.0098 0.0136 0.0165 0.0111 0.0090 0.0138 0.0120 0.0103 + 0.0121 0.0135 0.0131 0.0087 0.0107 0.0168 0.0128 0.0102 + 0.0069 0.0109 0.0091 0.0057 0.0061 0.0125 0.0103 0.0070 +Worst pmse = 0.016800 (meets spec limit 0.06) +Overall mse = 0.010283 (meets spec limit 0.02) + +Mean errors: + 0.0015 -0.0009 0.0006 0.0012 0.0002 0.0007 -0.0001 0.0005 + 0.0004 -0.0010 0.0000 0.0004 0.0006 0.0004 -0.0004 0.0007 + 0.0018 -0.0009 -0.0006 0.0000 -0.0003 -0.0001 0.0014 -0.0006 + -0.0002 -0.0011 0.0009 0.0004 -0.0003 0.0010 0.0010 0.0000 + 0.0004 0.0001 0.0010 0.0011 -0.0008 -0.0017 -0.0006 0.0009 + -0.0020 0.0000 0.0007 0.0021 0.0002 0.0002 -0.0004 -0.0003 + 0.0003 0.0005 -0.0003 -0.0001 0.0017 0.0002 -0.0004 0.0010 + 0.0015 0.0023 0.0013 0.0003 0.0005 -0.0011 -0.0003 0.0006 +Worst mean error = 0.002300 (meets spec limit 0.015) +Overall mean error = 0.000252 (meets spec limit 0.0015) + +0 elements of IDCT(0) were not zero + + +25.8u 0.0s 0:27 94% 0+216k 0+3io 0pf+0w + diff --git a/libfbui/MPEG/Makefile b/libfbui/MPEG/Makefile @@ -0,0 +1,99 @@ +# Makefile for mpeg2decode + +# Copyright (C) 1996, MPEG Software Simulation Group. All Rights Reserved. + +# +# Disclaimer of Warranty +# +# These software programs are available to the user without any license fee or +# royalty on an "as is" basis. The MPEG Software Simulation Group disclaims +# any and all warranties, whether express, implied, or statuary, including any +# implied warranties or merchantability or of fitness for a particular +# purpose. In no event shall the copyright-holder be liable for any +# incidental, punitive, or consequential damages of any kind whatsoever +# arising from the use of these programs. +# +# This disclaimer of warranty extends to the user of these programs and user's +# customers, employees, agents, transferees, successors, and assigns. +# +# The MPEG Software Simulation Group does not represent or warrant that the +# programs furnished hereunder are free of infringement of any third-party +# patents. +# +# Commercial implementations of MPEG-1 and MPEG-2 video, including shareware, +# are subject to royalty fees to patent holders. Many of these patents are +# general enough such that they are unavoidable regardless of implementation +# design. +# +# + +#WARNINGS = -Wall +#VERIFY = -DVERIFY + +#disable this flag if you do not want bitstream element tracing +#this will speed up the decoder some since it does not have to test +#the trace flag at several critical inner loop locations. +TRACE = -DTRACE + +#disable this flag if you do not need verbose trace, such as +#header information +VERBOSE = -DVERBOSE + +# uncomment the following two lines if you want to include X11 support + +# For FBUI don't use these: +# USE_DISP = -DDISPLAY +# LIBS = -lX11 + +# uncomment the following two lines if you want to use shared memory +# (faster display if server and client run on the same machine) + +# USE_SHMEM = -DSH_MEM +LIBS = ../libfbui.a # -lXext -lX11 + +# if your X11 include files / libraries are in a non standard location: +# set INCLUDEDIR to -I followed by the appropriate include file path and +# set LIBRARYDIR to -L followed by the appropriate library path and + +#INCLUDEDIR = -I/usr/openwin/include +LIBRARYDIR = -L/usr/X11/lib + +# +# GNU gcc +# +CC = gcc +CFLAGS = -O2 $(USE_DISP) $(USE_SHMEM) $(INCLUDEDIR) $(TRACE) $(VERBOSE) $(VERIFY) $(WARNINGS) + +OBJ = mpeg2dec.o getpic.o motion.o getvlc.o gethdr.o getblk.o getbits.o store.o recon.o spatscal.o idct.o idctref.o display.o systems.o subspic.o verify.o + +all: mpeg2decode + +pc: mpeg2dec.exe + +clean: + rm -f *.o *% core mpeg2decode + +mpeg2dec.exe: mpeg2decode + coff2exe mpeg2dec + +mpeg2decode: $(OBJ) + $(CC) $(CFLAGS) $(LIBRARYDIR) -o mpeg2decode $(OBJ) -lm $(LIBS) + +display.o : display.c config.h global.h mpeg2dec.h +getbits.o : getbits.c config.h global.h mpeg2dec.h +getblk.o : getblk.c config.h global.h mpeg2dec.h +gethdr.o : gethdr.c config.h global.h mpeg2dec.h +getpic.o : getpic.c config.h global.h mpeg2dec.h +getvlc.o : getvlc.c config.h global.h mpeg2dec.h getvlc.h +idct.o : idct.c config.h +idctref.o : idctref.c config.h +motion.o : motion.c config.h global.h mpeg2dec.h +mpeg2dec.o : mpeg2dec.c config.h global.h mpeg2dec.h +recon.o : recon.c config.h global.h mpeg2dec.h +spatscal.o : spatscal.c config.h global.h mpeg2dec.h +store.o : store.c config.h global.h mpeg2dec.h + +# additions since July 4, 1994 edition +systems.o : systems.c config.h global.h mpeg2dec.h +subspic.o : subspic.c config.h global.h mpeg2dec.h +verify.o: verify.c config.h global.h mpeg2dec.h diff --git a/libfbui/MPEG/README b/libfbui/MPEG/README @@ -0,0 +1,59 @@ + +Revised to support FBUI by Zack Smith +Nov 20, 2004 + +NOTE: + This mpeg player is very slow. + It's really not a serious utility. + Someone should create a Xine frontend for FBUI. + +Usage: + mpeg2decode -b file.mpeg + +=============================================================== + + +January 9, 1995: +===== +Pre-release caveats: + + - has only been tested with gcc. (I'm not sure we will even bother + with acc, or cc in the future). + + - I'm fully aware of the warnings received by -Wall + + - Verifier still not integrated (due to complexity), although + experimental vbv_delay code included in verify.c + + + +December 20, 1995 +=============================================================== +Frame buffer substitution edition of decoder. + +Restrictions: + - temporal_reference in bitstream must be correct. + + - substitute pictures must have pixel (luminance samples) width + and height equal to coded_picture_width (mb_width*16) and + coded_picture_height (mb_height*16) rather than horizontal_size + and vertical_size, respectively. + + - all input pictures must be interleaved into a frame. + + - frame count (index) is based on absolute display frame order with + no repeated (3:2 pulldown) fields or frames. + +-------------------------------------------------------- +Notes: + + - command line arguements in this edition differ from verifier + style. This decoder's arguments are the same as the + public distribution's (July 4, 1994) code . + + please note that this code, with frame buffer substitution, when it + is released will use the verifier style of arguments. + + - Carsten's updated spatial scalability decoder routines have been + incorperated. + diff --git a/libfbui/MPEG/README2 b/libfbui/MPEG/README2 @@ -0,0 +1,4 @@ + +I have removed the sample MPEG that I was including with this, +since it was overly large. + diff --git a/libfbui/MPEG/SPATIAL.DOC b/libfbui/MPEG/SPATIAL.DOC @@ -0,0 +1,154 @@ +The following changes have been made to debug spatial scalability: + +gethdr.c +-------- + +Temporal_reference is used to compute the frame number of each frame, +named true_framenum. The periodic reset at each GOP header as well as +the wrap of temporal_reference at 1024 cause a base value +temp_ref_base to be incremented accordingly. + +spatscal.c +---------- + +getspatref() + +A potential problem: Variable char fname[32] was dimensioned +statically and too small. + +true_framenum is used instead of lower_layer_temporal_reference to +determine the lower layer frame to be read for spatial prediction. + +The verification of lower_layer_temporal_reference is not possible +since the temporal reference values that have been encoded into the +base layer bitstream are not available to the enhancement layer +decoder. + +Since there is no decoder timing information available, the rules on +which frames can legally be used as spatial prediction frames cannot +be checked. + +Lower layer frames are read field-wise or frame-wise, depending on the +lower_layer_progressive_frame flag. Consistency between layers is +checked since the file format for frame and field pictures differs. + +Note that the base layer decoder must not use the -f option to enforce +frame-wise storage. + +Note further that only yuv image format (option -o0) is supported as +input format. + +spatpred() + +The code for the various combinations of llprog_frame, llfieldsel and +prog_frame has been completed and verified with the tceh_conf23 +bitstream that uses all permissive combinations. + + +getpic.c +-------- + +A small bug when storing an I- or P-frame: The prog_frame flag that +the decoder knows when storing the oldrefframe belongs to the current +refframe. Therefore the old value of the flag needs to be memorized. + + +store.c +------- + +A potential problem: the filename variables char outname[32], +tmpname[32] are statically dimensioned and quite small. + + +The concept of time in this video decoder software +-------------------------------------------------- + +When decoding a non-scalable bitstream, the frame number (i.e. +temporal position) of the current I- or P-frame can be derived +implicitly from the number of preceding B-frames after they have been +decoded. Therefore the temporal_reference entry in the picture header +is somewhat redundant and does not necessarily have to be evaluated in +the decoding process. + +Decoding of the enhancement layer of a spatial scalable hierarchy, +however, requires to know the temporal position of each frame at the +instant when it is decoded, since data from a lower layer reference +frame has to be incorporated. + +In the architecture of this video-only decoder decoding of a spatial +scalable hierarchy of bitstreams is done by calling mpeg2decode once +for the base layer bitstream and a second time for the enhancement +layer bitstream, indicating where the decoded base layer frames can be +found (option -s<filename>). + +Here the concept of time is only present in the form of frame numbers. +Therefore spatial scalable bitstream hierarchies can only be handled +under the assumption that base and enhancement layer bitstreams are +decoded to image sequences where corresponding images of both layers +have identical frame numbers. + +More specifically this means that base and enhancement layer +bitstreams must contain video with the same frame rate. Furthermore +only the temporally coincident frame of the base layer can be accessed +for spatial prediction by the enhancement layer decoder, since it is +not possible to resolve unambiguously the lower_layer_temporal_reference +which is meant to further specify the lower layer reference frame. + +======================== SPATIAL.DOC ========================0 + +Decoding a spatial scalable hierarchy of bitstreams +--------------------------------------------------- + +With this video-only decoder decoding of a spatial scalable hierarchy +of bitstreams is done by calling mpeg2decode once for the base layer +bitstream and a second time for the enhancement layer bitstream, +indicating where the decoded base layer frames can be found +(using option -s and supplying <spatial base filename>). + +mpeg2decode -r -o0 base.mpg base%d%c +mpeg2decode -r -o0 -f -s base%d%c enh.mpg enh%d + +Note that the base layer decoder must not use the -f option to enforce +frame-wise storage. + +Note further that only yuv image format (option -o0) is supported as +input format. + + +Timing / layer synchronisation in this video decoder software +------------------------------------------------------------- + +When decoding a non-scalable bitstream, the frame number (i.e. +temporal position) of the current I- or P-frame can be derived +implicitly from the number of preceding B-frames after they have been +decoded. Therefore the temporal_reference entry in the picture header +is somewhat redundant and does not necessarily have to be evaluated in +the decoding process. + +Decoding of the enhancement layer of a spatial scalable hierarchy, +however, requires to know the temporal position of each frame at the +instant when it is decoded, since data from a lower layer reference +frame has to be incorporated. + +The concept of time is only present in the form of frame numbers. +Therefore spatial scalable bitstream hierarchies can only be handled +under the assumption that base and enhancement layer bitstreams are +decoded to image sequences where corresponding images of both layers +have identical frame numbers. + +More specifically this means that base and enhancement layer +bitstreams must contain video with the same frame rate. Furthermore +only the temporally coincident frame of the base layer can be accessed +for spatial prediction by the enhancement layer decoder, since it is +not possible to resolve unambiguously the lower_layer_temporal_reference +which is meant to further specify the lower layer reference frame. + +Lower layer frames are read field-wise or frame-wise, depending on the +lower_layer_progressive_frame flag. Consistency between layers in this +respect is checked since the file format for frame and field pictures +differs. + + + + + diff --git a/libfbui/MPEG/TODO b/libfbui/MPEG/TODO @@ -0,0 +1,73 @@ + 1. Test bitstream + Small example bitstream (128x128 pixel dimensions) which employs all + picture_structure (top field, bottom field, frame), picture_coding_type + (I, P, and B), macroblock_type (forwards/backwards/interpolated, + intra/non-intra, coded/not-coded, quant/no quant, etc.), and + motion_type (field, frame, 16X8, dual prime) modes. + + 2. add trace printing for mpeg1 getblk routines. + + 3. modify getsys.c to parse program layer bitstreams (Systems) + with variable-length packets. + + 4. 24 bit X11 display + (borrow from Berkeley or find way for our code to use their interface) + + 5. MPEG-2 Transport layer systems streams parsing + + 6. Document IPR issue + + provide CableLabs URL + how IPR relates to our disclaimer. + + 7. TIFF library support (YCbCr 4:4:4, 4:2:2, and 4:2:0 pictures) +[deferred] + +10. IDCT rounding + As per IDCT corridgendum (Savatier, MPEG 95/XXX) + [done, but verified ?] + + +12. green dots in can + [ appears to be a display issue, probably related to convmat[] + error ] + +19. move Dual_Prime calculation into picture_data() + +20. motion vector calculation to include tappable stages to test + whether elements fall within [low:high] range. + +21. Integrate verifier routines + +22. Inter-layer verification routines + - check base and enhancement layers (e.g. SNR) + +23. Spatial verification + - considering that no base layer is available. + +24. SNR verification + [ done ] + +25. DP verification + [ not done. No longer any bitstreams with Data Partitioning distributed + since DP is not part of any official Profile ] + +26. merge all global bitsteam element variables into + common data structure (similar to layer_data). This is needed + for the verifier (whether or not headers in SNR and DP streams + are identical where needed to that of the base layer). + +27. investigate why MS-DOS wants an extra % sign for filename patterns + when more than one filename pattern is used in the command line argument + +28. convert -t (trace) flag into levels, merge with Verbose. + +29. seek to a specified frame number (support for MCI-like functions) + +30. document the "flash" VLC table decoding method in detail. + (namely how to map tables in Annex B to those in getvlc.h) + +31. MPEG-2 program stream compatibility + (a few minor bits of difference in the system header ). + +-------- diff --git a/libfbui/MPEG/config.h b/libfbui/MPEG/config.h @@ -0,0 +1,44 @@ +/* config.h, configuration defines */ + +/* Copyright (C) 1996, MPEG Software Simulation Group. All Rights Reserved. */ + +/* + * Disclaimer of Warranty + * + * These software programs are available to the user without any license fee or + * royalty on an "as is" basis. The MPEG Software Simulation Group disclaims + * any and all warranties, whether express, implied, or statuary, including any + * implied warranties or merchantability or of fitness for a particular + * purpose. In no event shall the copyright-holder be liable for any + * incidental, punitive, or consequential damages of any kind whatsoever + * arising from the use of these programs. + * + * This disclaimer of warranty extends to the user of these programs and user's + * customers, employees, agents, transferees, successors, and assigns. + * + * The MPEG Software Simulation Group does not represent or warrant that the + * programs furnished hereunder are free of infringement of any third-party + * patents. + * + * Commercial implementations of MPEG-1 and MPEG-2 video, including shareware, + * are subject to royalty fees to patent holders. Many of these patents are + * general enough such that they are unavoidable regardless of implementation + * design. + * + */ + +/* define NON_ANSI_COMPILER for compilers without function prototyping */ +/* #define NON_ANSI_COMPILER */ + +#ifdef NON_ANSI_COMPILER +#define _ANSI_ARGS_(x) () +#else +#define _ANSI_ARGS_(x) x +#endif + +#define RB "rb" +#define WB "wb" + +#ifndef O_BINARY +#define O_BINARY 0 +#endif diff --git a/libfbui/MPEG/display.c b/libfbui/MPEG/display.c @@ -0,0 +1,1218 @@ +/* display.c, X11 interface */ + +/* Copyright (C) 1996, MPEG Software Simulation Group. All Rights Reserved. */ + +/* + * Disclaimer of Warranty + * + * These software programs are available to the user without any license fee or + * royalty on an "as is" basis. The MPEG Software Simulation Group disclaims + * any and all warranties, whether express, implied, or statuary, including any + * implied warranties or merchantability or of fitness for a particular + * purpose. In no event shall the copyright-holder be liable for any + * incidental, punitive, or consequential damages of any kind whatsoever + * arising from the use of these programs. + * + * This disclaimer of warranty extends to the user of these programs and user's + * customers, employees, agents, transferees, successors, and assigns. + * + * The MPEG Software Simulation Group does not represent or warrant that the + * programs furnished hereunder are free of infringement of any third-party + * patents. + * + * Commercial implementations of MPEG-1 and MPEG-2 video, including shareware, + * are subject to royalty fees to patent holders. Many of these patents are + * general enough such that they are unavoidable regardless of implementation + * design. + * + */ + +#ifdef DISPLAY + + /* the Xlib interface is closely modeled after + * mpeg_play 2.0 by the Berkeley Plateau Research Group + */ + +#include <stdio.h> +#include <stdlib.h> + +#include <X11/Xlib.h> +#include <X11/Xutil.h> + +#include "config.h" +#include "global.h" + +/* private prototypes */ +static void Display_Image _ANSI_ARGS_((XImage *Ximage_Ptr, unsigned char *Dithered_Image)); +static void Dither_Frame _ANSI_ARGS_((unsigned char *src[])); +static void Dither_Top_Field _ANSI_ARGS_((unsigned char *src[], unsigned char *dst)); +static void Dither_Bottom_Field _ANSI_ARGS_((unsigned char *src[], unsigned char *dst)); +static void Dither_Top_Field420 _ANSI_ARGS_((unsigned char *src[], + unsigned char *dst)); +static void Dither_Bottom_Field420 _ANSI_ARGS_((unsigned char *src[], + unsigned char *dst)); + +/* local data */ +static unsigned char *Dithered_Image, *Dithered_Image2; + +static unsigned char Y_Table[256+16]; +static unsigned char Cb_Table[128+16]; +static unsigned char Cr_Table[128+16]; + +/* X11 related variables */ +static Display *Display_Ptr; +static Window Window_Instance; +static GC GC_Instance; +static XImage *Ximage_Ptr, *Ximage_Ptr2; +static unsigned char Pixel[256]; + +#ifdef SH_MEM + +#include <sys/ipc.h> +#include <sys/shm.h> +#include <X11/extensions/XShm.h> + +static int HandleXError _ANSI_ARGS_((Display *dpy, XErrorEvent *event)); +static void InstallXErrorHandler _ANSI_ARGS_((void)); +static void DeInstallXErrorHandler _ANSI_ARGS_((void)); + +static int Shmem_Flag; +static XShmSegmentInfo Shminfo1, Shminfo2; +static int gXErrorFlag; +static int CompletionType = -1; + +static int HandleXError(Dpy, Event) +Display *Dpy; +XErrorEvent *Event; +{ + gXErrorFlag = 1; + + return 0; +} + +static void InstallXErrorHandler() +{ + XSetErrorHandler(HandleXError); + XFlush(Display_Ptr); +} + +static void DeInstallXErrorHandler() +{ + XSetErrorHandler(NULL); + XFlush(Display_Ptr); +} + +#endif + +/* connect to server, create and map window, + * allocate colors and (shared) memory + */ +void Initialize_Display_Process(name) +char *name; +{ + int crv, cbu, cgu, cgv; + int Y, Cb, Cr, R, G, B; + int i; + char dummy; + int screen; + Colormap cmap; + int private; + XColor xcolor; + unsigned int fg, bg; + char *hello = "MPEG-2 Display"; + XSizeHints hint; + XVisualInfo vinfo; + XEvent xev; + unsigned long tmp_pixel; + XWindowAttributes xwa; + + Display_Ptr = XOpenDisplay(name); + + if (Display_Ptr == NULL) + Error("Can not open display\n"); + + screen = DefaultScreen(Display_Ptr); + + hint.x = 200; + hint.y = 200; + hint.width = horizontal_size; + hint.height = vertical_size; + hint.flags = PPosition | PSize; + + /* Get some colors */ + + bg = WhitePixel (Display_Ptr, screen); + fg = BlackPixel (Display_Ptr, screen); + + /* Make the window */ + + if (!XMatchVisualInfo(Display_Ptr, screen, 8, PseudoColor, &vinfo)) + { + if (!XMatchVisualInfo(Display_Ptr, screen, 8, GrayScale, &vinfo)) + Error("requires 8 bit display\n"); + } + + Window_Instance = XCreateSimpleWindow (Display_Ptr, DefaultRootWindow (Display_Ptr), + hint.x, hint.y, hint.width, hint.height, 4, fg, bg); + + XSelectInput(Display_Ptr, Window_Instance, StructureNotifyMask); + + /* Tell other applications about this window */ + + XSetStandardProperties (Display_Ptr, Window_Instance, hello, hello, None, NULL, 0, &hint); + + /* Map window. */ + + XMapWindow(Display_Ptr, Window_Instance); + + /* Wait for map. */ + do + { + XNextEvent(Display_Ptr, &xev); + } + while (xev.type != MapNotify || xev.xmap.event != Window_Instance); + + XSelectInput(Display_Ptr, Window_Instance, NoEventMask); + + /* matrix coefficients */ + crv = Inverse_Table_6_9[matrix_coefficients][0]; + cbu = Inverse_Table_6_9[matrix_coefficients][1]; + cgu = Inverse_Table_6_9[matrix_coefficients][2]; + cgv = Inverse_Table_6_9[matrix_coefficients][3]; + + /* allocate colors */ + + GC_Instance = DefaultGC(Display_Ptr, screen); + cmap = DefaultColormap(Display_Ptr, screen); + private = 0; + + /* color allocation: + * i is the (internal) 8 bit color number, it consists of separate + * bit fields for Y, U and V: i = (yyyyuuvv), we don't use yyyy=0000 + * and yyyy=1111, this leaves 32 colors for other applications + * + * the allocated colors correspond to the following Y, U and V values: + * Y: 24, 40, 56, 72, 88, 104, 120, 136, 152, 168, 184, 200, 216, 232 + * U,V: -48, -16, 16, 48 + * + * U and V values span only about half the color space; this gives + * usually much better quality, although highly saturated colors can + * not be displayed properly + * + * translation to R,G,B is implicitly done by the color look-up table + */ + for (i=16; i<240; i++) + { + /* color space conversion */ + Y = 16*((i>>4)&15) + 8; + Cb = 32*((i>>2)&3) - 48; + Cr = 32*(i&3) - 48; + + Y = 76309 * (Y - 16); /* (255/219)*65536 */ + + R = Clip[(Y + crv*Cr + 32768)>>16]; + G = Clip[(Y - cgu*Cb - cgv*Cr + 32768)>>16]; + B = Clip[(Y + cbu*Cb + 32786)>>16]; + + /* X11 colors are 16 bit */ + xcolor.red = R << 8; + xcolor.green = G << 8; + xcolor.blue = B << 8; + + if (XAllocColor(Display_Ptr, cmap, &xcolor) != 0) + Pixel[i] = xcolor.pixel; + else + { + /* allocation failed, have to use a private colormap */ + + if (private) + Error("Couldn't allocate private colormap"); + + private = 1; + + if (!Quiet_Flag) + fprintf(stderr, "Using private colormap (%d colors were available).\n", + i-16); + + /* Free colors. */ + while (--i >= 16) + { + tmp_pixel = Pixel[i]; /* because XFreeColors expects unsigned long */ + XFreeColors(Display_Ptr, cmap, &tmp_pixel, 1, 0); + } + + /* i is now 15, this restarts the outer loop */ + + /* create private colormap */ + + XGetWindowAttributes(Display_Ptr, Window_Instance, &xwa); + cmap = XCreateColormap(Display_Ptr, Window_Instance, xwa.visual, AllocNone); + XSetWindowColormap(Display_Ptr, Window_Instance, cmap); + } + } + +#ifdef SH_MEM + if (XShmQueryExtension(Display_Ptr)) + Shmem_Flag = 1; + else + { + Shmem_Flag = 0; + if (!Quiet_Flag) + fprintf(stderr, "Shared memory not supported\nReverting to normal Xlib\n"); + } + + if (Shmem_Flag) + CompletionType = XShmGetEventBase(Display_Ptr) + ShmCompletion; + + InstallXErrorHandler(); + + if (Shmem_Flag) + { + + Ximage_Ptr = XShmCreateImage(Display_Ptr, None, 8, ZPixmap, NULL, + &Shminfo1, + Coded_Picture_Width, Coded_Picture_Height); + + if (!progressive_sequence) + Ximage_Ptr2 = XShmCreateImage(Display_Ptr, None, 8, ZPixmap, NULL, + &Shminfo2, + Coded_Picture_Width, Coded_Picture_Height); + + /* If no go, then revert to normal Xlib calls. */ + + if (Ximage_Ptr==NULL || (!progressive_sequence && Ximage_Ptr2==NULL)) + { + if (Ximage_Ptr!=NULL) + XDestroyImage(Ximage_Ptr); + if (!progressive_sequence && Ximage_Ptr2!=NULL) + XDestroyImage(Ximage_Ptr2); + if (!Quiet_Flag) + fprintf(stderr, "Shared memory error, disabling (Ximage error)\n"); + goto shmemerror; + } + + /* Success here, continue. */ + + Shminfo1.shmid = shmget(IPC_PRIVATE, + Ximage_Ptr->bytes_per_line * Ximage_Ptr->height, + IPC_CREAT | 0777); + if (!progressive_sequence) + Shminfo2.shmid = shmget(IPC_PRIVATE, + Ximage_Ptr2->bytes_per_line * Ximage_Ptr2->height, + IPC_CREAT | 0777); + + if (Shminfo1.shmid<0 || (!progressive_sequence && Shminfo2.shmid<0)) + { + XDestroyImage(Ximage_Ptr); + if (!progressive_sequence) + XDestroyImage(Ximage_Ptr2); + if (!Quiet_Flag) + fprintf(stderr, "Shared memory error, disabling (seg id error)\n"); + goto shmemerror; + } + + Shminfo1.shmaddr = (char *) shmat(Shminfo1.shmid, 0, 0); + Shminfo2.shmaddr = (char *) shmat(Shminfo2.shmid, 0, 0); + + if (Shminfo1.shmaddr==((char *) -1) || + (!progressive_sequence && Shminfo2.shmaddr==((char *) -1))) + { + XDestroyImage(Ximage_Ptr); + if (Shminfo1.shmaddr!=((char *) -1)) + shmdt(Shminfo1.shmaddr); + if (!progressive_sequence) + { + XDestroyImage(Ximage_Ptr2); + if (Shminfo2.shmaddr!=((char *) -1)) + shmdt(Shminfo2.shmaddr); + } + if (!Quiet_Flag) + { + fprintf(stderr, "Shared memory error, disabling (address error)\n"); + } + goto shmemerror; + } + + Ximage_Ptr->data = Shminfo1.shmaddr; + Dithered_Image = (unsigned char *)Ximage_Ptr->data; + Shminfo1.readOnly = False; + XShmAttach(Display_Ptr, &Shminfo1); + if (!progressive_sequence) + { + Ximage_Ptr2->data = Shminfo2.shmaddr; + Dithered_Image2 = (unsigned char *)Ximage_Ptr2->data; + Shminfo2.readOnly = False; + XShmAttach(Display_Ptr, &Shminfo2); + } + + XSync(Display_Ptr, False); + + if (gXErrorFlag) + { + /* Ultimate failure here. */ + XDestroyImage(Ximage_Ptr); + shmdt(Shminfo1.shmaddr); + if (!progressive_sequence) + { + XDestroyImage(Ximage_Ptr2); + shmdt(Shminfo2.shmaddr); + } + if (!Quiet_Flag) + fprintf(stderr, "Shared memory error, disabling.\n"); + gXErrorFlag = 0; + goto shmemerror; + } + else + { + shmctl(Shminfo1.shmid, IPC_RMID, 0); + if (!progressive_sequence) + shmctl(Shminfo2.shmid, IPC_RMID, 0); + } + + if (!Quiet_Flag) + { + fprintf(stderr, "Sharing memory.\n"); + } + } + else + { +shmemerror: + Shmem_Flag = 0; +#endif + + Ximage_Ptr = XCreateImage(Display_Ptr,None,8,ZPixmap,0,&dummy, + Coded_Picture_Width,Coded_Picture_Height,8,0); + + if (!(Dithered_Image = (unsigned char *)malloc(Coded_Picture_Width* + Coded_Picture_Height))) + Error("malloc failed"); + + if (!progressive_sequence) + { + Ximage_Ptr2 = XCreateImage(Display_Ptr,None,8,ZPixmap,0,&dummy, + Coded_Picture_Width,Coded_Picture_Height,8,0); + + if (!(Dithered_Image2 = (unsigned char *)malloc(Coded_Picture_Width* + Coded_Picture_Height))) + Error("malloc failed"); + } + +#ifdef SH_MEM + } + + DeInstallXErrorHandler(); +#endif +} + +void Terminate_Display_Process() +{ +#ifdef SH_MEM + if (Shmem_Flag) + { + XShmDetach(Display_Ptr, &Shminfo1); + XDestroyImage(Ximage_Ptr); + shmdt(Shminfo1.shmaddr); + if (!progressive_sequence) + { + XShmDetach(Display_Ptr, &Shminfo2); + XDestroyImage(Ximage_Ptr2); + shmdt(Shminfo2.shmaddr); + } + } +#endif +} + +static void Display_Image(Ximage_Ptr,Dithered_Image) +XImage *Ximage_Ptr; +unsigned char *Dithered_Image; +{ + /* display dithered image */ +#ifdef SH_MEM + if (Shmem_Flag) + { + XShmPutImage(Display_Ptr, Window_Instance, GC_Instance, Ximage_Ptr, + 0, 0, 0, 0, Ximage_Ptr->width, Ximage_Ptr->height, True); + XFlush(Display_Ptr); + + while (1) + { + XEvent xev; + + XNextEvent(Display_Ptr, &xev); + if (xev.type == CompletionType) + break; + } + } + else +#endif + { + Ximage_Ptr->data = (char *) Dithered_Image; + XPutImage(Display_Ptr, Window_Instance, GC_Instance, Ximage_Ptr, 0, 0, 0, 0, Ximage_Ptr->width, Ximage_Ptr->height); + } +} + +void Display_Second_Field() +{ + Display_Image(Ximage_Ptr2,Dithered_Image2); +} + +/* 4x4 ordered dither + * + * threshold pattern: + * 0 8 2 10 + * 12 4 14 6 + * 3 11 1 9 + * 15 7 13 5 + */ + +void Initialize_Dither_Matrix() +{ + int i, v; + + for (i=-8; i<256+8; i++) + { + v = i>>4; + if (v<1) + v = 1; + else if (v>14) + v = 14; + Y_Table[i+8] = v<<4; + } + + for (i=0; i<128+16; i++) + { + v = (i-40)>>4; + if (v<0) + v = 0; + else if (v>3) + v = 3; + Cb_Table[i] = v<<2; + Cr_Table[i] = v; + } +} + +void dither(src) +unsigned char *src[]; +{ + /* should this test only the display flag, not progressive_sequence ? --CF */ + /* CHANGE 95/05/13: progressive_sequence -> progressive_frame */ + + if( progressive_frame || Display_Progressive_Flag) + Dither_Frame(src); + else + { + if ((picture_structure==FRAME_PICTURE && top_field_first) || picture_structure==BOTTOM_FIELD) + { + /* top field first */ + if (chroma_format==CHROMA420 && hiQdither) + { + Dither_Top_Field420(src,Dithered_Image); + Dither_Bottom_Field420(src,Dithered_Image2); + } + else + { + Dither_Top_Field(src,Dithered_Image); + Dither_Bottom_Field(src,Dithered_Image2); + } + } + else + { + /* bottom field first */ + if (chroma_format==CHROMA420 && hiQdither) + { + Dither_Bottom_Field420(src,Dithered_Image); + Dither_Top_Field420(src,Dithered_Image2); + } + else + { + Dither_Bottom_Field(src,Dithered_Image); + Dither_Top_Field(src,Dithered_Image2); + } + } + } + + Display_Image(Ximage_Ptr,Dithered_Image); +} + +static void Dither_Frame(src) +unsigned char *src[]; +{ + int i,j; + int y,u,v; + unsigned char *py,*pu,*pv,*dst; + + py = src[0]; + pu = src[1]; + pv = src[2]; + dst = Dithered_Image; + + for (j=0; j<Coded_Picture_Height; j+=4) + { + /* line j + 0 */ + for (i=0; i<Coded_Picture_Width; i+=4) + { + y = *py++; + u = *pu++ >> 1; + v = *pv++ >> 1; + *dst++ = Pixel[Y_Table[y]|Cb_Table[u]|Cr_Table[v]]; + y = *py++; + if (chroma_format==CHROMA444) + { + u = *pu++ >> 1; + v = *pv++ >> 1; + } + *dst++ = Pixel[Y_Table[y+8]|Cb_Table[u+8]|Cr_Table[v+8]]; + y = *py++; + u = *pu++ >> 1; + v = *pv++ >> 1; + *dst++ = Pixel[Y_Table[y+2]|Cb_Table[u+2]|Cr_Table[v+2]]; + y = *py++; + if (chroma_format==CHROMA444) + { + u = *pu++ >> 1; + v = *pv++ >> 1; + } + *dst++ = Pixel[Y_Table[y+10]|Cb_Table[u+10]|Cr_Table[v+10]]; + } + + if (chroma_format==CHROMA420) + { + pu -= Chroma_Width; + pv -= Chroma_Width; + } + + /* line j + 1 */ + for (i=0; i<Coded_Picture_Width; i+=4) + { + y = *py++; + u = *pu++ >> 1; + v = *pv++ >> 1; + *dst++ = Pixel[Y_Table[y+12]|Cb_Table[u+12]|Cr_Table[v+12]]; + y = *py++; + if (chroma_format==CHROMA444) + { + u = *pu++ >> 1; + v = *pv++ >> 1; + } + *dst++ = Pixel[Y_Table[y+4]|Cb_Table[u+4]|Cr_Table[v+4]]; + y = *py++; + u = *pu++ >> 1; + v = *pv++ >> 1; + *dst++ = Pixel[Y_Table[y+14]|Cb_Table[u+14]|Cr_Table[v+14]]; + y = *py++; + if (chroma_format==CHROMA444) + { + u = *pu++ >> 1; + v = *pv++ >> 1; + } + *dst++ = Pixel[Y_Table[y+6]|Cb_Table[u+6]|Cr_Table[v+6]]; + } + + /* line j + 2 */ + for (i=0; i<Coded_Picture_Width; i+=4) + { + y = *py++; + u = *pu++ >> 1; + v = *pv++ >> 1; + *dst++ = Pixel[Y_Table[y+3]|Cb_Table[u+3]|Cr_Table[v+3]]; + y = *py++; + if (chroma_format==CHROMA444) + { + u = *pu++ >> 1; + v = *pv++ >> 1; + } + *dst++ = Pixel[Y_Table[y+11]|Cb_Table[u+11]|Cr_Table[v+11]]; + y = *py++; + u = *pu++ >> 1; + v = *pv++ >> 1; + *dst++ = Pixel[Y_Table[y+1]|Cb_Table[u+1]|Cr_Table[v+1]]; + y = *py++; + if (chroma_format==CHROMA444) + { + u = *pu++ >> 1; + v = *pv++ >> 1; + } + *dst++ = Pixel[Y_Table[y+9]|Cb_Table[u+9]|Cr_Table[v+9]]; + } + + if (chroma_format==CHROMA420) + { + pu -= Chroma_Width; + pv -= Chroma_Width; + } + + /* line j + 3 */ + for (i=0; i<Coded_Picture_Width; i+=4) + { + y = *py++; + u = *pu++ >> 1; + v = *pv++ >> 1; + *dst++ = Pixel[Y_Table[y+15]|Cb_Table[u+15]|Cr_Table[v+15]]; + y = *py++; + if (chroma_format==CHROMA444) + { + u = *pu++ >> 1; + v = *pv++ >> 1; + } + *dst++ = Pixel[Y_Table[y+7]|Cb_Table[u+7]|Cr_Table[v+7]]; + y = *py++; + u = *pu++ >> 1; + v = *pv++ >> 1; + *dst++ = Pixel[Y_Table[y+13]|Cb_Table[u+13]|Cr_Table[v+13]]; + y = *py++; + if (chroma_format==CHROMA444) + { + u = *pu++ >> 1; + v = *pv++ >> 1; + } + *dst++ = Pixel[Y_Table[y+5]|Cb_Table[u+5]|Cr_Table[v+5]]; + } + } + +} + +static void Dither_Top_Field(src,dst) +unsigned char *src[]; +unsigned char *dst; +{ + int i,j; + int y,Y2,u,v; + unsigned char *py,*Y2_ptr,*pu,*pv,*dst2; + + py = src[0]; + Y2_ptr = src[0] + (Coded_Picture_Width<<1); + pu = src[1]; + pv = src[2]; + dst2 = dst + Coded_Picture_Width; + + for (j=0; j<Coded_Picture_Height; j+=4) + { + /* line j + 0, j + 1 */ + for (i=0; i<Coded_Picture_Width; i+=4) + { + y = *py++; + Y2 = *Y2_ptr++; + u = *pu++ >> 1; + v = *pv++ >> 1; + *dst++ = Pixel[Y_Table[y]|Cb_Table[u]|Cr_Table[v]]; + *dst2++ = Pixel[Y_Table[((y+Y2)>>1)+12]|Cb_Table[u+12]|Cr_Table[v+12]]; + + y = *py++; + Y2 = *Y2_ptr++; + if (chroma_format==CHROMA444) + { + u = *pu++ >> 1; + v = *pv++ >> 1; + } + *dst++ = Pixel[Y_Table[y+8]|Cb_Table[u+8]|Cr_Table[v+8]]; + *dst2++ = Pixel[Y_Table[((y+Y2)>>1)+4]|Cb_Table[u+4]|Cr_Table[v+4]]; + + y = *py++; + Y2 = *Y2_ptr++; + u = *pu++ >> 1; + v = *pv++ >> 1; + *dst++ = Pixel[Y_Table[y+2]|Cb_Table[u+2]|Cr_Table[v+2]]; + *dst2++ = Pixel[Y_Table[((y+Y2)>>1)+14]|Cb_Table[u+14]|Cr_Table[v+14]]; + + y = *py++; + Y2 = *Y2_ptr++; + if (chroma_format==CHROMA444) + { + u = *pu++ >> 1; + v = *pv++ >> 1; + } + *dst++ = Pixel[Y_Table[y+10]|Cb_Table[u+10]|Cr_Table[v+10]]; + *dst2++ = Pixel[Y_Table[((y+Y2)>>1)+6]|Cb_Table[u+6]|Cr_Table[v+6]]; + } + + py += Coded_Picture_Width; + + if (j!=(Coded_Picture_Height-4)) + Y2_ptr += Coded_Picture_Width; + else + Y2_ptr -= Coded_Picture_Width; + + dst += Coded_Picture_Width; + dst2 += Coded_Picture_Width; + + if (chroma_format==CHROMA420) + { + pu -= Chroma_Width; + pv -= Chroma_Width; + } + else + { + pu += Chroma_Width; + pv += Chroma_Width; + } + + /* line j + 2, j + 3 */ + for (i=0; i<Coded_Picture_Width; i+=4) + { + y = *py++; + Y2 = *Y2_ptr++; + u = *pu++ >> 1; + v = *pv++ >> 1; + *dst++ = Pixel[Y_Table[y+3]|Cb_Table[u+3]|Cr_Table[v+3]]; + *dst2++ = Pixel[Y_Table[((y+Y2)>>1)+15]|Cb_Table[u+15]|Cr_Table[v+15]]; + + y = *py++; + Y2 = *Y2_ptr++; + if (chroma_format==CHROMA444) + { + u = *pu++ >> 1; + v = *pv++ >> 1; + } + *dst++ = Pixel[Y_Table[y+11]|Cb_Table[u+11]|Cr_Table[v+11]]; + *dst2++ = Pixel[Y_Table[((y+Y2)>>1)+7]|Cb_Table[u+7]|Cr_Table[v+7]]; + + y = *py++; + Y2 = *Y2_ptr++; + u = *pu++ >> 1; + v = *pv++ >> 1; + *dst++ = Pixel[Y_Table[y+1]|Cb_Table[u+1]|Cr_Table[v+1]]; + *dst2++ = Pixel[Y_Table[((y+Y2)>>1)+13]|Cb_Table[u+13]|Cr_Table[v+13]]; + + y = *py++; + Y2 = *Y2_ptr++; + if (chroma_format==CHROMA444) + { + u = *pu++ >> 1; + v = *pv++ >> 1; + } + *dst++ = Pixel[Y_Table[y+9]|Cb_Table[u+9]|Cr_Table[v+9]]; + *dst2++ = Pixel[Y_Table[((y+Y2)>>1)+5]|Cb_Table[u+5]|Cr_Table[v+5]]; + } + + py += Coded_Picture_Width; + Y2_ptr += Coded_Picture_Width; + dst += Coded_Picture_Width; + dst2 += Coded_Picture_Width; + pu += Chroma_Width; + pv += Chroma_Width; + } +} + +static void Dither_Bottom_Field(src,dst) +unsigned char *src[]; +unsigned char *dst; +{ + int i,j; + int y,Y2,u,v; + unsigned char *py,*Y2_ptr,*pu,*pv,*dst2; + + py = src[0] + Coded_Picture_Width; + Y2_ptr = py; + pu = src[1] + Chroma_Width; + pv = src[2] + Chroma_Width; + dst2 = dst + Coded_Picture_Width; + + for (j=0; j<Coded_Picture_Height; j+=4) + { + /* line j + 0, j + 1 */ + for (i=0; i<Coded_Picture_Width; i+=4) + { + y = *py++; + Y2 = *Y2_ptr++; + u = *pu++ >> 1; + v = *pv++ >> 1; + *dst++ = Pixel[Y_Table[((y+Y2)>>1)]|Cb_Table[u]|Cr_Table[v]]; + *dst2++ = Pixel[Y_Table[Y2+12]|Cb_Table[u+12]|Cr_Table[v+12]]; + + y = *py++; + Y2 = *Y2_ptr++; + if (chroma_format==CHROMA444) + { + u = *pu++ >> 1; + v = *pv++ >> 1; + } + *dst++ = Pixel[Y_Table[((y+Y2)>>1)+8]|Cb_Table[u+8]|Cr_Table[v+8]]; + *dst2++ = Pixel[Y_Table[Y2+4]|Cb_Table[u+4]|Cr_Table[v+4]]; + + y = *py++; + Y2 = *Y2_ptr++; + u = *pu++ >> 1; + v = *pv++ >> 1; + *dst++ = Pixel[Y_Table[((y+Y2)>>1)+2]|Cb_Table[u+2]|Cr_Table[v+2]]; + *dst2++ = Pixel[Y_Table[Y2+14]|Cb_Table[u+14]|Cr_Table[v+14]]; + + y = *py++; + Y2 = *Y2_ptr++; + if (chroma_format==CHROMA444) + { + u = *pu++ >> 1; + v = *pv++ >> 1; + } + *dst++ = Pixel[Y_Table[((y+Y2)>>1)+10]|Cb_Table[u+10]|Cr_Table[v+10]]; + *dst2++ = Pixel[Y_Table[Y2+6]|Cb_Table[u+6]|Cr_Table[v+6]]; + } + + if (j==0) + py -= Coded_Picture_Width; + else + py += Coded_Picture_Width; + + Y2_ptr += Coded_Picture_Width; + dst += Coded_Picture_Width; + dst2 += Coded_Picture_Width; + + if (chroma_format==CHROMA420) + { + pu -= Chroma_Width; + pv -= Chroma_Width; + } + else + { + pu += Chroma_Width; + pv += Chroma_Width; + } + + /* line j + 2. j + 3 */ + for (i=0; i<Coded_Picture_Width; i+=4) + { + y = *py++; + Y2 = *Y2_ptr++; + u = *pu++ >> 1; + v = *pv++ >> 1; + *dst++ = Pixel[Y_Table[((y+Y2)>>1)+3]|Cb_Table[u+3]|Cr_Table[v+3]]; + *dst2++ = Pixel[Y_Table[Y2+15]|Cb_Table[u+15]|Cr_Table[v+15]]; + + y = *py++; + Y2 = *Y2_ptr++; + if (chroma_format==CHROMA444) + { + u = *pu++ >> 1; + v = *pv++ >> 1; + } + *dst++ = Pixel[Y_Table[((y+Y2)>>1)+11]|Cb_Table[u+11]|Cr_Table[v+11]]; + *dst2++ = Pixel[Y_Table[Y2+7]|Cb_Table[u+7]|Cr_Table[v+7]]; + + y = *py++; + Y2 = *Y2_ptr++; + u = *pu++ >> 1; + v = *pv++ >> 1; + *dst++ = Pixel[Y_Table[((y+Y2)>>1)+1]|Cb_Table[u+1]|Cr_Table[v+1]]; + *dst2++ = Pixel[Y_Table[Y2+13]|Cb_Table[u+13]|Cr_Table[v+13]]; + + y = *py++; + Y2 = *Y2_ptr++; + if (chroma_format==CHROMA444) + { + u = *pu++ >> 1; + v = *pv++ >> 1; + } + *dst++ = Pixel[Y_Table[((y+Y2)>>1)+9]|Cb_Table[u+9]|Cr_Table[v+9]]; + *dst2++ = Pixel[Y_Table[Y2+5]|Cb_Table[u+5]|Cr_Table[v+5]]; + } + + py += Coded_Picture_Width; + Y2_ptr += Coded_Picture_Width; + dst += Coded_Picture_Width; + dst2 += Coded_Picture_Width; + pu += Chroma_Width; + pv += Chroma_Width; + } +} + +static void Dither_Top_Field420(src,dst) +unsigned char *src[]; +unsigned char *dst; +{ + int i,j; + int Y1,Cb1,Cr1,Y2,Cb2,Cr2; + unsigned char *Y1_ptr,*Cb1_ptr,*Cr1_ptr,*Y2_ptr,*Cb2_ptr,*Cr2_ptr,*dst2; + + Y1_ptr = src[0]; + Cb1_ptr = src[1]; + Cr1_ptr = src[2]; + + Y2_ptr = Y1_ptr + (Coded_Picture_Width<<1); + Cb2_ptr = Cb1_ptr + (Chroma_Width<<1); + Cr2_ptr = Cr1_ptr + (Chroma_Width<<1); + + dst2 = dst + Coded_Picture_Width; + + for (j=0; j<Coded_Picture_Height; j+=4) + { + /* line j + 0, j + 1 */ + for (i=0; i<Coded_Picture_Width; i+=4) + { + Y1 = *Y1_ptr++; + Y2 = *Y2_ptr++; + Cb1 = *Cb1_ptr++ >> 1; + Cr1 = *Cr1_ptr++ >> 1; + Cb2 = *Cb2_ptr++ >> 1; + Cr2 = *Cr2_ptr++ >> 1; + *dst++ = Pixel[Y_Table[((3*Y1+Y2)>>2)]|Cb_Table[Cb1]|Cr_Table[Cr1]]; + *dst2++ = Pixel[Y_Table[((Y1+3*Y2)>>2)+12]|Cb_Table[((3*Cb1+Cb2)>>2)+12] + |Cr_Table[((3*Cr1+Cr2)>>2)+12]]; + + Y1 = *Y1_ptr++; + Y2 = *Y2_ptr++; + *dst++ = Pixel[Y_Table[((3*Y1+Y2)>>2)+8]|Cb_Table[Cb1+8]|Cr_Table[Cr1+8]]; + *dst2++ = Pixel[Y_Table[((Y1+3*Y2)>>2)+4]|Cb_Table[((3*Cb1+Cb2)>>2)+4] + |Cr_Table[((3*Cr1+Cr2)>>2)+4]]; + + Y1 = *Y1_ptr++; + Y2 = *Y2_ptr++; + Cb1 = *Cb1_ptr++ >> 1; + Cr1 = *Cr1_ptr++ >> 1; + Cb2 = *Cb2_ptr++ >> 1; + Cr2 = *Cr2_ptr++ >> 1; + *dst++ = Pixel[Y_Table[((3*Y1+Y2)>>2)+2]|Cb_Table[Cb1+2]|Cr_Table[Cr1+2]]; + *dst2++ = Pixel[Y_Table[((Y1+3*Y2)>>2)+14]|Cb_Table[((3*Cb1+Cb2)>>2)+14] + |Cr_Table[((3*Cr1+Cr2)>>2)+14]]; + + Y1 = *Y1_ptr++; + Y2 = *Y2_ptr++; + *dst++ = Pixel[Y_Table[((3*Y1+Y2)>>2)+10]|Cb_Table[Cb1+10]|Cr_Table[Cr1+10]]; + *dst2++ = Pixel[Y_Table[((Y1+3*Y2)>>2)+6]|Cb_Table[((3*Cb1+Cb2)>>2)+6] + |Cr_Table[((3*Cr1+Cr2)>>2)+6]]; + } + + Y1_ptr += Coded_Picture_Width; + + if (j!=(Coded_Picture_Height-4)) + Y2_ptr += Coded_Picture_Width; + else + Y2_ptr -= Coded_Picture_Width; + + Cb1_ptr -= Chroma_Width; + Cr1_ptr -= Chroma_Width; + Cb2_ptr -= Chroma_Width; + Cr2_ptr -= Chroma_Width; + + dst += Coded_Picture_Width; + dst2 += Coded_Picture_Width; + + /* line j + 2, j + 3 */ + for (i=0; i<Coded_Picture_Width; i+=4) + { + Y1 = *Y1_ptr++; + Y2 = *Y2_ptr++; + Cb1 = *Cb1_ptr++ >> 1; + Cr1 = *Cr1_ptr++ >> 1; + Cb2 = *Cb2_ptr++ >> 1; + Cr2 = *Cr2_ptr++ >> 1; + *dst++ = Pixel[Y_Table[((3*Y1+Y2)>>2)+3]|Cb_Table[((Cb1+Cb2)>>1)+3] + |Cr_Table[((Cr1+Cr2)>>1)+3]]; + *dst2++ = Pixel[Y_Table[((Y1+3*Y2)>>2)+15]|Cb_Table[((Cb1+3*Cb2)>>2)+15] + |Cr_Table[((Cr1+3*Cr2)>>2)+15]]; + + Y1 = *Y1_ptr++; + Y2 = *Y2_ptr++; + *dst++ = Pixel[Y_Table[((3*Y1+Y2)>>2)+11]|Cb_Table[((Cb1+Cb2)>>1)+11] + |Cr_Table[((Cr1+Cr2)>>1)+11]]; + *dst2++ = Pixel[Y_Table[((Y1+3*Y2)>>2)+7]|Cb_Table[((Cb1+3*Cb2)>>2)+7] + |Cr_Table[((Cr1+3*Cr2)>>2)+7]]; + + Y1 = *Y1_ptr++; + Y2 = *Y2_ptr++; + Cb1 = *Cb1_ptr++ >> 1; + Cr1 = *Cr1_ptr++ >> 1; + Cb2 = *Cb2_ptr++ >> 1; + Cr2 = *Cr2_ptr++ >> 1; + *dst++ = Pixel[Y_Table[((3*Y1+Y2)>>2)+1]|Cb_Table[((Cb1+Cb2)>>1)+1] + |Cr_Table[((Cr1+Cr2)>>1)+1]]; + *dst2++ = Pixel[Y_Table[((Y1+3*Y2)>>2)+13]|Cb_Table[((Cb1+3*Cb2)>>2)+13] + |Cr_Table[((Cr1+3*Cr2)>>2)+13]]; + + Y1 = *Y1_ptr++; + Y2 = *Y2_ptr++; + *dst++ = Pixel[Y_Table[((3*Y1+Y2)>>2)+9]|Cb_Table[((Cb1+Cb2)>>1)+9] + |Cr_Table[((Cr1+Cr2)>>1)+9]]; + *dst2++ = Pixel[Y_Table[((Y1+3*Y2)>>2)+5]|Cb_Table[((Cb1+3*Cb2)>>2)+5] + |Cr_Table[((Cr1+3*Cr2)>>2)+5]]; + } + + Y1_ptr += Coded_Picture_Width; + Y2_ptr += Coded_Picture_Width; + Cb1_ptr += Chroma_Width; + Cr1_ptr += Chroma_Width; + if (j!=(Coded_Picture_Height-8)) + { + Cb2_ptr += Chroma_Width; + Cr2_ptr += Chroma_Width; + } + else + { + Cb2_ptr -= Chroma_Width; + Cr2_ptr -= Chroma_Width; + } + dst += Coded_Picture_Width; + dst2+= Coded_Picture_Width; + } +} + +static void Dither_Bottom_Field420(src,dst) +unsigned char *src[]; +unsigned char *dst; +{ + int i,j; + int Y1,Cb1,Cr1,Y2,Cb2,Cr2; + unsigned char *Y1_ptr,*Cb1_ptr,*Cr1_ptr,*Y2_ptr,*Cb2_ptr,*Cr2_ptr,*dst2; + + Y2_ptr = Y1_ptr = src[0] + Coded_Picture_Width; + Cb2_ptr = Cb1_ptr = src[1] + Chroma_Width; + Cr2_ptr = Cr1_ptr = src[2] + Chroma_Width; + + dst2 = dst; + + for (j=0; j<Coded_Picture_Height; j+=4) + { + /* line j + 0, j + 1 */ + for (i=0; i<Coded_Picture_Width; i+=4) + { + Y1 = *Y1_ptr++; + Y2 = *Y2_ptr++; + Cb1 = *Cb1_ptr++ >> 1; + Cr1 = *Cr1_ptr++ >> 1; + Cb2 = *Cb2_ptr++ >> 1; + Cr2 = *Cr2_ptr++ >> 1; + *dst++ = Pixel[Y_Table[((3*Y1+Y2)>>2)+15]|Cb_Table[((3*Cb1+Cb2)>>2)+15] + |Cr_Table[((3*Cr1+Cr2)>>2)+15]]; + *dst2++ = Pixel[Y_Table[((Y1+3*Y2)>>2)]|Cb_Table[((Cb1+Cb2)>>1)] + |Cr_Table[((Cr1+Cr2)>>1)]]; + + Y1 = *Y1_ptr++; + Y2 = *Y2_ptr++; + *dst++ = Pixel[Y_Table[((3*Y1+Y2)>>2)+7]|Cb_Table[((3*Cb1+Cb2)>>2)+7] + |Cr_Table[((3*Cr1+Cr2)>>2)+7]]; + *dst2++ = Pixel[Y_Table[((Y1+3*Y2)>>2)+8]|Cb_Table[((Cb1+Cb2)>>1)+8] + |Cr_Table[((Cr1+Cr2)>>1)+8]]; + + Y1 = *Y1_ptr++; + Y2 = *Y2_ptr++; + Cb1 = *Cb1_ptr++ >> 1; + Cr1 = *Cr1_ptr++ >> 1; + Cb2 = *Cb2_ptr++ >> 1; + Cr2 = *Cr2_ptr++ >> 1; + *dst++ = Pixel[Y_Table[((3*Y1+Y2)>>2)+13]|Cb_Table[((3*Cb1+Cb2)>>2)+13] + |Cr_Table[((3*Cr1+Cr2)>>2)+13]]; + *dst2++ = Pixel[Y_Table[((Y1+3*Y2)>>2)+2]|Cb_Table[((Cb1+Cb2)>>1)+2] + |Cr_Table[((Cr1+Cr2)>>1)+2]]; + + Y1 = *Y1_ptr++; + Y2 = *Y2_ptr++; + *dst++ = Pixel[Y_Table[((3*Y1+Y2)>>2)+5]|Cb_Table[((3*Cb1+Cb2)>>2)+5] + |Cr_Table[((3*Cr1+Cr2)>>2)+5]]; + *dst2++ = Pixel[Y_Table[((Y1+3*Y2)>>2)+10]|Cb_Table[((Cb1+Cb2)>>1)+10] + |Cr_Table[((Cr1+Cr2)>>1)+10]]; + } + + if (j!=0) + Y1_ptr += Coded_Picture_Width; + else + Y1_ptr -= Coded_Picture_Width; + + Y2_ptr += Coded_Picture_Width; + + Cb1_ptr -= Chroma_Width; + Cr1_ptr -= Chroma_Width; + Cb2_ptr -= Chroma_Width; + Cr2_ptr -= Chroma_Width; + + if (j!=0) + dst += Coded_Picture_Width; + + dst2 += Coded_Picture_Width; + + /* line j + 2, j + 3 */ + for (i=0; i<Coded_Picture_Width; i+=4) + { + Y1 = *Y1_ptr++; + Y2 = *Y2_ptr++; + Cb1 = *Cb1_ptr++ >> 1; + Cr1 = *Cr1_ptr++ >> 1; + Cb2 = *Cb2_ptr++ >> 1; + Cr2 = *Cr2_ptr++ >> 1; + *dst++ = Pixel[Y_Table[((3*Y1+Y2)>>2)+12]|Cb_Table[((Cb1+3*Cb2)>>2)+12] + |Cr_Table[((Cr1+3*Cr2)>>2)+12]]; + *dst2++ = Pixel[Y_Table[((Y1+3*Y2)>>2)+3]|Cb_Table[Cb2+3] + |Cr_Table[Cr2+3]]; + + Y1 = *Y1_ptr++; + Y2 = *Y2_ptr++; + *dst++ = Pixel[Y_Table[((3*Y1+Y2)>>2)+4]|Cb_Table[((Cb1+3*Cb2)>>2)+4] + |Cr_Table[((Cr1+3*Cr2)>>2)+4]]; + *dst2++ = Pixel[Y_Table[((Y1+3*Y2)>>2)+11]|Cb_Table[Cb2+11] + |Cr_Table[Cr2+11]]; + + Y1 = *Y1_ptr++; + Y2 = *Y2_ptr++; + Cb1 = *Cb1_ptr++ >> 1; + Cr1 = *Cr1_ptr++ >> 1; + Cb2 = *Cb2_ptr++ >> 1; + Cr2 = *Cr2_ptr++ >> 1; + *dst++ = Pixel[Y_Table[((3*Y1+Y2)>>2)+14]|Cb_Table[((Cb1+3*Cb2)>>2)+14] + |Cr_Table[((Cr1+3*Cr2)>>2)+14]]; + *dst2++ = Pixel[Y_Table[((Y1+3*Y2)>>2)+1]|Cb_Table[Cb2+1] + |Cr_Table[Cr2+1]]; + + Y1 = *Y1_ptr++; + Y2 = *Y2_ptr++; + *dst++ = Pixel[Y_Table[((3*Y1+Y2)>>2)+6]|Cb_Table[((Cb1+3*Cb2)>>2)+6] + |Cr_Table[((Cr1+3*Cr2)>>2)+6]]; + *dst2++ = Pixel[Y_Table[((Y1+3*Y2)>>2)+9]|Cb_Table[Cb2+9] + |Cr_Table[Cr2+9]]; + } + + Y1_ptr += Coded_Picture_Width; + Y2_ptr += Coded_Picture_Width; + + if (j!=0) + { + Cb1_ptr += Chroma_Width; + Cr1_ptr += Chroma_Width; + } + else + { + Cb1_ptr -= Chroma_Width; + Cr1_ptr -= Chroma_Width; + } + + Cb2_ptr += Chroma_Width; + Cr2_ptr += Chroma_Width; + + dst += Coded_Picture_Width; + dst2+= Coded_Picture_Width; + } + + Y2_ptr -= (Coded_Picture_Width<<1); + Cb2_ptr -= (Chroma_Width<<1); + Cr2_ptr -= (Chroma_Width<<1); + + /* dither last line */ + for (i=0; i<Coded_Picture_Width; i+=4) + { + Y1 = *Y1_ptr++; + Y2 = *Y2_ptr++; + Cb1 = *Cb1_ptr++ >> 1; + Cr1 = *Cr1_ptr++ >> 1; + Cb2 = *Cb2_ptr++ >> 1; + Cr2 = *Cr2_ptr++ >> 1; + *dst++ = Pixel[Y_Table[((3*Y1+Y2)>>2)+15]|Cb_Table[((3*Cb1+Cb2)>>2)+15] + |Cr_Table[((3*Cr1+Cr2)>>2)+15]]; + + Y1 = *Y1_ptr++; + Y2 = *Y2_ptr++; + *dst++ = Pixel[Y_Table[((3*Y1+Y2)>>2)+7]|Cb_Table[((3*Cb1+Cb2)>>2)+7] + |Cr_Table[((3*Cr1+Cr2)>>2)+7]]; + + Y1 = *Y1_ptr++; + Y2 = *Y2_ptr++; + Cb1 = *Cb1_ptr++ >> 1; + Cr1 = *Cr1_ptr++ >> 1; + Cb2 = *Cb2_ptr++ >> 1; + Cr2 = *Cr2_ptr++ >> 1; + *dst++ = Pixel[Y_Table[((3*Y1+Y2)>>2)+13]|Cb_Table[((3*Cb1+Cb2)>>2)+13] + |Cr_Table[((3*Cr1+Cr2)>>2)+13]]; + + Y1 = *Y1_ptr++; + Y2 = *Y2_ptr++; + *dst++ = Pixel[Y_Table[((3*Y1+Y2)>>2)+5]|Cb_Table[((3*Cb1+Cb2)>>2)+5] + |Cr_Table[((3*Cr1+Cr2)>>2)+5]]; + } + +} +#endif diff --git a/libfbui/MPEG/getbits.c b/libfbui/MPEG/getbits.c @@ -0,0 +1,202 @@ +/* getbits.c, bit level routines */ + +/* + * All modifications (mpeg2decode -> mpeg2play) are + * Copyright (C) 1996, Stefan Eckart. All Rights Reserved. + */ + +/* Copyright (C) 1996, MPEG Software Simulation Group. All Rights Reserved. */ + +/* + * Disclaimer of Warranty + * + * These software programs are available to the user without any license fee or + * royalty on an "as is" basis. The MPEG Software Simulation Group disclaims + * any and all warranties, whether express, implied, or statuary, including any + * implied warranties or merchantability or of fitness for a particular + * purpose. In no event shall the copyright-holder be liable for any + * incidental, punitive, or consequential damages of any kind whatsoever + * arising from the use of these programs. + * + * This disclaimer of warranty extends to the user of these programs and user's + * customers, employees, agents, transferees, successors, and assigns. + * + * The MPEG Software Simulation Group does not represent or warrant that the + * programs furnished hereunder are free of infringement of any third-party + * patents. + * + * Commercial implementations of MPEG-1 and MPEG-2 video, including shareware, + * are subject to royalty fees to patent holders. Many of these patents are + * general enough such that they are unavoidable regardless of implementation + * design. + * + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "config.h" +#include "global.h" + +/* initialize buffer, call once before first getbits or showbits */ + +void Initialize_Buffer() +{ + ld->Incnt = 0; + ld->Rdptr = ld->Rdbfr + 2048; + ld->Rdmax = ld->Rdptr; + +#ifdef VERIFY + /* only the verifier uses this particular bit counter + * Bitcnt keeps track of the current parser position with respect + * to the video elementary stream being decoded, regardless + * of whether or not it is wrapped within a systems layer stream + */ + ld->Bitcnt = 0; +#endif + + ld->Bfr = 0; + Flush_Buffer(0); /* fills valid data into bfr */ +} + +void Fill_Buffer() +{ + int Buffer_Level; + + Buffer_Level = read(ld->Infile,ld->Rdbfr,2048); + ld->Rdptr = ld->Rdbfr; + + if (System_Stream_Flag) + ld->Rdmax -= 2048; + + + /* end of the bitstream file */ + if (Buffer_Level < 2048) + { + /* just to be safe */ + if (Buffer_Level < 0) + Buffer_Level = 0; + + /* pad until the next to the next 32-bit word boundary */ + while (Buffer_Level & 3) + ld->Rdbfr[Buffer_Level++] = 0; + + /* pad the buffer with sequence end codes */ + while (Buffer_Level < 2048) + { + ld->Rdbfr[Buffer_Level++] = SEQUENCE_END_CODE>>24; + ld->Rdbfr[Buffer_Level++] = SEQUENCE_END_CODE>>16; + ld->Rdbfr[Buffer_Level++] = SEQUENCE_END_CODE>>8; + ld->Rdbfr[Buffer_Level++] = SEQUENCE_END_CODE&0xff; + } + } +} + + +/* MPEG-1 system layer demultiplexer */ + +int Get_Byte() +{ + while(ld->Rdptr >= ld->Rdbfr+2048) + { + read(ld->Infile,ld->Rdbfr,2048); + ld->Rdptr -= 2048; + ld->Rdmax -= 2048; + } + return *ld->Rdptr++; +} + +/* extract a 16-bit word from the bitstream buffer */ +int Get_Word() +{ + int Val; + + Val = Get_Byte(); + return (Val<<8) | Get_Byte(); +} + + +/* return next n bits (right adjusted) without advancing */ + +unsigned int Show_Bits(N) +int N; +{ + return ld->Bfr >> (32-N); +} + + +/* return next bit (could be made faster than Get_Bits(1)) */ + +unsigned int Get_Bits1() +{ + return Get_Bits(1); +} + + +/* advance by n bits */ + +void Flush_Buffer(N) +int N; +{ + int Incnt; + + ld->Bfr <<= N; + + Incnt = ld->Incnt -= N; + + if (Incnt <= 24) + { + if (System_Stream_Flag && (ld->Rdptr >= ld->Rdmax-4)) + { + do + { + if (ld->Rdptr >= ld->Rdmax) + Next_Packet(); + ld->Bfr |= Get_Byte() << (24 - Incnt); + Incnt += 8; + } + while (Incnt <= 24); + } + else if (ld->Rdptr < ld->Rdbfr+2044) + { + do + { + ld->Bfr |= *ld->Rdptr++ << (24 - Incnt); + Incnt += 8; + } + while (Incnt <= 24); + } + else + { + do + { + if (ld->Rdptr >= ld->Rdbfr+2048) + Fill_Buffer(); + ld->Bfr |= *ld->Rdptr++ << (24 - Incnt); + Incnt += 8; + } + while (Incnt <= 24); + } + ld->Incnt = Incnt; + } + +#ifdef VERIFY + ld->Bitcnt += N; +#endif /* VERIFY */ + +} + + +/* return next n bits (right adjusted) */ + +unsigned int Get_Bits(N) +int N; +{ + unsigned int Val; + + Val = Show_Bits(N); + Flush_Buffer(N); + + return Val; +} + diff --git a/libfbui/MPEG/getblk.c b/libfbui/MPEG/getblk.c @@ -0,0 +1,570 @@ +/* getblk.c, DCT block decoding */ + +/* Copyright (C) 1996, MPEG Software Simulation Group. All Rights Reserved. */ + +/* + * Disclaimer of Warranty + * + * These software programs are available to the user without any license fee or + * royalty on an "as is" basis. The MPEG Software Simulation Group disclaims + * any and all warranties, whether express, implied, or statuary, including any + * implied warranties or merchantability or of fitness for a particular + * purpose. In no event shall the copyright-holder be liable for any + * incidental, punitive, or consequential damages of any kind whatsoever + * arising from the use of these programs. + * + * This disclaimer of warranty extends to the user of these programs and user's + * customers, employees, agents, transferees, successors, and assigns. + * + * The MPEG Software Simulation Group does not represent or warrant that the + * programs furnished hereunder are free of infringement of any third-party + * patents. + * + * Commercial implementations of MPEG-1 and MPEG-2 video, including shareware, + * are subject to royalty fees to patent holders. Many of these patents are + * general enough such that they are unavoidable regardless of implementation + * design. + * + */ + +#include <stdio.h> + +#include "config.h" +#include "global.h" + + +/* defined in getvlc.h */ +typedef struct { + char run, level, len; +} DCTtab; + +extern DCTtab DCTtabfirst[],DCTtabnext[],DCTtab0[],DCTtab1[]; +extern DCTtab DCTtab2[],DCTtab3[],DCTtab4[],DCTtab5[],DCTtab6[]; +extern DCTtab DCTtab0a[],DCTtab1a[]; + + +/* decode one intra coded MPEG-1 block */ + +void Decode_MPEG1_Intra_Block(comp,dc_dct_pred) +int comp; +int dc_dct_pred[]; +{ + int val, i, j, sign; + unsigned int code; + DCTtab *tab; + short *bp; + + bp = ld->block[comp]; + + /* ISO/IEC 11172-2 section 2.4.3.7: Block layer. */ + /* decode DC coefficients */ + if (comp<4) + bp[0] = (dc_dct_pred[0]+=Get_Luma_DC_dct_diff()) << 3; + else if (comp==4) + bp[0] = (dc_dct_pred[1]+=Get_Chroma_DC_dct_diff()) << 3; + else + bp[0] = (dc_dct_pred[2]+=Get_Chroma_DC_dct_diff()) << 3; + + if (Fault_Flag) return; + + /* D-pictures do not contain AC coefficients */ + if(picture_coding_type == D_TYPE) + return; + + /* decode AC coefficients */ + for (i=1; ; i++) + { + code = Show_Bits(16); + if (code>=16384) + tab = &DCTtabnext[(code>>12)-4]; + else if (code>=1024) + tab = &DCTtab0[(code>>8)-4]; + else if (code>=512) + tab = &DCTtab1[(code>>6)-8]; + else if (code>=256) + tab = &DCTtab2[(code>>4)-16]; + else if (code>=128) + tab = &DCTtab3[(code>>3)-16]; + else if (code>=64) + tab = &DCTtab4[(code>>2)-16]; + else if (code>=32) + tab = &DCTtab5[(code>>1)-16]; + else if (code>=16) + tab = &DCTtab6[code-16]; + else + { + if (!Quiet_Flag) + printf("invalid Huffman code in Decode_MPEG1_Intra_Block()\n"); + Fault_Flag = 1; + return; + } + + Flush_Buffer(tab->len); + + if (tab->run==64) /* end_of_block */ + return; + + if (tab->run==65) /* escape */ + { + i+= Get_Bits(6); + + val = Get_Bits(8); + if (val==0) + val = Get_Bits(8); + else if (val==128) + val = Get_Bits(8) - 256; + else if (val>128) + val -= 256; + + if((sign = (val<0))) + val = -val; + } + else + { + i+= tab->run; + val = tab->level; + sign = Get_Bits(1); + } + + if (i>=64) + { + if (!Quiet_Flag) + fprintf(stderr,"DCT coeff index (i) out of bounds (intra)\n"); + Fault_Flag = 1; + return; + } + + j = scan[ZIG_ZAG][i]; + val = (val*ld->quantizer_scale*ld->intra_quantizer_matrix[j]) >> 3; + + /* mismatch control ('oddification') */ + if (val!=0) /* should always be true, but it's not guaranteed */ + val = (val-1) | 1; /* equivalent to: if ((val&1)==0) val = val - 1; */ + + /* saturation */ + if (!sign) + bp[j] = (val>2047) ? 2047 : val; /* positive */ + else + bp[j] = (val>2048) ? -2048 : -val; /* negative */ + } +} + + +/* decode one non-intra coded MPEG-1 block */ + +void Decode_MPEG1_Non_Intra_Block(comp) +int comp; +{ + int val, i, j, sign; + unsigned int code; + DCTtab *tab; + short *bp; + + bp = ld->block[comp]; + + /* decode AC coefficients */ + for (i=0; ; i++) + { + code = Show_Bits(16); + if (code>=16384) + { + if (i==0) + tab = &DCTtabfirst[(code>>12)-4]; + else + tab = &DCTtabnext[(code>>12)-4]; + } + else if (code>=1024) + tab = &DCTtab0[(code>>8)-4]; + else if (code>=512) + tab = &DCTtab1[(code>>6)-8]; + else if (code>=256) + tab = &DCTtab2[(code>>4)-16]; + else if (code>=128) + tab = &DCTtab3[(code>>3)-16]; + else if (code>=64) + tab = &DCTtab4[(code>>2)-16]; + else if (code>=32) + tab = &DCTtab5[(code>>1)-16]; + else if (code>=16) + tab = &DCTtab6[code-16]; + else + { + if (!Quiet_Flag) + printf("invalid Huffman code in Decode_MPEG1_Non_Intra_Block()\n"); + Fault_Flag = 1; + return; + } + + Flush_Buffer(tab->len); + + if (tab->run==64) /* end_of_block */ + return; + + if (tab->run==65) /* escape */ + { + i+= Get_Bits(6); + + val = Get_Bits(8); + if (val==0) + val = Get_Bits(8); + else if (val==128) + val = Get_Bits(8) - 256; + else if (val>128) + val -= 256; + + if((sign = (val<0))) + val = -val; + } + else + { + i+= tab->run; + val = tab->level; + sign = Get_Bits(1); + } + + if (i>=64) + { + if (!Quiet_Flag) + fprintf(stderr,"DCT coeff index (i) out of bounds (inter)\n"); + Fault_Flag = 1; + return; + } + + j = scan[ZIG_ZAG][i]; + val = (((val<<1)+1)*ld->quantizer_scale*ld->non_intra_quantizer_matrix[j]) >> 4; + + /* mismatch control ('oddification') */ + if (val!=0) /* should always be true, but it's not guaranteed */ + val = (val-1) | 1; /* equivalent to: if ((val&1)==0) val = val - 1; */ + + /* saturation */ + if (!sign) + bp[j] = (val>2047) ? 2047 : val; /* positive */ + else + bp[j] = (val>2048) ? -2048 : -val; /* negative */ + } +} + + +/* decode one intra coded MPEG-2 block */ + +void Decode_MPEG2_Intra_Block(comp,dc_dct_pred) +int comp; +int dc_dct_pred[]; +{ + int val, i, j, sign, nc, cc, run; + unsigned int code; + DCTtab *tab; + short *bp; + int *qmat; + struct layer_data *ld1; + + /* with data partitioning, data always goes to base layer */ + ld1 = (ld->scalable_mode==SC_DP) ? &base : ld; + bp = ld1->block[comp]; + + if (base.scalable_mode==SC_DP) + if (base.priority_breakpoint<64) + ld = &enhan; + else + ld = &base; + + cc = (comp<4) ? 0 : (comp&1)+1; + + qmat = (comp<4 || chroma_format==CHROMA420) + ? ld1->intra_quantizer_matrix + : ld1->chroma_intra_quantizer_matrix; + + /* ISO/IEC 13818-2 section 7.2.1: decode DC coefficients */ + if (cc==0) + val = (dc_dct_pred[0]+= Get_Luma_DC_dct_diff()); + else if (cc==1) + val = (dc_dct_pred[1]+= Get_Chroma_DC_dct_diff()); + else + val = (dc_dct_pred[2]+= Get_Chroma_DC_dct_diff()); + + if (Fault_Flag) return; + + bp[0] = val << (3-intra_dc_precision); + + nc=0; + +#ifdef TRACE + if (Trace_Flag) + printf("DCT(%d)i:",comp); +#endif /* TRACE */ + + /* decode AC coefficients */ + for (i=1; ; i++) + { + code = Show_Bits(16); + if (code>=16384 && !intra_vlc_format) + tab = &DCTtabnext[(code>>12)-4]; + else if (code>=1024) + { + if (intra_vlc_format) + tab = &DCTtab0a[(code>>8)-4]; + else + tab = &DCTtab0[(code>>8)-4]; + } + else if (code>=512) + { + if (intra_vlc_format) + tab = &DCTtab1a[(code>>6)-8]; + else + tab = &DCTtab1[(code>>6)-8]; + } + else if (code>=256) + tab = &DCTtab2[(code>>4)-16]; + else if (code>=128) + tab = &DCTtab3[(code>>3)-16]; + else if (code>=64) + tab = &DCTtab4[(code>>2)-16]; + else if (code>=32) + tab = &DCTtab5[(code>>1)-16]; + else if (code>=16) + tab = &DCTtab6[code-16]; + else + { + if (!Quiet_Flag) + printf("invalid Huffman code in Decode_MPEG2_Intra_Block()\n"); + Fault_Flag = 1; + return; + } + + Flush_Buffer(tab->len); + +#ifdef TRACE + if (Trace_Flag) + { + printf(" ("); + Print_Bits(code,16,tab->len); + } +#endif /* TRACE */ + + if (tab->run==64) /* end_of_block */ + { +#ifdef TRACE + if (Trace_Flag) + printf("): EOB\n"); +#endif /* TRACE */ + return; + } + + if (tab->run==65) /* escape */ + { +#ifdef TRACE + if (Trace_Flag) + { + putchar(' '); + Print_Bits(Show_Bits(6),6,6); + } +#endif /* TRACE */ + + i+= run = Get_Bits(6); + +#ifdef TRACE + if (Trace_Flag) + { + putchar(' '); + Print_Bits(Show_Bits(12),12,12); + } +#endif /* TRACE */ + + val = Get_Bits(12); + if ((val&2047)==0) + { + if (!Quiet_Flag) + printf("invalid escape in Decode_MPEG2_Intra_Block()\n"); + Fault_Flag = 1; + return; + } + if((sign = (val>=2048))) + val = 4096 - val; + } + else + { + i+= run = tab->run; + val = tab->level; + sign = Get_Bits(1); + +#ifdef TRACE + if (Trace_Flag) + printf("%d",sign); +#endif /* TRACE */ + } + + if (i>=64) + { + if (!Quiet_Flag) + fprintf(stderr,"DCT coeff index (i) out of bounds (intra2)\n"); + Fault_Flag = 1; + return; + } + +#ifdef TRACE + if (Trace_Flag) + printf("): %d/%d",run,sign ? -val : val); +#endif /* TRACE */ + + j = scan[ld1->alternate_scan][i]; + val = (val * ld1->quantizer_scale * qmat[j]) >> 4; + bp[j] = sign ? -val : val; + nc++; + + if (base.scalable_mode==SC_DP && nc==base.priority_breakpoint-63) + ld = &enhan; + } +} + + +/* decode one non-intra coded MPEG-2 block */ + +void Decode_MPEG2_Non_Intra_Block(comp) +int comp; +{ + int val, i, j, sign, nc, run; + unsigned int code; + DCTtab *tab; + short *bp; + int *qmat; + struct layer_data *ld1; + + /* with data partitioning, data always goes to base layer */ + ld1 = (ld->scalable_mode==SC_DP) ? &base : ld; + bp = ld1->block[comp]; + + if (base.scalable_mode==SC_DP) + if (base.priority_breakpoint<64) + ld = &enhan; + else + ld = &base; + + qmat = (comp<4 || chroma_format==CHROMA420) + ? ld1->non_intra_quantizer_matrix + : ld1->chroma_non_intra_quantizer_matrix; + + nc = 0; + +#ifdef TRACE + if (Trace_Flag) + printf("DCT(%d)n:",comp); +#endif /* TRACE */ + + /* decode AC coefficients */ + for (i=0; ; i++) + { + code = Show_Bits(16); + if (code>=16384) + { + if (i==0) + tab = &DCTtabfirst[(code>>12)-4]; + else + tab = &DCTtabnext[(code>>12)-4]; + } + else if (code>=1024) + tab = &DCTtab0[(code>>8)-4]; + else if (code>=512) + tab = &DCTtab1[(code>>6)-8]; + else if (code>=256) + tab = &DCTtab2[(code>>4)-16]; + else if (code>=128) + tab = &DCTtab3[(code>>3)-16]; + else if (code>=64) + tab = &DCTtab4[(code>>2)-16]; + else if (code>=32) + tab = &DCTtab5[(code>>1)-16]; + else if (code>=16) + tab = &DCTtab6[code-16]; + else + { + if (!Quiet_Flag) + printf("invalid Huffman code in Decode_MPEG2_Non_Intra_Block()\n"); + Fault_Flag = 1; + return; + } + + Flush_Buffer(tab->len); + +#ifdef TRACE + if (Trace_Flag) + { + printf(" ("); + Print_Bits(code,16,tab->len); + } +#endif /* TRACE */ + + if (tab->run==64) /* end_of_block */ + { +#ifdef TRACE + if (Trace_Flag) + printf("): EOB\n"); +#endif /* TRACE */ + return; + } + + if (tab->run==65) /* escape */ + { +#ifdef TRACE + if (Trace_Flag) + { + putchar(' '); + Print_Bits(Show_Bits(6),6,6); + } +#endif /* TRACE */ + + i+= run = Get_Bits(6); + +#ifdef TRACE + if (Trace_Flag) + { + putchar(' '); + Print_Bits(Show_Bits(12),12,12); + } +#endif /* TRACE */ + + val = Get_Bits(12); + if ((val&2047)==0) + { + if (!Quiet_Flag) + printf("invalid escape in Decode_MPEG2_Intra_Block()\n"); + Fault_Flag = 1; + return; + } + if((sign = (val>=2048))) + val = 4096 - val; + } + else + { + i+= run = tab->run; + val = tab->level; + sign = Get_Bits(1); + +#ifdef TRACE + if (Trace_Flag) + printf("%d",sign); +#endif /* TRACE */ + } + + if (i>=64) + { + if (!Quiet_Flag) + fprintf(stderr,"DCT coeff index (i) out of bounds (inter2)\n"); + Fault_Flag = 1; + return; + } + +#ifdef TRACE + if (Trace_Flag) + printf("): %d/%d",run,sign?-val:val); +#endif /* TRACE */ + + j = scan[ld1->alternate_scan][i]; + val = (((val<<1)+1) * ld1->quantizer_scale * qmat[j]) >> 5; + bp[j] = sign ? -val : val; + nc++; + + if (base.scalable_mode==SC_DP && nc==base.priority_breakpoint-63) + ld = &enhan; + } +} diff --git a/libfbui/MPEG/gethdr.c b/libfbui/MPEG/gethdr.c @@ -0,0 +1,1077 @@ +/* gethdr.c, header decoding */ + +/* Copyright (C) 1996, MPEG Software Simulation Group. All Rights Reserved. */ + +/* + * Disclaimer of Warranty + * + * These software programs are available to the user without any license fee or + * royalty on an "as is" basis. The MPEG Software Simulation Group disclaims + * any and all warranties, whether express, implied, or statuary, including any + * implied warranties or merchantability or of fitness for a particular + * purpose. In no event shall the copyright-holder be liable for any + * incidental, punitive, or consequential damages of any kind whatsoever + * arising from the use of these programs. + * + * This disclaimer of warranty extends to the user of these programs and user's + * customers, employees, agents, transferees, successors, and assigns. + * + * The MPEG Software Simulation Group does not represent or warrant that the + * programs furnished hereunder are free of infringement of any third-party + * patents. + * + * Commercial implementations of MPEG-1 and MPEG-2 video, including shareware, + * are subject to royalty fees to patent holders. Many of these patents are + * general enough such that they are unavoidable regardless of implementation + * design. + * + */ + +#include <stdio.h> + +#include "config.h" +#include "global.h" + + +/* private prototypes */ +static void sequence_header _ANSI_ARGS_((void)); +static void group_of_pictures_header _ANSI_ARGS_((void)); +static void picture_header _ANSI_ARGS_((void)); +static void extension_and_user_data _ANSI_ARGS_((void)); +static void sequence_extension _ANSI_ARGS_((void)); +static void sequence_display_extension _ANSI_ARGS_((void)); +static void quant_matrix_extension _ANSI_ARGS_((void)); +static void sequence_scalable_extension _ANSI_ARGS_((void)); +static void picture_display_extension _ANSI_ARGS_((void)); +static void picture_coding_extension _ANSI_ARGS_((void)); +static void picture_spatial_scalable_extension _ANSI_ARGS_((void)); +static void picture_temporal_scalable_extension _ANSI_ARGS_((void)); +static int extra_bit_information _ANSI_ARGS_((void)); +static void copyright_extension _ANSI_ARGS_((void)); +static void user_data _ANSI_ARGS_((void)); +static void user_data _ANSI_ARGS_((void)); + + + + +/* introduced in September 1995 to assist spatial scalable decoding */ +static void Update_Temporal_Reference_Tacking_Data _ANSI_ARGS_((void)); +/* private variables */ +static int Temporal_Reference_Base = 0; +static int True_Framenum_max = -1; +static int Temporal_Reference_GOP_Reset = 0; + +#define RESERVED -1 +static double frame_rate_Table[16] = +{ + 0.0, + ((23.0*1000.0)/1001.0), + 24.0, + 25.0, + ((30.0*1000.0)/1001.0), + 30.0, + 50.0, + ((60.0*1000.0)/1001.0), + 60.0, + + RESERVED, + RESERVED, + RESERVED, + RESERVED, + RESERVED, + RESERVED, + RESERVED +}; + +/* + * decode headers from one input stream + * until an End of Sequence or picture start code + * is found + */ +int Get_Hdr() +{ + unsigned int code; + + for (;;) + { + /* look for next_start_code */ + next_start_code(); + code = Get_Bits32(); + + switch (code) + { + case SEQUENCE_HEADER_CODE: + sequence_header(); + break; + case GROUP_START_CODE: + group_of_pictures_header(); + break; + case PICTURE_START_CODE: + picture_header(); + return 1; + break; + case SEQUENCE_END_CODE: + return 0; + break; + default: + if (!Quiet_Flag) + fprintf(stderr,"Unexpected next_start_code %08x (ignored)\n",code); + break; + } + } +} + + +/* align to start of next next_start_code */ + +void next_start_code() +{ + /* byte align */ + Flush_Buffer(ld->Incnt&7); + while (Show_Bits(24)!=0x01L) + Flush_Buffer(8); +} + + +/* decode sequence header */ + +static void sequence_header() +{ + int i; + int pos; + + pos = ld->Bitcnt; + horizontal_size = Get_Bits(12); + vertical_size = Get_Bits(12); + aspect_ratio_information = Get_Bits(4); + frame_rate_code = Get_Bits(4); + bit_rate_value = Get_Bits(18); + marker_bit("sequence_header()"); + vbv_buffer_size = Get_Bits(10); + constrained_parameters_flag = Get_Bits(1); + + if((ld->load_intra_quantizer_matrix = Get_Bits(1))) + { + for (i=0; i<64; i++) + ld->intra_quantizer_matrix[scan[ZIG_ZAG][i]] = Get_Bits(8); + } + else + { + for (i=0; i<64; i++) + ld->intra_quantizer_matrix[i] = default_intra_quantizer_matrix[i]; + } + + if((ld->load_non_intra_quantizer_matrix = Get_Bits(1))) + { + for (i=0; i<64; i++) + ld->non_intra_quantizer_matrix[scan[ZIG_ZAG][i]] = Get_Bits(8); + } + else + { + for (i=0; i<64; i++) + ld->non_intra_quantizer_matrix[i] = 16; + } + + /* copy luminance to chrominance matrices */ + for (i=0; i<64; i++) + { + ld->chroma_intra_quantizer_matrix[i] = + ld->intra_quantizer_matrix[i]; + + ld->chroma_non_intra_quantizer_matrix[i] = + ld->non_intra_quantizer_matrix[i]; + } + +#ifdef VERBOSE + if (Verbose_Flag > NO_LAYER) + { + printf("sequence header (byte %d)\n",(pos>>3)-4); + if (Verbose_Flag > SEQUENCE_LAYER) + { + printf(" horizontal_size=%d\n",horizontal_size); + printf(" vertical_size=%d\n",vertical_size); + printf(" aspect_ratio_information=%d\n",aspect_ratio_information); + printf(" frame_rate_code=%d",frame_rate_code); + printf(" bit_rate_value=%d\n",bit_rate_value); + printf(" vbv_buffer_size=%d\n",vbv_buffer_size); + printf(" constrained_parameters_flag=%d\n",constrained_parameters_flag); + printf(" load_intra_quantizer_matrix=%d\n",ld->load_intra_quantizer_matrix); + printf(" load_non_intra_quantizer_matrix=%d\n",ld->load_non_intra_quantizer_matrix); + } + } +#endif /* VERBOSE */ + +#ifdef VERIFY + verify_sequence_header++; +#endif /* VERIFY */ + + extension_and_user_data(); +} + + + +/* decode group of pictures header */ +/* ISO/IEC 13818-2 section 6.2.2.6 */ +static void group_of_pictures_header() +{ + int pos; + + if (ld == &base) + { + Temporal_Reference_Base = True_Framenum_max + 1; /* *CH* */ + Temporal_Reference_GOP_Reset = 1; + } + pos = ld->Bitcnt; + drop_flag = Get_Bits(1); + hour = Get_Bits(5); + minute = Get_Bits(6); + marker_bit("group_of_pictures_header()"); + sec = Get_Bits(6); + frame = Get_Bits(6); + closed_gop = Get_Bits(1); + broken_link = Get_Bits(1); + +#ifdef VERBOSE + if (Verbose_Flag > NO_LAYER) + { + printf("group of pictures (byte %d)\n",(pos>>3)-4); + if (Verbose_Flag > SEQUENCE_LAYER) + { + printf(" drop_flag=%d\n",drop_flag); + printf(" timecode %d:%02d:%02d:%02d\n",hour,minute,sec,frame); + printf(" closed_gop=%d\n",closed_gop); + printf(" broken_link=%d\n",broken_link); + } + } +#endif /* VERBOSE */ + +#ifdef VERIFY + verify_group_of_pictures_header++; +#endif /* VERIFY */ + + extension_and_user_data(); + +} + + +/* decode picture header */ + +/* ISO/IEC 13818-2 section 6.2.3 */ +static void picture_header() +{ + int pos; + int Extra_Information_Byte_Count; + + /* unless later overwritten by picture_spatial_scalable_extension() */ + ld->pict_scal = 0; + + pos = ld->Bitcnt; + temporal_reference = Get_Bits(10); + picture_coding_type = Get_Bits(3); + vbv_delay = Get_Bits(16); + + if (picture_coding_type==P_TYPE || picture_coding_type==B_TYPE) + { + full_pel_forward_vector = Get_Bits(1); + forward_f_code = Get_Bits(3); + } + if (picture_coding_type==B_TYPE) + { + full_pel_backward_vector = Get_Bits(1); + backward_f_code = Get_Bits(3); + } + +#ifdef VERBOSE + if (Verbose_Flag>NO_LAYER) + { + printf("picture header (byte %d)\n",(pos>>3)-4); + if (Verbose_Flag>SEQUENCE_LAYER) + { + printf(" temporal_reference=%d\n",temporal_reference); + printf(" picture_coding_type=%d\n",picture_coding_type); + printf(" vbv_delay=%d\n",vbv_delay); + if (picture_coding_type==P_TYPE || picture_coding_type==B_TYPE) + { + printf(" full_pel_forward_vector=%d\n",full_pel_forward_vector); + printf(" forward_f_code =%d\n",forward_f_code); + } + if (picture_coding_type==B_TYPE) + { + printf(" full_pel_backward_vector=%d\n",full_pel_backward_vector); + printf(" backward_f_code =%d\n",backward_f_code); + } + } + } +#endif /* VERBOSE */ + +#ifdef VERIFY + verify_picture_header++; +#endif /* VERIFY */ + + Extra_Information_Byte_Count = + extra_bit_information(); + + extension_and_user_data(); + + /* update tracking information used to assist spatial scalability */ + Update_Temporal_Reference_Tacking_Data(); +} + +/* decode slice header */ + +/* ISO/IEC 13818-2 section 6.2.4 */ +int slice_header() +{ + int slice_vertical_position_extension; + int quantizer_scale_code; + int pos; + int slice_picture_id_enable = 0; + int slice_picture_id = 0; + int extra_information_slice = 0; + + pos = ld->Bitcnt; + + slice_vertical_position_extension = + (ld->MPEG2_Flag && vertical_size>2800) ? Get_Bits(3) : 0; + + if (ld->scalable_mode==SC_DP) + ld->priority_breakpoint = Get_Bits(7); + + quantizer_scale_code = Get_Bits(5); + ld->quantizer_scale = + ld->MPEG2_Flag ? (ld->q_scale_type ? Non_Linear_quantizer_scale[quantizer_scale_code] : quantizer_scale_code<<1) : quantizer_scale_code; + + /* slice_id introduced in March 1995 as part of the video corridendum + (after the IS was drafted in November 1994) */ + if (Get_Bits(1)) + { + ld->intra_slice = Get_Bits(1); + + slice_picture_id_enable = Get_Bits(1); + slice_picture_id = Get_Bits(6); + + extra_information_slice = extra_bit_information(); + } + else + ld->intra_slice = 0; + +#ifdef VERBOSE + if (Verbose_Flag>PICTURE_LAYER) + { + printf("slice header (byte %d)\n",(pos>>3)-4); + if (Verbose_Flag>SLICE_LAYER) + { + if (ld->MPEG2_Flag && vertical_size>2800) + printf(" slice_vertical_position_extension=%d\n",slice_vertical_position_extension); + + if (ld->scalable_mode==SC_DP) + printf(" priority_breakpoint=%d\n",ld->priority_breakpoint); + + printf(" quantizer_scale_code=%d\n",quantizer_scale_code); + + printf(" slice_picture_id_enable = %d\n", slice_picture_id_enable); + + if(slice_picture_id_enable) + printf(" slice_picture_id = %d\n", slice_picture_id); + + } + } +#endif /* VERBOSE */ + +#ifdef VERIFY + verify_slice_header++; +#endif /* VERIFY */ + + + return slice_vertical_position_extension; +} + + +/* decode extension and user data */ +/* ISO/IEC 13818-2 section 6.2.2.2 */ +static void extension_and_user_data() +{ + int code,ext_ID; + + next_start_code(); + + while ((code = Show_Bits(32))==EXTENSION_START_CODE || code==USER_DATA_START_CODE) + { + if (code==EXTENSION_START_CODE) + { + Flush_Buffer32(); + ext_ID = Get_Bits(4); + switch (ext_ID) + { + case SEQUENCE_EXTENSION_ID: + sequence_extension(); + break; + case SEQUENCE_DISPLAY_EXTENSION_ID: + sequence_display_extension(); + break; + case QUANT_MATRIX_EXTENSION_ID: + quant_matrix_extension(); + break; + case SEQUENCE_SCALABLE_EXTENSION_ID: + sequence_scalable_extension(); + break; + case PICTURE_DISPLAY_EXTENSION_ID: + picture_display_extension(); + break; + case PICTURE_CODING_EXTENSION_ID: + picture_coding_extension(); + break; + case PICTURE_SPATIAL_SCALABLE_EXTENSION_ID: + picture_spatial_scalable_extension(); + break; + case PICTURE_TEMPORAL_SCALABLE_EXTENSION_ID: + picture_temporal_scalable_extension(); + break; + case COPYRIGHT_EXTENSION_ID: + copyright_extension(); + break; + default: + fprintf(stderr,"reserved extension start code ID %d\n",ext_ID); + break; + } + next_start_code(); + } + else + { +#ifdef VERBOSE + if (Verbose_Flag>NO_LAYER) + printf("user data\n"); +#endif /* VERBOSE */ + Flush_Buffer32(); + user_data(); + } + } +} + + +/* decode sequence extension */ + +/* ISO/IEC 13818-2 section 6.2.2.3 */ +static void sequence_extension() +{ + int horizontal_size_extension; + int vertical_size_extension; + int bit_rate_extension; + int vbv_buffer_size_extension; + int pos; + + /* derive bit position for trace */ +#ifdef VERBOSE + pos = ld->Bitcnt; +#endif + + ld->MPEG2_Flag = 1; + + ld->scalable_mode = SC_NONE; /* unless overwritten by sequence_scalable_extension() */ + layer_id = 0; /* unless overwritten by sequence_scalable_extension() */ + + profile_and_level_indication = Get_Bits(8); + progressive_sequence = Get_Bits(1); + chroma_format = Get_Bits(2); + horizontal_size_extension = Get_Bits(2); + vertical_size_extension = Get_Bits(2); + bit_rate_extension = Get_Bits(12); + marker_bit("sequence_extension"); + vbv_buffer_size_extension = Get_Bits(8); + low_delay = Get_Bits(1); + frame_rate_extension_n = Get_Bits(2); + frame_rate_extension_d = Get_Bits(5); + + frame_rate = frame_rate_Table[frame_rate_code] * + ((frame_rate_extension_n+1)/(frame_rate_extension_d+1)); + + /* special case for 422 profile & level must be made */ + if((profile_and_level_indication>>7) & 1) + { /* escape bit of profile_and_level_indication set */ + + /* 4:2:2 Profile @ Main Level */ + if((profile_and_level_indication&15)==5) + { + profile = PROFILE_422; + level = MAIN_LEVEL; + } + } + else + { + profile = profile_and_level_indication >> 4; /* Profile is upper nibble */ + level = profile_and_level_indication & 0xF; /* Level is lower nibble */ + } + + + horizontal_size = (horizontal_size_extension<<12) | (horizontal_size&0x0fff); + vertical_size = (vertical_size_extension<<12) | (vertical_size&0x0fff); + + + /* ISO/IEC 13818-2 does not define bit_rate_value to be composed of + * both the original bit_rate_value parsed in sequence_header() and + * the optional bit_rate_extension in sequence_extension_header(). + * However, we use it for bitstream verification purposes. + */ + + bit_rate_value += (bit_rate_extension << 18); + bit_rate = ((double) bit_rate_value) * 400.0; + vbv_buffer_size += (vbv_buffer_size_extension << 10); + +#ifdef VERBOSE + if (Verbose_Flag>NO_LAYER) + { + printf("sequence extension (byte %d)\n",(pos>>3)-4); + + if (Verbose_Flag>SEQUENCE_LAYER) + { + printf(" profile_and_level_indication=%d\n",profile_and_level_indication); + + if (profile_and_level_indication<128) + { + printf(" profile=%d, level=%d\n",profile,level); + } + + printf(" progressive_sequence=%d\n",progressive_sequence); + printf(" chroma_format=%d\n",chroma_format); + printf(" horizontal_size_extension=%d\n",horizontal_size_extension); + printf(" vertical_size_extension=%d\n",vertical_size_extension); + printf(" bit_rate_extension=%d\n",bit_rate_extension); + printf(" vbv_buffer_size_extension=%d\n",vbv_buffer_size_extension); + printf(" low_delay=%d\n",low_delay); + printf(" frame_rate_extension_n=%d\n",frame_rate_extension_n); + printf(" frame_rate_extension_d=%d\n",frame_rate_extension_d); + } + } +#endif /* VERBOSE */ + +#ifdef VERIFY + verify_sequence_extension++; +#endif /* VERIFY */ + + +} + + +/* decode sequence display extension */ + +static void sequence_display_extension() +{ + int pos; + + pos = ld->Bitcnt; + video_format = Get_Bits(3); + color_description = Get_Bits(1); + + if (color_description) + { + color_primaries = Get_Bits(8); + transfer_characteristics = Get_Bits(8); + matrix_coefficients = Get_Bits(8); + } + + display_horizontal_size = Get_Bits(14); + marker_bit("sequence_display_extension"); + display_vertical_size = Get_Bits(14); + +#ifdef VERBOSE + if (Verbose_Flag>NO_LAYER) + { + printf("sequence display extension (byte %d)\n",(pos>>3)-4); + if (Verbose_Flag>SEQUENCE_LAYER) + { + + printf(" video_format=%d\n",video_format); + printf(" color_description=%d\n",color_description); + + if (color_description) + { + printf(" color_primaries=%d\n",color_primaries); + printf(" transfer_characteristics=%d\n",transfer_characteristics); + printf(" matrix_coefficients=%d\n",matrix_coefficients); + } + printf(" display_horizontal_size=%d\n",display_horizontal_size); + printf(" display_vertical_size=%d\n",display_vertical_size); + } + } +#endif /* VERBOSE */ + +#ifdef VERIFY + verify_sequence_display_extension++; +#endif /* VERIFY */ + +} + + +/* decode quant matrix entension */ +/* ISO/IEC 13818-2 section 6.2.3.2 */ +static void quant_matrix_extension() +{ + int i; + int pos; + + pos = ld->Bitcnt; + + if((ld->load_intra_quantizer_matrix = Get_Bits(1))) + { + for (i=0; i<64; i++) + { + ld->chroma_intra_quantizer_matrix[scan[ZIG_ZAG][i]] + = ld->intra_quantizer_matrix[scan[ZIG_ZAG][i]] + = Get_Bits(8); + } + } + + if((ld->load_non_intra_quantizer_matrix = Get_Bits(1))) + { + for (i=0; i<64; i++) + { + ld->chroma_non_intra_quantizer_matrix[scan[ZIG_ZAG][i]] + = ld->non_intra_quantizer_matrix[scan[ZIG_ZAG][i]] + = Get_Bits(8); + } + } + + if((ld->load_chroma_intra_quantizer_matrix = Get_Bits(1))) + { + for (i=0; i<64; i++) + ld->chroma_intra_quantizer_matrix[scan[ZIG_ZAG][i]] = Get_Bits(8); + } + + if((ld->load_chroma_non_intra_quantizer_matrix = Get_Bits(1))) + { + for (i=0; i<64; i++) + ld->chroma_non_intra_quantizer_matrix[scan[ZIG_ZAG][i]] = Get_Bits(8); + } + +#ifdef VERBOSE + if (Verbose_Flag>NO_LAYER) + { + printf("quant matrix extension (byte %d)\n",(pos>>3)-4); + printf(" load_intra_quantizer_matrix=%d\n", + ld->load_intra_quantizer_matrix); + printf(" load_non_intra_quantizer_matrix=%d\n", + ld->load_non_intra_quantizer_matrix); + printf(" load_chroma_intra_quantizer_matrix=%d\n", + ld->load_chroma_intra_quantizer_matrix); + printf(" load_chroma_non_intra_quantizer_matrix=%d\n", + ld->load_chroma_non_intra_quantizer_matrix); + } +#endif /* VERBOSE */ + +#ifdef VERIFY + verify_quant_matrix_extension++; +#endif /* VERIFY */ + +} + + +/* decode sequence scalable extension */ +/* ISO/IEC 13818-2 section 6.2.2.5 */ +static void sequence_scalable_extension() +{ + int pos; + + pos = ld->Bitcnt; + + /* values (without the +1 offset) of scalable_mode are defined in + Table 6-10 of ISO/IEC 13818-2 */ + ld->scalable_mode = Get_Bits(2) + 1; /* add 1 to make SC_DP != SC_NONE */ + + layer_id = Get_Bits(4); + + if (ld->scalable_mode==SC_SPAT) + { + lower_layer_prediction_horizontal_size = Get_Bits(14); + marker_bit("sequence_scalable_extension()"); + lower_layer_prediction_vertical_size = Get_Bits(14); + horizontal_subsampling_factor_m = Get_Bits(5); + horizontal_subsampling_factor_n = Get_Bits(5); + vertical_subsampling_factor_m = Get_Bits(5); + vertical_subsampling_factor_n = Get_Bits(5); + } + + if (ld->scalable_mode==SC_TEMP) + Error("temporal scalability not implemented\n"); + +#ifdef VERBOSE + if (Verbose_Flag>NO_LAYER) + { + printf("sequence scalable extension (byte %d)\n",(pos>>3)-4); + if (Verbose_Flag>SEQUENCE_LAYER) + { + printf(" scalable_mode=%d\n",ld->scalable_mode-1); + printf(" layer_id=%d\n",layer_id); + if (ld->scalable_mode==SC_SPAT) + { + printf(" lower_layer_prediction_horiontal_size=%d\n", + lower_layer_prediction_horizontal_size); + printf(" lower_layer_prediction_vertical_size=%d\n", + lower_layer_prediction_vertical_size); + printf(" horizontal_subsampling_factor_m=%d\n", + horizontal_subsampling_factor_m); + printf(" horizontal_subsampling_factor_n=%d\n", + horizontal_subsampling_factor_n); + printf(" vertical_subsampling_factor_m=%d\n", + vertical_subsampling_factor_m); + printf(" vertical_subsampling_factor_n=%d\n", + vertical_subsampling_factor_n); + } + } + } +#endif /* VERBOSE */ + +#ifdef VERIFY + verify_sequence_scalable_extension++; +#endif /* VERIFY */ + +} + + +/* decode picture display extension */ +/* ISO/IEC 13818-2 section 6.2.3.3. */ +static void picture_display_extension() +{ + int i; + int number_of_frame_center_offsets; + int pos; + + pos = ld->Bitcnt; + /* based on ISO/IEC 13818-2 section 6.3.12 + (November 1994) Picture display extensions */ + + /* derive number_of_frame_center_offsets */ + if(progressive_sequence) + { + if(repeat_first_field) + { + if(top_field_first) + number_of_frame_center_offsets = 3; + else + number_of_frame_center_offsets = 2; + } + else + { + number_of_frame_center_offsets = 1; + } + } + else + { + if(picture_structure!=FRAME_PICTURE) + { + number_of_frame_center_offsets = 1; + } + else + { + if(repeat_first_field) + number_of_frame_center_offsets = 3; + else + number_of_frame_center_offsets = 2; + } + } + + + /* now parse */ + for (i=0; i<number_of_frame_center_offsets; i++) + { + frame_center_horizontal_offset[i] = Get_Bits(16); + marker_bit("picture_display_extension, first marker bit"); + + frame_center_vertical_offset[i] = Get_Bits(16); + marker_bit("picture_display_extension, second marker bit"); + } + +#ifdef VERBOSE + if (Verbose_Flag>NO_LAYER) + { + printf("picture display extension (byte %d)\n",(pos>>3)-4); + if (Verbose_Flag>SEQUENCE_LAYER) + { + + for (i=0; i<number_of_frame_center_offsets; i++) + { + printf(" frame_center_horizontal_offset[%d]=%d\n",i, + frame_center_horizontal_offset[i]); + printf(" frame_center_vertical_offset[%d]=%d\n",i, + frame_center_vertical_offset[i]); + } + } + } +#endif /* VERBOSE */ + +#ifdef VERIFY + verify_picture_display_extension++; +#endif /* VERIFY */ + +} + + +/* decode picture coding extension */ +static void picture_coding_extension() +{ + int pos; + + pos = ld->Bitcnt; + + f_code[0][0] = Get_Bits(4); + f_code[0][1] = Get_Bits(4); + f_code[1][0] = Get_Bits(4); + f_code[1][1] = Get_Bits(4); + + intra_dc_precision = Get_Bits(2); + picture_structure = Get_Bits(2); + top_field_first = Get_Bits(1); + frame_pred_frame_dct = Get_Bits(1); + concealment_motion_vectors = Get_Bits(1); + ld->q_scale_type = Get_Bits(1); + intra_vlc_format = Get_Bits(1); + ld->alternate_scan = Get_Bits(1); + repeat_first_field = Get_Bits(1); + chroma_420_type = Get_Bits(1); + progressive_frame = Get_Bits(1); + composite_display_flag = Get_Bits(1); + + if (composite_display_flag) + { + v_axis = Get_Bits(1); + field_sequence = Get_Bits(3); + sub_carrier = Get_Bits(1); + burst_amplitude = Get_Bits(7); + sub_carrier_phase = Get_Bits(8); + } + +#ifdef VERBOSE + if (Verbose_Flag>NO_LAYER) + { + printf("picture coding extension (byte %d)\n",(pos>>3)-4); + if (Verbose_Flag>SEQUENCE_LAYER) + { + printf(" forward horizontal f_code=%d\n", f_code[0][0]); + printf(" forward vertical f_code=%d\n", f_code[0][1]); + printf(" backward horizontal f_code=%d\n", f_code[1][0]); + printf(" backward_vertical f_code=%d\n", f_code[1][1]); + printf(" intra_dc_precision=%d\n",intra_dc_precision); + printf(" picture_structure=%d\n",picture_structure); + printf(" top_field_first=%d\n",top_field_first); + printf(" frame_pred_frame_dct=%d\n",frame_pred_frame_dct); + printf(" concealment_motion_vectors=%d\n",concealment_motion_vectors); + printf(" q_scale_type=%d\n",ld->q_scale_type); + printf(" intra_vlc_format=%d\n",intra_vlc_format); + printf(" alternate_scan=%d\n",ld->alternate_scan); + printf(" repeat_first_field=%d\n",repeat_first_field); + printf(" chroma_420_type=%d\n",chroma_420_type); + printf(" progressive_frame=%d\n",progressive_frame); + printf(" composite_display_flag=%d\n",composite_display_flag); + + if (composite_display_flag) + { + printf(" v_axis=%d\n",v_axis); + printf(" field_sequence=%d\n",field_sequence); + printf(" sub_carrier=%d\n",sub_carrier); + printf(" burst_amplitude=%d\n",burst_amplitude); + printf(" sub_carrier_phase=%d\n",sub_carrier_phase); + } + } + } +#endif /* VERBOSE */ + +#ifdef VERIFY + verify_picture_coding_extension++; +#endif /* VERIFY */ +} + + +/* decode picture spatial scalable extension */ +/* ISO/IEC 13818-2 section 6.2.3.5. */ +static void picture_spatial_scalable_extension() +{ + int pos; + + pos = ld->Bitcnt; + + ld->pict_scal = 1; /* use spatial scalability in this picture */ + + lower_layer_temporal_reference = Get_Bits(10); + marker_bit("picture_spatial_scalable_extension(), first marker bit"); + lower_layer_horizontal_offset = Get_Bits(15); + if (lower_layer_horizontal_offset>=16384) + lower_layer_horizontal_offset-= 32768; + marker_bit("picture_spatial_scalable_extension(), second marker bit"); + lower_layer_vertical_offset = Get_Bits(15); + if (lower_layer_vertical_offset>=16384) + lower_layer_vertical_offset-= 32768; + spatial_temporal_weight_code_table_index = Get_Bits(2); + lower_layer_progressive_frame = Get_Bits(1); + lower_layer_deinterlaced_field_select = Get_Bits(1); + +#ifdef VERBOSE + if (Verbose_Flag>NO_LAYER) + { + printf("picture spatial scalable extension (byte %d)\n",(pos>>3)-4); + if (Verbose_Flag>SEQUENCE_LAYER) + { + printf(" lower_layer_temporal_reference=%d\n",lower_layer_temporal_reference); + printf(" lower_layer_horizontal_offset=%d\n",lower_layer_horizontal_offset); + printf(" lower_layer_vertical_offset=%d\n",lower_layer_vertical_offset); + printf(" spatial_temporal_weight_code_table_index=%d\n", + spatial_temporal_weight_code_table_index); + printf(" lower_layer_progressive_frame=%d\n",lower_layer_progressive_frame); + printf(" lower_layer_deinterlaced_field_select=%d\n",lower_layer_deinterlaced_field_select); + } + } +#endif /* VERBOSE */ + +#ifdef VERIFY + verify_picture_spatial_scalable_extension++; +#endif /* VERIFY */ + +} + + +/* decode picture temporal scalable extension + * + * not implemented + */ +/* ISO/IEC 13818-2 section 6.2.3.4. */ +static void picture_temporal_scalable_extension() +{ + Error("temporal scalability not supported\n"); + +#ifdef VERIFY + verify_picture_temporal_scalable_extension++; +#endif /* VERIFY */ +} + + +/* decode extra bit information */ +/* ISO/IEC 13818-2 section 6.2.3.4. */ +static int extra_bit_information() +{ + int Byte_Count = 0; + + while (Get_Bits1()) + { + Flush_Buffer(8); + Byte_Count++; + } + + return(Byte_Count); +} + + + +/* ISO/IEC 13818-2 section 5.3 */ +/* Purpose: this function is mainly designed to aid in bitstream conformance + testing. A simple Flush_Buffer(1) would do */ +void marker_bit(text) +char *text; +{ + int marker; + + marker = Get_Bits(1); + +#ifdef VERIFY + if(!marker) + printf("ERROR: %s--marker_bit set to 0",text); +#endif +} + + +/* ISO/IEC 13818-2 sections 6.3.4.1 and 6.2.2.2.2 */ +static void user_data() +{ + /* skip ahead to the next start code */ + next_start_code(); +} + + + +/* Copyright extension */ +/* ISO/IEC 13818-2 section 6.2.3.6. */ +/* (header added in November, 1994 to the IS document) */ + + +static void copyright_extension() +{ + int pos; + int reserved_data; + + pos = ld->Bitcnt; + + + copyright_flag = Get_Bits(1); + copyright_identifier = Get_Bits(8); + original_or_copy = Get_Bits(1); + + /* reserved */ + reserved_data = Get_Bits(7); + + marker_bit("copyright_extension(), first marker bit"); + copyright_number_1 = Get_Bits(20); + marker_bit("copyright_extension(), second marker bit"); + copyright_number_2 = Get_Bits(22); + marker_bit("copyright_extension(), third marker bit"); + copyright_number_3 = Get_Bits(22); + + if(Verbose_Flag>NO_LAYER) + { + printf("copyright_extension (byte %d)\n",(pos>>3)-4); + if (Verbose_Flag>SEQUENCE_LAYER) + { + printf(" copyright_flag =%d\n",copyright_flag); + + printf(" copyright_identifier=%d\n",copyright_identifier); + + printf(" original_or_copy = %d (original=1, copy=0)\n", + original_or_copy); + + printf(" copyright_number_1=%d\n",copyright_number_1); + printf(" copyright_number_2=%d\n",copyright_number_2); + printf(" copyright_number_3=%d\n",copyright_number_3); + } + } + +#ifdef VERIFY + verify_copyright_extension++; +#endif /* VERIFY */ +} + + + +/* introduced in September 1995 to assist Spatial Scalability */ +static void Update_Temporal_Reference_Tacking_Data() +{ + static int temporal_reference_wrap = 0; + static int temporal_reference_old = 0; + + if (ld == &base) /* *CH* */ + { + if (picture_coding_type!=B_TYPE && temporal_reference!=temporal_reference_old) + /* check first field of */ + { + /* non-B-frame */ + if (temporal_reference_wrap) + {/* wrap occured at previous I- or P-frame */ + /* now all intervening B-frames which could + still have high temporal_reference values are done */ + Temporal_Reference_Base += 1024; + temporal_reference_wrap = 0; + } + + /* distinguish from a reset */ + if (temporal_reference<temporal_reference_old && !Temporal_Reference_GOP_Reset) + temporal_reference_wrap = 1; /* we must have just passed a GOP-Header! */ + + temporal_reference_old = temporal_reference; + Temporal_Reference_GOP_Reset = 0; + } + + True_Framenum = Temporal_Reference_Base + temporal_reference; + + /* temporary wrap of TR at 1024 for M frames */ + if (temporal_reference_wrap && temporal_reference <= temporal_reference_old) + True_Framenum += 1024; + + True_Framenum_max = (True_Framenum > True_Framenum_max) ? + True_Framenum : True_Framenum_max; + } +} diff --git a/libfbui/MPEG/getpic.c b/libfbui/MPEG/getpic.c @@ -0,0 +1,1225 @@ +/* getpic.c, picture decoding */ + +/* Copyright (C) 1996, MPEG Software Simulation Group. All Rights Reserved. */ + +/* + * Disclaimer of Warranty + * + * These software programs are available to the user without any license fee or + * royalty on an "as is" basis. The MPEG Software Simulation Group disclaims + * any and all warranties, whether express, implied, or statuary, including any + * implied warranties or merchantability or of fitness for a particular + * purpose. In no event shall the copyright-holder be liable for any + * incidental, punitive, or consequential damages of any kind whatsoever + * arising from the use of these programs. + * + * This disclaimer of warranty extends to the user of these programs and user's + * customers, employees, agents, transferees, successors, and assigns. + * + * The MPEG Software Simulation Group does not represent or warrant that the + * programs furnished hereunder are free of infringement of any third-party + * patents. + * + * Commercial implementations of MPEG-1 and MPEG-2 video, including shareware, + * are subject to royalty fees to patent holders. Many of these patents are + * general enough such that they are unavoidable regardless of implementation + * design. + * + */ + +#include <stdio.h> + +#include "config.h" +#include "global.h" + +/* private prototypes*/ +static void picture_data _ANSI_ARGS_((int framenum)); +static void macroblock_modes _ANSI_ARGS_((int *pmacroblock_type, int *pstwtype, + int *pstwclass, int *pmotion_type, int *pmotion_vector_count, int *pmv_format, int *pdmv, + int *pmvscale, int *pdct_type)); +static void Clear_Block _ANSI_ARGS_((int comp)); +static void Sum_Block _ANSI_ARGS_((int comp)); +static void Saturate _ANSI_ARGS_((short *bp)); +static void Add_Block _ANSI_ARGS_((int comp, int bx, int by, + int dct_type, int addflag)); +static void Update_Picture_Buffers _ANSI_ARGS_((void)); +static void frame_reorder _ANSI_ARGS_((int bitstream_framenum, + int sequence_framenum)); +static void Decode_SNR_Macroblock _ANSI_ARGS_((int *SNRMBA, int *SNRMBAinc, + int MBA, int MBAmax, int *dct_type)); + +static void motion_compensation _ANSI_ARGS_((int MBA, int macroblock_type, + int motion_type, int PMV[2][2][2], int motion_vertical_field_select[2][2], + int dmvector[2], int stwtype, int dct_type)); + +static void skipped_macroblock _ANSI_ARGS_((int dc_dct_pred[3], + int PMV[2][2][2], int *motion_type, int motion_vertical_field_select[2][2], + int *stwtype, int *macroblock_type)); + +static int slice _ANSI_ARGS_((int framenum, int MBAmax)); + +static int start_of_slice _ANSI_ARGS_ ((int MBAmax, int *MBA, + int *MBAinc, int dc_dct_pred[3], int PMV[2][2][2])); + +static int decode_macroblock _ANSI_ARGS_((int *macroblock_type, + int *stwtype, int *stwclass, int *motion_type, int *dct_type, + int PMV[2][2][2], int dc_dct_pred[3], + int motion_vertical_field_select[2][2], int dmvector[2])); + + +/* decode one frame or field picture */ +void Decode_Picture(bitstream_framenum, sequence_framenum) +int bitstream_framenum, sequence_framenum; +{ + + if (picture_structure==FRAME_PICTURE && Second_Field) + { + /* recover from illegal number of field pictures */ + printf("odd number of field pictures\n"); + Second_Field = 0; + } + + /* IMPLEMENTATION: update picture buffer pointers */ + Update_Picture_Buffers(); + +#ifdef VERIFY + Check_Headers(bitstream_framenum, sequence_framenum); +#endif /* VERIFY */ + + /* ISO/IEC 13818-4 section 2.4.5.4 "frame buffer intercept method" */ + /* (section number based on November 1995 (Dallas) draft of the + conformance document) */ + if(Ersatz_Flag) + Substitute_Frame_Buffer(bitstream_framenum, sequence_framenum); + + /* form spatial scalable picture */ + + /* form spatial scalable picture */ + /* ISO/IEC 13818-2 section 7.7: Spatial scalability */ + if (base.pict_scal && !Second_Field) + { + Spatial_Prediction(); + } + + /* decode picture data ISO/IEC 13818-2 section 6.2.3.7 */ + picture_data(bitstream_framenum); + + /* write or display current or previously decoded reference frame */ + /* ISO/IEC 13818-2 section 6.1.1.11: Frame reordering */ + frame_reorder(bitstream_framenum, sequence_framenum); + + if (picture_structure!=FRAME_PICTURE) + Second_Field = !Second_Field; +} + + +/* decode all macroblocks of the current picture */ +/* stages described in ISO/IEC 13818-2 section 7 */ +static void picture_data(framenum) +int framenum; +{ + int MBAmax; + int ret; + + /* number of macroblocks per picture */ + MBAmax = mb_width*mb_height; + + if (picture_structure!=FRAME_PICTURE) + MBAmax>>=1; /* field picture has half as mnay macroblocks as frame */ + + for(;;) + { + if((ret=slice(framenum, MBAmax))<0) + return; + } + +} + + + +/* decode all macroblocks of the current picture */ +/* ISO/IEC 13818-2 section 6.3.16 */ +static int slice(framenum, MBAmax) +int framenum, MBAmax; +{ + int MBA; + int MBAinc, macroblock_type, motion_type, dct_type; + int dc_dct_pred[3]; + int PMV[2][2][2], motion_vertical_field_select[2][2]; + int dmvector[2]; + int stwtype, stwclass; + int SNRMBA, SNRMBAinc; + int ret; + + MBA = 0; /* macroblock address */ + MBAinc = 0; + + if((ret=start_of_slice(MBAmax, &MBA, &MBAinc, dc_dct_pred, PMV))!=1) + return(ret); + + if (Two_Streams && enhan.scalable_mode==SC_SNR) + { + SNRMBA=0; + SNRMBAinc=0; + } + + Fault_Flag=0; + + for (;;) + { + + /* this is how we properly exit out of picture */ + if (MBA>=MBAmax) + return(-1); /* all macroblocks decoded */ + +#ifdef TRACE + if (Trace_Flag) + printf("frame %d, MB %d\n",framenum,MBA); +#endif /* TRACE */ + +#ifdef DISPLAY + if (!progressive_frame && picture_structure==FRAME_PICTURE + && MBA==(MBAmax>>1) && framenum!=0 && Output_Type==T_X11 + && !Display_Progressive_Flag) + { + Display_Second_Field(); + } +#endif + + ld = &base; + + if (MBAinc==0) + { + if (base.scalable_mode==SC_DP && base.priority_breakpoint==1) + ld = &enhan; + + if (!Show_Bits(23) || Fault_Flag) /* next_start_code or fault */ + { +resync: /* if Fault_Flag: resynchronize to next next_start_code */ + Fault_Flag = 0; + return(0); /* trigger: go to next slice */ + } + else /* neither next_start_code nor Fault_Flag */ + { + if (base.scalable_mode==SC_DP && base.priority_breakpoint==1) + ld = &enhan; + + /* decode macroblock address increment */ + MBAinc = Get_macroblock_address_increment(); + + if (Fault_Flag) goto resync; + } + } + + if (MBA>=MBAmax) + { + /* MBAinc points beyond picture dimensions */ + if (!Quiet_Flag) + printf("Too many macroblocks in picture\n"); + return(-1); + } + + if (MBAinc==1) /* not skipped */ + { + ret = decode_macroblock(¯oblock_type, &stwtype, &stwclass, + &motion_type, &dct_type, PMV, dc_dct_pred, + motion_vertical_field_select, dmvector); + + if(ret==-1) + return(-1); + + if(ret==0) + goto resync; + + } + else /* MBAinc!=1: skipped macroblock */ + { + /* ISO/IEC 13818-2 section 7.6.6 */ + skipped_macroblock(dc_dct_pred, PMV, &motion_type, + motion_vertical_field_select, &stwtype, ¯oblock_type); + } + + /* SCALABILITY: SNR */ + /* ISO/IEC 13818-2 section 7.8 */ + /* NOTE: we currently ignore faults encountered in this routine */ + if (Two_Streams && enhan.scalable_mode==SC_SNR) + Decode_SNR_Macroblock(&SNRMBA, &SNRMBAinc, MBA, MBAmax, &dct_type); + + /* ISO/IEC 13818-2 section 7.6 */ + motion_compensation(MBA, macroblock_type, motion_type, PMV, + motion_vertical_field_select, dmvector, stwtype, dct_type); + + + /* advance to next macroblock */ + MBA++; + MBAinc--; + + /* SCALABILITY: SNR */ + if (Two_Streams && enhan.scalable_mode==SC_SNR) + { + SNRMBA++; + SNRMBAinc--; + } + + if (MBA>=MBAmax) + return(-1); /* all macroblocks decoded */ + } +} + + +/* ISO/IEC 13818-2 section 6.3.17.1: Macroblock modes */ +static void macroblock_modes(pmacroblock_type,pstwtype,pstwclass, + pmotion_type,pmotion_vector_count,pmv_format,pdmv,pmvscale,pdct_type) + int *pmacroblock_type, *pstwtype, *pstwclass; + int *pmotion_type, *pmotion_vector_count, *pmv_format, *pdmv, *pmvscale; + int *pdct_type; +{ + int macroblock_type; + int stwtype, stwcode, stwclass; + int motion_type = 0; + int motion_vector_count, mv_format, dmv, mvscale; + int dct_type; + static unsigned char stwc_table[3][4] + = { {6,3,7,4}, {2,1,5,4}, {2,5,7,4} }; + static unsigned char stwclass_table[9] + = {0, 1, 2, 1, 1, 2, 3, 3, 4}; + + /* get macroblock_type */ + macroblock_type = Get_macroblock_type(); + + if (Fault_Flag) return; + + /* get spatial_temporal_weight_code */ + if (macroblock_type & MB_WEIGHT) + { + if (spatial_temporal_weight_code_table_index==0) + stwtype = 4; + else + { + stwcode = Get_Bits(2); +#ifdef TRACE + if (Trace_Flag) + { + printf("spatial_temporal_weight_code ("); + Print_Bits(stwcode,2,2); + printf("): %d\n",stwcode); + } +#endif /* TRACE */ + stwtype = stwc_table[spatial_temporal_weight_code_table_index-1][stwcode]; + } + } + else + stwtype = (macroblock_type & MB_CLASS4) ? 8 : 0; + + /* SCALABILITY: derive spatial_temporal_weight_class (Table 7-18) */ + stwclass = stwclass_table[stwtype]; + + /* get frame/field motion type */ + if (macroblock_type & (MACROBLOCK_MOTION_FORWARD|MACROBLOCK_MOTION_BACKWARD)) + { + if (picture_structure==FRAME_PICTURE) /* frame_motion_type */ + { + motion_type = frame_pred_frame_dct ? MC_FRAME : Get_Bits(2); +#ifdef TRACE + if (!frame_pred_frame_dct && Trace_Flag) + { + printf("frame_motion_type ("); + Print_Bits(motion_type,2,2); + printf("): %s\n",motion_type==MC_FIELD?"Field": + motion_type==MC_FRAME?"Frame": + motion_type==MC_DMV?"Dual_Prime":"Invalid"); + } +#endif /* TRACE */ + } + else /* field_motion_type */ + { + motion_type = Get_Bits(2); +#ifdef TRACE + if (Trace_Flag) + { + printf("field_motion_type ("); + Print_Bits(motion_type,2,2); + printf("): %s\n",motion_type==MC_FIELD?"Field": + motion_type==MC_16X8?"16x8 MC": + motion_type==MC_DMV?"Dual_Prime":"Invalid"); + } +#endif /* TRACE */ + } + } + else if ((macroblock_type & MACROBLOCK_INTRA) && concealment_motion_vectors) + { + /* concealment motion vectors */ + motion_type = (picture_structure==FRAME_PICTURE) ? MC_FRAME : MC_FIELD; + } +#if 0 + else + { + printf("maroblock_modes(): unknown macroblock type\n"); + motion_type = -1; + } +#endif + + /* derive motion_vector_count, mv_format and dmv, (table 6-17, 6-18) */ + if (picture_structure==FRAME_PICTURE) + { + motion_vector_count = (motion_type==MC_FIELD && stwclass<2) ? 2 : 1; + mv_format = (motion_type==MC_FRAME) ? MV_FRAME : MV_FIELD; + } + else + { + motion_vector_count = (motion_type==MC_16X8) ? 2 : 1; + mv_format = MV_FIELD; + } + + dmv = (motion_type==MC_DMV); /* dual prime */ + + /* field mv predictions in frame pictures have to be scaled + * ISO/IEC 13818-2 section 7.6.3.1 Decoding the motion vectors + * IMPLEMENTATION: mvscale is derived for later use in motion_vectors() + * it displaces the stage: + * + * if((mv_format=="field")&&(t==1)&&(picture_structure=="Frame picture")) + * prediction = PMV[r][s][t] DIV 2; + */ + + mvscale = ((mv_format==MV_FIELD) && (picture_structure==FRAME_PICTURE)); + + /* get dct_type (frame DCT / field DCT) */ + dct_type = (picture_structure==FRAME_PICTURE) + && (!frame_pred_frame_dct) + && (macroblock_type & (MACROBLOCK_PATTERN|MACROBLOCK_INTRA)) + ? Get_Bits(1) + : 0; + +#ifdef TRACE + if (Trace_Flag && (picture_structure==FRAME_PICTURE) + && (!frame_pred_frame_dct) + && (macroblock_type & (MACROBLOCK_PATTERN|MACROBLOCK_INTRA))) + printf("dct_type (%d): %s\n",dct_type,dct_type?"Field":"Frame"); +#endif /* TRACE */ + + /* return values */ + *pmacroblock_type = macroblock_type; + *pstwtype = stwtype; + *pstwclass = stwclass; + *pmotion_type = motion_type; + *pmotion_vector_count = motion_vector_count; + *pmv_format = mv_format; + *pdmv = dmv; + *pmvscale = mvscale; + *pdct_type = dct_type; +} + + +/* move/add 8x8-Block from block[comp] to backward_reference_frame */ +/* copy reconstructed 8x8 block from block[comp] to current_frame[] + * ISO/IEC 13818-2 section 7.6.8: Adding prediction and coefficient data + * This stage also embodies some of the operations implied by: + * - ISO/IEC 13818-2 section 7.6.7: Combining predictions + * - ISO/IEC 13818-2 section 6.1.3: Macroblock +*/ +static void Add_Block(comp,bx,by,dct_type,addflag) +int comp,bx,by,dct_type,addflag; +{ + int cc,i, j, iincr; + unsigned char *rfp; + short *bp; + + + /* derive color component index */ + /* equivalent to ISO/IEC 13818-2 Table 7-1 */ + cc = (comp<4) ? 0 : (comp&1)+1; /* color component index */ + + if (cc==0) + { + /* luminance */ + + if (picture_structure==FRAME_PICTURE) + if (dct_type) + { + /* field DCT coding */ + rfp = current_frame[0] + + Coded_Picture_Width*(by+((comp&2)>>1)) + bx + ((comp&1)<<3); + iincr = (Coded_Picture_Width<<1) - 8; + } + else + { + /* frame DCT coding */ + rfp = current_frame[0] + + Coded_Picture_Width*(by+((comp&2)<<2)) + bx + ((comp&1)<<3); + iincr = Coded_Picture_Width - 8; + } + else + { + /* field picture */ + rfp = current_frame[0] + + (Coded_Picture_Width<<1)*(by+((comp&2)<<2)) + bx + ((comp&1)<<3); + iincr = (Coded_Picture_Width<<1) - 8; + } + } + else + { + /* chrominance */ + + /* scale coordinates */ + if (chroma_format!=CHROMA444) + bx >>= 1; + if (chroma_format==CHROMA420) + by >>= 1; + if (picture_structure==FRAME_PICTURE) + { + if (dct_type && (chroma_format!=CHROMA420)) + { + /* field DCT coding */ + rfp = current_frame[cc] + + Chroma_Width*(by+((comp&2)>>1)) + bx + (comp&8); + iincr = (Chroma_Width<<1) - 8; + } + else + { + /* frame DCT coding */ + rfp = current_frame[cc] + + Chroma_Width*(by+((comp&2)<<2)) + bx + (comp&8); + iincr = Chroma_Width - 8; + } + } + else + { + /* field picture */ + rfp = current_frame[cc] + + (Chroma_Width<<1)*(by+((comp&2)<<2)) + bx + (comp&8); + iincr = (Chroma_Width<<1) - 8; + } + } + + bp = ld->block[comp]; + + if (addflag) + { + for (i=0; i<8; i++) + { + for (j=0; j<8; j++) + { + *rfp = Clip[*bp++ + *rfp]; + rfp++; + } + + rfp+= iincr; + } + } + else + { + for (i=0; i<8; i++) + { + for (j=0; j<8; j++) + *rfp++ = Clip[*bp++ + 128]; + + rfp+= iincr; + } + } +} + + +/* ISO/IEC 13818-2 section 7.8 */ +static void Decode_SNR_Macroblock(SNRMBA, SNRMBAinc, MBA, MBAmax, dct_type) + int *SNRMBA, *SNRMBAinc; + int MBA, MBAmax; + int *dct_type; +{ + int SNRmacroblock_type, SNRcoded_block_pattern, SNRdct_type, dummy; + int slice_vert_pos_ext, quantizer_scale_code, comp, code; + + ld = &enhan; + + if (*SNRMBAinc==0) + { + if (!Show_Bits(23)) /* next_start_code */ + { + next_start_code(); + code = Show_Bits(32); + + if (code<SLICE_START_CODE_MIN || code>SLICE_START_CODE_MAX) + { + /* only slice headers are allowed in picture_data */ + if (!Quiet_Flag) + printf("SNR: Premature end of picture\n"); + return; + } + + Flush_Buffer32(); + + /* decode slice header (may change quantizer_scale) */ + slice_vert_pos_ext = slice_header(); + + /* decode macroblock address increment */ + *SNRMBAinc = Get_macroblock_address_increment(); + + /* set current location */ + *SNRMBA = + ((slice_vert_pos_ext<<7) + (code&255) - 1)*mb_width + *SNRMBAinc - 1; + + *SNRMBAinc = 1; /* first macroblock in slice: not skipped */ + } + else /* not next_start_code */ + { + if (*SNRMBA>=MBAmax) + { + if (!Quiet_Flag) + printf("Too many macroblocks in picture\n"); + return; + } + + /* decode macroblock address increment */ + *SNRMBAinc = Get_macroblock_address_increment(); + } + } + + if (*SNRMBA!=MBA) + { + /* streams out of sync */ + if (!Quiet_Flag) + printf("Cant't synchronize streams\n"); + return; + } + + if (*SNRMBAinc==1) /* not skipped */ + { + macroblock_modes(&SNRmacroblock_type, &dummy, &dummy, + &dummy, &dummy, &dummy, &dummy, &dummy, + &SNRdct_type); + + if (SNRmacroblock_type & MACROBLOCK_PATTERN) + *dct_type = SNRdct_type; + + if (SNRmacroblock_type & MACROBLOCK_QUANT) + { + quantizer_scale_code = Get_Bits(5); + ld->quantizer_scale = + ld->q_scale_type ? Non_Linear_quantizer_scale[quantizer_scale_code] : quantizer_scale_code<<1; + } + + /* macroblock_pattern */ + if (SNRmacroblock_type & MACROBLOCK_PATTERN) + { + SNRcoded_block_pattern = Get_coded_block_pattern(); + + if (chroma_format==CHROMA422) + SNRcoded_block_pattern = (SNRcoded_block_pattern<<2) | Get_Bits(2); /* coded_block_pattern_1 */ + else if (chroma_format==CHROMA444) + SNRcoded_block_pattern = (SNRcoded_block_pattern<<6) | Get_Bits(6); /* coded_block_pattern_2 */ + } + else + SNRcoded_block_pattern = 0; + + /* decode blocks */ + for (comp=0; comp<block_count; comp++) + { + Clear_Block(comp); + + if (SNRcoded_block_pattern & (1<<(block_count-1-comp))) + Decode_MPEG2_Non_Intra_Block(comp); + } + } + else /* SNRMBAinc!=1: skipped macroblock */ + { + for (comp=0; comp<block_count; comp++) + Clear_Block(comp); + } + + ld = &base; +} + + + +/* IMPLEMENTATION: set scratch pad macroblock to zero */ +static void Clear_Block(comp) +int comp; +{ + short *Block_Ptr; + int i; + + Block_Ptr = ld->block[comp]; + + for (i=0; i<64; i++) + *Block_Ptr++ = 0; +} + + +/* SCALABILITY: add SNR enhancement layer block data to base layer */ +/* ISO/IEC 13818-2 section 7.8.3.4: Addition of coefficients from the two layes */ +static void Sum_Block(comp) +int comp; +{ + short *Block_Ptr1, *Block_Ptr2; + int i; + + Block_Ptr1 = base.block[comp]; + Block_Ptr2 = enhan.block[comp]; + + for (i=0; i<64; i++) + *Block_Ptr1++ += *Block_Ptr2++; +} + + +/* limit coefficients to -2048..2047 */ +/* ISO/IEC 13818-2 section 7.4.3 and 7.4.4: Saturation and Mismatch control */ +static void Saturate(Block_Ptr) +short *Block_Ptr; +{ + int i, sum, val; + + sum = 0; + + /* ISO/IEC 13818-2 section 7.4.3: Saturation */ + for (i=0; i<64; i++) + { + val = Block_Ptr[i]; + + if (val>2047) + val = 2047; + else if (val<-2048) + val = -2048; + + Block_Ptr[i] = val; + sum+= val; + } + + /* ISO/IEC 13818-2 section 7.4.4: Mismatch control */ + if ((sum&1)==0) + Block_Ptr[63]^= 1; + +} + + +/* reuse old picture buffers as soon as they are no longer needed + based on life-time axioms of MPEG */ +static void Update_Picture_Buffers() +{ + int cc; /* color component index */ + unsigned char *tmp; /* temporary swap pointer */ + + for (cc=0; cc<3; cc++) + { + /* B pictures do not need to be save for future reference */ + if (picture_coding_type==B_TYPE) + { + current_frame[cc] = auxframe[cc]; + } + else + { + /* only update at the beginning of the coded frame */ + if (!Second_Field) + { + tmp = forward_reference_frame[cc]; + + /* the previously decoded reference frame is stored + coincident with the location where the backward + reference frame is stored (backwards prediction is not + needed in P pictures) */ + forward_reference_frame[cc] = backward_reference_frame[cc]; + + /* update pointer for potential future B pictures */ + backward_reference_frame[cc] = tmp; + } + + /* can erase over old backward reference frame since it is not used + in a P picture, and since any subsequent B pictures will use the + previously decoded I or P frame as the backward_reference_frame */ + current_frame[cc] = backward_reference_frame[cc]; + } + + /* IMPLEMENTATION: + one-time folding of a line offset into the pointer which stores the + memory address of the current frame saves offsets and conditional + branches throughout the remainder of the picture processing loop */ + if (picture_structure==BOTTOM_FIELD) + current_frame[cc]+= (cc==0) ? Coded_Picture_Width : Chroma_Width; + } +} + + +/* store last frame */ + +void Output_Last_Frame_of_Sequence(Framenum) +int Framenum; +{ + if (Second_Field) + printf("last frame incomplete, not stored\n"); + else + Write_Frame(backward_reference_frame,Framenum-1); +} + + + +static void frame_reorder(Bitstream_Framenum, Sequence_Framenum) +int Bitstream_Framenum, Sequence_Framenum; +{ + /* tracking variables to insure proper output in spatial scalability */ + static int Oldref_progressive_frame, Newref_progressive_frame; + + if (Sequence_Framenum!=0) + { + if (picture_structure==FRAME_PICTURE || Second_Field) + { + if (picture_coding_type==B_TYPE) + Write_Frame(auxframe,Bitstream_Framenum-1); + else + { + Newref_progressive_frame = progressive_frame; + progressive_frame = Oldref_progressive_frame; + + Write_Frame(forward_reference_frame,Bitstream_Framenum-1); + + Oldref_progressive_frame = progressive_frame = Newref_progressive_frame; + } + } +#ifdef DISPLAY + else if (Output_Type==T_X11) + { + if(!Display_Progressive_Flag) + Display_Second_Field(); + } +#endif + } + else + Oldref_progressive_frame = progressive_frame; + +} + + +/* ISO/IEC 13818-2 section 7.6 */ +static void motion_compensation(MBA, macroblock_type, motion_type, PMV, + motion_vertical_field_select, dmvector, stwtype, dct_type) +int MBA; +int macroblock_type; +int motion_type; +int PMV[2][2][2]; +int motion_vertical_field_select[2][2]; +int dmvector[2]; +int stwtype; +int dct_type; +{ + int bx, by; + int comp; + + /* derive current macroblock position within picture */ + /* ISO/IEC 13818-2 section 6.3.1.6 and 6.3.1.7 */ + bx = 16*(MBA%mb_width); + by = 16*(MBA/mb_width); + + /* motion compensation */ + if (!(macroblock_type & MACROBLOCK_INTRA)) + form_predictions(bx,by,macroblock_type,motion_type,PMV, + motion_vertical_field_select,dmvector,stwtype); + + /* SCALABILITY: Data Partitioning */ + if (base.scalable_mode==SC_DP) + ld = &base; + + /* copy or add block data into picture */ + for (comp=0; comp<block_count; comp++) + { + /* SCALABILITY: SNR */ + /* ISO/IEC 13818-2 section 7.8.3.4: Addition of coefficients from + the two a layers */ + if (Two_Streams && enhan.scalable_mode==SC_SNR) + Sum_Block(comp); /* add SNR enhancement layer data to base layer */ + + /* MPEG-2 saturation and mismatch control */ + /* base layer could be MPEG-1 stream, enhancement MPEG-2 SNR */ + /* ISO/IEC 13818-2 section 7.4.3 and 7.4.4: Saturation and Mismatch control */ + if ((Two_Streams && enhan.scalable_mode==SC_SNR) || ld->MPEG2_Flag) + Saturate(ld->block[comp]); + + /* ISO/IEC 13818-2 section Annex A: inverse DCT */ + if (Reference_IDCT_Flag) + Reference_IDCT(ld->block[comp]); + else + Fast_IDCT(ld->block[comp]); + + /* ISO/IEC 13818-2 section 7.6.8: Adding prediction and coefficient data */ + Add_Block(comp,bx,by,dct_type,(macroblock_type & MACROBLOCK_INTRA)==0); + } + +} + + + +/* ISO/IEC 13818-2 section 7.6.6 */ +static void skipped_macroblock(dc_dct_pred, PMV, motion_type, + motion_vertical_field_select, stwtype, macroblock_type) +int dc_dct_pred[3]; +int PMV[2][2][2]; +int *motion_type; +int motion_vertical_field_select[2][2]; +int *stwtype; +int *macroblock_type; +{ + int comp; + + /* SCALABILITY: Data Paritioning */ + if (base.scalable_mode==SC_DP) + ld = &base; + + for (comp=0; comp<block_count; comp++) + Clear_Block(comp); + + /* reset intra_dc predictors */ + /* ISO/IEC 13818-2 section 7.2.1: DC coefficients in intra blocks */ + dc_dct_pred[0]=dc_dct_pred[1]=dc_dct_pred[2]=0; + + /* reset motion vector predictors */ + /* ISO/IEC 13818-2 section 7.6.3.4: Resetting motion vector predictors */ + if (picture_coding_type==P_TYPE) + PMV[0][0][0]=PMV[0][0][1]=PMV[1][0][0]=PMV[1][0][1]=0; + + /* derive motion_type */ + if (picture_structure==FRAME_PICTURE) + *motion_type = MC_FRAME; + else + { + *motion_type = MC_FIELD; + + /* predict from field of same parity */ + /* ISO/IEC 13818-2 section 7.6.6.1 and 7.6.6.3: P field picture and B field + picture */ + motion_vertical_field_select[0][0]=motion_vertical_field_select[0][1] = + (picture_structure==BOTTOM_FIELD); + } + + /* skipped I are spatial-only predicted, */ + /* skipped P and B are temporal-only predicted */ + /* ISO/IEC 13818-2 section 7.7.6: Skipped macroblocks */ + *stwtype = (picture_coding_type==I_TYPE) ? 8 : 0; + + /* IMPLEMENTATION: clear MACROBLOCK_INTRA */ + *macroblock_type&= ~MACROBLOCK_INTRA; + +} + + +/* return==-1 means go to next picture */ +/* the expression "start of slice" is used throughout the normative + body of the MPEG specification */ +static int start_of_slice(MBAmax, MBA, MBAinc, + dc_dct_pred, PMV) +int MBAmax; +int *MBA; +int *MBAinc; +int dc_dct_pred[3]; +int PMV[2][2][2]; +{ + unsigned int code; + int slice_vert_pos_ext; + + ld = &base; + + Fault_Flag = 0; + + next_start_code(); + code = Show_Bits(32); + + if (code<SLICE_START_CODE_MIN || code>SLICE_START_CODE_MAX) + { + /* only slice headers are allowed in picture_data */ + if (!Quiet_Flag) + printf("start_of_slice(): Premature end of picture\n"); + + return(-1); /* trigger: go to next picture */ + } + + Flush_Buffer32(); + + /* decode slice header (may change quantizer_scale) */ + slice_vert_pos_ext = slice_header(); + + + /* SCALABILITY: Data Partitioning */ + if (base.scalable_mode==SC_DP) + { + ld = &enhan; + next_start_code(); + code = Show_Bits(32); + + if (code<SLICE_START_CODE_MIN || code>SLICE_START_CODE_MAX) + { + /* only slice headers are allowed in picture_data */ + if (!Quiet_Flag) + printf("DP: Premature end of picture\n"); + return(-1); /* trigger: go to next picture */ + } + + Flush_Buffer32(); + + /* decode slice header (may change quantizer_scale) */ + slice_vert_pos_ext = slice_header(); + + if (base.priority_breakpoint!=1) + ld = &base; + } + + /* decode macroblock address increment */ + *MBAinc = Get_macroblock_address_increment(); + + if (Fault_Flag) + { + printf("start_of_slice(): MBAinc unsuccessful\n"); + return(0); /* trigger: go to next slice */ + } + + /* set current location */ + /* NOTE: the arithmetic used to derive macroblock_address below is + * equivalent to ISO/IEC 13818-2 section 6.3.17: Macroblock + */ + *MBA = ((slice_vert_pos_ext<<7) + (code&255) - 1)*mb_width + *MBAinc - 1; + *MBAinc = 1; /* first macroblock in slice: not skipped */ + + /* reset all DC coefficient and motion vector predictors */ + /* reset all DC coefficient and motion vector predictors */ + /* ISO/IEC 13818-2 section 7.2.1: DC coefficients in intra blocks */ + dc_dct_pred[0]=dc_dct_pred[1]=dc_dct_pred[2]=0; + + /* ISO/IEC 13818-2 section 7.6.3.4: Resetting motion vector predictors */ + PMV[0][0][0]=PMV[0][0][1]=PMV[1][0][0]=PMV[1][0][1]=0; + PMV[0][1][0]=PMV[0][1][1]=PMV[1][1][0]=PMV[1][1][1]=0; + + /* successfull: trigger decode macroblocks in slice */ + return(1); +} + + +/* ISO/IEC 13818-2 sections 7.2 through 7.5 */ +static int decode_macroblock(macroblock_type, stwtype, stwclass, + motion_type, dct_type, PMV, dc_dct_pred, + motion_vertical_field_select, dmvector) +int *macroblock_type; +int *stwtype; +int *stwclass; +int *motion_type; +int *dct_type; +int PMV[2][2][2]; +int dc_dct_pred[3]; +int motion_vertical_field_select[2][2]; +int dmvector[2]; +{ + /* locals */ + int quantizer_scale_code; + int comp; + + int motion_vector_count; + int mv_format; + int dmv; + int mvscale; + int coded_block_pattern; + + /* SCALABILITY: Data Patitioning */ + if (base.scalable_mode==SC_DP) + { + if (base.priority_breakpoint<=2) + ld = &enhan; + else + ld = &base; + } + + /* ISO/IEC 13818-2 section 6.3.17.1: Macroblock modes */ + macroblock_modes(macroblock_type, stwtype, stwclass, + motion_type, &motion_vector_count, &mv_format, &dmv, &mvscale, + dct_type); + + if (Fault_Flag) return(0); /* trigger: go to next slice */ + + if (*macroblock_type & MACROBLOCK_QUANT) + { + quantizer_scale_code = Get_Bits(5); + +#ifdef TRACE + if (Trace_Flag) + { + printf("quantiser_scale_code ("); + Print_Bits(quantizer_scale_code,5,5); + printf("): %d\n",quantizer_scale_code); + } +#endif /* TRACE */ + + /* ISO/IEC 13818-2 section 7.4.2.2: Quantizer scale factor */ + if (ld->MPEG2_Flag) + ld->quantizer_scale = + ld->q_scale_type ? Non_Linear_quantizer_scale[quantizer_scale_code] + : (quantizer_scale_code << 1); + else + ld->quantizer_scale = quantizer_scale_code; + + /* SCALABILITY: Data Partitioning */ + if (base.scalable_mode==SC_DP) + /* make sure base.quantizer_scale is valid */ + base.quantizer_scale = ld->quantizer_scale; + } + + /* motion vectors */ + + + /* ISO/IEC 13818-2 section 6.3.17.2: Motion vectors */ + + /* decode forward motion vectors */ + if ((*macroblock_type & MACROBLOCK_MOTION_FORWARD) + || ((*macroblock_type & MACROBLOCK_INTRA) + && concealment_motion_vectors)) + { + if (ld->MPEG2_Flag) + motion_vectors(PMV,dmvector,motion_vertical_field_select, + 0,motion_vector_count,mv_format,f_code[0][0]-1,f_code[0][1]-1, + dmv,mvscale); + else + motion_vector(PMV[0][0],dmvector, + forward_f_code-1,forward_f_code-1,0,0,full_pel_forward_vector); + } + + if (Fault_Flag) return(0); /* trigger: go to next slice */ + + /* decode backward motion vectors */ + if (*macroblock_type & MACROBLOCK_MOTION_BACKWARD) + { + if (ld->MPEG2_Flag) + motion_vectors(PMV,dmvector,motion_vertical_field_select, + 1,motion_vector_count,mv_format,f_code[1][0]-1,f_code[1][1]-1,0, + mvscale); + else + motion_vector(PMV[0][1],dmvector, + backward_f_code-1,backward_f_code-1,0,0,full_pel_backward_vector); + } + + if (Fault_Flag) return(0); /* trigger: go to next slice */ + + if ((*macroblock_type & MACROBLOCK_INTRA) && concealment_motion_vectors) + Flush_Buffer(1); /* remove marker_bit */ + + if (base.scalable_mode==SC_DP && base.priority_breakpoint==3) + ld = &enhan; + + /* macroblock_pattern */ + /* ISO/IEC 13818-2 section 6.3.17.4: Coded block pattern */ + if (*macroblock_type & MACROBLOCK_PATTERN) + { + coded_block_pattern = Get_coded_block_pattern(); + + if (chroma_format==CHROMA422) + { + /* coded_block_pattern_1 */ + coded_block_pattern = (coded_block_pattern<<2) | Get_Bits(2); + +#ifdef TRACE + if (Trace_Flag) + { + printf("coded_block_pattern_1: "); + Print_Bits(coded_block_pattern,2,2); + printf(" (%d)\n",coded_block_pattern&3); + } +#endif /* TRACE */ + } + else if (chroma_format==CHROMA444) + { + /* coded_block_pattern_2 */ + coded_block_pattern = (coded_block_pattern<<6) | Get_Bits(6); + +#ifdef TRACE + if (Trace_Flag) + { + printf("coded_block_pattern_2: "); + Print_Bits(coded_block_pattern,6,6); + printf(" (%d)\n",coded_block_pattern&63); + } +#endif /* TRACE */ + } + } + else + coded_block_pattern = (*macroblock_type & MACROBLOCK_INTRA) ? + (1<<block_count)-1 : 0; + + if (Fault_Flag) return(0); /* trigger: go to next slice */ + + /* decode blocks */ + for (comp=0; comp<block_count; comp++) + { + /* SCALABILITY: Data Partitioning */ + if (base.scalable_mode==SC_DP) + ld = &base; + + Clear_Block(comp); + + if (coded_block_pattern & (1<<(block_count-1-comp))) + { + if (*macroblock_type & MACROBLOCK_INTRA) + { + if (ld->MPEG2_Flag) + Decode_MPEG2_Intra_Block(comp,dc_dct_pred); + else + Decode_MPEG1_Intra_Block(comp,dc_dct_pred); + } + else + { + if (ld->MPEG2_Flag) + Decode_MPEG2_Non_Intra_Block(comp); + else + Decode_MPEG1_Non_Intra_Block(comp); + } + + if (Fault_Flag) return(0); /* trigger: go to next slice */ + } + } + + if(picture_coding_type==D_TYPE) + { + /* remove end_of_macroblock (always 1, prevents startcode emulation) */ + /* ISO/IEC 11172-2 section 2.4.2.7 and 2.4.3.6 */ + marker_bit("D picture end_of_macroblock bit"); + } + + /* reset intra_dc predictors */ + /* ISO/IEC 13818-2 section 7.2.1: DC coefficients in intra blocks */ + if (!(*macroblock_type & MACROBLOCK_INTRA)) + dc_dct_pred[0]=dc_dct_pred[1]=dc_dct_pred[2]=0; + + /* reset motion vector predictors */ + if ((*macroblock_type & MACROBLOCK_INTRA) && !concealment_motion_vectors) + { + /* intra mb without concealment motion vectors */ + /* ISO/IEC 13818-2 section 7.6.3.4: Resetting motion vector predictors */ + PMV[0][0][0]=PMV[0][0][1]=PMV[1][0][0]=PMV[1][0][1]=0; + PMV[0][1][0]=PMV[0][1][1]=PMV[1][1][0]=PMV[1][1][1]=0; + } + + /* special "No_MC" macroblock_type case */ + /* ISO/IEC 13818-2 section 7.6.3.5: Prediction in P pictures */ + if ((picture_coding_type==P_TYPE) + && !(*macroblock_type & (MACROBLOCK_MOTION_FORWARD|MACROBLOCK_INTRA))) + { + /* non-intra mb without forward mv in a P picture */ + /* ISO/IEC 13818-2 section 7.6.3.4: Resetting motion vector predictors */ + PMV[0][0][0]=PMV[0][0][1]=PMV[1][0][0]=PMV[1][0][1]=0; + + /* derive motion_type */ + /* ISO/IEC 13818-2 section 6.3.17.1: Macroblock modes, frame_motion_type */ + if (picture_structure==FRAME_PICTURE) + *motion_type = MC_FRAME; + else + { + *motion_type = MC_FIELD; + /* predict from field of same parity */ + motion_vertical_field_select[0][0] = (picture_structure==BOTTOM_FIELD); + } + } + + if (*stwclass==4) + { + /* purely spatially predicted macroblock */ + /* ISO/IEC 13818-2 section 7.7.5.1: Resetting motion vector predictions */ + PMV[0][0][0]=PMV[0][0][1]=PMV[1][0][0]=PMV[1][0][1]=0; + PMV[0][1][0]=PMV[0][1][1]=PMV[1][1][0]=PMV[1][1][1]=0; + } + + /* successfully decoded macroblock */ + return(1); + +} /* decode_macroblock */ + + diff --git a/libfbui/MPEG/getvlc.c b/libfbui/MPEG/getvlc.c @@ -0,0 +1,799 @@ +/* getvlc.c, variable length decoding */ + +/* Copyright (C) 1996, MPEG Software Simulation Group. All Rights Reserved. */ + +/* + * Disclaimer of Warranty + * + * These software programs are available to the user without any license fee or + * royalty on an "as is" basis. The MPEG Software Simulation Group disclaims + * any and all warranties, whether express, implied, or statuary, including any + * implied warranties or merchantability or of fitness for a particular + * purpose. In no event shall the copyright-holder be liable for any + * incidental, punitive, or consequential damages of any kind whatsoever + * arising from the use of these programs. + * + * This disclaimer of warranty extends to the user of these programs and user's + * customers, employees, agents, transferees, successors, and assigns. + * + * The MPEG Software Simulation Group does not represent or warrant that the + * programs furnished hereunder are free of infringement of any third-party + * patents. + * + * Commercial implementations of MPEG-1 and MPEG-2 video, including shareware, + * are subject to royalty fees to patent holders. Many of these patents are + * general enough such that they are unavoidable regardless of implementation + * design. + * + */ + +#include <stdio.h> + +#include "config.h" +#include "global.h" +#include "getvlc.h" + +/* private prototypes */ +/* generic picture macroblock type processing functions */ +static int Get_I_macroblock_type _ANSI_ARGS_((void)); +static int Get_P_macroblock_type _ANSI_ARGS_((void)); +static int Get_B_macroblock_type _ANSI_ARGS_((void)); +static int Get_D_macroblock_type _ANSI_ARGS_((void)); + +/* spatial picture macroblock type processing functions */ +static int Get_I_Spatial_macroblock_type _ANSI_ARGS_((void)); +static int Get_P_Spatial_macroblock_type _ANSI_ARGS_((void)); +static int Get_B_Spatial_macroblock_type _ANSI_ARGS_((void)); +static int Get_SNR_macroblock_type _ANSI_ARGS_((void)); + +int Get_macroblock_type() +{ + int macroblock_type = 0; + + if (ld->scalable_mode==SC_SNR) + macroblock_type = Get_SNR_macroblock_type(); + else + { + switch (picture_coding_type) + { + case I_TYPE: + macroblock_type = ld->pict_scal ? Get_I_Spatial_macroblock_type() : Get_I_macroblock_type(); + break; + case P_TYPE: + macroblock_type = ld->pict_scal ? Get_P_Spatial_macroblock_type() : Get_P_macroblock_type(); + break; + case B_TYPE: + macroblock_type = ld->pict_scal ? Get_B_Spatial_macroblock_type() : Get_B_macroblock_type(); + break; + case D_TYPE: + macroblock_type = Get_D_macroblock_type(); + break; + default: + printf("Get_macroblock_type(): unrecognized picture coding type\n"); + break; + } + } + + return macroblock_type; +} + +static int Get_I_macroblock_type() +{ +#ifdef TRACE + if (Trace_Flag) + printf("macroblock_type(I) "); +#endif /* TRACE */ + + if (Get_Bits1()) + { +#ifdef TRACE + if (Trace_Flag) + printf("(1): Intra (1)\n"); +#endif /* TRACE */ + return 1; + } + + if (!Get_Bits1()) + { + if (!Quiet_Flag) + printf("Invalid macroblock_type code\n"); + Fault_Flag = 1; + } + +#ifdef TRACE + if (Trace_Flag) + printf("(01): Intra, Quant (17)\n"); +#endif /* TRACE */ + + return 17; +} + +static char *MBdescr[]={ + "", "Intra", "No MC, Coded", "", + "Bwd, Not Coded", "", "Bwd, Coded", "", + "Fwd, Not Coded", "", "Fwd, Coded", "", + "Interp, Not Coded", "", "Interp, Coded", "", + "", "Intra, Quant", "No MC, Coded, Quant", "", + "", "", "Bwd, Coded, Quant", "", + "", "", "Fwd, Coded, Quant", "", + "", "", "Interp, Coded, Quant", "" +}; + +static int Get_P_macroblock_type() +{ + int code; + +#ifdef TRACE + if (Trace_Flag) + printf("macroblock_type(P) ("); +#endif /* TRACE */ + + if ((code = Show_Bits(6))>=8) + { + code >>= 3; + Flush_Buffer(PMBtab0[code].len); +#ifdef TRACE + if (Trace_Flag) + { + Print_Bits(code,3,PMBtab0[code].len); + printf("): %s (%d)\n",MBdescr[(int)PMBtab0[code].val],PMBtab0[code].val); + } +#endif /* TRACE */ + return PMBtab0[code].val; + } + + if (code==0) + { + if (!Quiet_Flag) + printf("Invalid macroblock_type code\n"); + Fault_Flag = 1; + return 0; + } + + Flush_Buffer(PMBtab1[code].len); + +#ifdef TRACE + if (Trace_Flag) + { + Print_Bits(code,6,PMBtab1[code].len); + printf("): %s (%d)\n",MBdescr[(int)PMBtab1[code].val],PMBtab1[code].val); + } +#endif /* TRACE */ + + return PMBtab1[code].val; +} + +static int Get_B_macroblock_type() +{ + int code; + +#ifdef TRACE + if (Trace_Flag) + printf("macroblock_type(B) ("); +#endif /* TRACE */ + + if ((code = Show_Bits(6))>=8) + { + code >>= 2; + Flush_Buffer(BMBtab0[code].len); + +#ifdef TRACE + if (Trace_Flag) + { + Print_Bits(code,4,BMBtab0[code].len); + printf("): %s (%d)\n",MBdescr[(int)BMBtab0[code].val],BMBtab0[code].val); + } +#endif /* TRACE */ + + return BMBtab0[code].val; + } + + if (code==0) + { + if (!Quiet_Flag) + printf("Invalid macroblock_type code\n"); + Fault_Flag = 1; + return 0; + } + + Flush_Buffer(BMBtab1[code].len); + +#ifdef TRACE + if (Trace_Flag) + { + Print_Bits(code,6,BMBtab1[code].len); + printf("): %s (%d)\n",MBdescr[(int)BMBtab1[code].val],BMBtab1[code].val); + } +#endif /* TRACE */ + + return BMBtab1[code].val; +} + +static int Get_D_macroblock_type() +{ + if (!Get_Bits1()) + { + if (!Quiet_Flag) + printf("Invalid macroblock_type code\n"); + Fault_Flag=1; + } + + return 1; +} + +/* macroblock_type for pictures with spatial scalability */ +static int Get_I_Spatial_macroblock_type() +{ + int code; + +#ifdef TRACE + if (Trace_Flag) + printf("macroblock_type(I,spat) ("); +#endif /* TRACE */ + + code = Show_Bits(4); + + if (code==0) + { + if (!Quiet_Flag) + printf("Invalid macroblock_type code\n"); + Fault_Flag = 1; + return 0; + } + +#ifdef TRACE + if (Trace_Flag) + { + Print_Bits(code,4,spIMBtab[code].len); + printf("): %02x\n",spIMBtab[code].val); + } +#endif /* TRACE */ + + Flush_Buffer(spIMBtab[code].len); + return spIMBtab[code].val; +} + +static int Get_P_Spatial_macroblock_type() +{ + int code; + +#ifdef TRACE + if (Trace_Flag) + printf("macroblock_type(P,spat) ("); +#endif /* TRACE */ + + code = Show_Bits(7); + + if (code<2) + { + if (!Quiet_Flag) + printf("Invalid macroblock_type code\n"); + Fault_Flag = 1; + return 0; + } + + if (code>=16) + { + code >>= 3; + Flush_Buffer(spPMBtab0[code].len); + +#ifdef TRACE + if (Trace_Flag) + { + Print_Bits(code,4,spPMBtab0[code].len); + printf("): %02x\n",spPMBtab0[code].val); + } +#endif /* TRACE */ + + return spPMBtab0[code].val; + } + + Flush_Buffer(spPMBtab1[code].len); + +#ifdef TRACE + if (Trace_Flag) + { + Print_Bits(code,7,spPMBtab1[code].len); + printf("): %02x\n",spPMBtab1[code].val); + } +#endif /* TRACE */ + + return spPMBtab1[code].val; +} + +static int Get_B_Spatial_macroblock_type() +{ + int code; + VLCtab *p; + +#ifdef TRACE + if (Trace_Flag) + printf("macroblock_type(B,spat) ("); +#endif /* TRACE */ + + code = Show_Bits(9); + + if (code>=64) + p = &spBMBtab0[(code>>5)-2]; + else if (code>=16) + p = &spBMBtab1[(code>>2)-4]; + else if (code>=8) + p = &spBMBtab2[code-8]; + else + { + if (!Quiet_Flag) + printf("Invalid macroblock_type code\n"); + Fault_Flag = 1; + return 0; + } + + Flush_Buffer(p->len); + +#ifdef TRACE + if (Trace_Flag) + { + Print_Bits(code,9,p->len); + printf("): %02x\n",p->val); + } +#endif /* TRACE */ + + return p->val; +} + +static int Get_SNR_macroblock_type() +{ + int code; + +#ifdef TRACE /* *CH* */ + if (Trace_Flag) + printf("macroblock_type(SNR) ("); +#endif TRACE + + code = Show_Bits(3); + + if (code==0) + { + if (!Quiet_Flag) + printf("Invalid macroblock_type code\n"); + Fault_Flag = 1; + return 0; + } + + Flush_Buffer(SNRMBtab[code].len); + +#ifdef TRACE /* *CH* */ + if (Trace_Flag) + { + Print_Bits(code,3,SNRMBtab[code].len); + printf("): %s (%d)\n",MBdescr[(int)SNRMBtab[code].val],SNRMBtab[code].val); + } +#endif TRACE + + + return SNRMBtab[code].val; +} + +int Get_motion_code() +{ + int code; + +#ifdef TRACE + if (Trace_Flag) + printf("motion_code ("); +#endif /* TRACE */ + + if (Get_Bits1()) + { +#ifdef TRACE + if (Trace_Flag) + printf("0): 0\n"); +#endif /* TRACE */ + return 0; + } + + if ((code = Show_Bits(9))>=64) + { + code >>= 6; + Flush_Buffer(MVtab0[code].len); + +#ifdef TRACE + if (Trace_Flag) + { + Print_Bits(code,3,MVtab0[code].len); + printf("%d): %d\n", + Show_Bits(1),Show_Bits(1)?-MVtab0[code].val:MVtab0[code].val); + } +#endif /* TRACE */ + + return Get_Bits1()?-MVtab0[code].val:MVtab0[code].val; + } + + if (code>=24) + { + code >>= 3; + Flush_Buffer(MVtab1[code].len); + +#ifdef TRACE + if (Trace_Flag) + { + Print_Bits(code,6,MVtab1[code].len); + printf("%d): %d\n", + Show_Bits(1),Show_Bits(1)?-MVtab1[code].val:MVtab1[code].val); + } +#endif /* TRACE */ + + return Get_Bits1()?-MVtab1[code].val:MVtab1[code].val; + } + + if ((code-=12)<0) + { + if (!Quiet_Flag) +/* HACK */ + printf("Invalid motion_vector code (MBA %d, pic %d)\n", global_MBA, global_pic); + Fault_Flag=1; + return 0; + } + + Flush_Buffer(MVtab2[code].len); + +#ifdef TRACE + if (Trace_Flag) + { + Print_Bits(code+12,9,MVtab2[code].len); + printf("%d): %d\n", + Show_Bits(1),Show_Bits(1)?-MVtab2[code].val:MVtab2[code].val); + } +#endif /* TRACE */ + + return Get_Bits1() ? -MVtab2[code].val : MVtab2[code].val; +} + +/* get differential motion vector (for dual prime prediction) */ +int Get_dmvector() +{ +#ifdef TRACE + if (Trace_Flag) + printf("dmvector ("); +#endif /* TRACE */ + + if (Get_Bits(1)) + { +#ifdef TRACE + if (Trace_Flag) + printf(Show_Bits(1) ? "11): -1\n" : "10): 1\n"); +#endif /* TRACE */ + return Get_Bits(1) ? -1 : 1; + } + else + { +#ifdef TRACE + if (Trace_Flag) + printf("0): 0\n"); +#endif /* TRACE */ + return 0; + } +} + +int Get_coded_block_pattern() +{ + int code; + +#ifdef TRACE + if (Trace_Flag) + printf("coded_block_pattern_420 ("); +#endif /* TRACE */ + + if ((code = Show_Bits(9))>=128) + { + code >>= 4; + Flush_Buffer(CBPtab0[code].len); + +#ifdef TRACE + if (Trace_Flag) + { + Print_Bits(code,5,CBPtab0[code].len); + printf("): "); + Print_Bits(CBPtab0[code].val,6,6); + printf(" (%d)\n",CBPtab0[code].val); + } +#endif /* TRACE */ + + return CBPtab0[code].val; + } + + if (code>=8) + { + code >>= 1; + Flush_Buffer(CBPtab1[code].len); + +#ifdef TRACE + if (Trace_Flag) + { + Print_Bits(code,8,CBPtab1[code].len); + printf("): "); + Print_Bits(CBPtab1[code].val,6,6); + printf(" (%d)\n",CBPtab1[code].val); + } +#endif /* TRACE */ + + return CBPtab1[code].val; + } + + if (code<1) + { + if (!Quiet_Flag) + printf("Invalid coded_block_pattern code\n"); + Fault_Flag = 1; + return 0; + } + + Flush_Buffer(CBPtab2[code].len); + +#ifdef TRACE + if (Trace_Flag) + { + Print_Bits(code,9,CBPtab2[code].len); + printf("): "); + Print_Bits(CBPtab2[code].val,6,6); + printf(" (%d)\n",CBPtab2[code].val); + } +#endif /* TRACE */ + + return CBPtab2[code].val; +} + +int Get_macroblock_address_increment() +{ + int code, val; + +#ifdef TRACE + if (Trace_Flag) + printf("macroblock_address_increment ("); +#endif /* TRACE */ + + val = 0; + + while ((code = Show_Bits(11))<24) + { + if (code!=15) /* if not macroblock_stuffing */ + { + if (code==8) /* if macroblock_escape */ + { +#ifdef TRACE + if (Trace_Flag) + printf("00000001000 "); +#endif /* TRACE */ + + val+= 33; + } + else + { + if (!Quiet_Flag) + printf("Invalid macroblock_address_increment code\n"); + + Fault_Flag = 1; + return 1; + } + } + else /* macroblock suffing */ + { +#ifdef TRACE + if (Trace_Flag) + printf("00000001111 "); +#endif /* TRACE */ + } + + Flush_Buffer(11); + } + + /* macroblock_address_increment == 1 */ + /* ('1' is in the MSB position of the lookahead) */ + if (code>=1024) + { + Flush_Buffer(1); +#ifdef TRACE + if (Trace_Flag) + printf("1): %d\n",val+1); +#endif /* TRACE */ + return val + 1; + } + + /* codes 00010 ... 011xx */ + if (code>=128) + { + /* remove leading zeros */ + code >>= 6; + Flush_Buffer(MBAtab1[code].len); + +#ifdef TRACE + if (Trace_Flag) + { + Print_Bits(code,5,MBAtab1[code].len); + printf("): %d\n",val+MBAtab1[code].val); + } +#endif /* TRACE */ + + + return val + MBAtab1[code].val; + } + + /* codes 00000011000 ... 0000111xxxx */ + code-= 24; /* remove common base */ + Flush_Buffer(MBAtab2[code].len); + +#ifdef TRACE + if (Trace_Flag) + { + Print_Bits(code+24,11,MBAtab2[code].len); + printf("): %d\n",val+MBAtab2[code].val); + } +#endif /* TRACE */ + + return val + MBAtab2[code].val; +} + +/* combined MPEG-1 and MPEG-2 stage. parse VLC and + perform dct_diff arithmetic. + + MPEG-1: ISO/IEC 11172-2 section + MPEG-2: ISO/IEC 13818-2 section 7.2.1 + + Note: the arithmetic here is presented more elegantly than + the spec, yet the results, dct_diff, are the same. +*/ + +int Get_Luma_DC_dct_diff() +{ + int code, size, dct_diff; + +#ifdef TRACE +/* + if (Trace_Flag) + printf("dct_dc_size_luminance: ("); +*/ +#endif /* TRACE */ + + /* decode length */ + code = Show_Bits(5); + + if (code<31) + { + size = DClumtab0[code].val; + Flush_Buffer(DClumtab0[code].len); +#ifdef TRACE +/* + if (Trace_Flag) + { + Print_Bits(code,5,DClumtab0[code].len); + printf("): %d",size); + } +*/ +#endif /* TRACE */ + } + else + { + code = Show_Bits(9) - 0x1f0; + size = DClumtab1[code].val; + Flush_Buffer(DClumtab1[code].len); + +#ifdef TRACE +/* + if (Trace_Flag) + { + Print_Bits(code+0x1f0,9,DClumtab1[code].len); + printf("): %d",size); + } +*/ +#endif /* TRACE */ + } + +#ifdef TRACE +/* + if (Trace_Flag) + printf(", dct_dc_differential ("); +*/ +#endif /* TRACE */ + + if (size==0) + dct_diff = 0; + else + { + dct_diff = Get_Bits(size); +#ifdef TRACE +/* + if (Trace_Flag) + Print_Bits(dct_diff,size,size); +*/ +#endif /* TRACE */ + if ((dct_diff & (1<<(size-1)))==0) + dct_diff-= (1<<size) - 1; + } + +#ifdef TRACE +/* + if (Trace_Flag) + printf("): %d\n",dct_diff); +*/ +#endif /* TRACE */ + + return dct_diff; +} + + +int Get_Chroma_DC_dct_diff() +{ + int code, size, dct_diff; + +#ifdef TRACE +/* + if (Trace_Flag) + printf("dct_dc_size_chrominance: ("); +*/ +#endif /* TRACE */ + + /* decode length */ + code = Show_Bits(5); + + if (code<31) + { + size = DCchromtab0[code].val; + Flush_Buffer(DCchromtab0[code].len); + +#ifdef TRACE +/* + if (Trace_Flag) + { + Print_Bits(code,5,DCchromtab0[code].len); + printf("): %d",size); + } +*/ +#endif /* TRACE */ + } + else + { + code = Show_Bits(10) - 0x3e0; + size = DCchromtab1[code].val; + Flush_Buffer(DCchromtab1[code].len); + +#ifdef TRACE +/* + if (Trace_Flag) + { + Print_Bits(code+0x3e0,10,DCchromtab1[code].len); + printf("): %d",size); + } +*/ +#endif /* TRACE */ + } + +#ifdef TRACE +/* + if (Trace_Flag) + printf(", dct_dc_differential ("); +*/ +#endif /* TRACE */ + + if (size==0) + dct_diff = 0; + else + { + dct_diff = Get_Bits(size); +#ifdef TRACE +/* + if (Trace_Flag) + Print_Bits(dct_diff,size,size); +*/ +#endif /* TRACE */ + if ((dct_diff & (1<<(size-1)))==0) + dct_diff-= (1<<size) - 1; + } + +#ifdef TRACE +/* + if (Trace_Flag) + printf("): %d\n",dct_diff); +*/ +#endif /* TRACE */ + + return dct_diff; +} diff --git a/libfbui/MPEG/getvlc.h b/libfbui/MPEG/getvlc.h @@ -0,0 +1,491 @@ +/* getvlc.h, variable length code tables */ + +/* Copyright (C) 1996, MPEG Software Simulation Group. All Rights Reserved. */ + +/* + * Disclaimer of Warranty + * + * These software programs are available to the user without any license fee or + * royalty on an "as is" basis. The MPEG Software Simulation Group disclaims + * any and all warranties, whether express, implied, or statuary, including any + * implied warranties or merchantability or of fitness for a particular + * purpose. In no event shall the copyright-holder be liable for any + * incidental, punitive, or consequential damages of any kind whatsoever + * arising from the use of these programs. + * + * This disclaimer of warranty extends to the user of these programs and user's + * customers, employees, agents, transferees, successors, and assigns. + * + * The MPEG Software Simulation Group does not represent or warrant that the + * programs furnished hereunder are free of infringement of any third-party + * patents. + * + * Commercial implementations of MPEG-1 and MPEG-2 video, including shareware, + * are subject to royalty fees to patent holders. Many of these patents are + * general enough such that they are unavoidable regardless of implementation + * design. + * + */ + +/* NOTE: #define constants such as MACROBLOCK_QUANT are upper case + as per C programming convention. However, the MPEG document + (ISO/IEC 13818-2) lists them in all lower case (e.g. Annex B) */ + +/* NOTE: the VLC tables are in a flash format---a transformation + of the tables in Annex B to a form more convenient towards + parallel (more than one-bit-at-a-time) decoding */ + +typedef struct { + char val, len; +} VLCtab; + +typedef struct { + char run, level, len; +} DCTtab; + +/* Table B-3, macroblock_type in P-pictures, codes 001..1xx */ +static VLCtab PMBtab0[8] = { + {ERROR,0}, + {MACROBLOCK_MOTION_FORWARD,3}, + {MACROBLOCK_PATTERN,2}, {MACROBLOCK_PATTERN,2}, + {MACROBLOCK_MOTION_FORWARD|MACROBLOCK_PATTERN,1}, + {MACROBLOCK_MOTION_FORWARD|MACROBLOCK_PATTERN,1}, + {MACROBLOCK_MOTION_FORWARD|MACROBLOCK_PATTERN,1}, + {MACROBLOCK_MOTION_FORWARD|MACROBLOCK_PATTERN,1} +}; + +/* Table B-3, macroblock_type in P-pictures, codes 000001..00011x */ +static VLCtab PMBtab1[8] = { + {ERROR,0}, + {MACROBLOCK_QUANT|MACROBLOCK_INTRA,6}, + {MACROBLOCK_QUANT|MACROBLOCK_PATTERN,5}, {MACROBLOCK_QUANT|MACROBLOCK_PATTERN,5}, + {MACROBLOCK_QUANT|MACROBLOCK_MOTION_FORWARD|MACROBLOCK_PATTERN,5}, {MACROBLOCK_QUANT|MACROBLOCK_MOTION_FORWARD|MACROBLOCK_PATTERN,5}, + {MACROBLOCK_INTRA,5}, {MACROBLOCK_INTRA,5} +}; + +/* Table B-4, macroblock_type in B-pictures, codes 0010..11xx */ +static VLCtab BMBtab0[16] = { + {ERROR,0}, + {ERROR,0}, + {MACROBLOCK_MOTION_FORWARD,4}, + {MACROBLOCK_MOTION_FORWARD|MACROBLOCK_PATTERN,4}, + {MACROBLOCK_MOTION_BACKWARD,3}, + {MACROBLOCK_MOTION_BACKWARD,3}, + {MACROBLOCK_MOTION_BACKWARD|MACROBLOCK_PATTERN,3}, + {MACROBLOCK_MOTION_BACKWARD|MACROBLOCK_PATTERN,3}, + {MACROBLOCK_MOTION_FORWARD|MACROBLOCK_MOTION_BACKWARD,2}, + {MACROBLOCK_MOTION_FORWARD|MACROBLOCK_MOTION_BACKWARD,2}, + {MACROBLOCK_MOTION_FORWARD|MACROBLOCK_MOTION_BACKWARD,2}, + {MACROBLOCK_MOTION_FORWARD|MACROBLOCK_MOTION_BACKWARD,2}, + {MACROBLOCK_MOTION_FORWARD|MACROBLOCK_MOTION_BACKWARD|MACROBLOCK_PATTERN,2}, + {MACROBLOCK_MOTION_FORWARD|MACROBLOCK_MOTION_BACKWARD|MACROBLOCK_PATTERN,2}, + {MACROBLOCK_MOTION_FORWARD|MACROBLOCK_MOTION_BACKWARD|MACROBLOCK_PATTERN,2}, + {MACROBLOCK_MOTION_FORWARD|MACROBLOCK_MOTION_BACKWARD|MACROBLOCK_PATTERN,2} +}; + +/* Table B-4, macroblock_type in B-pictures, codes 000001..00011x */ +static VLCtab BMBtab1[8] = { + {ERROR,0}, + {MACROBLOCK_QUANT|MACROBLOCK_INTRA,6}, + {MACROBLOCK_QUANT|MACROBLOCK_MOTION_BACKWARD|MACROBLOCK_PATTERN,6}, + {MACROBLOCK_QUANT|MACROBLOCK_MOTION_FORWARD|MACROBLOCK_PATTERN,6}, + {MACROBLOCK_QUANT|MACROBLOCK_MOTION_FORWARD|MACROBLOCK_MOTION_BACKWARD|MACROBLOCK_PATTERN,5}, + {MACROBLOCK_QUANT|MACROBLOCK_MOTION_FORWARD|MACROBLOCK_MOTION_BACKWARD|MACROBLOCK_PATTERN,5}, + {MACROBLOCK_INTRA,5}, + {MACROBLOCK_INTRA,5} +}; + +/* Table B-5, macroblock_type in spat. scal. I-pictures, codes 0001..1xxx */ +static VLCtab spIMBtab[16] = { + {ERROR,0}, + {PERMITTED_SPATIAL_TEMPORAL_WEIGHT_CLASS,4}, + {MACROBLOCK_QUANT|MACROBLOCK_INTRA,4}, + {MACROBLOCK_INTRA,4}, + {PERMITTED_SPATIAL_TEMPORAL_WEIGHT_CLASS|MACROBLOCK_QUANT|MACROBLOCK_PATTERN,2}, {PERMITTED_SPATIAL_TEMPORAL_WEIGHT_CLASS|MACROBLOCK_QUANT|MACROBLOCK_PATTERN,2}, + {PERMITTED_SPATIAL_TEMPORAL_WEIGHT_CLASS|MACROBLOCK_QUANT|MACROBLOCK_PATTERN,2}, {PERMITTED_SPATIAL_TEMPORAL_WEIGHT_CLASS|MACROBLOCK_QUANT|MACROBLOCK_PATTERN,2}, + {PERMITTED_SPATIAL_TEMPORAL_WEIGHT_CLASS|MACROBLOCK_PATTERN,1}, {PERMITTED_SPATIAL_TEMPORAL_WEIGHT_CLASS|MACROBLOCK_PATTERN,1}, + {PERMITTED_SPATIAL_TEMPORAL_WEIGHT_CLASS|MACROBLOCK_PATTERN,1}, {PERMITTED_SPATIAL_TEMPORAL_WEIGHT_CLASS|MACROBLOCK_PATTERN,1}, + {PERMITTED_SPATIAL_TEMPORAL_WEIGHT_CLASS|MACROBLOCK_PATTERN,1}, {PERMITTED_SPATIAL_TEMPORAL_WEIGHT_CLASS|MACROBLOCK_PATTERN,1}, + {PERMITTED_SPATIAL_TEMPORAL_WEIGHT_CLASS|MACROBLOCK_PATTERN,1}, {PERMITTED_SPATIAL_TEMPORAL_WEIGHT_CLASS|MACROBLOCK_PATTERN,1} +}; + +/* Table B-6, macroblock_type in spat. scal. P-pictures, codes 0010..11xx */ +static VLCtab spPMBtab0[16] = +{ + {ERROR,0}, + {ERROR,0}, + {MACROBLOCK_MOTION_FORWARD,4}, + {SPATIAL_TEMPORAL_WEIGHT_CODE_FLAG|MACROBLOCK_MOTION_FORWARD,4}, + {MACROBLOCK_QUANT|MACROBLOCK_MOTION_FORWARD|MACROBLOCK_PATTERN,3}, {MACROBLOCK_QUANT|MACROBLOCK_MOTION_FORWARD|MACROBLOCK_PATTERN,3}, + {SPATIAL_TEMPORAL_WEIGHT_CODE_FLAG|MACROBLOCK_MOTION_FORWARD|MACROBLOCK_PATTERN,3}, {SPATIAL_TEMPORAL_WEIGHT_CODE_FLAG|MACROBLOCK_MOTION_FORWARD|MACROBLOCK_PATTERN,3}, + {MACROBLOCK_MOTION_FORWARD|MACROBLOCK_PATTERN,2}, + {MACROBLOCK_MOTION_FORWARD|MACROBLOCK_PATTERN,2}, + {MACROBLOCK_MOTION_FORWARD|MACROBLOCK_PATTERN,2}, + {MACROBLOCK_MOTION_FORWARD|MACROBLOCK_PATTERN,2}, + {SPATIAL_TEMPORAL_WEIGHT_CODE_FLAG|MACROBLOCK_QUANT|MACROBLOCK_MOTION_FORWARD|MACROBLOCK_PATTERN,2}, + {SPATIAL_TEMPORAL_WEIGHT_CODE_FLAG|MACROBLOCK_QUANT|MACROBLOCK_MOTION_FORWARD|MACROBLOCK_PATTERN,2}, + {SPATIAL_TEMPORAL_WEIGHT_CODE_FLAG|MACROBLOCK_QUANT|MACROBLOCK_MOTION_FORWARD|MACROBLOCK_PATTERN,2}, + {SPATIAL_TEMPORAL_WEIGHT_CODE_FLAG|MACROBLOCK_QUANT|MACROBLOCK_MOTION_FORWARD|MACROBLOCK_PATTERN,2} +}; + +/* Table B-6, macroblock_type in spat. scal. P-pictures, codes 0000010..000111x */ +static VLCtab spPMBtab1[16] = { + {ERROR,0}, + {ERROR,0}, + {PERMITTED_SPATIAL_TEMPORAL_WEIGHT_CLASS|MACROBLOCK_QUANT|MACROBLOCK_PATTERN,7}, + {PERMITTED_SPATIAL_TEMPORAL_WEIGHT_CLASS,7}, + {MACROBLOCK_PATTERN,7}, + {PERMITTED_SPATIAL_TEMPORAL_WEIGHT_CLASS|MACROBLOCK_PATTERN,7}, + {MACROBLOCK_QUANT|MACROBLOCK_INTRA,7}, + {MACROBLOCK_INTRA,7}, + {MACROBLOCK_QUANT|MACROBLOCK_PATTERN,6}, + {MACROBLOCK_QUANT|MACROBLOCK_PATTERN,6}, + {SPATIAL_TEMPORAL_WEIGHT_CODE_FLAG|MACROBLOCK_QUANT|MACROBLOCK_PATTERN,6}, + {SPATIAL_TEMPORAL_WEIGHT_CODE_FLAG|MACROBLOCK_QUANT|MACROBLOCK_PATTERN,6}, + {SPATIAL_TEMPORAL_WEIGHT_CODE_FLAG,6}, + {SPATIAL_TEMPORAL_WEIGHT_CODE_FLAG,6}, + {SPATIAL_TEMPORAL_WEIGHT_CODE_FLAG|MACROBLOCK_PATTERN,6}, + {SPATIAL_TEMPORAL_WEIGHT_CODE_FLAG|MACROBLOCK_PATTERN,6} +}; + +/* Table B-7, macroblock_type in spat. scal. B-pictures, codes 0010..11xx */ +static VLCtab spBMBtab0[14] = { + {MACROBLOCK_MOTION_FORWARD,4}, + {MACROBLOCK_MOTION_FORWARD|MACROBLOCK_PATTERN,4}, + {MACROBLOCK_MOTION_BACKWARD,3}, + {MACROBLOCK_MOTION_BACKWARD,3}, + {MACROBLOCK_MOTION_BACKWARD|MACROBLOCK_PATTERN,3}, + {MACROBLOCK_MOTION_BACKWARD|MACROBLOCK_PATTERN,3}, + {MACROBLOCK_MOTION_FORWARD|MACROBLOCK_MOTION_BACKWARD,2}, + {MACROBLOCK_MOTION_FORWARD|MACROBLOCK_MOTION_BACKWARD,2}, + {MACROBLOCK_MOTION_FORWARD|MACROBLOCK_MOTION_BACKWARD,2}, + {MACROBLOCK_MOTION_FORWARD|MACROBLOCK_MOTION_BACKWARD,2}, + {MACROBLOCK_MOTION_FORWARD|MACROBLOCK_MOTION_BACKWARD|MACROBLOCK_PATTERN,2}, + {MACROBLOCK_MOTION_FORWARD|MACROBLOCK_MOTION_BACKWARD|MACROBLOCK_PATTERN,2}, + {MACROBLOCK_MOTION_FORWARD|MACROBLOCK_MOTION_BACKWARD|MACROBLOCK_PATTERN,2}, + {MACROBLOCK_MOTION_FORWARD|MACROBLOCK_MOTION_BACKWARD|MACROBLOCK_PATTERN,2} +}; + +/* Table B-7, macroblock_type in spat. scal. B-pictures, codes 0000100..000111x */ +static VLCtab spBMBtab1[12] = { + {MACROBLOCK_QUANT|MACROBLOCK_MOTION_FORWARD|MACROBLOCK_PATTERN,7}, + {MACROBLOCK_QUANT|MACROBLOCK_MOTION_BACKWARD|MACROBLOCK_PATTERN,7}, + {MACROBLOCK_INTRA,7}, + {MACROBLOCK_QUANT|MACROBLOCK_MOTION_FORWARD|MACROBLOCK_MOTION_BACKWARD|MACROBLOCK_PATTERN,7}, + {SPATIAL_TEMPORAL_WEIGHT_CODE_FLAG|MACROBLOCK_MOTION_FORWARD,6}, + {SPATIAL_TEMPORAL_WEIGHT_CODE_FLAG|MACROBLOCK_MOTION_FORWARD,6}, + {SPATIAL_TEMPORAL_WEIGHT_CODE_FLAG|MACROBLOCK_MOTION_FORWARD|MACROBLOCK_PATTERN,6}, + {SPATIAL_TEMPORAL_WEIGHT_CODE_FLAG|MACROBLOCK_MOTION_FORWARD|MACROBLOCK_PATTERN,6}, + {SPATIAL_TEMPORAL_WEIGHT_CODE_FLAG|MACROBLOCK_MOTION_BACKWARD,6}, + {SPATIAL_TEMPORAL_WEIGHT_CODE_FLAG|MACROBLOCK_MOTION_BACKWARD,6}, + {SPATIAL_TEMPORAL_WEIGHT_CODE_FLAG|MACROBLOCK_MOTION_BACKWARD|MACROBLOCK_PATTERN,6}, + {SPATIAL_TEMPORAL_WEIGHT_CODE_FLAG|MACROBLOCK_MOTION_BACKWARD|MACROBLOCK_PATTERN,6} +}; + +/* Table B-7, macroblock_type in spat. scal. B-pictures, codes 00000100x..000001111 */ +static VLCtab spBMBtab2[8] = { + {MACROBLOCK_QUANT|MACROBLOCK_INTRA,8}, + {MACROBLOCK_QUANT|MACROBLOCK_INTRA,8}, + {SPATIAL_TEMPORAL_WEIGHT_CODE_FLAG|MACROBLOCK_QUANT|MACROBLOCK_MOTION_FORWARD|MACROBLOCK_PATTERN,8}, + {SPATIAL_TEMPORAL_WEIGHT_CODE_FLAG|MACROBLOCK_QUANT|MACROBLOCK_MOTION_FORWARD|MACROBLOCK_PATTERN,8}, + {SPATIAL_TEMPORAL_WEIGHT_CODE_FLAG|MACROBLOCK_QUANT|MACROBLOCK_MOTION_BACKWARD|MACROBLOCK_PATTERN,9}, + {PERMITTED_SPATIAL_TEMPORAL_WEIGHT_CLASS|MACROBLOCK_QUANT|MACROBLOCK_PATTERN,9}, + {PERMITTED_SPATIAL_TEMPORAL_WEIGHT_CLASS,9}, + {PERMITTED_SPATIAL_TEMPORAL_WEIGHT_CLASS|MACROBLOCK_PATTERN,9} +}; + +/* Table B-8, macroblock_type in spat. scal. B-pictures, codes 001..1xx */ +static VLCtab SNRMBtab[8] = { + {ERROR,0}, + {0,3}, + {MACROBLOCK_QUANT|MACROBLOCK_PATTERN,2}, + {MACROBLOCK_QUANT|MACROBLOCK_PATTERN,2}, + {MACROBLOCK_PATTERN,1}, + {MACROBLOCK_PATTERN,1}, + {MACROBLOCK_PATTERN,1}, + {MACROBLOCK_PATTERN,1} +}; + +/* Table B-10, motion_code, codes 0001 ... 01xx */ +static VLCtab MVtab0[8] = +{ {ERROR,0}, {3,3}, {2,2}, {2,2}, {1,1}, {1,1}, {1,1}, {1,1} +}; + +/* Table B-10, motion_code, codes 0000011 ... 000011x */ +static VLCtab MVtab1[8] = +{ {ERROR,0}, {ERROR,0}, {ERROR,0}, {7,6}, {6,6}, {5,6}, {4,5}, {4,5} +}; + +/* Table B-10, motion_code, codes 0000001100 ... 000001011x */ +static VLCtab MVtab2[12] = +{ {16,9}, {15,9}, {14,9}, {13,9}, + {12,9}, {11,9}, {10,8}, {10,8}, + {9,8}, {9,8}, {8,8}, {8,8} +}; + +/* Table B-9, coded_block_pattern, codes 01000 ... 111xx */ +static VLCtab CBPtab0[32] = +{ {ERROR,0}, {ERROR,0}, {ERROR,0}, {ERROR,0}, + {ERROR,0}, {ERROR,0}, {ERROR,0}, {ERROR,0}, + {62,5}, {2,5}, {61,5}, {1,5}, {56,5}, {52,5}, {44,5}, {28,5}, + {40,5}, {20,5}, {48,5}, {12,5}, {32,4}, {32,4}, {16,4}, {16,4}, + {8,4}, {8,4}, {4,4}, {4,4}, {60,3}, {60,3}, {60,3}, {60,3} +}; + +/* Table B-9, coded_block_pattern, codes 00000100 ... 001111xx */ +static VLCtab CBPtab1[64] = +{ {ERROR,0}, {ERROR,0}, {ERROR,0}, {ERROR,0}, + {58,8}, {54,8}, {46,8}, {30,8}, + {57,8}, {53,8}, {45,8}, {29,8}, {38,8}, {26,8}, {37,8}, {25,8}, + {43,8}, {23,8}, {51,8}, {15,8}, {42,8}, {22,8}, {50,8}, {14,8}, + {41,8}, {21,8}, {49,8}, {13,8}, {35,8}, {19,8}, {11,8}, {7,8}, + {34,7}, {34,7}, {18,7}, {18,7}, {10,7}, {10,7}, {6,7}, {6,7}, + {33,7}, {33,7}, {17,7}, {17,7}, {9,7}, {9,7}, {5,7}, {5,7}, + {63,6}, {63,6}, {63,6}, {63,6}, {3,6}, {3,6}, {3,6}, {3,6}, + {36,6}, {36,6}, {36,6}, {36,6}, {24,6}, {24,6}, {24,6}, {24,6} +}; + +/* Table B-9, coded_block_pattern, codes 000000001 ... 000000111 */ +static VLCtab CBPtab2[8] = +{ {ERROR,0}, {0,9}, {39,9}, {27,9}, {59,9}, {55,9}, {47,9}, {31,9} +}; + +/* Table B-1, macroblock_address_increment, codes 00010 ... 011xx */ +static VLCtab MBAtab1[16] = +{ {ERROR,0}, {ERROR,0}, {7,5}, {6,5}, {5,4}, {5,4}, {4,4}, {4,4}, + {3,3}, {3,3}, {3,3}, {3,3}, {2,3}, {2,3}, {2,3}, {2,3} +}; + +/* Table B-1, macroblock_address_increment, codes 00000011000 ... 0000111xxxx */ +static VLCtab MBAtab2[104] = +{ + {33,11}, {32,11}, {31,11}, {30,11}, {29,11}, {28,11}, {27,11}, {26,11}, + {25,11}, {24,11}, {23,11}, {22,11}, {21,10}, {21,10}, {20,10}, {20,10}, + {19,10}, {19,10}, {18,10}, {18,10}, {17,10}, {17,10}, {16,10}, {16,10}, + {15,8}, {15,8}, {15,8}, {15,8}, {15,8}, {15,8}, {15,8}, {15,8}, + {14,8}, {14,8}, {14,8}, {14,8}, {14,8}, {14,8}, {14,8}, {14,8}, + {13,8}, {13,8}, {13,8}, {13,8}, {13,8}, {13,8}, {13,8}, {13,8}, + {12,8}, {12,8}, {12,8}, {12,8}, {12,8}, {12,8}, {12,8}, {12,8}, + {11,8}, {11,8}, {11,8}, {11,8}, {11,8}, {11,8}, {11,8}, {11,8}, + {10,8}, {10,8}, {10,8}, {10,8}, {10,8}, {10,8}, {10,8}, {10,8}, + {9,7}, {9,7}, {9,7}, {9,7}, {9,7}, {9,7}, {9,7}, {9,7}, + {9,7}, {9,7}, {9,7}, {9,7}, {9,7}, {9,7}, {9,7}, {9,7}, + {8,7}, {8,7}, {8,7}, {8,7}, {8,7}, {8,7}, {8,7}, {8,7}, + {8,7}, {8,7}, {8,7}, {8,7}, {8,7}, {8,7}, {8,7}, {8,7} +}; + +/* Table B-12, dct_dc_size_luminance, codes 00xxx ... 11110 */ +static VLCtab DClumtab0[32] = +{ {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, + {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, + {0, 3}, {0, 3}, {0, 3}, {0, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, + {4, 3}, {4, 3}, {4, 3}, {4, 3}, {5, 4}, {5, 4}, {6, 5}, {ERROR, 0} +}; + +/* Table B-12, dct_dc_size_luminance, codes 111110xxx ... 111111111 */ +static VLCtab DClumtab1[16] = +{ {7, 6}, {7, 6}, {7, 6}, {7, 6}, {7, 6}, {7, 6}, {7, 6}, {7, 6}, + {8, 7}, {8, 7}, {8, 7}, {8, 7}, {9, 8}, {9, 8}, {10,9}, {11,9} +}; + +/* Table B-13, dct_dc_size_chrominance, codes 00xxx ... 11110 */ +static VLCtab DCchromtab0[32] = +{ {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, + {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, + {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, + {3, 3}, {3, 3}, {3, 3}, {3, 3}, {4, 4}, {4, 4}, {5, 5}, {ERROR, 0} +}; + +/* Table B-13, dct_dc_size_chrominance, codes 111110xxxx ... 1111111111 */ +static VLCtab DCchromtab1[32] = +{ {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, + {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, + {7, 7}, {7, 7}, {7, 7}, {7, 7}, {7, 7}, {7, 7}, {7, 7}, {7, 7}, + {8, 8}, {8, 8}, {8, 8}, {8, 8}, {9, 9}, {9, 9}, {10,10}, {11,10} +}; + +/* Table B-14, DCT coefficients table zero, + * codes 0100 ... 1xxx (used for first (DC) coefficient) + */ +DCTtab DCTtabfirst[12] = +{ + {0,2,4}, {2,1,4}, {1,1,3}, {1,1,3}, + {0,1,1}, {0,1,1}, {0,1,1}, {0,1,1}, + {0,1,1}, {0,1,1}, {0,1,1}, {0,1,1} +}; + +/* Table B-14, DCT coefficients table zero, + * codes 0100 ... 1xxx (used for all other coefficients) + */ +DCTtab DCTtabnext[12] = +{ + {0,2,4}, {2,1,4}, {1,1,3}, {1,1,3}, + {64,0,2}, {64,0,2}, {64,0,2}, {64,0,2}, /* EOB */ + {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2} +}; + +/* Table B-14, DCT coefficients table zero, + * codes 000001xx ... 00111xxx + */ +DCTtab DCTtab0[60] = +{ + {65,0,6}, {65,0,6}, {65,0,6}, {65,0,6}, /* Escape */ + {2,2,7}, {2,2,7}, {9,1,7}, {9,1,7}, + {0,4,7}, {0,4,7}, {8,1,7}, {8,1,7}, + {7,1,6}, {7,1,6}, {7,1,6}, {7,1,6}, + {6,1,6}, {6,1,6}, {6,1,6}, {6,1,6}, + {1,2,6}, {1,2,6}, {1,2,6}, {1,2,6}, + {5,1,6}, {5,1,6}, {5,1,6}, {5,1,6}, + {13,1,8}, {0,6,8}, {12,1,8}, {11,1,8}, + {3,2,8}, {1,3,8}, {0,5,8}, {10,1,8}, + {0,3,5}, {0,3,5}, {0,3,5}, {0,3,5}, + {0,3,5}, {0,3,5}, {0,3,5}, {0,3,5}, + {4,1,5}, {4,1,5}, {4,1,5}, {4,1,5}, + {4,1,5}, {4,1,5}, {4,1,5}, {4,1,5}, + {3,1,5}, {3,1,5}, {3,1,5}, {3,1,5}, + {3,1,5}, {3,1,5}, {3,1,5}, {3,1,5} +}; + +/* Table B-15, DCT coefficients table one, + * codes 000001xx ... 11111111 +*/ +DCTtab DCTtab0a[252] = +{ + {65,0,6}, {65,0,6}, {65,0,6}, {65,0,6}, /* Escape */ + {7,1,7}, {7,1,7}, {8,1,7}, {8,1,7}, + {6,1,7}, {6,1,7}, {2,2,7}, {2,2,7}, + {0,7,6}, {0,7,6}, {0,7,6}, {0,7,6}, + {0,6,6}, {0,6,6}, {0,6,6}, {0,6,6}, + {4,1,6}, {4,1,6}, {4,1,6}, {4,1,6}, + {5,1,6}, {5,1,6}, {5,1,6}, {5,1,6}, + {1,5,8}, {11,1,8}, {0,11,8}, {0,10,8}, + {13,1,8}, {12,1,8}, {3,2,8}, {1,4,8}, + {2,1,5}, {2,1,5}, {2,1,5}, {2,1,5}, + {2,1,5}, {2,1,5}, {2,1,5}, {2,1,5}, + {1,2,5}, {1,2,5}, {1,2,5}, {1,2,5}, + {1,2,5}, {1,2,5}, {1,2,5}, {1,2,5}, + {3,1,5}, {3,1,5}, {3,1,5}, {3,1,5}, + {3,1,5}, {3,1,5}, {3,1,5}, {3,1,5}, + {1,1,3}, {1,1,3}, {1,1,3}, {1,1,3}, + {1,1,3}, {1,1,3}, {1,1,3}, {1,1,3}, + {1,1,3}, {1,1,3}, {1,1,3}, {1,1,3}, + {1,1,3}, {1,1,3}, {1,1,3}, {1,1,3}, + {1,1,3}, {1,1,3}, {1,1,3}, {1,1,3}, + {1,1,3}, {1,1,3}, {1,1,3}, {1,1,3}, + {1,1,3}, {1,1,3}, {1,1,3}, {1,1,3}, + {1,1,3}, {1,1,3}, {1,1,3}, {1,1,3}, + {64,0,4}, {64,0,4}, {64,0,4}, {64,0,4}, /* EOB */ + {64,0,4}, {64,0,4}, {64,0,4}, {64,0,4}, + {64,0,4}, {64,0,4}, {64,0,4}, {64,0,4}, + {64,0,4}, {64,0,4}, {64,0,4}, {64,0,4}, + {0,3,4}, {0,3,4}, {0,3,4}, {0,3,4}, + {0,3,4}, {0,3,4}, {0,3,4}, {0,3,4}, + {0,3,4}, {0,3,4}, {0,3,4}, {0,3,4}, + {0,3,4}, {0,3,4}, {0,3,4}, {0,3,4}, + {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, + {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, + {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, + {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, + {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, + {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, + {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, + {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, + {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, + {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, + {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, + {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, + {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, + {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, + {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, + {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, + {0,2,3}, {0,2,3}, {0,2,3}, {0,2,3}, + {0,2,3}, {0,2,3}, {0,2,3}, {0,2,3}, + {0,2,3}, {0,2,3}, {0,2,3}, {0,2,3}, + {0,2,3}, {0,2,3}, {0,2,3}, {0,2,3}, + {0,2,3}, {0,2,3}, {0,2,3}, {0,2,3}, + {0,2,3}, {0,2,3}, {0,2,3}, {0,2,3}, + {0,2,3}, {0,2,3}, {0,2,3}, {0,2,3}, + {0,2,3}, {0,2,3}, {0,2,3}, {0,2,3}, + {0,4,5}, {0,4,5}, {0,4,5}, {0,4,5}, + {0,4,5}, {0,4,5}, {0,4,5}, {0,4,5}, + {0,5,5}, {0,5,5}, {0,5,5}, {0,5,5}, + {0,5,5}, {0,5,5}, {0,5,5}, {0,5,5}, + {9,1,7}, {9,1,7}, {1,3,7}, {1,3,7}, + {10,1,7}, {10,1,7}, {0,8,7}, {0,8,7}, + {0,9,7}, {0,9,7}, {0,12,8}, {0,13,8}, + {2,3,8}, {4,2,8}, {0,14,8}, {0,15,8} +}; + +/* Table B-14, DCT coefficients table zero, + * codes 0000001000 ... 0000001111 + */ +DCTtab DCTtab1[8] = +{ + {16,1,10}, {5,2,10}, {0,7,10}, {2,3,10}, + {1,4,10}, {15,1,10}, {14,1,10}, {4,2,10} +}; + +/* Table B-15, DCT coefficients table one, + * codes 000000100x ... 000000111x + */ +DCTtab DCTtab1a[8] = +{ + {5,2,9}, {5,2,9}, {14,1,9}, {14,1,9}, + {2,4,10}, {16,1,10}, {15,1,9}, {15,1,9} +}; + +/* Table B-14/15, DCT coefficients table zero / one, + * codes 000000010000 ... 000000011111 + */ +DCTtab DCTtab2[16] = +{ + {0,11,12}, {8,2,12}, {4,3,12}, {0,10,12}, + {2,4,12}, {7,2,12}, {21,1,12}, {20,1,12}, + {0,9,12}, {19,1,12}, {18,1,12}, {1,5,12}, + {3,3,12}, {0,8,12}, {6,2,12}, {17,1,12} +}; + +/* Table B-14/15, DCT coefficients table zero / one, + * codes 0000000010000 ... 0000000011111 + */ +DCTtab DCTtab3[16] = +{ + {10,2,13}, {9,2,13}, {5,3,13}, {3,4,13}, + {2,5,13}, {1,7,13}, {1,6,13}, {0,15,13}, + {0,14,13}, {0,13,13}, {0,12,13}, {26,1,13}, + {25,1,13}, {24,1,13}, {23,1,13}, {22,1,13} +}; + +/* Table B-14/15, DCT coefficients table zero / one, + * codes 00000000010000 ... 00000000011111 + */ +DCTtab DCTtab4[16] = +{ + {0,31,14}, {0,30,14}, {0,29,14}, {0,28,14}, + {0,27,14}, {0,26,14}, {0,25,14}, {0,24,14}, + {0,23,14}, {0,22,14}, {0,21,14}, {0,20,14}, + {0,19,14}, {0,18,14}, {0,17,14}, {0,16,14} +}; + +/* Table B-14/15, DCT coefficients table zero / one, + * codes 000000000010000 ... 000000000011111 + */ +DCTtab DCTtab5[16] = +{ + {0,40,15}, {0,39,15}, {0,38,15}, {0,37,15}, + {0,36,15}, {0,35,15}, {0,34,15}, {0,33,15}, + {0,32,15}, {1,14,15}, {1,13,15}, {1,12,15}, + {1,11,15}, {1,10,15}, {1,9,15}, {1,8,15} +}; + +/* Table B-14/15, DCT coefficients table zero / one, + * codes 0000000000010000 ... 0000000000011111 + */ +DCTtab DCTtab6[16] = +{ + {1,18,16}, {1,17,16}, {1,16,16}, {1,15,16}, + {6,3,16}, {16,2,16}, {15,2,16}, {14,2,16}, + {13,2,16}, {12,2,16}, {11,2,16}, {31,1,16}, + {30,1,16}, {29,1,16}, {28,1,16}, {27,1,16} +}; + diff --git a/libfbui/MPEG/global.h b/libfbui/MPEG/global.h @@ -0,0 +1,489 @@ +/* global.h, global variables */ + +/* Copyright (C) 1996, MPEG Software Simulation Group. All Rights Reserved. */ + +/* + * Disclaimer of Warranty + * + * These software programs are available to the user without any license fee or + * royalty on an "as is" basis. The MPEG Software Simulation Group disclaims + * any and all warranties, whether express, implied, or statuary, including any + * implied warranties or merchantability or of fitness for a particular + * purpose. In no event shall the copyright-holder be liable for any + * incidental, punitive, or consequential damages of any kind whatsoever + * arising from the use of these programs. + * + * This disclaimer of warranty extends to the user of these programs and user's + * customers, employees, agents, transferees, successors, and assigns. + * + * The MPEG Software Simulation Group does not represent or warrant that the + * programs furnished hereunder are free of infringement of any third-party + * patents. + * + * Commercial implementations of MPEG-1 and MPEG-2 video, including shareware, + * are subject to royalty fees to patent holders. Many of these patents are + * general enough such that they are unavoidable regardless of implementation + * design. + * + */ + +#include "mpeg2dec.h" + +/* choose between declaration (GLOBAL undefined) + * and definition (GLOBAL defined) + * GLOBAL is defined in exactly one file mpeg2dec.c) + */ + +#ifndef GLOBAL +#define EXTERN extern +#else +#define EXTERN +#endif + +/* prototypes of global functions */ +/* readpic.c */ +void Substitute_Frame_Buffer _ANSI_ARGS_ ((int bitstream_framenum, + int sequence_framenum)); + +/* Get_Bits.c */ +void Initialize_Buffer _ANSI_ARGS_((void)); +void Fill_Buffer _ANSI_ARGS_((void)); +unsigned int Show_Bits _ANSI_ARGS_((int n)); +unsigned int Get_Bits1 _ANSI_ARGS_((void)); +void Flush_Buffer _ANSI_ARGS_((int n)); +unsigned int Get_Bits _ANSI_ARGS_((int n)); +int Get_Byte _ANSI_ARGS_((void)); +int Get_Word _ANSI_ARGS_((void)); + +/* systems.c */ +void Next_Packet _ANSI_ARGS_((void)); +int Get_Long _ANSI_ARGS_((void)); +void Flush_Buffer32 _ANSI_ARGS_((void)); +unsigned int Get_Bits32 _ANSI_ARGS_((void)); + + +/* getblk.c */ +void Decode_MPEG1_Intra_Block _ANSI_ARGS_((int comp, int dc_dct_pred[])); +void Decode_MPEG1_Non_Intra_Block _ANSI_ARGS_((int comp)); +void Decode_MPEG2_Intra_Block _ANSI_ARGS_((int comp, int dc_dct_pred[])); +void Decode_MPEG2_Non_Intra_Block _ANSI_ARGS_((int comp)); + +/* gethdr.c */ +int Get_Hdr _ANSI_ARGS_((void)); +void next_start_code _ANSI_ARGS_((void)); +int slice_header _ANSI_ARGS_((void)); +void marker_bit _ANSI_ARGS_((char *text)); + +/* getpic.c */ +void Decode_Picture _ANSI_ARGS_((int bitstream_framenum, + int sequence_framenum)); +void Output_Last_Frame_of_Sequence _ANSI_ARGS_((int framenum)); + +/* getvlc.c */ +int Get_macroblock_type _ANSI_ARGS_((void)); +int Get_motion_code _ANSI_ARGS_((void)); +int Get_dmvector _ANSI_ARGS_((void)); +int Get_coded_block_pattern _ANSI_ARGS_((void)); +int Get_macroblock_address_increment _ANSI_ARGS_((void)); +int Get_Luma_DC_dct_diff _ANSI_ARGS_((void)); +int Get_Chroma_DC_dct_diff _ANSI_ARGS_((void)); + +/* idct.c */ +void Fast_IDCT _ANSI_ARGS_((short *block)); +void Initialize_Fast_IDCT _ANSI_ARGS_((void)); + +/* Reference_IDCT.c */ +void Initialize_Reference_IDCT _ANSI_ARGS_((void)); +void Reference_IDCT _ANSI_ARGS_((short *block)); + +/* motion.c */ +void motion_vectors _ANSI_ARGS_((int PMV[2][2][2], int dmvector[2], + int motion_vertical_field_select[2][2], int s, int motion_vector_count, + int mv_format, int h_r_size, int v_r_size, int dmv, int mvscale)); +void motion_vector _ANSI_ARGS_((int *PMV, int *dmvector, + int h_r_size, int v_r_size, int dmv, int mvscale, int full_pel_vector)); +void Dual_Prime_Arithmetic _ANSI_ARGS_((int DMV[][2], int *dmvector, int mvx, int mvy)); + +/* mpeg2dec.c */ +void Error _ANSI_ARGS_((char *text)); +void Warning _ANSI_ARGS_((char *text)); +void Print_Bits _ANSI_ARGS_((int code, int bits, int len)); + +/* recon.c */ +void form_predictions _ANSI_ARGS_((int bx, int by, int macroblock_type, + int motion_type, int PMV[2][2][2], int motion_vertical_field_select[2][2], + int dmvector[2], int stwtype)); + +/* spatscal.c */ +void Spatial_Prediction _ANSI_ARGS_((void)); + +/* store.c */ +void Write_Frame _ANSI_ARGS_((unsigned char *src[], int frame)); + +#ifdef DISPLAY +/* display.c */ +void Initialize_Display_Process _ANSI_ARGS_((char *name)); +void Terminate_Display_Process _ANSI_ARGS_((void)); +void Display_Second_Field _ANSI_ARGS_((void)); +void dither _ANSI_ARGS_((unsigned char *src[])); +void Initialize_Dither_Matrix _ANSI_ARGS_((void)); +#endif + +/* global variables */ + +EXTERN char Version[] +#ifdef GLOBAL + ="mpeg2decode V1.2a, 96/07/19" +#endif +; + +EXTERN char Author[] +#ifdef GLOBAL + ="(C) 1996, MPEG Software Simulation Group" +#endif +; + + +/* zig-zag and alternate scan patterns */ +EXTERN unsigned char scan[2][64] +#ifdef GLOBAL += +{ + { /* Zig-Zag scan pattern */ + 0,1,8,16,9,2,3,10,17,24,32,25,18,11,4,5, + 12,19,26,33,40,48,41,34,27,20,13,6,7,14,21,28, + 35,42,49,56,57,50,43,36,29,22,15,23,30,37,44,51, + 58,59,52,45,38,31,39,46,53,60,61,54,47,55,62,63 + }, + { /* Alternate scan pattern */ + 0,8,16,24,1,9,2,10,17,25,32,40,48,56,57,49, + 41,33,26,18,3,11,4,12,19,27,34,42,50,58,35,43, + 51,59,20,28,5,13,6,14,21,29,36,44,52,60,37,45, + 53,61,22,30,7,15,23,31,38,46,54,62,39,47,55,63 + } +} +#endif +; + +/* default intra quantization matrix */ +EXTERN unsigned char default_intra_quantizer_matrix[64] +#ifdef GLOBAL += +{ + 8, 16, 19, 22, 26, 27, 29, 34, + 16, 16, 22, 24, 27, 29, 34, 37, + 19, 22, 26, 27, 29, 34, 34, 38, + 22, 22, 26, 27, 29, 34, 37, 40, + 22, 26, 27, 29, 32, 35, 40, 48, + 26, 27, 29, 32, 35, 40, 48, 58, + 26, 27, 29, 34, 38, 46, 56, 69, + 27, 29, 35, 38, 46, 56, 69, 83 +} +#endif +; + +/* non-linear quantization coefficient table */ +EXTERN unsigned char Non_Linear_quantizer_scale[32] +#ifdef GLOBAL += +{ + 0, 1, 2, 3, 4, 5, 6, 7, + 8,10,12,14,16,18,20,22, + 24,28,32,36,40,44,48,52, + 56,64,72,80,88,96,104,112 +} +#endif +; + +/* color space conversion coefficients + * for YCbCr -> RGB mapping + * + * entries are {crv,cbu,cgu,cgv} + * + * crv=(255/224)*65536*(1-cr)/0.5 + * cbu=(255/224)*65536*(1-cb)/0.5 + * cgu=(255/224)*65536*(cb/cg)*(1-cb)/0.5 + * cgv=(255/224)*65536*(cr/cg)*(1-cr)/0.5 + * + * where Y=cr*R+cg*G+cb*B (cr+cg+cb=1) + */ + +/* ISO/IEC 13818-2 section 6.3.6 sequence_display_extension() */ + +EXTERN int Inverse_Table_6_9[8][4] +#ifdef GLOBAL += +{ + {117504, 138453, 13954, 34903}, /* no sequence_display_extension */ + {117504, 138453, 13954, 34903}, /* ITU-R Rec. 709 (1990) */ + {104597, 132201, 25675, 53279}, /* unspecified */ + {104597, 132201, 25675, 53279}, /* reserved */ + {104448, 132798, 24759, 53109}, /* FCC */ + {104597, 132201, 25675, 53279}, /* ITU-R Rec. 624-4 System B, G */ + {104597, 132201, 25675, 53279}, /* SMPTE 170M */ + {117579, 136230, 16907, 35559} /* SMPTE 240M (1987) */ +} +#endif +; + + + + + +/* output types (Output_Type) */ +#define T_YUV 0 +#define T_SIF 1 +#define T_TGA 2 +#define T_PPM 3 +#define T_X11 4 +#define T_X11HIQ 5 +#define T_FBUI 6 + +/* decoder operation control variables */ +EXTERN int Output_Type; +EXTERN int hiQdither; + +/* decoder operation control flags */ +EXTERN int Quiet_Flag; +EXTERN int Trace_Flag; +EXTERN int Fault_Flag; +EXTERN int Verbose_Flag; +EXTERN int Two_Streams; +EXTERN int Spatial_Flag; +EXTERN int Reference_IDCT_Flag; +EXTERN int Frame_Store_Flag; +EXTERN int System_Stream_Flag; +EXTERN int Display_Progressive_Flag; +EXTERN int Ersatz_Flag; +EXTERN int Big_Picture_Flag; +EXTERN int Verify_Flag; +EXTERN int Stats_Flag; +EXTERN int User_Data_Flag; +EXTERN int Main_Bitstream_Flag; + + +/* filenames */ +EXTERN char *Output_Picture_Filename; +EXTERN char *Substitute_Picture_Filename; +EXTERN char *Main_Bitstream_Filename; +EXTERN char *Enhancement_Layer_Bitstream_Filename; + + +/* buffers for multiuse purposes */ +EXTERN char Error_Text[256]; +EXTERN unsigned char *Clip; + +/* pointers to generic picture buffers */ +EXTERN unsigned char *backward_reference_frame[3]; +EXTERN unsigned char *forward_reference_frame[3]; + +EXTERN unsigned char *auxframe[3]; +EXTERN unsigned char *current_frame[3]; +EXTERN unsigned char *substitute_frame[3]; + + +/* pointers to scalability picture buffers */ +EXTERN unsigned char *llframe0[3]; +EXTERN unsigned char *llframe1[3]; + +EXTERN short *lltmp; +EXTERN char *Lower_Layer_Picture_Filename; + + + + +/* non-normative variables derived from normative elements */ +EXTERN int Coded_Picture_Width; +EXTERN int Coded_Picture_Height; +EXTERN int Chroma_Width; +EXTERN int Chroma_Height; +EXTERN int block_count; +EXTERN int Second_Field; +EXTERN int profile, level; + +/* normative derived variables (as per ISO/IEC 13818-2) */ +EXTERN int horizontal_size; +EXTERN int vertical_size; +EXTERN int mb_width; +EXTERN int mb_height; +EXTERN double bit_rate; +EXTERN double frame_rate; + + + +/* headers */ + +/* ISO/IEC 13818-2 section 6.2.2.1: sequence_header() */ +EXTERN int aspect_ratio_information; +EXTERN int frame_rate_code; +EXTERN int bit_rate_value; +EXTERN int vbv_buffer_size; +EXTERN int constrained_parameters_flag; + +/* ISO/IEC 13818-2 section 6.2.2.3: sequence_extension() */ +EXTERN int profile_and_level_indication; +EXTERN int progressive_sequence; +EXTERN int chroma_format; +EXTERN int low_delay; +EXTERN int frame_rate_extension_n; +EXTERN int frame_rate_extension_d; + +/* ISO/IEC 13818-2 section 6.2.2.4: sequence_display_extension() */ +EXTERN int video_format; +EXTERN int color_description; +EXTERN int color_primaries; +EXTERN int transfer_characteristics; +EXTERN int matrix_coefficients; +EXTERN int display_horizontal_size; +EXTERN int display_vertical_size; + +/* ISO/IEC 13818-2 section 6.2.3: picture_header() */ +EXTERN int temporal_reference; +EXTERN int picture_coding_type; +EXTERN int vbv_delay; +EXTERN int full_pel_forward_vector; +EXTERN int forward_f_code; +EXTERN int full_pel_backward_vector; +EXTERN int backward_f_code; + + +/* ISO/IEC 13818-2 section 6.2.3.1: picture_coding_extension() header */ +EXTERN int f_code[2][2]; +EXTERN int intra_dc_precision; +EXTERN int picture_structure; +EXTERN int top_field_first; +EXTERN int frame_pred_frame_dct; +EXTERN int concealment_motion_vectors; + +EXTERN int intra_vlc_format; + +EXTERN int repeat_first_field; + +EXTERN int chroma_420_type; +EXTERN int progressive_frame; +EXTERN int composite_display_flag; +EXTERN int v_axis; +EXTERN int field_sequence; +EXTERN int sub_carrier; +EXTERN int burst_amplitude; +EXTERN int sub_carrier_phase; + + + +/* ISO/IEC 13818-2 section 6.2.3.3: picture_display_extension() header */ +EXTERN int frame_center_horizontal_offset[3]; +EXTERN int frame_center_vertical_offset[3]; + + + +/* ISO/IEC 13818-2 section 6.2.2.5: sequence_scalable_extension() header */ +EXTERN int layer_id; +EXTERN int lower_layer_prediction_horizontal_size; +EXTERN int lower_layer_prediction_vertical_size; +EXTERN int horizontal_subsampling_factor_m; +EXTERN int horizontal_subsampling_factor_n; +EXTERN int vertical_subsampling_factor_m; +EXTERN int vertical_subsampling_factor_n; + + +/* ISO/IEC 13818-2 section 6.2.3.5: picture_spatial_scalable_extension() header */ +EXTERN int lower_layer_temporal_reference; +EXTERN int lower_layer_horizontal_offset; +EXTERN int lower_layer_vertical_offset; +EXTERN int spatial_temporal_weight_code_table_index; +EXTERN int lower_layer_progressive_frame; +EXTERN int lower_layer_deinterlaced_field_select; + + + + + + +/* ISO/IEC 13818-2 section 6.2.3.6: copyright_extension() header */ +EXTERN int copyright_flag; +EXTERN int copyright_identifier; +EXTERN int original_or_copy; +EXTERN int copyright_number_1; +EXTERN int copyright_number_2; +EXTERN int copyright_number_3; + +/* ISO/IEC 13818-2 section 6.2.2.6: group_of_pictures_header() */ +EXTERN int drop_flag; +EXTERN int hour; +EXTERN int minute; +EXTERN int sec; +EXTERN int frame; +EXTERN int closed_gop; +EXTERN int broken_link; + + + +/* layer specific variables (needed for SNR and DP scalability) */ +EXTERN struct layer_data { + /* bit input */ + int Infile; + unsigned char Rdbfr[2048]; + unsigned char *Rdptr; + unsigned char Inbfr[16]; + /* from mpeg2play */ + unsigned int Bfr; + unsigned char *Rdmax; + int Incnt; + int Bitcnt; + /* sequence header and quant_matrix_extension() */ + int intra_quantizer_matrix[64]; + int non_intra_quantizer_matrix[64]; + int chroma_intra_quantizer_matrix[64]; + int chroma_non_intra_quantizer_matrix[64]; + + int load_intra_quantizer_matrix; + int load_non_intra_quantizer_matrix; + int load_chroma_intra_quantizer_matrix; + int load_chroma_non_intra_quantizer_matrix; + + int MPEG2_Flag; + /* sequence scalable extension */ + int scalable_mode; + /* picture coding extension */ + int q_scale_type; + int alternate_scan; + /* picture spatial scalable extension */ + int pict_scal; + /* slice/macroblock */ + int priority_breakpoint; + int quantizer_scale; + int intra_slice; + short block[12][64]; +} base, enhan, *ld; + + + +#ifdef VERIFY +EXTERN int verify_sequence_header; +EXTERN int verify_group_of_pictures_header; +EXTERN int verify_picture_header; +EXTERN int verify_slice_header; +EXTERN int verify_sequence_extension; +EXTERN int verify_sequence_display_extension; +EXTERN int verify_quant_matrix_extension; +EXTERN int verify_sequence_scalable_extension; +EXTERN int verify_picture_display_extension; +EXTERN int verify_picture_coding_extension; +EXTERN int verify_picture_spatial_scalable_extension; +EXTERN int verify_picture_temporal_scalable_extension; +EXTERN int verify_copyright_extension; +#endif /* VERIFY */ + + +EXTERN int Decode_Layer; + +/* verify.c */ +#ifdef VERIFY +void Check_Headers _ANSI_ARGS_((int Bitstream_Framenum, int Sequence_Framenum)); +void Clear_Verify_Headers _ANSI_ARGS_((void)); +#endif /* VERIFY */ + + +EXTERN int global_MBA; +EXTERN int global_pic; +EXTERN int True_Framenum; diff --git a/libfbui/MPEG/idct.c b/libfbui/MPEG/idct.c @@ -0,0 +1,211 @@ +/* idct.c, inverse fast discrete cosine transform */ + +/* Copyright (C) 1996, MPEG Software Simulation Group. All Rights Reserved. */ + +/* + * Disclaimer of Warranty + * + * These software programs are available to the user without any license fee or + * royalty on an "as is" basis. The MPEG Software Simulation Group disclaims + * any and all warranties, whether express, implied, or statuary, including any + * implied warranties or merchantability or of fitness for a particular + * purpose. In no event shall the copyright-holder be liable for any + * incidental, punitive, or consequential damages of any kind whatsoever + * arising from the use of these programs. + * + * This disclaimer of warranty extends to the user of these programs and user's + * customers, employees, agents, transferees, successors, and assigns. + * + * The MPEG Software Simulation Group does not represent or warrant that the + * programs furnished hereunder are free of infringement of any third-party + * patents. + * + * Commercial implementations of MPEG-1 and MPEG-2 video, including shareware, + * are subject to royalty fees to patent holders. Many of these patents are + * general enough such that they are unavoidable regardless of implementation + * design. + * + */ + +/**********************************************************/ +/* inverse two dimensional DCT, Chen-Wang algorithm */ +/* (cf. IEEE ASSP-32, pp. 803-816, Aug. 1984) */ +/* 32-bit integer arithmetic (8 bit coefficients) */ +/* 11 mults, 29 adds per DCT */ +/* sE, 18.8.91 */ +/**********************************************************/ +/* coefficients extended to 12 bit for IEEE1180-1990 */ +/* compliance sE, 2.1.94 */ +/**********************************************************/ + +/* this code assumes >> to be a two's-complement arithmetic */ +/* right shift: (-2)>>1 == -1 , (-3)>>1 == -2 */ + +#include "config.h" + +#define W1 2841 /* 2048*sqrt(2)*cos(1*pi/16) */ +#define W2 2676 /* 2048*sqrt(2)*cos(2*pi/16) */ +#define W3 2408 /* 2048*sqrt(2)*cos(3*pi/16) */ +#define W5 1609 /* 2048*sqrt(2)*cos(5*pi/16) */ +#define W6 1108 /* 2048*sqrt(2)*cos(6*pi/16) */ +#define W7 565 /* 2048*sqrt(2)*cos(7*pi/16) */ + +/* global declarations */ +void Initialize_Fast_IDCT _ANSI_ARGS_((void)); +void Fast_IDCT _ANSI_ARGS_((short *block)); + +/* private data */ +static short iclip[1024]; /* clipping table */ +static short *iclp; + +/* private prototypes */ +static void idctrow _ANSI_ARGS_((short *blk)); +static void idctcol _ANSI_ARGS_((short *blk)); + +/* row (horizontal) IDCT + * + * 7 pi 1 + * dst[k] = sum c[l] * src[l] * cos( -- * ( k + - ) * l ) + * l=0 8 2 + * + * where: c[0] = 128 + * c[1..7] = 128*sqrt(2) + */ + +static void idctrow(blk) +short *blk; +{ + int x0, x1, x2, x3, x4, x5, x6, x7, x8; + + /* shortcut */ + if (!((x1 = blk[4]<<11) | (x2 = blk[6]) | (x3 = blk[2]) | + (x4 = blk[1]) | (x5 = blk[7]) | (x6 = blk[5]) | (x7 = blk[3]))) + { + blk[0]=blk[1]=blk[2]=blk[3]=blk[4]=blk[5]=blk[6]=blk[7]=blk[0]<<3; + return; + } + + x0 = (blk[0]<<11) + 128; /* for proper rounding in the fourth stage */ + + /* first stage */ + x8 = W7*(x4+x5); + x4 = x8 + (W1-W7)*x4; + x5 = x8 - (W1+W7)*x5; + x8 = W3*(x6+x7); + x6 = x8 - (W3-W5)*x6; + x7 = x8 - (W3+W5)*x7; + + /* second stage */ + x8 = x0 + x1; + x0 -= x1; + x1 = W6*(x3+x2); + x2 = x1 - (W2+W6)*x2; + x3 = x1 + (W2-W6)*x3; + x1 = x4 + x6; + x4 -= x6; + x6 = x5 + x7; + x5 -= x7; + + /* third stage */ + x7 = x8 + x3; + x8 -= x3; + x3 = x0 + x2; + x0 -= x2; + x2 = (181*(x4+x5)+128)>>8; + x4 = (181*(x4-x5)+128)>>8; + + /* fourth stage */ + blk[0] = (x7+x1)>>8; + blk[1] = (x3+x2)>>8; + blk[2] = (x0+x4)>>8; + blk[3] = (x8+x6)>>8; + blk[4] = (x8-x6)>>8; + blk[5] = (x0-x4)>>8; + blk[6] = (x3-x2)>>8; + blk[7] = (x7-x1)>>8; +} + +/* column (vertical) IDCT + * + * 7 pi 1 + * dst[8*k] = sum c[l] * src[8*l] * cos( -- * ( k + - ) * l ) + * l=0 8 2 + * + * where: c[0] = 1/1024 + * c[1..7] = (1/1024)*sqrt(2) + */ +static void idctcol(blk) +short *blk; +{ + int x0, x1, x2, x3, x4, x5, x6, x7, x8; + + /* shortcut */ + if (!((x1 = (blk[8*4]<<8)) | (x2 = blk[8*6]) | (x3 = blk[8*2]) | + (x4 = blk[8*1]) | (x5 = blk[8*7]) | (x6 = blk[8*5]) | (x7 = blk[8*3]))) + { + blk[8*0]=blk[8*1]=blk[8*2]=blk[8*3]=blk[8*4]=blk[8*5]=blk[8*6]=blk[8*7]= + iclp[(blk[8*0]+32)>>6]; + return; + } + + x0 = (blk[8*0]<<8) + 8192; + + /* first stage */ + x8 = W7*(x4+x5) + 4; + x4 = (x8+(W1-W7)*x4)>>3; + x5 = (x8-(W1+W7)*x5)>>3; + x8 = W3*(x6+x7) + 4; + x6 = (x8-(W3-W5)*x6)>>3; + x7 = (x8-(W3+W5)*x7)>>3; + + /* second stage */ + x8 = x0 + x1; + x0 -= x1; + x1 = W6*(x3+x2) + 4; + x2 = (x1-(W2+W6)*x2)>>3; + x3 = (x1+(W2-W6)*x3)>>3; + x1 = x4 + x6; + x4 -= x6; + x6 = x5 + x7; + x5 -= x7; + + /* third stage */ + x7 = x8 + x3; + x8 -= x3; + x3 = x0 + x2; + x0 -= x2; + x2 = (181*(x4+x5)+128)>>8; + x4 = (181*(x4-x5)+128)>>8; + + /* fourth stage */ + blk[8*0] = iclp[(x7+x1)>>14]; + blk[8*1] = iclp[(x3+x2)>>14]; + blk[8*2] = iclp[(x0+x4)>>14]; + blk[8*3] = iclp[(x8+x6)>>14]; + blk[8*4] = iclp[(x8-x6)>>14]; + blk[8*5] = iclp[(x0-x4)>>14]; + blk[8*6] = iclp[(x3-x2)>>14]; + blk[8*7] = iclp[(x7-x1)>>14]; +} + +/* two dimensional inverse discrete cosine transform */ +void Fast_IDCT(block) +short *block; +{ + int i; + + for (i=0; i<8; i++) + idctrow(block+8*i); + + for (i=0; i<8; i++) + idctcol(block+i); +} + +void Initialize_Fast_IDCT() +{ + int i; + + iclp = iclip+512; + for (i= -512; i<512; i++) + iclp[i] = (i<-256) ? -256 : ((i>255) ? 255 : i); +} diff --git a/libfbui/MPEG/idctref.c b/libfbui/MPEG/idctref.c @@ -0,0 +1,108 @@ +/* Reference_IDCT.c, Inverse Discrete Fourier Transform, double precision */ + +/* Copyright (C) 1996, MPEG Software Simulation Group. All Rights Reserved. */ + +/* + * Disclaimer of Warranty + * + * These software programs are available to the user without any license fee or + * royalty on an "as is" basis. The MPEG Software Simulation Group disclaims + * any and all warranties, whether express, implied, or statuary, including any + * implied warranties or merchantability or of fitness for a particular + * purpose. In no event shall the copyright-holder be liable for any + * incidental, punitive, or consequential damages of any kind whatsoever + * arising from the use of these programs. + * + * This disclaimer of warranty extends to the user of these programs and user's + * customers, employees, agents, transferees, successors, and assigns. + * + * The MPEG Software Simulation Group does not represent or warrant that the + * programs furnished hereunder are free of infringement of any third-party + * patents. + * + * Commercial implementations of MPEG-1 and MPEG-2 video, including shareware, + * are subject to royalty fees to patent holders. Many of these patents are + * general enough such that they are unavoidable regardless of implementation + * design. + * + */ + +/* Perform IEEE 1180 reference (64-bit floating point, separable 8x1 + * direct matrix multiply) Inverse Discrete Cosine Transform +*/ + + +/* Here we use math.h to generate constants. Compiler results may + vary a little */ + +#include <math.h> + +#include "config.h" + +#ifndef PI +# ifdef M_PI +# define PI M_PI +# else +# define PI 3.14159265358979323846 +# endif +#endif + +/* global declarations */ +void Initialize_Fast_IDCTref _ANSI_ARGS_((void)); +void Reference_IDCT _ANSI_ARGS_((short *block)); + +/* private data */ + +/* cosine transform matrix for 8x1 IDCT */ +static double c[8][8]; + +/* initialize DCT coefficient matrix */ + +void Initialize_Reference_IDCT() +{ + int freq, time; + double scale; + + for (freq=0; freq < 8; freq++) + { + scale = (freq == 0) ? sqrt(0.125) : 0.5; + for (time=0; time<8; time++) + c[freq][time] = scale*cos((PI/8.0)*freq*(time + 0.5)); + } +} + +/* perform IDCT matrix multiply for 8x8 coefficient block */ + +void Reference_IDCT(block) +short *block; +{ + int i, j, k, v; + double partial_product; + double tmp[64]; + + for (i=0; i<8; i++) + for (j=0; j<8; j++) + { + partial_product = 0.0; + + for (k=0; k<8; k++) + partial_product+= c[k][j]*block[8*i+k]; + + tmp[8*i+j] = partial_product; + } + + /* Transpose operation is integrated into address mapping by switching + loop order of i and j */ + + for (j=0; j<8; j++) + for (i=0; i<8; i++) + { + partial_product = 0.0; + + for (k=0; k<8; k++) + partial_product+= c[k][i]*tmp[8*k+j]; + + v = (int) floor(partial_product+0.5); + block[8*i+j] = (v<-256) ? -256 : ((v>255) ? 255 : v); + } +} diff --git a/libfbui/MPEG/motion.c b/libfbui/MPEG/motion.c @@ -0,0 +1,236 @@ +/* motion.c, motion vector decoding */ + +/* Copyright (C) 1996, MPEG Software Simulation Group. All Rights Reserved. */ + +/* + * Disclaimer of Warranty + * + * These software programs are available to the user without any license fee or + * royalty on an "as is" basis. The MPEG Software Simulation Group disclaims + * any and all warranties, whether express, implied, or statuary, including any + * implied warranties or merchantability or of fitness for a particular + * purpose. In no event shall the copyright-holder be liable for any + * incidental, punitive, or consequential damages of any kind whatsoever + * arising from the use of these programs. + * + * This disclaimer of warranty extends to the user of these programs and user's + * customers, employees, agents, transferees, successors, and assigns. + * + * The MPEG Software Simulation Group does not represent or warrant that the + * programs furnished hereunder are free of infringement of any third-party + * patents. + * + * Commercial implementations of MPEG-1 and MPEG-2 video, including shareware, + * are subject to royalty fees to patent holders. Many of these patents are + * general enough such that they are unavoidable regardless of implementation + * design. + * + */ + +#include <stdio.h> + +#include "config.h" +#include "global.h" + +/* private prototypes */ +static void decode_motion_vector _ANSI_ARGS_((int *pred, int r_size, int motion_code, + int motion_residualesidual, int full_pel_vector)); + +/* ISO/IEC 13818-2 sections 6.2.5.2, 6.3.17.2, and 7.6.3: Motion vectors */ +void motion_vectors(PMV,dmvector, + motion_vertical_field_select,s,motion_vector_count,mv_format,h_r_size,v_r_size,dmv,mvscale) +int PMV[2][2][2]; +int dmvector[2]; +int motion_vertical_field_select[2][2]; +int s, motion_vector_count, mv_format, h_r_size, v_r_size, dmv, mvscale; +{ + if (motion_vector_count==1) + { + if (mv_format==MV_FIELD && !dmv) + { + motion_vertical_field_select[1][s] = motion_vertical_field_select[0][s] = Get_Bits(1); +#ifdef TRACE + if (Trace_Flag) + { + printf("motion_vertical_field_select[][%d] (%d): %d\n",s, + motion_vertical_field_select[0][s],motion_vertical_field_select[0][s]); + } +#endif /* TRACE */ + } + + motion_vector(PMV[0][s],dmvector,h_r_size,v_r_size,dmv,mvscale,0); + + /* update other motion vector predictors */ + PMV[1][s][0] = PMV[0][s][0]; + PMV[1][s][1] = PMV[0][s][1]; + } + else + { + motion_vertical_field_select[0][s] = Get_Bits(1); +#ifdef TRACE + if (Trace_Flag) + { + printf("motion_vertical_field_select[0][%d] (%d): %d\n",s, + motion_vertical_field_select[0][s],motion_vertical_field_select[0][s]); + } +#endif /* TRACE */ + motion_vector(PMV[0][s],dmvector,h_r_size,v_r_size,dmv,mvscale,0); + + motion_vertical_field_select[1][s] = Get_Bits(1); +#ifdef TRACE + if (Trace_Flag) + { + printf("motion_vertical_field_select[1][%d] (%d): %d\n",s, + motion_vertical_field_select[1][s],motion_vertical_field_select[1][s]); + } +#endif /* TRACE */ + motion_vector(PMV[1][s],dmvector,h_r_size,v_r_size,dmv,mvscale,0); + } +} + +/* get and decode motion vector and differential motion vector + for one prediction */ +void motion_vector(PMV,dmvector, + h_r_size,v_r_size,dmv,mvscale,full_pel_vector) +int *PMV; +int *dmvector; +int h_r_size; +int v_r_size; +int dmv; /* MPEG-2 only: get differential motion vectors */ +int mvscale; /* MPEG-2 only: field vector in frame pic */ +int full_pel_vector; /* MPEG-1 only */ +{ + int motion_code, motion_residual; + + /* horizontal component */ + /* ISO/IEC 13818-2 Table B-10 */ + motion_code = Get_motion_code(); + + motion_residual = (h_r_size!=0 && motion_code!=0) ? Get_Bits(h_r_size) : 0; + +#ifdef TRACE + if (Trace_Flag) + { + if (h_r_size!=0 && motion_code!=0) + { + printf("motion_residual ("); + Print_Bits(motion_residual,h_r_size,h_r_size); + printf("): %d\n",motion_residual); + } + } +#endif /* TRACE */ + + + decode_motion_vector(&PMV[0],h_r_size,motion_code,motion_residual,full_pel_vector); + + if (dmv) + dmvector[0] = Get_dmvector(); + + + /* vertical component */ + motion_code = Get_motion_code(); + motion_residual = (v_r_size!=0 && motion_code!=0) ? Get_Bits(v_r_size) : 0; + +#ifdef TRACE + if (Trace_Flag) + { + if (v_r_size!=0 && motion_code!=0) + { + printf("motion_residual ("); + Print_Bits(motion_residual,v_r_size,v_r_size); + printf("): %d\n",motion_residual); + } + } +#endif /* TRACE */ + + if (mvscale) + PMV[1] >>= 1; /* DIV 2 */ + + decode_motion_vector(&PMV[1],v_r_size,motion_code,motion_residual,full_pel_vector); + + if (mvscale) + PMV[1] <<= 1; + + if (dmv) + dmvector[1] = Get_dmvector(); + +#ifdef TRACE + if (Trace_Flag) + printf("PMV = %d,%d\n",PMV[0],PMV[1]); +#endif /* TRACE */ +} + +/* calculate motion vector component */ +/* ISO/IEC 13818-2 section 7.6.3.1: Decoding the motion vectors */ +/* Note: the arithmetic here is more elegant than that which is shown + in 7.6.3.1. The end results (PMV[][][]) should, however, be the same. */ + +static void decode_motion_vector(pred,r_size,motion_code,motion_residual,full_pel_vector) +int *pred; +int r_size, motion_code, motion_residual; +int full_pel_vector; /* MPEG-1 (ISO/IEC 11172-1) support */ +{ + int lim, vec; + + lim = 16<<r_size; + vec = full_pel_vector ? (*pred >> 1) : (*pred); + + if (motion_code>0) + { + vec+= ((motion_code-1)<<r_size) + motion_residual + 1; + if (vec>=lim) + vec-= lim + lim; + } + else if (motion_code<0) + { + vec-= ((-motion_code-1)<<r_size) + motion_residual + 1; + if (vec<-lim) + vec+= lim + lim; + } + *pred = full_pel_vector ? (vec<<1) : vec; +} + + +/* ISO/IEC 13818-2 section 7.6.3.6: Dual prime additional arithmetic */ +void Dual_Prime_Arithmetic(DMV,dmvector,mvx,mvy) +int DMV[][2]; +int *dmvector; /* differential motion vector */ +int mvx, mvy; /* decoded mv components (always in field format) */ +{ + if (picture_structure==FRAME_PICTURE) + { + if (top_field_first) + { + /* vector for prediction of top field from bottom field */ + DMV[0][0] = ((mvx +(mvx>0))>>1) + dmvector[0]; + DMV[0][1] = ((mvy +(mvy>0))>>1) + dmvector[1] - 1; + + /* vector for prediction of bottom field from top field */ + DMV[1][0] = ((3*mvx+(mvx>0))>>1) + dmvector[0]; + DMV[1][1] = ((3*mvy+(mvy>0))>>1) + dmvector[1] + 1; + } + else + { + /* vector for prediction of top field from bottom field */ + DMV[0][0] = ((3*mvx+(mvx>0))>>1) + dmvector[0]; + DMV[0][1] = ((3*mvy+(mvy>0))>>1) + dmvector[1] - 1; + + /* vector for prediction of bottom field from top field */ + DMV[1][0] = ((mvx +(mvx>0))>>1) + dmvector[0]; + DMV[1][1] = ((mvy +(mvy>0))>>1) + dmvector[1] + 1; + } + } + else + { + /* vector for prediction from field of opposite 'parity' */ + DMV[0][0] = ((mvx+(mvx>0))>>1) + dmvector[0]; + DMV[0][1] = ((mvy+(mvy>0))>>1) + dmvector[1]; + + /* correct for vertical field shift */ + if (picture_structure==TOP_FIELD) + DMV[0][1]--; + else + DMV[0][1]++; + } +} + diff --git a/libfbui/MPEG/mpeg2dec.c b/libfbui/MPEG/mpeg2dec.c @@ -0,0 +1,774 @@ + +/* mpeg2dec.c, main(), initialization, option processing */ + +/* Copyright (C) 1996, MPEG Software Simulation Group. All Rights Reserved. */ + +/* + * Disclaimer of Warranty + * + * These software programs are available to the user without any license fee or + * royalty on an "as is" basis. The MPEG Software Simulation Group disclaims + * any and all warranties, whether express, implied, or statuary, including any + * implied warranties or merchantability or of fitness for a particular + * purpose. In no event shall the copyright-holder be liable for any + * incidental, punitive, or consequential damages of any kind whatsoever + * arising from the use of these programs. + * + * This disclaimer of warranty extends to the user of these programs and user's + * customers, employees, agents, transferees, successors, and assigns. + * + * The MPEG Software Simulation Group does not represent or warrant that the + * programs furnished hereunder are free of infringement of any third-party + * patents. + * + * Commercial implementations of MPEG-1 and MPEG-2 video, including shareware, + * are subject to royalty fees to patent holders. Many of these patents are + * general enough such that they are unavoidable regardless of implementation + * design. + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> +#include <fcntl.h> + +#define GLOBAL +#include "config.h" +#include "global.h" + +/* private prototypes */ +static int video_sequence _ANSI_ARGS_((int *framenum)); +static int Decode_Bitstream _ANSI_ARGS_((void)); +static int Headers _ANSI_ARGS_((void)); +static void Initialize_Sequence _ANSI_ARGS_((void)); +static void Initialize_Decoder _ANSI_ARGS_((void)); +static void Deinitialize_Sequence _ANSI_ARGS_((void)); +static void Process_Options _ANSI_ARGS_((int argc, char *argv[])); + +int fbui_console; + +#if OLD +static int Get_Val _ANSI_ARGS_((char *argv[])); +#endif + +/* #define DEBUG */ + +static void Clear_Options(); +#ifdef DEBUG +static void Print_Options(); +#endif + +int main(argc,argv) +int argc; +char *argv[]; +{ + int ret, code; + + Clear_Options(); + + fbui_console = -1; + + /* decode command line arguments */ + Process_Options(argc,argv); + +#ifdef DEBUG + Print_Options(); +#endif + + ld = &base; /* select base layer context */ + + /* open MPEG base layer bitstream file(s) */ + /* NOTE: this is either a base layer stream or a spatial enhancement stream */ + if ((base.Infile=open(Main_Bitstream_Filename,O_RDONLY|O_BINARY))<0) + { + fprintf(stderr,"Base layer input file %s not found\n", Main_Bitstream_Filename); + exit(1); + } + + + if(base.Infile != 0) + { + Initialize_Buffer(); + + if(Show_Bits(8)==0x47) + { + sprintf(Error_Text,"Decoder currently does not parse transport streams\n"); + Error(Error_Text); + } + + next_start_code(); + code = Show_Bits(32); + + switch(code) + { + case SEQUENCE_HEADER_CODE: + break; + case PACK_START_CODE: + System_Stream_Flag = 1; + case VIDEO_ELEMENTARY_STREAM: + System_Stream_Flag = 1; + break; + default: + sprintf(Error_Text,"Unable to recognize stream type\n"); + Error(Error_Text); + break; + } + + lseek(base.Infile, 0l, 0); + Initialize_Buffer(); + } + + if(base.Infile!=0) + { + lseek(base.Infile, 0l, 0); + } + + Initialize_Buffer(); + + if(Two_Streams) + { + ld = &enhan; /* select enhancement layer context */ + + if ((enhan.Infile = open(Enhancement_Layer_Bitstream_Filename,O_RDONLY|O_BINARY))<0) + { + sprintf(Error_Text,"enhancment layer bitstream file %s not found\n", + Enhancement_Layer_Bitstream_Filename); + + Error(Error_Text); + } + + Initialize_Buffer(); + ld = &base; + } + + Initialize_Decoder(); + + ret = Decode_Bitstream(); + + close(base.Infile); + + if (Two_Streams) + close(enhan.Infile); + + return 0; +} + +/* IMPLEMENTAION specific rouintes */ +static void Initialize_Decoder() +{ + int i; + + /* Clip table */ + if (!(Clip=(unsigned char *)malloc(1024))) + Error("Clip[] malloc failed\n"); + + Clip += 384; + + for (i=-384; i<640; i++) + Clip[i] = (i<0) ? 0 : ((i>255) ? 255 : i); + + /* IDCT */ + if (Reference_IDCT_Flag) + Initialize_Reference_IDCT(); + else + Initialize_Fast_IDCT(); + +} + +/* mostly IMPLEMENTAION specific rouintes */ +static void Initialize_Sequence() +{ + int cc, size; + static int Table_6_20[3] = {6,8,12}; + + /* check scalability mode of enhancement layer */ + if (Two_Streams && (enhan.scalable_mode!=SC_SNR) && (base.scalable_mode!=SC_DP)) + Error("unsupported scalability mode\n"); + + /* force MPEG-1 parameters for proper decoder behavior */ + /* see ISO/IEC 13818-2 section D.9.14 */ + if (!base.MPEG2_Flag) + { + progressive_sequence = 1; + progressive_frame = 1; + picture_structure = FRAME_PICTURE; + frame_pred_frame_dct = 1; + chroma_format = CHROMA420; + matrix_coefficients = 5; + } + + /* round to nearest multiple of coded macroblocks */ + /* ISO/IEC 13818-2 section 6.3.3 sequence_header() */ + mb_width = (horizontal_size+15)/16; + mb_height = (base.MPEG2_Flag && !progressive_sequence) ? 2*((vertical_size+31)/32) + : (vertical_size+15)/16; + + Coded_Picture_Width = 16*mb_width; + Coded_Picture_Height = 16*mb_height; + + /* ISO/IEC 13818-2 sections 6.1.1.8, 6.1.1.9, and 6.1.1.10 */ + Chroma_Width = (chroma_format==CHROMA444) ? Coded_Picture_Width + : Coded_Picture_Width>>1; + Chroma_Height = (chroma_format!=CHROMA420) ? Coded_Picture_Height + : Coded_Picture_Height>>1; + + /* derived based on Table 6-20 in ISO/IEC 13818-2 section 6.3.17 */ + block_count = Table_6_20[chroma_format-1]; + + for (cc=0; cc<3; cc++) + { + if (cc==0) + size = Coded_Picture_Width*Coded_Picture_Height; + else + size = Chroma_Width*Chroma_Height; + + if (!(backward_reference_frame[cc] = (unsigned char *)malloc(size))) + Error("backward_reference_frame[] malloc failed\n"); + + if (!(forward_reference_frame[cc] = (unsigned char *)malloc(size))) + Error("forward_reference_frame[] malloc failed\n"); + + if (!(auxframe[cc] = (unsigned char *)malloc(size))) + Error("auxframe[] malloc failed\n"); + + if(Ersatz_Flag) + if (!(substitute_frame[cc] = (unsigned char *)malloc(size))) + Error("substitute_frame[] malloc failed\n"); + + + if (base.scalable_mode==SC_SPAT) + { + /* this assumes lower layer is 4:2:0 */ + if (!(llframe0[cc] = (unsigned char *)malloc((lower_layer_prediction_horizontal_size*lower_layer_prediction_vertical_size)/(cc?4:1)))) + Error("llframe0 malloc failed\n"); + if (!(llframe1[cc] = (unsigned char *)malloc((lower_layer_prediction_horizontal_size*lower_layer_prediction_vertical_size)/(cc?4:1)))) + Error("llframe1 malloc failed\n"); + } + } + + /* SCALABILITY: Spatial */ + if (base.scalable_mode==SC_SPAT) + { + if (!(lltmp = (short *)malloc(lower_layer_prediction_horizontal_size*((lower_layer_prediction_vertical_size*vertical_subsampling_factor_n)/vertical_subsampling_factor_m)*sizeof(short)))) + Error("lltmp malloc failed\n"); + } + +#ifdef DISPLAY + if (Output_Type==T_X11) + { + Initialize_Display_Process(""); + Initialize_Dither_Matrix(); + } +#endif /* DISPLAY */ + +} + +void Error(text) +char *text; +{ + fprintf(stderr,text); + exit(1); +} + +/* Trace_Flag output */ +void Print_Bits(code,bits,len) +int code,bits,len; +{ + int i; + for (i=0; i<len; i++) + printf("%d",(code>>(bits-1-i))&1); +} + + +/* option processing */ +static void Process_Options(argc,argv) +int argc; /* argument count */ +char *argv[]; /* argument vector */ +{ + int i, LastArg, NextArg; + + /* at least one argument should be present */ + if (argc<2) + { + printf("\n%s, %s\n",Version,Author); + printf("Usage: mpeg2decode {options}\n\ +Options: -b file main bitstream (base or spatial enhancement layer)\n\ + -# FBUI console number\n\ + -cn file conformance report (n: level)\n\ + -e file enhancement layer bitstream (SNR or Data Partitioning)\n\ + -f store/display interlaced video in frame format\n\ + -g concatenated file format for substitution method (-x)\n\ + -in file information & statistics report (n: level)\n\ + -l file file name pattern for lower layer sequence\n\ + (for spatial scalability)\n\ + -on file output format (0:YUV 1:SIF 2:TGA 3:PPM 4:X11 5:X11HiQ 6:FBUI)\n\ + -q disable warnings to stderr\n\ + -r use double precision reference IDCT\n\ + -t enable low level tracing to stdout\n\ + -u file print user_data to stdio or file\n\ + -vn verbose output (n: level)\n\ + -x file filename pattern of picture substitution sequence\n\n\ +File patterns: for sequential filenames, \"printf\" style, e.g. rec%%d\n\ + or rec%%d%%c for fieldwise storage\n\ +Levels: 0:none 1:sequence 2:picture 3:slice 4:macroblock 5:block\n\n\ +Example: mpeg2decode -b bitstream.mpg -f -r -o0 rec%%d\n\ + \n"); + exit(0); + } + + + Output_Type = 6; /* default: FBUI */ + i = 1; + + /* command-line options are proceeded by '-' */ + + while(i < argc) + { + /* check if this is the last argument */ + LastArg = ((argc-i)==1); + + /* parse ahead to see if another flag immediately follows current + argument (this is used to tell if a filename is missing) */ + if(!LastArg) + NextArg = (argv[i+1][0]=='-'); + else + NextArg = 0; + + /* second character, [1], after '-' is the switch */ + if(argv[i][0]=='-') + { + if (isdigit(argv[i][1])) { + fbui_console = -atoi(argv[i]); + } + else switch(toupper(argv[i][1])) + { + /* third character. [2], is the value */ + case 'B': + Main_Bitstream_Flag = 1; + + if(NextArg || LastArg) + { + printf("ERROR: -b must be followed the main bitstream filename\n"); + } + else + Main_Bitstream_Filename = argv[++i]; + + break; + + + case 'C': + +#ifdef VERIFY + Verify_Flag = atoi(&argv[i][2]); + + if((Verify_Flag < NO_LAYER) || (Verify_Flag > ALL_LAYERS)) + { + printf("ERROR: -c level (%d) out of range [%d,%d]\n", + Verify_Flag, NO_LAYER, ALL_LAYERS); + exit(ERROR); + } +#else /* VERIFY */ + printf("This program not compiled for Verify_Flag option\n"); +#endif /* VERIFY */ + break; + + case 'E': + Two_Streams = 1; /* either Data Partitioning (DP) or SNR Scalability enhancment */ + + if(NextArg || LastArg) + { + printf("ERROR: -e must be followed by filename\n"); + exit(ERROR); + } + else + Enhancement_Layer_Bitstream_Filename = argv[++i]; + + break; + + + case 'F': + Frame_Store_Flag = 1; + break; + + case 'G': + Big_Picture_Flag = 1; + break; + + + case 'I': +#ifdef VERIFY + Stats_Flag = atoi(&argv[i][2]); +#else /* VERIFY */ + printf("WARNING: This program not compiled for -i option\n"); +#endif /* VERIFY */ + break; + + case 'L': /* spatial scalability flag */ + Spatial_Flag = 1; + + if(NextArg || LastArg) + { + printf("ERROR: -l must be followed by filename\n"); + exit(ERROR); + } + else + Lower_Layer_Picture_Filename = argv[++i]; + + break; + + case 'O': + + Output_Type = atoi(&argv[i][2]); + + if((Output_Type==4) || (Output_Type==5) || Output_Type==6) + Output_Picture_Filename = ""; /* no need of filename */ + else if(NextArg || LastArg) + { + printf("ERROR: -o must be followed by filename\n"); + exit(ERROR); + } + else + /* filename is separated by space, so it becomes the next argument */ + Output_Picture_Filename = argv[++i]; + +#ifdef DISPLAY + if (Output_Type==T_X11HIQ) + { + hiQdither = 1; + Output_Type=T_X11; + } +#endif /* DISPLAY */ + break; + + case 'Q': + Quiet_Flag = 1; + break; + + case 'R': + Reference_IDCT_Flag = 1; + break; + + case 'T': +#ifdef TRACE + Trace_Flag = 1; +#else /* TRACE */ + printf("WARNING: This program not compiled for -t option\n"); +#endif /* TRACE */ + break; + + case 'U': + User_Data_Flag = 1; + + case 'V': +#ifdef VERBOSE + Verbose_Flag = atoi(&argv[i][2]); +#else /* VERBOSE */ + printf("This program not compiled for -v option\n"); +#endif /* VERBOSE */ + break; + + + case 'X': + Ersatz_Flag = 1; + + if(NextArg || LastArg) + { + printf("ERROR: -x must be followed by filename\n"); + exit(ERROR); + } + else + Substitute_Picture_Filename = argv[++i]; + + break; + + + + default: + fprintf(stderr,"undefined option -%c ignored. Exiting program\n", + argv[i][1]); + + exit(ERROR); + + } /* switch() */ + } /* if argv[i][0] == '-' */ + + i++; + + /* check for bitstream filename argument (there must always be one, at the very end + of the command line arguments */ + + } /* while() */ + + + /* options sense checking */ + + if(Main_Bitstream_Flag!=1) + { + printf("There must be a main bitstream specified (-b filename)\n"); + } + + /* force display process to show frame pictures */ + if((Output_Type==4 || Output_Type==5) && Frame_Store_Flag) + Display_Progressive_Flag = 1; + else + Display_Progressive_Flag = 0; + +#ifdef VERIFY + /* parse the bitstream, do not actually decode it completely */ + + +#if 0 + if(Output_Type==-1) + { + Decode_Layer = Verify_Flag; + printf("FYI: Decoding bitstream elements up to: %s\n", + Layer_Table[Decode_Layer]); + } + else +#endif + Decode_Layer = ALL_LAYERS; + +#endif /* VERIFY */ + + /* no output type specified */ + if(Output_Type==-1) + { + Output_Type = 9; + Output_Picture_Filename = ""; + } + + +#ifdef DISPLAY + if (Output_Type==T_X11) + { + if(Frame_Store_Flag) + Display_Progressive_Flag = 1; + else + Display_Progressive_Flag = 0; + + Frame_Store_Flag = 1; /* to avoid calling dither() twice */ + } +#endif + + +} + + +#ifdef OLD +/* + this is an old routine used to convert command line arguments + into integers +*/ +static int Get_Val(argv) +char *argv[]; +{ + int val; + + if (sscanf(argv[1]+2,"%d",&val)!=1) + return 0; + + while (isdigit(argv[1][2])) + argv[1]++; + + return val; +} +#endif + + + +static int Headers() +{ + int ret; + + ld = &base; + + + /* return when end of sequence (0) or picture + header has been parsed (1) */ + + ret = Get_Hdr(); + + + if (Two_Streams) + { + ld = &enhan; + if (Get_Hdr()!=ret && !Quiet_Flag) + fprintf(stderr,"streams out of sync\n"); + ld = &base; + } + + return ret; +} + + + +static int Decode_Bitstream() +{ + int ret; + int Bitstream_Framenum; + + Bitstream_Framenum = 0; + + for(;;) + { + +#ifdef VERIFY + Clear_Verify_Headers(); +#endif /* VERIFY */ + + ret = Headers(); + + if(ret==1) + { + ret = video_sequence(&Bitstream_Framenum); + } + else + return(ret); + } + +} + + +extern void shutdown_fbui(); + +static void Deinitialize_Sequence() +{ + int i; + + /* clear flags */ + base.MPEG2_Flag=0; + + for(i=0;i<3;i++) + { + free(backward_reference_frame[i]); + free(forward_reference_frame[i]); + free(auxframe[i]); + + if (base.scalable_mode==SC_SPAT) + { + free(llframe0[i]); + free(llframe1[i]); + } + } + + if (base.scalable_mode==SC_SPAT) + free(lltmp); + +#ifdef DISPLAY + if (Output_Type==T_X11) + Terminate_Display_Process(); +#endif + shutdown_fbui(); +} + + +static int video_sequence(Bitstream_Framenumber) +int *Bitstream_Framenumber; +{ + int Bitstream_Framenum; + int Sequence_Framenum; + int Return_Value; + + Bitstream_Framenum = *Bitstream_Framenumber; + Sequence_Framenum=0; + + Initialize_Sequence(); + + /* decode picture whose header has already been parsed in + Decode_Bitstream() */ + + + Decode_Picture(Bitstream_Framenum, Sequence_Framenum); + + /* update picture numbers */ + if (!Second_Field) + { + Bitstream_Framenum++; + Sequence_Framenum++; + } + + /* loop through the rest of the pictures in the sequence */ + while ((Return_Value=Headers())) + { + Decode_Picture(Bitstream_Framenum, Sequence_Framenum); + + if (!Second_Field) + { + Bitstream_Framenum++; + Sequence_Framenum++; + } + } + + /* put last frame */ + if (Sequence_Framenum!=0) + { + Output_Last_Frame_of_Sequence(Bitstream_Framenum); + } + + Deinitialize_Sequence(); + +#ifdef VERIFY + Clear_Verify_Headers(); +#endif /* VERIFY */ + + *Bitstream_Framenumber = Bitstream_Framenum; + return(Return_Value); +} + + + +static void Clear_Options() +{ + Verbose_Flag = 0; + Output_Type = 0; + Output_Picture_Filename = " "; + hiQdither = 0; + Output_Type = 0; + Frame_Store_Flag = 0; + Spatial_Flag = 0; + Lower_Layer_Picture_Filename = " "; + Reference_IDCT_Flag = 0; + Trace_Flag = 0; + Quiet_Flag = 0; + Ersatz_Flag = 0; + Substitute_Picture_Filename = " "; + Two_Streams = 0; + Enhancement_Layer_Bitstream_Filename = " "; + Big_Picture_Flag = 0; + Main_Bitstream_Flag = 0; + Main_Bitstream_Filename = " "; + Verify_Flag = 0; + Stats_Flag = 0; + User_Data_Flag = 0; +} + + +#ifdef DEBUG +static void Print_Options() +{ + + printf("Verbose_Flag = %d\n", Verbose_Flag); + printf("Output_Type = %d\n", Output_Type); + printf("Output_Picture_Filename = %s\n", Output_Picture_Filename); + printf("hiQdither = %d\n", hiQdither); + printf("Output_Type = %d\n", Output_Type); + printf("Frame_Store_Flag = %d\n", Frame_Store_Flag); + printf("Spatial_Flag = %d\n", Spatial_Flag); + printf("Lower_Layer_Picture_Filename = %s\n", Lower_Layer_Picture_Filename); + printf("Reference_IDCT_Flag = %d\n", Reference_IDCT_Flag); + printf("Trace_Flag = %d\n", Trace_Flag); + printf("Quiet_Flag = %d\n", Quiet_Flag); + printf("Ersatz_Flag = %d\n", Ersatz_Flag); + printf("Substitute_Picture_Filename = %s\n", Substitute_Picture_Filename); + printf("Two_Streams = %d\n", Two_Streams); + printf("Enhancement_Layer_Bitstream_Filename = %s\n", Enhancement_Layer_Bitstream_Filename); + printf("Big_Picture_Flag = %d\n", Big_Picture_Flag); + printf("Main_Bitstream_Flag = %d\n", Main_Bitstream_Flag); + printf("Main_Bitstream_Filename = %s\n", Main_Bitstream_Filename); + printf("Verify_Flag = %d\n", Verify_Flag); + printf("Stats_Flag = %d\n", Stats_Flag); + printf("User_Data_Flag = %d\n", User_Data_Flag); + +} +#endif diff --git a/libfbui/MPEG/mpeg2dec.h b/libfbui/MPEG/mpeg2dec.h @@ -0,0 +1,129 @@ +/* mpeg2dec.h, MPEG specific defines */ + +/* Copyright (C) 1996, MPEG Software Simulation Group. All Rights Reserved. */ + +/* + * Disclaimer of Warranty + * + * These software programs are available to the user without any license fee or + * royalty on an "as is" basis. The MPEG Software Simulation Group disclaims + * any and all warranties, whether express, implied, or statuary, including any + * implied warranties or merchantability or of fitness for a particular + * purpose. In no event shall the copyright-holder be liable for any + * incidental, punitive, or consequential damages of any kind whatsoever + * arising from the use of these programs. + * + * This disclaimer of warranty extends to the user of these programs and user's + * customers, employees, agents, transferees, successors, and assigns. + * + * The MPEG Software Simulation Group does not represent or warrant that the + * programs furnished hereunder are free of infringement of any third-party + * patents. + * + * Commercial implementations of MPEG-1 and MPEG-2 video, including shareware, + * are subject to royalty fees to patent holders. Many of these patents are + * general enough such that they are unavoidable regardless of implementation + * design. + * + */ + +#define ERROR (-1) + +#define PICTURE_START_CODE 0x100 +#define SLICE_START_CODE_MIN 0x101 +#define SLICE_START_CODE_MAX 0x1AF +#define USER_DATA_START_CODE 0x1B2 +#define SEQUENCE_HEADER_CODE 0x1B3 +#define SEQUENCE_ERROR_CODE 0x1B4 +#define EXTENSION_START_CODE 0x1B5 +#define SEQUENCE_END_CODE 0x1B7 +#define GROUP_START_CODE 0x1B8 +#define SYSTEM_START_CODE_MIN 0x1B9 +#define SYSTEM_START_CODE_MAX 0x1FF + +#define ISO_END_CODE 0x1B9 +#define PACK_START_CODE 0x1BA +#define SYSTEM_START_CODE 0x1BB + +#define VIDEO_ELEMENTARY_STREAM 0x1e0 + +/* scalable_mode */ +#define SC_NONE 0 +#define SC_DP 1 +#define SC_SPAT 2 +#define SC_SNR 3 +#define SC_TEMP 4 + +/* picture coding type */ +#define I_TYPE 1 +#define P_TYPE 2 +#define B_TYPE 3 +#define D_TYPE 4 + +/* picture structure */ +#define TOP_FIELD 1 +#define BOTTOM_FIELD 2 +#define FRAME_PICTURE 3 + +/* macroblock type */ +#define MACROBLOCK_INTRA 1 +#define MACROBLOCK_PATTERN 2 +#define MACROBLOCK_MOTION_BACKWARD 4 +#define MACROBLOCK_MOTION_FORWARD 8 +#define MACROBLOCK_QUANT 16 +#define SPATIAL_TEMPORAL_WEIGHT_CODE_FLAG 32 +#define PERMITTED_SPATIAL_TEMPORAL_WEIGHT_CLASS 64 + + +/* motion_type */ +#define MC_FIELD 1 +#define MC_FRAME 2 +#define MC_16X8 2 +#define MC_DMV 3 + +/* mv_format */ +#define MV_FIELD 0 +#define MV_FRAME 1 + +/* chroma_format */ +#define CHROMA420 1 +#define CHROMA422 2 +#define CHROMA444 3 + +/* extension start code IDs */ + +#define SEQUENCE_EXTENSION_ID 1 +#define SEQUENCE_DISPLAY_EXTENSION_ID 2 +#define QUANT_MATRIX_EXTENSION_ID 3 +#define COPYRIGHT_EXTENSION_ID 4 +#define SEQUENCE_SCALABLE_EXTENSION_ID 5 +#define PICTURE_DISPLAY_EXTENSION_ID 7 +#define PICTURE_CODING_EXTENSION_ID 8 +#define PICTURE_SPATIAL_SCALABLE_EXTENSION_ID 9 +#define PICTURE_TEMPORAL_SCALABLE_EXTENSION_ID 10 + +#define ZIG_ZAG 0 + +#define PROFILE_422 (128+5) +#define MAIN_LEVEL 8 + +/* Layers: used by Verbose_Flag, Verifier_Flag, Stats_Flag, and Trace_Flag */ +#define NO_LAYER 0 +#define SEQUENCE_LAYER 1 +#define PICTURE_LAYER 2 +#define SLICE_LAYER 3 +#define MACROBLOCK_LAYER 4 +#define BLOCK_LAYER 5 +#define EVENT_LAYER 6 +#define ALL_LAYERS 7 + + + +#define FILENAME_LENGTH 256 + + + + +#define MB_WEIGHT 32 +#define MB_CLASS4 64 + diff --git a/libfbui/MPEG/recon.c b/libfbui/MPEG/recon.c @@ -0,0 +1,467 @@ +/* Predict.c, motion compensation routines */ + +/* Copyright (C) 1996, MPEG Software Simulation Group. All Rights Reserved. */ + +/* + * Disclaimer of Warranty + * + * These software programs are available to the user without any license fee or + * royalty on an "as is" basis. The MPEG Software Simulation Group disclaims + * any and all warranties, whether express, implied, or statuary, including any + * implied warranties or merchantability or of fitness for a particular + * purpose. In no event shall the copyright-holder be liable for any + * incidental, punitive, or consequential damages of any kind whatsoever + * arising from the use of these programs. + * + * This disclaimer of warranty extends to the user of these programs and user's + * customers, employees, agents, transferees, successors, and assigns. + * + * The MPEG Software Simulation Group does not represent or warrant that the + * programs furnished hereunder are free of infringement of any third-party + * patents. + * + * Commercial implementations of MPEG-1 and MPEG-2 video, including shareware, + * are subject to royalty fees to patent holders. Many of these patents are + * general enough such that they are unavoidable regardless of implementation + * design. + * + */ + +#include <stdio.h> + +#include "config.h" +#include "global.h" + +/* private prototypes */ +static void form_prediction _ANSI_ARGS_((unsigned char *src[], int sfield, + unsigned char *dst[], int dfield, + int lx, int lx2, int w, int h, int x, int y, int dx, int dy, + int average_flag)); + +static void form_component_prediction _ANSI_ARGS_((unsigned char *src, unsigned char *dst, + int lx, int lx2, int w, int h, int x, int y, int dx, int dy, int average_flag)); + +void form_predictions(bx,by,macroblock_type,motion_type,PMV,motion_vertical_field_select,dmvector,stwtype) +int bx, by; +int macroblock_type; +int motion_type; +int PMV[2][2][2], motion_vertical_field_select[2][2], dmvector[2]; +int stwtype; +{ + int currentfield; + unsigned char **predframe; + int DMV[2][2]; + int stwtop, stwbot; + + stwtop = stwtype%3; /* 0:temporal, 1:(spat+temp)/2, 2:spatial */ + stwbot = stwtype/3; + + if ((macroblock_type & MACROBLOCK_MOTION_FORWARD) + || (picture_coding_type==P_TYPE)) + { + if (picture_structure==FRAME_PICTURE) + { + if ((motion_type==MC_FRAME) + || !(macroblock_type & MACROBLOCK_MOTION_FORWARD)) + { + /* frame-based prediction (broken into top and bottom halves + for spatial scalability prediction purposes) */ + if (stwtop<2) + form_prediction(forward_reference_frame,0,current_frame,0, + Coded_Picture_Width,Coded_Picture_Width<<1,16,8,bx,by, + PMV[0][0][0],PMV[0][0][1],stwtop); + + if (stwbot<2) + form_prediction(forward_reference_frame,1,current_frame,1, + Coded_Picture_Width,Coded_Picture_Width<<1,16,8,bx,by, + PMV[0][0][0],PMV[0][0][1],stwbot); + } + else if (motion_type==MC_FIELD) /* field-based prediction */ + { + /* top field prediction */ + if (stwtop<2) + form_prediction(forward_reference_frame,motion_vertical_field_select[0][0], + current_frame,0,Coded_Picture_Width<<1,Coded_Picture_Width<<1,16,8, + bx,by>>1,PMV[0][0][0],PMV[0][0][1]>>1,stwtop); + + /* bottom field prediction */ + if (stwbot<2) + form_prediction(forward_reference_frame,motion_vertical_field_select[1][0], + current_frame,1,Coded_Picture_Width<<1,Coded_Picture_Width<<1,16,8, + bx,by>>1,PMV[1][0][0],PMV[1][0][1]>>1,stwbot); + } + else if (motion_type==MC_DMV) /* dual prime prediction */ + { + /* calculate derived motion vectors */ + Dual_Prime_Arithmetic(DMV,dmvector,PMV[0][0][0],PMV[0][0][1]>>1); + + if (stwtop<2) + { + /* predict top field from top field */ + form_prediction(forward_reference_frame,0,current_frame,0, + Coded_Picture_Width<<1,Coded_Picture_Width<<1,16,8,bx,by>>1, + PMV[0][0][0],PMV[0][0][1]>>1,0); + + /* predict and add to top field from bottom field */ + form_prediction(forward_reference_frame,1,current_frame,0, + Coded_Picture_Width<<1,Coded_Picture_Width<<1,16,8,bx,by>>1, + DMV[0][0],DMV[0][1],1); + } + + if (stwbot<2) + { + /* predict bottom field from bottom field */ + form_prediction(forward_reference_frame,1,current_frame,1, + Coded_Picture_Width<<1,Coded_Picture_Width<<1,16,8,bx,by>>1, + PMV[0][0][0],PMV[0][0][1]>>1,0); + + /* predict and add to bottom field from top field */ + form_prediction(forward_reference_frame,0,current_frame,1, + Coded_Picture_Width<<1,Coded_Picture_Width<<1,16,8,bx,by>>1, + DMV[1][0],DMV[1][1],1); + } + } + else + /* invalid motion_type */ + printf("invalid motion_type\n"); + } + else /* TOP_FIELD or BOTTOM_FIELD */ + { + /* field picture */ + currentfield = (picture_structure==BOTTOM_FIELD); + + /* determine which frame to use for prediction */ + if ((picture_coding_type==P_TYPE) && Second_Field + && (currentfield!=motion_vertical_field_select[0][0])) + predframe = backward_reference_frame; /* same frame */ + else + predframe = forward_reference_frame; /* previous frame */ + + if ((motion_type==MC_FIELD) + || !(macroblock_type & MACROBLOCK_MOTION_FORWARD)) + { + /* field-based prediction */ + if (stwtop<2) + form_prediction(predframe,motion_vertical_field_select[0][0],current_frame,0, + Coded_Picture_Width<<1,Coded_Picture_Width<<1,16,16,bx,by, + PMV[0][0][0],PMV[0][0][1],stwtop); + } + else if (motion_type==MC_16X8) + { + if (stwtop<2) + { + form_prediction(predframe,motion_vertical_field_select[0][0],current_frame,0, + Coded_Picture_Width<<1,Coded_Picture_Width<<1,16,8,bx,by, + PMV[0][0][0],PMV[0][0][1],stwtop); + + /* determine which frame to use for lower half prediction */ + if ((picture_coding_type==P_TYPE) && Second_Field + && (currentfield!=motion_vertical_field_select[1][0])) + predframe = backward_reference_frame; /* same frame */ + else + predframe = forward_reference_frame; /* previous frame */ + + form_prediction(predframe,motion_vertical_field_select[1][0],current_frame,0, + Coded_Picture_Width<<1,Coded_Picture_Width<<1,16,8,bx,by+8, + PMV[1][0][0],PMV[1][0][1],stwtop); + } + } + else if (motion_type==MC_DMV) /* dual prime prediction */ + { + if (Second_Field) + predframe = backward_reference_frame; /* same frame */ + else + predframe = forward_reference_frame; /* previous frame */ + + /* calculate derived motion vectors */ + Dual_Prime_Arithmetic(DMV,dmvector,PMV[0][0][0],PMV[0][0][1]); + + /* predict from field of same parity */ + form_prediction(forward_reference_frame,currentfield,current_frame,0, + Coded_Picture_Width<<1,Coded_Picture_Width<<1,16,16,bx,by, + PMV[0][0][0],PMV[0][0][1],0); + + /* predict from field of opposite parity */ + form_prediction(predframe,!currentfield,current_frame,0, + Coded_Picture_Width<<1,Coded_Picture_Width<<1,16,16,bx,by, + DMV[0][0],DMV[0][1],1); + } + else + /* invalid motion_type */ + printf("invalid motion_type\n"); + } + stwtop = stwbot = 1; + } + + if (macroblock_type & MACROBLOCK_MOTION_BACKWARD) + { + if (picture_structure==FRAME_PICTURE) + { + if (motion_type==MC_FRAME) + { + /* frame-based prediction */ + if (stwtop<2) + form_prediction(backward_reference_frame,0,current_frame,0, + Coded_Picture_Width,Coded_Picture_Width<<1,16,8,bx,by, + PMV[0][1][0],PMV[0][1][1],stwtop); + + if (stwbot<2) + form_prediction(backward_reference_frame,1,current_frame,1, + Coded_Picture_Width,Coded_Picture_Width<<1,16,8,bx,by, + PMV[0][1][0],PMV[0][1][1],stwbot); + } + else /* field-based prediction */ + { + /* top field prediction */ + if (stwtop<2) + form_prediction(backward_reference_frame,motion_vertical_field_select[0][1], + current_frame,0,Coded_Picture_Width<<1,Coded_Picture_Width<<1,16,8, + bx,by>>1,PMV[0][1][0],PMV[0][1][1]>>1,stwtop); + + /* bottom field prediction */ + if (stwbot<2) + form_prediction(backward_reference_frame,motion_vertical_field_select[1][1], + current_frame,1,Coded_Picture_Width<<1,Coded_Picture_Width<<1,16,8, + bx,by>>1,PMV[1][1][0],PMV[1][1][1]>>1,stwbot); + } + } + else /* TOP_FIELD or BOTTOM_FIELD */ + { + /* field picture */ + if (motion_type==MC_FIELD) + { + /* field-based prediction */ + form_prediction(backward_reference_frame,motion_vertical_field_select[0][1], + current_frame,0,Coded_Picture_Width<<1,Coded_Picture_Width<<1,16,16, + bx,by,PMV[0][1][0],PMV[0][1][1],stwtop); + } + else if (motion_type==MC_16X8) + { + form_prediction(backward_reference_frame,motion_vertical_field_select[0][1], + current_frame,0,Coded_Picture_Width<<1,Coded_Picture_Width<<1,16,8, + bx,by,PMV[0][1][0],PMV[0][1][1],stwtop); + + form_prediction(backward_reference_frame,motion_vertical_field_select[1][1], + current_frame,0,Coded_Picture_Width<<1,Coded_Picture_Width<<1,16,8, + bx,by+8,PMV[1][1][0],PMV[1][1][1],stwtop); + } + else + /* invalid motion_type */ + printf("invalid motion_type\n"); + } + } +} + +static void form_prediction(src,sfield,dst,dfield,lx,lx2,w,h,x,y,dx,dy,average_flag) +unsigned char *src[]; /* prediction source buffer */ +int sfield; /* prediction source field number (0 or 1) */ +unsigned char *dst[]; /* prediction destination buffer */ +int dfield; /* prediction destination field number (0 or 1)*/ +int lx,lx2; /* line strides */ +int w,h; /* prediction block/sub-block width, height */ +int x,y; /* pixel co-ordinates of top-left sample in current MB */ +int dx,dy; /* horizontal, vertical prediction address */ +int average_flag; /* add prediction error to prediction ? */ +{ + /* Y */ + form_component_prediction(src[0]+(sfield?lx2>>1:0),dst[0]+(dfield?lx2>>1:0), + lx,lx2,w,h,x,y,dx,dy,average_flag); + + if (chroma_format!=CHROMA444) + { + lx>>=1; lx2>>=1; w>>=1; x>>=1; dx/=2; + } + + if (chroma_format==CHROMA420) + { + h>>=1; y>>=1; dy/=2; + } + + /* Cb */ + form_component_prediction(src[1]+(sfield?lx2>>1:0),dst[1]+(dfield?lx2>>1:0), + lx,lx2,w,h,x,y,dx,dy,average_flag); + + /* Cr */ + form_component_prediction(src[2]+(sfield?lx2>>1:0),dst[2]+(dfield?lx2>>1:0), + lx,lx2,w,h,x,y,dx,dy,average_flag); +} + +/* ISO/IEC 13818-2 section 7.6.4: Forming predictions */ +/* NOTE: the arithmetic below produces numerically equivalent results + * to 7.6.4, yet is more elegant. It differs in the following ways: + * + * 1. the vectors (dx, dy) are based on cartesian frame + * coordiantes along a half-pel grid (always positive numbers) + * In contrast, vector[r][s][t] are differential (with positive and + * negative values). As a result, deriving the integer vectors + * (int_vec[t]) from dx, dy is accomplished by a simple right shift. + * + * 2. Half pel flags (xh, yh) are equivalent to the LSB (Least + * Significant Bit) of the half-pel coordinates (dx,dy). + * + * + * NOTE: the work of combining predictions (ISO/IEC 13818-2 section 7.6.7) + * is distributed among several other stages. This is accomplished by + * folding line offsets into the source and destination (src,dst) + * addresses (note the call arguments to form_prediction() in Predict()), + * line stride variables lx and lx2, the block dimension variables (w,h), + * average_flag, and by the very order in which Predict() is called. + * This implementation design (implicitly different than the spec) + * was chosen for its elegance. +*/ + +static void form_component_prediction(src,dst,lx,lx2,w,h,x,y,dx,dy,average_flag) +unsigned char *src; +unsigned char *dst; +int lx; /* raster line increment */ +int lx2; +int w,h; +int x,y; +int dx,dy; +int average_flag; /* flag that signals bi-directional or Dual-Prime + averaging (7.6.7.1 and 7.6.7.4). if average_flag==1, + a previously formed prediction has been stored in + pel_pred[] */ +{ + int xint; /* horizontal integer sample vector: analogous to int_vec[0] */ + int yint; /* vertical integer sample vectors: analogous to int_vec[1] */ + int xh; /* horizontal half sample flag: analogous to half_flag[0] */ + int yh; /* vertical half sample flag: analogous to half_flag[1] */ + int i, j, v; + unsigned char *s; /* source pointer: analogous to pel_ref[][] */ + unsigned char *d; /* destination pointer: analogous to pel_pred[][] */ + + /* half pel scaling for integer vectors */ + xint = dx>>1; + yint = dy>>1; + + /* derive half pel flags */ + xh = dx & 1; + yh = dy & 1; + + /* compute the linear address of pel_ref[][] and pel_pred[][] + based on cartesian/raster cordinates provided */ + s = src + lx*(y+yint) + x + xint; + d = dst + lx*y + x; + + if (!xh && !yh) /* no horizontal nor vertical half-pel */ + { + if (average_flag) + { + for (j=0; j<h; j++) + { + for (i=0; i<w; i++) + { + v = d[i]+s[i]; + d[i] = (v+(v>=0?1:0))>>1; + } + + s+= lx2; + d+= lx2; + } + } + else + { + for (j=0; j<h; j++) + { + for (i=0; i<w; i++) + { + d[i] = s[i]; + } + + s+= lx2; + d+= lx2; + } + } + } + else if (!xh && yh) /* no horizontal but vertical half-pel */ + { + if (average_flag) + { + for (j=0; j<h; j++) + { + for (i=0; i<w; i++) + { + v = d[i] + ((unsigned int)(s[i]+s[i+lx]+1)>>1); + d[i]=(v+(v>=0?1:0))>>1; + } + + s+= lx2; + d+= lx2; + } + } + else + { + for (j=0; j<h; j++) + { + for (i=0; i<w; i++) + { + d[i] = (unsigned int)(s[i]+s[i+lx]+1)>>1; + } + + s+= lx2; + d+= lx2; + } + } + } + else if (xh && !yh) /* horizontal but no vertical half-pel */ + { + if (average_flag) + { + for (j=0; j<h; j++) + { + for (i=0; i<w; i++) + { + v = d[i] + ((unsigned int)(s[i]+s[i+1]+1)>>1); + d[i] = (v+(v>=0?1:0))>>1; + } + + s+= lx2; + d+= lx2; + } + } + else + { + for (j=0; j<h; j++) + { + for (i=0; i<w; i++) + { + d[i] = (unsigned int)(s[i]+s[i+1]+1)>>1; + } + + s+= lx2; + d+= lx2; + } + } + } + else /* if (xh && yh) horizontal and vertical half-pel */ + { + if (average_flag) + { + for (j=0; j<h; j++) + { + for (i=0; i<w; i++) + { + v = d[i] + ((unsigned int)(s[i]+s[i+1]+s[i+lx]+s[i+lx+1]+2)>>2); + d[i] = (v+(v>=0?1:0))>>1; + } + + s+= lx2; + d+= lx2; + } + } + else + { + for (j=0; j<h; j++) + { + for (i=0; i<w; i++) + { + d[i] = (unsigned int)(s[i]+s[i+1]+s[i+lx]+s[i+lx+1]+2)>>2; + } + + s+= lx2; + d+= lx2; + } + } + } +} diff --git a/libfbui/MPEG/spatscal.c b/libfbui/MPEG/spatscal.c @@ -0,0 +1,331 @@ + +#include <stdio.h> +#include "config.h" +#include "global.h" + +/* private prototypes */ +static void Read_Lower_Layer_Component_Framewise _ANSI_ARGS_((int comp, int lw, int lh)); +static void Read_Lower_Layer_Component_Fieldwise _ANSI_ARGS_((int comp, int lw, int lh)); +static void Make_Spatial_Prediction_Frame _ANSI_ARGS_((int progressive_frame, + int llprogressive_frame, unsigned char *fld0, unsigned char *fld1, + short *tmp, unsigned char *dst, int llx0, int lly0, int llw, int llh, + int horizontal_size, int vertical_size, int vm, int vn, int hm, int hn, + int aperture)); +static void Deinterlace _ANSI_ARGS_((unsigned char *fld0, unsigned char *fld1, + int j0, int lx, int ly, int aperture)); +static void Subsample_Vertical _ANSI_ARGS_((unsigned char *s, short *d, + int lx, int lys, int lyd, int m, int n, int j0, int dj)); +static void Subsample_Horizontal _ANSI_ARGS_((short *s, unsigned char *d, + int x0, int lx, int lxs, int lxd, int ly, int m, int n)); + + + +/* get reference frame */ +void Spatial_Prediction() +{ + + if(Frame_Store_Flag) + { + Read_Lower_Layer_Component_Framewise(0,lower_layer_prediction_horizontal_size, + lower_layer_prediction_vertical_size); /* Y */ + Read_Lower_Layer_Component_Framewise(1,lower_layer_prediction_horizontal_size>>1, + lower_layer_prediction_vertical_size>>1); /* Cb ("U") */ + Read_Lower_Layer_Component_Framewise(2,lower_layer_prediction_horizontal_size>>1, + lower_layer_prediction_vertical_size>>1); /* Cr ("V") */ + } + else + { + Read_Lower_Layer_Component_Fieldwise(0,lower_layer_prediction_horizontal_size, + lower_layer_prediction_vertical_size); /* Y */ + Read_Lower_Layer_Component_Fieldwise(1,lower_layer_prediction_horizontal_size>>1, + lower_layer_prediction_vertical_size>>1); /* Cb ("U") */ + Read_Lower_Layer_Component_Fieldwise(2,lower_layer_prediction_horizontal_size>>1, + lower_layer_prediction_vertical_size>>1); /* Cr ("V") */ + } + + + Make_Spatial_Prediction_Frame /* Y */ + (progressive_frame,lower_layer_progressive_frame,llframe0[0],llframe1[0], + lltmp,current_frame[0],lower_layer_horizontal_offset, + lower_layer_vertical_offset, + lower_layer_prediction_horizontal_size, + lower_layer_prediction_vertical_size, + horizontal_size,vertical_size,vertical_subsampling_factor_m, + vertical_subsampling_factor_n,horizontal_subsampling_factor_m, + horizontal_subsampling_factor_n, + picture_structure!=FRAME_PICTURE); /* this changed from CD to DIS */ + + Make_Spatial_Prediction_Frame /* Cb */ + (progressive_frame,lower_layer_progressive_frame,llframe0[1],llframe1[1], + lltmp,current_frame[1],lower_layer_horizontal_offset/2, + lower_layer_vertical_offset/2, + lower_layer_prediction_horizontal_size>>1, + lower_layer_prediction_vertical_size>>1, + horizontal_size>>1,vertical_size>>1,vertical_subsampling_factor_m, + vertical_subsampling_factor_n,horizontal_subsampling_factor_m, + horizontal_subsampling_factor_n,1); + + Make_Spatial_Prediction_Frame /* Cr */ + (progressive_frame,lower_layer_progressive_frame,llframe0[2],llframe1[2], + lltmp,current_frame[2],lower_layer_horizontal_offset/2, + lower_layer_vertical_offset/2, + lower_layer_prediction_horizontal_size>>1, + lower_layer_prediction_vertical_size>>1, + horizontal_size>>1,vertical_size>>1,vertical_subsampling_factor_m, + vertical_subsampling_factor_n,horizontal_subsampling_factor_m, + horizontal_subsampling_factor_n,1); + +} + +static void Read_Lower_Layer_Component_Framewise(comp,lw,lh) + int comp; + int lw, lh; +{ + FILE *fd; + char fname[256]; + char ext[3][3] = {".Y",".U",".V"}; +/* char *ext = {".Y",".U",".V"}; */ + int i,j; + + sprintf(fname,Lower_Layer_Picture_Filename,True_Framenum); + strcat(fname,ext[comp]); +#ifdef VERBOSE + if (Verbose_Flag>1) + printf("reading %s\n",fname); +#endif VERBOSE + fd=fopen(fname,"rb"); + if (fd==NULL) exit(-1); + for (j=0; j<lh; j++) { + for (i=0; i<lw; i++) + llframe0[comp][lw*j+i]=getc(fd); + if (! lower_layer_progressive_frame) { + j++; + for (i=0; i<lw; i++) + llframe1[comp][lw*j+i]=getc(fd); + } + } + fclose(fd); +} + + +static void Read_Lower_Layer_Component_Fieldwise(comp,lw,lh) + int comp; + int lw, lh; +{ + FILE *fd; + char fname[256]; + char ext[3][3] = {".Y",".U",".V"}; +/* char *ext = {".Y",".U",".V"}; */ + int i,j; + + sprintf(fname,Lower_Layer_Picture_Filename,True_Framenum,lower_layer_progressive_frame ? 'f':'a'); + strcat(fname,ext[comp]); +#ifdef VERBOSE + if (Verbose_Flag>1) + printf("reading %s\n",fname); +#endif VERBOSE + fd=fopen(fname,"rb"); + if (fd==NULL) exit(-1); + for (j=0; j<lh; j+=lower_layer_progressive_frame?1:2) + for (i=0; i<lw; i++) + llframe0[comp][lw*j+i]=getc(fd); + fclose(fd); + + if (! lower_layer_progressive_frame) { + sprintf(fname,Lower_Layer_Picture_Filename,True_Framenum,'b'); + strcat(fname,ext[comp]); +#ifdef VERBOSE + if (Verbose_Flag>1) + printf("reading %s\n",fname); +#endif VERBOSE + fd=fopen(fname,"rb"); + if (fd==NULL) exit(-1); + for (j=1; j<lh; j+=2) + for (i=0; i<lw; i++) + llframe1[comp][lw*j+i]=getc(fd); + fclose(fd); + } +} + + +/* form spatial prediction */ +static void Make_Spatial_Prediction_Frame(progressive_frame, + llprogressive_frame,fld0,fld1,tmp,dst,llx0,lly0,llw,llh,horizontal_size, + vertical_size,vm,vn,hm,hn,aperture) +int progressive_frame,llprogressive_frame; +unsigned char *fld0,*fld1; +short *tmp; +unsigned char *dst; +int llx0,lly0,llw,llh,horizontal_size,vertical_size,vm,vn,hm,hn,aperture; +{ + int w, h, x0, llw2, llh2; + + llw2 = (llw*hn)/hm; + llh2 = (llh*vn)/vm; + + if (llprogressive_frame) + { + /* progressive -> progressive / interlaced */ + Subsample_Vertical(fld0,tmp,llw,llh,llh2,vm,vn,0,1); + } + else if (progressive_frame) + { + /* interlaced -> progressive */ + if (lower_layer_deinterlaced_field_select) + { + Deinterlace(fld1,fld0,0,llw,llh,aperture); + Subsample_Vertical(fld1,tmp,llw,llh,llh2,vm,vn,0,1); + } + else + { + Deinterlace(fld0,fld1,1,llw,llh,aperture); + Subsample_Vertical(fld0,tmp,llw,llh,llh2,vm,vn,0,1); + } + } + else + { + /* interlaced -> interlaced */ + Deinterlace(fld0,fld1,1,llw,llh,aperture); + Deinterlace(fld1,fld0,0,llw,llh,aperture); + Subsample_Vertical(fld0,tmp,llw,llh,llh2,vm,vn,0,2); + Subsample_Vertical(fld1,tmp,llw,llh,llh2,vm,vn,1,2); + } + + /* vertical limits */ + if (lly0<0) + { + tmp-= llw*lly0; + llh2+= lly0; + if (llh2<0) + llh2 = 0; + h = (vertical_size<llh2) ? vertical_size : llh2; + } + else + { + dst+= horizontal_size*lly0; + h= vertical_size - lly0; + if (h>llh2) + h = llh2; + } + + /* horizontal limits */ + if (llx0<0) + { + x0 = -llx0; + llw2+= llx0; + if (llw2<0) + llw2 = 0; + w = (horizontal_size<llw2) ? horizontal_size : llw2; + } + else + { + dst+= llx0; + x0 = 0; + w = horizontal_size - llx0; + if (w>llw2) + w = llw2; + } + + Subsample_Horizontal(tmp,dst,x0,w,llw,horizontal_size,h,hm,hn); +} + +/* deinterlace one field (interpolate opposite parity samples) + * + * deinterlacing is done in-place: if j0=1, fld0 contains the input field in + * its even lines and the odd lines are interpolated by this routine + * if j0=0, the input field is in the odd lines and the even lines are + * interpolated + * + * fld0: field to be deinterlaced + * fld1: other field (referenced by the two field aperture filter) + * j0: 0: interpolate even (top) lines, 1: interpolate odd (bottom) lines + * lx: width of fld0 and fld1 + * ly: height of the deinterlaced field (has to be even) + * aperture: 1: use one field aperture filter (two field otherwise) + */ +static void Deinterlace(fld0,fld1,j0,lx,ly,aperture) +unsigned char *fld0,*fld1; +int j0,lx,ly; /* ly has to be even */ +int aperture; +{ + int i,j,v; + unsigned char *p0, *p0m1, *p0p1, *p1, *p1m2, *p1p2; + + /* deinterlace one field */ + for (j=j0; j<ly; j+=2) + { + p0 = fld0+lx*j; + p0m1 = (j==0) ? p0+lx : p0-lx; + p0p1 = (j==ly-1) ? p0-lx : p0+lx; + + if (aperture) + for (i=0; i<lx; i++) + p0[i] = (unsigned int)(p0m1[i] + p0p1[i] + 1)>>1; + else + { + p1 = fld1 + lx*j; + p1m2 = (j<2) ? p1 : p1-2*lx; + p1p2 = (j>=ly-2) ? p1 : p1+2*lx; + for (i=0; i<lx; i++) + { + v = 8*(p0m1[i]+p0p1[i]) + 2*p1[i] - p1m2[i] - p1p2[i]; + p0[i] = Clip[(v + ((v>=0) ? 8 : 7))>>4]; + } + } + } +} + +/* vertical resampling */ +static void Subsample_Vertical(s,d,lx,lys,lyd,m,n,j0,dj) +unsigned char *s; +short *d; +int lx, lys, lyd, m, n, j0, dj; +{ + int i, j, c1, c2, jd; + unsigned char *s1, *s2; + short *d1; + + for (j=j0; j<lyd; j+=dj) + { + d1 = d + lx*j; + jd = (j*m)/n; + s1 = s + lx*jd; + s2 = (jd<lys-1)? s1+lx : s1; + c2 = (16*((j*m)%n) + (n>>1))/n; + c1 = 16 - c2; + for (i=0; i<lx; i++) + d1[i] = c1*s1[i] + c2*s2[i]; + } +} + +/* horizontal resampling */ +static void Subsample_Horizontal(s,d,x0,lx,lxs,lxd,ly,m,n) +short *s; +unsigned char *d; +int x0, lx, lxs, lxd, ly, m, n; +{ + int i, i1, j, id, c1, c2, v; + short *s1, *s2; + unsigned char *d1; + + for (i1=0; i1<lx; i1++) + { + d1 = d + i1; + i = x0 + i1; + id = (i*m)/n; + s1 = s+id; + s2 = (id<lxs-1) ? s1+1 : s1; + c2 = (16*((i*m)%n) + (n>>1))/n; + c1 = 16 - c2; + for (j=0; j<ly; j++) + { + v = c1*(*s1) + c2*(*s2); + *d1 = (v + ((v>=0) ? 128 : 127))>>8; + d1+= lxd; + s1+= lxs; + s2+= lxs; + } + } +} + + diff --git a/libfbui/MPEG/store.c b/libfbui/MPEG/store.c @@ -0,0 +1,749 @@ +/* store.c, picture output routines */ + +/* Copyright (C) 1996, MPEG Software Simulation Group. All Rights Reserved. */ + +/* + * Disclaimer of Warranty + * + * These software programs are available to the user without any license fee or + * royalty on an "as is" basis. The MPEG Software Simulation Group disclaims + * any and all warranties, whether express, implied, or statuary, including any + * implied warranties or merchantability or of fitness for a particular + * purpose. In no event shall the copyright-holder be liable for any + * incidental, punitive, or consequential damages of any kind whatsoever + * arising from the use of these programs. + * + * This disclaimer of warranty extends to the user of these programs and user's + * customers, employees, agents, transferees, successors, and assigns. + * + * The MPEG Software Simulation Group does not represent or warrant that the + * programs furnished hereunder are free of infringement of any third-party + * patents. + * + * Commercial implementations of MPEG-1 and MPEG-2 video, including shareware, + * are subject to royalty fees to patent holders. Many of these patents are + * general enough such that they are unavoidable regardless of implementation + * design. + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <fcntl.h> +#include <time.h> + +#include "config.h" +#include "global.h" + +#include "../libfbui.h" + +#ifndef DISPLAY /* if not X11 */ +static Display *fbui_display = NULL; +static Window *fbui_window = NULL; + +extern int fbui_console; + +static time_t t = 0; +static int frame_counter = 0; + +void shutdown_fbui () { + if (fbui_display) + fbui_display_close (fbui_display); +} +#endif + +/* private prototypes */ +static void store_one _ANSI_ARGS_((char *outname, unsigned char *src[], + int offset, int incr, int height)); +static void store_yuv _ANSI_ARGS_((char *outname, unsigned char *src[], + int offset, int incr, int height)); +static void store_sif _ANSI_ARGS_((char *outname, unsigned char *src[], + int offset, int incr, int height)); +static void store_fbui _ANSI_ARGS_((char *outname, unsigned char *src[], + int offset, int incr, int height, int tgaflag)); +static void store_ppm_tga _ANSI_ARGS_((char *outname, unsigned char *src[], + int offset, int incr, int height, int tgaflag)); +static void store_yuv1 _ANSI_ARGS_((char *name, unsigned char *src, + int offset, int incr, int width, int height)); +static void putbyte _ANSI_ARGS_((int c)); +static void putword _ANSI_ARGS_((int w)); +static void conv422to444 _ANSI_ARGS_((unsigned char *src, unsigned char *dst)); +static void conv420to422 _ANSI_ARGS_((unsigned char *src, unsigned char *dst)); + +#define OBFRSIZE 4096 +static unsigned char obfr[OBFRSIZE]; +static unsigned char *optr; +static int outfile; + +/* + * store a picture as either one frame or two fields + */ +void Write_Frame(src,frame) +unsigned char *src[]; +int frame; +{ + char outname[FILENAME_LENGTH]; + + if (progressive_sequence || progressive_frame || Frame_Store_Flag) + { + /* progressive */ + sprintf(outname,Output_Picture_Filename,frame,'f'); + store_one(outname,src,0,Coded_Picture_Width,vertical_size); + } + else + { + /* interlaced */ + sprintf(outname,Output_Picture_Filename,frame,'a'); + store_one(outname,src,0,Coded_Picture_Width<<1,vertical_size>>1); + + sprintf(outname,Output_Picture_Filename,frame,'b'); + store_one(outname,src, + Coded_Picture_Width,Coded_Picture_Width<<1,vertical_size>>1); + } +} + +/* + * store one frame or one field + */ +static void store_one(outname,src,offset,incr,height) +char *outname; +unsigned char *src[]; +int offset, incr, height; +{ + switch (Output_Type) + { + case T_YUV: + store_yuv(outname,src,offset,incr,height); + break; + case T_SIF: + store_sif(outname,src,offset,incr,height); + break; + case T_TGA: + store_ppm_tga(outname,src,offset,incr,height,1); + break; + case T_PPM: + store_ppm_tga(outname,src,offset,incr,height,0); + break; + case T_FBUI: + store_fbui (outname,src,offset,incr,height,0); + break; + +#ifdef DISPLAY + case T_X11: + dither(src); + break; +#endif + default: + break; + } +} + +/* separate headerless files for y, u and v */ +static void store_yuv(outname,src,offset,incr,height) +char *outname; +unsigned char *src[]; +int offset,incr,height; +{ + int hsize; + char tmpname[FILENAME_LENGTH]; + + hsize = horizontal_size; + + sprintf(tmpname,"%s.Y",outname); + store_yuv1(tmpname,src[0],offset,incr,hsize,height); + + if (chroma_format!=CHROMA444) + { + offset>>=1; incr>>=1; hsize>>=1; + } + + if (chroma_format==CHROMA420) + { + height>>=1; + } + + sprintf(tmpname,"%s.U",outname); + store_yuv1(tmpname,src[1],offset,incr,hsize,height); + + sprintf(tmpname,"%s.V",outname); + store_yuv1(tmpname,src[2],offset,incr,hsize,height); +} + +/* auxiliary routine */ +static void store_yuv1(name,src,offset,incr,width,height) +char *name; +unsigned char *src; +int offset,incr,width,height; +{ + int i, j; + unsigned char *p; + + if (!Quiet_Flag) + fprintf(stderr,"saving %s\n",name); + + if ((outfile = open(name,O_CREAT|O_TRUNC|O_WRONLY|O_BINARY,0666))==-1) + { + sprintf(Error_Text,"Couldn't create %s\n",name); + Error(Error_Text); + } + + optr=obfr; + + for (i=0; i<height; i++) + { + p = src + offset + incr*i; + for (j=0; j<width; j++) + putbyte(*p++); + } + + if (optr!=obfr) + write(outfile,obfr,optr-obfr); + + close(outfile); +} + +/* + * store as headerless file in U,Y,V,Y format + */ +static void store_sif (outname,src,offset,incr,height) +char *outname; +unsigned char *src[]; +int offset, incr, height; +{ + int i,j; + unsigned char *py, *pu, *pv; + static unsigned char *u422, *v422; + + if (chroma_format==CHROMA444) + Error("4:4:4 not supported for SIF format"); + + if (chroma_format==CHROMA422) + { + u422 = src[1]; + v422 = src[2]; + } + else + { + if (!u422) + { + if (!(u422 = (unsigned char *)malloc((Coded_Picture_Width>>1) + *Coded_Picture_Height))) + Error("malloc failed"); + if (!(v422 = (unsigned char *)malloc((Coded_Picture_Width>>1) + *Coded_Picture_Height))) + Error("malloc failed"); + } + + conv420to422(src[1],u422); + conv420to422(src[2],v422); + } + + strcat(outname,".SIF"); + + if (!Quiet_Flag) + fprintf(stderr,"saving %s\n",outname); + + if ((outfile = open(outname,O_CREAT|O_TRUNC|O_WRONLY|O_BINARY,0666))==-1) + { + sprintf(Error_Text,"Couldn't create %s\n",outname); + Error(Error_Text); + } + + optr = obfr; + + for (i=0; i<height; i++) + { + py = src[0] + offset + incr*i; + pu = u422 + (offset>>1) + (incr>>1)*i; + pv = v422 + (offset>>1) + (incr>>1)*i; + + for (j=0; j<horizontal_size; j+=2) + { + putbyte(*pu++); + putbyte(*py++); + putbyte(*pv++); + putbyte(*py++); + } + } + + if (optr!=obfr) + write(outfile,obfr,optr-obfr); + + close(outfile); +} + +/* + * store as PPM (PBMPLUS) or uncompressed Truevision TGA ('Targa') file + */ +static void store_ppm_tga(outname,src,offset,incr,height,tgaflag) +char *outname; +unsigned char *src[]; +int offset, incr, height; +int tgaflag; +{ + int i, j; + int y, u, v, r, g, b; + int crv, cbu, cgu, cgv; + unsigned char *py, *pu, *pv; + static unsigned char tga24[14] = {0,0,2,0,0,0,0, 0,0,0,0,0,24,32}; + char header[FILENAME_LENGTH]; + static unsigned char *u422, *v422, *u444, *v444; + + if (chroma_format==CHROMA444) + { + u444 = src[1]; + v444 = src[2]; + } + else + { + if (!u444) + { + if (chroma_format==CHROMA420) + { + if (!(u422 = (unsigned char *)malloc((Coded_Picture_Width>>1) + *Coded_Picture_Height))) + Error("malloc failed"); + if (!(v422 = (unsigned char *)malloc((Coded_Picture_Width>>1) + *Coded_Picture_Height))) + Error("malloc failed"); + } + + if (!(u444 = (unsigned char *)malloc(Coded_Picture_Width + *Coded_Picture_Height))) + Error("malloc failed"); + + if (!(v444 = (unsigned char *)malloc(Coded_Picture_Width + *Coded_Picture_Height))) + Error("malloc failed"); + } + + if (chroma_format==CHROMA420) + { + conv420to422(src[1],u422); + conv420to422(src[2],v422); + conv422to444(u422,u444); + conv422to444(v422,v444); + } + else + { + conv422to444(src[1],u444); + conv422to444(src[2],v444); + } + } + + strcat(outname,tgaflag ? ".tga" : ".ppm"); + + if (!Quiet_Flag) + fprintf(stderr,"saving %s\n",outname); + + if ((outfile = open(outname,O_CREAT|O_TRUNC|O_WRONLY|O_BINARY,0666))==-1) + { + sprintf(Error_Text,"Couldn't create %s\n",outname); + Error(Error_Text); + } + + optr = obfr; + + if (tgaflag) + { + /* TGA header */ + for (i=0; i<12; i++) + putbyte(tga24[i]); + + putword(horizontal_size); putword(height); + putbyte(tga24[12]); putbyte(tga24[13]); + } + else + { + /* PPM header */ + sprintf(header,"P6\n%d %d\n255\n",horizontal_size,height); + + for (i=0; header[i]!=0; i++) + putbyte(header[i]); + } + + /* matrix coefficients */ + crv = Inverse_Table_6_9[matrix_coefficients][0]; + cbu = Inverse_Table_6_9[matrix_coefficients][1]; + cgu = Inverse_Table_6_9[matrix_coefficients][2]; + cgv = Inverse_Table_6_9[matrix_coefficients][3]; + + for (i=0; i<height; i++) + { + py = src[0] + offset + incr*i; + pu = u444 + offset + incr*i; + pv = v444 + offset + incr*i; + + for (j=0; j<horizontal_size; j++) + { + u = *pu++ - 128; + v = *pv++ - 128; + y = 76309 * (*py++ - 16); /* (255/219)*65536 */ + r = Clip[(y + crv*v + 32768)>>16]; + g = Clip[(y - cgu*u - cgv*v + 32768)>>16]; + b = Clip[(y + cbu*u + 32786)>>16]; + + if (tgaflag) + { + putbyte(b); putbyte(g); putbyte(r); + } + else + { + putbyte(r); putbyte(g); putbyte(b); + } + } + } + + if (optr!=obfr) + write(outfile,obfr,optr-obfr); + + close(outfile); +} + +/* + * store to FBUI + */ +static void store_fbui (outname,src,offset,incr,height,tgaflag) +char *outname; +unsigned char *src[]; +int offset, incr, height; +int tgaflag; +{ + int i, j; + int y, u, v, r, g, b; + int crv, cbu, cgu, cgv; + unsigned char *py, *pu, *pv; + static unsigned char tga24[14] = {0,0,2,0,0,0,0, 0,0,0,0,0,24,32}; + char header[FILENAME_LENGTH]; + static unsigned char *u422, *v422, *u444, *v444; + + if (chroma_format==CHROMA444) + { + u444 = src[1]; + v444 = src[2]; + } + else + { + if (!u444) + { + if (chroma_format==CHROMA420) + { + if (!(u422 = (unsigned char *)malloc((Coded_Picture_Width>>1) + *Coded_Picture_Height))) + Error("malloc failed"); + if (!(v422 = (unsigned char *)malloc((Coded_Picture_Width>>1) + *Coded_Picture_Height))) + Error("malloc failed"); + } + + if (!(u444 = (unsigned char *)malloc(Coded_Picture_Width + *Coded_Picture_Height))) + Error("malloc failed"); + + if (!(v444 = (unsigned char *)malloc(Coded_Picture_Width + *Coded_Picture_Height))) + Error("malloc failed"); + } + + if (chroma_format==CHROMA420) + { + conv420to422(src[1],u422); + conv420to422(src[2],v422); + conv422to444(u422,u444); + conv422to444(v422,v444); + } + else + { + conv422to444(src[1],u444); + conv422to444(src[2],v444); + } + } + + optr = obfr; + + if (!fbui_display) { + fbui_display = fbui_display_open (); + if (!fbui_display) + FATAL ("cannot open display"); + + t = time(NULL); + + short win_w; + short win_h; + unsigned long fg = RGB_WHITE, bg = RGB_BLACK; + int argc = 1; + char *argv[] = { "foo" }; + fbui_window = fbui_window_open (fbui_display, + horizontal_size,height, &win_w, &win_h, 9999,9999, 0, 15, + &fg, &bg, "mpeg2decode", "", + FBUI_PROGTYPE_APP, + false, + false, + fbui_console, + true, + false, + false, + argc,argv); + if (!fbui_window) + FATAL ("cannot create window"); + } + + /* matrix coefficients */ + crv = Inverse_Table_6_9[matrix_coefficients][0]; + cbu = Inverse_Table_6_9[matrix_coefficients][1]; + cgu = Inverse_Table_6_9[matrix_coefficients][2]; + cgv = Inverse_Table_6_9[matrix_coefficients][3]; + + unsigned char *rows = (unsigned char*) malloc (3 * horizontal_size * height); + if (!rows) + FATAL ("cannot allocate image buffer"); + + for (i=0; i<height; i++) + { + py = src[0] + offset + incr*i; + pu = u444 + offset + incr*i; + pv = v444 + offset + incr*i; + + for (j=0; j<horizontal_size; j++) + { + u = *pu++ - 128; + v = *pv++ - 128; + y = 76309 * (*py++ - 16); /* (255/219)*65536 */ + r = Clip[(y + crv*v + 32768)>>16]; + g = Clip[(y - cgu*u - cgv*v + 32768)>>16]; + b = Clip[(y + cbu*u + 32786)>>16]; + + unsigned long row_ix = 3 * (j + i * horizontal_size); + rows [row_ix++] = r; + rows [row_ix++] = g; + rows [row_ix++] = b; + } + } + + for (i=0; i<height; i++) + { + fbui_put_rgb3 (fbui_display, fbui_window, 0, i, horizontal_size, + rows + i * horizontal_size * 3); + fbui_flush (fbui_display, fbui_window); + } + + time_t t2 = time(NULL); + if (t != t2) { + t = t2; + printf ("mpeg2decode fps = %d\n", frame_counter); + frame_counter = 0; + } + frame_counter++; + + Event ev; + if (!fbui_poll_event (fbui_display,&ev,FBUI_EVENTMASK_ALL)) { + if (ev.type == FBUI_EVENT_KEY) { + short ch = fbui_convert_key (fbui_display, ev.key); + if (ch == 'q') { + shutdown_fbui (); + exit(0); + } + } + } + + free (rows); +} + +static void putbyte(c) +int c; +{ + *optr++ = c; + + if (optr == obfr+OBFRSIZE) + { + write(outfile,obfr,OBFRSIZE); + optr = obfr; + } +} + +static void putword(w) +int w; +{ + putbyte(w); putbyte(w>>8); +} + +/* horizontal 1:2 interpolation filter */ +static void conv422to444(src,dst) +unsigned char *src,*dst; +{ + int i, i2, w, j, im3, im2, im1, ip1, ip2, ip3; + + w = Coded_Picture_Width>>1; + + if (base.MPEG2_Flag) + { + for (j=0; j<Coded_Picture_Height; j++) + { + for (i=0; i<w; i++) + { + i2 = i<<1; + im2 = (i<2) ? 0 : i-2; + im1 = (i<1) ? 0 : i-1; + ip1 = (i<w-1) ? i+1 : w-1; + ip2 = (i<w-2) ? i+2 : w-1; + ip3 = (i<w-3) ? i+3 : w-1; + + /* FIR filter coefficients (*256): 21 0 -52 0 159 256 159 0 -52 0 21 */ + /* even samples (0 0 256 0 0) */ + dst[i2] = src[i]; + + /* odd samples (21 -52 159 159 -52 21) */ + dst[i2+1] = Clip[(int)(21*(src[im2]+src[ip3]) + -52*(src[im1]+src[ip2]) + +159*(src[i]+src[ip1])+128)>>8]; + } + src+= w; + dst+= Coded_Picture_Width; + } + } + else + { + for (j=0; j<Coded_Picture_Height; j++) + { + for (i=0; i<w; i++) + { + + i2 = i<<1; + im3 = (i<3) ? 0 : i-3; + im2 = (i<2) ? 0 : i-2; + im1 = (i<1) ? 0 : i-1; + ip1 = (i<w-1) ? i+1 : w-1; + ip2 = (i<w-2) ? i+2 : w-1; + ip3 = (i<w-3) ? i+3 : w-1; + + /* FIR filter coefficients (*256): 5 -21 70 228 -37 11 */ + dst[i2] = Clip[(int)( 5*src[im3] + -21*src[im2] + +70*src[im1] + +228*src[i] + -37*src[ip1] + +11*src[ip2]+128)>>8]; + + dst[i2+1] = Clip[(int)( 5*src[ip3] + -21*src[ip2] + +70*src[ip1] + +228*src[i] + -37*src[im1] + +11*src[im2]+128)>>8]; + } + src+= w; + dst+= Coded_Picture_Width; + } + } +} + +/* vertical 1:2 interpolation filter */ +static void conv420to422(src,dst) +unsigned char *src,*dst; +{ + int w, h, i, j, j2; + int jm6, jm5, jm4, jm3, jm2, jm1, jp1, jp2, jp3, jp4, jp5, jp6, jp7; + + w = Coded_Picture_Width>>1; + h = Coded_Picture_Height>>1; + + if (progressive_frame) + { + /* intra frame */ + for (i=0; i<w; i++) + { + for (j=0; j<h; j++) + { + j2 = j<<1; + jm3 = (j<3) ? 0 : j-3; + jm2 = (j<2) ? 0 : j-2; + jm1 = (j<1) ? 0 : j-1; + jp1 = (j<h-1) ? j+1 : h-1; + jp2 = (j<h-2) ? j+2 : h-1; + jp3 = (j<h-3) ? j+3 : h-1; + + /* FIR filter coefficients (*256): 5 -21 70 228 -37 11 */ + /* New FIR filter coefficients (*256): 3 -16 67 227 -32 7 */ + dst[w*j2] = Clip[(int)( 3*src[w*jm3] + -16*src[w*jm2] + +67*src[w*jm1] + +227*src[w*j] + -32*src[w*jp1] + +7*src[w*jp2]+128)>>8]; + + dst[w*(j2+1)] = Clip[(int)( 3*src[w*jp3] + -16*src[w*jp2] + +67*src[w*jp1] + +227*src[w*j] + -32*src[w*jm1] + +7*src[w*jm2]+128)>>8]; + } + src++; + dst++; + } + } + else + { + /* intra field */ + for (i=0; i<w; i++) + { + for (j=0; j<h; j+=2) + { + j2 = j<<1; + + /* top field */ + jm6 = (j<6) ? 0 : j-6; + jm4 = (j<4) ? 0 : j-4; + jm2 = (j<2) ? 0 : j-2; + jp2 = (j<h-2) ? j+2 : h-2; + jp4 = (j<h-4) ? j+4 : h-2; + jp6 = (j<h-6) ? j+6 : h-2; + + /* Polyphase FIR filter coefficients (*256): 2 -10 35 242 -18 5 */ + /* New polyphase FIR filter coefficients (*256): 1 -7 30 248 -21 5 */ + dst[w*j2] = Clip[(int)( 1*src[w*jm6] + -7*src[w*jm4] + +30*src[w*jm2] + +248*src[w*j] + -21*src[w*jp2] + +5*src[w*jp4]+128)>>8]; + + /* Polyphase FIR filter coefficients (*256): 11 -38 192 113 -30 8 */ + /* New polyphase FIR filter coefficients (*256):7 -35 194 110 -24 4 */ + dst[w*(j2+2)] = Clip[(int)( 7*src[w*jm4] + -35*src[w*jm2] + +194*src[w*j] + +110*src[w*jp2] + -24*src[w*jp4] + +4*src[w*jp6]+128)>>8]; + + /* bottom field */ + jm5 = (j<5) ? 1 : j-5; + jm3 = (j<3) ? 1 : j-3; + jm1 = (j<1) ? 1 : j-1; + jp1 = (j<h-1) ? j+1 : h-1; + jp3 = (j<h-3) ? j+3 : h-1; + jp5 = (j<h-5) ? j+5 : h-1; + jp7 = (j<h-7) ? j+7 : h-1; + + /* Polyphase FIR filter coefficients (*256): 11 -38 192 113 -30 8 */ + /* New polyphase FIR filter coefficients (*256):7 -35 194 110 -24 4 */ + dst[w*(j2+1)] = Clip[(int)( 7*src[w*jp5] + -35*src[w*jp3] + +194*src[w*jp1] + +110*src[w*jm1] + -24*src[w*jm3] + +4*src[w*jm5]+128)>>8]; + + dst[w*(j2+3)] = Clip[(int)( 1*src[w*jp7] + -7*src[w*jp5] + +30*src[w*jp3] + +248*src[w*jp1] + -21*src[w*jm1] + +5*src[w*jm3]+128)>>8]; + } + src++; + dst++; + } + } +} diff --git a/libfbui/MPEG/subspic.c b/libfbui/MPEG/subspic.c @@ -0,0 +1,392 @@ +/* #define DEBUG */ +/* subspic.c, Frame buffer substitution routines */ + +/* Copyright (C) 1996, MPEG Software Simulation Group. All Rights Reserved. */ + +/* + * Disclaimer of Warranty + * + * These software programs are available to the user without any license fee or + * royalty on an "as is" basis. The MPEG Software Simulation Group disclaims + * any and all warranties, whether express, implied, or statuary, including any + * implied warranties or merchantability or of fitness for a particular + * purpose. In no event shall the copyright-holder be liable for any + * incidental, punitive, or consequential damages of any kind whatsoever + * arising from the use of these programs. + * + * This disclaimer of warranty extends to the user of these programs and user's + * customers, employees, agents, transferees, successors, and assigns. + * + * The MPEG Software Simulation Group does not represent or warrant that the + * programs furnished hereunder are free of infringement of any third-party + * patents. + * + * Commercial implementations of MPEG-1 and MPEG-2 video, including shareware, + * are subject to royalty fees to patent holders. Many of these patents are + * general enough such that they are unavoidable regardless of implementation + * design. + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <fcntl.h> + +#include "config.h" +#include "global.h" + +/* private prototypes*/ +static void Read_Frame _ANSI_ARGS_((char *filename, + unsigned char *frame_buffer[], int framenum)); +static void Copy_Frame _ANSI_ARGS_((unsigned char *src, unsigned char *dst, + int width, int height, int parity, int incr)); +static int Read_Components _ANSI_ARGS_ ((char *filename, + unsigned char *frame[3], int framenum)); +static int Read_Component _ANSI_ARGS_ ((char *fname, unsigned char *frame, + int width, int height)); +static int Extract_Components _ANSI_ARGS_ ((char *filename, + unsigned char *frame[3], int framenum)); + + +/* substitute frame buffer routine */ +void Substitute_Frame_Buffer (bitstream_framenum, sequence_framenum) +int bitstream_framenum; +int sequence_framenum; +{ + /* static tracking variables */ + static int previous_temporal_reference; + static int previous_bitstream_framenum; + static int previous_anchor_temporal_reference; + static int previous_anchor_bitstream_framenum; + static int previous_picture_coding_type; + static int bgate; + + /* local temporary variables */ + int substitute_display_framenum; + + +#ifdef DEBUG + printf("SUB: seq fn(%d) bitfn(%d) tempref(%d) picstr(%d) type(%d)\n", + sequence_framenum, bitstream_framenum, temporal_reference, + picture_structure, picture_coding_type); +#endif + + /* we don't substitute at the first picture of a sequence */ + if((sequence_framenum!=0)||(Second_Field)) + { + /* only at the start of the frame */ + if ((picture_structure==FRAME_PICTURE)||(!Second_Field)) + { + if(picture_coding_type==P_TYPE) + { + /* the most recently decoded reference frame needs substituting */ + substitute_display_framenum = bitstream_framenum - 1; + + Read_Frame(Substitute_Picture_Filename, forward_reference_frame, + substitute_display_framenum); + } + /* only the first B frame in a consequitve set of B pictures + loads a substitute backward_reference_frame since all subsequent + B frames predict from the same reference pictures */ + else if((picture_coding_type==B_TYPE)&&(bgate!=1)) + { + substitute_display_framenum = + (previous_temporal_reference - temporal_reference) + + bitstream_framenum - 1; + + Read_Frame(Substitute_Picture_Filename, backward_reference_frame, + substitute_display_framenum); + } + } /* P fields can predict from the two most recently decoded fields, even + from the first field of the same frame being decoded */ + else if(Second_Field && (picture_coding_type==P_TYPE)) + { + /* our favourite case: the IP field picture pair */ + if((previous_picture_coding_type==I_TYPE)&&(picture_coding_type==P_TYPE)) + { + substitute_display_framenum = bitstream_framenum; + } + else /* our more generic P field picture pair */ + { + substitute_display_framenum = + (temporal_reference - previous_anchor_temporal_reference) + + bitstream_framenum - 1; + } + + Read_Frame(Substitute_Picture_Filename, current_frame, substitute_display_framenum); + } +#ifdef DEBUG + else if((picture_coding_type!=B_TYPE)||(picture_coding_type!=D_TYPE)) + { + printf("NO SUBS FOR THIS PICTURE\n"); + } +#endif + } + + + /* set b gate so we don't redundantly load next time around */ + if(picture_coding_type==B_TYPE) + bgate = 1; + else + bgate = 0; + + /* update general tracking variables */ + if((picture_structure==FRAME_PICTURE)||(!Second_Field)) + { + previous_temporal_reference = temporal_reference; + previous_bitstream_framenum = bitstream_framenum; + } + + /* update reference frame tracking variables */ + if((picture_coding_type!=B_TYPE) && + ((picture_structure==FRAME_PICTURE)||Second_Field)) + { + previous_anchor_temporal_reference = temporal_reference; + previous_anchor_bitstream_framenum = bitstream_framenum; + } + + previous_picture_coding_type = picture_coding_type; + +} + + +/* Note: fields are only read to serve as the same-frame reference for + a second field */ +static void Read_Frame(fname,frame,framenum) +char *fname; +unsigned char *frame[]; +int framenum; +{ + int parity; + int rerr = 0; + int field_mode; + + if(framenum<0) + printf("ERROR: framenum (%d) is less than zero\n", framenum); + + + if(Big_Picture_Flag) + rerr = Extract_Components(fname, substitute_frame, framenum); + else + rerr = Read_Components(fname, substitute_frame, framenum); + + if(rerr!=0) + { + printf("was unable to substitute frame\n"); + } + + /* now copy to the appropriate buffer */ + /* first field (which we are attempting to substitute) must be + of opposite field parity to the current one */ + if((Second_Field)&&(picture_coding_type==P_TYPE)) + { + parity = (picture_structure==TOP_FIELD ? 1:0); + field_mode = (picture_structure==FRAME_PICTURE ? 0:1); + } + else + { + /* Like frame structued pictures, B pictures only substitute an entire frame + since both fields always predict from the same frame (with respect + to forward/backwards directions) */ + parity = 0; + field_mode = 0; + } + + + Copy_Frame(substitute_frame[0], frame[0], Coded_Picture_Width, + Coded_Picture_Height, parity, field_mode); + + Copy_Frame(substitute_frame[1], frame[1], Chroma_Width, Chroma_Height, + parity, field_mode); + + Copy_Frame(substitute_frame[2], frame[2], Chroma_Width, Chroma_Height, + parity, field_mode); + +#ifdef VERBOSE + if(Verbose_Flag > NO_LAYER) + printf("substituted %s %d\n", + (field_mode ? (parity?"bottom field":"bottom field"):"frame"), framenum); +#endif +} + + + + +static int Read_Components(filename, frame, framenum) +char *filename; +unsigned char *frame[3]; +int framenum; +{ + int err = 0; + char outname[FILENAME_LENGTH]; + char name[FILENAME_LENGTH]; + + sprintf(outname,filename,framenum); + + + sprintf(name,"%s.Y",outname); + err += Read_Component(name, frame[0], Coded_Picture_Width, + Coded_Picture_Height); + + sprintf(name,"%s.U",outname); + err += Read_Component(name, frame[1], Chroma_Width, Chroma_Height); + + sprintf(name,"%s.V",outname); + err += Read_Component(name, frame[2], Chroma_Width, Chroma_Height); + + return(err); +} + + +static int Read_Component(Filename, Frame, Width, Height) +char *Filename; +unsigned char *Frame; +int Width; +int Height; +{ + int Size; + int Bytes_Read; + int Infile; + + Size = Width*Height; + +#ifdef DEBUG + printf("SUBS: reading %s\n", filename); +#endif + + if(!(Infile=open(Filename,O_RDONLY|O_BINARY))<0) + { + printf("ERROR: unable to open reference filename (%s)\n", Filename); + return(-1); + } + + Bytes_Read = read(Infile, Frame, Size); + + if(Bytes_Read!=Size) + { + printf("was able to read only %d bytes of %d of file %s\n", + Bytes_Read, Size, Filename); + } + + close(Infile); + return(0); +} + + +/* optimization: do not open the big file each time. Open once at start + of decoder, and close at the very last frame */ + +/* Note: "big" files were used in E-mail exchanges almost exclusively by the + MPEG Committee's syntax validation and conformance ad-hoc groups from + the year 1993 until 1995 */ +static int Extract_Components(filename, frame, framenum) +char *filename; +unsigned char *frame[3]; +int framenum; +{ +/* int err = 0; */ + FILE *fd; + int line; + int size, offset; + + + if (!(fd = fopen(filename,"rb"))) + { + sprintf(Error_Text,"Couldn't open %s\n",filename); + return(-1); + } + + /* compute size of each frame (in bytes) */ + size = (Coded_Picture_Width*Coded_Picture_Height); + + if(chroma_format==CHROMA444) + size = (size * 3); + else if(chroma_format==CHROMA422) + size = (size * 2); + else if(chroma_format==CHROMA420) + size = ((size*3)>>1); + else + printf("ERROR: chroma_format (%d) not recognized\n", chroma_format); + + + /* compute distance into "big" file */ + offset = size*framenum; + +#ifdef DEBUG + printf("EXTRACTING: frame(%d) offset(%d), size (%d) from %s\n", + framenum, offset, size, filename); +#endif + + /* seek to location in big file where desired frame begins */ + /* note: this offset cannot exceed a few billion bytes due to the */ + /* obvious limitations of 32-bit integers */ + fseek(fd, offset, 0); + + /* Y */ + for (line=0; line<Coded_Picture_Height; line++) + { + fread(frame[0]+(line*Coded_Picture_Width),1,Coded_Picture_Width,fd); + } + + /* Cb */ + for (line=0; line<Chroma_Height; line++) + { + fread(frame[1]+(line*Chroma_Width),1,Chroma_Width,fd); + } + + /* Cr */ + for (line=0; line<Chroma_Height; line++) + { + fread(frame[2]+(line*Chroma_Width),1,Chroma_Width,fd); + } + + + fclose(fd); + return(0); +} + + +static void Copy_Frame(src, dst, width, height, parity, field_mode) +unsigned char *src; +unsigned char *dst; +int width; +int height; +int parity; /* field parity (top or bottom) to overwrite */ +int field_mode; /* 0 = frame, 1 = field */ +{ + int row, col; + int s, d; + int incr; + + s = d = 0; + +#ifdef DEBUG + printf("COPYING (w=%d, h=%d, parity=%d, field_mode=%d)\n", + width,height,parity,field_mode); +#endif /* DEBUG */ + + if(field_mode) + { + incr = 2; + + if(parity==0) + s += width; + } + else + { + incr = 1; + } + + for(row=0; row<height; row+=incr) + { + for(col=0; col<width; col++) + { + dst[d+col] = src[s+col]; + } + + d += (width*incr); + s += (width*incr); + } + +} + diff --git a/libfbui/MPEG/systems.c b/libfbui/MPEG/systems.c @@ -0,0 +1,200 @@ +/* systems.c, systems-specific routines */ + +/* Copyright (C) 1996, MPEG Software Simulation Group. All Rights Reserved. */ + +/* + * Disclaimer of Warranty + * + * These software programs are available to the user without any license fee or + * royalty on an "as is" basis. The MPEG Software Simulation Group disclaims + * any and all warranties, whether express, implied, or statuary, including any + * implied warranties or merchantability or of fitness for a particular + * purpose. In no event shall the copyright-holder be liable for any + * incidental, punitive, or consequential damages of any kind whatsoever + * arising from the use of these programs. + * + * This disclaimer of warranty extends to the user of these programs and user's + * customers, employees, agents, transferees, successors, and assigns. + * + * The MPEG Software Simulation Group does not represent or warrant that the + * programs furnished hereunder are free of infringement of any third-party + * patents. + * + * Commercial implementations of MPEG-1 and MPEG-2 video, including shareware, + * are subject to royalty fees to patent holders. Many of these patents are + * general enough such that they are unavoidable regardless of implementation + * design. + * + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "config.h" +#include "global.h" + +/* initialize buffer, call once before first getbits or showbits */ + +/* parse system layer, ignore everything we don't need */ +void Next_Packet() +{ + unsigned int code; + int l; + + for(;;) + { + code = Get_Long(); + + /* remove system layer byte stuffing */ + while ((code & 0xffffff00) != 0x100) + code = (code<<8) | Get_Byte(); + + switch(code) + { + case PACK_START_CODE: /* pack header */ + /* skip pack header (system_clock_reference and mux_rate) */ + ld->Rdptr += 8; + break; + case VIDEO_ELEMENTARY_STREAM: + code = Get_Word(); /* packet_length */ + ld->Rdmax = ld->Rdptr + code; + + code = Get_Byte(); + + if((code>>6)==0x02) + { + ld->Rdptr++; + code=Get_Byte(); /* parse PES_header_data_length */ + ld->Rdptr+=code; /* advance pointer by PES_header_data_length */ + printf("MPEG-2 PES packet\n"); + return; + } + else if(code==0xff) + { + /* parse MPEG-1 packet header */ + while((code=Get_Byte())== 0xFF); + } + + /* stuffing bytes */ + if(code>=0x40) + { + if(code>=0x80) + { + fprintf(stderr,"Error in packet header\n"); + exit(1); + } + /* skip STD_buffer_scale */ + ld->Rdptr++; + code = Get_Byte(); + } + + if(code>=0x30) + { + if(code>=0x40) + { + fprintf(stderr,"Error in packet header\n"); + exit(1); + } + /* skip presentation and decoding time stamps */ + ld->Rdptr += 9; + } + else if(code>=0x20) + { + /* skip presentation time stamps */ + ld->Rdptr += 4; + } + else if(code!=0x0f) + { + fprintf(stderr,"Error in packet header\n"); + exit(1); + } + return; + case ISO_END_CODE: /* end */ + /* simulate a buffer full of sequence end codes */ + l = 0; + while (l<2048) + { + ld->Rdbfr[l++] = SEQUENCE_END_CODE>>24; + ld->Rdbfr[l++] = SEQUENCE_END_CODE>>16; + ld->Rdbfr[l++] = SEQUENCE_END_CODE>>8; + ld->Rdbfr[l++] = SEQUENCE_END_CODE&0xff; + } + ld->Rdptr = ld->Rdbfr; + ld->Rdmax = ld->Rdbfr + 2048; + return; + default: + if(code>=SYSTEM_START_CODE) + { + /* skip system headers and non-video packets*/ + code = Get_Word(); + ld->Rdptr += code; + } + else + { + fprintf(stderr,"Unexpected startcode %08x in system layer\n",code); + exit(1); + } + break; + } + } +} + + + +void Flush_Buffer32() +{ + int Incnt; + + ld->Bfr = 0; + + Incnt = ld->Incnt; + Incnt -= 32; + + if (System_Stream_Flag && (ld->Rdptr >= ld->Rdmax-4)) + { + while (Incnt <= 24) + { + if (ld->Rdptr >= ld->Rdmax) + Next_Packet(); + ld->Bfr |= Get_Byte() << (24 - Incnt); + Incnt += 8; + } + } + else + { + while (Incnt <= 24) + { + if (ld->Rdptr >= ld->Rdbfr+2048) + Fill_Buffer(); + ld->Bfr |= *ld->Rdptr++ << (24 - Incnt); + Incnt += 8; + } + } + ld->Incnt = Incnt; + +#ifdef VERIFY + ld->Bitcnt += 32; +#endif /* VERIFY */ +} + + +unsigned int Get_Bits32() +{ + unsigned int l; + + l = Show_Bits(32); + Flush_Buffer32(); + + return l; +} + + +int Get_Long() +{ + int i; + + i = Get_Word(); + return (i<<16) | Get_Word(); +} + + diff --git a/libfbui/MPEG/verify.c b/libfbui/MPEG/verify.c @@ -0,0 +1,303 @@ +/* verify.c + * + * Bitstream verification routines + * + * + */ +#ifdef VERIFY + +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> +#include <fcntl.h> +#include <math.h> /* needed for ceil() */ + +#include "config.h" +#include "global.h" + +/* #define DEBUG */ +#ifdef DEBUG +#define PC +#endif + +#ifdef PC +#include <conio.h> /* needed for getch() */ +#endif /* PC */ + +/* + Check picture headers: due to the VBV definition of picture data, + this routine must be called immediately before any picture data + is parsed. (before the first slice start code, including any slice + start code stuffing). +*/ + + +static void Check_VBV_Delay _ANSI_ARGS_((int Bitstream_Framenum, int Sequence_Framenum)); + + +void Check_Headers(Bitstream_Framenum, Sequence_Framenum) +int Bitstream_Framenum; +int Sequence_Framenum; +{ + + + if((!low_delay)&&(vbv_delay!=0)&&(vbv_delay!=0xFFFF)) + Check_VBV_Delay(Bitstream_Framenum, Sequence_Framenum); + + /* clear out the header tracking variables so we have an accurate + count next time */ + Clear_Verify_Headers(); +} + + + +/* + * Verify vbv_delay value in picture header + * (low_delay==1 checks not implemented. this does not exhaustively test all + * possibilities suggested in ISO/IEC 13818-2 Annex C. It only checks + * for constant rate streams) + * + * Q:how do we tell a variable rate stream from a constant rate stream anyway? + * it's not as simple as vbv_delay==0xFFFF, since we need meaningful + * vbv_delay values to calculate the piecewise rate in the first place! + * + * Also: no special provisions at the beginning or end of a sequence + */ + +static void Check_VBV_Delay(Bitstream_Framenum, Sequence_Framenum) +int Bitstream_Framenum; +int Sequence_Framenum; +{ + double B; /* buffer size */ + double Bn; /* buffer fullness for picture n */ + double R; /* bitrate */ + double I; /* time interval (t[n+1] - t[n]) */ + double T; /* inverse of the frame rate (frame period) */ + + int d; + int internal_vbv_delay; + + static int previous_IorP_picture_structure; + static int previous_IorP_repeat_first_field; + static int previous_IorP_top_field_first; + static int previous_vbv_delay; + static int previous_bitstream_position; + + static double previous_Bn; + static double E; /* maximum quantization error or mismatch */ + + + + if((Sequence_Framenum==0)&&(!Second_Field)) + { /* first coded picture of sequence */ + + R = bit_rate; + + /* the initial buffer occupancy is taken on faith + that is, we believe what is transmitted in the first coded picture header + to be the true/actual buffer occupancy */ + + Bn = (R * (double) vbv_delay) / 90000.0; + B = 16 * 1024 * vbv_buffer_size; + + + /* maximum quantization error in bitrate (bit_rate_value is quantized/ + rounded-up to units of 400 bits/sec as per ISO/IEC 13818-2 + section 6.3.3 */ + + E = (400.0/frame_rate) + 400; + +#ifdef DEBUG + printf("vbv_buffer_size (B) = %.0f, Bn=%f, E=%f, \nbitrate=%f, vbv_delay=%d frame_rate=%f\n", + B, Bn, E, bit_rate, vbv_delay, frame_rate); +#endif + + } + else /* not the first coded picture of sequence */ + { + + /* derive the interval (I). The interval tells us how many constant rate bits + * will have been downloaded to the buffer during the current picture period + * + * interval assumes that: + * 1. whilst we are decoding the current I or P picture, we are displaying + * the previous I or P picture which was stored in the reorder + * buffer (pointed to by forward_reference_frame in this implementation) + * + * 2. B pictures are output ("displayed") at the time when they are decoded + * + */ + + if(progressive_sequence) /* Annex C.9 (progressive_sequence==1, low_delay==0) */ + { + + T = 1/frame_rate; /* inverse of the frame rate (frame period) */ + + if(picture_coding_type==B_TYPE) + { + if(repeat_first_field==1) + { + if(top_field_first==1) + I = T*3; /* three frame periods */ + else + I = T*2; /* two frame periods */ + } + else + I = T; /* one frame period */ + } + else /* P or I frame */ + { + if(previous_IorP_repeat_first_field==1) + { + if(previous_IorP_top_field_first==1) + I = 3*T; + else + I = 2*T; + } + else + I = T; + } + } + else /* Annex C.11 (progressive_sequence==0, low_delay==0) */ + { + + T = 1/(2*frame_rate); /* inverse of two times the frame rate (field period) */ + + if(picture_coding_type==B_TYPE) + { + if(picture_structure==FRAME_PICTURE) + { + if(repeat_first_field==0) + I = 2*T; /* two field periods */ + else + I = 3*T; /* three field periods */ + } + else /* B field */ + { + I = T; /* one field period */ + } + } + else /* I or P picture */ + { + if(picture_structure==FRAME_PICTURE) + { + if(previous_IorP_repeat_first_field==0) + I = 2*T; + else + I = 3*T; + } + else + { + if(Second_Field==0) /* first field of current frame */ + I = T; + else /* second field of current frame */ + { + /* formula: previous I or P display period (2*T or 3*T) minus the + very recent decode period (T) of the first field of the current + frame */ + + if(previous_IorP_picture_structure!=FRAME_PICTURE + || previous_IorP_repeat_first_field==0) + I = 2*T - T; /* a net of one field period */ + else if(previous_IorP_picture_structure==FRAME_PICTURE + && previous_IorP_repeat_first_field==1) + I = 3*T - T; /* a net of two field periods */ + } + } + } + } + + /* derive coded size of previous picture */ + d = ld->Bitcnt - previous_bitstream_position; + + /* Rate = Distance/Time */ + + /* piecewise constant rate (variable rate stream) calculation + * R = ((double) d /((previous_vbv_delay - vbv_delay)/90000 + I)); + */ + + R = bit_rate; + + /* compute buffer fullness just before removing picture n + * + * Bn = previous_Bn + (I*R) - d; (recursive formula) + * + * where: + * + * n is the current picture + * + * Bn is the buffer fullness for the current picture + * + * previous_Bn is the buffer fullness of the previous picture + * + * (I*R ) is the bits accumulated during the current picture + * period + * + * d is the number of bits removed during the decoding of the + * previous picture + */ + + Bn = previous_Bn + (I*R) - d; + + /* compute internally derived vbv_delay (rouding up with ceil()) */ + internal_vbv_delay = (int) ceil((90000 * Bn / bit_rate)); + +#ifdef DEBUG + printf("\nvbv_delay: internal=%d, bitstream=%d\n", internal_vbv_delay, vbv_delay); + + printf("Bn=%f, prevBn=%f, I=%f, R=%f, d=%d\n", Bn, previous_Bn, I, R, d); + printf("frame(%d), pictstruct(%d), picttype(%d)\n", Sequence_Framenum, + picture_structure, picture_coding_type); + + /* report error */ + if(internal_vbv_delay != vbv_delay) + { + printf("WARNING: internal_vbv_delay(%d) != vbv_delay(%d)\n", + internal_vbv_delay, vbv_delay); + } +#endif + + } /* not the first coded picture of sequence */ + + +#ifdef PC + getch(); +#endif /* PC */ + + /* update generic tracking variables */ + previous_bitstream_position = ld->Bitcnt ; + previous_vbv_delay = vbv_delay; + previous_Bn = Bn; + + /* reference picture: reordered/delayed output picture */ + if(picture_coding_type!=B_TYPE) + { + previous_IorP_repeat_first_field = repeat_first_field; + previous_IorP_top_field_first = top_field_first; + previous_IorP_picture_structure = picture_structure; + } + +} + + + +/* variables to keep track of the occurance of redundant headers between pictures */ +void Clear_Verify_Headers() +{ + verify_sequence_header = 0; + verify_group_of_pictures_header = 0; + verify_picture_header = 0; + verify_slice_header = 0; + verify_sequence_extension = 0; + verify_sequence_display_extension = 0; + verify_quant_matrix_extension = 0; + verify_sequence_scalable_extension = 0; + verify_picture_display_extension = 0; + verify_picture_coding_extension = 0; + verify_picture_spatial_scalable_extension = 0; + verify_picture_temporal_scalable_extension = 0; + verify_copyright_extension = 0; +} + +#endif /* VERIFY */ + diff --git a/libfbui/MailCheck/COPYING b/libfbui/MailCheck/COPYING @@ -0,0 +1,280 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS diff --git a/libfbui/MailCheck/Makefile b/libfbui/MailCheck/Makefile @@ -0,0 +1,15 @@ + +EXE=fbcheck +SRC= main.c check.c + +test: ${SRC} + gcc -lm -I.. -g ${SRC} ../libfbui.a -o ${EXE} + # strip ${EXE} + +clean: + rm -f ${EXE} + +install: ${EXE} + cp ${EXE} /usr/bin + chmod 755 /usr/bin/${EXE} + diff --git a/libfbui/MailCheck/check.c b/libfbui/MailCheck/check.c @@ -0,0 +1,164 @@ +#include <stdio.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netdb.h> +#include <netinet/in.h> +#include <arpa/nameser.h> +#include <resolv.h> + +#define PORTNUM 110 + +typedef unsigned char uchar; + +static int +getline (int fd, char *buf, int buflen) +{ + int got; + char ch; + int ix=0; + + buf[0] = 0; + + while (ix < (buflen-1)) { + got = recv (fd, &ch, 1, 0); + + if (-1 == got && !ix) { + perror ("recv"); + return -1; + } + + if (!got) + continue; + + if (ch == '\n') + break; + if (ch == '\r') + continue; + + buf [ix++] = ch; + } + + buf [ix] = 0; + return ix; +} + + +int +checkmail (char *server, char *username, char *password) +{ + int fd, result; + char buf[256]; + char *tmp; + int total=0; + int tries; + + fd = socket(PF_INET, SOCK_STREAM, 0); + if (fd == -1) { + perror("socket"); + return -1; + } + + char *s = strchr (server, '\n'); + if (s) *s=0; + s = strchr (server, '\r'); + if (s) *s=0; + s = strchr (username, '\n'); + if (s) *s=0; + s = strchr (username, '\r'); + if (s) *s=0; + s = strchr (password, '\n'); + if (s) *s=0; + s = strchr (password, '\r'); + if (s) *s=0; + + struct hostent* host; + host = gethostbyname (server); + if (!host) { + perror ("gethostbyname"); + close(fd); + return -1; + } + + struct sockaddr_in sockaddr; + memset (&sockaddr, 0, sizeof (struct sockaddr_in)); + sockaddr.sin_family = AF_INET; + sockaddr.sin_port = htons(PORTNUM); + bcopy(host->h_addr, &sockaddr.sin_addr, host->h_length); + + result = connect (fd, (struct sockaddr*) &sockaddr, + sizeof(struct sockaddr)); + if (result) { + perror ("connect"); + close(fd); + return -1; + } + + if (-1 == getline(fd, buf, 256)) { + close(fd); + return -1; + } + + sprintf (buf, "user %s\n", username); + if (0 > write (fd, buf, strlen(buf))) { + perror ("write"); + close(fd); + return -1; + } + + if (-1 == getline(fd, buf, 256)) { + close(fd); + return -1; + } + + sprintf (buf, "pass %s\n", password); + if (0 > write (fd, buf, strlen(buf))) { + perror ("write"); + close(fd); + return -1; + } + + if (-1 == getline(fd, buf, 256)) { + close(fd); + return -1; + } + + sprintf (buf, "list\n"); + if (0 > write (fd, buf, strlen(buf))) { + perror ("write"); + close(fd); + return -1; + } + + if (-1 == getline(fd, buf, 256)) { + close(fd); + return -1; + } + + if (!strncmp ("+OK", buf, 3)) { + + /* the next line has a count */ + if (-1 == getline(fd, buf, 256)) { + close(fd); + return -1; + } + + total = atoi(buf); + printf ("you have %d message(s).\n", total); + } + else + { + printf ("response not +OK: (%s)\n",buf); + } + + sprintf (buf, "quit\n"); + if (0 > write (fd, buf, strlen(buf))) { + perror ("write"); + close(fd); + return -1; + } + + close(fd); + return total; +} + + diff --git a/libfbui/MailCheck/main.c b/libfbui/MailCheck/main.c @@ -0,0 +1,168 @@ + +/*========================================================================= + * + * fbcheck, a POP3 mail checker for FBUI (in-kernel framebuffer UI) + * Copyright (C) 2004 Zachary T Smith, fbui@comcast.net + * + * This module is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This module 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this module; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * (See the file COPYING in the main directory of this archive for + * more details.) + * + *=======================================================================*/ + + +typedef unsigned long u32; +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <sys/ioctl.h> +#include <linux/fb.h> +#include <sys/mman.h> +#include <unistd.h> +#include <string.h> + +#include <linux/vt.h> +#include <linux/input.h> + +#include "libfbui.h" + + +int +main(int argc, char** argv) +{ + Display *dpy; + Window *win; + Font *pcf = font_new (); + u32 fg,bg; + char *server, *user, *pass; + + char tmp[300]; + sprintf (tmp, "%s/.fbcheckrc", getenv("HOME")); + FILE *f = fopen (tmp,"r"); + if (!f) + FATAL("cannot open configuration file (~/.fbcheckrc)"); + if (!fgets (tmp, 300, f)) + FATAL("cannot read configuration file (~/.fbcheckrc)"); + server = strdup(tmp); + if (!fgets (tmp, 300, f)) + FATAL("cannot read configuration file (~/.fbcheckrc)"); + user = strdup(tmp); + if (!fgets (tmp, 300, f)) + FATAL("cannot read configuration file (~/.fbcheckrc)"); + pass = strdup(tmp); + + if (!pcf_read (pcf, "timR10.pcf")) { + font_free (pcf); + FATAL ("cannot load font"); + } + + short line_height = pcf->ascent + pcf->descent; + + fg = RGB_YELLOW; + bg = RGB_BROWN; + + short win_w, win_h; + dpy = fbui_display_open (); + if (!dpy) + FATAL ("cannot open display"); + + win = fbui_window_open (dpy, 150,50, &win_w, &win_h, 250, 50, + 300, -1, + &fg, &bg, + "fbcheck", "", + FBUI_PROGTYPE_LAUNCHER, false,false, -1,false, + false, false, argc,argv); + if (!win) + FATAL ("cannot create window"); + + time_t t0 = time(NULL); + time_t t = t0 + 999; + while (1) { + int total; + int need_redraw=0; + Event ev; + + usleep(50000); + + if ((t - t0) >= 60) { + total = checkmail (server,user,pass); + t0 = t = time(NULL); + need_redraw=1; + } + + int err; + if (err = fbui_poll_event (dpy, &ev, + FBUI_EVENTMASK_ALL - FBUI_EVENTMASK_KEY)) + { + if (err != FBUI_ERR_NOEVENT) + fbui_print_error (err); + continue; + } +printf ("%s got event %s\n", argv[0], fbui_get_event_name (ev.type)); + + int num = ev.type; + + switch (num) { + case FBUI_EVENT_EXPOSE: + need_redraw=1; + break; + + case FBUI_EVENT_MOVE_RESIZE: + win_w = ev.width; + win_h = ev.height; + break; + + } + + if (!need_redraw) + continue; + + int underline = 0; + char text[200]; + if (total < 0) { + sprintf (text, "Mailserver unreachable"); + } else if (total > 0) { + sprintf (text, "Messages: <<%d>>", total); + underline = 1; + } else { + sprintf (text, "~ No messages ~"); + } + + short w,a,d; + font_string_dims(pcf,text,&w,&a,&d); +printf ("mc str dims %d %d %d\n",w,a,d); + + int x, y; + x = (win_w - w) / 2; + if (d < 0) + d = -d; + y = (win_h - (a+d)) / 2; + + fbui_clear (dpy, win); + fbui_draw_string (dpy, win, pcf, x,y, text, fg); + if (underline) + fbui_draw_hline (dpy, win, x, x+w-1, 2 + y + pcf->ascent, fg); + fbui_flush (dpy, win); + } + + fbui_window_close(dpy, win); + fbui_display_close (dpy); + + free(server); + free(user); + free(pass); +} diff --git a/libfbui/Makefile b/libfbui/Makefile @@ -0,0 +1,13 @@ + +SRC= libfbui.c +OBJ= libfbui.o +LIB= libfbui.a + +CFLAGS= -g + +${LIB}: ${OBJ} + ar rs ${LIB} ${OBJ} + + +clean: + rm -f ${OBJ} ${LIB} diff --git a/libfbui/MultiTest/COPYING b/libfbui/MultiTest/COPYING @@ -0,0 +1,280 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS diff --git a/libfbui/MultiTest/Makefile b/libfbui/MultiTest/Makefile @@ -0,0 +1,15 @@ + +EXE=fbmtest +SRC= main.c + +test: ${SRC} + gcc -lm -I.. -g ${SRC} ../libfbui.a -o ${EXE} + # strip ${EXE} + +clean: + rm -f ${EXE} + +install: ${EXE} + cp ${EXE} /usr/bin + chmod 755 /usr/bin/${EXE} + diff --git a/libfbui/MultiTest/fbmtest b/libfbui/MultiTest/fbmtest Binary files differ. diff --git a/libfbui/MultiTest/main.c b/libfbui/MultiTest/main.c @@ -0,0 +1,172 @@ + +/*========================================================================= + * + * fbmtest, a multiple-window-per-application test program for FBUI + * Copyright (C) 2004 Zachary T Smith, fbui@comcast.net + * + * This module is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This module 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this module; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * (See the file COPYING in the main directory of this archive for + * more details.) + * + *=======================================================================*/ + + +typedef unsigned long u32; +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <sys/ioctl.h> +#include <linux/fb.h> +#include <sys/mman.h> +#include <unistd.h> +#include <string.h> + +#include <linux/vt.h> +#include <linux/input.h> + +#include "libfbui.h" + + +#define NUMWINS 5 +int +main(int argc, char** argv) +{ + Display *dpy; + Window *windows[NUMWINS]; + int inside[NUMWINS]; + Font *pcf = font_new (); + u32 fg,bg; + int i; + int vc=-1; + + i=1; + while(i<argc) { + if (!strncmp("-c",argv[i],2)) { + if (argv[i][2]) + vc = atoi (2 + argv[i]); + } + i++; + } + + if (!pcf_read (pcf, "timR12.pcf")) { + font_free (pcf); + pcf = NULL; + FATAL ("cannot load font"); + } + + short line_height = pcf->ascent + pcf->descent; + + fg = RGB_YELLOW; + bg = RGB_BROWN; + + short win_w, win_h; + dpy = fbui_display_open (); + if (!dpy) + FATAL ("cannot open display"); + + srand (time(NULL)); + + for (i=0; i< NUMWINS; i++) { + Window *win; + char subtitle[10]; + + inside[i] = 0; + + sprintf (subtitle, "%d", i); + + do { + short win_w = 150; + short win_h = 150; + int x = rand () % (dpy->width - win_w); + int y = rand () & (dpy->height - win_h); + win = fbui_window_open (dpy, win_w, win_h, + &win_w, &win_h, 999,999, + x, y, + &fg, &bg, + "fbmtest", subtitle, + FBUI_PROGTYPE_APP, + false,false, vc, + false, + false, + i == 3 ? true : false, // hide the 4th window + 0,NULL); + } while (!win); + + windows[i] = win; + } + + printf ("MultiTest: All windows created.\n"); + + while (1) { + int total; + int need=0; + Event ev; + Window *win; + int x=0, y=0; + int type; + int err; + + /* Get any event for ANY of our windows */ + + if (err = fbui_wait_event (dpy, &ev, FBUI_EVENTMASK_ALL)) + { + fbui_print_error (err); + continue; + } + + win = ev.win; + if (!win) + FATAL("null window"); + + type = ev.type; + +printf ("%s (subwindow %d) got event %s\n", argv[0], win->id, + fbui_get_event_name (type)); + + if (type == FBUI_EVENT_ENTER) + inside [win->id] = 1; + else if (type == FBUI_EVENT_LEAVE) + inside [win->id] = 0; + + fbui_clear (dpy, win); + + char expr[100]; + sprintf (expr, "This is window %d", win->id); + + i=0; + int in = 0; + while(i < NUMWINS) { + if (win->id == windows[i]->id) { + in = inside[i]; + break; + } + i++; + } + + if (in) + fbui_draw_rect (dpy, win, 0, 0, 149,149, RGB_YELLOW); + + fbui_draw_string (dpy, win, pcf, 6,6, expr, fg); + + if (type == FBUI_EVENT_MOTION) { + fbui_draw_line (dpy, win, 0,0, ev.x, ev.y, RGB_WHITE); + fbui_flush (dpy, win); + } + } + + fbui_display_close (dpy); +} diff --git a/libfbui/PanelManager/COPYING b/libfbui/PanelManager/COPYING @@ -0,0 +1,280 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS diff --git a/libfbui/PanelManager/Makefile b/libfbui/PanelManager/Makefile @@ -0,0 +1,15 @@ + +EXE=fbpm +SRC= main.c jpeg.c rect.c + +test: ${SRC} + gcc -lm -ljpeg -I.. -g ${SRC} ../libfbui.a -o ${EXE} + # strip ${EXE} + +clean: + rm -f ${EXE} + +install: ${EXE} + cp ${EXE} /usr/bin + chmod 755 /usr/bin/${EXE} + diff --git a/libfbui/PanelManager/README b/libfbui/PanelManager/README @@ -0,0 +1,19 @@ + +Frame Buffer Panel Manager (fbpm) + +The panel manager is an approach to organizing windows +based on my own personal usage patterns, more or less. + +Use alt-<number key> to flip to a specific windows. +Use alt-Tab to flip to the next app window. +Use alt-Backspace to exit, killing all windows and + their processes. + +Eventually I will add the ability to divide the main area +between two or three applications, especially since +the concept of an 'ephemeral' application such as a +calculator or to-do list requires that. + +Zack Smith + + diff --git a/libfbui/PanelManager/TODO b/libfbui/PanelManager/TODO @@ -0,0 +1,3 @@ + +* Need to implement space for Tools, particularly a launch-menu tool. + diff --git a/libfbui/PanelManager/jpeg.c b/libfbui/PanelManager/jpeg.c @@ -0,0 +1,318 @@ + +/* + * example.c + * + * This file illustrates how to use the IJG code as a subroutine library + * to read or write JPEG image files. You should look at this code in + * conjunction with the documentation file libjpeg.doc. + * + * This code will not do anything useful as-is, but it may be helpful as a + * skeleton for constructing routines that call the JPEG library. + * + * We present these routines in the same coding style used in the JPEG code + * (ANSI function definitions, etc); but you are of course free to code your + * routines in a different style if you prefer. + */ + +#include <stdio.h> + +/* + * Include file for users of JPEG library. + * You will need to have included system headers that define at least + * the typedefs FILE and size_t before you can include jpeglib.h. + * (stdio.h is sufficient on ANSI-conforming systems.) + * You may also wish to include "jerror.h". + */ + +#include <jpeglib.h> + +/* + * <setjmp.h> is used for the optional error recovery mechanism shown in + * the second part of the example. + */ + +#include <setjmp.h> + +/******************** JPEG COMPRESSION SAMPLE INTERFACE *******************/ + +/* This half of the example shows how to feed data into the JPEG compressor. + * We present a minimal version that does not worry about refinements such + * as error recovery (the JPEG code will just exit() if it gets an error). + */ + +/* + * IMAGE DATA FORMATS: + * + * The standard input image format is a rectangular array of pixels, with + * each pixel having the same number of "component" values (color channels). + * Each pixel row is an array of JSAMPLEs (which typically are unsigned chars). + * If you are working with color data, then the color values for each pixel + * must be adjacent in the row; for example, R,G,B,R,G,B,R,G,B,... for 24-bit + * RGB color. + * + * For this example, we'll assume that this data structure matches the way + * our application has stored the image in memory, so we can just pass a + * pointer to our image buffer. In particular, let's say that the image is + * RGB color and is described by: + */ + +extern JSAMPLE * image_buffer; /* Points to large array of R,G,B-order data */ +extern int image_height; /* Number of rows in image */ +extern int image_width; /* Number of columns in image */ +extern int image_ncomponents; + +static int y=0; +int put_scanline_someplace(JSAMPLE* data, int width) +{ + if (!image_buffer) { + image_buffer = (JSAMPLE*) malloc (width * image_height * 3); + if (!image_buffer) { + printf ("failed to malloc image buffer\n"); + exit(2); + } + } + + int i = width; + unsigned char *tmp = (unsigned char*) data; + unsigned char *tmp2 = (unsigned char*) (image_buffer + y*width); + memcpy (tmp2,tmp,width); + y++; +} + + +/* + * Sample routine for JPEG compression. We assume that the target file name + * and a compression quality factor are passed in. + */ + + +/******************** JPEG DECOMPRESSION SAMPLE INTERFACE *******************/ + +/* This half of the example shows how to read data from the JPEG decompressor. + * It's a bit more refined than the above, in that we show: + * (a) how to modify the JPEG library's standard error-reporting behavior; + * (b) how to allocate workspace using the library's memory manager. + * + * Just to make this example a little different from the first one, we'll + * assume that we do not intend to put the whole image into an in-memory + * buffer, but to send it line-by-line someplace else. We need a one- + * scanline-high JSAMPLE array as a work buffer, and we will let the JPEG + * memory manager allocate it for us. This approach is actually quite useful + * because we don't need to remember to deallocate the buffer separately: it + * will go away automatically when the JPEG object is cleaned up. + */ + +/* + * ERROR HANDLING: + * + * The JPEG library's standard error handler (jerror.c) is divided into + * several "methods" which you can override individually. This lets you + * adjust the behavior without duplicating a lot of code, which you might + * have to update with each future release. + * + * Our example here shows how to override the "error_exit" method so that + * control is returned to the library's caller when a fatal error occurs, + * rather than calling exit() as the standard error_exit method does. + * + * We use C's setjmp/longjmp facility to return control. This means that the + * routine which calls the JPEG library must first execute a setjmp() call to + * establish the return point. We want the replacement error_exit to do a + * longjmp(). But we need to make the setjmp buffer accessible to the + * error_exit routine. To do this, we make a private extension of the + * standard JPEG error handler object. (If we were using C++, we'd say we + * were making a subclass of the regular error handler.) + * + * Here's the extended error handler struct: + */ + +struct my_error_mgr { + struct jpeg_error_mgr pub; /* "public" fields */ + + jmp_buf setjmp_buffer; /* for return to caller */ +}; + +typedef struct my_error_mgr * my_error_ptr; + +/* + * Here's the routine that will replace the standard error_exit method: + */ + +METHODDEF(void) +my_error_exit (j_common_ptr cinfo) +{ + /* cinfo->err really points to a my_error_mgr struct, so coerce pointer */ + my_error_ptr myerr = (my_error_ptr) cinfo->err; + + /* Always display the message. */ + /* We could postpone this until after returning, if we chose. */ + (*cinfo->err->output_message) (cinfo); + + /* Return control to the setjmp point */ + longjmp(myerr->setjmp_buffer, 1); +} + +/* + * Sample routine for JPEG decompression. We assume that the source file name + * is passed in. We want to return 1 on success, 0 on error. + */ + +GLOBAL(int) +read_JPEG_file (char * filename) +{ + /* This struct contains the JPEG decompression parameters and pointers to + * working space (which is allocated as needed by the JPEG library). + */ + struct jpeg_decompress_struct cinfo; + /* We use our private extension JPEG error handler. + * Note that this struct must live as long as the main JPEG parameter + * struct, to avoid dangling-pointer problems. + */ + struct my_error_mgr jerr; + /* More stuff */ + FILE * infile; /* source file */ + JSAMPARRAY buffer; /* Output row buffer */ + int row_stride; /* physical row width in output buffer */ + + /* In this example we want to open the input file before doing anything else, + * so that the setjmp() error recovery below can assume the file is open. + * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that + * requires it in order to read binary files. + */ + + if ((infile = fopen(filename, "rb")) == NULL) { + fprintf(stderr, "can't open %s\n", filename); + return 0; + } + + /* Step 1: allocate and initialize JPEG decompression object */ + + /* We set up the normal JPEG error routines, then override error_exit. */ + cinfo.err = jpeg_std_error(&jerr.pub); + jerr.pub.error_exit = my_error_exit; + /* Establish the setjmp return context for my_error_exit to use. */ + if (setjmp(jerr.setjmp_buffer)) { + /* If we get here, the JPEG code has signaled an error. + * We need to clean up the JPEG object, close the input file, and return. + */ + jpeg_destroy_decompress(&cinfo); + fclose(infile); + return 0; + } + /* Now we can initialize the JPEG decompression object. */ + jpeg_create_decompress(&cinfo); + + /* Step 2: specify data source (eg, a file) */ + + jpeg_stdio_src(&cinfo, infile); + + /* Step 3: read file parameters with jpeg_read_header() */ + + (void) jpeg_read_header(&cinfo, TRUE); + /* We can ignore the return value from jpeg_read_header since + * (a) suspension is not possible with the stdio data source, and + * (b) we passed TRUE to reject a tables-only JPEG file as an error. + * See libjpeg.doc for more info. + */ + + /* Step 4: set parameters for decompression */ + + /* In this example, we don't need to change any of the defaults set by + * jpeg_read_header(), so we do nothing here. + */ + + /* Step 5: Start decompressor */ + + (void) jpeg_start_decompress(&cinfo); + /* We can ignore the return value since suspension is not possible + * with the stdio data source. + */ + + /* We may need to do some setup of our own at this point before reading + * the data. After jpeg_start_decompress() we have the correct scaled + * output image dimensions available, as well as the output colormap + * if we asked for color quantization. + * In this example, we need to make an output work buffer of the right size. + */ + /* JSAMPLEs per row in output buffer */ + + image_height = cinfo.output_height; + image_width = cinfo.output_width; + row_stride = cinfo.output_width * cinfo.output_components; + image_ncomponents = cinfo.output_components; + + /* Make a one-row-high sample array that will go away when done with image */ + buffer = (*cinfo.mem->alloc_sarray) + ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1); + + /* Step 6: while (scan lines remain to be read) */ + /* jpeg_read_scanlines(...); */ + + /* Here we use the library's state variable cinfo.output_scanline as the + * loop counter, so that we don't have to keep track ourselves. + */ + while (cinfo.output_scanline < cinfo.output_height) { + /* jpeg_read_scanlines expects an array of pointers to scanlines. + * Here the array is only one element long, but you could ask for + * more than one scanline at a time if that's more convenient. + */ + (void) jpeg_read_scanlines(&cinfo, buffer, 1); + /* Assume put_scanline_someplace wants a pointer and sample count. */ + put_scanline_someplace(buffer[0], row_stride); + } + + /* Step 7: Finish decompression */ + + (void) jpeg_finish_decompress(&cinfo); + /* We can ignore the return value since suspension is not possible + * with the stdio data source. + */ + + /* Step 8: Release JPEG decompression object */ + + /* This is an important step since it will release a good deal of memory. */ + jpeg_destroy_decompress(&cinfo); + + /* After finish_decompress, we can close the input file. + * Here we postpone it until after no more JPEG errors are possible, + * so as to simplify the setjmp error logic above. (Actually, I don't + * think that jpeg_destroy can do an error exit, but why assume anything...) + */ + fclose(infile); + + /* At this point you may want to check to see whether any corrupt-data + * warnings occurred (test whether jerr.pub.num_warnings is nonzero). + */ + + /* And we're done! */ +y=0; + return 1; +} + +/* + * SOME FINE POINTS: + * + * In the above code, we ignored the return value of jpeg_read_scanlines, + * which is the number of scanlines actually read. We could get away with + * this because we asked for only one line at a time and we weren't using + * a suspending data source. See libjpeg.doc for more info. + * + * We cheated a bit by calling alloc_sarray() after jpeg_start_decompress(); + * we should have done it beforehand to ensure that the space would be + * counted against the JPEG max_memory setting. In some systems the above + * code would risk an out-of-memory error. However, in general we don't + * know the output image dimensions before jpeg_start_decompress(), unless we + * call jpeg_calc_output_dimensions(). See libjpeg.doc for more about this. + * + * Scanlines are returned in the same order as they appear in the JPEG file, + * which is standardly top-to-bottom. If you must emit data bottom-to-top, + * you can use one of the virtual arrays provided by the JPEG memory manager + * to invert the data. See wrbmp.c for an example. + * + * As with compression, some operating modes may require temporary files. + * On some systems you may need to set up a signal handler to ensure that + * temporary files are deleted if the program is interrupted. See libjpeg.doc. + */ + + + + diff --git a/libfbui/PanelManager/main.c b/libfbui/PanelManager/main.c @@ -0,0 +1,936 @@ + +/*========================================================================= + * + * fbpm, a window manager for FBUI (in-kernel framebuffer UI) + * Copyright (C) 2004 Zachary T Smith, fbui@comcast.net + * + * This module is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This module 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this module; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * (See the file COPYING in the main directory of this archive for + * more details.) + * + *=======================================================================*/ + +/* + * Changes: + * + * Oct 19, 2004, fbui@comcast.net: got rectangle subtraction working + * Oct 19, 2004, fbui@comcast.net: got background image drawing working + * Oct 21, 2004, fbui@comcast.net: began conversion to panel manager + * Dec 12, 2004, fbui@comcast.net: implemented alt-key switching between apps + * Dec 31, 2004, fbui@comcast.net: added drawing of background areas + */ + + + +#include <stdio.h> +#include <time.h> +#include <sys/types.h> +#include <unistd.h> +#include <math.h> +#include <jpeglib.h> +#include <signal.h> +#include <errno.h> + +#include "libfbui.h" + + +#define min(AA,BB) ( (AA)<(BB) ? (AA) : (BB) ) +#define max(AA,BB) ( (AA)>(BB) ? (AA) : (BB) ) + + +extern void draw_background (Display *dpy, Window *win); + +extern int read_JPEG_file (char*); + +void draw_titlebar (Display *dpy, Window *self, short width, char *title, char*); + + +#define circle1_width 16 +#define circle1_height 16 +static unsigned char circle1_bits[] = { + 0xc0, 0x01, 0x30, 0x06, 0x0c, 0x18, 0x84, 0x10, 0xc2, 0x20, 0xc2, 0x20, + 0xa1, 0x40, 0x81, 0x40, 0x81, 0x40, 0x82, 0x20, 0x82, 0x20, 0x84, 0x10, + 0x0c, 0x18, 0x30, 0x06, 0xc0, 0x01, 0x00, 0x00}; + +#define circle2_width 16 +#define circle2_height 16 +static unsigned char circle2_bits[] = { + 0xc0, 0x01, 0x30, 0x06, 0x0c, 0x18, 0xc4, 0x11, 0x22, 0x22, 0x02, 0x22, + 0x01, 0x42, 0x01, 0x41, 0x81, 0x40, 0x42, 0x20, 0x22, 0x20, 0xe4, 0x13, + 0x0c, 0x18, 0x30, 0x06, 0xc0, 0x01, 0x00, 0x00}; + +#define circle3_width 16 +#define circle3_height 16 +static unsigned char circle3_bits[] = { + 0xc0, 0x01, 0x30, 0x06, 0x0c, 0x18, 0xe4, 0x13, 0x02, 0x21, 0x82, 0x20, + 0xc1, 0x41, 0x01, 0x42, 0x01, 0x42, 0x02, 0x22, 0x22, 0x22, 0xc4, 0x11, + 0x0c, 0x18, 0x30, 0x06, 0xc0, 0x01, 0x00, 0x00}; + +#define circle8_width 16 +#define circle8_height 16 +static unsigned char circle8_bits[] = { + 0xc0, 0x01, 0x30, 0x06, 0x0c, 0x18, 0xc4, 0x11, 0x22, 0x22, 0x22, 0x22, + 0xc1, 0x41, 0x21, 0x42, 0x21, 0x42, 0x22, 0x22, 0x22, 0x22, 0xc4, 0x11, + 0x0c, 0x18, 0x30, 0x06, 0xc0, 0x01, 0x00, 0x00}; + +#define circle4_width 16 +#define circle4_height 16 +static unsigned char circle4_bits[] = { + 0xc0, 0x01, 0x30, 0x06, 0x0c, 0x18, 0x04, 0x11, 0x22, 0x21, 0x22, 0x21, + 0x21, 0x41, 0xe1, 0x43, 0x01, 0x41, 0x02, 0x21, 0x02, 0x21, 0x04, 0x11, + 0x0c, 0x18, 0x30, 0x06, 0xc0, 0x01, 0x00, 0x00}; + +#define circle5_width 16 +#define circle5_height 16 +static unsigned char circle5_bits[] = { + 0xc0, 0x01, 0x30, 0x06, 0x0c, 0x18, 0xe4, 0x13, 0x22, 0x20, 0x22, 0x20, + 0xe1, 0x41, 0x01, 0x42, 0x01, 0x42, 0x02, 0x22, 0x22, 0x22, 0xc4, 0x11, + 0x0c, 0x18, 0x30, 0x06, 0xc0, 0x01, 0x00, 0x00}; + +#define circle6_width 16 +#define circle6_height 16 +static unsigned char circle6_bits[] = { + 0xc0, 0x01, 0x30, 0x06, 0x0c, 0x18, 0xc4, 0x11, 0x22, 0x22, 0x22, 0x20, + 0x21, 0x40, 0xe1, 0x41, 0x21, 0x42, 0x22, 0x22, 0x22, 0x22, 0xc4, 0x11, + 0x0c, 0x18, 0x30, 0x06, 0xc0, 0x01, 0x00, 0x00}; + +#define circle7_width 16 +#define circle7_height 16 +static unsigned char circle7_bits[] = { + 0xc0, 0x01, 0x30, 0x06, 0x0c, 0x18, 0xe4, 0x13, 0x02, 0x22, 0x02, 0x22, + 0x01, 0x41, 0x81, 0x40, 0x81, 0x40, 0x82, 0x20, 0x82, 0x20, 0x84, 0x10, + 0x0c, 0x18, 0x30, 0x06, 0xc0, 0x01, 0x00, 0x00}; + +#define circle9_width 16 +#define circle9_height 16 +static unsigned char circle9_bits[] = { + 0xc0, 0x01, 0x30, 0x06, 0x0c, 0x18, 0xc4, 0x11, 0x22, 0x22, 0x22, 0x22, + 0x21, 0x42, 0xc1, 0x43, 0x01, 0x41, 0x02, 0x21, 0x82, 0x20, 0x84, 0x10, + 0x0c, 0x18, 0x30, 0x06, 0xc0, 0x01, 0x00, 0x00}; + +#define circle0_width 16 +#define circle0_height 16 +static unsigned char circle0_bits[] = { + 0xc0, 0x01, 0x30, 0x06, 0x0c, 0x18, 0xc4, 0x11, 0x22, 0x22, 0x22, 0x22, + 0x21, 0x42, 0x21, 0x42, 0x21, 0x42, 0x22, 0x22, 0x22, 0x22, 0xc4, 0x11, + 0x0c, 0x18, 0x30, 0x06, 0xc0, 0x01, 0x00, 0x00}; + + +static short icon_height = circle0_height; + + +static unsigned char *bitmaps[10] = { + circle1_bits, + circle2_bits, + circle3_bits, + circle4_bits, + circle5_bits, + circle6_bits, + circle7_bits, + circle8_bits, + circle9_bits, + circle0_bits, +}; + +unsigned short reverse16 (unsigned short value) +{ + int i; + unsigned short result = 0; + for (i=0; i<16; i++) { + unsigned short j = 1 << i; + unsigned short j2 = 1 << (15-i); + if (j & value) + result |= j2; + } + return result; +} + +short win_w, win_h; +#define STEELBLUE 0x4682B4 + +extern JSAMPLE * image_buffer; +extern int image_height; +extern int image_width; +extern int image_ncomponents; +extern int read_JPEG_file (char*); + +int foreground_id = -1; + +Font *font1; +Font *font2; +short line_height; // font1's + +static short separator_size = 2; + +static char grayscale=0; /* 1 forces bg image to grayscale */ + + +int window_count; + +#define MAXWINS (40) +struct fbui_wininfo info[MAXWINS]; + + + +static short mainarea_width; +static short mainarea_height; + +static short bottomarea_width; +static short bottomarea_height; + +static short rightarea_width; +static short rightarea_height; + +static short listarea_width; +static short listarea_height; + +static short rightarea_height_remaining; +static short bottomarea_width_remaining; + + +void +draw_window_list (Display *dpy, Window *self) +{ + int i; + short icon_width; + short lx, ly; + short key=1; + short line_height = font1->ascent + font1->descent; + + // The (#) icons + icon_width = 16; + icon_height = 16; + + lx = win_w - listarea_width; + ly = win_h - listarea_height; + fbui_fill_area (dpy, self, lx,ly, win_w,win_h, RGB_CYAN); + + int appcount = 0; + for (i=0; i < window_count; i++) { + int t = info[i].program_type; + unsigned char *bits_source = bitmaps [appcount < 10 ? appcount : 9]; + + if (t == FBUI_PROGTYPE_APP || + t == FBUI_PROGTYPE_EPHEMERAL || !t) + { + int j; + for (j=0; j<icon_height; j++) { + unsigned short bits = 0; + int k = j << 1; + bits = bits_source [k+1]; + bits <<= 8; + bits |= bits_source [k]; + bits = reverse16 (bits); + + fbui_tinyblit (dpy, self, lx+2, ly+j, + RGB_BLACK, RGB_NOCOLOR, + icon_width, bits); + } + + fbui_draw_string (dpy, self, font1, + lx+3+icon_width,ly, + info[i].name, RGB_BLUE); + + appcount++; + ly += max(line_height,icon_height); + } + } + + // No apps? Clear out the title bar. + if (!appcount) { + // fbui_clear_area (dpy, self, 0, 0, mainarea_width-1, line_height-1); + fbui_draw_string (dpy, self, font1, lx+3, ly, "No apps.", RGB_BLUE); + } +} + + +void +flip (Display *dpy, Window *self, int which /* 0...8 */ ) +{ + int i, appcounter; + int count; + + if (which < 0 || which > 8) { + return; + } + + /* Firstly count the number of apps and ephemerals */ + count=0; + i = 0; + while (i < window_count) { + char type = info[i].program_type; + if (type == FBUI_PROGTYPE_APP || type == FBUI_PROGTYPE_EPHEMERAL || !type) + count++; + i++; + } + /* Rule: overlarge # switches to last */ + if (which >= count) + which = count - 1; + + /* Secondly hide all */ + i = 0; + while (i < window_count) { + char type = info[i].program_type; + if (type == FBUI_PROGTYPE_APP || type == FBUI_PROGTYPE_EPHEMERAL || !type) { + fbui_hide (dpy, self, info[i].id); + } + i++; + } + + /* Thirdly bring the flipped-to window to the fore */ + appcounter = 0; + i = 0; + struct fbui_wininfo *wi = NULL; + while (i < window_count) { + char type = info[i].program_type; + if (type == FBUI_PROGTYPE_APP || type == FBUI_PROGTYPE_EPHEMERAL || !type) { + if (appcounter == which) { + int retval; + short id = info[i].id; + wi = &info[i]; + foreground_id = id; + if (retval = fbui_unhide (dpy, self, id)) + printf ("fbpm: unhide failed %d\n", retval); + fbui_assign_keyfocus (dpy, self, id); + break; + } + appcounter++; + } + i++; + } + + if (wi) + draw_titlebar (dpy,self,wi->width, wi->name, wi->subtitle); +} + + +void +flip_to_next (Display *dpy, Window *self) +{ + int i; + char found_current = 0; + char appcounter = 0; + + if (foreground_id < 0) + return; + + i = 0; + while (i < window_count) { + char type = info[i].program_type; + short id = info[i].id; + + if (type == FBUI_PROGTYPE_APP || type == FBUI_PROGTYPE_EPHEMERAL || !type) { + if (found_current) { + flip (dpy, self, appcounter); + return; + } + + if (id == foreground_id) + found_current = 1; + + appcounter++; + } + i++; + } + + // Not found, which means it was the last one. + flip (dpy, self, 0); +} + + +void draw_titlebar (Display *dpy, Window *self, short width, char *title, char *subtitle) +{ + if (!window_count) + return; + + // draw gradient behind text + int j=0; + while (j < width) { + unsigned long r,g,b; + int n = 255 - j/2; + int k = n > 1 ? n : 0; + r = 30; + g = 32 + (7*k)/8; + b = k/3; + r <<= 16; + b <<= 8; + fbui_draw_vline (dpy, self, + j, 0, line_height-1, r|g|b); + j++; + } + + // draw program name/pid + char tmp[200]; + if (!subtitle || !*subtitle) + sprintf(tmp,"%s", title,subtitle); + else + sprintf(tmp,"%s (%s)", title,subtitle); + fbui_draw_string (dpy, self, font1,0,0,tmp, RGB_YELLOW); +} + + +int +main(int argc, char** argv) +{ + int i,j; + Display *dpy; + Window *self; + + window_count = 0; + + font1 = font_new (); // main font + // font2 = font_new (); // subtitle font + + if (!pcf_read (font1, "timR12.pcf")) { + font_free (font1); + font1 = NULL; + FATAL ("cannot load font"); + } + + /* Get text height...will determine size of list area. + */ + line_height = font1->ascent + font1->descent; + + long fgcolor = RGB_NOCOLOR; // not used + long bgcolor = STEELBLUE; + + dpy = fbui_display_open (); + if (!dpy) + FATAL ("cannot open display"); + + self = fbui_window_open (dpy, 1,1, &win_w, &win_h, + 9999,9999, // no max wid/ht + 0, 0, + &fgcolor, &bgcolor, + "fbpm", "", + FBUI_PROGTYPE_WM, + true, + true, + -1, + false, + true, // all motion + false,// not hidden + argc,argv); + if (!self) { + fbui_display_close (dpy); + FATAL ("cannot open manager window"); + } + + /* Check for a background image */ + image_width=0; + image_height=0; + image_ncomponents=0; + image_buffer=NULL; + char *image_path=NULL; + i=1; + while (i<argc) { + char *s = argv[i]; + int ch = s ? s[0] : 0; + if (ch && '-' != ch) { + image_path = argv[i]; + break; + } + i++; + } + if (image_path) { + int result; + result = read_JPEG_file (image_path); + if (image_ncomponents != 3) + result=0; + if (!result) { + WARNING ("cannot read background image"); + if (image_buffer) + free(image_buffer); + image_buffer=NULL; + image_width=0; + image_height=0; + image_ncomponents=0; + } + + } + + /* If the wm was started after windows appeared, + * we need to hide those windows to prevent fbui_overlap_check + * from complaining. + */ + window_count = fbui_window_info (dpy, self, &info[0], MAXWINS); + for (i=0; i<window_count; i++) { + int rv = fbui_hide (dpy, self, info[i].id); + if (rv) { + printf ("hide of %s failed! (%d)\n", info[i].name,rv); + } + } + + listarea_height = icon_height * 10; + rightarea_width = 78; + listarea_width = rightarea_width; + bottomarea_width = win_w - rightarea_width; + mainarea_width = bottomarea_width; + bottomarea_height = 25; + mainarea_height = win_h - bottomarea_height; + rightarea_height = mainarea_height - listarea_height; + bottomarea_width_remaining = bottomarea_width; + rightarea_height_remaining = rightarea_height; + + if (FBUI_SUCCESS != fbui_accelerator (dpy, self, '1', 1)) + FATAL ("cannot register accelerator"); + if (FBUI_SUCCESS != fbui_accelerator (dpy, self, '2', 1)) + FATAL ("cannot register accelerator"); + if (FBUI_SUCCESS != fbui_accelerator (dpy, self, '3', 1)) + FATAL ("cannot register accelerator"); + if (FBUI_SUCCESS != fbui_accelerator (dpy, self, '4', 1)) + FATAL ("cannot register accelerator"); + if (FBUI_SUCCESS != fbui_accelerator (dpy, self, '5', 1)) + FATAL ("cannot register accelerator"); + if (FBUI_SUCCESS != fbui_accelerator (dpy, self, '6', 1)) + FATAL ("cannot register accelerator"); + if (FBUI_SUCCESS != fbui_accelerator (dpy, self, '7', 1)) + FATAL ("cannot register accelerator"); + if (FBUI_SUCCESS != fbui_accelerator (dpy, self, '8', 1)) + FATAL ("cannot register accelerator"); + if (FBUI_SUCCESS != fbui_accelerator (dpy, self, '9', 1)) + FATAL ("cannot register accelerator"); + if (FBUI_SUCCESS != fbui_accelerator (dpy, self, '0', 1)) + FATAL ("cannot register accelerator"); + + /* Alt-tab switches between apps + */ + if (FBUI_SUCCESS != fbui_accelerator (dpy, self, '\t', 1)) + FATAL ("cannot register accelerator"); + + /* Alt-backsp shuts down FBUI on the current VC + */ + if (FBUI_SUCCESS != fbui_accelerator (dpy, self, '\b', 1)) + FATAL ("cannot register accelerator"); + + /* Alt-PrtSc is to perform a screendump + */ + if (FBUI_SUCCESS != fbui_accelerator (dpy, self, FBUI_ACCEL_PRTSC, 1)) + FATAL ("cannot register accelerator"); + + if (FBUI_SUCCESS != fbui_placement (dpy, self, 1)) + FATAL ("cannot force auto-placement"); + + int need_list = 1; + int need_redraw = 0; + goto getlist; + + while(1) { + Event ev; + int err; + if (err = fbui_wait_event (dpy, &ev, + FBUI_EVENTMASK_ALL - FBUI_EVENTMASK_KEY)) + { + fbui_print_error (err); + continue; + } +printf ("%s got event %s\n", argv[0], fbui_get_event_name (ev.type)); + + int num = ev.type; + + if (ev.win != self) + FATAL ("event not for our window"); + + if (num == FBUI_EVENT_EXPOSE) { + need_redraw = 1; + } + else if (num == FBUI_EVENT_WINCHANGE) { + need_redraw = 1; + need_list = 1; + } + else if (num == FBUI_EVENT_ENTER) { + printf ("fbpm got Enter (it shouldnt)\n"); + continue; + } + else if (num == FBUI_EVENT_LEAVE) { + printf ("fbpm got Leave (it shouldnt)\n"); + continue; + } + else if (num == FBUI_EVENT_ACCEL) { + short key = ev.key; + +printf ("ACCEL key %d\n", key); + + switch (key) { + case '\b': + goto finit; + + case '\t': + flip_to_next (dpy, self); + continue; + + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + flip (dpy, self, key - '1'); + continue; + + case FBUI_ACCEL_PRTSC: + printf ("Dumping screen image to dump.jpg\n"); + system ("fbdump"); + continue; + } + } + +getlist: + if (need_list) { + int i; + short new_x0[MAXWINS]; + short new_y0[MAXWINS]; + short new_x1[MAXWINS]; + short new_y1[MAXWINS]; + short zone[MAXWINS]; + + short new_application_window = -1; + + int total_existing_application_windows = 0; + short existing_application_windows[MAXWINS]; + + for (i=0; i<MAXWINS; i++) + existing_application_windows[i] = -1; + + char foreground_is_in_foreground = 0; + char foreground_found = 0; + + /* Get a list of existing application windows, + * since we need to bring any new app window + * to the fore. + */ + for (i=0; i<window_count; i++) { + if (info[i].program_type == FBUI_PROGTYPE_APP) { + existing_application_windows [total_existing_application_windows++] = info[i].id; + + if (info[i].id == foreground_id) { + if (!info[i].hidden) + foreground_is_in_foreground = 1; + } + } + } + +printf ("----------------------------------------------\n"); +printf ("fbpm: Getting window list..."); + window_count = fbui_window_info (dpy, self, &info[0], MAXWINS); +printf ("%d total\n", window_count); + + /* Perform a window census... + */ + int total_bottom = 0; + int total_right = 0; + int total_main = 0; + for (i=0; i<window_count; i++) { + int id = info[i].id; + + switch (info[i].program_type) { + case FBUI_PROGTYPE_WM: +printf (" %d wm %s id=%d pid=%d %s\n", i, info[i].name, id,info[i].hidden?"hidden":""); + break; + case FBUI_PROGTYPE_APP: + total_main++; +printf (" %d app %s id=%d pid=%d %s\n", i, info[i].name, id,info[i].pid,info[i].hidden?"hidden":""); + j=0; + char got_it_already = 0; + while (j < total_existing_application_windows) { + if (id == existing_application_windows[j]) { + got_it_already = 1; + break; + } + j++; + } + + if (!got_it_already) + new_application_window = id; + + if (foreground_id == id) + foreground_found = 1; + + break; + case FBUI_PROGTYPE_LAUNCHER: + total_bottom++; +printf (" %d launcher %s id=%d pid=%d %s\n", i, info[i].name, id,info[i].pid,info[i].hidden?"hidden":""); + break; + case FBUI_PROGTYPE_TOOL: + total_right++; +printf (" %d tool %s id=%d pid=%d %s\n", i, info[i].name, id,info[i].pid,info[i].hidden?"hidden":""); + break; + case FBUI_PROGTYPE_EPHEMERAL: + total_main++; +printf (" %d ephemeral %s id=%d pid=%d %s\n", i, info[i].name, id,info[i].pid,info[i].hidden?"hidden":""); + break; + case FBUI_PROGTYPE_NONE: + total_main++; +printf (" %d (no type) %s id=%d pid=%d %s\n", i, info[i].name, id,info[i].pid,info[i].hidden?"hidden":""); + break; + default: + total_main++; +printf (" %d (unknown type) %s id=%d pid=%d %s\n", i, info[i].name, id,info[i].pid,info[i].hidden?"hidden":""); + break; + } + } + + /* Determine what the new positions of all of + * the windows will be. + */ + int bottom_ration = total_bottom ? bottomarea_width / total_bottom : 0; + int right_ration = total_right ? rightarea_height / total_right : 0; + int bottom_x = 0; + int right_y = 0; + + if (!foreground_found) + foreground_id = -1; + + for (i=0; i<window_count; i++) { + char whichzone=0; /* 1=main, 2=bottom, 3=right */ + int x0=-1,y0,x1,y1; + short x = info[i].x; + short y = info[i].y; + short w = info[i].width; + short h = info[i].height; + short max_w = info[i].max_width; + short max_h = info[i].max_height; +//printf ("from info[%d] x %d y %d w %d h %d\n",(int)i,(int)x,(int)y,(int)w,(int)h); + + switch (info[i].program_type) { + case FBUI_PROGTYPE_WM: + break; + + case FBUI_PROGTYPE_APP: + case FBUI_PROGTYPE_EPHEMERAL: + default: + whichzone=1; + x0 = 0; + y0 = line_height; // leave space for title + x1 = mainarea_width - 1 - separator_size; + y1 = mainarea_height - 1 - separator_size; + + if (new_application_window < 0 && foreground_id == -1) + foreground_id = info[i].id; + + break; + + case FBUI_PROGTYPE_LAUNCHER: + whichzone=2; + x0 = bottom_x; + if (w < bottom_ration) + bottom_x += (w + separator_size); + else if (max_w > 1 && max_w < bottom_ration) + bottom_x += max_w; + else + bottom_x += bottom_ration; + x1 = bottom_x - 1 - separator_size; + y0 = mainarea_height; + y1 = win_h - 1; + break; + + case FBUI_PROGTYPE_TOOL: + whichzone=3; + x0 = mainarea_width; + x1 = win_w - 1; + y0 = right_y; + if (h < right_ration) + right_y += (h + separator_size); + else if (max_h > 1 && max_h < right_ration) + right_y += max_h; + else + right_y += right_ration; + y1 = right_y - 1 - separator_size; + break; + } + + new_x0 [i] = x0; + new_y0 [i] = y0; + new_x1 [i] = x1; + new_y1 [i] = y1; + zone [i] = whichzone; +printf (" new pos '%s' = %d %d, %d %d\n", info[i].name,x0,y0,x1,y1); + } + + /* Determine which zones changed. + */ + char bottom_changed=0; + char right_changed=0; + char main_changed=0; + for (i=0; i<window_count; i++) { + if (info[i].need_placement || + new_x0[i] != info[i].x || + new_y0[i] != info[i].y || + new_x1[i] != info[i].x+info[i].width-1 || + new_y1[i] != info[i].y+info[i].height-1) + { + switch (zone[i]) { + case 1: + main_changed=1; + break; + case 2: + bottom_changed=1; + break; + case 3: + right_changed=1; + break; + } + } + } + + if (!foreground_found) + main_changed = 1; + if (new_application_window >= 0) + main_changed = 1; + + if (main_changed) + printf ("-main changed-\n"); + if (bottom_changed) + printf ("-bottom changed-\n"); + if (right_changed) + printf ("-right changed-\n"); + + /* For each zone that changed, hide all + * windows. + */ + if (main_changed) { + for (i=0; i<window_count; i++) { + if (zone[i]==1) + fbui_hide (dpy, self, info[i].id); + } + } + if (bottom_changed) { + for (i=0; i<window_count; i++) { + if (zone[i]==2) + fbui_hide (dpy, self, info[i].id); + } + } + if (right_changed) { + for (i=0; i<window_count; i++) { + if (zone[i]==3) + fbui_hide (dpy, self, info[i].id); + } + } + + /* Now make the size/position changes, + * while windows are hidden. + */ + for (i=0; i<window_count; i++) + { + int domove=0; + if ((zone[i]==1 && main_changed) || + (zone[i]==2 && bottom_changed) || + (zone[i]==3 && right_changed)) + domove=1; + + if (info[i].need_placement) + domove=1; + + if (domove) + fbui_move_resize (dpy, self, info[i].id, + new_x0[i], + new_y0[i], + new_x1[i], + new_y1[i]); + } + + /* Unhide windows that need it. + */ + for (i=0; i<window_count; i++) + { + if ((zone[i]==2 && bottom_changed) || + (zone[i]==3 && right_changed)) + { + int retval; + if (retval = fbui_unhide (dpy, self, info[i].id)) + printf ("fbpm: unhide failed %d\n", retval); + } + } + + /* Only one main window gets focus + */ + if (new_application_window != -1) { + int retval; + if (retval = fbui_unhide (dpy, self, new_application_window)) + printf ("fbpm: unhide failed %d\n", retval); + fbui_assign_keyfocus (dpy, self, new_application_window); + foreground_id = new_application_window; +printf ("unhid new app %d\n", new_application_window); + } + else if (foreground_id != -1) { + int retval; +printf ("unhid fg win %d\n", foreground_id); + if (retval = fbui_unhide (dpy, self, foreground_id)) + printf ("fbpm: unhide failed %d\n", retval); + fbui_assign_keyfocus (dpy, self, foreground_id); + } + +printf ("After moves...\n"); + window_count = fbui_window_info (dpy, self, &info[0], MAXWINS); + for (i=0; i<window_count; i++) { +printf (" program %s.... %s\n", info[i].name,info[i].hidden?"hidden":""); + } + + need_list=0; + + need_redraw = 1; + } + + if (need_redraw) { + int i; + + need_redraw = 0; + + draw_background (dpy,self); + draw_window_list (dpy, self); + + i=0; + while (i < window_count) { + struct fbui_wininfo *wi = &info[i]; + int x,y; + + if (wi->id == foreground_id) { + draw_titlebar (dpy,self,wi->width, wi->name,wi->subtitle); + break; + } + + i++; + } + } + } +finit: + ; + + int mypid = getpid(); + for (i=0; i < window_count; i++) { + if (info[i].pid != mypid) + kill (info[i].pid, SIGTERM); + } + + for (i=0; i < window_count; i++) { +#if 0 + draw_background (dpy, self, + info[i].x, + info[i].y - line_height, + info[i].x + info[i].width - 1, + info[i].y - 1); + fbui_flush (dpy, self); +#endif + } + + fbui_window_close (dpy, self); + fbui_display_close (dpy); + + return 0; +} diff --git a/libfbui/PanelManager/rect.c b/libfbui/PanelManager/rect.c @@ -0,0 +1,389 @@ + +/*========================================================================= + * + * fbpm, a panel-based window manager for FBUI (in-kernel framebuffer UI) + * Copyright (C) 2004 Zachary T Smith, fbui@comcast.net + * + * This module is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This module 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this module; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * (See the file COPYING in the main directory of this archive for + * more details.) + * + *=======================================================================*/ + +#include <stdio.h> +#include <linux/fb.h> +#include <libfbui.h> +#include <jpeglib.h> + +extern int window_count; +extern struct fbui_wininfo info[]; + +JSAMPLE * image_buffer; +int image_height; +int image_width; +int image_ncomponents; + +extern short win_w, win_h; + +char grayscale=0; /* 1 forces bg image to grayscale */ + + + + +/* -----------------Rectangle subtraction code----------------- */ + +typedef struct rect { + short x0,y0,x1,y1; + struct rect *next; +} Rect; + +static Rect* Rect_new(short x0, short y0, short x1, short y1) +{ + Rect *nu = (Rect*) malloc (sizeof(Rect)); + if (!nu) return NULL; + + nu->x0 = x0; + nu->y0 = y0; + nu->x1 = x1; + nu->y1 = y1; + nu->next = NULL; + + return nu; +} + +static void Rect_sort (Rect *r) +{ + if (!r) return; + if (r->x0 > r->x1) { + short tmp = r->x0; + r->x0 = r->x1; + r->x1 = tmp; + } + if (r->y0 > r->y1) { + short tmp = r->y0; + r->y0 = r->y1; + r->y1 = tmp; + } +} + +static Rect* Rect_dup (Rect *r) +{ + if (!r) return NULL; + return Rect_new (r->x0,r->y0,r->x1,r->y1); +} + +static int Rect_subtract (Rect *a, Rect *b, Rect *rects[]) +{ + int count=0; + if (!a || !b || !rects) return; + + if (a->x0==b->x0 && a->x1==b->x1 && a->y0==b->y0 && a->y1==b->y1) + return 0; + + Rect_sort(a); + Rect_sort(b); + +#define between(N,M,O) (N>=M && N<=O) + + int i=-1, j=-1; + if (b->x1 < a->x0) + i=0; + else if (b->x0 <= a->x0 && between(b->x1,a->x0,a->x1)) + i=1; + else if (between(b->x0,a->x0,a->x1) && b->x1 >= a->x1) + i=3; + else if (between(b->x0,a->x0,a->x1) && between(b->x1,a->x0,a->x1)) + i=2; + else + i=4; + + if (b->y1 < a->y0) + j=0; + else if (b->y0 <= a->y0 && between(b->y1,a->y0,a->y1)) + j=1; + else if (between(b->y0,a->y0,a->y1) && b->y1 >= a->y1) + j=3; + else if (between(b->y0,a->y0,a->y1) && between(b->y1,a->y0,a->y1)) + j=2; + else + j=4; + +/* + j values + +-------+ + | 0 | + +-------+ + +-------+ + +--------------+ | | + | | | 1 | +-------+ + | | | | | | + | a | +-------+ | 2 | + | | | | + | | +-------+ + | | +-------+ + +--------------+ | 3 | + +-------+ +-------+ + i values: | 4 | + +-------+ +--------+ +-------+ +-------+ + | 0 | | 2 | | 4 | + +-------+ +--------+ +-------+ + +---------+ +--------+ + | 1 | | 3 | + +---------+ +--------+ + */ + // totally outside + if (i==0 || i==4 || j==0 || j==4) { + rects[count++] = Rect_dup(a); + return count; + } + else + // totally inside + if (i==2 && j==2) { + if (a->x0 != b->x0) + rects[count++] = Rect_new (a->x0,a->y0,b->x0-1,a->y1); //left + if (a->y0 != b->y0) + rects[count++] = Rect_new (b->x0,a->y0,b->x1,b->y0-1); //top + if (a->y1 != b->y1) + rects[count++] = Rect_new (b->x0,b->y1+1,b->x1,a->y1); //bottom + if (a->x1 != b->x1) + rects[count++] = Rect_new (b->x0+1,a->y0,a->x1,a->y1); //right + return count; + } + else + if (i==1 && j==2) { + if (a->y0 != b->y0) + rects[count++] = Rect_new (a->x0,a->y0,b->x1,b->y0-1); // topleft + if (a->y1 != b->y1) + rects[count++] = Rect_new (a->x0,b->y1+1,b->x1,a->y1); // bottomleft + if (a->x1 != b->x1) + rects[count++] = Rect_new (b->x1+1,a->y0,a->x1,a->y1); // right + return count; + } + else + if (i==3 && j==2) { + if (a->y0 != b->y0) + rects[count++] = Rect_new (a->x0,a->y0,a->x1,b->y0-1); // top + if (a->x0 != b->x0) + rects[count++] = Rect_new (a->x0,b->y0,b->x0-1,b->y1); // middle + if (a->y1 != b->y1) + rects[count++] = Rect_new (a->x0,b->y1+1,a->x1,a->y1); // bottom + return count; + } + else + if (i==2 && j==1) { + if (a->x0 != b->x0) + rects[count++] = Rect_new (a->x0,a->y0,b->x0-1,b->y1); // topleft + if (a->x1 != b->x1) + rects[count++] = Rect_new (b->x1+1,a->y0,a->x1,b->y1); // topright + if (a->y1 != b->y1) + rects[count++] = Rect_new (a->x0,b->y1+1,a->x1,a->y1); //bottom + return count; + } + else + if (i==2 && j==3) { + if (a->y0 != b->y0) + rects[count++] = Rect_new (a->x0,a->y0,a->x1,b->y0-1); // top + if (a->x0 != b->x0) + rects[count++] = Rect_new (a->x0,b->y0,b->x0-1,a->y1); // bottomleft + if (a->x1 != b->x1) + rects[count++] = Rect_new (b->x1+1,b->y0,a->x1,a->y1); // bottomright + return count; + } + else + if (i==3 && j==1) { + if (a->x0 != b->x0) + rects[count++] = Rect_new (a->x0,a->y0,b->x0-1,a->y1); // left + if (a->y1 > b->y1) + rects[count++] = Rect_new (b->x0,b->y1+1,a->x1,a->y1); // bottomright + return count; + } + else + if (i==3 && j==3) { + if (a->x0 != b->x0) + rects[count++] = Rect_new (a->x0,a->y0,b->x0-1,a->y1); // left + if (a->y0 < b->y0) + rects[count++] = Rect_new (b->x0,a->y0,a->x1,b->y0-1); //topright + return count; + } + else + if (i==1 && j==1) { + if (a->x1 != b->x1) + rects[count++] = Rect_new (b->x1+1,a->y0,a->x1,a->y1); // right + if (a->y1 != b->y1) + rects[count++] = Rect_new (a->x0,b->y1+1,b->x1,a->y1); // bottomleft + return count; + } + else + if (i==1 && j==3) { + if (a->x1 != b->x1) + rects[count++] = Rect_new (b->x1+1,a->y0,a->x1,a->y1); // right + if (a->y0 < b->y0) + rects[count++] = Rect_new (a->x0,a->y0,b->x1,b->y0-1); // topleft + return count; + } + else + printf ("combo %d %d\n",i,j); +} + +static void Rect_delete(Rect *r) +{ + if (r) + free((void*)r); +} + + +/* Draws a portion of the background + * If an image has been loaded, it draws that. + * Otherwise, a green gradient. + */ +void +draw_image (Display *dpy, Window *win, short x0, short y0, short x1, short y1) +{ + int i,j; + if (x0 > x1) { + short tmp=x0;x0=x1;x1=tmp; + } + if (y0 > y1) { + short tmp=y0;y0=y1;y1=tmp; + } + if (x1<0) return; + if (y1<0) return; + if (x0<0) x0=0; + if (y0<0) y0=0; + + /* If we have no background image, don't sweat it, just draw + * a gradient + */ + if (!image_buffer) { + for (i=x0; i<=x1; i++) { + unsigned long k = (191 * i) / win_w; + unsigned long color = (35 + k) + (90 << 8); + fbui_draw_vline (dpy, win, i,y0,y1, color); + } + fbui_flush (dpy, win); + return; + } + + if (x0>=image_width) return; + if (y0>=image_height) return; + if (x1>=image_width) x1=image_width-1; + if (y1>=image_height) y1=image_height-1; + + for (j=y0; j<=y1; j++) { + if (image_ncomponents == 1 || grayscale) { + for(i=x0; i<x1; i++) { + unsigned long pix=0; + unsigned char *p = image_buffer + + image_ncomponents*(i + j*image_width); + + /* pixels are grayscale */ + if (image_ncomponents == 1) { + pix = *p; + pix <<= 8; + pix |= *p; + pix <<= 8; + pix |= *p; + } else { + pix = *p++; + pix += *p++; + pix += *p; + pix /= 3; + pix |= (pix<<8) | (pix<<16); + } + + fbui_draw_point (dpy, win, i, j, pix); + } + } + else + { + fbui_put_rgb3 (dpy, win, x0, j, x1-x0+1, + image_buffer + 3*(j*image_width+x0)); + } + } + + fbui_flush(dpy,win); +} + + +void +draw_background (Display *dpy, Window *win) +{ + Rect *list1 = Rect_new (0,0,win_w-1,win_h-1); + Rect *list2 = NULL; + Rect *ptr; + int mypid = getpid(); + int i; + + for (i=0; i<window_count; i++) { + Rect *r0,*r1,*r2,*r3; + struct fbui_wininfo *wi = &info[i]; + Rect *windowrect = Rect_new(wi->x,wi->y, + wi->x+wi->width-1,wi->y+wi->height-1); +//printf ("subtracting %s\n", wi->name); + if (wi->pid != mypid) { + ptr = list1; + while(ptr) { + Rect *rects[4]; + int count = Rect_subtract (ptr,windowrect,rects); + int j=0; + while (j < count) { + rects[j]->next = list2; + list2 = rects[j]; + j++; + } + ptr = ptr->next; + } + ptr = list1; + Rect *next; + while (ptr) { + next = ptr->next; + Rect_delete(ptr); + ptr=next; + } + list1 = list2; + list2 = NULL; + +#if 0 +int k=0; +Rect *n = list1; +while(n) { k++; +printf (" rect: %d %d - %d %d\n", n->x0,n->y0,n->x1,n->y1); +n=n->next; +} +printf ("result list now has %d rectangles\n", k); +#endif + } + + Rect_delete (windowrect); + } + + /* draw the background */ + ptr=list1; + while(ptr) { + draw_image (dpy,win, ptr->x0,ptr->y0,ptr->x1,ptr->y1); + ptr=ptr->next; + } + fbui_flush (dpy, win); + + /* remove the rectangle list */ + ptr = list1; + while (ptr) { + Rect *next = ptr->next; + Rect_delete(ptr); + ptr=next; + } +} + diff --git a/libfbui/README b/libfbui/README @@ -0,0 +1,42 @@ + +Greetings, + +This is FBUI, whose purpose is to implement an in-kernel +GUI that offers minimal functionality within a tiny space; +and FBUI Library, which exists to make using FBUI's ioctls +simpler. Why in-kernel? To put a limit on GUI bloat. + +FBUI is not intended to satisfy all users' needs. +For instance, the typical home computer user will not want +to use it since it doesn't support overlapping windows, +which are a bad idea anyway. + +However for those of us who accept its limitations +and requirements, and see virtue in its simplicity and +lack of bloat, it may be preferable. + +Enjoy, + +Zack Smith +fbui@comcast.net + +===================================================== + +Installation Instructions + +1. +Before trying to compile, don't forget to replace + /usr/include/linux with a symlink to + /usr/src/linux/include/linux. + +2. +To make all, run ./makeall.sh in the libfbui directory. + +3. +To run most of the FBUI applications and tools +in the 5th virtual console, along with the panel manager, + run ./start2.sh 4 +then press Alt-F5. + +-end- + diff --git a/libfbui/Scribble/COPYING b/libfbui/Scribble/COPYING @@ -0,0 +1,280 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS diff --git a/libfbui/Scribble/Makefile b/libfbui/Scribble/Makefile @@ -0,0 +1,15 @@ + +EXE=fbscribble +SRC= main.c + +test: ${SRC} + gcc -lm -I.. -g ${SRC} ../libfbui.a -o ${EXE} + # strip ${EXE} + +clean: + rm -f ${EXE} + +install: ${EXE} + cp ${EXE} /usr/bin + chmod 755 /usr/bin/${EXE} + diff --git a/libfbui/Scribble/fbscribble b/libfbui/Scribble/fbscribble Binary files differ. diff --git a/libfbui/Scribble/main.c b/libfbui/Scribble/main.c @@ -0,0 +1,365 @@ + +/*========================================================================= + * + * fbscribble, a simple drawing program + * Copyright (C) 2004 Zachary T Smith, fbui@comcast.net + * + * This module is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This module 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this module; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * (See the file COPYING in the main directory of this archive for + * more details.) + * + *=======================================================================*/ + + +typedef unsigned long u32; + + +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <linux/fb.h> +#include <linux/input.h> +#include <string.h> + +#include <linux/vt.h> +#include <linux/input.h> + +#include "libfbui.h" + + +typedef struct { + short width, height; + short depth; // allowed: 24 or 48 + char *path; + char *title; + char *creator; + char *comment; + + unsigned char *pixels; +} Canvas; + + +Canvas *Canvas_create (short w, short h, short d) +{ + Canvas *nu; + unsigned char *pixels; + + if (w<0 || h<0) + return NULL; + if (d!=24 && d!=48) + return NULL; + + int size = w * h * (d==24 ? 3 : 6); + pixels = (unsigned char*) malloc(size); + if (!pixels) + FATAL ("out of memory"); + memset ((void*)pixels, 0xffffff, size); + + nu = (Canvas*) malloc(sizeof(Canvas)); + if (!nu) + FATAL ("out of memory"); + + memset ((void*)nu, 0, sizeof(Canvas)); + nu->width = w; + nu->height = w; + nu->depth = d; + nu->pixels = pixels; + return nu; +} + +void Canvas_put_pixel (Canvas *canvas, short x, short y, unsigned long pixel) +{ + if (!canvas) + return; + if (canvas->depth != 24) + return; + if (x < 0 || y < 0 || x>=canvas->width || y>=canvas->height) + return; + if (!canvas->pixels) + FATAL ("Canvas lacks pixmap"); + /*----------------*/ + + unsigned long ix = (x + y*canvas->width) * (canvas->depth/8); + canvas->pixels [ix++] = pixel >> 16; + canvas->pixels [ix++] = pixel >> 8; + canvas->pixels [ix] = pixel; +} + +void Canvas_clear (Canvas *canvas) +{ + if (!canvas) + return; + if (!canvas->pixels) + return; + /*----------------*/ + + int size = canvas->width * canvas->height * (canvas->depth==24 ? 3 : 6); + memset ((void*)canvas->pixels, 0xffffff, size); +} + +void Canvas_draw (Canvas *canvas, Display* dpy, Window *win, int zoom) +{ + if (!canvas || !dpy || !win) + return; + + if (zoom != 1) + return; + + fbui_fill_area (dpy, win, 0,0, win->width-1, win->height-1, 0xB0B0B0); + + int x,y; + int bytes_per_pixel = canvas->depth / 8; + + int x0 = (win->width - canvas->width) >> 1; + int y0 = (win->height - canvas->height) >> 1; + + for (y=0; y<canvas->height; y++) { + for (x=0; x<canvas->width; x++) { + unsigned long ix = (x + y*canvas->width) * bytes_per_pixel; + unsigned long pixel; + pixel = canvas->pixels [ix++]; + pixel <<= 8; + pixel |= canvas->pixels [ix++]; + pixel <<= 8; + pixel |= canvas->pixels [ix]; + + fbui_draw_point (dpy, win, x0 + x, y0 + y, pixel); + } + } +} + +int Canvas_deserialize (Canvas *canvas, char *path) +{ + FILE *f; + + if (!canvas || !path) + FATAL ("null ptr param"); + /*----------------*/ + + f = fopen (path, "r"); + if (!f) + return false; + + int a,b,c; + if (3 != fscanf (f, "%d %d %d\n", &a,&b,&c)) { + fclose (f); + return false; + } + + if (a < 0 || b < 0 || (c != 24 && c != 48)) + return false; + + if (canvas->pixels) + free (canvas->pixels); + + int bytes_per_pixel = c/8; + + int size = a * b * bytes_per_pixel; + unsigned char *pixels = (unsigned char*) malloc(size); + if (!pixels) + FATAL ("out of memory"); + memset ((void*)pixels, 0xffffff, size); + + canvas->pixels = pixels; + canvas->width = a; + canvas->height = b; + canvas->depth = c; + + int x,y; + for (y=0; y<canvas->height; y++) { + for (x=0; x<canvas->width; x++) { + unsigned long value; + + if (1 != fscanf (f, "%06lx", &value)) { + fclose(f); + return false; + } + + unsigned long r,b,g; + r = 0xff & (value >> 16); + g = 0xff & (value >> 8); + b = 0xff & value; + + unsigned long ix = (x + y*canvas->width) * bytes_per_pixel; + pixels [ix++] = r; + pixels [ix++] = g; + pixels [ix] = b; + } + } + + fclose(f); + return true; +} + +int Canvas_serialize (Canvas *canvas, char *path) +{ + FILE *f; + + if (!canvas || !path) + FATAL ("null ptr param"); + /*----------------*/ + + f = fopen (path, "w"); + if (!f) + return false; + + fprintf (f, "%d %d %d\n", canvas->width, canvas->height, canvas->depth); + + int x,y; + int bytes_per_pixel = canvas->depth / 8; + + for (y=0; y<canvas->height; y++) { + for (x=0; x<canvas->width; x++) { + unsigned long ix = (x + y*canvas->width) * bytes_per_pixel; + unsigned long pixel; + pixel = canvas->pixels [ix++]; + pixel <<= 8; + pixel |= canvas->pixels [ix++]; + pixel <<= 8; + pixel |= canvas->pixels [ix]; + + fprintf (f, "%06lx ", pixel); + } + fprintf (f,"\n"); + } + fclose(f); +} + +int +main(int argc, char** argv) +{ + Display *dpy; + Window *win; + u32 fg,bg; + int i; + int vc=-1; + char button_down = 0; + + short canvas_w, canvas_h; + + Canvas *canvas = Canvas_create (240,240,24); + + if (Canvas_deserialize (canvas, "image")) + printf ("fbscribble: successfully read image\n"); + else { + printf ("fbscribble: failed to read image\n"); + Canvas_clear (canvas); + } + + fg = RGB_BLACK; + bg = RGB_WHITE; + + short win_w, win_h; + dpy = fbui_display_open (); + if (!dpy) + FATAL ("cannot open display"); + + win_w = 320; + win_h = 320; + + canvas_w = win_w; + canvas_h = win_h; + + win = fbui_window_open (dpy, win_w, win_h, + &win_w, &win_h, 999,999, + 0, 0, + &fg, &bg, + "fbscribble", "", + FBUI_PROGTYPE_APP, + false,false, + vc, + true, // need keys + false, // all motion + false, // not hidden + argc, argv); + + int x0 = (win->width - canvas->width) >> 1; + int y0 = (win->height - canvas->height) >> 1; + + while (1) { + int total; + int need=0; + Event ev; + Window *win; + int x=0, y=0; + int type; + int err; + + if (err = fbui_wait_event (dpy, &ev, FBUI_EVENTMASK_ALL)) { + fbui_print_error (err); + continue; + } + +printf ("%s got event %s\n", argv[0], fbui_get_event_name (ev.type)); + + win = ev.win; + if (!win) + FATAL("null window"); + + type = ev.type; + + switch (type) { + case FBUI_EVENT_EXPOSE: + Canvas_draw (canvas, dpy, win, 1); + continue; + + case FBUI_EVENT_KEY: { + short key = ev.key >> 2; + short state = ev.key & 3; +printf ("key=%d\n", key); + + if (state && key == KEY_Q) + goto finit; + + if (state && key == KEY_S) + Canvas_serialize (canvas, "image"); + + if (state && key == KEY_L) + Canvas_deserialize (canvas, "image"); + break; + } + + case FBUI_EVENT_BUTTON: +printf ("got button event, value=%d\n", ev.key); + if (ev.key & FBUI_BUTTON_LEFT) + button_down = ev.key & 1; + break; + + case FBUI_EVENT_MOTION: { + short x= ev.x - x0; + short y= ev.y - y0; + + if (button_down && x >= 0 && y >= 0 && + x < canvas->width && y < canvas->height) + { + Canvas_put_pixel (canvas, x, y, RGB_RED); + fbui_draw_point (dpy, win, ev.x, ev.y, RGB_RED); + fbui_flush (dpy, win); + } + break; + } + + case FBUI_MOVE_RESIZE: + x0 = (ev.width - canvas->width) >> 1; + y0 = (ev.height - canvas->height) >> 1; + break; + } + } +finit: + + fbui_display_close (dpy); +} diff --git a/libfbui/Start/COPYING b/libfbui/Start/COPYING @@ -0,0 +1,280 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS diff --git a/libfbui/Start/Makefile b/libfbui/Start/Makefile @@ -0,0 +1,15 @@ + +EXE=fbstart +SRC= main.c + +test: ${SRC} + gcc -lm -I.. -g ${SRC} ../libfbui.a -o ${EXE} + # strip ${EXE} + +clean: + rm -f ${EXE} + +install: ${EXE} + cp ${EXE} /usr/bin + chmod 755 /usr/bin/${EXE} + diff --git a/libfbui/Start/TODO b/libfbui/Start/TODO @@ -0,0 +1,3 @@ + +* Need to add commandline specification of program to run. + diff --git a/libfbui/Start/fbstart b/libfbui/Start/fbstart Binary files differ. diff --git a/libfbui/Start/main.c b/libfbui/Start/main.c @@ -0,0 +1,145 @@ + +/*========================================================================= + * + * fbstart, a simple button FBUI program to launch another FBUI program + * Copyright (C) 2004 Zachary T Smith, fbui@comcast.net + * + * This module is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This module 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this module; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * (See the file COPYING in the main directory of this archive for + * more details.) + * + *=======================================================================*/ + + +typedef unsigned long u32; +#include <stdio.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <sys/ioctl.h> +#include <linux/fb.h> +#include <sys/mman.h> +#include <unistd.h> +#include <string.h> + +#include <linux/vt.h> +#include <linux/input.h> + +#include "libfbui.h" + + +int +main(int argc, char** argv) +{ + Display *dpy; + Window *win; + Font *pcf = font_new (); + u32 fg,bg; + char *program = "fblauncher"; + + if (!pcf_read (pcf, "ncenBI14.pcf")) { + font_free (pcf); + FATAL ("cannot load font"); + } + + short line_height = pcf->ascent + pcf->descent; + + fg = 0x5000; + bg = 0x40ff40; + + short maxwidth, a,d; + font_string_dims (pcf, "~Start~", &maxwidth, &a, &d); + + short win_w, win_h; + dpy = fbui_display_open (); + if (!dpy) + FATAL ("cannot open display"); + + win = fbui_window_open (dpy, maxwidth,50, &win_w, &win_h, maxwidth, line_height*2, + 0, -1, + &fg, &bg, + "fbstart", "", + FBUI_PROGTYPE_LAUNCHER, + false,false, + -1, + false, // doesn't need keys: buttons only + false, + false, + argc,argv); + if (!win) + FATAL ("cannot create window"); + + while (1) { + int need_redraw=0; + Event ev; + + int err; + if (err = fbui_wait_event (dpy, &ev, FBUI_EVENTMASK_ALL)) + { + if (err != FBUI_ERR_NOEVENT) + fbui_print_error (err); + continue; + } + + int num = ev.type; + + switch (num) { + case FBUI_EVENT_EXPOSE: + need_redraw=1; + break; + + case FBUI_EVENT_MOVE_RESIZE: + win_w = ev.width; + win_h = ev.height; + need_redraw=1; + break; + + case FBUI_EVENT_BUTTON: + if (ev.key & FBUI_BUTTON_LEFT) { + if (ev.key & 1) { + if (!fork()) { + system (program); + goto done; + } + } + } + break; + } + + if (!need_redraw) + continue; + + char text[100]; + sprintf (text, "Start"); + + short w,a,d; + font_string_dims(pcf,text,&w,&a,&d); + + int x, y; + x = (win_w - w) / 2; + if (d < 0) + d = -d; + y = (win_h - (a+d)) / 2; + + fbui_clear (dpy, win); + fbui_draw_string (dpy, win, pcf, x,y, text, fg); + } + +done: + fbui_window_close(dpy, win); + fbui_display_close (dpy); +} diff --git a/libfbui/TODO b/libfbui/TODO @@ -0,0 +1,32 @@ + +* fbpm: implement support for Ephemeral apps + +* test mouse pointer focus + +* investigate multi-test problem + +* implement 16-bit fonts, add support for Unicode + +* investigate PCF first-char problem....abandon PCF? + +* need to flesh out minimum-maximum window size concepts + +* should permit tool program to specify a width-height ratio + +* add support for single overlapping "dialog" window? + +--- + +* add the following to FBUI: + - anti-aliased line draw + - put pixels w/transparency + +* add to FBWM: + - program list, move/maximize/hide/unhide + +* more applications: + - launch menu (Ephemeral) + - xvid player + - xine UI + - rtf editor + diff --git a/libfbui/Term/COPYING b/libfbui/Term/COPYING @@ -0,0 +1,280 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS diff --git a/libfbui/Term/Makefile b/libfbui/Term/Makefile @@ -0,0 +1,14 @@ + +SRC=ansi.c fbterm.c main.c forkpty.c iswprint.c +EXE=fbterm + + +fbterm: ${SRC} + gcc -DHAVE_FORKPTY -I.. -g ${SRC} ../libfbui.a -o ${EXE} -lutil + +install: ${EXE} + cp ${EXE} /usr/bin + chmod 755 /usr/bin/${EXE} + +clean: + rm -f ${EXE} diff --git a/libfbui/Term/README b/libfbui/Term/README @@ -0,0 +1,24 @@ +Greetings, + +This program, fbterm, is my port of ggiterm to use FBUI, which +is my in-kernel framebuffer GUI. The non-FBUI related code was +written by Aurelien Reynaud. Merci Aurelien! + +I used ggiterm because rxvt and xterm seemed more tightly tied to X. +Because fbterm's based on ggiterm, it inherits any minor defects +that ggiterm may or may not have had. However it basically works well. + +To use it, compile it with the makefile. The file libfbui.a is +expected to be in the parent directory. + +Use 'tic' to compile the terminfo file. + +Enjoy, +Zack Smith + +---------- +My changes: +* Oct 15, 2004: added buffers for expose events +* Oct 19, 2004: added -c and -geo support +* Nov 2, 2004: updated for multi-window FBUI + diff --git a/libfbui/Term/ansi.c b/libfbui/Term/ansi.c @@ -0,0 +1,824 @@ + +#include <linux/fb.h> + +#include "fbterm.h" + + +void fbtermEraseLine (); +void fbtermEraseToEOL (); +void fbtermEraseFromBOL (); +void fbtermEraseDisplay (); +void fbtermEraseToEOD (); +void fbtermEraseFromBOD (); +void fbtermInsertChars (unsigned int); +void fbtermEraseNChars (unsigned int); +void fbtermDeleteChars (unsigned int); +void fbtermScrollUp (unsigned int); +void fbtermScrollDown (unsigned int); +void fbtermNextPos (); + +int savedcursor_x, savedcursor_y; +int saved_blink, saved_bold, saved_invisible, saved_reverse, saved_underline, saved_altcharset; +int linewrap_pending; + +extern wchar_t last_char; +extern int cursor_x, cursor_y, cursor_x0, cursor_y0, cell_w, cell_h; +extern int terminal_width, terminal_height; +extern int blink_mode, bold_mode, invisible_mode, reverse_mode, underline_mode, altcharset_mode; +extern int autowrap; +extern int force_cursor_mode; +extern int region_top, region_bottom; +extern int (*fbtermWriteChar) (wchar_t); + + +extern char* tabstops; + +extern unsigned long color[]; +extern int default_bgcolor, default_fgcolor, fgcolor, bgcolor; +extern ggi_visual_t vis; + +int min (int a, int b) +{ + return (b<a?b:a); +} + + +void MoveCursor (int x, int y) +{ + debug (DEBUG_DETAIL, "Entering with cursor position (%d,%d)", cursor_x/cell_w+1, cursor_y/cell_h+1); + + cursor_x = x; + cursor_y = y; + while (cursor_y >= region_bottom * cell_h) + { + fbtermScrollUp (1); + cursor_y -= cell_h; + } + if (autowrap && cursor_x > (terminal_width-1) * cell_w) + { + cursor_x = cursor_x0 + (terminal_width-1) * cell_w; + linewrap_pending = 1; + } + else + { + linewrap_pending = 0; + } + debug (DEBUG_DETAIL, "Leaving with cursor position (%d,%d)", cursor_x/cell_w+1, cursor_y/cell_h+1); + if (linewrap_pending) debug (DEBUG_DETAIL, "Line wrap pending"); +} + + +/*------------------------------------------------------------------------------ +| Cursor motion | +------------------------------------------------------------------------------*/ + +void do_CR () +{ + debug (DEBUG_DETAIL, "Special character code [CR] detected"); + MoveCursor (cursor_x0, cursor_y); +} + +void do_LF () +{ + debug (DEBUG_DETAIL, "Special character code [LF] detected"); + MoveCursor (cursor_x, cursor_y + cell_h); +} + +void do_cub (unsigned int p1) +{ + debug (DEBUG_DETAIL, "Escape Sequence 'cub %d' detected", p1); + /* Move cursor p1 characters to the left */ + MoveCursor (cursor_x - (cell_w * p1), cursor_y); +} + +void do_cud (unsigned int p1) +{ + debug (DEBUG_DETAIL, "Escape Sequence 'cud %d' detected", p1); + /* Move cursor down p1 lines */ + MoveCursor (cursor_x, cursor_y + (cell_h * p1)); +} + +void do_cuf (unsigned int p1) +{ + debug (DEBUG_DETAIL, "Escape Sequence 'cuf %d' detected", p1); + /* Move cursor p1 characters to the right */ + MoveCursor (cursor_x + (cell_w * p1), cursor_y); +} + +void do_cup (unsigned int row, unsigned int column) +{ + debug (DEBUG_DETAIL, "Escape Sequence 'cup %d %d' detected", row, column); + MoveCursor (cursor_x0 + (column - 1) * cell_w, cursor_y0 + (row - 1) * cell_h); +} + +void do_cuu (unsigned int p1) +{ + debug (DEBUG_DETAIL, "Escape Sequence 'cuu %d' detected", p1); + /* Move cursor up p1 lines */ + MoveCursor (cursor_x, cursor_y - (cell_h * p1)); +} + +void do_home () +{ + debug (DEBUG_DETAIL, "Escape Sequence 'home' detected"); + MoveCursor (cursor_x0, cursor_y0); +} + + +/*------------------------------------------------------------------------------ +| Mode handling | +------------------------------------------------------------------------------*/ + +void do_blink () +{ + debug (DEBUG_DETAIL, "Escape Sequence 'blink' or part of 'sgr' detected"); + debug (DEBUG_DETAIL, "Entering blink mode"); + blink_mode = 1; +} + +void do_bold () +{ + debug (DEBUG_DETAIL, "Escape Sequence 'bold' or part of 'sgr' detected"); + debug (DEBUG_DETAIL, "Entering bold mode"); + bold_mode = 1; +} + +void do_invis () +{ + debug (DEBUG_DETAIL, "Escape Sequence 'invis' or part of 'sgr' detected"); + debug (DEBUG_DETAIL, "Entering invisible mode"); + invisible_mode = 1; +} + +void do_rev () +{ + debug (DEBUG_DETAIL, "Escape Sequence 'rev|smso' or part of 'sgr' detected"); + debug (DEBUG_DETAIL, "Entering reverse video mode"); + reverse_mode = 1; +} + +void do_rmacs () +{ + debug (DEBUG_DETAIL, "Escape Sequence 'rmacs' or part of 'sgr|sgr0' detected"); + debug (DEBUG_DETAIL, "Leaving altcharset mode"); + altcharset_mode = 0; +} + +void do_smacs () +{ + debug (DEBUG_DETAIL, "Escape Sequence 'smacs' or part of 'sgr' detected"); + debug (DEBUG_DETAIL, "Entering altcharset mode"); + altcharset_mode = 1; +} + +void do_smul () +{ + debug (DEBUG_DETAIL, "Escape Sequence 'smul' or part of 'sgr' detected"); + debug (DEBUG_DETAIL, "Entering underline mode"); + underline_mode = 1; +} + +void do_leave_all_modes () +{ + debug (DEBUG_DETAIL, "Leaving all modes except altcharset"); + bold_mode = 0; + blink_mode = 0; + underline_mode = 0; + reverse_mode = 0; + invisible_mode = 0; + altcharset_mode = 0; + fgcolor = default_fgcolor; + bgcolor = default_bgcolor; +} + +/*------------------------------------------------------------------------------ +| Area clear | +------------------------------------------------------------------------------*/ + +void do_ed () +{ + debug (DEBUG_DETAIL, "Escape Sequence 'ed' detected"); + fbtermEraseToEOD (); +} + +void do_el () +{ + debug (DEBUG_DETAIL, "Escape Sequence 'el' detected"); + fbtermEraseToEOL (); +} + +void do_el1 () +{ + debug (DEBUG_DETAIL, "Escape Sequence 'el1' detected"); + fbtermEraseFromBOL (); +} + +/*------------------------------------------------------------------------------ +| Insert/Delete characters | +------------------------------------------------------------------------------*/ + +void do_ich (unsigned int p1) +{ + debug (DEBUG_DETAIL, "Escape Sequence 'ich %d' detected", p1); + /* Insert p1 characters at current position */ + fbtermInsertChars (p1); +} + +void do_dch (unsigned int p1) +{ + debug (DEBUG_DETAIL, "Escape Sequence 'dch %d' detected", p1); + /* Delete p1 characters */ + fbtermDeleteChars (p1); +} + +void do_ech (unsigned int p1) +{ + debug (DEBUG_DETAIL, "Escape Sequence 'ech %d' detected", p1); + /* Erase p1 characters, starting at current position */ + fbtermEraseNChars (p1); +} + + +/*------------------------------------------------------------------------------ +| Scrolling | +------------------------------------------------------------------------------*/ + +void do_indn (unsigned int p1) +{ + debug (DEBUG_DETAIL, "Escape Sequence 'indn %d' detected", p1); + /* Scroll forward p1 lines */ + fbtermScrollUp (p1); +} + +void do_rin (unsigned int p1) +{ + debug (DEBUG_DETAIL, "Escape Sequence 'rin %d' detected", p1); + /* Scroll back p1 lines */ + fbtermScrollDown (p1); +} + +void do_change_region (unsigned int p1, unsigned int p2) +{ + debug (DEBUG_DETAIL, "Escape Sequence 'csr %d %d' detected", p1, p2); + /* Set scrolling region to lines p1->p2 */ + region_top = p1-1; + region_bottom = p2; +} + +/*------------------------------------------------------------------------------ +| Tabs | +------------------------------------------------------------------------------*/ + +void do_cbt () +{ + debug (DEBUG_DETAIL, "Escape Sequence 'cbt' detected"); + /* Back to preceding tap stop */ + do + { + MoveCursor (cursor_x - cell_w, cursor_y); + } + while (cursor_x/cell_w && !tabstops[cursor_x/cell_w]); +} + +void do_ht () +{ + debug (DEBUG_DETAIL, "Escape Sequence 'ht' detected"); + /* Go to the next tab stop */ + do + { + MoveCursor (cursor_x + cell_w, cursor_y); + } + while (cursor_x/cell_w < terminal_width-1 && !tabstops[cursor_x/cell_w]); +} + +void do_hts () +{ + debug (DEBUG_DETAIL, "Escape Sequence 'hts' detected"); + /* Set a tab stop in current column */ + tabstops[cursor_x/cell_w] = 1; +} + +void do_tbc () +{ + debug (DEBUG_DETAIL, "Escape Sequence 'tbc' detected"); + /* Clear all tab stops */ + memset (tabstops, 0, terminal_width); + /*tabstops[0] = 1; + tabstops[terminal_width] = 1;*/ +} + +void do_clear_current_tab () +{ + /* vt100 but not in terminfo */ + tabstops[cursor_x/cell_w] = 0; +} + +/*------------------------------------------------------------------------------ +| Colors | +------------------------------------------------------------------------------*/ + +void do_op () +{ + debug (DEBUG_DETAIL, "Escape Sequence 'op' detected"); + /* Reset fg and bg colors to their default values */ + fgcolor = default_fgcolor; + bgcolor = default_bgcolor; +} + +void do_setab (unsigned int p1) +{ + debug (DEBUG_DETAIL, "Escape Sequence 'setab %d' detected", p1); + /* Set bg color to color #p1 */ + if (p1 == 9) bgcolor = default_bgcolor; + else bgcolor = p1; +} + +void do_setaf (unsigned int p1) +{ + debug (DEBUG_DETAIL, "Escape Sequence 'setaf %d' detected", p1); + /* Set fg color to color #p1 */ + if (p1 == 9) fgcolor = default_fgcolor; + else fgcolor = p1; +} + +/*------------------------------------------------------------------------------ +| User strings | +------------------------------------------------------------------------------*/ + +void do_identify (unsigned char *shellinput, size_t *shellinput_size) +{ + debug (DEBUG_DETAIL, "User string 'u9' or Enquiry detected"); + /* Enquire sequence sent to identify the terminal type + Should answer by sending the u8 user string */ + memcpy (shellinput + *shellinput_size, "\033[?1;0c", 7); + *shellinput_size += 7; +} + +void do_send_cursor_position (unsigned char *shellinput, size_t *shellinput_size) +{ + debug (DEBUG_DETAIL, "Query cursor position detected"); + /* Cursor position request */ + *shellinput_size += sprintf ((char*)shellinput, "\033[%d;%dR", cursor_y / cell_h + 1, cursor_x / cell_w + 1); +} + +void do_send_status (unsigned char *shellinput, size_t *shellinput_size) +{ + debug (DEBUG_DETAIL, "Terminal status report requested"); + /* Request terminal status + \E[0n if OK, \E[3n if NOK (but we're always OK, aren't we?) */ + memcpy (shellinput + *shellinput_size, "\033[0n", 4); + *shellinput_size += 4; +} + + +/*------------------------------------------------------------------------------ +| Others | +------------------------------------------------------------------------------*/ + +void do_BELL () +{ + debug (DEBUG_DETAIL, "Special character code [BELL] detected"); + /* This should be a visual bell! */ +} + +void do_rep (unsigned int count) +{ + debug (DEBUG_DETAIL, "Escape Sequence 'rep %d' detected", count); + /* Repeat last character count times */ + while (count) + { + fbtermWriteChar (last_char); + fbtermNextPos (); + count--; + } +} + + +int +HandleEscapeSequences (unsigned char **buf, size_t *bufsize, unsigned char *shellinput, size_t *shellinput_size) +{ + size_t index; + unsigned char *escape; + unsigned int param[9] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + int in_ansi=0, in_escape=0, num_param=1, finished=0, i, ansi_question_mark=0; + + escape = *buf; + index = 0; + + do + { + if (!in_escape && !in_ansi) + { + finished = 1; + switch (escape[index]) + { + case 000: /* ignored */ + break; + case 005: + if (SHELLINPUT_SIZE - *shellinput_size >= 5) do_identify (shellinput, shellinput_size); + else return 2; + break; + case 007: /* Bell (7) */ + do_BELL (); + break; + case 010: /* Backspace */ + do_cub (1); + break; + case 011: /* Tab expansion */ + do_ht (); + break; + case 012: /* Line feed (10) */ + case 013: + case 014: + do_LF (); + break; + case 015: /* Carriage return (13) */ + do_CR (); + break; + case 016: + do_smacs (); + break; + case 017: + do_rmacs (); + break; + case 033: /* Escape character */ + in_escape = 1; + finished = 0; + break; + case 0177: /* for FreeBSD */ + do_cub (1); + break; + default: + return 1; + } + index++; + continue; + } + if (in_escape && !in_ansi) + { + finished = 1; + switch (escape[index]) + { + case '[': + in_ansi = 1; + finished = 0; + break; + /* Character set designator (we don't care) */ + case '(': /* G0 */ + case ')': /* G1 */ + if (index != 1) return 1; + finished = 0; + break; + /* Character set */ + case '0': /* line drawing set */ + if (index != 2) return 1; + switch (escape[1]) + { + case '(': + altcharset_mode = 1; + break; + case ')': break; + } + finished = 1; + case '1': /* alternate character ROM */ + case '2': /* alternate character ROM (graphics) */ + case 'A': /* United Kingdom */ + case 'B': /* US ASCII */ + if (index != 2) return 1; + switch (escape[1]) + { + case '(': + altcharset_mode = 0; + break; + case ')': break; + } + finished = 1; + break; + case 'D': + do_indn (1); + break; + case 'E': + do_CR (); + do_LF (); + break; + case 'H': + do_hts (); + break; + case 'M': + do_rin (1); + break; + case 'Z': /* identify, same as \E[c */ + if (SHELLINPUT_SIZE - *shellinput_size >= 7) do_identify (shellinput, shellinput_size); + else return 2; + break; + case '>': + /*force_cursor_mode = 1;*/ + break; + case '=': + /*force_cursor_mode = 0;*/ + break; + case '7': + /* Should we save current colors too? */ + saved_blink = blink_mode; + saved_bold = bold_mode; + saved_invisible = invisible_mode; + saved_reverse = reverse_mode; + saved_underline = underline_mode; + saved_altcharset = altcharset_mode; + savedcursor_x = cursor_x; + savedcursor_y = cursor_y; + break; + case '8': + blink_mode = saved_blink; + bold_mode = saved_bold; + invisible_mode = saved_invisible; + reverse_mode = saved_reverse; + underline_mode = saved_underline; + altcharset_mode = saved_altcharset; + cursor_x = savedcursor_x; + cursor_y = savedcursor_y; + break; + default: + return 1; + } + index++; + continue; + } + if (in_ansi) + { + finished = 1; + switch (escape[index]) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + param[num_param-1] = param[num_param-1]*10+escape[index]-48; + finished = 0; + break; + case ';': + num_param++; + finished = 0; + break; + case '?': + if (escape[index-1] != '[') + { + return 1; + } + ansi_question_mark = 1; + finished = 0; + break; + case '@': + if (!param[0]) param[0] = 1; + do_ich (param[0]); + break; + case 'A': + if (!param[0]) param[0] = 1; + do_cuu (param[0]); + break; + case 'B': + if (!param[0]) param[0] = 1; + do_cud (param[0]); + break; + case 'C': + if (!param[0]) param[0] = 1; + do_cuf (param[0]); + break; + case 'D': + if (!param[0]) param[0] = 1; + do_cub (param[0]); + break; + case 'F': + if (!param[0]) param[0] = 1; + do_rep (param[0]); + break; + case 'H': + case 'f': + if (!param[0]) param[0] = 1; + if (!param[1]) param[1] = 1; + do_cup (param[0], param[1]); + break; + case 'J': + switch (param[0]) + { + case 0: + /* Erase from cursor to end of screen */ + do_ed (); + break; + case 1: + /* Erase from beginning of screen to cursor */ + /* vt100 but no associated capability */ + fbtermEraseFromBOD (); + break; + case 2: + /* Erase entire screen */ + /* vt100 but no associated capability */ + fbtermEraseDisplay (); + break; + default: + return 1; + } + break; + case 'K': + switch (param[0]) + { + case 0: + /* Erase from cursor to end of line */ + do_el (); + break; + case 1: + /* Erase from beginning of line to cursor */ + do_el1 (); + break; + case 2: + /* Erase entire line containing cursor */ + /* vt100 but no associated capability */ + fbtermEraseLine (); + break; + default: + return 1; + } + break; + case 'P': + if (!param[0]) param[0] = 1; + do_dch (param[0]); + break; + case 'S': + if (!param[0]) param[0] = 1; + do_indn (param[0]); + break; + case 'T': + if (!param[0]) param[0] = 1; + do_rin (param[0]); + break; + case 'X': + if (!param[0]) param[0] = 1; + do_ech (param[0]); + break; + case 'Z': + do_cbt (); + break; + case 'c': + if (param[0]) return 1; + if (SHELLINPUT_SIZE - *shellinput_size >= 7) do_identify (shellinput, shellinput_size); + else return 2; + break; + case 'g': + switch (param[0]) + { + case 3: + do_tbc (); + break; + case 0: + do_clear_current_tab (); + break; + default: + return 1; + } + break; + case 'h': + if (ansi_question_mark) + { + for (i = 0; i < num_param; i++) + { + switch (param[i]) + { + case 1: + force_cursor_mode = 1; + break; + case 7: + autowrap = 1; + break; + /* the other modes are not implemented */ + case 3: + case 4: + case 5: + case 6: + case 8: + case 9: + break; + default: + return 1; + } + } + } + else + { + if (param[0] != 20) return 1; + } + break; + case 'l': + if (ansi_question_mark) + { + for (i = 0; i < num_param; i++) + { + switch (param[i]) + { + case 1: + force_cursor_mode = 0; + break; + case 7: + autowrap = 0; + break; + /* the other modes are not implemented */ + case 2: + case 3: + case 4: + case 5: + case 6: + case 8: + case 9: + break; + default: + return 1; + } + } + } + else + { + if (param[0] != 20) return 1; + } + break; + case 'm': + for (i = 0; i < num_param; i++) + { + switch (param[i]) + { + case 0: + do_leave_all_modes (); + break; + case 1: + do_bold (); + break; + case 4: + do_smul (); + break; + case 5: + do_blink (); + break; + case 7: + do_rev (); + break; + case 8: + do_invis (); + break; + default: + if (param[i]/10 == 3) + { + do_setaf (param[i] - 30); + break; + } + if (param[i]/10 == 4) + { + do_setab (param[i] - 40); + break; + } + return 1; + } + } + break; + case 'n': + switch (param[0]) + { + case 5: /* status report */ + if (SHELLINPUT_SIZE - *shellinput_size >= 4) + do_send_status (shellinput, shellinput_size); + else return 2; + break; + case 6: /* curosr position */ + if (SHELLINPUT_SIZE - *shellinput_size >= MAX_PARAM_SIZE*2+5) + do_send_cursor_position (shellinput, shellinput_size); + else return 2; + break; + default: + return 1; + } + break; + case 'r': + if (!param[0]) param[0] = 1; + if (!param[1]) param[0] = terminal_height; + do_change_region (param[0], param[1]); + break; + default: + return 1; + } + } + index++; + } + while (index<(*bufsize) && !finished && num_param<=MAX_PARAM_NUM && param[num_param]<=MAX_PARAM_VALUE); + + if (finished) + { + (*buf) += index; + (*bufsize) -= index; + return 0; + } + if (index>=(*bufsize)) return 2; + return 1; +} diff --git a/libfbui/Term/fbterm.c b/libfbui/Term/fbterm.c @@ -0,0 +1,464 @@ + +#define VERSION "0.1" +#include "fbterm.h" + +/* External functions and variables */ + +int HandleEscapeSequences (unsigned char **, size_t *, unsigned char*, size_t*); +void MoveCursor (int, int); + +void fbtermNextPos (); +int FBUIWriteChar (wchar_t); +int FBUIInit_graphicsmode (int,short,short,short,short); +void HandleFBUIEvents (unsigned char *, size_t *); +void FBUIExit (void); +void fbtermBlinkCursor (int); +#ifdef DEBUG +void ShowGrid (void); +#endif /* DEBUG */ + + +extern int vis_w, vis_h; +extern int cursor_x, cursor_y, cursor_x0, cursor_y0, cell_w, cell_h; +extern int altcharset_mode; +extern int region_top, region_bottom; + +extern char **environ; + +/* Global variables */ +int terminal_width, terminal_height; +int quit = 0; +#ifdef DEBUG +int debuglevel = 0; +#endif /* DEBUG */ +wchar_t last_char; +char result[SHELLOUTPUT_SIZE*4+1]; +char *tabstops; + + +int (*fbtermWriteChar) (wchar_t charcode); +int (*fbtermGetShellChar) (wchar_t *charcode, unsigned char **inputbuf, + size_t *inputsize); +int (*fbtermPutShellChar) (unsigned char *buffer, + size_t *index, wchar_t charcode); + + +int +DefaultGetShellChar (wchar_t *charcode, unsigned char **inputbuf, + size_t *inputsize) +{ +#ifdef MULTIBYTE + size_t bytes; + + if (altcharset_mode) + { + /* we bypass the multibyte handling */ + *charcode = (*inputbuf)[0]; + (*inputsize)--; + (*inputbuf)++; + return 0; + } + bytes = mbtowc (charcode, (char*) *inputbuf, *inputsize); + switch (bytes) + { + case -1: + /* invalid character encountered */ + debug (DEBUG_INFO, + "Invalid byte, skipping it"); + (*inputsize)--; + (*inputbuf)++; + return 1; + case -2: + /* incomplete input */ + debug (DEBUG_INFO, + "Incomplete input"); + return 2; + default: + (*inputsize) -= bytes; + (*inputbuf) += bytes; + return 0; + } +#else + *charcode = (*inputbuf)[0]; + (*inputsize)--; + (*inputbuf)++; + return 0; +#endif +} + +int +DefaultPutShellChar (unsigned char *buffer, size_t *index, wchar_t charcode) +{ +# ifdef MULTIBYTE + (*index) += wctomb ((char*) buffer, charcode); +# else + buffer[*index] = (unsigned char)(charcode & 0xFF); + (*index)++; +# endif + return 0; +} + +void +fbtermUsage (void) +{ + fprintf (stderr, + "\n" + "fbterm v%s by Z. Smith\n" + "Based on ggiterm v0.6.2 by A. Reynaud\n" + "\n" + "Usage: fbterm [OPTIONS...]\n" + "Where option is one or more of:\n" + " --help\n", VERSION); + fprintf (stderr, + " --debuglevel n (%d:none, %d:info, %d:detailed, %d:total, default:%d)\n", + DEBUG_NONE, DEBUG_INFO, DEBUG_DETAIL, DEBUG_TOTAL, DEBUG_NONE); + fprintf (stderr, + " --font <font file>\n" + " --font-size n (default: %d)\n\n", DEFAULT_FONTSIZE); +} + +void +child_died () +{ + quit = 2; +} + + +#ifdef DEBUG +char* BinaryToPrintable (unsigned char* buffer, size_t size) +{ + int i, index=0; + + for (i=0; i<size; i++) + { + if (buffer[i]>=32 && buffer[i]<=126) + { + sprintf (result+index, "%c", buffer[i]); + index++; + } + else + { + sprintf (result+index, "\\%03o", buffer[i]); + index += 4; + } + } + result[index] = '\0'; + return result; +} +#endif /* DEBUG */ + +void +HandleShellOutput (unsigned char *shelloutput, size_t *shelloutput_size, unsigned char *shellinput, size_t *shellinput_size) +{ + int err; + size_t buffer_size; + unsigned char *buffer; + wchar_t charcode; + + buffer = shelloutput; + buffer_size = *shelloutput_size; + do + { + debug (DEBUG_DETAIL, "Parsing shell output: %s", BinaryToPrintable (buffer, buffer_size)); + do + { + err = HandleEscapeSequences (&buffer, &buffer_size, shellinput, shellinput_size); + debug (DEBUG_DETAIL, "HandleEscapeSequences returned %d", err); + } + while (!err && buffer_size > 0); + if (err == 1 && buffer_size > 0) + { + err = fbtermGetShellChar (&charcode, &buffer, &buffer_size); + if (!err) + { +#ifdef MULTIBYTE + if (iswprint ((wint_t)charcode)) + { + debug (DEBUG_DETAIL, + "Character code = 0x%08lX (%09ld)\t\"%lc\"", + (unsigned long)charcode, (unsigned long)charcode, (wint_t)charcode); +#else + if (isprint (charcode)) + { + debug (DEBUG_DETAIL, + "Character code = 0x%08lX (%09ld)\t\"%c\"", + (unsigned long)charcode, (unsigned long)charcode, (int)charcode); +#endif + } + else + { + debug (DEBUG_DETAIL, + "Character code = 0x%08lX (%09ld)\t\"?\" (unprintable)", + (unsigned long)charcode, (unsigned long)charcode); + } + fbtermWriteChar (charcode); + last_char = charcode; + fbtermNextPos (); + } + } + } + while (buffer_size > 0 && err != 2); + // ggiFlush (vis); + memmove (shelloutput, buffer, buffer_size); + *shelloutput_size = buffer_size; +} + + +extern int fbui_parse_geom (char *s1, short *w, short *h, short *xr, short *yr); + +int master_fd; +struct winsize ws; + +int +/*main (int argc, char **argv, char **envp)*/ +main (int argc, char **argv) +{ + int err, using_ft=0; + pid_t shell_pid; + unsigned char shelloutput[SHELLOUTPUT_SIZE]; + size_t shelloutput_size = 0; + unsigned char shellinput[SHELLINPUT_SIZE]; + size_t shellinput_size = 0; + char buf[128]; + struct timeval tv; + fd_set rfds, wfds; + char *shell = "/bin/sh"; + + int vc = -1; + short cols = 80; + short rows = 33; + short xrel = 0; + short yrel = 10; + + argv++; + argc--; + int i=0; + while (i < argc) { + if (!strncmp (argv[i], "-c",2)) { + vc = atoi (argv[i]+2); + } + else if (!strncmp (argv[i], "-geo",4)) { + short n1,n2,n3,n4; + if (fbui_parse_geom (argv[i]+4,&n1,&n2,&n3,&n4)) { + cols = n1; + rows = n2; + xrel = n3; + yrel = n4; + } + } + else if (!strcmp (argv[i], "--help")) { + fbtermUsage (); + return 0; + } + else if (!strcmp (argv[i], "--encoding")) { + fbtermError ("The --encoding option is obsolete. Codesets are now handled automatically."); + argc -= 2; + argv += 2; + continue; + } + else + if (!strcmp (argv[i], "--debuglevel")) + { +#ifdef DEBUG + debuglevel = strtol (argv[1], NULL, 10); + if (errno == ERANGE) + { + perror ("fbterm: strtol"); + return 1; + } + argc -= 2; + argv += 2; + continue; +#else + fbtermError ("Debug support not compiled in\n"); + return 1; +#endif /* DEBUG */ + } else { + fbtermError ("Unknown option %s\n", argv[i]); + return 1; + } + i++; + } + + /* Get current locale */ +#ifdef MULTIBYTE + setlocale (LC_CTYPE, ""); +# ifdef HAVE_NL_LANGINFO + debug (DEBUG_INFO, "Current codeset is %s", nl_langinfo (CODESET)); +# else + debug (DEBUG_INFO, "Current codeset is unknown - nl_langinfo() undefined"); +# endif + debug (DEBUG_INFO, "Maximum character length is %d", MB_CUR_MAX); +#endif /* MULTIBYTE */ + + debug (DEBUG_INFO, "Setting up default handlers:"); + fbtermGetShellChar = &DefaultGetShellChar; + debug (DEBUG_INFO, " fbtermGetShellChar -> DefaultGetShellChar"); + fbtermPutShellChar = &DefaultPutShellChar; + debug (DEBUG_INFO, " fbtermPutShellChar -> DefaultPutShellChar"); + fbtermWriteChar = &FBUIWriteChar; + debug (DEBUG_INFO, " fbtermWriteChar -> FBUIWriteChar"); + + err = FBUIInit_graphicsmode (vc,cols,rows,xrel,yrel); + if (!err) + { + debug (DEBUG_INFO, "Using FBUI in graphics mode."); + } + else + { + fbtermError ("Cannot complete FBUI setup. Aborting."); + FBUIExit (); + return 1; + } + + region_top = 0; + region_bottom = terminal_height; + MoveCursor (cursor_x0, cursor_y0); + debug (DEBUG_INFO, "Terminal is %d x %d characters", + terminal_width, terminal_height); + debug (DEBUG_INFO, "Characters are %d x %d pixels", cell_w, + cell_h); + /* Allocate and populate the array for tab stops */ + tabstops = malloc (terminal_width * sizeof(char)); + for (err=0; err<terminal_width; err++) + { + tabstops[err] = (err%8 ? 0 : 1); + } + + if (getenv ("SHELL") != NULL) + { + shell = getenv ("SHELL"); + } + signal (SIGCHLD, child_died); + + ws.ws_col = terminal_width; + ws.ws_row = terminal_height; + ws.ws_xpixel = vis_w; + ws.ws_ypixel = vis_h; + + /* in the following, buf should be set to NULL because of buffer overflow + * risk, but is left so for debugging purposes */ + shell_pid = forkpty (&master_fd, buf, NULL, &ws); + if (shell_pid < 0) + { + perror ("fbterm: Couldn't fork. Exiting.\n"); + exit (1); + } + if (shell_pid == 0) + { + char *argv[] = { shell, NULL }; +#ifdef HAVE_PUTENV + putenv ("TERM=fbterm"); +#else + setenv ("TERM", "fbterm", 1); +#endif /* HAVE_PUTENV */ + debug (DEBUG_DETAIL, + "This is the forked process (PID %d, child of PID %d)\n", + (int)getpid (), (int)getppid ()); + debug (DEBUG_DETAIL, + "Sample UTF-8 output: Caractères français"); + debug (DEBUG_DETAIL, + "Sample LATIN1 output: Caractères français"); + debug (DEBUG_DETAIL, "Now exec-ing %s", shell); + execve (argv[0], argv, environ); + exit (1); + } + debug (DEBUG_INFO, "Child forked (PID %d), pseudo tty is %s", + (int)shell_pid, buf); + debug (DEBUG_INFO, "Waiting for its death..."); + + while (!quit) + { + fbtermBlinkCursor (CURSOR_AUTO); + + /* do we have pending FBUI events? + * (non blocking) + */ + HandleFBUIEvents (shellinput, &shellinput_size); + + tv.tv_sec = 0; + tv.tv_usec = 20000; + FD_ZERO (&rfds); + FD_ZERO (&wfds); + FD_SET (master_fd, &rfds); + if (shellinput_size) + FD_SET (master_fd, &wfds); + + err = select (master_fd + 1, &rfds, &wfds, NULL, &tv); + if (err < 0 && errno != EINTR) + { + perror ("fbterm: select"); + continue; + } + if (quit) break; + if (err) debug (DEBUG_DETAIL, "%d file descriptors updated", err); + + if (FD_ISSET (master_fd, &wfds)) + { + debug (DEBUG_DETAIL, "master_fd is ready for writing"); + /* if we have anything pending, then write it */ + if (shellinput_size) + { + do err = write (master_fd, shellinput, shellinput_size); + while (err < 0 && errno == EINTR && !quit); + if (err < 0) + { + perror ("fbterm: write"); + continue; + } + if (quit) break; + debug (DEBUG_DETAIL, + "Written %d bytes out of %d to master_fd", err, + (int)shellinput_size); + memmove (shellinput, shellinput+err, shellinput_size - err); + shellinput_size -= err; + } + } + + if (FD_ISSET (master_fd, &rfds)) + { + debug (DEBUG_DETAIL, "master_fd is set\nmain: Reading:"); + debug (DEBUG_DETAIL, "Buffer index is %d", (int)shelloutput_size); + do err = read (master_fd, shelloutput + shelloutput_size, SHELLOUTPUT_SIZE - shelloutput_size); + while (err < 0 && errno == EINTR && !quit); + if (err < 0) + { + perror ("fbterm: read"); + continue; + } + if (err == 0) quit = 1; + if (quit) break; + if (err > 0) + { + debug (DEBUG_DETAIL, "Read %d bytes from master_fd", err); + shelloutput_size += err; + debug (DEBUG_DETAIL, + "Buffer index is now %d", + (int)shelloutput_size); + fbtermBlinkCursor (CURSOR_HIDE); + HandleShellOutput (shelloutput, &shelloutput_size, shellinput, &shellinput_size); + fbtermBlinkCursor (CURSOR_SHOW); + } + debug (DEBUG_DETAIL, "Finished reading"); + } + } + + switch (quit) + { + case 1: + debug (DEBUG_INFO, "Exiting: EOF condition"); + break; + case 2: + debug (DEBUG_INFO, "Exiting: Child process has died"); + break; + case 3: + debug (DEBUG_INFO, "Exiting: Pipe error"); + break; + } + fbtermBlinkCursor (1); + FBUIExit (); + free (tabstops); + close (master_fd); + + return (0); +} diff --git a/libfbui/Term/fbterm.h b/libfbui/Term/fbterm.h @@ -0,0 +1,136 @@ + + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + + +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +/* for struct winsize and struct termios, not always included by FORKPTY_HEADER */ +#include <termios.h> +/* for pid_t, strangely not included by FORKPTY_HEADER */ +#include <sys/types.h> +/* for execve, read, write */ +#include <unistd.h> + + +#ifdef MULTIBYTE + +# include <locale.h> +/* MacOS X doesn't have langinfo.h, although the docs say otherwise. It's a + bug on their part since it's a Single Unix Specification requirement */ +# ifdef HAVE_NL_LANGINFO +# include <langinfo.h> +# endif + +# ifdef HAVE_ISWPRINT +# include <wctype.h> +# else +# define wint_t unsigned int +int iswprint (wint_t wc); +# endif + +#else /* MULTIBYTE */ + +# define wchar_t unsigned int +# include <ctype.h> /* pour isprint */ + +#endif /* MULTIBYTE */ + +#if !STDC_HEADERS + +/* if the standard C headers are not present, we need to declare the functions + that may be declared in some other unknown header ourselves */ +long int strtol(const char *nptr, char **endptr, int base); +void *memcpy(void *dest, const void *src, size_t n); +void *memset(void *s, int c, size_t n); +void *memmove(void *dest, const void *src, size_t n); +int strcmp(const char *s1, const char *s2); + +/* Then maybe the functions themselves are not present... Tough! */ +# if !HAVE_MEMMOVE +# /* find a solution */ +# endif +# if !HAVE_MEMCPY +# /* find a solution */ +# endif +# if !HAVE_MEMSET +# /* find a solution */ +# endif +# if !HAVE_STRCMP +# /* find a solution */ +# endif + +#else +# include <string.h> +#endif /* STDC_HEADERS */ + + +/* signals */ +#include <signal.h> + +/* for forkpty() */ +#include <sys/ioctl.h> /* some systems (BSD) need it even with FORKPTY_HEADER */ +#ifdef FORKPTY_HEADER +# include FORKPTY_HEADER +#else +pid_t forkpty(int *amaster, char *name, struct termios *termp, struct winsize *winp); +#endif + +/* for select and associated macros */ +#ifdef HAVE_SYS_SELECT_H +#include <sys/select.h> +#else +#include <sys/time.h> +#include <sys/types.h> +#include <unistd.h> +#endif + +/* for gettimeofday */ +#include <sys/time.h> + + +/* FBUI */ +#include <ggi/ggi.h> + +#define fbtermError(...) { fprintf (stderr, "%s: ", __func__); fprintf (stderr, __VA_ARGS__); fprintf (stderr, "\n"); } + +#ifdef DEBUG +extern int debuglevel; +#define debug(level, ...) {if (level <= debuglevel) { fprintf (stdout, "%s: ", __func__); fprintf (stdout, __VA_ARGS__); fprintf (stdout, "\n"); }} +#else +#define debug(level, ...) {} +#endif + +#define DEBUG_NONE 0 +#define DEBUG_INFO 1 +#define DEBUG_DETAIL 2 +#define DEBUG_TOTAL 3 + +#define CURSOR_AUTO 0 +#define CURSOR_HIDE 1 +#define CURSOR_SHOW 2 + +#define MAX_PARAM_NUM 9 +#define MAX_PARAM_VALUE 32767 +#define MAX_PARAM_SIZE 5 + +/* must be at least MAX_PARAM_SIZE*2+5 chars long, since do_u6() can send that much */ +#define SHELLINPUT_SIZE (MAX_PARAM_SIZE*2+5+17) + +/* set with care: + - must be greater than the biggest escape sequence possible + - input is frozen while shell output is rendered, so user experience + commands it must not be too big either + - when rendering of entire strings gets implemented, a small value will + prevent taking advantage of it + 128 seems a good compromise... */ +#define SHELLOUTPUT_SIZE 128 + +/* must be defined because even if FT support is not compiled in, + FreetypeInit() is called with fontsize as argument */ +#define DEFAULT_FONTSIZE 12 + +#define FBUIFLUSH_BUG diff --git a/libfbui/Term/fbterm.termcap b/libfbui/Term/fbterm.termcap @@ -0,0 +1,22 @@ +# Reconstructed via infocmp from file: /home/aurelien/.terminfo/g/fbterm +fbterm|vt100-compatible terminal for FBUI:\ + :am:ms:xn:xo:\ + :Co#8:co#80:it#8:li#24:pa#64:vt#3:\ + :@8=\EOM:AB=\E[4%dm:AF=\E[3%dm:DC=\E[%dP:DO=\E[%dB:\ + :IC=\E[%d@:K1=\EOq:K2=\EOr:K3=\EOs:K4=\EOp:K5=\EOn:\ + :LE=\E[%dD:RA=\E[?7l:RI=\E[%dC:SA=\E[?7h:SF=\E[%dS:\ + :SR=\E[%dT:UP=\E[%dA:\ + :ac=++,,--..00``aaffgghhjjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~:\ + :ae=^O:as=^N:bl=^G:bt=\E[Z:cb=\E[1K:cd=\E[J:ce=\E[K:\ + :cl=\E[H\E[J:cm=\E[%i%d;%dH:cr=^M:cs=\E[%i%d;%dr:\ + :ct=\E[3g:dc=\E[P:do=^J:eA=\E(B\E)0:ec=\E[%dX:ei=:ho=\E[H:\ + :im=:k0=\EOy:k1=\EOP:k2=\EOQ:k3=\EOR:k4=\EOS:k5=\EOt:\ + :k6=\EOu:k7=\EOv:k8=\EOl:k9=\EOw:k;=\EOx:kB=\E[Z:kI=\E[L:\ + :kb=^H:kd=\EOB:ke=\E[?1l\E>:kl=\EOD:kr=\EOC:ks=\E[?1h\E=:\ + :ku=\EOA:le=^H:mb=\E[5m:md=\E[1m:me=\E[m\017:mk=\E[8m:\ + :mr=\E[7m:nd=\E[C:op=\E[39;49m:rc=\E8:\ + :..rp=%p1%c\E[%p2%{1}%-%dF:\ + :rs=\E>\E[?3l\E[?4l\E[?5l\E[?7h\E[?8h:\ + :..sa=\E[0%?%p1%p6%|%t;1%;%?%p2%t;4%;%?%p1%p3%|%t;7%;%?%p4%t;5%;%?%p7%t;8%;m%?%p9%t\016%e\017%;:\ + :sc=\E7:se=\E[m:sf=^J:so=\E[7m:sr=\EM:st=\EH:ta=^I:ue=\E[m:\ + :up=\E[A:us=\E[4m: diff --git a/libfbui/Term/fbterm.terminfo b/libfbui/Term/fbterm.terminfo @@ -0,0 +1,109 @@ +# fbterm capabilities (terminfo source) +# As fbterm recognizes the vt100 escape sequences, this is essentially +# the linux vt100 terminfo entry, without the timings, and with some additional +# capabilities specific to fbterm. +# To generate the termcap equivalent, use infocmp -C -r fbterm > fbterm.termcap + +fbterm|vt100-compatible terminal for FBUI, + +# Original vt100 capabilities + am, + msgr, + xenl, + xon, + cols#80, + it#8, + lines#24, + vt#3, + bel=^G, + blink=\E[5m, + bold=\E[1m, + clear=\E[H\E[J, + cr=^M, + csr=\E[%i%p1%d;%p2%dr, + cub=\E[%p1%dD, + cub1=^H, + cud=\E[%p1%dB, + cud1=^J, + cuf=\E[%p1%dC, + cuf1=\E[C, + cup=\E[%i%p1%d;%p2%dH, + cuu=\E[%p1%dA, + cuu1=\E[A, + ed=\E[J, + el=\E[K, + el1=\E[1K, + enacs=\E(B\E)0, + home=\E[H, + ht=^I, + hts=\EH, + ind=^J, + ka1=\EOq, + ka3=\EOs, + kb2=\EOr, + kbs=^H, + kc1=\EOp, + kc3=\EOn, + kcub1=\EOD, + kcud1=\EOB, + kcuf1=\EOC, + kcuu1=\EOA, + kent=\EOM, + kf0=\EOy, + kf1=\EOP, + kf10=\EOx, + kf2=\EOQ, + kf3=\EOR, + kf4=\EOS, + kf5=\EOt, + kf6=\EOu, + kf7=\EOv, + kf8=\EOl, + kf9=\EOw, + rc=\E8, + rev=\E[7m, + ri=\EM, + rmacs=^O, + rmam=\E[?7l, + rmkx=\E[?1l\E>, + rmso=\E[m, + rmul=\E[m, + rs2=\E>\E[?3l\E[?4l\E[?5l\E[?7h\E[?8h, + sc=\E7, + sgr0=\E[m\017, + smacs=^N, + smam=\E[?7h, + smkx=\E[?1h\E=, + smso=\E[7m, + smul=\E[4m, + tbc=\E[3g, +# Color handling + colors#8, + pairs#64, + op=\E[39;49m, + setab=\E[4%p1%dm, + setaf=\E[3%p1%dm, +# Alternate character set. fbterm supports more graphical characters than vt100 +# acsc=``aaffggjjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~, + acsc=++\,\,--..00``aaffgghhjjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~, +# Invisible mode + invis=\E[8m, +# Modified sgr to include invisible mode +# sgr=\E[0%?%p1%p6%|%t;1%;%?%p2%t;4%;%?%p1%p3%|%t;7%;%?%p4%t;5%;m%?%p9%t\016%e\017%;$<2>, + sgr=\E[0%?%p1%p6%|%t;1%;%?%p2%t;4%;%?%p1%p3%|%t;7%;%?%p4%t;5%;%?%p7%t;8%;m%?%p9%t\016%e\017%;, +# Scroll several lines at a time + indn=\E[%p1%dS, + rin=\E[%p1%dT, +# Repeat the last character + rep=%p1%c\E[%p2%{1}%-%dF, +# Insert key + kich1=\E[L, +# Insert characters + ich=\E[%p1%d@, +# Delete or erase characters + ech=\E[%p1%dX, + dch=\E[%p1%dP, + dch1=\E[P, +# Back Tab + cbt=\E[Z, + kcbt=\E[Z, diff --git a/libfbui/Term/forkpty.c b/libfbui/Term/forkpty.c @@ -0,0 +1,111 @@ + +#include "fbterm.h" + +#ifndef HAVE_FORKPTY + +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <termios.h> +/*#if GWINSZ_IN_SYS_IOCTL*/ +#include <sys/ioctl.h> +/*#endif*/ + + +int forkpty_findtty (int* master_fd, int* slave_fd, char *name) +{ + int n; + char master_name[16]; + char slave_name[16]; + + for (n=0; n<16; n++) + { + sprintf (master_name, "/dev/ptyp%x", n); + *master_fd = open (master_name, O_RDWR); + if (*master_fd >= 0) break; + } + + if (n==16) return -1; + + sprintf (slave_name, "/dev/ttyp%x", n); + sprintf (name, "/dev/ttyp%x", n); + *slave_fd = open (slave_name, O_RDWR); + if (*slave_fd < 0) + { + perror (slave_name); + close (*master_fd); + return -1; + } + + return 0; +} + + + + +pid_t forkpty (int *master_fd, char *name, struct termios *termp, struct winsize *winp) +{ + int slave_fd; + pid_t pid; + + debug (DEBUG_INFO, "entering custom forkpty\n"); + if (forkpty_findtty (master_fd, &slave_fd, name) < 0) + { + fbtermError ("Couldn't open any tty.\n"); + return -1; + } + + if (ioctl (*master_fd, TIOCSWINSZ, winp) < 0) + { + fbtermError ("Error setting window size.\n"); + } + + debug (DEBUG_DETAIL, "Forking\n"); + if ((pid = fork ()) == 0) + { + close (*master_fd); + + seteuid (getuid ()); + setegid (getgid ()); + setsid (); + + /* If we have TIOCSCTTY we use it to set our controlling tty */ +#ifdef TIOCSCTTY + ioctl (slave_fd, TIOCSCTTY, 0); +#else + /* If not this should do: the first tty a process opens becomes + its controlling tty */ + debug (DEBUG_INFO, "Child: Closing %s\n", name); + close (slave_fd); + debug (DEBUG_INFO, "Child: Reopening %s\n", name); + slave_fd = open (name, O_RDWR); + if (slave_fd < 0) + { + perror (name); + fbtermError ("Child: Couldn't reopen %s\nExiting\n", name); + /* if it didn't work, exit noisily! */ + exit (1); + } + else + debug (DEBUG_INFO, "Child: Reopened %s\n", name); +#endif /* TIOCSCTTY */ + + close (0); + close (1); + close (2); + + dup2 (slave_fd, 0); + dup2 (slave_fd, 1); + dup2 (slave_fd, 2); + } + else + { + close (slave_fd); + debug (DEBUG_INFO, "leaving custom forkpty\n"); + } + return pid; +} + +#endif /* HAVE_FORKPTY */ diff --git a/libfbui/Term/iswprint.c b/libfbui/Term/iswprint.c @@ -0,0 +1,14 @@ + +#include "fbterm.h" + +#ifndef HAVE_ISWPRINT + +int iswprint (wint_t wc) +{ + if (wc >= 0x0 && wc <= 0x1F) return 0; + if (wc >= 0x7F && wc <= 0x9F) return 0; + if (wc >= 0xE000 && wc <= 0xF8FF) return 0; + return 1; +} + +#endif /* HAVE_ISWPRINT */ diff --git a/libfbui/Term/main.c b/libfbui/Term/main.c @@ -0,0 +1,792 @@ + +/*========================================================================= + * + * fbterm, a terminal emulator based on ggiterm for FBUI. + * Copyright (C) 2004 Zachary T Smith, fbui@comcast.net + * Portions from ggiterm are Copyright (C) by Aurelien Reynaud. + * + * This module is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This module 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this module; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * (See the file COPYING in the main directory of this archive for + * more details.) + * + *=======================================================================*/ + +#include <linux/fb.h> + +#include "libfbui.h" +#include "fbterm.h" + +#define BLINK_TIME 500 + +static Display *dpy = NULL; +static Window *win = NULL; +static Font *font = NULL; + +extern struct winsize ws; +extern int master_fd; + +extern int terminal_width, terminal_height; + +static wchar_t *exposebuffer; +static char *exposebuffer_fg; +static char *exposebuffer_bg; + +/* Global variables */ +int vis_w, vis_h; +int cursor_x, cursor_y, cursor_x0, cursor_y0, cell_w, cell_h; +static RGB color[16] = { + 0, + 0xb00000, + 0xb000, + 0xb0b000, + 0xb0, + 0xb000b0, + 0xb0b0, + 0xb0b0b0, + + 0, + 0xff0000, + 0xff00, + 0xffff00, + 0xff, + 0xff00ff, + 0xffff, + 0xffffff, +}; + +int default_bgcolor, default_fgcolor, fgcolor, bgcolor; +int blink_mode = 0, bold_mode = 0, invisible_mode = 0, reverse_mode = 0, underline_mode = 0, altcharset_mode = 0; +int autowrap = 1, force_cursor_mode = 0; +int region_top, region_bottom; +extern int linewrap_pending; + +extern int (*fbtermPutShellChar) (unsigned char *, size_t *, wchar_t); + +void redraw () +{ + int j; + for (j=0; j<terminal_height; j++) { + int i; + for (i=0; i<terminal_width; ) { + int ix =i + j*terminal_width; + wchar_t ch = exposebuffer[ix]; + char s[terminal_width]; + unsigned long fg, bg; + char my_fg = exposebuffer_fg [ix]; + char my_bg = exposebuffer_bg [ix]; + fg = color [my_fg]; + bg = color [my_bg]; + + short x0,y0; + x0 = cell_w*i; + y0 = cell_h*j; + + char all_blanks = 1; + + /* find maximal area that has the same bg/fg colors */ + int k=1; + s[0] = ch; + while ((k+i)<terminal_width && exposebuffer_fg[ix+k]==my_fg && + exposebuffer_bg[ix+k]==my_bg) + { + ch = s[k] = exposebuffer[ix+k]; + if (ch != ' ') + all_blanks = 0; + k++; + } + s[k] = 0; + fbui_fill_area (dpy, win, x0,y0,x0+(k*cell_w)-1,y0+cell_h-1, bg); + + if (!all_blanks) + fbui_draw_string (dpy, win, NULL, x0,y0, s, fg); + i += k; + } + } +} + +void resize(int new_width, int new_height) +{ + int i, j; + + if (new_width==terminal_width && new_height==terminal_height) + return; + + unsigned long size = new_width * new_height; + wchar_t *newbuffer = (wchar_t*) malloc(sizeof(wchar_t) * size); + char *newbuffer_fg = malloc(size); + char *newbuffer_bg = malloc(size); + + if (!newbuffer || !newbuffer_fg || !newbuffer_bg) + FATAL ("out of memory in resize()"); + + for (j=0;j<size;j++) { + newbuffer[j] = ' '; + newbuffer_fg[j] = default_fgcolor; + newbuffer_bg[j] = default_bgcolor; + } + + for (j=0; j<terminal_height; j++) { + for (i=0; i<terminal_width; i++) { + if (i < new_width && j < new_height) { + int ix =i + j*terminal_width; + wchar_t ch = exposebuffer[ix]; + char fg = exposebuffer_fg [ix]; + char bg = exposebuffer_bg [ix]; + + int ix2 = i + j*new_width; + newbuffer[ix2] = ch; + newbuffer_fg[ix2] = fg; + newbuffer_fg[ix2] = bg; + } + } + } + + free (exposebuffer); + free (exposebuffer_fg); + free (exposebuffer_bg); + + exposebuffer = newbuffer; + exposebuffer_fg = newbuffer_fg; + exposebuffer_bg = newbuffer_bg; + + terminal_width = new_width; + terminal_height = new_height; + +#if 0 + redraw(); + + fbui_draw_line (dpy,win,0,0,100,100,RGB_YELLOW); + fbui_flush (dpy,win); +#endif +} + +void scroll_exposebuf_up(int num, int top, int bottom) +{ + int i,j,k; + int y; + for (j=top+num; j<=bottom; j+=num) { + k=0; + while (k < num) { + y = j+k; + if (y < terminal_height) + for (i=0; i<terminal_width; i++) { + int ix = i+terminal_width*y; + exposebuffer [ix-terminal_width] = exposebuffer[ix]; + exposebuffer_fg [ix-terminal_width] = exposebuffer_fg [ix]; + exposebuffer_bg [ix-terminal_width] = exposebuffer_bg [ix]; + } + k++; + } + } + k=0; + while (k < num) { + y = bottom-k-1; + if (y < terminal_height) + for (i=0; i<terminal_width; i++) { + int ix = i+terminal_width*y; + exposebuffer [ix] = ' '; + exposebuffer_fg [ix] = default_bgcolor; + exposebuffer_bg [ix] = default_bgcolor; + } + k++; + } +} + + +void scroll_exposebuf_down() +{ + int i,j; + for (j=terminal_height-2; j>=0; j--) { + for (i=0; i<terminal_width; i++) { + int ix = i+terminal_width*j; + exposebuffer [ix+terminal_width] = exposebuffer[ix]; + exposebuffer_fg [ix+terminal_width] = exposebuffer_fg [ix]; + exposebuffer_bg [ix+terminal_width] = exposebuffer_bg [ix]; + } + } + for (i=0; i<terminal_width; i++) { + exposebuffer [i] = ' '; + exposebuffer_fg [i] = default_bgcolor; + exposebuffer_bg [i] = default_bgcolor; + } +} + + + +void MoveCursor (int, int); + + +wchar_t AsciiGetAltChar (wchar_t charcode) +{ + switch (charcode) + { + case '+': charcode = '>'; break; /* vt100 '+': arrow pointing right */ + case ',': charcode = '<'; break; /* vt100 ',': arrow pointing left */ + case '-': charcode = 0136; break; /* vt100 '-': arrow pointing up */ + case '.': charcode = 'v'; break; /* vt100 '.': arrow pointing down */ + case '0': charcode = '#'; break; /* vt100 '0': solid square block */ + case '`': charcode = '+'; break; /* vt100 '`': diamond */ + case 'a': charcode = ':'; break; /* vt100 'a': checker board (stipple) */ + case 'f': charcode = '\\'; break; /* vt100 'f': degree */ + case 'g': charcode = '#'; break; /* vt100 'g': plus/minus */ + case 'h': charcode = '#'; break; /* vt100 'h': board os squares */ + case 'j': charcode = '+'; break; /* vt100 'j': rightdown corner */ + case 'k': charcode = '+'; break; /* vt100 'k': upright corner */ + case 'l': charcode = '+'; break; /* vt100 'l': upleft corner */ + case 'm': charcode = '+'; break; /* vt100 'm': downleft corner */ + case 'n': charcode = '+'; break; /* vt100 'n': crossover */ + case 'o': charcode = '~'; break; /* vt100 'o': scan line 1 */ + case 'p': charcode = '-'; break; /* vt100 'p': scan line 3 */ + case 'q': charcode = '-'; break; /* vt100 'q': horizontal line */ + case 'r': charcode = '-'; break; /* vt100 'r': scan line 7 */ + case 's': charcode = '_'; break; /* vt100 's': scan line 9 */ + case 't': charcode = '+'; break; /* vt100 't': tee pointing right */ + case 'u': charcode = '+'; break; /* vt100 'u': tee pointing left */ + case 'v': charcode = '+'; break; /* vt100 'v': tee pointing up */ + case 'w': charcode = '+'; break; /* vt100 'w': tee pointing down */ + case 'x': charcode = '|'; break; /* vt100 'x': vertical line */ + case 'y': charcode = '<'; break; /* vt100 'y': less or equal */ + case 'z': charcode = '>'; break; /* vt100 'z': more or equal */ + case '{': charcode = '*'; break; /* vt100 '{': Pi */ + case '|': charcode = '!'; break; /* vt100 '|': not equal */ + case '}': charcode = 'f'; break; /* vt100 '}': UK pound */ + case '~': charcode = 'o'; break; /* vt100 '~': bullet */ + } + return charcode; +} + + +void +fbtermBlinkCursor (int force) +{ + int x,y; + x = cell_w*(int)(cursor_x/cell_w); + y = cell_h*(int)(cursor_y/cell_h); + + if (force != CURSOR_HIDE) + { + fbui_fill_area (dpy, win, + x, y, x + cell_w - 1, y + cell_h - 1, color[fgcolor]); + } + else + { + fbui_fill_area (dpy, win, + x, y, x + cell_w - 1, y + cell_h - 1, color[bgcolor]); + } + fbui_flush (dpy, win); +} + +void +fbtermDeleteChars (unsigned int nb_chars) +{ + int x, y; + + x = cell_w * (int)(cursor_x / cell_w); + y = cell_h * (int)(cursor_y / cell_h); + /* Copy the characters between current+nb_chars and EOL to current position */ + /*ggiFlush (vis);*/ + + fbui_flush (dpy, win); + fbui_copy_area (dpy, win, x+(nb_chars*cell_w), y, x, y, + vis_w-x-(nb_chars*cell_w), cell_h); +} + +void +fbtermInsertChars (unsigned int nb_chars) +{ + int x, y; + + x = cell_w * (int)(cursor_x / cell_w); + y = cell_h * (int)(cursor_y / cell_h); + + fbui_copy_area (dpy, win, x, y, x+(nb_chars*cell_w), y, vis_w-x, cell_h); + fbui_fill_area (dpy, win, x, y, nb_chars*cell_w, cell_h, color[default_bgcolor]); +} + +void +fbtermEraseNChars (unsigned int nb_chars) +{ + int x, y; + + x = cell_w * (int)(cursor_x / cell_w); + y = cell_h * (int)(cursor_y / cell_h); + + fbui_fill_area (dpy, win, x, y, nb_chars*cell_w, cell_h, color[default_bgcolor]); +} + +void +fbtermEraseToEOL () +{ + int x, y; + + x = cell_w * (int)(cursor_x / cell_w); + y = cell_h * (int)(cursor_y / cell_h); + + fbui_fill_area (dpy, win, x, y, vis_w-x, cell_h, color[default_bgcolor]); +} + +void +fbtermEraseFromBOL () +{ + int x, y; + + x = cell_w * (int)(cursor_x / cell_w + 1); + y = cell_h * (int)(cursor_y / cell_h); + + fbui_fill_area (dpy, win, 0, y, x, cell_h, color[default_bgcolor]); +} + +void +fbtermEraseLine () +{ + int y; + + y = cell_h * (int)(cursor_y / cell_h); + + fbui_fill_area (dpy, win, 0, y, vis_w, cell_h, color[default_bgcolor]); +} + +void +fbtermEraseToEOD () +{ + int y; + + fbtermEraseToEOL (); + y = cell_h * (int)(cursor_y / cell_h + 1); + + fbui_fill_area (dpy, win, 0, y, vis_w, vis_h-y, color[default_bgcolor]); +} + +void +fbtermEraseFromBOD () +{ + int y; + + fbtermEraseFromBOL (); + y = cell_h * (int)(cursor_y / cell_h); + + fbui_fill_area (dpy, win, 0, 0, vis_w, y, color[default_bgcolor]); +} + +void +fbtermEraseDisplay () +{ + int i; + + fbui_fill_area (dpy, win, 0,0, + terminal_width*cell_w-1, + terminal_height*cell_h-1, + color [default_bgcolor]); + fbui_flush (dpy, win); + + int c = default_bgcolor; + int size = terminal_width * terminal_height; + for (i=0; i<size; i++) { + exposebuffer[i] = ' '; + exposebuffer_fg[i] = c; + exposebuffer_bg[i] = c; + } +} + +void +fbtermScrollUp (unsigned int nb_lines) +{ + debug (DEBUG_DETAIL, "Scrolling %d lines in region %d-%d", nb_lines, region_top, region_bottom); + +#if 0 + /* too slow due to video memory read speed */ + + fbui_copy_area (dpy, win, 0, (region_top+nb_lines)*cell_h, + 0, region_top*cell_h, + vis_w, (region_bottom-region_top-nb_lines)*cell_h); + int y = (region_bottom - nb_lines)*cell_h; + fbui_fill_area (dpy, win, 0, y, vis_w, vis_h, color[default_bgcolor]); +#endif + + scroll_exposebuf_up (nb_lines, region_top, region_bottom); + redraw(); +} + +void +fbtermScrollDown (unsigned int nb_lines) +{ + debug (DEBUG_DETAIL, "Scrolling %d lines in region %d-%d", nb_lines, region_top, region_bottom); +#if 0 + /* too slow due to video memory read speed */ + + fbui_copy_area (dpy, win, 0, region_top*cell_h, + 0, (region_top+nb_lines)*cell_h, + vis_w, (region_bottom-region_top-nb_lines)*cell_h); + int y = region_top*cell_h; + fbui_fill_area (dpy, win, 0, 0, vis_w, y-1, color[default_bgcolor]); +#endif + + scroll_exposebuf_down(); + redraw(); +} + +void +fbtermNextPos () +{ + MoveCursor (cursor_x + cell_w, cursor_y); +} + + +int +FBUIWriteChar (wchar_t charcode) +{ + int cur_bgcolor, cur_fgcolor, dummy_color; + + if (linewrap_pending) + { + MoveCursor (cursor_x0, cursor_y + cell_h); + } + cur_bgcolor = bgcolor; + cur_fgcolor = fgcolor; + if (altcharset_mode) + { + charcode = AsciiGetAltChar (charcode); + } + if (reverse_mode) + { + dummy_color = cur_bgcolor; + cur_bgcolor = cur_fgcolor; + cur_fgcolor = dummy_color; + } + if (invisible_mode) + { + cur_fgcolor = cur_bgcolor; + } + if (bold_mode) + { + cur_fgcolor += 8; + } + + fbui_fill_area (dpy, win, cursor_x, cursor_y, cursor_x + cell_w - 1, cursor_y + cell_h - 1, color[cur_bgcolor]); + char s[2] = { (char)charcode, 0 }; + + fbui_draw_string (dpy, win, NULL, cursor_x, cursor_y, s, color[cur_fgcolor]); + + /* Save to buffer for later expose */ + int i = cursor_x / cell_w; + int j = cursor_y / cell_h; + int ix = i + j * terminal_width; + int size = terminal_width * terminal_height; + if (ix < size) { + exposebuffer [ix] = charcode; + exposebuffer_fg [ix] = cur_fgcolor; + exposebuffer_bg [ix] = cur_bgcolor; + } + + if (underline_mode) { + fbui_draw_hline (dpy, win, cursor_x, cursor_x+cell_w-1, cursor_y+cell_h-1, + color[cur_fgcolor]); + fbui_flush (dpy, win); + } + + return 0; +} + + + +void +HandleFBUIEvents (unsigned char *shellinput, size_t *shellinput_size) +{ + struct timeval tv; + int i; + + tv.tv_sec = 0; + tv.tv_usec = 0; + + Event ev; + unsigned char event_num; + + usleep (3000); + if (fbui_poll_event (dpy, &ev, FBUI_EVENTMASK_ALL)) + return; + + event_num = ev.type; + + if (ev.win != win) { +printf ("event id = %d, window id %d\n", ev.id, win->id); + FATAL ("event not for fbterm window"); + } + + if (event_num == FBUI_EVENT_EXPOSE) { + redraw(); + } + else if (event_num == FBUI_EVENT_MOVE_RESIZE) { + vis_w = ev.width; + vis_h = ev.height; + int new_width = vis_w / cell_w; + int new_height = vis_h / cell_h; + resize (new_width, new_height); + + // update the OS + ws.ws_col = terminal_width; + ws.ws_row = terminal_height; + ws.ws_xpixel = vis_w; + ws.ws_ypixel = vis_h; + if (ioctl (master_fd, TIOCSWINSZ, &ws) < 0) { + WARNING("unable to set tty window size"); + } + } + else if (event_num == FBUI_EVENT_ENTER) { + printf ("fbterm got Enter\n"); + return; + } + else if (event_num == FBUI_EVENT_LEAVE) { + printf ("fbterm got Leave\n"); + return; + } + else if (event_num == FBUI_EVENT_ACCEL) { + // Not using accelerators + return; + } + else if (event_num == FBUI_EVENT_KEY) { + short ch = fbui_convert_key (dpy, ev.key); + if (!ch) + return; + + if (SHELLINPUT_SIZE - *shellinput_size >= (MB_CUR_MAX>3?MB_CUR_MAX:3)) + switch (ch) { + case '\n': + shellinput[*shellinput_size] = '\n'; + (*shellinput_size)++; + break; + + case 8: + case 9: + case FBUI_DEL: + shellinput[*shellinput_size] = 0x08; + (*shellinput_size)++; + break; + + default: + fbtermPutShellChar (shellinput, shellinput_size, ch); + break; + + case FBUI_F1: + memcpy (shellinput+*shellinput_size, "\033OP", 3); + (*shellinput_size) += 3; + break; + case FBUI_F2: + memcpy (shellinput+*shellinput_size, "\033OQ", 3); + (*shellinput_size) += 3; + break; + case FBUI_F3: + memcpy (shellinput+*shellinput_size, "\033OR", 3); + (*shellinput_size) += 3; + break; + case FBUI_F4: + memcpy (shellinput+*shellinput_size, "\033OS", 3); + (*shellinput_size) += 3; + break; + case FBUI_F5: + memcpy (shellinput+*shellinput_size, "\033Ot", 3); + (*shellinput_size) += 3; + break; + case FBUI_F6: + memcpy (shellinput+*shellinput_size, "\033Ou", 3); + (*shellinput_size) += 3; + break; + case FBUI_F7: + memcpy (shellinput+*shellinput_size, "\033Ov", 3); + (*shellinput_size) += 3; + break; + case FBUI_F8: + memcpy (shellinput+*shellinput_size, "\033Ol", 3); + (*shellinput_size) += 3; + break; + case FBUI_F9: + memcpy (shellinput+*shellinput_size, "\033Ow", 3); + (*shellinput_size) += 3; + break; + case FBUI_F10: + memcpy (shellinput+*shellinput_size, "\033Ox", 3); + (*shellinput_size) += 3; + break; + + case FBUI_UP: + memcpy (shellinput+*shellinput_size, "\033OA", 3); + (*shellinput_size) += 3; + break; + case FBUI_DOWN: + memcpy (shellinput+*shellinput_size, "\033OB", 3); + (*shellinput_size) += 3; + break; + case FBUI_LEFT: + memcpy (shellinput+*shellinput_size, "\033OD", 3); + (*shellinput_size) += 3; + break; + case FBUI_RIGHT: + memcpy (shellinput+*shellinput_size, "\033OC", 3); + (*shellinput_size) += 3; + break; + case FBUI_PGUP: + memcpy (shellinput+*shellinput_size, "\033Os", 3); + (*shellinput_size) += 3; + break; + case FBUI_PGDN: + memcpy (shellinput+*shellinput_size, "\033On", 3); + (*shellinput_size) += 3; + break; + case FBUI_INS: + memcpy (shellinput+*shellinput_size, "\033[L", 3); + (*shellinput_size) += 3; + break; + case FBUI_HOME: + memcpy (shellinput+*shellinput_size, "\033Oq", 3); + (*shellinput_size) += 3; + break; + case FBUI_END: + memcpy (shellinput+*shellinput_size, "\033Op", 3); + (*shellinput_size) += 3; + break; + } + } +} + + +void FBUIMapColors () +{ + int i; +} + +int +FBUIInit_graphicsmode (int vc,short cols,short rows,short xrel,short yrel) +{ + int err; + char dummy[64]; + long size = rows * cols; + + terminal_width = cols; + terminal_height = rows; + +printf ("cols=%d rows=%d\n",cols,rows); + + exposebuffer=(wchar_t*) malloc(size * sizeof(wchar_t)); + exposebuffer_fg=(char*) malloc(size); + exposebuffer_bg=(char*) malloc(size); + + font = font_new (); + if (!pcf_read (font, "courR14.pcf")) { + font_free (font); + FATAL ("cannot load font"); + } + + cell_h = font->ascent + font->descent; + + if (!cell_h) { + fbui_window_close (dpy, win); + printf ("oops, invalid font data\n"); + exit(1); + } + + cell_w = font->widths [' ' - font->first_char]; + + if (!cell_w) { + cell_w = font->widths ['W' - font->first_char]; + if (!cell_w) { + fbui_window_close (dpy, win); + printf ("oops, invalid font data\n"); + exit(1); + } + } + + int default_w = cell_w * cols; + int default_h = cell_h * rows; +printf ("fbterm: trying for window size %d,%d to provide %dx%d text\n", default_w, default_h, rows,cols); + + default_fgcolor = 7; + default_bgcolor = 0; + fgcolor = default_fgcolor; + bgcolor = default_bgcolor; + + int argc=1; + char *argv[1] = {"foo"}; + + if (xrel > 999) { + xrel = 2; + yrel = 15; + } + + short win_w, win_h; + + long fg; + long bg = color[default_bgcolor]; + + dpy = fbui_display_open (); + if (!dpy) + FATAL ("cannot open display"); + + win = fbui_window_open (dpy, default_w, default_h, + &win_w, &win_h, + 9999,9999, + 0, +20, + &fg, &bg, + "fbterm", "", + FBUI_PROGTYPE_APP, + false,false, + vc, + true, + false, + false, argc,argv); + if (!win) + FATAL ("cannot create window"); + + vis_w = win_w; + vis_h = win_h; + + if (win_w < 1 || win_h < 1) { + printf ("Don't have window dimensions yet.\n"); + } else { + printf ("Window dimensions %d,%d (%dx%d) text\n", + win_w,win_h,win_w/cell_w,win_h/cell_h); + } + + cursor_x0 = 0; + cursor_y0 = 0; + + if (fbui_set_font (dpy, win, font)) + FATAL ("cannot set font"); + + return 0; +} + + +#ifdef DEBUG +void ShowGrid (void) +{ + int x, y; + + ggiSetGCForeground (vis, color[2]); + for (x = 0; x < vis_w; x += cell_w) + { + ggiDrawVLine (vis, x, 0, vis_h); + } + for (y = 0; y < vis_h; y += cell_h) + { + ggiDrawHLine (vis, 0, y, vis_w); + } +} +#endif /* DEBUG */ + +void FBUIExit (void) +{ + fbui_window_close (dpy, win); + fbui_display_close (dpy); +} diff --git a/libfbui/Term/old-docs/AUTHORS b/libfbui/Term/old-docs/AUTHORS @@ -0,0 +1,37 @@ + + +From ggiterm: + +Main (and only) author: + Aurelien Reynaud (dedale1 at users dot sourceforge dot net) + + +First of all, thank you for taking interest in this project! + +I have been following the GGI/KGI effort for many years now with a strong interest, +as I see it as the (admittedly long term) ultimate future for console and graphics +subsystems in Unix-like OSes. +However, I never contributed any code to the core projects, mostly due to a lack of +time and ageing programming skills (which date back to my school years!). + +But the time had come to give back to the community more than 'thanks for the hard +work'. So I scratched my head and wondered what kind of useful piece of software I +could put together, which would both increase my programming skills to a level where +I can later consider contributing kernel code, and still help the GGI project as a +whole. + +A terminal application for GGI fits admirably into this scheme: +- GGI programming +- console subsystem +- use of the Freetype library +- i18n mysteries (conversion between character codes, unicode) +- GNU build tools (automake, autoconf, etc...) + +I decided to start from scratch, but used as a source of inspiration an already +existing project: nixterm, written by Andrew Apted. As of today, this project seems +to be abandoned (or considered done) by his author, but I nonetheless would like to +thank him here for the good work he did. + + + + Aurelien Reynaud, 06/26/2003 diff --git a/libfbui/Term/old-docs/ChangeLog b/libfbui/Term/old-docs/ChangeLog @@ -0,0 +1,110 @@ + +Oct 2004, plinius@comcast.net: conversion to fbui + + +------------------------------------------------- + +12/02/2003 - Version 0.6.2 released +The previous in-depth changes broke compilation on many architectures. This +version has been tested and builds on linux, freebsd, openbsd, macosx and +solaris. Hopefully it works for all of them... +- switched form mbrtowc/wcrtomb to mbtowc/wctomb +- added custom iswprint() for systems lacking it +- configure/build fixes for *bsd and macosx + +11/28/2003 - Version 0.6.1 released + +Heavily reworked code, but few user-visible changes. Default TERM value is now +"ggiterm" instead of "ansi", whose definition is not consistent across systems. +We are also vt100-compatible for systems where ggiterm definition cannot be added. +New features: +- i18n in input as well as output +- vt100 compatibility (according to the terminal definitions of supported systems) +Fixes: +- Solaris configure/build fixes +- Require freetype2 v2.0.9. Earlier versions didn't have FT_Get_First_Char() +- call ggiFlushRegion() after each character output. This shouldn't be necessary + but but it kills the longstanding "disappearing lines" bug with LibGGI > 2.0.1 +General: +- removed iconv dependancy. Now we use native libc multibyte handling + (--encoding option deprecated) +- use __func__ c99 facility to output errors and debugging messages +- use GGI asynchronous mode to speed up the X target + (alas nullified by too many calls to ggiFlushRegion()) +- control-sequences parser entirely rewritten +- added terminfo/termcap entries for ggiterm + + +10/30/2003 - Version 0.6 released + +Major new feature: colors! Includes also many bugfixes and improvements to the build system, +thanks to the feedback on the first users. +New features: +- invisible mode implemented +- bold mode implemented +- underline mode implemented +- colors implemented +- Tab stops implemented +- User strings u6 u7 u8 u9 implemented +- SHIFT-TAB mapped to ANSI BackTab key +Fixes: +- Better (but still not perfect) handling of modifier keys +- segfault when font is rejected and debuglevel is > 0 +- non destructive tabs, as requested by ANSI +- error at compilation when FT support not compiled in +- Fixed incorrect behaviour of Backspace. +- Freetype won't do aliasing if color depth <= 8 +- rounding error in cell size computing caused the last character's column + to be overwritten by the next char +- Now renders OK very small font sizes +- only send one ggi event at a time to the shell. Hopefully fixes the "hold down + the enter key" bug +Build system: +- Added minimalistic forkpty() replacement for when the system doesn't have it +- Removed remaining warnings caused by size_t != int +- cleanup of configure.in +- fixed typo in configure.in + Now ./configure --with-ggi-prefix=DIR behaves as expected + + +10/16/2003 - Bugfix version 0.5.1 released + +No new features added, but many bugfixes, both in code and build system. +Many thanks to Christoph Egger for his help and patience! +Fixes: +- More careful typing wrt size_t to avoid warnings +- Correct handling of Backspace (the bug appears when using tcsh, but bash doesn't care) +- fixed coredump on exit when no font specified +- compile error when freetype is not present on the system +Build system: +- ggiterm now uses autotools 1.7 +- libggi in nonstandard places is a configure option +- handle the case when forkpty() is in libc rather than in libutil (BSDs, OSX, ...) +- Modified Makefile.am to require freetype v2.1.4 when compiling on MacOS X + (the freetype build system is buggy on OSX for versions < 2.1.4) + + +10/10/2003 - Version 0.5 released + +Well, it's beginning to come along nicely... ggiterm is now quite useable. +- Most of the ANSI terminal capabilities have been implemented: cursor motions, +alternate charset, reverse video, area clearing, scrolling, insert/delete lines +and characters. +- Fixed width fonts are handled mostly correctly, with occasional minor graphic +glitches. Variables width fonts are another matter! +- Key repeat is supported +- All features are optional: freetype support, iconv support, debugging +- Terminal size is dynamic +- Font size is now an option +- The ugly green grid now only appears in debugging mode + + +06/26/2003 - Initial release + +This is just a proof of concept, barely useable. +- an ugly green grid, used to calibrate the fonts is still visible +- should work on the X target, but don't ask for more +- input doesn't recognize modifier keys +- displayed characters are supposed to be UTF-8 +- lots of debugging output +- slow diff --git a/libfbui/Term/old-docs/INSTALL b/libfbui/Term/old-docs/INSTALL @@ -0,0 +1,229 @@ +Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002 Free Software +Foundation, Inc. + + This file is free documentation; the Free Software Foundation gives +unlimited permission to copy, distribute and modify it. + +Basic Installation +================== + + These are generic installation instructions. + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, and a +file `config.log' containing compiler output (useful mainly for +debugging `configure'). + + It can also use an optional file (typically called `config.cache' +and enabled with `--cache-file=config.cache' or simply `-C') that saves +the results of its tests to speed up reconfiguring. (Caching is +disabled by default to prevent problems with accidental use of stale +cache files.) + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release. If you are using the cache, and at +some point `config.cache' contains results you don't want to keep, you +may remove or edit it. + + The file `configure.ac' (or `configure.in') is used to create +`configure' by a program called `autoconf'. You only need +`configure.ac' if you want to change it or regenerate `configure' using +a newer version of `autoconf'. + +The simplest way to compile this package is: + + 1. `cd' to the directory containing the package's source code and type + `./configure' to configure the package for your system. If you're + using `csh' on an old version of System V, you might need to type + `sh ./configure' instead to prevent `csh' from trying to execute + `configure' itself. + + Running `configure' takes awhile. While running, it prints some + messages telling which features it is checking for. + + 2. Type `make' to compile the package. + + 3. Optionally, type `make check' to run any self-tests that come with + the package. + + 4. Type `make install' to install the programs and any data files and + documentation. + + 5. You can remove the program binaries and object files from the + source code directory by typing `make clean'. To also remove the + files that `configure' created (so you can compile the package for + a different kind of computer), type `make distclean'. There is + also a `make maintainer-clean' target, but that is intended mainly + for the package's developers. If you use it, you may have to get + all sorts of other programs in order to regenerate files that came + with the distribution. + +Compilers and Options +===================== + + Some systems require unusual options for compilation or linking that +the `configure' script does not know about. Run `./configure --help' +for details on some of the pertinent environment variables. + + You can give `configure' initial values for configuration parameters +by setting variables in the command line or in the environment. Here +is an example: + + ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix + + *Note Defining Variables::, for more details. + +Compiling For Multiple Architectures +==================================== + + You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you must use a version of `make' that +supports the `VPATH' variable, such as GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. + + If you have to use a `make' that does not support the `VPATH' +variable, you have to compile the package for one architecture at a +time in the source code directory. After you have installed the +package for one architecture, use `make distclean' before reconfiguring +for another architecture. + +Installation Names +================== + + By default, `make install' will install the package's files in +`/usr/local/bin', `/usr/local/man', etc. You can specify an +installation prefix other than `/usr/local' by giving `configure' the +option `--prefix=PATH'. + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +give `configure' the option `--exec-prefix=PATH', the package will use +PATH as the prefix for installing programs and libraries. +Documentation and other data files will still use the regular prefix. + + In addition, if you use an unusual directory layout you can give +options like `--bindir=PATH' to specify different values for particular +kinds of files. Run `configure --help' for a list of the directories +you can set and what kinds of files go in them. + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + +Optional Features +================= + + Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + +Specifying the System Type +========================== + + There may be some features `configure' cannot figure out +automatically, but needs to determine by the type of machine the package +will run on. Usually, assuming the package is built to be run on the +_same_ architectures, `configure' can figure that out, but if it prints +a message saying it cannot guess the machine type, give it the +`--build=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name which has the form: + + CPU-COMPANY-SYSTEM + +where SYSTEM can have one of these forms: + + OS KERNEL-OS + + See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the machine type. + + If you are _building_ compiler tools for cross-compiling, you should +use the `--target=TYPE' option to select the type of system they will +produce code for. + + If you want to _use_ a cross compiler, that generates code for a +platform different from the build platform, you should specify the +"host" platform (i.e., that on which the generated programs will +eventually be run) with `--host=TYPE'. + +Sharing Defaults +================ + + If you want to set default values for `configure' scripts to share, +you can create a site shell script called `config.site' that gives +default values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Defining Variables +================== + + Variables not defined in a site shell script can be set in the +environment passed to `configure'. However, some packages may run +configure again during the build, and the customized values of these +variables may be lost. In order to avoid this problem, you should set +them in the `configure' command line, using `VAR=value'. For example: + + ./configure CC=/usr/local2/bin/gcc + +will cause the specified gcc to be used as the C compiler (unless it is +overridden in the site shell script). + +`configure' Invocation +====================== + + `configure' recognizes the following options to control how it +operates. + +`--help' +`-h' + Print a summary of the options to `configure', and exit. + +`--version' +`-V' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`--cache-file=FILE' + Enable the cache: use and save the results of the tests in FILE, + traditionally `config.cache'. FILE defaults to `/dev/null' to + disable caching. + +`--config-cache' +`-C' + Alias for `--cache-file=config.cache'. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. To + suppress all normal output, redirect it to `/dev/null' (any error + messages will still be shown). + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`configure' also accepts some other, not widely useful, options. Run +`configure --help' for more details. + diff --git a/libfbui/Term/old-docs/TODO b/libfbui/Term/old-docs/TODO @@ -0,0 +1,19 @@ + + +Code cleanup, speed improvements: +- use getopt() to parse command line options +- use freetype caching capabilities +- use directbuffers ? +- render strings instead of characters +- investigate the ggiFlush() "bug" + +User visible features: +- improve autogen.sh for use with autotools versions previous to 1.7 +- look into libtool for static/dynamic/mixed building +- add --default-term option +- add --execute option +- make it possible to use multiple/variable width fonts +- make complete and documented ggiterm.terminfo +- automate terminfo -> termcap (cf autogen.sh) +- test other color depths +- create man page diff --git a/libfbui/Term/old-docs/tmp b/libfbui/Term/old-docs/tmp diff --git a/libfbui/Test/COPYING b/libfbui/Test/COPYING @@ -0,0 +1,280 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS diff --git a/libfbui/Test/Makefile b/libfbui/Test/Makefile @@ -0,0 +1,15 @@ + +EXE=fbtest +SRC= main.c + +fbtest: ${SRC} + gcc -lm -I.. -g ${SRC} ../libfbui.a -o ${EXE} + # strip ${EXE} + +clean: + rm -f ${EXE} + +install: ${EXE} + cp ${EXE} /usr/bin + chmod 755 /usr/bin/${EXE} + diff --git a/libfbui/Test/main.c b/libfbui/Test/main.c @@ -0,0 +1,398 @@ + +/*========================================================================= + * + * fbtest, a test for FBUI (in-kernel framebuffer UI) + * Copyright (C) 2004 Zachary T Smith, fbui@comcast.net + * + * This module is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This module 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this module; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * (See the file COPYING in the main directory of this archive for + * more details.) + * + *=======================================================================*/ + + +typedef unsigned long u32; +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <sys/ioctl.h> +#include <linux/fb.h> +#include <sys/mman.h> +#include <unistd.h> +#include <string.h> + +#include <linux/vt.h> +#include <linux/input.h> + + +#include "libfbui.h" + + + + +void +random_rect_test(Display* dpy, Window *win) +{ + int i=0; + srand(1243+time(NULL)); + printf ("50000 random rectangles\n"); + while (i++ < 50000) + { + int x0 = rand(); + int y0 = rand(); + int x1 = rand(); + int y1= rand(); + x0 &= 2047; + x1 &= 2047; + y0 &= 2047; + y1 &= 2047; + x0 -= 800; + y0 -= 800; + x1 -= 800; + y1 -= 800; + fbui_draw_rect (dpy,win,x0,y0,x1,y1,rand()); + } +} + + + +int +main(int argc, char** argv) +{ + int i; + int vc=-1; + + Display *dpy; + Window *win; + Font *pcf = font_new (); + + if (!pcf_read (pcf, "timR12.pcf")) { + font_free (pcf); + pcf = NULL; + FATAL ("cannot load font"); + } + + short win_w, win_h; + long fg,bg; + bg=0x303030; + + dpy = fbui_display_open (); + if (!dpy) + FATAL ("cannot open display"); + + win = fbui_window_open (dpy, 300,200, &win_w, &win_h, 9999,9999, 370, 15, + &fg, &bg, "fbtest", "", + FBUI_PROGTYPE_APP, false,false, vc, + false, false,false, + argc,argv); + if (!win) + FATAL ("cannot create window"); + + int whichtest = argc >= 2 ? atoi(argv[1]) : 0; + + if (!whichtest || whichtest==1) + { + printf ("100000 lines\n"); + for (i=0;i<100000; i++) + { + short x0 = (rand() & 2047) - 800; + short y0 = (rand() & 2047) - 800; + short x1 = (rand() & 2047) - 800; + short y1 = (rand() & 2047) - 800; + fbui_draw_line (dpy, win, x0,y0,x1,y1,rand()); + } + } + + if (!whichtest || whichtest==2) + { + printf ("500000 hlines\n"); + int j; + for(j=0; j<1000; j++) + { + i=0; + unsigned long color=rand(); + while(i < 500) + { + int x1 = rand() % 800; + int x2 = rand() % 800; + int y = rand() % 600; + fbui_draw_hline (dpy, win, x1,x2,y,color); + i++; + } + fbui_flush (dpy, win); + i=0; + while(i < 500) + { + fbui_draw_hline (dpy, win, 0, i, i,color); + i++; + } + fbui_flush (dpy, win); + } + } + + + if (!whichtest || whichtest==3) + { + if(pcf) + { + fbui_draw_line(dpy, win, 0,0,799,599,RGB_RED); + fbui_draw_line(dpy, win, 799,0,0,599,RGB_RED); + + int n=0; + while(n<200) { + int y = 0; + + while (y<600) { +#define TESTSTR "01234 ? ABC_EFGHI ~` JKLMNOPQRSTItest m,yYqpaafgjklz<>?!@#$%^&*()~" + int rv = fbui_draw_string (dpy, win, pcf, + -100,y, TESTSTR, rand() & 0xffffff); + + y += pcf->ascent + pcf->descent; + } + n++; + } + } + if (pcf) font_free (pcf); + + } + + + if (!whichtest || whichtest==4) + { +printf ("rects\n"); + random_rect_test(dpy, win); + } + + if (!whichtest || whichtest==5) + { + printf ("10000 random filled rectangles\n"); + for (i=0; i<10000; i++) + { + fbui_fill_area (dpy,win, rand() % 1000,rand()%700,rand()%900,rand()%500, + rand()); + } + } + + if (!whichtest || whichtest==6) + { + fbui_fill_area (dpy, win, 0,0,799,599,RGB_ORANGE); + + static unsigned char drawthis[256*3]; + for (i=0; i<256; i++) { + drawthis[i*3] = i; + drawthis[i*3+1] = 255-i; + drawthis[i*3+2] = i/2; + } + + printf ("10000 256x16 put-native operations\n"); + + i=0; + while(i<10000) + { + int j=0; + short x = rand() % 800; + short y = rand() % 600; + while (j<16) { + int tmp = fbui_put (dpy, win, x,j+y,256, drawthis ); + if (tmp != FBUI_SUCCESS) { + fbui_window_close(dpy, win); + printf ("error %d from fbui_put\n", tmp); + exit(0); + } + j++; + } + i++; + } + } + + if (!whichtest || whichtest==7) + { + printf ("5000 fullscreen filled rectangles\n"); + for (i=0; i<5000; i++) + { + fbui_fill_area (dpy, win, -20,-20,1000,999,rand()); + } + } + + if (!whichtest || whichtest==8) + { + // draw 100,000 pixels + i=0; + while (i < 100000) + { + fbui_draw_point (dpy, win, i/2000,i&511, i & 0xff); + i++; + } + } + + if (!whichtest || whichtest==9) + { + fbui_fill_area (dpy, win, 0,0,398,298, RGB_RED); + fbui_fill_area (dpy, win, 400,0,799,298, RGB_GREEN); + fbui_fill_area (dpy, win, 0,300,398,599, RGB_BLUE); + fbui_fill_area (dpy, win, 400,300,799,599, RGB_YELLOW); + + printf ("10000 inverted lines\n"); + for (i=0;i<10000; i++) + { + short x0 = (rand() & 2047) - 800; + short y0 = (rand() & 2047) - 800; + short x1 = (rand() & 2047) - 800; + short y1 = (rand() & 2047) - 800; + + fbui_invert_line (dpy, win, x0,y0,x1,y1); + } + } + + if (!whichtest || whichtest==10) + { + unsigned long drawthis[256]; + for (i=0; i<256; i++) { + unsigned long value = i/2; + value <<= 8; + value |= 255-i; + value <<= 8; + value |= 192; + drawthis[i] = value; + } + + printf ("50000 256x16 put-rgb operations\n"); + + i=0; + while(i<50000) + { + int j=0; + int x = (rand() & 2047) - 800; + int y = (rand() & 2047) - 800; + while(j<16) { + fbui_put_rgb (dpy, win, x,y+j,256, drawthis ); + j++; + } + i++; + } + } + + if (!whichtest || whichtest==11) + { + fbui_draw_line (dpy, win, 0,0,799,599, RGB_BLUE); + fbui_draw_line (dpy, win, 799,0,0,599, RGB_GREEN); + + for (i=0; i<6; i++) + fbui_copy_area (dpy, win, 0,10,0,0,800,600); + } + + if (!whichtest || whichtest==12) + { + fbui_draw_line (dpy, win, 0,0,799,599, RGB_BLUE); + fbui_draw_line (dpy, win, 799,0,0,599, RGB_BLUE); + + for (i=0; i<6; i++) + fbui_copy_area (dpy, win, 0,0,0,10,800,800); + } + + if (!whichtest || whichtest==13) + { + fbui_draw_line (dpy, win, 0,0,799,599, RGB_YELLOW); + fbui_draw_line (dpy, win, 799,0,0,599, RGB_ORANGE); + + for (i=0; i<6; i++) + fbui_copy_area (dpy, win, 0,0,10,0,800,800); + } + + if (!whichtest || whichtest==14) + { + fbui_draw_line (dpy, win, 0,0,799,599, RGB_BLUE); + fbui_draw_line (dpy, win, 799,0,0,599, RGB_BLUE); + + for (i=0; i<6; i++) + fbui_copy_area (dpy, win, 10,0,0,0,800,800); + } + + if (!whichtest || whichtest==15) + { + static unsigned char drawthis[768]; + for (i=0; i<768; ) { + drawthis[i++] = i/6; + drawthis[i++] = 255-i/3; + drawthis[i++] = 0xff; + } + + printf ("50000 256x16 put-rgb operations\n"); + + i=0; + while(i<50000) + { + int j=0; + int x = (rand() & 2047) - 800; + int y = (rand() & 2047) - 800; + while(j<16) { + fbui_put_rgb3 (dpy, win, x,y+j,256, drawthis ); + j++; + } + i++; + } + } + + if (!whichtest || whichtest==16) + { + int j=256; + + printf ("vlines\n"); + +#if 1 + for (j=0; j<256; j++) { + i=0; + unsigned long color = (rand() & 0xffff00) | (j & 255); + while(i<5000) + { + fbui_draw_vline (dpy, win, i-1000,i-2000,i-1000,color); + i++; + } + fbui_flush (dpy, win); + } +#endif + fbui_clear (dpy, win); + fbui_flush (dpy, win); + for (j=0 ; j<640; j++) + { + double r; + int factor = j / 160; + i=0; + unsigned long color=rand(); + while(i<win_w) + { + r = i; + r /= win_w/4; + r *= 3.1415926536; + r *= factor; + r = sin(r); + int y = r*(win_h/2) + (win_h/2); + fbui_draw_vline (dpy, win, i, (j&1) ? 0 : win_h, y,color); + i++; + } + fbui_flush (dpy, win); + } + fbui_draw_vline (dpy, win, 100, 0, 100, RGB_WHITE); + fbui_draw_vline (dpy, win, 110, 100, 0, RGB_WHITE); + fbui_flush (dpy, win); + } + + fbui_window_close(dpy, win); + fbui_display_close (dpy); + + return 0; +} diff --git a/libfbui/ToDo/COPYING b/libfbui/ToDo/COPYING @@ -0,0 +1,280 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS diff --git a/libfbui/ToDo/Makefile b/libfbui/ToDo/Makefile @@ -0,0 +1,15 @@ + +EXE=fbtodo +SRC= main.c + +${EXE}: ${SRC} + gcc -I.. ${CFLAGS} ${SRC} -lm ../libfbui.a -g -o ${EXE} + strip ${EXE} + +clean: + rm -f ${EXE} + +install: ${EXE} + cp ${EXE} /usr/bin + chmod 755 /usr/bin/${EXE} + diff --git a/libfbui/ToDo/README b/libfbui/ToDo/README @@ -0,0 +1,4 @@ + +This program merely displays the contents of ~/.todo. +No editing. + diff --git a/libfbui/ToDo/main.c b/libfbui/ToDo/main.c @@ -0,0 +1,331 @@ + +/*========================================================================= + * + * fbtodo, a "To Do List" for FBUI (in-kernel framebuffer UI) + * Copyright (C) 2004 Zachary T Smith, fbui@comcast.net + * + * This module is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This module 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this module; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * (See the file COPYING in the main directory of this archive for + * more details.) + * + *=======================================================================*/ + + +/* Changes + * + */ + +#include <stdio.h> +#include <sys/param.h> +#include <time.h> +#include <unistd.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <string.h> + + +#include "libfbui.h" + + +Font *titlefont, *listfont; +short titlefontheight, listfontheight; + + +short total_items; +struct item { + char *s; + struct item *next; +}; +struct item *items; + +struct item *item_new(char *s) +{ + if (!s) return NULL; + + struct item *nu = (struct item*)malloc(sizeof(struct item)); + if (!nu) + FATAL("cannot allocate list item"); + + nu->next=NULL; + nu->s = strdup(s); + if (!nu->s) + FATAL("cannot allocate string for item"); + return nu; +} + +struct item *append_item (char *s) +{ + struct item *nu = item_new (s); + if (nu) { + struct item *i = items; + if (!i) { + items = nu; + } else { + while (i->next) + i = i->next; + i->next = nu; + } + ++total_items; + } + return nu; +} + +int readline (FILE *f, char *line) +{ + int ix=0; + short ch; + while (EOF != (ch = fgetc (f))) { + if (ch == '\r') + continue; + if (ch == '\n') + break; + line[ix++] = ch; + if (ix==249) break; + } + line[ix]=0; + if (!ix && ch == EOF) + return -1; + else + return ix; +} + + +int readfile (char *path) +{ + short ch; + char line[250]; + if (!path) + return 0; + FILE *f = fopen (path, "r"); + if (!f) + return 0; + + int count; + if (readline (f, line) < 1) + return 0; + + count = atoi (line); + + while(count--) { + if (-1 == readline (f, line)) + break; + + if (line[0]) + append_item (line); + } + + fclose (f); + return 1; +} + + +static short w = 200; +static short h = 200; + +int +main(int argc, char** argv) +{ + int i; + Display *dpy; + Window *win; + char path[MAXPATHLEN]; + struct stat st; + FILE *f; + int highlight_which = 0; + + total_items = 0; + items=NULL; + + strcpy (path, getenv ("HOME")); + strcat (path, "/.todo"); + i = stat (path, &st); + if (i) { + WARNING ("can't open ~/.todo; creating..."); + f = fopen (path, "w"); + fprintf (f, "4\n"); + fprintf (f, "Get lunch\n"); + fprintf (f, "GregPalast.org\n"); + fprintf (f, "VoteCobb.org\n"); + fprintf (f, "VotersUnite.org\n"); + fclose (f); + } + + f = fopen (path, "r"); + if (!f) + FATAL ("can't open ~/.todo"); + fclose (f); + + if (!readfile (path)) + FATAL ("error reading ~/.todo"); + + titlefont = font_new (); + listfont = font_new (); + if (!titlefont || !listfont) + FATAL ("cannot allocate Font"); + + if (!pcf_read (titlefont, "helvR12.pcf")) + FATAL ("cannot read Helv bold 12 point"); + if (!pcf_read (listfont, "timR10.pcf")) + FATAL ("cannot read Times 12 point"); + + short indent,a,d; + font_string_dims (listfont, "88. ", &indent, &a, &d); + + listfontheight = listfont->ascent + listfont->descent; + titlefontheight = titlefont->ascent + titlefont->descent; + + unsigned long titlecolor = RGB_RED; + unsigned long listcolor = RGB_BROWN; + unsigned long titlefontcolor = RGB_YELLOW; + unsigned long listfontcolor = RGB_ORANGE; + unsigned long sepcolor = RGB_WHITE; + unsigned long listhighlightcolor = RGB_LTBROWN; + + dpy = fbui_display_open (); + if (!dpy) + FATAL("cannot open display"); + + w = 150; + h = 150; + win = fbui_window_open (dpy, w,h, &w, &h, 9999,9999, 0, -1, + &listfontcolor, + &listcolor, + "fbtodo", "", + FBUI_PROGTYPE_TOOL, false,false, -1, + false, false,false, + argc,argv); + if (!win) + FATAL ("cannot create window"); + + short x, y; + + char done=0; + while(!done) { + char needdraw=0; + char fulldraw=0; + Event ev; + int err; + + if (err = fbui_wait_event (dpy, &ev, FBUI_EVENTMASK_ALL)) { + fbui_print_error (err); + continue; + } + + int type = ev.type; + Window *win2 = ev.win; +//printf ("fbtodo got event %s\n", fbui_get_event_name (ev.type)); + + if (win2 != win) + FATAL ("event's window is not ours"); + + switch(type) { + case FBUI_EVENT_MOTION: + x = ev.x; + y = ev.y; + if (y >= (titlefontheight + 1)) { + int which = (y - titlefontheight - 1) / listfontheight; + if (which > total_items) + which = total_items; + if (which != highlight_which) { + highlight_which = which; + needdraw = 1; + } + } + break; + + case FBUI_EVENT_EXPOSE: + needdraw=1; + fulldraw=1; + break; + + case FBUI_EVENT_ENTER: + break; + + case FBUI_EVENT_BUTTON: + if (x >= w-10 && y < 10 && (ev.key & FBUI_BUTTON_LEFT)) { + done=1; + continue; + } + break; + + case FBUI_EVENT_LEAVE: + if (highlight_which != -1) { + highlight_which = -1; + needdraw=1; + } + break; + case FBUI_EVENT_MOVE_RESIZE: + w = ev.width; + h = ev.height; + break; + } + + if (!needdraw) + continue; + + if (fulldraw) { + char title[200]; + sprintf (title, "To do: %d item%s\n", total_items, + total_items > 1 ? "s" : ""); + + short wid,a,d; + font_string_dims (titlefont, title, &wid,&a,&d); + short title_pos = (w - wid) / 2; + + fbui_fill_area (dpy, win, 0, 0, w-1, titlefontheight, titlecolor); + fbui_draw_hline (dpy, win, 0, w-1, titlefontheight, sepcolor); + fbui_draw_string (dpy, win, titlefont, title_pos, 0, + title, titlefontcolor); + } + + fbui_fill_area (dpy, win, 0, titlefontheight+1, w-1, h, listcolor); + +#if 0 + fbui_draw_line (dpy, win, w-10, 2, w-3, 9, RGB_WHITE); + fbui_draw_line (dpy, win, w-10, 9, w-3, 2, RGB_WHITE); +#endif + + struct item *im = items; + int ix=0; + while (im) { + char numstr[5]; + sprintf (numstr, "%d.", ix+1); + + short y = titlefontheight+1+ix*listfontheight; + + if (ix == highlight_which) + fbui_fill_area (dpy, win, 0, y, w, y + listfontheight, + listhighlightcolor); + + fbui_draw_string (dpy, win, listfont, + 0, titlefontheight+1+ix*listfontheight, + numstr, listfontcolor); + + fbui_draw_string (dpy, win, listfont, + indent, y, im->s, listfontcolor); + + im = im->next; + ix++; + } + + fbui_flush (dpy, win); + } + + fbui_window_close (dpy, win); + fbui_display_close (dpy); + return 0; +} diff --git a/libfbui/Viewer/497_1031_3.tif b/libfbui/Viewer/497_1031_3.tif Binary files differ. diff --git a/libfbui/Viewer/COPYING b/libfbui/Viewer/COPYING @@ -0,0 +1,280 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS diff --git a/libfbui/Viewer/Makefile b/libfbui/Viewer/Makefile @@ -0,0 +1,15 @@ + +EXE=fbview +SRC= main.c jpeg.c + +${EXE}: ${SRC} + gcc -Wall -lm -I.. -g ${SRC} ../libfbui.a -o ${EXE} -ljpeg -ltiff + # strip ${EXE} + +clean: + rm -f ${EXE} + +install: ${EXE} + cp ${EXE} /usr/bin + chmod 755 /usr/bin/${EXE} + diff --git a/libfbui/Viewer/README b/libfbui/Viewer/README @@ -0,0 +1,14 @@ + +IMAGE VIEWER FOR FBUI + +If you don't specify a geometry e.g. -geo500x500+10+10, fbview tries to take the +entire screen. + +Controls: + +Key Effect +--------- ---------------- +spacebar next image +q quit +g toggle grayscale + diff --git a/libfbui/Viewer/TODO b/libfbui/Viewer/TODO @@ -0,0 +1,11 @@ + +Need: + +* Slideshow capability. + +* Readers for PNMs, NEFs. + +* Need zoom and rotate functionality. + +* What can be done to speed up jpeglib reading? + diff --git a/libfbui/Viewer/h_opportunity_rock0113_02.jpg b/libfbui/Viewer/h_opportunity_rock0113_02.jpg Binary files differ. diff --git a/libfbui/Viewer/jpeg.c b/libfbui/Viewer/jpeg.c @@ -0,0 +1,187 @@ + +/* This file is just a simple modification of the jpeglib + * sample program. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + + +#include <jpeglib.h> + +#include <setjmp.h> + +#include "libfbui.h" + + +extern JSAMPLE * image_buffer; /* Points to large array of R,G,B-order data */ +extern int image_height; /* Number of rows in image */ +extern int image_width; /* Number of columns in image */ +extern int image_ncomponents; + +static int y=0; + +extern unsigned char *get_buffer (unsigned long size); + +int put_scanline_someplace(JSAMPLE* data, int width) +{ + if (!image_buffer) { +printf ("image_width=%d image_height=%d\n", image_width,image_height); + image_buffer = get_buffer (image_width *image_height*3); + if (!image_buffer) + FATAL ("failed to malloc image buffer"); + } + + if (y >= image_height) + return 1; + if (width >= 3*image_width) + width = 3 * image_width; + + unsigned char *tmp = (unsigned char*) data; + unsigned char *tmp2 = (unsigned char*) image_buffer; + tmp2 = &tmp2 [3 * y * image_width]; + memcpy (tmp2,tmp,width); + y++; + return 1; +} + + + +struct my_error_mgr { + struct jpeg_error_mgr pub; /* "public" fields */ + + jmp_buf setjmp_buffer; /* for return to caller */ +}; + +typedef struct my_error_mgr * my_error_ptr; + +METHODDEF(void) +my_error_exit (j_common_ptr cinfo) +{ + my_error_ptr myerr = (my_error_ptr) cinfo->err; + + (*cinfo->err->output_message) (cinfo); + + longjmp(myerr->setjmp_buffer, 1); +} + +GLOBAL(int) +read_JPEG_file (char * filename) +{ + struct jpeg_decompress_struct cinfo; + struct my_error_mgr jerr; + FILE * infile; /* source file */ + JSAMPARRAY buffer; /* Output row buffer */ + int row_stride; /* physical row width in output buffer */ + +y=0; + + if ((infile = fopen(filename, "rb")) == NULL) { + fprintf(stderr, "can't open %s\n", filename); + return 0; + } + + /* Step 1: allocate and initialize JPEG decompression object */ + + /* We set up the normal JPEG error routines, then override error_exit. */ + cinfo.err = jpeg_std_error(&jerr.pub); + jerr.pub.error_exit = my_error_exit; + /* Establish the setjmp return context for my_error_exit to use. */ + if (setjmp(jerr.setjmp_buffer)) { + /* If we get here, the JPEG code has signaled an error. + * We need to clean up the JPEG object, close the input file, and return. + */ + jpeg_destroy_decompress(&cinfo); + fclose(infile); + return 0; + } + /* Now we can initialize the JPEG decompression object. */ + jpeg_create_decompress(&cinfo); + + /* Step 2: specify data source (eg, a file) */ + + jpeg_stdio_src(&cinfo, infile); + + /* Step 3: read file parameters with jpeg_read_header() */ + + (void) jpeg_read_header(&cinfo, TRUE); + /* We can ignore the return value from jpeg_read_header since + * (a) suspension is not possible with the stdio data source, and + * (b) we passed TRUE to reject a tables-only JPEG file as an error. + * See libjpeg.doc for more info. + */ + + /* Step 4: set parameters for decompression */ + + /* In this example, we don't need to change any of the defaults set by + * jpeg_read_header(), so we do nothing here. + */ + + /* Step 5: Start decompressor */ + + (void) jpeg_start_decompress(&cinfo); + /* We can ignore the return value since suspension is not possible + * with the stdio data source. + */ + + /* We may need to do some setup of our own at this point before reading + * the data. After jpeg_start_decompress() we have the correct scaled + * output image dimensions available, as well as the output colormap + * if we asked for color quantization. + * In this example, we need to make an output work buffer of the right size. + */ + /* JSAMPLEs per row in output buffer */ + + image_height = cinfo.output_height; + image_width = cinfo.output_width; + row_stride = cinfo.output_width * cinfo.output_components; + image_ncomponents = cinfo.output_components; + + /* Make a one-row-high sample array that will go away when done with image */ + buffer = (*cinfo.mem->alloc_sarray) + ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1); + + /* Step 6: while (scan lines remain to be read) */ + /* jpeg_read_scanlines(...); */ + + /* Here we use the library's state variable cinfo.output_scanline as the + * loop counter, so that we don't have to keep track ourselves. + */ + while (cinfo.output_scanline < cinfo.output_height) { + /* jpeg_read_scanlines expects an array of pointers to scanlines. + * Here the array is only one element long, but you could ask for + * more than one scanline at a time if that's more convenient. + */ + (void) jpeg_read_scanlines(&cinfo, buffer, 1); + /* Assume put_scanline_someplace wants a pointer and sample count. */ + put_scanline_someplace(buffer[0], row_stride); + } + + /* Step 7: Finish decompression */ + + (void) jpeg_finish_decompress(&cinfo); + /* We can ignore the return value since suspension is not possible + * with the stdio data source. + */ + + /* Step 8: Release JPEG decompression object */ + + /* This is an important step since it will release a good deal of memory. */ + jpeg_destroy_decompress(&cinfo); + + /* After finish_decompress, we can close the input file. + * Here we postpone it until after no more JPEG errors are possible, + * so as to simplify the setjmp error logic above. (Actually, I don't + * think that jpeg_destroy can do an error exit, but why assume anything...) + */ + fclose(infile); + + /* At this point you may want to check to see whether any corrupt-data + * warnings occurred (test whether jerr.pub.num_warnings is nonzero). + */ + + /* And we're done! */ + return 1; +} + diff --git a/libfbui/Viewer/main.c b/libfbui/Viewer/main.c @@ -0,0 +1,746 @@ + +/*========================================================================= + * + * fbview, an image viewer for FBUI (in-kernel framebuffer UI) + * Copyright (C) 2004 Zachary T Smith, fbui@comcast.net + * + * This module is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This module 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this module; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * (See the file COPYING in the main directory of this archive for + * more details.) + * + *=======================================================================*/ + + +/* Changes + * + * Sept 26, 2004: Updated for grayscale images. + * Dec 18, 2004: Updated for TIFFs. + * Jan 11, 2004: Fixed memory allocation bugs. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <time.h> +#include <unistd.h> +#include <math.h> +#include <string.h> + +#include "libfbui.h" + +#include <jpeglib.h> +#include <tiffio.h> + + +typedef struct item { + struct item *next; + char *str; +} Item; + + + +static unsigned char *buffer = NULL; +static unsigned long buflen=0; + +unsigned char *get_buffer (unsigned long size) +{ + if (!buffer) { + buffer = (JSAMPLE*) malloc (size); + if (!buffer) + FATAL ("failed to malloc image buffer\n"); + + buflen = size; + return buffer; + } + else + { + if (size < buflen) + return buffer; + else { + buffer = realloc (buffer, size); + return buffer; + } + } +} + + +static Item *file_list = NULL; + +void append_item (char *str) +{ + Item *nu = (Item*)malloc(sizeof(Item)); + memset ((void*)nu,0,sizeof(Item)); + nu->str = strdup (str); + + Item *last=NULL; + last=file_list; + while(last) { + if (last->next) + last = last->next; + else + break; + } + if (!last) + file_list = nu; + else + last->next = nu; +} + +char *nth_item (int n) +{ + Item *item= file_list; + + while (n--) { + if (item) + item = item->next; + if (!item) + break; + } + + return item? item->str : NULL; +} + + +Font *pcf; +int target_w, target_h; +int available_height, text_height; + +typedef struct +{ + int dx, dy; + int e; + int j; + int sum; +} +BresenhamInfo; + +void +bresenham_init (BresenhamInfo *bi, int target_size, int original_size) +{ + if (!bi) + FATAL("null ptr param"); + if (!target_size || !original_size) + FATAL("zero numeric param"); + if (target_size > original_size) + FATAL("expansion requested"); + + bi->dx = original_size; + bi->dy = target_size; + bi->e = (bi->dy<<1) - bi->dx; + bi->j = 0; + bi->sum = 0; // diag +} + + +int +bresenham_get (BresenhamInfo *bi) +{ + char done = 0; + + if (!bi) + FATAL("null ptr param"); + + done = false; + + int initial_j = bi->j; + + while (bi->j <= bi->dx && !done) + { + if (bi->e >= 0) + { + done = true; + bi->e -= (bi->dx<<1); + } + bi->e += (bi->dy<<1); + ++bi->j; + } + + int count = bi->j - initial_j; + bi->sum += count; + if (bi->sum > bi->dx) + { + int *i=0; + *i++; + } + return count; +} + + +JSAMPLE * image_buffer; +unsigned long *image_buffer_long; +unsigned char *shrunken_image_buffer; +int image_height; +int image_width; +int image_ncomponents; +int image_orig_width, image_orig_height; + +static int grayscale=0; + +static int fileNum = 0; +static char *path = NULL; + +extern int read_JPEG_file (char*); + +static unsigned char bres_x_ary [3000]; +static unsigned char bres_y_ary [3000]; + +static short win_w, win_h; +static char do_shrink=0; + +void shrink_image (short target_w, short target_h); + +void +rescale() +{ +printf ("fbview: entered rescale()\n"); + do_shrink=0; + target_w = image_width; + target_h = image_height > available_height ? available_height : image_height; + + if (win_w < image_width || available_height < image_height) + { + do_shrink = 1; + + double ratio = 0; + if (win_w < image_width) { + ratio = win_w / (double) image_width; + } + if (available_height < image_height) { + double r = available_height / (double) image_height; + if (ratio == 0 || r < ratio) + ratio = r; + } + target_w = image_width * ratio; + target_h = image_height * ratio; + } + + if (do_shrink) { + shrink_image (target_w, target_h); + image_width = target_w; + image_height= target_h; + do_shrink = 0; + image_ncomponents = 3; + } +} + +int +readnext (Display *dpy, Window *win) +{ + path=NULL; + int result=0; + + while (!result) { + image_width=0; + image_height=0; + image_ncomponents=0; + + path = nth_item (fileNum++); + if (!path) + break; + + if (image_buffer) { + image_buffer = NULL; + } + if (image_buffer_long) { + image_buffer_long = NULL; + } + if (shrunken_image_buffer) { + shrunken_image_buffer = NULL; + } + + char *extension = path; + char *s = NULL; + while ((s = strchr (extension, '.'))) { + extension = s; + if (strchr (s+1, '.')) { + extension = s+1; + } else + break; + } + if (extension == path) { + fprintf (stderr, "fbview: invalid filename %s\n", path); + continue; + } + + if (!strcmp (extension, ".jpg") || + !strcmp (extension, ".JPG") || + !strcmp (extension, ".jpeg") || + !strcmp (extension, ".JPEG")) + { + result = read_JPEG_file (path); + if (result) { + printf ("JPEG information: %s, width %d height %d depth %d\n", + path,image_width,image_height,image_ncomponents*8); + if (image_ncomponents != 3 && image_ncomponents != 1) + result=0; + image_buffer_long = NULL; + image_orig_width = image_width; + image_orig_height = image_height; + } + + } + else + if (!strcmp (extension, ".tif") || + !strcmp (extension, ".TIF") || + !strcmp (extension, ".tiff") || + !strcmp (extension, ".TIFF")) + { + TIFF *tiff = TIFFOpen (path, "r"); + if (tiff) { + unsigned long w, h; + unsigned short d, samples; + char ok = 1; + + if (!TIFFGetField (tiff, TIFFTAG_IMAGEWIDTH, &w)) + ok = 0; + if (!TIFFGetField (tiff, TIFFTAG_IMAGELENGTH, &h)) + ok = 0; + if (!TIFFGetField (tiff, TIFFTAG_BITSPERSAMPLE, &d)) + ok = 0; + if (TIFFGetField (tiff, TIFFTAG_SAMPLESPERPIXEL, &samples)) + d *= samples; + + if (!ok) { + TIFFClose (tiff); + fprintf (stderr, "TIFF %s: missing dimensions or depth\n", path); + continue; + } + + printf ("TIFF information: %s, width %lu height %lu depth %u\n", + path, w,h,d); + + image_width = w; + image_height = h; + image_orig_width = image_width; + image_orig_height = image_height; + image_ncomponents = d / 8; // RGBA + + image_buffer_long = (unsigned long*) get_buffer (w * h * 4); + if (!image_buffer_long) { + TIFFClose (tiff); + FATAL ("out of memory"); + } + + if (!TIFFReadRGBAImage (tiff, w, h, image_buffer_long, 1)) { + TIFFClose (tiff); + fprintf (stderr, "fbview: error reading %s\n", path); + } + + image_buffer = NULL; + + TIFFClose (tiff); + result = 1; + } + else + result = 0; + } + else + if (!strcmp (extension, ".nef") || + !strcmp (extension, ".NEF")) + { + fprintf (stderr, "fbview: not supporting raw images yet: %s\n", path); + continue; + } + else + { + fprintf (stderr, "fbview: unsupported image extension in %s\n", path); + continue; + } + } + + if (!path) + return 0; + + if (result) + fbui_set_subtitle (dpy, win, path); + + rescale(); + + return 1; +} + + +void printloading (Display *dpy, Window *win) +{ + fbui_draw_string (dpy, win, pcf, 10, 10, "Loading...", RGB_WHITE); + fbui_flush (dpy, win); +} + + +void shrink_image (short target_w, short target_h) +{ + BresenhamInfo b; + + image_width = image_orig_width; + image_height = image_orig_height; + + bresenham_init (&b, target_w, image_width); + int n=0, i, j, inc; + for (i=0; i<image_width; i+=inc) { + inc = bres_x_ary[n++] = bresenham_get(&b); + } + bresenham_init (&b, target_h, image_height); + n=0; + for (i=0; i<image_height; i+=inc) { + inc = bres_y_ary[n++] = bresenham_get(&b); + } + + shrunken_image_buffer = malloc (target_w * target_h * 3); + if (!shrunken_image_buffer) + FATAL("out of memory"); + + /* shrink */ + int yinc = 0; + int x, y; + for (y=0, j=0; j<image_height; j+=yinc, y++) + { + yinc = bres_y_ary [y]; + + int xinc = 0; + + for(x=0, i=0; i<image_width; i+=xinc, x++) + { + xinc = bres_x_ary [x]; + + unsigned long r,g,b; + r=g=b=0; + + /* collect a pixel average */ + int k,l; + for (k=0; k<xinc; k++) { + for (l=0; l<yinc; l++) { + unsigned char *p = NULL; + unsigned long *p2 = NULL; + + if (image_buffer) { + p = image_buffer + image_ncomponents * (i+k + (j+l)*image_width); + unsigned char pix=0; + if (image_ncomponents == 1) { + pix = *p; + r += pix; + g += pix; + b += pix; + } else { + /* 3 */ + r += *p++; + g += *p++; + b += *p; + } + } + else if (image_buffer_long) { + // TIFFs are upside down + int yy = j + l; + if (yy >= image_height-1) + yy = image_height-1; + + yy = (image_height-1) - yy; + + p2 = image_buffer_long + i+k + yy*image_width; + + unsigned long pix = *p2; + unsigned long r0, g0, b0; + register unsigned long m; + b0 = pix >> 16; + g0 = pix >> 8; + r0 = pix; + m = 0xff; + r0 &= m; + b0 &= m; + g0 &= m; + r += r0; + g += g0; + b += b0; + } + } + } + short factor = xinc * yinc; + r /= factor; + g /= factor; + b /= factor; + + unsigned long ix = 3 * (x + y * target_w); + + if (grayscale) { + short n = (r + g + b) / 3; + r = g = b = n; + } + + shrunken_image_buffer [ix++] = r; + shrunken_image_buffer [ix++] = g; + shrunken_image_buffer [ix] = b; + } + } +} + + +int +main(int argc, char** argv) +{ + int i,j; + Display *dpy; + Window *win; + char this_image_shrunken = 0; + + path=NULL; + image_buffer=NULL; + image_buffer_long=NULL; + image_height=0; + image_width=0; + shrunken_image_buffer = NULL; + + if (argc==1) + return 0; + + pcf = font_new (); + + if (!pcf_read (pcf, "timR12.pcf")) { + font_free (pcf); + pcf = NULL; + FATAL ("cannot load font"); + } + + text_height = pcf->ascent + pcf->descent; + +/* XX + * To fix: If only one image file, we should open + * with dimensions of that file, plus room for text + */ + long fg,bg; + fg = RGB_NOCOLOR; + bg = RGB_BLACK; + + dpy = fbui_display_open (); + if (!dpy) + FATAL ("cannot open display"); + + /* get the maximal window */ + image_width=dpy->width-1; + image_height=dpy->height-1; + + win = fbui_window_open (dpy, image_width, image_height + 5 + text_height, + &win_w, &win_h, + 9999,9999, // max wid/ht + 0, 0, + &fg, &bg, + "fbview", "", + FBUI_PROGTYPE_APP, + false, // not requesting control + false, // therefore not autoplacing anything + -1, + true, // need keys + false, // not all motion + false, // not hidden + argc,argv); + if (!win) + FATAL ("cannot create window"); + + /* Parse file list */ + i=1; + while (i<argc) { + char ch = *argv[i]; + /* params used by FBUI lib will be truncated to zero length */ + if (ch && ch != '-') { + printf ("param '%s'\n", argv[i]); + append_item (argv[i]); + } + i++; + } + + fileNum = 0; + + available_height = win_h - 5 - text_height; + + printloading (dpy, win); + + int result = readnext (dpy,win); + + if (!result) { + fbui_display_close (dpy); + exit(0); + } + + fbui_clear (dpy, win); + fbui_flush (dpy, win); + + /* event loop */ + char done=0; + while(!done) { + Event ev; + int err; + if ((err = fbui_wait_event (dpy, &ev, FBUI_EVENTMASK_ALL))) { + fbui_print_error (err); + continue; + } +printf ("%s got event %s\n", argv[0], fbui_get_event_name (ev.type)); + + int num = ev.type; + + if (ev.win != win) + FATAL ("got event for another window"); + + switch (num) { + case FBUI_EVENT_MOVE_RESIZE: +printf ("fbview got MR: %d %d\n", win_w, win_h); + if (win_w == ev.width && win_h && ev.height) + continue; + win_w = ev.width; + win_h = ev.height; + available_height = win_h - 5 - text_height; + if (image_buffer) + rescale (); + break; + + case FBUI_EVENT_ENTER: + printf ("fbview got Enter\n"); + continue; + + case FBUI_EVENT_LEAVE: + printf ("fbview got Leave\n"); + continue; + + case FBUI_EVENT_MOTION: { + short x, y; + + x = ev.x; + y = ev.y; + + /* not used */ + continue; + } + + case FBUI_EVENT_KEY: { + short ch = fbui_convert_key (dpy, ev.key); + +#if 0 + if (ch) + printf ("viewer got key '%c' (0x%02x)\n", ch,ch); +#endif + + if (ch == 'q' || ch == 'Q') { + done=1; + continue; + } + else if (ch == 'g' || ch == 'G') { + grayscale = !grayscale; + } + else + if (ch == ' ') { + if (this_image_shrunken) + free (shrunken_image_buffer); + + shrunken_image_buffer = NULL; + this_image_shrunken = 0; + + fbui_clear (dpy, win); + printloading (dpy, win); + + int result= readnext (dpy,win); + + if (!result) { + fbui_window_close (dpy, win); + exit(0); + } + } + else + continue; + } + + case FBUI_EVENT_EXPOSE: + break; + + default: + continue; + } + + char expr [100]; + char *tmp = path; + char *tmp2; + while ((tmp2 = strchr(tmp, '/'))) { + tmp = tmp2 + 1; + } + sprintf (expr, "%s (%d x %d, depth %d)", tmp, + image_orig_width, image_orig_height, + image_ncomponents * 8); + short w,a,d; + font_string_dims (pcf, expr, &w,&a,&d); + fbui_clear_area (dpy, win, 0, target_h+5, w, target_h+5 + text_height); + fbui_draw_string (dpy, win, pcf, 0, target_h + 5, expr, RGB_WHITE); + + for (j=0; j<image_height; j++) { + if (image_ncomponents == 1 || grayscale) { + for(i=0; i<image_width; i++) { + unsigned long pix=0; + unsigned char *p = NULL; + unsigned long *p2 = NULL; + + if (shrunken_image_buffer) { + p = shrunken_image_buffer + image_ncomponents*(i + j*image_width); + pix = *p++; + pix += *p++; + pix += *p; + pix /= 3; + pix |= (pix<<8) | (pix<<16); + } + else if (image_buffer) { + p = image_buffer + image_ncomponents*(i + j*image_width); + /* pixels are grayscale */ + if (image_ncomponents == 1) { + pix = *p; + pix <<= 8; + pix |= *p; + pix <<= 8; + pix |= *p; + } else { + pix = *p++; + pix += *p++; + pix += *p; + pix /= 3; + pix |= (pix<<8) | (pix<<16); + } + } + else if (image_buffer_long) { + int yy = (image_height-1) - j; + p2= image_buffer_long + i + yy*image_width; + pix = *p2; + } + + fbui_draw_point (dpy, win, i, j, pix); + } + } + else + { + if (shrunken_image_buffer) + fbui_put_rgb3 (dpy, win, 0, j, image_width, + shrunken_image_buffer + 3*j*image_width); + else if (image_buffer) + fbui_put_rgb3 (dpy, win, 0, j, image_width, + image_buffer + 3*j*image_width); + else if (image_buffer_long) + fbui_put_rgb (dpy, win, 0, j, image_width, + image_buffer_long + 4*j*image_width); + } + } + + fbui_flush (dpy, win); + } /* while */ + + fbui_flush (dpy, win); + fbui_window_close (dpy, win); + fbui_display_close (dpy); + + if (buffer) + free (buffer); + return 0; +} diff --git a/libfbui/Viewer/meander.jpg b/libfbui/Viewer/meander.jpg Binary files differ. diff --git a/libfbui/WindowManager/COPYING b/libfbui/WindowManager/COPYING @@ -0,0 +1,280 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS diff --git a/libfbui/WindowManager/Makefile b/libfbui/WindowManager/Makefile @@ -0,0 +1,15 @@ + +EXE=fbwm +SRC= main.c jpeg.c rect.c + +test: ${SRC} + gcc -lm -ljpeg -I.. -g ${SRC} ../libfbui.a -o ${EXE} + # strip ${EXE} + +clean: + rm -f ${EXE} + +install: ${EXE} + cp ${EXE} /usr/bin + chmod 755 /usr/bin/${EXE} + diff --git a/libfbui/WindowManager/README b/libfbui/WindowManager/README @@ -0,0 +1,5 @@ + +Moving and resizing of windows not supported yet. + +To exit -- killing all windows -- use Alt-Backspace. + diff --git a/libfbui/WindowManager/jpeg.c b/libfbui/WindowManager/jpeg.c @@ -0,0 +1,318 @@ + +/* + * example.c + * + * This file illustrates how to use the IJG code as a subroutine library + * to read or write JPEG image files. You should look at this code in + * conjunction with the documentation file libjpeg.doc. + * + * This code will not do anything useful as-is, but it may be helpful as a + * skeleton for constructing routines that call the JPEG library. + * + * We present these routines in the same coding style used in the JPEG code + * (ANSI function definitions, etc); but you are of course free to code your + * routines in a different style if you prefer. + */ + +#include <stdio.h> + +/* + * Include file for users of JPEG library. + * You will need to have included system headers that define at least + * the typedefs FILE and size_t before you can include jpeglib.h. + * (stdio.h is sufficient on ANSI-conforming systems.) + * You may also wish to include "jerror.h". + */ + +#include <jpeglib.h> + +/* + * <setjmp.h> is used for the optional error recovery mechanism shown in + * the second part of the example. + */ + +#include <setjmp.h> + +/******************** JPEG COMPRESSION SAMPLE INTERFACE *******************/ + +/* This half of the example shows how to feed data into the JPEG compressor. + * We present a minimal version that does not worry about refinements such + * as error recovery (the JPEG code will just exit() if it gets an error). + */ + +/* + * IMAGE DATA FORMATS: + * + * The standard input image format is a rectangular array of pixels, with + * each pixel having the same number of "component" values (color channels). + * Each pixel row is an array of JSAMPLEs (which typically are unsigned chars). + * If you are working with color data, then the color values for each pixel + * must be adjacent in the row; for example, R,G,B,R,G,B,R,G,B,... for 24-bit + * RGB color. + * + * For this example, we'll assume that this data structure matches the way + * our application has stored the image in memory, so we can just pass a + * pointer to our image buffer. In particular, let's say that the image is + * RGB color and is described by: + */ + +extern JSAMPLE * image_buffer; /* Points to large array of R,G,B-order data */ +extern int image_height; /* Number of rows in image */ +extern int image_width; /* Number of columns in image */ +extern int image_ncomponents; + +static int y=0; +int put_scanline_someplace(JSAMPLE* data, int width) +{ + if (!image_buffer) { + image_buffer = (JSAMPLE*) malloc (width * image_height * 3); + if (!image_buffer) { + printf ("failed to malloc image buffer\n"); + exit(2); + } + } + + int i = width; + unsigned char *tmp = (unsigned char*) data; + unsigned char *tmp2 = (unsigned char*) (image_buffer + y*width); + memcpy (tmp2,tmp,width); + y++; +} + + +/* + * Sample routine for JPEG compression. We assume that the target file name + * and a compression quality factor are passed in. + */ + + +/******************** JPEG DECOMPRESSION SAMPLE INTERFACE *******************/ + +/* This half of the example shows how to read data from the JPEG decompressor. + * It's a bit more refined than the above, in that we show: + * (a) how to modify the JPEG library's standard error-reporting behavior; + * (b) how to allocate workspace using the library's memory manager. + * + * Just to make this example a little different from the first one, we'll + * assume that we do not intend to put the whole image into an in-memory + * buffer, but to send it line-by-line someplace else. We need a one- + * scanline-high JSAMPLE array as a work buffer, and we will let the JPEG + * memory manager allocate it for us. This approach is actually quite useful + * because we don't need to remember to deallocate the buffer separately: it + * will go away automatically when the JPEG object is cleaned up. + */ + +/* + * ERROR HANDLING: + * + * The JPEG library's standard error handler (jerror.c) is divided into + * several "methods" which you can override individually. This lets you + * adjust the behavior without duplicating a lot of code, which you might + * have to update with each future release. + * + * Our example here shows how to override the "error_exit" method so that + * control is returned to the library's caller when a fatal error occurs, + * rather than calling exit() as the standard error_exit method does. + * + * We use C's setjmp/longjmp facility to return control. This means that the + * routine which calls the JPEG library must first execute a setjmp() call to + * establish the return point. We want the replacement error_exit to do a + * longjmp(). But we need to make the setjmp buffer accessible to the + * error_exit routine. To do this, we make a private extension of the + * standard JPEG error handler object. (If we were using C++, we'd say we + * were making a subclass of the regular error handler.) + * + * Here's the extended error handler struct: + */ + +struct my_error_mgr { + struct jpeg_error_mgr pub; /* "public" fields */ + + jmp_buf setjmp_buffer; /* for return to caller */ +}; + +typedef struct my_error_mgr * my_error_ptr; + +/* + * Here's the routine that will replace the standard error_exit method: + */ + +METHODDEF(void) +my_error_exit (j_common_ptr cinfo) +{ + /* cinfo->err really points to a my_error_mgr struct, so coerce pointer */ + my_error_ptr myerr = (my_error_ptr) cinfo->err; + + /* Always display the message. */ + /* We could postpone this until after returning, if we chose. */ + (*cinfo->err->output_message) (cinfo); + + /* Return control to the setjmp point */ + longjmp(myerr->setjmp_buffer, 1); +} + +/* + * Sample routine for JPEG decompression. We assume that the source file name + * is passed in. We want to return 1 on success, 0 on error. + */ + +GLOBAL(int) +read_JPEG_file (char * filename) +{ + /* This struct contains the JPEG decompression parameters and pointers to + * working space (which is allocated as needed by the JPEG library). + */ + struct jpeg_decompress_struct cinfo; + /* We use our private extension JPEG error handler. + * Note that this struct must live as long as the main JPEG parameter + * struct, to avoid dangling-pointer problems. + */ + struct my_error_mgr jerr; + /* More stuff */ + FILE * infile; /* source file */ + JSAMPARRAY buffer; /* Output row buffer */ + int row_stride; /* physical row width in output buffer */ + + /* In this example we want to open the input file before doing anything else, + * so that the setjmp() error recovery below can assume the file is open. + * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that + * requires it in order to read binary files. + */ + + if ((infile = fopen(filename, "rb")) == NULL) { + fprintf(stderr, "can't open %s\n", filename); + return 0; + } + + /* Step 1: allocate and initialize JPEG decompression object */ + + /* We set up the normal JPEG error routines, then override error_exit. */ + cinfo.err = jpeg_std_error(&jerr.pub); + jerr.pub.error_exit = my_error_exit; + /* Establish the setjmp return context for my_error_exit to use. */ + if (setjmp(jerr.setjmp_buffer)) { + /* If we get here, the JPEG code has signaled an error. + * We need to clean up the JPEG object, close the input file, and return. + */ + jpeg_destroy_decompress(&cinfo); + fclose(infile); + return 0; + } + /* Now we can initialize the JPEG decompression object. */ + jpeg_create_decompress(&cinfo); + + /* Step 2: specify data source (eg, a file) */ + + jpeg_stdio_src(&cinfo, infile); + + /* Step 3: read file parameters with jpeg_read_header() */ + + (void) jpeg_read_header(&cinfo, TRUE); + /* We can ignore the return value from jpeg_read_header since + * (a) suspension is not possible with the stdio data source, and + * (b) we passed TRUE to reject a tables-only JPEG file as an error. + * See libjpeg.doc for more info. + */ + + /* Step 4: set parameters for decompression */ + + /* In this example, we don't need to change any of the defaults set by + * jpeg_read_header(), so we do nothing here. + */ + + /* Step 5: Start decompressor */ + + (void) jpeg_start_decompress(&cinfo); + /* We can ignore the return value since suspension is not possible + * with the stdio data source. + */ + + /* We may need to do some setup of our own at this point before reading + * the data. After jpeg_start_decompress() we have the correct scaled + * output image dimensions available, as well as the output colormap + * if we asked for color quantization. + * In this example, we need to make an output work buffer of the right size. + */ + /* JSAMPLEs per row in output buffer */ + + image_height = cinfo.output_height; + image_width = cinfo.output_width; + row_stride = cinfo.output_width * cinfo.output_components; + image_ncomponents = cinfo.output_components; + + /* Make a one-row-high sample array that will go away when done with image */ + buffer = (*cinfo.mem->alloc_sarray) + ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1); + + /* Step 6: while (scan lines remain to be read) */ + /* jpeg_read_scanlines(...); */ + + /* Here we use the library's state variable cinfo.output_scanline as the + * loop counter, so that we don't have to keep track ourselves. + */ + while (cinfo.output_scanline < cinfo.output_height) { + /* jpeg_read_scanlines expects an array of pointers to scanlines. + * Here the array is only one element long, but you could ask for + * more than one scanline at a time if that's more convenient. + */ + (void) jpeg_read_scanlines(&cinfo, buffer, 1); + /* Assume put_scanline_someplace wants a pointer and sample count. */ + put_scanline_someplace(buffer[0], row_stride); + } + + /* Step 7: Finish decompression */ + + (void) jpeg_finish_decompress(&cinfo); + /* We can ignore the return value since suspension is not possible + * with the stdio data source. + */ + + /* Step 8: Release JPEG decompression object */ + + /* This is an important step since it will release a good deal of memory. */ + jpeg_destroy_decompress(&cinfo); + + /* After finish_decompress, we can close the input file. + * Here we postpone it until after no more JPEG errors are possible, + * so as to simplify the setjmp error logic above. (Actually, I don't + * think that jpeg_destroy can do an error exit, but why assume anything...) + */ + fclose(infile); + + /* At this point you may want to check to see whether any corrupt-data + * warnings occurred (test whether jerr.pub.num_warnings is nonzero). + */ + + /* And we're done! */ +y=0; + return 1; +} + +/* + * SOME FINE POINTS: + * + * In the above code, we ignored the return value of jpeg_read_scanlines, + * which is the number of scanlines actually read. We could get away with + * this because we asked for only one line at a time and we weren't using + * a suspending data source. See libjpeg.doc for more info. + * + * We cheated a bit by calling alloc_sarray() after jpeg_start_decompress(); + * we should have done it beforehand to ensure that the space would be + * counted against the JPEG max_memory setting. In some systems the above + * code would risk an out-of-memory error. However, in general we don't + * know the output image dimensions before jpeg_start_decompress(), unless we + * call jpeg_calc_output_dimensions(). See libjpeg.doc for more about this. + * + * Scanlines are returned in the same order as they appear in the JPEG file, + * which is standardly top-to-bottom. If you must emit data bottom-to-top, + * you can use one of the virtual arrays provided by the JPEG memory manager + * to invert the data. See wrbmp.c for an example. + * + * As with compression, some operating modes may require temporary files. + * On some systems you may need to set up a signal handler to ensure that + * temporary files are deleted if the program is interrupted. See libjpeg.doc. + */ + + + + diff --git a/libfbui/WindowManager/main.c b/libfbui/WindowManager/main.c @@ -0,0 +1,313 @@ + +/*========================================================================= + * + * fbwm, a window manager for FBUI (in-kernel framebuffer UI) + * Copyright (C) 2004 Zachary T Smith, fbui@comcast.net + * + * This module is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This module 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this module; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * (See the file COPYING in the main directory of this archive for + * more details.) + * + *=======================================================================*/ + +/* + * Changes: + * + * Oct 19, 2004, fbui@comcast.net: got rectangle subtraction working + * Oct 19, 2004, fbui@comcast.net: got background image drawing working + * Dec 31, 2004, fbui@comcast.net: moved rectangle code to separate file + */ + + + +#include <stdio.h> +#include <time.h> +#include <sys/types.h> +#include <unistd.h> +#include <math.h> +#include <jpeglib.h> +#include <signal.h> + + +#include "libfbui.h" + + +short win_w, win_h; +#define STEELBLUE 0x4682B4 + +extern JSAMPLE * image_buffer; +extern int image_height; +extern int image_width; +extern int image_ncomponents; + +extern int read_JPEG_file (char*); + +extern char grayscale; /* 1 forces bg image to grayscale */ + +struct fbui_wininfo info[200]; +struct fbui_wininfo prev[200]; +int window_count; + + +extern void +draw_image (Display *dpy, Window *win, short x0, short y0, short x1, short y1); + +extern void +draw_background (Display *dpy, Window *win, struct fbui_wininfo *, int); + + +void +update_focus (Display *dpy, Window *self) +{ + int i; + for (i=0; i<window_count; i++) { + if (info[i].program_type == FBUI_PROGTYPE_APP) + fbui_assign_keyfocus (dpy, self, info[i].id); + } +} + + +int +main(int argc, char** argv) +{ + int mypid,i,j; + Display *dpy; + Window *self; + Font *pcf; + short line_height; + + grayscale=0; + + pcf = font_new (); + if (!pcf) + FATAL ("out o' memory"); + + if (!pcf_read (pcf, "timR12.pcf")) { + font_free (pcf); + FATAL ("cannot read Times 12"); + } + + line_height = pcf->ascent + pcf->descent; + + long fg,bg=0x404040; + + dpy = fbui_display_open (); + if (!dpy) + FATAL ("request for control denied"); + + self = fbui_window_open (dpy, 1,1, &win_w, &win_h, 9999,9999, + 0, 0, + &fg, &bg, + "fbwm", "", + FBUI_PROGTYPE_WM, + true, // we are a window manager + false, // but we are not autopositioning anything + -1, + false, // we don't need keys + false, // don't need all motion + false, // not hidden + argc,argv); + if (!self) + FATAL ("cannot open manager window"); + + /* Check for a background image */ + image_width=0; + image_height=0; + image_ncomponents=0; + image_buffer=NULL; + char *image_path=NULL; + i=1; + while (i<argc) { + char *s = argv[i]; + int ch = s ? s[0] : 0; + if (ch && '-' != ch) { + image_path = argv[i]; + break; + } + i++; + } + if (image_path) { + int result; + result = read_JPEG_file (image_path); + if (image_ncomponents != 3) + result=0; + if (!result) + FATAL ("cannot read background image"); + + } + + if (FBUI_SUCCESS != fbui_accelerator (dpy, self, '1', 1)) + FATAL ("cannot register accelerator"); + if (FBUI_SUCCESS != fbui_accelerator (dpy, self, '2', 1)) + FATAL ("cannot register accelerator"); + if (FBUI_SUCCESS != fbui_accelerator (dpy, self, '3', 1)) + FATAL ("cannot register accelerator"); + if (FBUI_SUCCESS != fbui_accelerator (dpy, self, '4', 1)) + FATAL ("cannot register accelerator"); + if (FBUI_SUCCESS != fbui_accelerator (dpy, self, '5', 1)) + FATAL ("cannot register accelerator"); + if (FBUI_SUCCESS != fbui_accelerator (dpy, self, '6', 1)) + FATAL ("cannot register accelerator"); + if (FBUI_SUCCESS != fbui_accelerator (dpy, self, '7', 1)) + FATAL ("cannot register accelerator"); + if (FBUI_SUCCESS != fbui_accelerator (dpy, self, '8', 1)) + FATAL ("cannot register accelerator"); + if (FBUI_SUCCESS != fbui_accelerator (dpy, self, '9', 1)) + FATAL ("cannot register accelerator"); + if (FBUI_SUCCESS != fbui_accelerator (dpy, self, '0', 1)) + FATAL ("cannot register accelerator"); + + /* Alt-tab switches between apps + */ + if (FBUI_SUCCESS != fbui_accelerator (dpy, self, '\t', 1)) + FATAL ("cannot register accelerator"); + + /* Alt-backsp shuts down FBUI on the current VC + */ + if (FBUI_SUCCESS != fbui_accelerator (dpy, self, '\b', 1)) + FATAL ("cannot register accelerator"); + + int need_list = 0; + int need_redraw = 0; + + while(1) { + Event ev; + int err; + if (err = fbui_wait_event (dpy, &ev, + FBUI_EVENTMASK_ALL - FBUI_EVENTMASK_KEY)) + { + fbui_print_error (err); + continue; + } + int num = ev.type; +printf ("%s got event %s\n", argv[0], fbui_get_event_name (ev.type)); + + if (ev.win != self) { +printf ("ev.win=%08x\n", (unsigned long) ev.win); + FATAL ("got event for another win"); + } + + if (num == FBUI_EVENT_EXPOSE) { + need_redraw = 1; + need_list = 1; + } + else if (num == FBUI_EVENT_WINCHANGE) { + need_list = 1; + } + else if (num == FBUI_EVENT_ACCEL) { + short key = ev.key; +printf ("FBWM accel is %d (0x%04x)\n", key,key); + if (key == '\b') { +printf ("FBWM got alt-backspace\n"); + goto done; + } + + if (key == '\t') { + continue; + } + } + + if (need_list) { + int i; + int prev_count = window_count; + + need_redraw = 1; + + for (i=0; i<window_count; i++) + prev[i] = info[i]; + + window_count = fbui_window_info (dpy, self, &info[0], 200); + + /* determine which windows have disappeared */ + for (i=0; i<window_count; i++) { + int missing=1; + int j=0; +printf ("%d: window id %d, %s width %d height %d\n", + i, info[i].id, info[i].name, info[i].width, info[i].height); + while (j < window_count) { + if (prev[i].pid == info[j].pid) { + missing=0; + break; + } + j++; + } + if (missing) { + draw_image (dpy, self, + prev[i].x, + prev[i].y - line_height, + prev[i].x + prev[i].width - 1, + prev[i].y - 1); + fbui_flush(dpy, self); + } + } + + update_focus (dpy, self); + + need_list=0; + } + + if (need_redraw) { + int i; + + need_redraw = 0; + + // Fill in the gaps + draw_background (dpy, self, info, window_count); + + i=0; + while (i < window_count) { + char tmp[100]; + struct fbui_wininfo *wi = &info[i]; + int x,y; + + // locate window + x = wi->x; + y = wi->y; + + // draw gradient behind text + int j=0; + while (j < wi->width) { + unsigned long r,g,b; + int k = (255 - j/2) > 1 ? (255 - j/2) : 0; + r = 30; + g = 32 + (7*k)/8; + b = k/3; + r <<= 16; + b <<= 8; + fbui_draw_vline (dpy, self, x+j, y-1, y-line_height, + r|g|b); + j++; + } + + // draw program name/pid + sprintf(tmp,"%s (pid=%d)", wi->name,wi->pid); + fbui_draw_string (dpy, self, pcf,x,y-line_height,tmp, RGB_YELLOW); + + i++; + } + } + } + +done: + mypid = getpid(); + for (i=0; i<window_count; i++) { + if (info[i].pid != mypid) + kill (info[i].pid, SIGTERM); + } + + fbui_display_close (dpy); + return 0; +} diff --git a/libfbui/WindowManager/rect.c b/libfbui/WindowManager/rect.c @@ -0,0 +1,389 @@ + +/*========================================================================= + * + * fbwm, a window manager for FBUI (in-kernel framebuffer UI) + * Copyright (C) 2004 Zachary T Smith, fbui@comcast.net + * + * This module is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This module 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this module; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * (See the file COPYING in the main directory of this archive for + * more details.) + * + *=======================================================================*/ + +#include <stdio.h> +#include <linux/fb.h> +#include <libfbui.h> +#include <jpeglib.h> + +extern int window_count; +extern struct fbui_wininfo *info; + +JSAMPLE * image_buffer; +int image_height; +int image_width; +int image_ncomponents; + +extern short win_w, win_h; + +char grayscale=0; /* 1 forces bg image to grayscale */ + + + + +/* -----------------Rectangle subtraction code----------------- */ + +typedef struct rect { + short x0,y0,x1,y1; + struct rect *next; +} Rect; + +static Rect* Rect_new(short x0, short y0, short x1, short y1) +{ + Rect *nu = (Rect*) malloc (sizeof(Rect)); + if (!nu) return NULL; + + nu->x0 = x0; + nu->y0 = y0; + nu->x1 = x1; + nu->y1 = y1; + nu->next = NULL; + + return nu; +} + +static void Rect_sort (Rect *r) +{ + if (!r) return; + if (r->x0 > r->x1) { + short tmp = r->x0; + r->x0 = r->x1; + r->x1 = tmp; + } + if (r->y0 > r->y1) { + short tmp = r->y0; + r->y0 = r->y1; + r->y1 = tmp; + } +} + +static Rect* Rect_dup (Rect *r) +{ + if (!r) return NULL; + return Rect_new (r->x0,r->y0,r->x1,r->y1); +} + +static int Rect_subtract (Rect *a, Rect *b, Rect *rects[]) +{ + int count=0; + if (!a || !b || !rects) return; + + if (a->x0==b->x0 && a->x1==b->x1 && a->y0==b->y0 && a->y1==b->y1) + return 0; + + Rect_sort(a); + Rect_sort(b); + +#define between(N,M,O) (N>=M && N<=O) + + int i=-1, j=-1; + if (b->x1 < a->x0) + i=0; + else if (b->x0 <= a->x0 && between(b->x1,a->x0,a->x1)) + i=1; + else if (between(b->x0,a->x0,a->x1) && b->x1 >= a->x1) + i=3; + else if (between(b->x0,a->x0,a->x1) && between(b->x1,a->x0,a->x1)) + i=2; + else + i=4; + + if (b->y1 < a->y0) + j=0; + else if (b->y0 <= a->y0 && between(b->y1,a->y0,a->y1)) + j=1; + else if (between(b->y0,a->y0,a->y1) && b->y1 >= a->y1) + j=3; + else if (between(b->y0,a->y0,a->y1) && between(b->y1,a->y0,a->y1)) + j=2; + else + j=4; + +/* + j values + +-------+ + | 0 | + +-------+ + +-------+ + +--------------+ | | + | | | 1 | +-------+ + | | | | | | + | a | +-------+ | 2 | + | | | | + | | +-------+ + | | +-------+ + +--------------+ | 3 | + +-------+ +-------+ + i values: | 4 | + +-------+ +--------+ +-------+ +-------+ + | 0 | | 2 | | 4 | + +-------+ +--------+ +-------+ + +---------+ +--------+ + | 1 | | 3 | + +---------+ +--------+ + */ + // totally outside + if (i==0 || i==4 || j==0 || j==4) { + rects[count++] = Rect_dup(a); + return count; + } + else + // totally inside + if (i==2 && j==2) { + if (a->x0 != b->x0) + rects[count++] = Rect_new (a->x0,a->y0,b->x0-1,a->y1); //left + if (a->y0 != b->y0) + rects[count++] = Rect_new (b->x0,a->y0,b->x1,b->y0-1); //top + if (a->y1 != b->y1) + rects[count++] = Rect_new (b->x0,b->y1+1,b->x1,a->y1); //bottom + if (a->x1 != b->x1) + rects[count++] = Rect_new (b->x0+1,a->y0,a->x1,a->y1); //right + return count; + } + else + if (i==1 && j==2) { + if (a->y0 != b->y0) + rects[count++] = Rect_new (a->x0,a->y0,b->x1,b->y0-1); // topleft + if (a->y1 != b->y1) + rects[count++] = Rect_new (a->x0,b->y1+1,b->x1,a->y1); // bottomleft + if (a->x1 != b->x1) + rects[count++] = Rect_new (b->x1+1,a->y0,a->x1,a->y1); // right + return count; + } + else + if (i==3 && j==2) { + if (a->y0 != b->y0) + rects[count++] = Rect_new (a->x0,a->y0,a->x1,b->y0-1); // top + if (a->x0 != b->x0) + rects[count++] = Rect_new (a->x0,b->y0,b->x0-1,b->y1); // middle + if (a->y1 != b->y1) + rects[count++] = Rect_new (a->x0,b->y1+1,a->x1,a->y1); // bottom + return count; + } + else + if (i==2 && j==1) { + if (a->x0 != b->x0) + rects[count++] = Rect_new (a->x0,a->y0,b->x0-1,b->y1); // topleft + if (a->x1 != b->x1) + rects[count++] = Rect_new (b->x1+1,a->y0,a->x1,b->y1); // topright + if (a->y1 != b->y1) + rects[count++] = Rect_new (a->x0,b->y1+1,a->x1,a->y1); //bottom + return count; + } + else + if (i==2 && j==3) { + if (a->y0 != b->y0) + rects[count++] = Rect_new (a->x0,a->y0,a->x1,b->y0-1); // top + if (a->x0 != b->x0) + rects[count++] = Rect_new (a->x0,b->y0,b->x0-1,a->y1); // bottomleft + if (a->x1 != b->x1) + rects[count++] = Rect_new (b->x1+1,b->y0,a->x1,a->y1); // bottomright + return count; + } + else + if (i==3 && j==1) { + if (a->x0 != b->x0) + rects[count++] = Rect_new (a->x0,a->y0,b->x0-1,a->y1); // left + if (a->y1 > b->y1) + rects[count++] = Rect_new (b->x0,b->y1+1,a->x1,a->y1); // bottomright + return count; + } + else + if (i==3 && j==3) { + if (a->x0 != b->x0) + rects[count++] = Rect_new (a->x0,a->y0,b->x0-1,a->y1); // left + if (a->y0 < b->y0) + rects[count++] = Rect_new (b->x0,a->y0,a->x1,b->y0-1); //topright + return count; + } + else + if (i==1 && j==1) { + if (a->x1 != b->x1) + rects[count++] = Rect_new (b->x1+1,a->y0,a->x1,a->y1); // right + if (a->y1 != b->y1) + rects[count++] = Rect_new (a->x0,b->y1+1,b->x1,a->y1); // bottomleft + return count; + } + else + if (i==1 && j==3) { + if (a->x1 != b->x1) + rects[count++] = Rect_new (b->x1+1,a->y0,a->x1,a->y1); // right + if (a->y0 < b->y0) + rects[count++] = Rect_new (a->x0,a->y0,b->x1,b->y0-1); // topleft + return count; + } + else + printf ("combo %d %d\n",i,j); +} + +static void Rect_delete(Rect *r) +{ + if (r) + free((void*)r); +} + + +/* Draws a portion of the background + * If an image has been loaded, it draws that. + * Otherwise, a green gradient. + */ +void +draw_image (Display *dpy, Window *win, short x0, short y0, short x1, short y1) +{ + int i,j; + if (x0 > x1) { + short tmp=x0;x0=x1;x1=tmp; + } + if (y0 > y1) { + short tmp=y0;y0=y1;y1=tmp; + } + if (x1<0) return; + if (y1<0) return; + if (x0<0) x0=0; + if (y0<0) y0=0; + + /* If we have no background image, don't sweat it, just draw + * a gradient + */ + if (!image_buffer) { + for (i=x0; i<=x1; i++) { + unsigned long k = (191 * i) / win_w; + unsigned long color = (35 + k) + (90 << 8); + fbui_draw_vline (dpy, win, i,y0,y1, color); + } + fbui_flush (dpy, win); + return; + } + + if (x0>=image_width) return; + if (y0>=image_height) return; + if (x1>=image_width) x1=image_width-1; + if (y1>=image_height) y1=image_height-1; + + for (j=y0; j<=y1; j++) { + if (image_ncomponents == 1 || grayscale) { + for(i=x0; i<x1; i++) { + unsigned long pix=0; + unsigned char *p = image_buffer + + image_ncomponents*(i + j*image_width); + + /* pixels are grayscale */ + if (image_ncomponents == 1) { + pix = *p; + pix <<= 8; + pix |= *p; + pix <<= 8; + pix |= *p; + } else { + pix = *p++; + pix += *p++; + pix += *p; + pix /= 3; + pix |= (pix<<8) | (pix<<16); + } + + fbui_draw_point (dpy, win, i, j, pix); + } + } + else + { + fbui_put_rgb3 (dpy, win, x0, j, x1-x0+1, + image_buffer + 3*(j*image_width+x0)); + } + } + + fbui_flush(dpy,win); +} + + +void +draw_background (Display *dpy, Window *win, struct fbui_wininfo *info, int window_count) +{ + Rect *list1 = Rect_new (0,0,win_w-1,win_h-1); + Rect *list2 = NULL; + Rect *ptr; + int mypid = getpid(); + int i; + + for (i=0; i<window_count; i++) { + Rect *r0,*r1,*r2,*r3; + struct fbui_wininfo *wi = &info[i]; + Rect *windowrect = Rect_new(wi->x,wi->y, + wi->x+wi->width-1,wi->y+wi->height-1); +//printf ("subtracting %s\n", wi->name); + if (wi->pid != mypid) { + ptr = list1; + while(ptr) { + Rect *rects[4]; + int count = Rect_subtract (ptr,windowrect,rects); + int j=0; + while (j < count) { + rects[j]->next = list2; + list2 = rects[j]; + j++; + } + ptr = ptr->next; + } + ptr = list1; + Rect *next; + while (ptr) { + next = ptr->next; + Rect_delete(ptr); + ptr=next; + } + list1 = list2; + list2 = NULL; + +#if 0 +int k=0; +Rect *n = list1; +while(n) { k++; +printf (" rect: %d %d - %d %d\n", n->x0,n->y0,n->x1,n->y1); +n=n->next; +} +printf ("result list now has %d rectangles\n", k); +#endif + } + + Rect_delete (windowrect); + } + + /* draw the background */ + ptr=list1; + while(ptr) { + draw_image (dpy,win, ptr->x0,ptr->y0,ptr->x1,ptr->y1); + ptr=ptr->next; + } + fbui_flush (dpy, win); + + /* remove the rectangle list */ + ptr = list1; + while (ptr) { + Rect *next = ptr->next; + Rect_delete(ptr); + ptr=next; + } +} + diff --git a/libfbui/cleanall.sh b/libfbui/cleanall.sh @@ -0,0 +1,13 @@ +#/bin/sh + +DIRS=". Calc Launcher MPEG Test Clock ToDo Term LoadMonitor Viewer +MailCheck Dump WindowManager PanelManager" + +for DIR in $DIRS +do +cd $DIR +make clean +if [ "$DIR" != "." ] +then cd .. +fi +done diff --git a/libfbui/clouds.jpg b/libfbui/clouds.jpg Binary files differ. diff --git a/libfbui/install.sh b/libfbui/install.sh @@ -0,0 +1,16 @@ +#!/bin/sh + +if [ $UID != 0 ] +then echo "You must be root to install!"; exit +fi + +DIRS="Clock ToDo Term LoadMonitor Viewer MailCheck Dump WindowManager PanelManager" + +for DIR in $DIRS +do +cd $DIR +make install +cd .. +done + + diff --git a/libfbui/libfbui.c b/libfbui/libfbui.c @@ -0,0 +1,2428 @@ + +/*========================================================================= + * + * libfbui, a library for accessing FBUI (in-kernel framebuffer GUI). + * Copyright (C) 2003-2004 Zachary T Smith, fbui@comcast.net + * + * This module is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This module 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this module; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * (See the file COPYING in the main directory of this archive for + * more details.) + * + *=======================================================================*/ + +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <sys/ioctl.h> +#include <linux/fb.h> +#include <sys/mman.h> +#include <unistd.h> +#include <linux/vt.h> +#include <signal.h> +#include <errno.h> +#include <linux/input.h> +#include <string.h> +#include <stdlib.h> +#include <ctype.h> +#include <time.h> +#include <sys/param.h> + + + +#include "libfbui.h" + + +static struct fb_fix_screeninfo fi; +static struct fb_var_screeninfo vi; +static struct fbui_openparams oi; + +#define ERRLOG "/tmp/fbui.log" + + +static int dpi = 75; + + +/*----------------------------------------------------------------------------- + * Changes: + * + * Sep 23, ZS: added SIGTERM handler + * Sep 24, ZS: added commandline processing of console# (-c) + * Sep 25, ZS: added read_point + * Sep 25, ZS: added errlog + * Sep 26, ZS: added commandline processing of geometry (-geo) + * Sep 26, ZS: more signals supported + * Oct 01, ZS: updated for new use of control ioctl + * Oct 14, ZS: added support for fbui-input events + * Oct 14, ZS: added keycode->char conversion + * Oct 22, ZS: fbui_open now ensures dims are available + * Oct 26, ZS: added -fg and -bg + * + *----------------------------------------------------------------------------*/ + + +Display *my_dpy = NULL; +int display_fd; + + +static void +errlog (char *s, char *s2) +{ + FILE *f=fopen(ERRLOG,"a"); + if (!f) + return; + fprintf(f, "%s(): %s\n", s,s2); + fprintf(f, "\tsystem error(%d): %s\n", errno,strerror(errno)); + fclose(f); +} + + +int +fbui_flush (Display *dpy, Window *win) +{ + int result=0; + + if (!dpy || !win) return -1; + /*---------------*/ + + if (win->command_ix <= 2) + return 0; + + win->command[0] = win->id; + win->command[1] = win->command_ix-2; + if (win->command[1]) + result = ioctl (dpy->fd, FBIO_UI_EXEC, (void*) win->command); + win->command[0] = win->id; + win->command[1] = 0; + win->command_ix = 2; + return result; +} + +static int +check_flush (Display *dpy, Window *win, int need) +{ + unsigned short nwords; + int result=0; + + if (!dpy || !win) return -1; + /*---------------*/ + nwords = win->command_ix-2; + if (nwords + need >= LIBFBUI_COMMANDBUFLEN) { + result = fbui_flush (dpy,win); + } + return result; +} + + + +/* called only by wm */ +int +fbui_window_info (Display* dpy, Window *wm, struct fbui_wininfo* info, int ninfo) +{ + int result=0; + + if (!dpy || !info || ninfo<=0) return -1011; + /*---------------*/ + + static struct fbui_ctrlparams ctl; + memset (&ctl, 0, sizeof (struct fbui_ctrlparams)); + ctl.op = FBUI_WININFO; + ctl.id = wm->id; + ctl.info = info; + ctl.ninfo = ninfo; + + return ioctl (dpy->fd, FBIO_UI_CONTROL, (unsigned long) &ctl); +} + +int +fbui_accelerator (Display* dpy, Window *wm, short key, short op) +{ + int result=0; + + if (!dpy) return -1; + /*---------------*/ + + struct fbui_ctrlparams ctl; + memset (&ctl, 0, sizeof (struct fbui_ctrlparams)); + ctl.op = FBUI_ACCEL; + ctl.id = wm->id; + ctl.x = key; + ctl.y = op; + + return ioctl (dpy->fd, FBIO_UI_CONTROL, (unsigned long) &ctl) < 0 ? -errno : 0; +} + + +int +fbui_cut (Display* dpy, Window *win, unsigned char *data, unsigned long length) +{ + if (!dpy || !win || !data || !length) + return -1; + /*---------------*/ + + struct fbui_ctrlparams ctl; + memset (&ctl, 0, sizeof (struct fbui_ctrlparams)); + ctl.op = FBUI_CUT; + ctl.id = win->id; + ctl.pointer = data; + ctl.cutpaste_length = length; + + return ioctl (dpy->fd, FBIO_UI_CONTROL, (unsigned long) &ctl) < 0 ? -errno : 0; +} + +int +fbui_paste (Display* dpy, Window *win, unsigned char *data, unsigned long max) +{ + if (!dpy || !win || !data || !max) + return -1; + /*---------------*/ + + struct fbui_ctrlparams ctl; + memset (&ctl, 0, sizeof (struct fbui_ctrlparams)); + ctl.op = FBUI_PASTE; + ctl.id = win->id; + ctl.pointer = data; + ctl.cutpaste_length = max; + + return ioctl (dpy->fd, FBIO_UI_CONTROL, (unsigned long) &ctl) < 0 ? -errno : 0; +} + + +long +fbui_cut_length (Display* dpy, Window *win) +{ + if (!dpy || !win) + return -1; + /*---------------*/ + + struct fbui_ctrlparams ctl; + memset (&ctl, 0, sizeof (struct fbui_ctrlparams)); + ctl.op = FBUI_CUTLENGTH; + ctl.id = win->id; + + return ioctl (dpy->fd, FBIO_UI_CONTROL, (unsigned long) &ctl) < 0 ? -errno : 0; +} + + +/* 1 => force all windows to be auto placed + */ +/* called only by wm */ +int +fbui_placement (Display* dpy, Window *wm, int yes) +{ + int result=0; + + if (!dpy) return -1; + /*---------------*/ + + struct fbui_ctrlparams ctl; + memset (&ctl, 0, sizeof (struct fbui_ctrlparams)); + ctl.op = FBUI_PLACEMENT; + ctl.id = wm->id; + ctl.x = yes; + + return ioctl (dpy->fd, FBIO_UI_CONTROL, (unsigned long) &ctl) < 0 ? -errno : 0; +} + + +/* called only by wm */ +int +fbui_redraw (Display *dpy, Window *wm, short win) +{ + int result=0; + + if (!dpy) return -1; + /*---------------*/ + + struct fbui_ctrlparams ctl; + memset (&ctl, 0, sizeof (struct fbui_ctrlparams)); + ctl.op = FBUI_REDRAW; + ctl.id = wm->id; + ctl.id2 = win; + + return ioctl (dpy->fd, FBIO_UI_CONTROL, (unsigned long)&ctl) < 0 ? -errno : 0; +} + + + +/* called only by wm */ +int +fbui_move_resize (Display *dpy, Window *wm, short id, short x0, short y0, short x1, short y1) +{ + int result=0; + + if (!dpy) return -1; + /*---------------*/ + + if (x0>x1) { short tmp=x0;x0=x1;x1=tmp; } + if (y0>y1) { short tmp=y0;y0=y1;y1=tmp; } + + struct fbui_ctrlparams ctl; + memset (&ctl, 0, sizeof (struct fbui_ctrlparams)); + ctl.op = FBUI_MOVE_RESIZE; + ctl.id = wm->id; + ctl.id2 = id; + ctl.x = x0; + ctl.y = y0; + ctl.width = x1-x0+1; + ctl.height = y1-y0+1; + + return ioctl (dpy->fd, FBIO_UI_CONTROL, (unsigned long)&ctl) < 0 ? -errno : 0; +} + +/* called only by wm */ +int +fbui_delete (Display *dpy, Window *wm, short id) +{ + int result=0; + + if (!dpy) return -1; + /*---------------*/ + + struct fbui_ctrlparams ctl; + memset (&ctl, 0, sizeof (struct fbui_ctrlparams)); + ctl.op = FBUI_DELETE; + ctl.id = wm->id; + ctl.id2 = id; + + int rv=1; + do { + rv = ioctl (dpy->fd, FBIO_UI_CONTROL, (unsigned long)&ctl); + if (rv < 0 && -errno != FBUI_ERR_DRAWING) + FATAL ("error when deleting window"); + } + while (rv); + + return 0; +} + +/* called only by wm */ +int +fbui_assign_keyfocus (Display *dpy, Window *wm, short id) +{ + int result=0; + + if (!dpy) return -1; + /*---------------*/ + + struct fbui_ctrlparams ctl; + memset (&ctl, 0, sizeof (struct fbui_ctrlparams)); + ctl.op = FBUI_ASSIGN_KEYFOCUS; + ctl.id = wm->id; + ctl.id2 = id; + + return ioctl (dpy->fd, FBIO_UI_CONTROL, (unsigned long)&ctl) < 0 ? -errno : 0; +} + +/* called only by wm */ +int +fbui_assign_pointerfocus (Display *dpy, Window *wm, short id) +{ + int result=0; + + if (!dpy) return -1; + /*---------------*/ + + struct fbui_ctrlparams ctl; + memset (&ctl, 0, sizeof (struct fbui_ctrlparams)); + ctl.op = FBUI_ASSIGN_PTRFOCUS; + ctl.id = wm->id; + ctl.id2 = id; + + return ioctl (dpy->fd, FBIO_UI_CONTROL, (unsigned long)&ctl) < 0 ? -errno : 0; +} + +/* called only by wm */ +int +fbui_hide (Display *dpy, Window *wm, short id) +{ + int result=0; + + if (!dpy) return -1; + /*---------------*/ + + struct fbui_ctrlparams ctl; + memset (&ctl, 0, sizeof (struct fbui_ctrlparams)); + ctl.op = FBUI_HIDE; + ctl.id = wm->id; + ctl.id2 = id; + + return ioctl (dpy->fd, FBIO_UI_CONTROL, (unsigned long)&ctl) < 0 ? -errno : 0; +} + +/* called only by wm */ +int +fbui_unhide (Display *dpy, Window *wm, short id) +{ + int result=0; + + if (!dpy) return -1; + /*---------------*/ + + struct fbui_ctrlparams ctl; + memset (&ctl, 0, sizeof (struct fbui_ctrlparams)); + ctl.op = FBUI_UNHIDE; + ctl.id = wm->id; + ctl.id2 = id; + + result = ioctl (dpy->fd, FBIO_UI_CONTROL, (unsigned long)&ctl); + if (result < 0) + result = -errno; + return result; +} + +int +fbui_draw_point (Display *dpy, Window *win, short x, short y, unsigned long color) +{ + int result=0; + + if (!dpy || !win) return -1; + /*---------------*/ + if (result = check_flush (dpy, win,5)) + return result; + + win->command [win->command_ix++] = FBUI_POINT; + win->command [win->command_ix++] = x; + win->command [win->command_ix++] = y; + win->command [win->command_ix++] = color; + win->command [win->command_ix++] = color>>16; + + return 0; +} + +unsigned long +fbui_read_point (Display *dpy, Window *win, short x, short y) +{ + int result=0; + + if (!dpy || !win) return -1; + /*---------------*/ + if (result = check_flush (dpy, win,3)) + return result; + + win->command [win->command_ix++] = FBUI_READPOINT; + win->command [win->command_ix++] = x; + win->command [win->command_ix++] = y; + + return fbui_flush (dpy, win); +} + +int +fbui_draw_vline (Display *dpy, Window *win, short x, short y0, short y1, unsigned long color) +{ + int result=0; + + if (!dpy || !win) return -1; + /*---------------*/ + if (result = check_flush (dpy, win,6)) + return result; + + win->command [win->command_ix++] = FBUI_VLINE; + win->command [win->command_ix++] = y0; + win->command [win->command_ix++] = y1; + win->command [win->command_ix++] = color; + win->command [win->command_ix++] = color>>16; + win->command [win->command_ix++] = x; + + return 0; +} + +int +fbui_tinyblit (Display *dpy, Window *win, short x, short y, + unsigned long color, + unsigned long bgcolor, + short width, + unsigned long bits) +{ + int result=0; + + if (!dpy || !win) return -1; + /*---------------*/ + if (result = check_flush (dpy, win,10)) + return result; + + win->command [win->command_ix++] = FBUI_TINYBLIT; + win->command [win->command_ix++] = x; + win->command [win->command_ix++] = y; + win->command [win->command_ix++] = color; + win->command [win->command_ix++] = color>>16; + win->command [win->command_ix++] = bgcolor; + win->command [win->command_ix++] = bgcolor>>16; + win->command [win->command_ix++] = width; + win->command [win->command_ix++] = bits; + win->command [win->command_ix++] = bits>>16; + +fbui_flush(dpy,win); + + return 0; +} + +int +fbui_draw_hline (Display *dpy, Window *win, short x0, short x1, short y, unsigned long color) +{ + int result=0; + + if (!dpy || !win) return -1; + /*---------------*/ + if (result = check_flush (dpy, win,6)) + return result; + + win->command [win->command_ix++] = FBUI_HLINE; + win->command [win->command_ix++] = x0; + win->command [win->command_ix++] = x1; + win->command [win->command_ix++] = color; + win->command [win->command_ix++] = color>>16; + win->command [win->command_ix++] = y; + + return 0; +} + +int +fbui_draw_line (Display *dpy, Window *win, short x0, short y0, short x1, short y1, unsigned long color) +{ + int result=0; + + if (!dpy || !win) return -1; + /*---------------*/ + if (result = check_flush (dpy, win,7)) + return result; + win->command [win->command_ix++] = FBUI_LINE; + win->command [win->command_ix++] = x0; + win->command [win->command_ix++] = y0; + win->command [win->command_ix++] = x1; + win->command [win->command_ix++] = y1; + win->command [win->command_ix++] = color; + win->command [win->command_ix++] = color>>16; + + return 0; +} + + +int +fbui_invert_line (Display *dpy, Window *win, short x0, short y0, short x1, short y1) +{ + int result=0; + + if (!dpy || !win) return -1; + /*---------------*/ + if (result = check_flush (dpy, win,5)) + return result; + + win->command [win->command_ix++] = FBUI_INVERTLINE; + win->command [win->command_ix++] = x0; + win->command [win->command_ix++] = y0; + win->command [win->command_ix++] = x1; + win->command [win->command_ix++] = y1; + + return 0; +} + + +int +fbui_draw_string (Display *dpy, Window *win, struct fbui_font *font, + short x0, short y0, char *str_, + unsigned long color) +{ + int result=0; + unsigned long n; + unsigned long n2; + unsigned char *str = (unsigned char*) str_; + + if (!dpy || !win || !str) + return -1; + /*---------------*/ + + if (result = check_flush (dpy, win,10)) + return result; + + if (!str) FATAL("null param3"); + + n = (unsigned long) str; + n2 = (unsigned long)font; + + win->command [win->command_ix++] = FBUI_STRING; + win->command [win->command_ix++] = x0; + win->command [win->command_ix++] = y0; + win->command [win->command_ix++] = n2; + win->command [win->command_ix++] = n2>>16; + win->command [win->command_ix++] = strlen (str); + win->command [win->command_ix++] = n; + win->command [win->command_ix++] = n>>16; + win->command [win->command_ix++] = color; + win->command [win->command_ix++] = color>>16; + + /* gotta flush, string may not last */ + return fbui_flush (dpy, win); +} + +int +fbui_set_subtitle (Display *dpy, Window *win, char *str) +{ + struct fbui_ctrlparams ctl; + + if (!dpy || !win || !str) + return FBUI_ERR_NULLPTR; + + memset (&ctl, 0, sizeof (struct fbui_ctrlparams)); + ctl.op = FBUI_SUBTITLE; + ctl.id = win->id; + strncpy (ctl.string, str, FBUI_NAMELEN); + + return ioctl (dpy->fd, FBIO_UI_CONTROL, &ctl) < 0 ? -errno : 0; +} + +int +fbui_set_font (Display *dpy, Window *win, struct fbui_font *font) +{ + if (!dpy || !win || !font) + return -1; + + struct fbui_ctrlparams ctl; + memset (&ctl, 0, sizeof (struct fbui_ctrlparams)); + ctl.op = FBUI_SETFONT; + ctl.id = win->id; + ctl.pointer = (unsigned char*) font; + + return ioctl (dpy->fd, FBIO_UI_CONTROL, (unsigned long) &ctl) < 0 ? -errno : 0; +} + + +int +fbui_clear (Display *dpy, Window *win) +{ + int result=0; + + if (!dpy || !win) return -1; + /*---------------*/ + if (result = check_flush (dpy, win,1)) + return result; + + win->command [win->command_ix++] = FBUI_CLEAR; + + return 0; +} + +int +fbui_draw_rect (Display *dpy, Window *win, short x0, short y0, short x1, short y1, unsigned long color) +{ + int result=0; + + if (!dpy || !win) return -1; + /*---------------*/ + if (result = check_flush (dpy, win,7)) + return result; + + win->command [win->command_ix++] = FBUI_RECT; + win->command [win->command_ix++] = x0; + win->command [win->command_ix++] = y0; + win->command [win->command_ix++] = x1; + win->command [win->command_ix++] = y1; + win->command [win->command_ix++] = color; + win->command [win->command_ix++] = color>>16; + + return 0; +} + +int +fbui_fill_area (Display *dpy, Window *win, short x0, short y0, short x1, short y1, unsigned long color) +{ + int result=0; + + if (!dpy || !win) return -1; + /*---------------*/ + if (result = check_flush (dpy, win,7)) + return result; + + win->command [win->command_ix++] = FBUI_FILLAREA; + win->command [win->command_ix++] = x0; + win->command [win->command_ix++] = y0; + win->command [win->command_ix++] = x1; + win->command [win->command_ix++] = y1; + win->command [win->command_ix++] = color; + win->command [win->command_ix++] = color>>16; + + return 0; +} + +int +fbui_clear_area (Display *dpy, Window *win, short x0, short y0, short x1, short y1) +{ + int result=0; + + if (!dpy || !win) return -1; + /*---------------*/ + if (result = check_flush (dpy, win,5)) + return result; + + win->command [win->command_ix++] = FBUI_CLEARAREA; + win->command [win->command_ix++] = x0; + win->command [win->command_ix++] = y0; + win->command [win->command_ix++] = x1; + win->command [win->command_ix++] = y1; + + return 0; +} + +int +fbui_copy_area (Display *dpy, Window *win, short xsrc, short ysrc, short xdest, short ydest, short w, short h) +{ + int result=0; + + if (!dpy || !win) return -1; + /*---------------*/ + if (result = check_flush (dpy, win,7)) + return result; + + win->command [win->command_ix++] = FBUI_COPYAREA; + win->command [win->command_ix++] = xsrc; + win->command [win->command_ix++] = ysrc; + win->command [win->command_ix++] = xdest; + win->command [win->command_ix++] = ydest; + win->command [win->command_ix++] = w; + win->command [win->command_ix++] = h; + + return 0; +} + +int +fbui_put (Display *dpy, Window *win, short x, short y, short n, unsigned char *p) +{ + int result=0; + + if (!dpy || !win || !p) return -1; + /*---------------*/ + if (result = check_flush (dpy, win,6)) + return result; + + win->command [win->command_ix++] = FBUI_PUT; + win->command [win->command_ix++] = x; + win->command [win->command_ix++] = y; + win->command [win->command_ix++] = (unsigned long)p; + win->command [win->command_ix++] = ((unsigned long)p)>>16; + win->command [win->command_ix++] = n; + + return 0; +} + +int +fbui_put_rgb (Display *dpy, Window *win, short x, short y, short n, unsigned long *p) +{ + int result=0; + + if (!dpy || !win || !p) return -1; + /*---------------*/ + if (result = check_flush (dpy, win,6)) + return result; + + win->command [win->command_ix++] = FBUI_PUTRGB; + win->command [win->command_ix++] = x; + win->command [win->command_ix++] = y; + win->command [win->command_ix++] = (unsigned long) p; + win->command [win->command_ix++] = ((unsigned long) p) >>16; + win->command [win->command_ix++] = n; + + return 0; +} + +int +fbui_put_rgb3 (Display *dpy, Window *win, short x, short y, short n, unsigned char *p) +{ + int result=0; + + if (!dpy || !win || !p) return -1; + /*---------------*/ + if (result = check_flush (dpy, win,6)) + return result; + + win->command [win->command_ix++] = FBUI_PUTRGB3; + win->command [win->command_ix++] = x; + win->command [win->command_ix++] = y; + win->command [win->command_ix++] = (unsigned long) p; + win->command [win->command_ix++] = ((unsigned long) p) >>16; + win->command [win->command_ix++] = n; + + return 0; +} + + +int +fbui_window_close (Display *dpy, Window *win) +{ + int r; + + if (!dpy || !win) return -1; + /*---------------*/ + // fbui_flush (dpy, win); + + r = ioctl (dpy->fd, FBIO_UI_CLOSE, win->id); + + Window *prev = NULL; + Window *ptr = dpy->list; + while (ptr) { + if (win == ptr) + break; + prev = ptr; + ptr = ptr->next; + } + if (ptr) { + if (!prev) + dpy->list = win->next; + else + prev->next = win->next; + } + + free (win); + return r; +} + + + +// key info that comes from FBUI : bits 0-1= state 2-15=keycode +int +fbui_convert_key (Display *dpy, long keyinfo) +{ + int key,state; + unsigned short ch=0; + + if (!dpy) return -1; + /*---------------*/ + + state = 3 & keyinfo; + key = keyinfo >> 2; + + switch (key) { + case KEY_RIGHTSHIFT: + case KEY_LEFTSHIFT: + dpy->shift = state>0; + return 0; + + case KEY_RIGHTCTRL: + case KEY_LEFTCTRL: + dpy->ctrl = state>0; + return 0; + + case KEY_RIGHTALT: + case KEY_LEFTALT: + dpy->alt = state>0; + return 0; + } + + if (state==0) + return 0; + + switch (key) { + case KEY_ENTER: ch = '\n'; break; + case KEY_ESC: ch = 27; break; + case KEY_SPACE: ch = ' '; break; + case KEY_MINUS: ch = !dpy->shift ? '-' : '_'; break; + case KEY_EQUAL: ch = !dpy->shift ? '=' : '+'; break; + case KEY_BACKSPACE: ch = 8; break; + case KEY_SEMICOLON: ch = !dpy->shift ? ';' : ':'; break; + case KEY_COMMA: ch = !dpy->shift ? ',' : '<'; break; + case KEY_DOT: ch = !dpy->shift ? '.' : '>'; break; + case KEY_GRAVE: ch = !dpy->shift ? '`' : '~'; break; + case KEY_BACKSLASH: ch = !dpy->shift ? '\\' : '|'; break; + case KEY_LEFTBRACE: ch = !dpy->shift ? '[' : '{'; break; + case KEY_RIGHTBRACE: ch = !dpy->shift ? ']' : '}'; break; + case KEY_APOSTROPHE: ch = !dpy->shift ? '\'' : '"'; break; + case KEY_SLASH: ch = !dpy->shift ? '/' : '?'; break; + case KEY_TAB: ch = !dpy->shift ? '\t' : FBUI_LEFTTAB; break; + case KEY_A: ch = 'a'; break; + case KEY_B: ch = 'b'; break; + case KEY_C: ch = 'c'; break; + case KEY_D: ch = 'd'; break; + case KEY_E: ch = 'e'; break; + case KEY_F: ch = 'f'; break; + case KEY_G: ch = 'g'; break; + case KEY_H: ch = 'h'; break; + case KEY_I: ch = 'i'; break; + case KEY_J: ch = 'j'; break; + case KEY_K: ch = 'k'; break; + case KEY_L: ch = 'l'; break; + case KEY_M: ch = 'm'; break; + case KEY_N: ch = 'n'; break; + case KEY_O: ch = 'o'; break; + case KEY_P: ch = 'p'; break; + case KEY_Q: ch = 'q'; break; + case KEY_R: ch = 'r'; break; + case KEY_S: ch = 's'; break; + case KEY_T: ch = 't'; break; + case KEY_U: ch = 'u'; break; + case KEY_V: ch = 'v'; break; + case KEY_W: ch = 'w'; break; + case KEY_X: ch = 'x'; break; + case KEY_Y: ch = 'y'; break; + case KEY_Z: ch = 'z'; break; + case KEY_0: ch = '0'; break; + case KEY_1: ch = '1'; break; + case KEY_2: ch = '2'; break; + case KEY_3: ch = '3'; break; + case KEY_4: ch = '4'; break; + case KEY_5: ch = '5'; break; + case KEY_6: ch = '6'; break; + case KEY_7: ch = '7'; break; + case KEY_8: ch = '8'; break; + case KEY_9: ch = '9'; break; + + /* special chars section */ + case KEY_UP: ch = FBUI_UP; break; + case KEY_DOWN: ch = FBUI_DOWN; break; + case KEY_LEFT: ch = FBUI_LEFT; break; + case KEY_RIGHT: ch = FBUI_RIGHT; break; + + case KEY_INSERT: ch = FBUI_INS; break; + case KEY_DELETE: ch = FBUI_DEL; break; + case KEY_HOME: ch = FBUI_HOME; break; + case KEY_END: ch = FBUI_END; break; + case KEY_PAGEUP: ch = FBUI_PGUP; break; + case KEY_PAGEDOWN: ch = FBUI_PGDN; break; + case KEY_SCROLLLOCK: ch = FBUI_SCRLK; break; + case KEY_NUMLOCK: ch = FBUI_NUMLK; break; + case KEY_CAPSLOCK: ch = FBUI_CAPSLK; break; + + case KEY_PRINT: ch = FBUI_PRTSC; break; + + case KEY_F1: ch = FBUI_F1; break; + case KEY_F2: ch = FBUI_F2; break; + case KEY_F3: ch = FBUI_F3; break; + case KEY_F4: ch = FBUI_F4; break; + case KEY_F5: ch = FBUI_F5; break; + case KEY_F6: ch = FBUI_F6; break; + case KEY_F7: ch = FBUI_F7; break; + case KEY_F8: ch = FBUI_F8; break; + case KEY_F9: ch = FBUI_F9; break; + case KEY_F10: ch = FBUI_F10; break; + case KEY_F11: ch = FBUI_F11; break; + case KEY_F12: ch = FBUI_F12; break; + + /* mouse buttons */ + case BTN_LEFT: ch = FBUI_BUTTON_LEFT; break; + case BTN_RIGHT: ch = FBUI_BUTTON_RIGHT; break; + case BTN_MIDDLE: ch = FBUI_BUTTON_MIDDLE; break; + } + + if (dpy->ctrl && isalpha(ch)) + ch &= 31; + else + if (dpy->shift && isalpha(ch)) + ch = toupper(ch); + + if (dpy->shift && isdigit(ch)) { + switch (ch) { + case '0': ch = ')'; break; + case '1': ch = '!'; break; + case '2': ch = '@'; break; + case '3': ch = '#'; break; + case '4': ch = '$'; break; + case '5': ch = '%'; break; + case '6': ch = '^'; break; + case '7': ch = '&'; break; + case '8': ch = '*'; break; + case '9': ch = '('; break; + } + } + + return ch; +} + + +int +fbui_poll_event (Display *dpy, Event *e, unsigned short mask) +{ + Window *win; + short win_id; + long retval; + + if (!dpy || !e) + return -1; + /*---------------*/ + win = dpy->list; + while (win) { + fbui_flush (dpy, win); + win = win->next; + } + + memset (e, 0, sizeof(Event)); + + struct fbui_event event; + struct fbui_ctrlparams ctl; + memset (&ctl, 0, sizeof (struct fbui_ctrlparams)); + ctl.op = FBUI_POLLEVENT; + ctl.id = dpy->list ? dpy->list->id : -1; /* window id not required but faster */ + ctl.x = (short)mask; + ctl.event = &event; + retval = ioctl (dpy->fd, FBIO_UI_CONTROL, &ctl); + + if (retval < 0) + return -errno; + + e->type = event.type; + e->id = win_id = event.id; + e->key = event.key; + e->x = event.x; + e->y = event.y; + e->width = event.width; + e->height = event.height; + + win = dpy->list; + while (win) { + if (win->id == win_id) + break; + win = win->next; + } + e->win = win; + + if (!win) + fprintf(stderr, "libfbui: cannot identify window for id %d\n", win_id); + else + if (event.type == FBUI_MOVE_RESIZE) { + win->width = event.width; + win->height = event.height; + } + + return 0; +} + +int +fbui_wait_event (Display *dpy, Event *e, unsigned short mask) +{ + Window *win; + + if (!dpy || !e) + return -1; + /*---------------*/ + + win = dpy->list; + while (win) { + fbui_flush (dpy, win); + win = win->next; + } + + memset (e, 0, sizeof(Event)); + + struct fbui_event event; + struct fbui_ctrlparams ctl; + memset (&ctl, 0, sizeof (struct fbui_ctrlparams)); + ctl.op = FBUI_WAITEVENT; + ctl.id = dpy->list ? dpy->list->id : -1; /* window id not required but faster */ + ctl.x = (short)mask; + ctl.event = &event; + int retval = ioctl (dpy->fd, FBIO_UI_CONTROL, &ctl); + + if (retval < 0) + return -errno; + + e->type = event.type; + short win_id = event.id; + e->id = win_id; + e->key = event.key; + e->x = event.x; + e->y = event.y; + e->width = event.width; + e->height = event.height; + + win = dpy->list; + while (win) { + if (win->id == win_id) + break; + win = win->next; + } + e->win = win; + + if (!win) + fprintf(stderr, "libfbui: cannot identify window for id %d\n", win_id); + else + if (event.type == FBUI_MOVE_RESIZE) { + win->width = event.width; + win->height = event.height; + } + + + return 0; +} + +int +fbui_get_dims (Display *dpy, Window *win, short *width, short *height) +{ + long result; + + if (!dpy || !win || !width || !height) + return -1; + /*---------------*/ + + fbui_flush (dpy, win); + + *width = 0; + *height = 0; + + struct fbui_ctrlparams ctl; + memset (&ctl, 0, sizeof (struct fbui_ctrlparams)); + ctl.op = FBUI_GETDIMS; + ctl.id = win->id; + + result = ioctl (dpy->fd, FBIO_UI_CONTROL, &ctl); +//printf ("getdims retval %d (%d)\n",result,-errno); + if (result < 0) + return -errno; + + *width = result >> 16; + *height = result & 0xffff; + + win->width = *width; + win->height = *height; + + return 0; +} + + +/* note: mouse buttons appear as keystrokes */ +int +fbui_read_mouse (Display *dpy, Window *win, short *x, short *y) +{ + long result; + + if (!dpy || !win || !x || !y) + return -1; + /*---------------*/ + + fbui_flush (dpy, win); + + *x = 0; + *y = 0; + + struct fbui_ctrlparams ctl; + memset (&ctl, 0, sizeof (struct fbui_ctrlparams)); + ctl.op = FBUI_READMOUSE; + ctl.id = win->id; + + result = ioctl (dpy->fd, FBIO_UI_CONTROL, &ctl); + if (result < 0) + return result; + + *x = result >> 16; + *y = result & 0xffff; + + return 0; +} + + +int +fbui_get_position (Display *dpy, Window *win, short *x, short *y) +{ + unsigned long result; + + if (!dpy || !win || !x || !y) + return -1; + /*---------------*/ + + fbui_flush (dpy, win); + + *x = -1; + *y = -1; + + struct fbui_ctrlparams ctl; + memset (&ctl, 0, sizeof (struct fbui_ctrlparams)); + ctl.op = FBUI_GETPOSN; + + result = ioctl (dpy->fd, FBIO_UI_CONTROL, &ctl); + if (result < 0) + return 0; + + *x = result >> 16; + *y = result & 0xffff; + + return 1; +} + +static void kill_handler (int foo) +{ + if (my_dpy) { + Window *win = my_dpy->list; + while (win) { + Window *next = win->next; + fbui_window_close (my_dpy, win); + win = next; + } + my_dpy->list = NULL; + fbui_display_close (my_dpy); + } + exit(-1); +} + +static int hex_to_int (char h) +{ + h = tolower(h); + if (h >= '0' && h <= '9') + return h - '0'; + else + if (h >= 'a' && h <= 'f') + return 10 + h - 'a'; + else + return 0; +} + +static long parse_rgb (char *s) +{ + int len; + long c; + if (!s) return -1; + len = strlen (s); + if (len == 3) { + c = hex_to_int (*s++); + c <<= 8; + c |= hex_to_int (*s++); + c <<= 8; + c |= hex_to_int (*s++); + c <<= 4; + return c; + } + if (len == 6) { + c = hex_to_int (*s++); + c <<= 4; + c |= hex_to_int (*s++); + c <<= 4; + c |= hex_to_int (*s++); + c <<= 4; + c |= hex_to_int (*s++); + c <<= 4; + c |= hex_to_int (*s++); + c <<= 4; + c |= hex_to_int (*s++); + return c; + } + return -1; +} + + +static int +getline (FILE *f, char *buf, int buflen) +{ + int got; + char ch; + int ix=0; + + buf[0] = 0; + + while (ix < (buflen-1)) { + got = fread (&ch, 1, 1, f); + + if (!got) + break; + + if (ch == '\n') + break; + if (ch == '\r') + continue; + + buf [ix++] = ch; + } + + buf [ix] = 0; + return ix; +} + +long +parse_colorname (char *s) +{ + if (!strcmp(s, "red")) + return RGB_RED; + if (!strcmp(s, "green")) + return RGB_GREEN; + if (!strcmp(s, "blue")) + return RGB_BLUE; + if (!strcmp(s, "black")) + return 0; + if (!strcmp(s, "white")) + return 0xffffff; + if (!strcmp(s, "steelblue")) + return RGB_STEELBLUE; + if (!strcmp(s, "sienna")) + return RGB_SIENNA; + if (!strcmp(s, "cyan")) + return RGB_CYAN; + if (!strcmp(s, "orange")) + return RGB_ORANGE; + if (!strcmp(s, "yellow")) + return RGB_YELLOW; + if (!strcmp(s, "magenta")) + return RGB_MAGENTA; + if (!strcmp(s, "purple")) + return RGB_PURPLE; + if (!strcmp(s, "brown")) + return RGB_BROWN; + if (!strcmp(s, "gray")) + return RGB_GRAY; + + FILE *f = fopen ("/usr/X11/lib/X11/rgb.txt","r"); + char buffer [200]; + if (!f) return -1; + while (getline (f, buffer, 199)) { + int r,g,b; + char name[100]; + if (4 == sscanf(buffer,"%u %u %u %s", &r, &g, &b, name)) { + if (!strcmp (s, name)) { + long color; + r &= 0xff; + g &= 0xff; + b &= 0xff; + color = r; + color <<= 8; + color |= g; + color <<= 8; + color |= b; + fclose(f); + return color; + } + } + } + fclose(f); + + return -1; +} + + +/* not static since it's used by fbterm */ + +int fbui_parse_geom (char *s1, short *w, short *h, short *xr, short *yr) +{ + short width=0,height=0,xrel=-1,yrel=-1; + char *s2 = NULL; + char *s3 = NULL; + char *s4 = NULL; + + if (!s1 || !w || !h || !xr || !yr) + return 0; + /*---------------*/ + + if (*s1 && isdigit(*s1)) { + char *s2 = strchr (s1, 'x'); + if (!s2) + return 0; + *s2++ = 0; + + s3 = s2; + while (*s3 && isdigit(*s3)) + s3++; + + if (*s3) { + xrel = *s3=='-' ? -1 : 1; + *s3++ = 0; + + s4 = s3; + while (*s4 && isdigit(*s4)) + s4++; + + if (s4) { + yrel = *s4=='-' ? -1 : 1; + *s4++ = 0; + } + } else { + xrel = 9999; /* no position given */ + s3 = NULL; + } + + width = atoi(s1); + height = atoi(s2); + + if (s3 && s4) { + int a = atoi(s3); + int b = atoi(s4); + if (xrel == 1) { + xrel = a; + } else { + xrel = -a - 1; + } + if (yrel == 1) { + yrel = b; + } else { + yrel = -b - 1; + } + } else { + xrel = 9999; + } + *w = width; + *h = height; + *xr = xrel; + *yr = yrel; + return 1; + } else + return 0; +} + + +void +fbui_display_close (Display* dpy) +{ + if (dpy) { + Window *win = dpy->list; + while (win) { + fbui_window_close (dpy, win); + win = win->next; + } + close (dpy->fd); + free (dpy); + } +} + +Display* +fbui_display_open () +{ + Display *dpy = NULL; + int success=0; + int fd; + + if (my_dpy) + FATAL ("attempt to re-init"); + + fd = open ("/dev/fb0", O_RDWR ); + if (fd < 0) + fd = open ("/dev/fb/0", O_RDWR ); + display_fd = fd; + if (fd < 0) + { + success= 0; + perror("open"); + errlog(__FUNCTION__, "Open failed"); + } + else + { + if (ioctl (fd, FBIOGET_FSCREENINFO, &fi)) + { + perror("ioctl"); + success= 0; + errlog(__FUNCTION__, "ioctl1 failed"); + } + else + if (ioctl (fd, FBIOGET_VSCREENINFO, &vi)) + { + perror("ioctl"); + success= 0; + errlog(__FUNCTION__, "ioctl2 failed"); + } + else + { + if (fi.visual != FB_VISUAL_TRUECOLOR && + fi.visual != FB_VISUAL_DIRECTCOLOR ) + { + FATAL ("Oops, we need a direct/truecolor display"); + success= 0; + errlog(__FUNCTION__, "wrong visual"); + } + else + { + printf ("Framebuffer resolution: %dx%d, %dbpp\n", vi.xres, vi.yres, vi.bits_per_pixel); + + success = 1; + } + } + } + + if (success) { + dpy = (Display*) malloc (sizeof(Display)); + if (!dpy) { + fprintf (stderr, "out of memory\n"); + return NULL; + } + + my_dpy = dpy; + memset ((void*)dpy, 0, sizeof(Display)); + dpy->fd = fd; + + dpy->width = vi.xres; + dpy->height = vi.yres; + dpy->depth = vi.bits_per_pixel; + + dpy->red_offset = vi.red.offset; + dpy->green_offset = vi.green.offset; + dpy->blue_offset = vi.blue.offset; + dpy->red_length = vi.red.length; + dpy->green_length = vi.green.length; + dpy->blue_length = vi.blue.length; + + signal (SIGTERM, kill_handler); + signal (SIGINT, kill_handler); + signal (SIGSEGV, kill_handler); + } + return dpy; +} + +Window* +fbui_window_open (Display *dpy, + short width, short height, + short *width_return, short *height_return, + short max_width, short max_height, + short xrel, short yrel, + unsigned long *fgcolor_inout, + unsigned long *bgcolor_inout, + char *name, char *subtitle, + char program_type, + char request_control, + char doing_autopositioning, + char vc_, + char need_keys, + char receive_all_motion, + char initially_hidden, + int argc, char **argv) +{ + int i; + char vc=-1; + long fgcolor; + long bgcolor; + Window *win = NULL; + char force_type = -1; + + if (!dpy || !name || !width_return || !height_return || + !fgcolor_inout || !bgcolor_inout) + { + WARNING ("null param"); + return NULL; + } + /*---------------*/ + fgcolor = *fgcolor_inout; + bgcolor = *bgcolor_inout; + + i=1; + if (argv) + while(i < argc) { + char *str = argv[i]; + if (!strncmp(str, "-type=",6)) { + char *tstr = str+6; + if (!strcmp (tstr, "app")) + force_type = FBUI_PROGTYPE_APP; + else if (strcmp (tstr, "launcher")) + force_type = FBUI_PROGTYPE_LAUNCHER; + else if (strcmp (tstr, "tool")) + force_type = FBUI_PROGTYPE_TOOL; + else if (strcmp (tstr, "emphemeral")) + force_type = FBUI_PROGTYPE_EPHEMERAL; + else if (strcmp (tstr, "none")) + force_type = FBUI_PROGTYPE_NONE; + } + else if (!strncmp(str, "-geo",4)) { + int ch = str[4]; + char *values=NULL; + *str = 0; + if (ch && isdigit(ch)) { + values = str+4; + } else { + if (i != (argc-1)) { + values = argv[++i]; + argv[i][0] = 0; + } + } + + if (values) { + short w,h,xr,yr; + if (fbui_parse_geom (values,&w,&h,&xr,&yr)) { + width = w; + height = h; + if (xr != 9999) { + xrel = xr; + yrel = yr; + } + } + } + } + else + if (!strncmp (str, "-bg", 3) || !strncmp(str, "-fg",3)) { + char *s = 3 + str; + char which = str[1]; + char ch = *s; + long color = -1; + *str = 0; + if (ch == '=') + ch = *++s; + if (!ch) { + s = argv[++i]; + ch = s ? *s : 0; + } + if (ch == '#') { + color = parse_rgb (s+1); + } + else if (ch) { + color = parse_colorname (s); + } + if (color != -1) { + if (which == 'f') + fgcolor = color; + else + bgcolor = color; + } + argv[i][0] = 0; + } + else + if (!strncmp(str, "-c",2)) { + char *s = 2 + str; + if (*s && isdigit(*s)) { + vc = atoi(s); + *str = 0; + } else { + *str = 0; + if (i != (argc-1)) { + vc = atoi(argv[++i]); + *argv[i] = 0; + } else { + fprintf(stderr, "Usage: %s [-cCONSOLE#] [-fgCOLOR] [-bgCOLOR]\n", argv[0]); + } + } + } + i++; + } + if (vc_ != -1 && vc == -1) + vc = vc_; + + if (width > max_width) + width = max_width; + if (height > max_height) + height = max_height; + + int result; + + oi.req_control = request_control ? 1 : 0; + oi.x0 = xrel >= 0 ? xrel : vi.xres + xrel + 1 - width; + oi.y0 = yrel >= 0 ? yrel : vi.yres + yrel + 1 - height; + oi.x1= oi.x0 + width - 1; + oi.y1= oi.y0 + height - 1; + oi.max_width = max_width; + oi.max_height = max_height; + oi.bgcolor = bgcolor; + oi.initially_hidden = initially_hidden; + *fgcolor_inout = fgcolor; + *bgcolor_inout = bgcolor; +printf ("vc=%d\n",vc); + oi.desired_vc = vc; + oi.doing_autoposition = doing_autopositioning ? 1 : 0; + oi.need_keys = need_keys ? 1 : 0; + oi.receive_all_motion = receive_all_motion ? 1 : 0; + oi.program_type = force_type >= 0 ? force_type : program_type; + strncpy (oi.name, name, FBUI_NAMELEN); + strncpy (oi.subtitle, subtitle, FBUI_NAMELEN); + result = ioctl (dpy->fd, FBIO_UI_OPEN, &oi); + if (result < 0) + { + char expr[100]; + sprintf (expr, "errcode %d\n",result); + errlog(__FUNCTION__, expr); + return NULL; + } + + win = (Window*) malloc (sizeof(Window)); + if (!win) + FATAL ("out of memory"); + memset (win, 0, sizeof (Window)); + + win->id = result; + win->command_ix = 2; + win->next = dpy->list; + dpy->list = win; + + short w,h; + + while (fbui_get_dims (dpy, win, &w, &h)) { + printf ("%s: waiting for window dimensions\n", __FUNCTION__); + sleep (1); + } + + *width_return = w; + *height_return = h; + + return win; +} + + +Font * +font_new (void) +{ + Font *nu; + nu = (Font*) malloc(sizeof (Font)); + if (!nu) + FATAL("out of memory") + else + { + memset ((void*) nu, 0, sizeof (Font)); + nu->bitmap_buffer = NULL; + // nu->dpi = 0; + nu->ascent = 0; + nu->descent = 0; + } + return nu; +} + +void +font_free (Font* font) +{ + int i; + if (!font) + return; // error + + if (font->lefts) + free ((void*) font->lefts); + if (font->widths) + free ((void*) font->widths); + if (font->descents) + free ((void*) font->descents); + if (font->widths) + free ((void*) font->widths); + if (font->heights) + free ((void*) font->heights); + if (font->bitmaps) + free ((void*) font->bitmaps); + + free ((void*)font); +} + + +void +font_char_dims (Font *font, uchar ch, short *w, short *asc, short *desc) +{ + if (!font || !w || !asc || !desc) + return; // error + + ch -= font->first_char; + *w = font->widths[ch]; + *asc = font->ascent; + *desc = font->descent; +} + + +void +font_string_dims (Font *font, unsigned char *str, short *w, short *a, short *d) +{ + if (!font || !str || !w || !a || !d) + return; // error + + short w0 = 0; + int ch; + + while ((ch = *str++)) { + ch -= font->first_char; + if (ch >= 0) + w0 += font->widths [ch]; + } + + *w = w0; + *a = font->ascent; + *d = font->descent; +} + + + +static uchar bit_reversal_array [256] = +{ +0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, 0x15, 0x95, +0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff, +}; + + +#define ZZ(a,b,c,d) ((((unsigned long)d)<<24)|(((unsigned long)c)<<16)|(((unsigned short)b)<<8)|a) + + +inline unsigned long ULONG(char endian, unsigned char* pp) +{ + if (endian) + return (((unsigned long)pp[0]) << 24) | (((unsigned long)pp[1]) << 16) | (((unsigned short)pp[2]) << 8) | pp[3]; + else + return (((unsigned long)pp[3]) << 24) | (((unsigned long)pp[2]) << 16) | (((unsigned short)pp[1]) << 8) | pp[0]; +} + + +inline unsigned short USHORT(char endian, unsigned char* pp) +{ + unsigned short i; + + if (endian) + i = (((unsigned short)pp[0]) << 8) | pp[1]; + else + i = (((unsigned short)pp[1]) << 8) | pp[0]; + + return i; +} + + +enum { + PCF_PROPS = 1, + PCF_ACCEL = 2, + PCF_METRICS = 4, + PCF_BITMAPS = 8, + PCF_INK_METRICS = 16, + PCF_BDF_ENCODINGS = 32, + PCF_SWIDTHS = 64, + PCF_GLYPH_NAMES = 128, + PCF_BDF_ACCEL = 256, + +}; + +enum { + PCF_BIG_ENDIAN = (1<<2), + PCF_COMPRESSED = 256, +}; + +// A pcf that is "compressed" has smaller metrics info +// but the bitmap data is the same. + + +static unsigned char *read_buffer = NULL; + +char +pcf_read_encodings (Font* pcf, unsigned char* orig) +{ + unsigned char *ptr = orig; + unsigned long format; + char endian; + + format = ULONG(0,ptr); ptr += 4; + endian = (format & PCF_BIG_ENDIAN) ? true : false; + + ptr += 2; // skip: first column + ptr += 2; // skip: last column + + ptr += 2; // skip: first row + ptr += 2; // skip: last row + + // read default char + + unsigned short defaultChar = USHORT(endian,ptr); ptr += 2; + unsigned short numChars = USHORT(endian,ptr); ptr += 2; + +#if 0 + printf ("pcf_read_encodings(): default char = %d, num chars = %d\n", + pcf->first_char, numChars); +#endif + + /* kludge */ + pcf->first_char = 31; + pcf->last_char = 255; + + return true; +} + + +char +pcf_read_bitmaps (Font* pcf, unsigned char* orig) +{ + unsigned char *ptr = orig; + unsigned long format; + char endian; + char compressed; + unsigned long nChars; + int i, j; + unsigned char *offsets; + + format = ULONG(0,ptr); ptr += 4; + endian = (format & PCF_BIG_ENDIAN) ? true : false; + compressed = (format & PCF_COMPRESSED) ? true : false; + + int storage_unit = (format >> 4) & 3; + int row_unit = format & 3; + int bit_order = format & 8; + + nChars = ULONG(endian,ptr); ptr += 4; + if (pcf->nchars) + { + if (pcf->nchars != nChars) + FATAL ("#metrics != #chars"); + } + else + { + pcf->nchars = nChars; + } + + offsets = ptr; + ptr += 4 * nChars; + + unsigned char *ptr2 = ptr + 4 * (3 & format); + unsigned long data_size = ULONG(endian,ptr2); + + ptr += 16; + + pcf->bitmap_buffer = malloc (data_size); + if (!pcf->widths) + { + pcf->lefts = malloc (nChars); + pcf->widths = malloc (nChars); + pcf->bitwidths = malloc (nChars); + pcf->descents = malloc (nChars); + pcf->heights = malloc (nChars); + + if (!pcf->lefts || !pcf->heights) + FATAL ("out of memory"); + } + + pcf->bitmaps = malloc (nChars * sizeof(char*)); + + if (!pcf->bitmap_buffer || !pcf->lefts || !pcf->widths || !pcf->heights + || !pcf->bitmaps) + FATAL ("unable to allocate font data"); + + // Copy over bitmap data. + for (i=0; i < data_size; i++) + { + pcf->bitmap_buffer[i] = ptr[i]; + } + + // Need to ensure that the leftmost font bit is bit 7. + // + if (!bit_order) + { + unsigned char *p = pcf->bitmap_buffer; + i = data_size; + while (i--) { + *p++ = bit_reversal_array[*p]; + } + } + + // Need to re-order the bytes to make them + // little-endian, if they were written in big-endian format. + // + unsigned char *p; + switch (row_unit) { + default: + case 0: // row = 1 byte + break; + + case 1: // row = 1 short + if (storage_unit == 0 && endian) { + unsigned char *p = pcf->bitmap_buffer; + i = nChars / 2; + while (i) + { + int tmp = *p; + *p = *(p+1); + *++p = tmp; + i--; + } + } + break; + + case 2: // row = 1 long + if (endian) { + switch (storage_unit) { + case 0: + p = pcf->bitmap_buffer; + i = nChars / 4; + while (i) + { + int tmp = *p; + *p = *(p+3); + *(p+3) = tmp; + + p++; + tmp = *p; + *p = *(p+1); + *(p+1) = tmp; + + p += 3; + + i--; + } + break; + case 1: + p = pcf->bitmap_buffer; + i = nChars / 4; + while (i) + { + int tmp = *p; + int tmp2 = *(p+1); + *p = *(p+2); + *(p+1) = *(p+3); + *(p+2) = tmp; + *(p+3) = tmp2; + + p += 4; + + i--; + } + break; + default: + break; + } + } + break; + } + + // Now generate pointers for character data. + // + j = 8 << row_unit; + + for (i=0; i < nChars; i++) + { + unsigned long offset = ULONG(endian,offsets); offsets += 4; + pcf->bitmaps [i] = pcf->bitmap_buffer + offset; + pcf->bitwidths [i] = j; + } + + return true; +} + + +char +pcf_read_metrics (Font* pcf, unsigned char* orig) +{ + unsigned char *ptr = orig; + unsigned long format; + char endian; + char compressed; + unsigned long nMetrics; + int i; + + format = ULONG(0,ptr); ptr += 4; + endian = (format & PCF_BIG_ENDIAN) ? true : false; + compressed = (format & PCF_COMPRESSED) ? true : false; + + if (compressed) + { + nMetrics = USHORT(endian,ptr); + ptr += 2; + } + else + { + nMetrics = ULONG(endian,ptr); + ptr += 4; + } + + if (!pcf->nchars && !pcf->widths) + { + pcf->lefts = malloc (nMetrics); + pcf->widths = malloc (nMetrics); + pcf->bitwidths = malloc (nMetrics); + pcf->descents = malloc (nMetrics); + pcf->heights = malloc (nMetrics); + + if (!pcf->lefts || !pcf->heights) + FATAL ("out of memory"); + } + + if (compressed) + { + for (i=0; i < nMetrics; i++) + { + pcf->lefts[i] = ((short)*ptr++) - 0x80; + ptr++; // skip right-bearing + pcf->widths[i] = ((short)*ptr++) - 0x80; + pcf->heights [i] = ((short)*ptr++) - 0x80; // get ascent + pcf->descents[i] = ((short)*ptr++) - 0x80; + pcf->heights [i] += pcf->descents[i]; // height=ascent+descent + // There is no attr byte in compressed version. + + pcf->bitwidths[i] = pcf->widths[i]; + +#if 0 +printf ("char %c(%d): w=%d ht=%d desc=%d\n", i+32,i+32, pcf->widths[i], pcf->heights[i], pcf->descents[i]); +#endif + } + } + else + { + for (i=0; i < nMetrics; i++) + { + pcf->lefts [i] = USHORT (endian,ptr); ptr += 2; + ptr += 2; + pcf->widths[i] = USHORT (endian,ptr); ptr += 2; + pcf->heights [i] = USHORT (endian,ptr); ptr += 2; + pcf->descents[i] = USHORT (endian,ptr); ptr += 2; + ptr += 2; // skip attr word + + pcf->bitwidths[i] = pcf->widths[i]; + } + } + + return true; +} + +char +pcf_read_accelerator (Font* pcf, unsigned char* orig) +{ + unsigned char *ptr = orig; + unsigned long format; + char endian; + int i; + + format = ULONG(0,ptr); ptr += 4; + endian= (format & PCF_BIG_ENDIAN) ? 1 : 0; + + ptr += 8; + + pcf->ascent = ULONG(endian,ptr); ptr += 4; + pcf->descent = ULONG(endian,ptr); ptr += 4; + +// printf ("ascent = %u , descent = %d\n", ascent, descent); + + return true; +} + + + +char +pcf_read_properties (Font* pcf, unsigned char* orig) +{ + unsigned char *ptr = orig; + unsigned long format, nprops; + char endian; + int i; + + format = ULONG(0,ptr); ptr += 4; + endian = (format & PCF_BIG_ENDIAN) ? 1 : 0; + nprops = ULONG(endian,ptr); ptr += 4; + + unsigned char* str_buffer = ptr + nprops*9 + 4; + +// printf ("format=%08lx\n", format); +// printf ("nprops=%08lx\n", nprops); + + i = ((unsigned long)str_buffer) & 3; + if (i) str_buffer += (4-i); + + for (i = 0; i < nprops; i++) + { + unsigned long name = ULONG(endian,ptr); ptr += 4; + unsigned char is_string = *ptr++; + unsigned long value = ULONG(endian,ptr); ptr += 4; + + char *str = ((char*)str_buffer) + name; + if (is_string) + { + char *str2 = ((char*)str_buffer) + value; + + switch (*str) { + + case 'F': + + if (!strcmp ("FAMILY_NAME", str)) + { +//printf ("family-name=%s\n", str2); +#if 0 + if (strlen (str2) < 63) + strcpy (pcf->family, str2); + else + strncpy (pcf->family, str2, 63); +#endif + } + else + if (!strcmp ("FULL_NAME", str)) + { +//printf ("full-name=%s\n", str2); +#if 0 + if (strlen (str2) < 63) + strcpy (pcf->fullname, str2); + else + strncpy (pcf->fullname, str2, 63); +#endif + } + break; + + case 'C': + + if (!strcmp ("CHARSET_REGISTRY", str)) + { +// printf ("charset registry=%s\n", str2); +#if 0 + if (strcmp ("ISO8859", str2)) + return false; +#endif + } + break; + + case 'S': + + if (!strcmp ("SLANT", str)) + { +//printf ("slant=%s\n", str2); +#if 0 + char angle=*str2; + if (angle=='R') + pcf->italic=0; + else + pcf->italic=1; +#endif + } + break; + + case 'W': + + if (!strcmp ("WEIGHT_NAME", str)) + { +//prf ("weight-name=%s\n", str2); +#if 0 + if (!strcmp(str2, "Bold")) { + pcf->weight = FONT_WEIGHT_BOLD; + } + else + if (!strcmp(str2, "Medium")) { + pcf->weight = FONT_WEIGHT_MEDIUM; + } + else + pcf->weight = FONT_WEIGHT_MEDIUM; +#endif + } + break; + + default: + break; + + //printf ("\tunused property name(%ld) %s value(%ld) %s\n", + // name, str, value, str2); + } + } + else + { + switch (*str) { + + case 'P': + + if (!strcmp ("POINT_SIZE", str)) + { +//printf ("point size=%lu\n", value); +#if 0 + double sz = value; + pcf->size = sz / 10.0; +#endif + } + break; + + case 'R': + + if (!strcmp ("RESOLUTION_X", str)) + { +//printf ("resolution x=%lu\n", value); +#if 0 + pcf->dpi = value; +#endif + } + break; + + case 'C': + + // We're using only iso8859-1 fonts. + // + if (!strcmp ("CHARSET_ENCODING", str)) + { +// printf ("encoding=%d\n", value); + if (value != 1) + return false; + } + default: + break; + + // printf ("\tunused property name %s value %lu\n", str, value); + } + } + } + return true; +} + + +char +pcf_read (Font* pcf, char *path) +{ + int i; + FILE *f; + static char *line; + char *param; + char *param_end; + short param_length; + unsigned char *us; + char *s; + char *s2; + char *s3; + int char_num = 0; + static char got_start = false; + static char got_encoding = false; + static char got_end = false; + static char got_bitmap = false; + struct stat statbuf; + char path2[PATH_MAX]; + + if (*path != '/') { + char *dir = getenv("PCFFONTDIR"); + if (dir) { + strcpy (path2, dir); + if ('/' != dir[strlen(dir)-1]) + strcat (path2, "/"); + } else + sprintf (path2, "/usr/X11R6/lib/fonts/%d%s", dpi, "dpi/"); + + strcat (path2, path); + } + else + strcpy (path2, path); + +// printf ("path='%s'\n", path2); + if (stat (path2, &statbuf)) + return false; + + unsigned long size = statbuf.st_size; + +#if 0 + pcf->fullname[0]=0; + pcf->family[0]=0; +#endif + + f = fopen (path2, "rb"); + if (!f) + return false; + + read_buffer = malloc (size); + if (!read_buffer) + FATAL ("unable to allocate font read buffer!"); + i = fread (read_buffer,1,size,f); + if (i != size) + FATAL ("cannot read entire font file"); + fclose (f); + f = NULL; + uchar *ptr = read_buffer; + + // Read the TOC + unsigned long toc_type; + unsigned long toc_total; + + toc_type = ULONG(0,ptr); ptr += 4; + toc_total = ULONG(0,ptr); ptr += 4; + if (toc_type != ZZ(1, 'f','c','p')) + FATAL ("pcf file has bad header"); + + for (i=0; i < toc_total; i++) + { + unsigned long j; + unsigned short type; + unsigned char *table; + +// printf ("toc entry %d:\n", i); + + type = ULONG(0,ptr); ptr += 4; +// printf (" type=%u, ", type); + + j = ULONG(0,ptr); ptr += 4; + // printf (" format=%lu, ", j); + + j = ULONG(0,ptr); ptr += 4; + // printf (" size=%lu, ", j); + + j = ULONG(0,ptr); ptr += 4; + // printf (" offset=%lu\n", j); + + table = read_buffer + j; + + switch (type) + { + case PCF_PROPS: + if (!pcf_read_properties (pcf, table)) + return false; + break; + + case PCF_BDF_ENCODINGS : + if (!pcf_read_encodings (pcf, table)) + return false; + break; + + case PCF_ACCEL: + if (!pcf_read_accelerator (pcf, table)) + return false; + break; + + case PCF_METRICS: + if (!pcf_read_metrics (pcf, table)) + return false; + break; + + case PCF_BITMAPS: + if (!pcf_read_bitmaps (pcf, table)) + return false; + break; + + default: + ; + } + } + + if (read_buffer) + { + free (read_buffer); + read_buffer = NULL; + } + + return true; +} + + +char *fbui_get_event_name (int type) +{ + char *s="(unknown)"; + switch (type) { + case FBUI_EVENT_NONE: s="(none)"; break; + case FBUI_EVENT_EXPOSE: s="Expose"; break; + case FBUI_EVENT_HIDE: s="Hide"; break; + case FBUI_EVENT_UNHIDE: s="Unhide"; break; + case FBUI_EVENT_ENTER: s="Enter"; break; + case FBUI_EVENT_LEAVE: s="Leave"; break; + case FBUI_EVENT_KEY: s="Key"; break; + case FBUI_EVENT_MOVE_RESIZE: s="MoveResize"; break; + case FBUI_EVENT_ACCEL: s="Accel"; break; + case FBUI_EVENT_WINCHANGE: s="WinChange"; break; + case FBUI_EVENT_MOTION: s="Motion"; break; + case FBUI_EVENT_BUTTON: s="Button"; break; + } + return s; +} + + +void fbui_print_error (int value) +{ + printf ("FBUI error: %s\n", fbui_error_name(value)); +} + +char *fbui_error_name (int value) +{ + char *s = "(none)"; + + if (value >= 0) + value = -value; + + switch (value) { + case FBUI_ERR_BADADDR: s = "bad address"; break; + case FBUI_ERR_NULLPTR: s = "null pointer"; break; + case FBUI_ERR_OFFSCREEN: s = "offscreen"; break; + case FBUI_ERR_NOTRUNNING: s = "not running"; break; + case FBUI_ERR_WRONGVISUAL: s = "wrong visual"; break; + case FBUI_ERR_NOTPLACED: s = "not placed"; break; + case FBUI_ERR_BIGENDIAN: s = "big endian"; break; + case FBUI_ERR_INVALIDCMD: s = "invalid command"; break; + case FBUI_ERR_BADPID: s = "bad process id"; break; + case FBUI_ERR_ACCELBUSY: s = "accelerator key in use"; break; + case FBUI_ERR_NOFONT: s = "no font"; break; + case FBUI_ERR_NOMEM: s = "out of memory"; break; + case FBUI_ERR_NOTOPEN: s = "not open"; break; + case FBUI_ERR_OVERLAP: s = "window overlap"; break; + case FBUI_ERR_ALREADYOPEN: s = "already open"; break; + case FBUI_ERR_MISSINGWIN: s = "missing window"; break; + case FBUI_ERR_NOTWM: s = "not a window manager"; break; + case FBUI_ERR_WRONGWM: s = "wrong window manager"; break; + case FBUI_ERR_HAVEWM: s = "already have window manager"; break; + case FBUI_ERR_KEYFOCUSDENIED: s = "key focus request denied"; break; + case FBUI_ERR_KEYFOCUSERR: s = "key focus error"; break; + case FBUI_ERR_BADPARAM: s = "bad parameter"; break; + case FBUI_ERR_NOMOUSE: s = "no mouse"; break; + case FBUI_ERR_MOUSEREAD: s = "mouse read error"; break; + case FBUI_ERR_OVERLARGECUT: s = "overlarge cut"; break; + case FBUI_ERR_BADWIN: s = "bad window"; break; + case FBUI_ERR_PASTEFAIL: s = "paste failed"; break; + case FBUI_ERR_CUTFAIL: s = "cut failed"; break; + case FBUI_ERR_NOEVENT: s = "no events"; break; + case FBUI_ERR_DRAWING: s = "busy drawing"; break; + case FBUI_ERR_MISSINGPROCENT: s = "missing process entry"; break; + case FBUI_ERR_BADVC: s = "bad virtual console number"; break; + } + return s; +} diff --git a/libfbui/libfbui.h b/libfbui/libfbui.h @@ -0,0 +1,217 @@ + +/*========================================================================= + * + * libfbui, a library for accessing FBUI (in-kernel framebuffer GUI). + * Copyright (C) 2003-2004 Zachary T Smith, fbui@comcast.net + * + * This module is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This module 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this module; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * (See the file COPYING in the main directory of this archive for + * more details.) + * + *=======================================================================*/ + + +#ifndef _FBUI_H +#define _FBUI_H + +#include <linux/fb.h> + + +typedef unsigned char uchar; +typedef unsigned char bool; + +enum { true=1, false=0 }; + +#define LIBFBUI_COMMANDBUFLEN (4096) + + + +typedef struct win { + int id; + + unsigned short command [LIBFBUI_COMMANDBUFLEN + 1]; + unsigned short command_ix; + + int width, height; + + struct win *next; +} Window; + +typedef struct { + int fd; + + Window *list; + + unsigned char shift,ctrl,alt; + short width, height, depth; + + /* needed for creating native-format pixmaps */ + short red_offset, green_offset, blue_offset; + short red_length, green_length, blue_length; +} Display; + +typedef struct { + Window *win; + short id; + char type; + short key; + short x,y,width,height; +} Event; + + + +extern int fbui_poll_event (Display *dpy, Event *, unsigned short mask); /* returns <0 when error */ +extern int fbui_wait_event (Display *dpy, Event *, unsigned short mask); /* returns <0 when error */ + +extern int fbui_read_mouse (Display *dpy, Window*, short*,short*); + +extern int fbui_get_dims (Display *dpy, Window*, short*,short*); +extern int fbui_get_position (Display *dpy, Window*, short*,short*); + +/* raw to ascii conversion: */ +extern int fbui_convert_key (Display *, long); + +extern int fbui_flush (Display *, Window *); + +extern int fbui_cut (Display*,Window *wm, unsigned char *data, unsigned long length); +extern int fbui_paste (Display*,Window *wm, unsigned char *data, unsigned long max_length); +extern long fbui_cut_length (Display*,Window *wm); + +extern int fbui_hide(Display*,Window *wm,short id); +extern int fbui_unhide(Display*,Window *wm,short id); +extern int fbui_delete(Display*,Window *wm,short id); +extern int fbui_redraw(Display*,Window *wm,short id); +extern int fbui_move_resize(Display*,Window *wm,short id,short,short,short,short); +extern int fbui_window_info (Display*,Window *wm,struct fbui_wininfo*,int); +extern int fbui_accelerator (Display* dpy, Window *wm,short key, short op); + +extern int fbui_assign_keyfocus (Display*,Window *wm,short); +extern int fbui_assign_ptrfocus (Display*,Window *wm,short); + +extern int fbui_placement (Display* dpy,Window *wm, int yes); + +extern int fbui_draw_point (Display*,Window*, short x, short y,unsigned long); +extern unsigned long fbui_read_point (Display*,Window*, short x, short y); +extern int fbui_draw_vline (Display*,Window*, short x, short y0, short y1,unsigned long); +extern int fbui_draw_hline (Display*,Window*, short x0, short x1, short y,unsigned long); + +extern int fbui_set_subtitle (Display*,Window*, char *); + +extern int +fbui_tinyblit (Display *dpy, Window *win, short x, short y, + unsigned long color, + unsigned long bgcolor, + short width, + unsigned long bits); + +extern int fbui_draw_line (Display*,Window*, short x0, short y0, short x1, short y1,unsigned long); +extern int fbui_invert_line (Display*,Window*, short x0, short y0, short x1, short y1); +extern int fbui_draw_string (Display*,Window*, struct fbui_font*,short, short, char *,unsigned long); +extern int fbui_set_font (Display *dpy, Window *win, struct fbui_font *font); +extern int fbui_clear (Display *, Window*); +extern int fbui_draw_rect (Display*,Window*, short x0, short y0, short x1, short y1,unsigned long); +extern int fbui_fill_area (Display*,Window*, short x0, short y0, short x1, short y1,unsigned long); +extern int fbui_clear_area (Display*,Window*, short x0, short y0, short x1, short y1); +extern int fbui_copy_area (Display*,Window*, short xsrc, short ysrc, short xdest, short ydest, short w, short h); +extern int fbui_put (Display*,Window*, short x, short y, short n, unsigned char *p); +extern int fbui_put_rgb (Display*,Window*, short x, short y, short n, unsigned long *p); +extern int fbui_put_rgb3 (Display*,Window*, short x, short y, short n, unsigned char *p); + +extern Display *fbui_display_open (); +extern void fbui_display_close (Display *); + +extern int fbui_window_close (Display *, Window*); + +extern Window *fbui_window_open (Display *dpy, short width, short height, + short *width_return, short *height_return, + short max_width, short max_height, + short xrel, short yrel, + unsigned long *fgcolor_inout, + unsigned long *bgcolor_inout, + char*, char*, + char progtype, + char req_ctl, + char doing_autopositioning, + char vc, + char need_keys, + char receive_all_motion, + char initially_hidden, + int argc,char** argv); + +/* special keys */ +#define FBUI_DEL (127) + +#define FBUISPECIALKEYSBASE 1024 + +#define FBUI_UP (FBUISPECIALKEYSBASE+0) +#define FBUI_DOWN (FBUISPECIALKEYSBASE+1) +#define FBUI_LEFT (FBUISPECIALKEYSBASE+2) +#define FBUI_RIGHT (FBUISPECIALKEYSBASE+3) +#define FBUI_F1 (FBUISPECIALKEYSBASE+4) +#define FBUI_F2 (FBUISPECIALKEYSBASE+5) +#define FBUI_F3 (FBUISPECIALKEYSBASE+6) +#define FBUI_F4 (FBUISPECIALKEYSBASE+7) +#define FBUI_F5 (FBUISPECIALKEYSBASE+8) +#define FBUI_F6 (FBUISPECIALKEYSBASE+9) +#define FBUI_F7 (FBUISPECIALKEYSBASE+10) +#define FBUI_F8 (FBUISPECIALKEYSBASE+11) +#define FBUI_F9 (FBUISPECIALKEYSBASE+12) +#define FBUI_F10 (FBUISPECIALKEYSBASE+13) +#define FBUI_F11 (FBUISPECIALKEYSBASE+14) +#define FBUI_F12 (FBUISPECIALKEYSBASE+15) +#define FBUI_INS (FBUISPECIALKEYSBASE+16) +#define FBUI_HOME (FBUISPECIALKEYSBASE+17) +#define FBUI_END (FBUISPECIALKEYSBASE+18) +#define FBUI_PGUP (FBUISPECIALKEYSBASE+19) +#define FBUI_PGDN (FBUISPECIALKEYSBASE+20) +#define FBUI_SCRLK (FBUISPECIALKEYSBASE+21) +#define FBUI_NUMLK (FBUISPECIALKEYSBASE+22) +#define FBUI_LEFTTAB (FBUISPECIALKEYSBASE+23) +#define FBUI_PRTSC (FBUISPECIALKEYSBASE+24) +#define FBUI_CAPSLK (FBUISPECIALKEYSBASE+25) + + +#define FONT_WEIGHT_LIGHT (0) +#define FONT_WEIGHT_MEDIUM (1) +#define FONT_WEIGHT_BOLD (2) +#define FONT_WEIGHT_BLACK (3) + +typedef struct fbui_font Font; + +extern void font_string_dims (Font *font, unsigned char*, short *w, short *ascent, short *descent); +extern void font_char_dims (Font *font, uchar ch, short *w, short *asc, short *desc); + +extern Font* font_new (void); +extern void font_free (Font*); + +extern char pcf_read (Font* pcf, char *path); + +extern char *fbui_get_event_name (int type); + +extern int display_fd; +extern Display *my_dpy; + +void fbui_print_error (int value); +char *fbui_error_name (int value); + + +#define FATAL(s) { fbui_display_close (my_dpy); fprintf(stderr,"Error in %s(): %s\n",__FUNCTION__,s); exit(1); } +#define WARNING(s) { fprintf(stderr,"Warning in %s(): %s\n",__FUNCTION__,s); } + + + + +#endif diff --git a/libfbui/makeall.sh b/libfbui/makeall.sh @@ -0,0 +1,23 @@ +#/bin/sh + +FILES="libfbui.a libfbui.o Calc/fbcalc Launcher/fblauncher +Clock/fbclock Term/fbterm LoadMonitor/fbload Viewer/fbview +MailCheck/fbcheck Test/fbtest WindowManager/fbwm PanelManager/fbpm +ToDo/fbtodo MPEG/mpeg2decode" + +DIRS=". Calc Launcher MPEG Test Clock ToDo Term LoadMonitor Viewer +MailCheck Dump WindowManager PanelManager" + +for FILE in $FILES +do +rm -f $FILE +done + +for DIR in $DIRS +do +cd $DIR +make +if [ "$DIR" != "." ] +then cd .. +fi +done diff --git a/libfbui/start-fbwm.sh b/libfbui/start-fbwm.sh @@ -0,0 +1,21 @@ +#/bin/sh + +if [ "$1" == "" ]; then + export A=4 +else + export A=$1 +fi + +Clock/fbclock -c$A -geo130x50+0-0 & +MailCheck/fbcheck -geo 150x50+200-0 -c$A & + LoadMonitor/fbload 4 -geo80x150-0-0 -c$A & +Viewer/fbview -geo80x120-0+30 Viewer/meander.jpg -c$A & + Term/fbterm -c$A & +Calc/fbcalc -geo80x200-0+160 -c$A & + +sleep 2 +# sleep needed because fbwm doesn't handle requests for autoplacement +WindowManager/fbwm clouds.jpg -c$A + +#sleep 60 +#Dump/fbdump diff --git a/libfbui/start.sh b/libfbui/start.sh @@ -0,0 +1,45 @@ +#/bin/sh + +sync +sync +sync +sync +sync +sync +sync +sync + +if [ "$1" == "" ]; then + export A=4 +else + export A=$1 +fi + + +PanelManager/fbpm -c$A clouds.jpg & +Start/fbstart -c$A & +Clock/fbclock -c$A -geo72x72+0-0 & +# MailCheck/fbcheck -geo 150x50+200-0 -c$A & +LoadMonitor/fbload 4 -fg=orange -bg=black -geo200x150-0-0 -c$A & +MPEG/mpeg2decode -$A -b MPEG/2004-18-a-low_mpeg.mpg & +Viewer/fbview -geo150x120-0+30 Viewer/497_1031_3.tif -c$A & +Scribble/fbscribble -c$A & +Calc/fbcalc -c$A & +Term/fbterm -c$A & +ToDo/fbtodo -c$A & + +#echo "break exit" > cmds +#echo "break exit" >> cmds +#echo "break exit" >> cmds +#echo "break exit" >> cmds +#echo "break exit" >> cmds +#echo "break exit" >> cmds +#echo "break exit" >> cmds +#echo "break exit" >> cmds +#echo "break exit" >> cmds +#echo "break exit" >> cmds +#echo "break exit" >> cmds +#echo "break exit" >> cmds +#echo "break exit" >> cmds +#echo "run -c$A" >> cmds +
This webpage is intended to be an accessible preview of this repository. To get a fuller picture, clone it and use the git CLI.