summaryrefslogtreecommitdiff
path: root/libwinnie/src/fbdev
diff options
context:
space:
mode:
authorEleni Maria Stea <elene.mst@gmail.com>2013-04-01 01:29:13 +0300
committerEleni Maria Stea <elene.mst@gmail.com>2013-04-01 01:29:13 +0300
commit7b5d2df884abb7084d71f17cc29a618c0b6f47ef (patch)
tree0c6bdb1d6e847ae745f01f599f4c709adcfdd7bb /libwinnie/src/fbdev
parentb4c8d68e0357683cec82fb8a9c5a4447155b3192 (diff)
created libwinnie (library), winnie (the server application) and clients
Diffstat (limited to 'libwinnie/src/fbdev')
-rw-r--r--libwinnie/src/fbdev/event.cc60
-rw-r--r--libwinnie/src/fbdev/gfx.cc221
-rw-r--r--libwinnie/src/fbdev/keyboard.cc140
-rw-r--r--libwinnie/src/fbdev/mouse.cc202
4 files changed, 623 insertions, 0 deletions
diff --git a/libwinnie/src/fbdev/event.cc b/libwinnie/src/fbdev/event.cc
new file mode 100644
index 0000000..00e12cd
--- /dev/null
+++ b/libwinnie/src/fbdev/event.cc
@@ -0,0 +1,60 @@
+/*
+winnie - an experimental window system
+
+Copyright (C) 2013 Eleni Maria Stea
+
+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 3 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, see <http://www.gnu.org/licenses/>.
+
+Author: Eleni Maria Stea <elene.mst@gmail.com>
+*/
+
+#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/libwinnie/src/fbdev/gfx.cc b/libwinnie/src/fbdev/gfx.cc
new file mode 100644
index 0000000..ff86d9c
--- /dev/null
+++ b/libwinnie/src/fbdev/gfx.cc
@@ -0,0 +1,221 @@
+/*
+winnie - an experimental window system
+
+Copyright (C) 2013 Eleni Maria Stea
+
+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 3 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, see <http://www.gnu.org/licenses/>.
+
+Author: Eleni Maria Stea <elene.mst@gmail.com>
+*/
+
+#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 <sys/mman.h>
+#include <sys/time.h>
+#include <unistd.h>
+
+#include <linux/fb.h>
+
+#include "gfx.h"
+#include "shalloc.h"
+#include "winnie.h"
+
+#define FRAMEBUFFER_SIZE(xsz, ysz, bpp) ((xsz) * (ysz) * (bpp) / CHAR_BIT)
+
+static unsigned char *framebuffer;
+static int dev_fd;
+static int rgb_order[3];
+
+struct Graphics {
+ Rect screen_rect;
+ Rect clipping_rect;
+ int color_depth;
+ Pixmap *pixmap;
+};
+
+static Graphics *gfx;
+
+bool init_gfx()
+{
+ if(!(gfx = (Graphics*)sh_malloc(sizeof *gfx))) {
+ return false;
+ }
+
+ get_subsys()->graphics_offset = (int)((char*)gfx - (char*)get_pool());
+
+ dev_fd = -1;
+
+ 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);
+
+ gfx->screen_rect.x = gfx->screen_rect.y = 0;
+ gfx->screen_rect.width = sinfo.xres_virtual;
+ gfx->screen_rect.height = sinfo.yres_virtual;
+ gfx->color_depth = sinfo.bits_per_pixel;
+
+ rgb_order[0] = sinfo.red.offset / 8;
+ rgb_order[1] = sinfo.green.offset / 8;
+ rgb_order[2] = sinfo.blue.offset / 8;
+
+ set_clipping_rect(gfx->screen_rect);
+
+ int sz = FRAMEBUFFER_SIZE(gfx->screen_rect.width, gfx->screen_rect.height, gfx->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;
+ }
+
+// TODO: uncomment when I find how to use intelfb instead of i915 GRRRR.-
+ fb_vblank vblank;
+ if(ioctl(dev_fd, FBIOGET_VBLANK, &vblank) == -1) {
+// fprintf(stderr, "FBIOGET_VBLANK error: %s\n", strerror(errno));
+ }
+/*
+ else {
+ printf("flags: %x\n", vblank.flags);
+ printf("count: %d\n", vblank.count);
+ printf("beam position: %d, %d\n", vblank.hcount, vblank.vcount);
+ }
+*/
+
+ if(!(gfx->pixmap = (Pixmap*)sh_malloc(sizeof(Pixmap)))) {
+ fprintf(stderr, "Failed to allocate pixmap.\n");
+ return false;
+ }
+
+ gfx->pixmap->width = gfx->screen_rect.width;
+ gfx->pixmap->height = gfx->screen_rect.height;
+
+ int fbsize = gfx->pixmap->width * gfx->pixmap->height * gfx->color_depth / 8;
+ if(!(gfx->pixmap->pixels = (unsigned char*)sh_malloc(fbsize))) {
+ fprintf(stderr, "failed to allocate the pixmap framebuffer.\n");
+ return false;
+ }
+
+ return true;
+}
+
+void destroy_gfx()
+{
+ clear_screen(0, 0, 0);
+ gfx_update(gfx->screen_rect);
+
+ if(dev_fd != -1) {
+ close(dev_fd);
+ }
+
+ dev_fd = -1;
+
+ munmap(framebuffer, FRAMEBUFFER_SIZE(gfx->screen_rect.width, gfx->screen_rect.height, gfx->color_depth));
+ framebuffer = 0;
+
+ sh_free(gfx->pixmap->pixels);
+ gfx->pixmap->pixels = 0;
+ sh_free(gfx->pixmap);
+ sh_free(gfx);
+}
+
+unsigned char *get_framebuffer()
+{
+ return gfx->pixmap->pixels;
+}
+
+Pixmap *get_framebuffer_pixmap()
+{
+ return gfx->pixmap;
+}
+
+Rect get_screen_size()
+{
+ return gfx->screen_rect;
+}
+
+int get_color_depth()
+{
+ return gfx->color_depth;
+}
+
+void set_clipping_rect(const Rect &rect)
+{
+ gfx->clipping_rect = rect_intersection(rect, get_screen_size());
+}
+
+const Rect &get_clipping_rect()
+{
+ return gfx->clipping_rect;
+}
+
+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 gfx_update(const Rect &upd_rect)
+{
+ Rect rect = rect_intersection(upd_rect, gfx->screen_rect);
+ unsigned char *sptr = gfx->pixmap->pixels + (rect.y * gfx->screen_rect.width + rect.x) * 4;
+ unsigned char *dptr = framebuffer + (rect.y * gfx->screen_rect.width + rect.x) * 4;
+
+ for(int i=0; i<rect.height; i++) {
+ memcpy(dptr, sptr, rect.width * 4);
+ sptr += gfx->screen_rect.width * 4;
+ dptr += gfx->screen_rect.width * 4;
+ }
+}
+
+void wait_vsync()
+{
+ unsigned long arg = 0;
+ if(ioctl(dev_fd, FBIO_WAITFORVSYNC, &arg) == -1) {
+// printf("ioctl error %s\n", strerror(errno));
+ }
+}
+
+void get_rgb_order(int *r, int *g, int *b)
+{
+ *r = rgb_order[0];
+ *g = rgb_order[1];
+ *b = rgb_order[2];
+}
+
+#endif // WINNIE_FBDEV
diff --git a/libwinnie/src/fbdev/keyboard.cc b/libwinnie/src/fbdev/keyboard.cc
new file mode 100644
index 0000000..22f129a
--- /dev/null
+++ b/libwinnie/src/fbdev/keyboard.cc
@@ -0,0 +1,140 @@
+/*
+winnie - an experimental window system
+
+Copyright (C) 2013 Eleni Maria Stea
+
+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 3 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, see <http://www.gnu.org/licenses/>.
+
+Author: Eleni Maria Stea <elene.mst@gmail.com>
+*/
+
+#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 "shalloc.h"
+#include "window.h"
+#include "winnie.h"
+#include "wm.h"
+
+struct Keyboard {
+ int dev_fd;
+ enum {RAW, CANONICAL} ttystate;
+};
+
+static Keyboard *keyboard;
+
+bool init_keyboard()
+{
+ if(!(keyboard = (Keyboard*)sh_malloc(sizeof *keyboard))) {
+ return false;
+ }
+
+ get_subsys()->keyboard_offset = (int)((char*)keyboard - (char*)get_pool());
+
+ keyboard->ttystate = keyboard->CANONICAL;
+ keyboard->dev_fd = -1;
+
+ if((keyboard->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(keyboard->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(keyboard->dev_fd, TCSAFLUSH, &buf) < 0) {
+ return false;
+ }
+
+ keyboard->ttystate = keyboard->RAW;
+ return true;
+}
+
+void destroy_keyboard()
+{
+ struct termios buf;
+
+ if(tcgetattr(keyboard->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(keyboard->dev_fd, TCSAFLUSH, &buf) < 0) {
+ fprintf(stderr, "Cannot set the tty parameters : %s\n", strerror(errno));
+ }
+
+ keyboard->ttystate = keyboard->CANONICAL;
+
+ if(keyboard->dev_fd != -1) {
+ close(keyboard->dev_fd);
+ keyboard->dev_fd = -1;
+ }
+
+ sh_free(keyboard);
+}
+
+int get_keyboard_fd()
+{
+ return keyboard->dev_fd;
+}
+
+void process_keyboard_event()
+{
+ char key;
+ if(read(keyboard->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/libwinnie/src/fbdev/mouse.cc b/libwinnie/src/fbdev/mouse.cc
new file mode 100644
index 0000000..1fb2d55
--- /dev/null
+++ b/libwinnie/src/fbdev/mouse.cc
@@ -0,0 +1,202 @@
+/*
+winnie - an experimental window system
+
+Copyright (C) 2013 Eleni Maria Stea
+
+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 3 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, see <http://www.gnu.org/licenses/>.
+
+Author: Eleni Maria Stea <elene.mst@gmail.com>
+*/
+
+#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 "shalloc.h"
+#include "window.h"
+#include "winnie.h"
+#include "wm.h"
+
+#define BN_LEFT 1
+#define BN_RIGHT 2
+#define BN_MIDDLE 4
+
+static int read_mouse();
+
+struct Mouse {
+ int dev_fd;
+ Rect bounds;
+ int pointer_x;
+ int pointer_y;
+ int bnstate;
+};
+
+static Mouse *mouse;
+
+bool init_mouse()
+{
+ if(!(mouse = (Mouse*)sh_malloc(sizeof *mouse))) {
+ return false;
+ }
+ get_subsys()->mouse_offset = (int)((char*)mouse - (char*)get_pool());
+ memset(mouse, 0, sizeof *mouse);
+
+ mouse->dev_fd = -1;
+
+ if((mouse->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(mouse->dev_fd != -1) {
+ close(mouse->dev_fd);
+ mouse->dev_fd = -1;
+ }
+ sh_free(mouse);
+}
+
+void set_mouse_bounds(const Rect &rect)
+{
+ mouse->bounds = rect;
+}
+
+int get_mouse_fd()
+{
+ return mouse->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 = mouse->bnstate;
+ int prev_x = mouse->pointer_x;
+ int prev_y = mouse->pointer_y;
+
+ if(read_mouse() == -1) {
+ return;
+ }
+
+ Window *top;
+ if(!(top = wm->get_grab_window())) {
+ top = wm->get_window_at_pos(mouse->pointer_x, mouse->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 = mouse->pointer_x - prev_x;
+ int dy = mouse->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, mouse->pointer_x - rect.x, mouse->pointer_y - rect.y);
+ }
+ }
+
+ MouseButtonFuncType button_callback;
+ if((mouse->bnstate != prev_state) && top && (button_callback = top->get_mouse_button_callback())) {
+ int num_bits = sizeof mouse->bnstate * CHAR_BIT;
+ for(int i=0; i<num_bits; i++) {
+ int s = (mouse->bnstate >> i) & 1;
+ int prev_s = (prev_state >> i) & 1;
+ if(s != prev_s) {
+ Rect rect = top->get_absolute_rect();
+ button_callback(top, i, s, mouse->pointer_x - rect.x, mouse->pointer_y - rect.y);
+ }
+ }
+ }
+}
+
+void get_pointer_pos(int *x, int *y)
+{
+ *x = mouse->pointer_x;
+ *y = mouse->pointer_y;
+}
+
+int get_button_state()
+{
+ return mouse->bnstate;
+}
+
+int get_button(int bn)
+{
+ if(bn < 0 || bn >= 3) {
+ return 0;
+ }
+ return (mouse->bnstate & (1 << bn)) != 0;
+}
+
+static int read_mouse()
+{
+ int rd;
+ signed char state[3] = {0, 0, 0};
+
+ if((rd = read(mouse->dev_fd, state, 3)) == -1) {
+ fprintf(stderr, "Unable to get mouse state : %s\n", strerror(errno));
+ return -1;
+ }
+
+ mouse->bnstate = state[0] & 7;
+ mouse->pointer_x += state[1];
+ mouse->pointer_y -= state[2];
+
+ if(mouse->pointer_x < mouse->bounds.x) {
+ mouse->pointer_x = mouse->bounds.x;
+ }
+
+ if(mouse->pointer_y < mouse->bounds.y) {
+ mouse->pointer_y = mouse->bounds.y;
+ }
+
+ if(mouse->pointer_x > mouse->bounds.x + mouse->bounds.width - 1) {
+ mouse->pointer_x = mouse->bounds.x + mouse->bounds.width - 1;
+ }
+
+ if(mouse->pointer_y > mouse->bounds.y + mouse->bounds.height - 1) {
+ mouse->pointer_y = mouse->bounds.y + mouse->bounds.height - 1;
+ }
+
+ return 0;
+}
+#endif // WINNIE_FBDEV