summaryrefslogtreecommitdiff
path: root/src/fbdev
diff options
context:
space:
mode:
Diffstat (limited to 'src/fbdev')
-rw-r--r--src/fbdev/event.cc39
-rw-r--r--src/fbdev/gfx.cc226
-rw-r--r--src/fbdev/keyboard.cc102
-rw-r--r--src/fbdev/mouse.cc161
4 files changed, 528 insertions, 0 deletions
diff --git a/src/fbdev/event.cc b/src/fbdev/event.cc
new file mode 100644
index 0000000..611ec3c
--- /dev/null
+++ b/src/fbdev/event.cc
@@ -0,0 +1,39 @@
+#ifdef WINNIE_FBDEV
+#include <stdio.h>
+
+#include <errno.h>
+#include <unistd.h>
+#include <sys/select.h>
+
+#include "event.h"
+#include "wm.h"
+#include "keyboard.h"
+#include "mouse.h"
+
+void process_events()
+{
+ int keyb_fd = get_keyboard_fd();
+ int mouse_fd = get_mouse_fd();
+
+ for(;;) {
+ wm->process_windows();
+
+ fd_set read_set;
+
+ FD_ZERO(&read_set);
+ FD_SET(keyb_fd, &read_set);
+ FD_SET(mouse_fd, &read_set);
+
+ int maxfd = keyb_fd > mouse_fd ? keyb_fd : mouse_fd;
+
+ while(select(maxfd + 1, &read_set, 0, 0, 0) == -1 && errno == EINTR);
+
+ if(FD_ISSET(keyb_fd, &read_set)) {
+ process_keyboard_event();
+ }
+ if(FD_ISSET(mouse_fd, &read_set)) {
+ process_mouse_event();
+ }
+ }
+}
+#endif // WINNIE_FBDEV
diff --git a/src/fbdev/gfx.cc b/src/fbdev/gfx.cc
new file mode 100644
index 0000000..00e1881
--- /dev/null
+++ b/src/fbdev/gfx.cc
@@ -0,0 +1,226 @@
+#ifdef WINNIE_FBDEV
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <unistd.h>
+
+#include <linux/fb.h>
+
+#include "gfx.h"
+
+#define FRAMEBUFFER_SIZE(xsz, ysz, bpp) ((xsz) * (ysz) * (bpp) / CHAR_BIT)
+
+static unsigned char *framebuffer;
+static int dev_fd = -1;
+
+static Rect screen_rect;
+static int color_depth; // bits per pixel
+
+bool init_gfx()
+{
+ if((dev_fd = open("/dev/fb0", O_RDWR)) == -1) {
+ fprintf(stderr, "Cannot open /dev/fb0 : %s\n", strerror(errno));
+ return false;
+ }
+
+ fb_var_screeninfo sinfo;
+ if(ioctl(dev_fd, FBIOGET_VSCREENINFO, &sinfo) == -1) {
+ close(dev_fd);
+ dev_fd = -1;
+ fprintf(stderr, "Unable to get screen info : %s\n", strerror(errno));
+ return false;
+ }
+
+ printf("width : %d height : %d\n : bpp : %d\n", sinfo.xres, sinfo.yres, sinfo.bits_per_pixel);
+ printf("virtual w: %d virtual h: %d\n", sinfo.xres_virtual, sinfo.yres_virtual);
+
+ screen_rect.x = screen_rect.y = 0;
+ screen_rect.width = sinfo.xres_virtual;
+ screen_rect.height = sinfo.yres_virtual;
+ color_depth = sinfo.bits_per_pixel;
+
+ int sz = FRAMEBUFFER_SIZE(screen_rect.width, screen_rect.height, color_depth);
+ framebuffer = (unsigned char*)mmap(0, sz, PROT_READ | PROT_WRITE, MAP_SHARED, dev_fd, 0);
+
+ if(framebuffer == (void*)-1) {
+ close(dev_fd);
+ dev_fd = -1;
+ fprintf(stderr, "Cannot map the framebuffer to memory : %s\n", strerror(errno));
+ return false;
+ }
+
+ return true;
+}
+
+void destroy_gfx()
+{
+ clear_screen(0, 0, 0);
+
+ if(dev_fd != -1) {
+ close(dev_fd);
+ }
+
+ dev_fd = -1;
+
+ munmap(framebuffer, FRAMEBUFFER_SIZE(screen_rect.width, screen_rect.height, color_depth));
+ framebuffer = 0;
+}
+
+unsigned char *get_framebuffer()
+{
+ return framebuffer;
+}
+
+Rect get_screen_size()
+{
+ return screen_rect;
+}
+
+int get_color_depth()
+{
+ return color_depth;
+}
+
+void clear_screen(int r, int g, int b)
+{
+ fill_rect(screen_rect, r, g, b);
+}
+
+void fill_rect(const Rect &rect, int r, int g, int b)
+{
+ Rect drect = rect;
+
+ if(drect.x < 0) {
+ drect.x = 0;
+ }
+
+ if(drect.y < 0) {
+ drect.y = 0;
+ }
+
+ unsigned char *fb = framebuffer + (drect.x + screen_rect.width * drect.y) * 4;
+ for(int i=0; i<drect.height; i++) {
+ for(int j=0; j<drect.width; j++) {
+ fb[j * 4] = b;
+ fb[j * 4 + 1] = g;
+ fb[j * 4 + 2] = r;
+ }
+ fb += screen_rect.width * 4;
+ }
+}
+
+void set_cursor_visibility(bool visible)
+{
+ fb_cursor curs;
+ curs.enable = visible ? 1 : 0;
+
+ if(ioctl(dev_fd, FBIO_CURSOR, &curs) == -1) {
+ fprintf(stderr, "Cannot toggle cursor visibility : %s\n", strerror(errno));
+ }
+}
+
+void blit(unsigned char *src_img, const Rect &src_rect, unsigned char* dest_img,
+ const Rect &dest_rect, int dest_x, int dest_y)
+{
+ int width = src_rect.width;
+ int height = src_rect.height;
+
+ int xoffs = dest_x - dest_rect.x;
+ if(xoffs < 0) {
+ dest_x = dest_rect.x;
+ width += xoffs;
+ }
+
+ int yoffs = dest_y - dest_rect.y;
+ if(yoffs < 0) {
+ dest_y = dest_rect.y;
+ height += yoffs;
+ }
+
+ int xend = dest_x + width;
+ if(xend >= dest_rect.width) {
+ width -= xend - dest_rect.width;
+ }
+
+ int yend = dest_y + height;
+ if(yend >= dest_rect.height) {
+ height -= yend - dest_rect.height;
+ }
+
+ if(width <= 0 || height <= 0) {
+ return;
+ }
+
+ unsigned char *sptr = src_img + (src_rect.y * src_rect.width + src_rect.x) * 4;
+ unsigned char *dptr = dest_img + (dest_y * dest_rect.width + dest_x) * 4;
+
+ for(int i=0; i<height; i++) {
+ memcpy(dptr, sptr, width * 4);
+ sptr += src_rect.width * 4;
+ dptr += dest_rect.width * 4;
+ }
+}
+
+void blit_key(unsigned char *src_img, const Rect &src_rect, unsigned char* dest_img,
+ const Rect &dest_rect, int dest_x, int dest_y, int key_r, int key_g, int key_b)
+{
+ int width = src_rect.width;
+ int height = src_rect.height;
+
+ int xoffs = dest_x - dest_rect.x;
+ if(xoffs < 0) {
+ dest_x = dest_rect.x;
+ width += xoffs;
+ }
+
+ int yoffs = dest_y - dest_rect.y;
+ if(yoffs < 0) {
+ dest_y = dest_rect.y;
+ height += yoffs;
+ }
+
+ int xend = dest_x + width;
+ if(xend >= dest_rect.width) {
+ width -= xend - dest_rect.width;
+ }
+
+ int yend = dest_y + height;
+ if(yend >= dest_rect.height) {
+ height -= yend - dest_rect.height;
+ }
+
+ if(width <= 0 || height <= 0) {
+ return;
+ }
+
+ unsigned char *sptr = src_img + (src_rect.y * src_rect.width + src_rect.x) * 4;
+ unsigned char *dptr = dest_img + (dest_y * dest_rect.width + dest_x) * 4;
+
+ for(int i=0; i<height; i++) {
+ for(int j=0; j<width; j++) {
+ int r = sptr[j * 4];
+ int g = sptr[j * 4 + 1];
+ int b = sptr[j * 4 + 2];
+
+ if(r != key_r || g != key_g || b != key_b) {
+ dptr[j * 4] = b;
+ dptr[j * 4 + 1] = g;
+ dptr[j * 4 + 2] = r;
+ }
+ }
+
+ sptr += src_rect.width * 4;
+ dptr += dest_rect.width * 4;
+ }
+}
+
+void gfx_update()
+{
+}
+
+#endif // WINNIE_FBDEV
diff --git a/src/fbdev/keyboard.cc b/src/fbdev/keyboard.cc
new file mode 100644
index 0000000..77f0bdd
--- /dev/null
+++ b/src/fbdev/keyboard.cc
@@ -0,0 +1,102 @@
+#ifdef WINNIE_FBDEV
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <termios.h>
+#include <unistd.h>
+
+#include "keyboard.h"
+#include "window.h"
+#include "wm.h"
+
+static int dev_fd = -1;
+static enum {RAW, CANONICAL} ttystate = CANONICAL;
+
+bool init_keyboard()
+{
+ if((dev_fd = open("/dev/tty", O_RDWR)) == -1) {
+ fprintf(stderr, "Cannot open /dev/tty : %s\n", strerror(errno));
+ return false;
+ }
+
+ struct termios buf;
+
+ if(tcgetattr(dev_fd, &buf) < 0) {
+ fprintf(stderr, "Cannot get the tty parameters : %s\n", strerror(errno));
+ return false;
+ }
+
+ buf.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
+ buf.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
+ buf.c_cflag &= ~(CSIZE | PARENB);
+ buf.c_cflag |= CS8;
+ buf.c_oflag &= ~(OPOST);
+
+ if(tcsetattr(dev_fd, TCSAFLUSH, &buf) < 0) {
+ return false;
+ }
+
+ ttystate = RAW;
+ return true;
+}
+
+void destroy_keyboard()
+{
+ struct termios buf;
+
+ if(tcgetattr(dev_fd, &buf) < 0) {
+ fprintf(stderr, "Cannot get the tty parameters : %s\n", strerror(errno));
+ }
+
+ buf.c_lflag |= (ECHO | ICANON | IEXTEN | ISIG);
+ buf.c_iflag |= (BRKINT | ICRNL | INPCK | ISTRIP | IXON);
+ buf.c_cflag |= (CSIZE | PARENB);
+ buf.c_cflag &= CS8;
+ buf.c_oflag |= (OPOST);
+
+ if(tcsetattr(dev_fd, TCSAFLUSH, &buf) < 0) {
+ fprintf(stderr, "Cannot set the tty parameters : %s\n", strerror(errno));
+ }
+
+ ttystate = CANONICAL;
+
+ if(dev_fd != -1) {
+ close(dev_fd);
+ dev_fd = -1;
+ }
+}
+
+int get_keyboard_fd()
+{
+ return dev_fd;
+}
+
+void process_keyboard_event()
+{
+ char key;
+ if(read(dev_fd, &key, 1) < 1) {
+ return;
+ }
+
+ if(key == 'q') {
+ exit(0);
+ }
+
+ Window *focused_win = wm->get_focused_window();
+ if(focused_win) {
+ KeyboardFuncType keyb_callback = focused_win->get_keyboard_callback();
+ if(keyb_callback) {
+ keyb_callback(focused_win, key, true); //TODO: true??
+ }
+ }
+
+ /* TODO:
+ * - handle system-wide key combinations (alt-tab?)
+ * - otherwise send keypress/release to focused window
+ */
+}
+#endif // WINNIE_FBDEV
diff --git a/src/fbdev/mouse.cc b/src/fbdev/mouse.cc
new file mode 100644
index 0000000..5fd080b
--- /dev/null
+++ b/src/fbdev/mouse.cc
@@ -0,0 +1,161 @@
+#ifdef WINNIE_FBDEV
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <termios.h>
+#include <unistd.h>
+
+#include "geom.h"
+#include "gfx.h"
+#include "mouse.h"
+#include "window.h"
+#include "wm.h"
+
+#define BN_LEFT 1
+#define BN_RIGHT 2
+#define BN_MIDDLE 4
+
+static int read_mouse();
+
+static int dev_fd = -1; // file descriptor for /dev/psaux
+static Rect bounds;
+static int pointer_x, pointer_y;
+static int bnstate;
+
+bool init_mouse()
+{
+ if((dev_fd = open("/dev/psaux", O_RDONLY | O_NONBLOCK)) == -1) {
+ fprintf(stderr, "Cannot open /dev/psaux : %s\n", strerror(errno));
+ return false;
+ }
+
+ set_mouse_bounds(get_screen_size());
+ return true;
+}
+
+void destroy_mouse()
+{
+ if(dev_fd != -1) {
+ close(dev_fd);
+ dev_fd = -1;
+ }
+}
+
+void set_mouse_bounds(const Rect &rect)
+{
+ bounds = rect;
+}
+
+int get_mouse_fd()
+{
+ return dev_fd;
+}
+
+void process_mouse_event()
+{
+ /* TODO:
+ * - read all pending events from mouse fd (use O_NONBLOCK so that
+ * read will return -1 when there are no more events instead of blocking).
+ */
+
+ int prev_state = bnstate;
+ int prev_x = pointer_x;
+ int prev_y = pointer_y;
+
+ if(read_mouse() == -1) {
+ return;
+ }
+
+ Window *top = wm->get_window_at_pos(pointer_x, pointer_y);
+ if(top) {
+ wm->set_focused_window(top);
+ }
+ else {
+ wm->set_focused_window(0);
+ }
+
+ /* - send each pointer move and button press/release to the topmost window
+ * with the pointer on it.
+ */
+
+ int dx = pointer_x - prev_x;
+ int dy = pointer_y - prev_y;
+
+ if((dx || dy) && top) {
+ MouseMotionFuncType motion_callback = top->get_mouse_motion_callback();
+ if(motion_callback) {
+ Rect rect = top->get_absolute_rect();
+ motion_callback(top, pointer_x - rect.x, pointer_y - rect.y);
+ }
+ }
+
+ MouseButtonFuncType button_callback;
+ if((bnstate != prev_state) && top && (button_callback = top->get_mouse_button_callback())) {
+ int num_bits = sizeof bnstate * CHAR_BIT;
+ for(int i=0; i<num_bits; i++) {
+ int s = (bnstate >> i) & 1;
+ int prev_s = (prev_state >> i) & 1;
+ if(s != prev_s) {
+ button_callback(top, i, s);
+ }
+ }
+ }
+}
+
+void get_pointer_pos(int *x, int *y)
+{
+ *x = pointer_x;
+ *y = pointer_y;
+}
+
+int get_button_state()
+{
+ return bnstate;
+}
+
+int get_button(int bn)
+{
+ if(bn < 0 || bn >= 3) {
+ return 0;
+ }
+ return (bnstate & (1 << bn)) != 0;
+}
+
+static int read_mouse()
+{
+ int rd;
+ signed char state[3] = {0, 0, 0};
+
+ if((rd = read(dev_fd, state, 3)) == -1) {
+ fprintf(stderr, "Unable to get mouse state : %s\n", strerror(errno));
+ return -1;
+ }
+
+ bnstate = state[0] & 7;
+ pointer_x += state[1];
+ pointer_y -= state[2];
+
+ if(pointer_x < bounds.x) {
+ pointer_x = bounds.x;
+ }
+
+ if(pointer_y < bounds.y) {
+ pointer_y = bounds.y;
+ }
+
+ if(pointer_x > bounds.x + bounds.width - 1) {
+ pointer_x = bounds.x + bounds.width - 1;
+ }
+
+ if(pointer_y > bounds.y + bounds.height - 1) {
+ pointer_y = bounds.y + bounds.height - 1;
+ }
+
+ return 0;
+}
+#endif // WINNIE_FBDEV