created libwinnie (library), winnie (the server application) and clients
authorEleni Maria Stea <elene.mst@gmail.com>
Sun, 31 Mar 2013 22:29:13 +0000 (01:29 +0300)
committerEleni Maria Stea <elene.mst@gmail.com>
Sun, 31 Mar 2013 22:29:13 +0000 (01:29 +0300)
35 files changed:
.bzrignore
libwinnie/Makefile [new file with mode: 0644]
libwinnie/README [new file with mode: 0644]
libwinnie/src/event.h [new file with mode: 0644]
libwinnie/src/fbdev/event.cc [new file with mode: 0644]
libwinnie/src/fbdev/gfx.cc [new file with mode: 0644]
libwinnie/src/fbdev/keyboard.cc [new file with mode: 0644]
libwinnie/src/fbdev/mouse.cc [new file with mode: 0644]
libwinnie/src/geom.cc [new file with mode: 0644]
libwinnie/src/geom.h [new file with mode: 0644]
libwinnie/src/gfx.cc [new file with mode: 0644]
libwinnie/src/gfx.h [new file with mode: 0644]
libwinnie/src/keyboard.h [new file with mode: 0644]
libwinnie/src/mouse.h [new file with mode: 0644]
libwinnie/src/mouse_cursor.h [new file with mode: 0644]
libwinnie/src/pixmap.cc [new file with mode: 0644]
libwinnie/src/pixmap.h [new file with mode: 0644]
libwinnie/src/sdl/event.cc [new file with mode: 0644]
libwinnie/src/sdl/gfx.cc [new file with mode: 0644]
libwinnie/src/sdl/keyboard.cc [new file with mode: 0644]
libwinnie/src/sdl/mouse.cc [new file with mode: 0644]
libwinnie/src/semaphore.h [new file with mode: 0644]
libwinnie/src/shalloc.cc [new file with mode: 0644]
libwinnie/src/shalloc.h [new file with mode: 0644]
libwinnie/src/text.cc [new file with mode: 0644]
libwinnie/src/text.h [new file with mode: 0644]
libwinnie/src/window.cc [new file with mode: 0644]
libwinnie/src/window.h [new file with mode: 0644]
libwinnie/src/winnie.cc [new file with mode: 0644]
libwinnie/src/winnie.h [new file with mode: 0644]
libwinnie/src/wm.cc [new file with mode: 0644]
libwinnie/src/wm.h [new file with mode: 0644]
winnie/Makefile [new file with mode: 0644]
winnie/README [new file with mode: 0644]
winnie/src/main.cc [new file with mode: 0644]

index 94ca2b4..a438335 100644 (file)
@@ -1,9 +1 @@
-src/event.d
-src/geom.d
-src/gfx.d
-src/keyboard.d
-src/main.d
-src/mouse.d
-src/window.d
-src/winnie.d
-src/wm.d
+*.d
diff --git a/libwinnie/Makefile b/libwinnie/Makefile
new file mode 100644 (file)
index 0000000..df1e0e9
--- /dev/null
@@ -0,0 +1,40 @@
+PREFIX=/usr/local
+src = $(wildcard src/*.cc) $(wildcard src/fbdev/*.cc) $(wildcard src/sdl/*.cc)
+obj = $(src:.cc=.o)
+#dep = $(obj:.o=.d)
+lib_so = libwinnie.so
+
+dbg = -g
+opt = -O0
+inc = -Isrc
+
+backend = SDL
+
+ifeq ($(backend), SDL)
+       def = -DWINNIE_SDL
+       libs = -lSDL
+else
+       def = -DWINNIE_FBDEV
+endif
+
+CXX = g++
+CXXFLAGS = -pedantic -Wall $(dbg) $(opt) $(inc) $(def) `freetype-config --cflags`
+LDFLAGS = $(libs) `freetype-config --libs` -lrt
+
+$(lib_so): $(obj)
+       $(CXX) -o $@ -shared $(obj) $(LDFLAGS)
+
+.PHONY: clean
+clean:
+       rm -f $(obj) $(lib_so)
+
+.PHONY: install
+install: $(lib_so)
+       mkdir -p $(PREFIX)/lib
+       mkdir -p $(PREFIX)/bin
+       cp $(lib_so) $(PREFIX)/lib/$(lib_so)
+       ldconfig
+
+.PHONY: uninstall
+uninstall:
+       rm -f $(PREFIX)/lib/$(lib_so)
diff --git a/libwinnie/README b/libwinnie/README
new file mode 100644 (file)
index 0000000..b83f62c
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+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>
+*/
+
+The winnie library.
diff --git a/libwinnie/src/event.h b/libwinnie/src/event.h
new file mode 100644 (file)
index 0000000..2207c1b
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+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>
+*/
+
+#ifndef EVENT_H_
+#define EVENT_H_
+
+class Window;
+
+typedef void (*DisplayFuncType)(Window* win);
+typedef void (*KeyboardFuncType)(Window* win, int key, bool pressed);
+typedef void (*MouseButtonFuncType)(Window *win, int bn, bool pressed, int x, int y);
+typedef void (*MouseMotionFuncType)(Window *win, int x, int y);
+
+struct Callbacks {
+       DisplayFuncType display;
+       KeyboardFuncType keyboard;
+       MouseButtonFuncType button;
+       MouseMotionFuncType motion;
+};
+
+void process_events();
+
+#endif
diff --git a/libwinnie/src/fbdev/event.cc b/libwinnie/src/fbdev/event.cc
new file mode 100644 (file)
index 0000000..00e12cd
--- /dev/null
@@ -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 (file)
index 0000000..ff86d9c
--- /dev/null
@@ -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 (file)
index 0000000..22f129a
--- /dev/null
@@ -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 (file)
index 0000000..1fb2d55
--- /dev/null
@@ -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
diff --git a/libwinnie/src/geom.cc b/libwinnie/src/geom.cc
new file mode 100644 (file)
index 0000000..53181db
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+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>
+*/
+
+#include "geom.h"
+
+Rect::Rect()
+{
+       x = y = width = height = 0;
+}
+
+Rect::Rect(int x, int y, int w, int h)
+{
+       this->x = x;
+       this->y = y;
+       width = w;
+       height = h;
+}
+
+static inline int min(int x, int y)
+{
+       return x < y ? x : y;
+}
+
+static inline int max(int x, int y)
+{
+       return x > y ? x : y;
+}
+
+Rect rect_union(const Rect &a, const Rect &b)
+{
+       Rect uni;
+       uni.x = min(a.x, b.x);
+       uni.y = min(a.y, b.y);
+       uni.width = max(a.x + a.width, b.x + b.width) - uni.x;
+       uni.height = max(a.y + a.height, b.y + b.height) - uni.y;
+
+       return uni;
+}
+
+Rect rect_intersection(const Rect &a, const Rect &b)
+{
+       Rect intersect;
+       intersect.x = max(a.x, b.x);
+       intersect.y = max(a.y, b.y);
+       intersect.width = max(min(a.x + a.width, b.x + b.width) - intersect.x, 0);
+       intersect.height = max(min(a.y + a.height, b.y + b.height) - intersect.y, 0);
+
+       return intersect;
+}
diff --git a/libwinnie/src/geom.h b/libwinnie/src/geom.h
new file mode 100644 (file)
index 0000000..220069d
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+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>
+*/
+
+#ifndef GEOM_H_
+#define GEOM_H_
+
+struct Rect {
+       int x, y;
+       int width, height;
+
+       Rect();
+       Rect(int x, int y, int w, int h);
+};
+
+Rect rect_union(const Rect &a, const Rect &b);
+Rect rect_intersection(const Rect &a, const Rect &b);
+
+#endif // GEOM_H_
diff --git a/libwinnie/src/gfx.cc b/libwinnie/src/gfx.cc
new file mode 100644 (file)
index 0000000..b72e43b
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+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>
+*/
+
+#include <string.h>
+
+#include "geom.h"
+#include "gfx.h"
+
+void clear_screen(int r, int g, int b)
+{
+       Rect screen_rect = get_screen_size();
+       fill_rect(screen_rect, r, g, b);
+}
+
+void fill_rect(const Rect &rect, int r, int g, int b)
+{
+       Rect drect = rect;
+       Rect screen_rect = get_screen_size();
+       Rect clipping_rect = get_clipping_rect();
+
+       if(drect.x < clipping_rect.x) {
+               drect.width -= clipping_rect.x - drect.x;
+               drect.x = clipping_rect.x;
+       }
+
+       if(drect.y < clipping_rect.y) {
+               drect.height -= clipping_rect.y - drect.y;
+               drect.y = clipping_rect.y;
+       }
+
+       if(drect.x + drect.width >= clipping_rect.x + clipping_rect.width) {
+               drect.width = clipping_rect.width + clipping_rect.x - drect.x;
+       }
+
+       if(drect.y + drect.height >= clipping_rect.y + clipping_rect.height) {
+               drect.height = clipping_rect.height + clipping_rect.y - drect.y;
+       }
+
+       unsigned char *fb = get_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 blit(unsigned char *src_img, const Rect &src_rect, unsigned char* dest_img,
+               const Rect &dest_rect, int dest_x, int dest_y)
+{
+       int red_offs, green_offs, blue_offs;
+       get_rgb_order(&red_offs, &green_offs, &blue_offs);
+
+       Rect irect = rect_intersection(get_clipping_rect(), dest_rect);
+
+       int width = src_rect.width;
+       int height = src_rect.height;
+
+       int xoffs = dest_x - irect.x;
+       if(xoffs < 0) {
+               dest_x = irect.x;
+               width += xoffs;
+       }
+
+       int yoffs = dest_y - irect.y;
+       if(yoffs < 0) {
+               dest_y = irect.y;
+               height += yoffs;
+       }
+
+       int xend = dest_x + width;
+       if(xend >= irect.width) {
+               width -= xend - irect.width;
+       }
+
+       int yend = dest_y + height;
+       if(yend >= irect.height) {
+               height -= yend - irect.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++) {
+                       dptr[j * 4 + red_offs] = sptr[j * 4];
+                       dptr[j * 4 + green_offs] = sptr[j * 4 + 1];
+                       dptr[j * 4 + blue_offs] = sptr[j * 4 + 2];
+               }
+               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 red_offs, green_offs, blue_offs;
+       get_rgb_order(&red_offs, &green_offs, &blue_offs);
+
+       Rect irect = rect_intersection(get_clipping_rect(), dest_rect);
+
+       int width = src_rect.width;
+       int height = src_rect.height;
+
+       int xoffs = dest_x - irect.x;
+       if(xoffs < 0) {
+               dest_x = irect.x;
+               width += xoffs;
+       }
+
+       int yoffs = dest_y - irect.y;
+       if(yoffs < 0) {
+               dest_y = irect.y;
+               height += yoffs;
+       }
+
+       int xend = dest_x + width;
+       if(xend >= irect.width) {
+               width -= xend - irect.width;
+       }
+
+       int yend = dest_y + height;
+       if(yend >= irect.height) {
+               height -= yend - irect.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 + red_offs] = r;
+                               dptr[j * 4 + green_offs] = g;
+                               dptr[j * 4 + blue_offs] = b;
+                       }
+               }
+
+               sptr += src_rect.width * 4;
+               dptr += dest_rect.width * 4;
+       }
+}
diff --git a/libwinnie/src/gfx.h b/libwinnie/src/gfx.h
new file mode 100644 (file)
index 0000000..e6d4b49
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+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>
+*/
+
+#ifndef GFX_H_
+#define GFX_H_
+
+#include "geom.h"
+#include "pixmap.h"
+
+bool init_gfx();
+void destroy_gfx();
+
+unsigned char *get_framebuffer();
+Pixmap *get_framebuffer_pixmap();
+
+Rect get_screen_size();
+int get_color_depth();
+
+void set_clipping_rect(const Rect &clip_rect);
+const Rect &get_clipping_rect();
+
+void clear_screen(int r, int g, int b);
+void fill_rect(const Rect &rect, int r, int g, int b);
+
+void set_cursor_visibility(bool visible);
+
+void blit(unsigned char *src_img, const Rect &src_rect, unsigned char* dest_img,
+               const Rect &dest_rect, int dest_x, int dest_y);
+
+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);
+
+void gfx_update(const Rect &rect);
+
+void wait_vsync(); // vertical synchronization
+
+void get_rgb_order(int *r, int *g, int *b);
+
+#endif //GFX_H_
diff --git a/libwinnie/src/keyboard.h b/libwinnie/src/keyboard.h
new file mode 100644 (file)
index 0000000..548ddbb
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+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>
+*/
+
+#ifndef KEYBOARD_H_
+#define KEYBOARD_H_
+
+bool init_keyboard();
+void destroy_keyboard();
+
+int get_keyboard_fd();
+void process_keyboard_event();
+
+#endif // KEYBOARD_H_
diff --git a/libwinnie/src/mouse.h b/libwinnie/src/mouse.h
new file mode 100644 (file)
index 0000000..6fbe711
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+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>
+*/
+
+#ifndef MOUSE_H_
+#define MOUSE_H_
+
+struct Rect;
+
+bool init_mouse();
+void destroy_mouse();
+
+void set_mouse_bounds(const Rect &rect);
+
+int get_mouse_fd();
+void process_mouse_event();
+
+void get_pointer_pos(int *x, int *y);
+int get_button_state();
+int get_button(int bn);
+
+#endif // MOUSE_H_
diff --git a/libwinnie/src/mouse_cursor.h b/libwinnie/src/mouse_cursor.h
new file mode 100644 (file)
index 0000000..f64934e
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+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>
+*/
+
+#ifndef MOUSE_CURSOR_H_
+#define MOUSE_CURSOR_H_
+
+const int mouse_cursor_width = 8;
+const int mouse_cursor_height = 16;
+
+const int mouse_cursor_bw[] = {
+       128, 128,   0,   0,   0,   0,   0,   0,
+       128, 255, 128,   0,   0,   0,   0,   0,
+       128, 255, 255, 128,   0,   0,   0,   0,
+       128, 255, 255, 255, 128,   0,   0,   0,
+       128, 255, 255, 255, 255, 128,   0,   0,
+       128, 255, 255, 255, 255, 255, 128,   0,
+       128, 255, 255, 255, 255, 255, 255, 128,
+       128, 255, 255, 255, 255, 255, 128,   0,
+       128, 255, 255, 255, 255, 128,   0,   0,
+       128, 255, 255, 255, 255, 128,   0,   0,
+       128, 255, 255, 255, 255, 255, 128,   0,
+       128, 255, 255, 255, 255, 255, 128,   0,
+       128, 255, 128, 128, 255, 255, 255, 128,
+       128, 128,   0, 128, 255, 255, 255, 128,
+       128,   0,   0,   0, 128, 255, 255, 128,
+         0,   0,   0,   0,   0, 128, 128, 128
+};
+
+
+
+#endif // MOUSE_CURSOR_H_
diff --git a/libwinnie/src/pixmap.cc b/libwinnie/src/pixmap.cc
new file mode 100644 (file)
index 0000000..8e50fa3
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+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>
+*/
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include "pixmap.h"
+
+Pixmap::Pixmap()
+{
+       width = height = 0;
+       pixels = 0;
+}
+
+Pixmap::Pixmap(const Pixmap &pixmap)
+{
+       width = height = 0;
+       pixels = 0;
+       set_image(pixmap.width, pixmap.height, pixmap.pixels);
+}
+
+Pixmap &Pixmap::operator=(const Pixmap &pixmap)
+{
+       if(this != &pixmap) {
+               set_image(pixmap.width, pixmap.height, pixmap.pixels);
+       }
+
+       return *this;
+}
+
+Pixmap::~Pixmap()
+{
+       if(pixels) {
+               delete [] pixels;
+       }
+}
+
+int Pixmap::get_width() const
+{
+       return width;
+}
+
+int Pixmap::get_height() const
+{
+       return height;
+}
+
+Rect Pixmap::get_rect() const
+{
+       Rect rect(0, 0, width, height);
+       return rect;
+}
+
+bool Pixmap::set_image(int x, int y, unsigned char *pix)
+{
+       delete [] pixels;
+
+       pixels = new unsigned char[x * y * 4];
+       width = x;
+       height = y;
+
+       if(pix) {
+               memcpy(pixels, pix, x * y * 4);
+       }
+       return true;
+}
+
+const unsigned char *Pixmap::get_image() const
+{
+       return pixels;
+}
+
+unsigned char *Pixmap::get_image()
+{
+       return pixels;
+}
+
+bool Pixmap::load(const char *fname)
+{
+       FILE *fp;
+       int hdrline = 0;
+
+       if(!(fp = fopen(fname, "rb"))) {
+               fprintf(stderr, "failed to open pixmap: %s: %s\n", fname, strerror(errno));
+               return false;
+       }
+
+       /* read ppm header */
+       while(hdrline < 3) {
+               char buf[64];
+
+               if(!fgets(buf, sizeof buf, fp))
+                       goto err;
+               
+               /* skip comments */
+               if(buf[0] == '#')
+                       continue;
+
+               switch(hdrline++) {
+               case 0:
+                       /* first header line should be P6 */
+                       if(strcmp(buf, "P6\n") != 0)
+                               goto err;
+                       break;
+
+               case 1:
+                       /* second header line contains the pixmap dimensions */
+                       if(sscanf(buf, "%d %d", &width, &height) != 2)
+                               goto err;
+                       break;
+               }
+       }
+
+       set_image(width, height, 0);
+
+       for(int i=0; i<width * height * 4; i++) {
+               int c;
+               if(i % 4 != 3) {
+                       c = fgetc(fp);
+                       if(c < 0)
+                               goto err;
+               }
+               else {
+                       c = 255;
+               }
+               pixels[i] = c;
+       }
+       fclose(fp);
+       return true;
+
+err:
+       fprintf(stderr, "failed to load pixmap: %s\n", fname);
+       fclose(fp);
+       return false;
+}
+
+bool Pixmap::save(const char *fname) const
+{
+       if(!pixels) {
+               return false;
+       }
+
+       FILE *fp = fopen(fname, "wb");
+       if(!fp) {
+               fprintf(stderr, "failed to save pixmap: %s: %s\n", fname, strerror(errno));
+               return false;
+       }
+
+       fprintf(fp, "P6\n%d %d\n255\n", width, height);
+
+       for(int i=0; i<width * height; i++) {
+               fputc(pixels[i * 4], fp);
+               fputc(pixels[i * 4 + 1], fp);
+               fputc(pixels[i * 4 + 2], fp);
+       }
+
+       fclose(fp);
+       return true;
+}
diff --git a/libwinnie/src/pixmap.h b/libwinnie/src/pixmap.h
new file mode 100644 (file)
index 0000000..3ebfd87
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+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>
+*/
+
+#ifndef PIXMAP_H_
+#define PIXMAP_H_
+
+#include "geom.h"
+
+class Pixmap {
+public:
+       int width, height;
+       unsigned char *pixels;
+
+       Pixmap();
+
+       Pixmap(const Pixmap &pixmap);
+       Pixmap &operator=(const Pixmap& pixmap);
+
+       ~Pixmap();
+
+       int get_width() const;
+       int get_height() const;
+       Rect get_rect() const;
+
+       bool set_image(int x, int y, unsigned char *pix = 0);
+       const unsigned char *get_image() const;
+       unsigned char *get_image();
+
+       bool load(const char *fname);
+       bool save(const char *fname) const;
+};
+
+#endif // PIXMAP_H_
diff --git a/libwinnie/src/sdl/event.cc b/libwinnie/src/sdl/event.cc
new file mode 100644 (file)
index 0000000..685c323
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+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_SDL
+#include <stdlib.h>
+#include <SDL/SDL.h>
+
+#include "event.h"
+#include "keyboard.h"
+#include "mouse.h"
+#include "wm.h"
+
+SDL_Event sdl_event;
+void process_events()
+{
+       wm->process_windows();
+       if(!SDL_WaitEvent(&sdl_event)) {
+               return;
+       }
+
+       switch(sdl_event.type) {
+       case SDL_KEYDOWN:
+       case SDL_KEYUP:
+               process_keyboard_event();
+               break;
+       case SDL_MOUSEMOTION:
+       case SDL_MOUSEBUTTONDOWN:
+       case SDL_MOUSEBUTTONUP:
+               process_mouse_event();
+               break;
+       case SDL_QUIT:
+               exit(0);
+       default:
+               break;
+       }
+}
+
+#endif // WINNIE_SDL
diff --git a/libwinnie/src/sdl/gfx.cc b/libwinnie/src/sdl/gfx.cc
new file mode 100644 (file)
index 0000000..7e098b9
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+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_SDL
+#include <stdio.h>
+#include <stdlib.h>
+#include <SDL/SDL.h>
+
+#include "gfx.h"
+#include "shalloc.h"
+#include "winnie.h"
+
+static SDL_Surface *fbsurf;
+
+struct Graphics {
+       Rect screen_rect;
+       Rect clipping_rect;
+       int color_depth; // bits per pixel
+       Pixmap *pixmap;
+};
+
+static Graphics *gfx;
+
+bool init_gfx()
+{
+       if(SDL_Init(SDL_INIT_VIDEO) == -1) {
+               fprintf(stderr, "failed to initialize SDL\n");
+               return false;
+       }
+
+       if(!(gfx = (Graphics*)sh_malloc(sizeof *gfx))) {
+               return false;
+       }
+
+       get_subsys()->graphics_offset = (int)((char*)gfx - (char*)get_pool());
+
+       Rect scr_rect(0, 0, 1024, 768);
+       gfx->screen_rect = scr_rect;
+       gfx->color_depth = 32;
+
+       if(!(fbsurf = SDL_SetVideoMode(gfx->screen_rect.width, gfx->screen_rect.height, gfx->color_depth, 0))) {
+               fprintf(stderr, "Failed to set video mode\n");
+               return false;
+       }
+       SDL_ShowCursor(0);
+
+       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;
+       }
+
+       set_clipping_rect(gfx->screen_rect);
+
+       return true;
+}
+
+void destroy_gfx()
+{
+       sh_free(gfx->pixmap->pixels);
+       gfx->pixmap->pixels = 0;
+       sh_free(gfx->pixmap);
+       sh_free(gfx);
+       SDL_Quit();
+}
+
+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)
+{
+}
+
+void gfx_update(const Rect &upd_rect)
+{
+       if(SDL_MUSTLOCK(fbsurf)) {
+               SDL_LockSurface(fbsurf);
+       }
+
+       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 = (unsigned char*)fbsurf->pixels + (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;
+       }
+
+       if(SDL_MUSTLOCK(fbsurf)) {
+               SDL_UnlockSurface(fbsurf);
+       }
+       SDL_UpdateRect(fbsurf, rect.x, rect.y, rect.width, rect.height);
+}
+
+void wait_vsync()
+{
+}
+
+void get_rgb_order(int *r, int *g, int *b)
+{
+       *r = fbsurf->format->Rshift / 8;
+       *g = fbsurf->format->Gshift / 8;
+       *b = fbsurf->format->Bshift / 8;
+}
+
+#endif // WINNIE_SDL
diff --git a/libwinnie/src/sdl/keyboard.cc b/libwinnie/src/sdl/keyboard.cc
new file mode 100644 (file)
index 0000000..2290213
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+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_SDL
+#include <SDL/SDL.h>
+
+#include "keyboard.h"
+#include "window.h"
+#include "wm.h"
+
+extern SDL_Event sdl_event;
+
+bool init_keyboard()
+{
+       return true;
+}
+
+void destroy_keyboard()
+{
+}
+
+int get_keyboard_fd()
+{
+       return -1;
+}
+
+void process_keyboard_event()
+{
+       int key = sdl_event.key.keysym.sym;
+
+       Window *focused_win = wm->get_focused_window();
+       if(focused_win) {
+               KeyboardFuncType keyb_callback = focused_win->get_keyboard_callback();
+               if(keyb_callback) {
+                       bool pressed = sdl_event.key.state == SDL_PRESSED;
+                       keyb_callback(focused_win, key, pressed);
+               }
+       }
+}
+#endif // WINNIE_SDL
diff --git a/libwinnie/src/sdl/mouse.cc b/libwinnie/src/sdl/mouse.cc
new file mode 100644 (file)
index 0000000..3ba98a0
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+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_SDL
+#include <SDL/SDL.h>
+
+#include "mouse.h"
+#include "shalloc.h"
+#include "wm.h"
+#include "window.h"
+#include "winnie.h"
+
+extern SDL_Event sdl_event;
+
+struct Mouse {
+       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);
+       return true;
+}
+
+void destroy_mouse()
+{
+       sh_free(mouse);
+}
+
+void set_mouse_bounds(const Rect &rect)
+{
+}
+
+int get_mouse_fd()
+{
+       return -1;
+}
+
+void process_mouse_event()
+{
+       int bn;
+       MouseMotionFuncType motion_callback = 0;
+       MouseButtonFuncType button_callback = 0;
+
+       Window *win;
+       if(!(win = wm->get_grab_window())) {
+               win = wm->get_window_at_pos(mouse->pointer_x, mouse->pointer_y);
+               if(win) {
+                       wm->set_focused_window(win);
+               }
+               else {
+                       wm->set_focused_window(0);
+               }
+       }
+
+       switch(sdl_event.type) {
+       case SDL_MOUSEMOTION:
+               mouse->pointer_x = sdl_event.motion.x;
+               mouse->pointer_y = sdl_event.motion.y;
+               if(win && (motion_callback = win->get_mouse_motion_callback())) {
+                       Rect rect = win->get_absolute_rect();
+                       motion_callback(win, mouse->pointer_x - rect.x, mouse->pointer_y - rect.y);
+               }
+               break;
+
+       case SDL_MOUSEBUTTONUP:
+       case SDL_MOUSEBUTTONDOWN:
+               bn = sdl_event.button.button - SDL_BUTTON_LEFT;
+               if(sdl_event.button.state == SDL_PRESSED) {
+                       mouse->bnstate |= 1 << bn;
+               }
+               else {
+                       mouse->bnstate &= ~(1 << bn);
+               }
+               if(win && (button_callback = win->get_mouse_button_callback())) {
+                       Rect rect = win->get_absolute_rect();
+                       button_callback(win, bn, sdl_event.button.state, 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;
+}
+#endif // WINNIE_SDL
diff --git a/libwinnie/src/semaphore.h b/libwinnie/src/semaphore.h
new file mode 100644 (file)
index 0000000..1ab8920
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+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>
+*/
+
+#ifndef SEMAPHORE_H_
+#define SEMAPHORE_H_
+
+bool init_semaphore();
+void destroy_semaphore();
+
+#endif // SEMAPHORE_H_
diff --git a/libwinnie/src/shalloc.cc b/libwinnie/src/shalloc.cc
new file mode 100644 (file)
index 0000000..5d4715a
--- /dev/null
@@ -0,0 +1,217 @@
+/*
+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>
+*/
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <map>
+
+#include "shalloc.h"
+
+#define SHMNAME        "/winnie.shm"
+
+#define POOL_SIZE 16777216
+#define BLOCK_SIZE 512
+
+#define NUM_BLOCKS (POOL_SIZE / BLOCK_SIZE)
+#define BITMAP_SIZE (NUM_BLOCKS / 32)
+
+static bool is_allocated(int block_number);
+static int addr_to_block(unsigned char *addr);
+static unsigned char *block_to_addr(int block_number);
+static void alloc_blocks(int block_pos, int num_blocks);
+static void free_blocks(int block_pos, int num_blocks);
+
+static void print_stats();
+static int fd;
+
+static unsigned char *pool;
+static std::map<int, int> alloc_sizes; //starting block -> number of blocks
+
+// 0 means not allocated 1 means allocated
+static uint32_t bitmap[BITMAP_SIZE];
+
+struct Statistics {
+       int alloc_num;
+       int free_num;
+       int alloc_memsize;
+       int free_memsize;
+};
+
+static Statistics stats;
+
+bool init_shared_memory()
+{
+       if(((fd = shm_open(SHMNAME, O_RDWR | O_CREAT, S_IRWXU)) == -1)) {
+               fprintf(stderr, "Failed to open shared memory: %s\n", strerror(errno));
+               return false;
+       }
+       ftruncate(fd, POOL_SIZE);
+
+       if((pool = (unsigned char*)mmap(0, POOL_SIZE, PROT_READ | PROT_WRITE,
+                                       MAP_SHARED, fd, 0)) == (void*)-1) {
+               fprintf(stderr, "Failed to map shared memory: %s\n", strerror(errno));
+       }
+
+       shm_unlink(SHMNAME);
+
+       for(int i=0; i<BITMAP_SIZE; i++) {
+               bitmap[i] = 0;
+       }
+
+       alloc_sizes.clear();
+       memset(&stats, 0, sizeof stats);
+
+       return true;
+}
+
+void destroy_shared_memory()
+{
+       print_stats();
+       if(munmap(pool, POOL_SIZE) == -1) {
+               fprintf(stderr, "Failed to unmap shared memory: %s\n", strerror(errno));
+       }
+}
+
+void *sh_malloc(size_t bytes)
+{
+       if(!bytes) {
+               return 0;
+       }
+
+       int num_blocks = (bytes + BLOCK_SIZE - 1) / BLOCK_SIZE;
+       
+       int free_block;
+       int ctr = 0;
+       for(int i=0; i<NUM_BLOCKS; i++) {
+               if(!is_allocated(i)) {
+                       if(!ctr) {
+                               free_block = i;
+                       }
+                       ctr++;
+               }
+               else {
+                       ctr = 0;
+               }
+
+               if(ctr == num_blocks) {
+                       alloc_blocks(free_block, num_blocks);
+                       return block_to_addr(free_block);
+               }
+       }
+
+       return 0;
+}
+
+void sh_free(void *ptr)
+{
+       int block = addr_to_block((unsigned char*)ptr);
+       std::map<int, int>::iterator it;
+       if((it = alloc_sizes.find(block)) != alloc_sizes.end()) {
+               int num_blocks = it->second;
+               free_blocks(block, num_blocks);
+               alloc_sizes.erase(it);
+       }
+       else {
+               fprintf(stderr, "Attempt to free non-existent blocks from: %d\n", block);
+       }
+}
+
+void *get_pool()
+{
+       return (void*)pool;
+}
+
+static bool is_allocated(int block_number)
+{
+       int idx = block_number / 32;
+       int bit_num = block_number % 32;
+
+       if((bitmap[idx] >> bit_num) & 1) {
+               return true;
+       }
+
+       return false;
+}
+
+static int addr_to_block(unsigned char *addr)
+{
+       assert(addr >= pool);
+       assert(addr < pool + POOL_SIZE);
+
+       return (addr - pool) / BLOCK_SIZE;
+}
+
+static unsigned char *block_to_addr(int block_number)
+{
+       assert(block_number >= 0);
+       assert(block_number < NUM_BLOCKS);
+
+       return pool + block_number * BLOCK_SIZE;
+}
+
+static void alloc_blocks(int block_pos, int num_blocks)
+{
+       for(int i=0; i<num_blocks; i++) {
+               int block_number = i + block_pos;
+               int idx = block_number / 32;
+               int bit_num = block_number % 32;
+       
+               bitmap[idx] |= ((uint32_t)1 << bit_num); // or pow(2, i)
+       }
+
+       alloc_sizes[block_pos] = num_blocks;
+
+       stats.alloc_num++;
+       stats.alloc_memsize += BLOCK_SIZE * num_blocks;
+}
+
+static void free_blocks(int block_pos, int num_blocks)
+{
+       for(int i=0; i<num_blocks; i++) {
+               int block_number = i + block_pos;
+               int idx = block_number / 32;
+               int bit_num = block_number % 32;
+
+               bitmap[idx] &= ~((uint32_t)1 << bit_num);
+       }
+
+       stats.free_num++;
+       stats.free_memsize += BLOCK_SIZE * num_blocks;
+}
+
+static void print_stats()
+{
+       printf("Total allocated memory: %d\n", stats.alloc_memsize);
+       printf("Total deallocated memory: %d\n", stats.free_memsize);
+       printf("Number of allocations: %d\n", stats.alloc_num);
+       printf("Number of deallocations: %d\n", stats.free_num);
+}
+
diff --git a/libwinnie/src/shalloc.h b/libwinnie/src/shalloc.h
new file mode 100644 (file)
index 0000000..bb0daf7
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+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>
+*/
+
+#ifndef SHALLOC_H_
+#define SHALLOC_H_
+
+#include <cstring>
+
+bool init_shared_memory();
+void destroy_shared_memory();
+
+void *sh_malloc(size_t bytes);
+void sh_free(void *ptr);
+
+void *get_pool();
+
+#endif // SHALLOC_H_
diff --git a/libwinnie/src/text.cc b/libwinnie/src/text.cc
new file mode 100644 (file)
index 0000000..7dbae5d
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+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>
+*/
+
+#include <ft2build.h>
+#include <freetype/freetype.h>
+
+#include "gfx.h"
+#include "shalloc.h"
+#include "text.h"
+#include "winnie.h"
+
+#define DPI 72
+#define FONT_PATH "/usr/share/fonts/truetype/ttf-dejavu/DejaVuSansMono.ttf"
+#define FONT_SIZE 16
+
+static int draw_glyph(Pixmap *pixmap, int x, int y, char c);
+
+struct Text {
+       FT_Library ft_lib;
+       FT_Face ft_face;
+       int text_x, text_y;
+       int text_color[3];
+};
+
+static Text *text;
+
+bool init_text()
+{
+       if(!(text = (Text*)sh_malloc(sizeof *text))) {
+               return false;
+       }
+
+       get_subsys()->text_offset = (int)((char*)text - (char*)get_pool());
+
+       if(FT_Init_FreeType(&text->ft_lib)) {
+               fprintf(stderr, "Failed to initialize the FreeType library!\n");
+               return false;
+       }
+
+       if(FT_New_Face(text->ft_lib, FONT_PATH, 0, &text->ft_face)) {
+               fprintf(stderr, "Failed to load font: %s\n", FONT_PATH);
+               return false;
+       }
+
+       if(FT_Set_Char_Size(text->ft_face, 0, FONT_SIZE * 64, DPI, DPI)) {
+               fprintf(stderr, "Failed to set font size\n");
+               return false;
+       }
+
+       set_text_color(255, 255, 255);
+
+       return true;
+}
+
+void destroy_text()
+{
+       sh_free(text);
+}
+
+void draw_text(const char *txt, Pixmap *pixmap)
+{
+       if(!pixmap) {
+               pixmap = get_framebuffer_pixmap();
+       }
+
+       while(*txt != 0) {
+               text->text_x += draw_glyph(pixmap, text->text_x, text->text_y, *txt);
+               txt++;
+       }
+}
+
+void set_text_position(int x, int y)
+{
+       text->text_x = x;
+       text->text_y = y;
+
+}
+
+void set_text_color(int r, int g, int b)
+{
+       text->text_color[0] = r;
+       text->text_color[1] = g;
+       text->text_color[2] = b;
+}
+
+static int draw_glyph(Pixmap *pixmap, int x, int y, char c)
+{
+       if(FT_Load_Char(text->ft_face, c, FT_LOAD_RENDER)) {
+               return 0;
+       }
+
+       x += text->ft_face->glyph->bitmap_left;
+       y -= text->ft_face->glyph->bitmap_top;
+
+       FT_Bitmap *ft_bmp = &text->ft_face->glyph->bitmap;
+       unsigned char *bmp_ptr = ft_bmp->buffer;
+       unsigned char *pxm_ptr = pixmap->get_image() + (pixmap->get_width() * y + x) * 4;
+
+       Rect clipping_rect = get_clipping_rect();
+
+       for(int i=0; i<ft_bmp->rows; i++) {
+               int dest_y = i + y;
+               if(dest_y >= clipping_rect.y + clipping_rect.height) {
+                       break;
+               }
+
+               if(dest_y >= clipping_rect.y) {
+                       for(int j=0; j<ft_bmp->width; j++) {
+                               int dest_x = j + x;
+
+                               if(dest_x >= clipping_rect.x + clipping_rect.width) {
+                                       break;
+                               }
+
+                               if(bmp_ptr[j] && dest_x >= clipping_rect.x) {
+                                       int a = (int)bmp_ptr[j];
+                                       pxm_ptr[4 * j] = (a * text->text_color[0] + pxm_ptr[4 * j] * (255 - a)) / 255;
+                                       pxm_ptr[4 * j + 1] = (a * text->text_color[1] + pxm_ptr[4 * j + 1] * (255 - a)) / 255;
+                                       pxm_ptr[4 * j + 2] = (a * text->text_color[2] + pxm_ptr[4 * j + 2] * (255 - a)) / 255;
+                               }
+                       }
+               }
+
+               pxm_ptr += 4 * pixmap->get_width();
+               bmp_ptr += ft_bmp->pitch;
+       }
+
+       return text->ft_face->glyph->advance.x >> 6;
+}
diff --git a/libwinnie/src/text.h b/libwinnie/src/text.h
new file mode 100644 (file)
index 0000000..a94388a
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+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>
+*/
+
+#ifndef TEXT_H_
+#define TEXT_H_
+
+bool init_text();
+void destroy_text();
+
+void draw_text(const char *txt, Pixmap *pixmap = 0);
+void set_text_position(int x, int y);
+void set_text_color(int r, int g, int b);
+
+#endif // TEXT_H_
diff --git a/libwinnie/src/window.cc b/libwinnie/src/window.cc
new file mode 100644 (file)
index 0000000..04f72cd
--- /dev/null
@@ -0,0 +1,271 @@
+/*
+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>
+*/
+
+#include <algorithm>
+#include <stdio.h> //TODO
+#include <string.h>
+
+#include "gfx.h"
+#include "window.h"
+#include "wm.h"
+
+Window::Window()
+{
+       parent = 0;
+       title = 0;
+       rect.x = rect.y = 0;
+       rect.width = rect.height = 128;
+       memset(&callbacks, 0, sizeof callbacks);
+       dirty = true;
+       managed = true;
+       focusable = true;
+       state = STATE_NORMAL;
+}
+
+Window::~Window()
+{
+       for(size_t i=0; i<children.size(); i++) {
+               wm->remove_window(children[i]);
+               delete children[i];
+       }
+
+       delete [] title;
+}
+
+const Rect &Window::get_rect() const
+{
+       return rect;
+}
+
+Rect Window::get_absolute_rect() const
+{
+       if(!parent) {
+               return rect;
+       }
+
+       Rect absolute_rect;
+       absolute_rect = parent->get_absolute_rect();
+
+       absolute_rect.x += rect.x;
+       absolute_rect.y += rect.y;
+       absolute_rect.width = rect.width;
+       absolute_rect.height = rect.height;
+
+       return absolute_rect;
+}
+
+bool Window::contains_point(int ptr_x, int ptr_y)
+{
+       Rect abs_rect = get_absolute_rect();
+       return ptr_x >= abs_rect.x && ptr_x < abs_rect.x + abs_rect.width &&
+                       ptr_y >= abs_rect.y && ptr_y < abs_rect.y + abs_rect.height;
+}
+
+void Window::move(int x, int y)
+{
+       invalidate();   // moved, should redraw, MUST BE CALLED FIRST
+       rect.x = x;
+       rect.y = y;
+}
+
+void Window::resize(int x, int y)
+{
+       invalidate();   // resized, should redraw, MUST BE CALLED FIRST
+       rect.width = x;
+       rect.height = y;
+}
+
+void Window::set_title(const char *s)
+{
+       delete [] title;
+
+       title = new char[strlen(s) + 1];
+       strcpy(title, s);
+}
+
+const char *Window::get_title() const
+{
+       return title;
+}
+
+void Window::invalidate()
+{
+       dirty = true;
+       Rect abs_rect = get_absolute_rect();
+       wm->invalidate_region(abs_rect);
+}
+
+void Window::draw(Rect *dirty_region)
+{
+       Rect abs_rect = get_absolute_rect();
+       Rect intersect = rect_intersection(abs_rect, *dirty_region);
+       if(intersect.width && intersect.height) {
+               Rect prev_clip = get_clipping_rect();
+               set_clipping_rect(abs_rect);
+               
+               if(callbacks.display) {
+                       callbacks.display(this);
+               }
+               dirty = false;
+
+               draw_children(abs_rect);
+               
+               *dirty_region = rect_union(*dirty_region, abs_rect);
+               set_clipping_rect(prev_clip);
+       }
+}
+
+void Window::draw_children(const Rect &dirty_region)
+{
+       Rect drect = dirty_region;
+       for(size_t i=0; i<children.size(); i++) {
+               children[i]->draw(&drect);
+       }
+}
+
+unsigned char *Window::get_win_start_on_fb()
+{
+       unsigned char *fb = get_framebuffer();
+       Rect abs_rect = get_absolute_rect();
+       return fb + get_color_depth() * (get_screen_size().x * abs_rect.y + abs_rect.x) / 8;
+}
+
+int Window::get_scanline_width()
+{
+       return get_screen_size().x;
+}
+
+void Window::set_managed(bool managed)
+{
+       this->managed = managed;
+}
+
+bool Window::get_managed() const
+{
+       return managed;
+}
+
+void Window::set_focusable(bool focusable)
+{
+       this->focusable = focusable;
+}
+
+bool Window::get_focusable() const
+{
+       return focusable;
+}
+
+bool Window::get_dirty() const
+{
+       return dirty;
+}
+
+void Window::set_display_callback(DisplayFuncType func)
+{
+       callbacks.display = func;
+}
+
+void Window::set_keyboard_callback(KeyboardFuncType func)
+{
+       callbacks.keyboard = func;
+}
+
+void Window::set_mouse_button_callback(MouseButtonFuncType func)
+{
+       callbacks.button = func;
+}
+
+void Window::set_mouse_motion_callback(MouseMotionFuncType func)
+{
+       callbacks.motion = func;
+}
+
+const DisplayFuncType Window::get_display_callback() const
+{
+       return callbacks.display;
+}
+
+const KeyboardFuncType Window::get_keyboard_callback() const
+{
+       return callbacks.keyboard;
+}
+
+const MouseButtonFuncType Window::get_mouse_button_callback() const
+{
+       return callbacks.button;
+}
+
+const MouseMotionFuncType Window::get_mouse_motion_callback() const
+{
+       return callbacks.motion;
+}
+
+void Window::add_child(Window *win)
+{
+       children.push_back(win);
+       if(win->parent) {
+               win->parent->remove_child(win);
+       }
+       win->parent = this;
+}
+
+void Window::remove_child(Window *win)
+{
+       std::vector<Window*>::iterator it;
+       it = std::find(children.begin(), children.end(), win);
+       if(it != children.end()) {
+               children.erase(it);
+               win->parent = 0;
+       }
+}
+
+Window **Window::get_children()
+{
+       if(children.empty()) {
+               return 0;
+       }
+       return &children[0];
+}
+
+int Window::get_children_count() const
+{
+       return (int)children.size();
+}
+
+const Window *Window::get_parent() const
+{
+       return parent;
+}
+
+Window *Window::get_parent()
+{
+       return parent;
+}
+
+void Window::set_state(State state)
+{
+       this->state = state;
+}
+
+Window::State Window::get_state() const
+{
+       return state;
+}
diff --git a/libwinnie/src/window.h b/libwinnie/src/window.h
new file mode 100644 (file)
index 0000000..b5cc360
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+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>
+*/
+
+#ifndef WINDOW_H_
+#define WINDOW_H_
+
+#include <vector>
+
+#include "geom.h"
+#include "event.h"
+
+class Window {
+public:
+       enum State {STATE_NORMAL, STATE_MINIMIZED, STATE_MAXIMIZED, STATE_SHADED};
+
+private:
+       char *title;
+       State state;
+
+       Rect rect;
+       Rect normal_rect; // normal state rectangle managed by the wm
+
+       Callbacks callbacks;
+
+       std::vector<Window*> children;
+       Window* parent;
+
+       bool dirty;
+       bool managed; // whether the wm manages (+decorates) this win
+       bool focusable;
+
+public:
+       Window();
+       ~Window();
+
+       const Rect &get_rect() const;
+       Rect get_absolute_rect() const;
+       bool contains_point(int ptr_x, int ptr_y);
+
+       void move(int x, int y);
+       void resize(int x, int y);
+
+       void set_title(const char *s);
+       const char *get_title() const;
+
+       /* mark this window as dirty, and notify the window manager
+        * to repaint it, and anything it used to cover.
+        */
+       void invalidate();
+
+       void draw(Rect *dirty_region);
+       void draw_children(const Rect &dirty_region);
+
+       unsigned char *get_win_start_on_fb();
+       int get_scanline_width();
+
+       void set_managed(bool managed);
+       bool get_managed() const;
+
+       void set_focusable(bool focusable);
+       bool get_focusable() const;
+
+       bool get_dirty() const;
+
+       void set_display_callback(DisplayFuncType func);
+       void set_keyboard_callback(KeyboardFuncType func);
+       void set_mouse_button_callback(MouseButtonFuncType func);
+       void set_mouse_motion_callback(MouseMotionFuncType func);
+
+       const DisplayFuncType get_display_callback() const;
+       const KeyboardFuncType get_keyboard_callback() const;
+       const MouseButtonFuncType get_mouse_button_callback() const;
+       const MouseMotionFuncType get_mouse_motion_callback() const;
+
+       // win hierarchy
+       void add_child(Window *win);
+       void remove_child(Window *win);
+
+       Window **get_children();
+       int get_children_count() const;
+
+       const Window *get_parent() const;
+       Window *get_parent();
+
+       void set_state(State state);
+       State get_state() const;
+
+       // XXX remove if not needed
+       friend class WindowManager;
+};
+
+#endif // WINDOW_H_
diff --git a/libwinnie/src/winnie.cc b/libwinnie/src/winnie.cc
new file mode 100644 (file)
index 0000000..ffbe94d
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+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>
+*/
+
+#include <sys/time.h>
+
+#include "keyboard.h"
+#include "mouse.h"
+#include "shalloc.h"
+#include "winnie.h"
+
+static Subsys *subsys;
+
+bool winnie_init()
+{
+       if(!init_shared_memory()) {
+               return false;
+       }
+
+       if(!(subsys = (Subsys*)sh_malloc(sizeof *subsys))) {
+               return false;
+       }
+
+       if(!init_gfx()) {
+               return false;
+       }
+
+       if(!init_window_manager()) {
+               return false;
+       }
+
+       if(!init_keyboard()) {
+               return false;
+       }
+
+       if(!init_mouse()) {
+               return false;
+       }
+
+       if(!init_text()) {
+               return false;
+       }
+
+       wm->invalidate_region(get_screen_size());
+       return true;
+}
+
+void winnie_shutdown()
+{
+       destroy_gfx();
+       destroy_keyboard();
+       destroy_mouse();
+       destroy_text();
+       destroy_window_manager();
+
+       sh_free(subsys);
+
+       destroy_shared_memory();
+}
+
+long winnie_get_time()
+{
+       static struct timeval init_tv;
+       struct timeval tv;
+
+       gettimeofday(&tv, 0);
+
+       if(!tv.tv_sec && !tv.tv_usec) {
+               init_tv = tv;
+               return 0;
+       }
+
+       return (tv.tv_usec - init_tv.tv_usec) / 1000 + (tv.tv_sec - init_tv.tv_sec) * 1000;
+}
+
+Subsys *get_subsys()
+{
+       return subsys;
+}
diff --git a/libwinnie/src/winnie.h b/libwinnie/src/winnie.h
new file mode 100644 (file)
index 0000000..899357c
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+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>
+*/
+
+#ifndef WINNIE_H_
+#define WINNIE_H_
+
+#include "event.h"
+#include "geom.h"
+#include "gfx.h"
+#include "keyboard.h"
+#include "mouse.h"
+#include "text.h"
+#include "window.h"
+#include "wm.h"
+
+struct Subsys {
+       int graphics_offset;
+       int keyboard_offset;
+       int mouse_offset;
+       int text_offset;
+       int wm_offset;
+};
+
+bool winnie_init();
+void winnie_shutdown();
+
+long winnie_get_time();
+
+Subsys *get_subsys();
+
+#endif
diff --git a/libwinnie/src/wm.cc b/libwinnie/src/wm.cc
new file mode 100644 (file)
index 0000000..621a23f
--- /dev/null
@@ -0,0 +1,497 @@
+/*
+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>
+*/
+
+#include <algorithm>
+#include <limits.h>
+#include <stdexcept>
+#include <stdio.h>     // TODO
+
+#include "gfx.h"
+#include "mouse.h"
+#include "mouse_cursor.h"
+#include "shalloc.h"
+#include "text.h"
+#include "window.h"
+#include "winnie.h"
+#include "wm.h"
+
+#define DCLICK_INTERVAL 400
+
+WindowManager *wm;
+
+static void display(Window *win);
+static void mouse(Window *win, int bn, bool pressed, int x, int y);
+static void motion(Window *win, int x, int y);
+
+bool init_window_manager()
+{
+       void *wm_mem;
+       if(!(wm_mem = sh_malloc(sizeof *wm))) {
+               return false;
+       }
+
+       wm = new (wm_mem) WindowManager; 
+
+       get_subsys()->wm_offset = (int)((char*)wm - (char*)get_pool());
+
+       return true;
+}
+
+void destroy_window_manager()
+{
+       wm->~WindowManager();
+       sh_free(wm);
+}
+
+void WindowManager::create_frame(Window *win)
+{
+       Window *frame = new Window;
+       Window *parent = win->get_parent();
+
+       frame->set_display_callback(display);
+       frame->set_mouse_button_callback(mouse);
+       frame->set_mouse_motion_callback(motion);
+       frame->set_focusable(false);
+       frame->add_child(win);
+
+       windows.push_back(frame);
+
+       Rect win_rect = win->get_rect();
+       frame->move(win_rect.x - frame_thickness,
+                       win_rect.y - frame_thickness - titlebar_thickness);
+       frame->resize(win_rect.width + frame_thickness * 2,
+                       win_rect.height + frame_thickness * 2 + titlebar_thickness);
+
+       win->move(frame_thickness, frame_thickness + titlebar_thickness);
+       parent->add_child(frame);
+}
+
+void WindowManager::destroy_frame(Window *win)
+{
+       Window *frame = win->parent;
+       if(!frame) {
+               return;
+       }
+
+       if(grab_win == win) {
+               release_mouse();
+       }
+
+       std::list<Window*>::iterator it;
+       it = std::find(windows.begin(), windows.end(), frame);
+       if(it != windows.end()) {
+               root_win->add_child(win);
+               windows.erase(it);
+               delete frame;
+       }
+}
+
+WindowManager::WindowManager()
+{
+       if(!wm) {
+               wm = this;
+       } else {
+               throw std::runtime_error("Trying to create a second instance of WindowManager!\n");
+       }
+
+       root_win = new Window;
+       root_win->resize(get_screen_size().width, get_screen_size().height);
+       root_win->move(0, 0);
+       root_win->set_managed(false);
+
+       grab_win = 0;
+       focused_win = 0;
+       background = 0;
+
+       bg_color[0] = 210;
+       bg_color[1] = 106;
+       bg_color[2] = 106;
+
+       frame_thickness = 8;
+       titlebar_thickness = 16;
+
+       set_focused_frame_color(0, 0, 0);
+       set_unfocused_frame_color(200, 200, 200);
+
+       mouse_cursor.set_image(mouse_cursor_width, mouse_cursor_height);
+       unsigned char *pixels = mouse_cursor.get_image();
+
+       for(int i=0; i<mouse_cursor_height; i++) {
+               for(int j=0; j<mouse_cursor_width; j++) {
+                       int val = mouse_cursor_bw[i * mouse_cursor_width + j];
+                       *pixels++ = val;
+                       *pixels++ = val;
+                       *pixels++ = val;
+                       *pixels++ = 255;
+               }
+       }
+}
+
+WindowManager::~WindowManager()
+{
+       delete root_win;
+}
+
+void WindowManager::invalidate_region(const Rect &rect)
+{
+       dirty_rects.push_back(rect);
+}
+
+void WindowManager::process_windows()
+{
+       if(dirty_rects.empty()) {
+               return;
+       }
+
+       std::list<Rect>::iterator drit = dirty_rects.begin();
+       Rect uni = *drit++;
+       while(drit != dirty_rects.end()) {
+               uni = rect_union(uni, *drit++);
+       }
+       dirty_rects.clear();
+
+       wait_vsync();
+
+       if(!background) {
+               fill_rect(uni, bg_color[0], bg_color[1], bg_color[2]);
+       }
+       else {
+               blit(background->pixels, Rect(0, 0, background->width, background->height),
+                               get_framebuffer(), get_screen_size(), 0, 0);
+       }
+
+       root_win->draw_children(uni);
+
+       // draw mouse cursor
+       int mouse_x, mouse_y;
+       get_pointer_pos(&mouse_x, &mouse_y);
+
+       blit_key(mouse_cursor.get_image(), mouse_cursor.get_rect(),
+                       get_framebuffer(), get_screen_size(), mouse_x, mouse_y,
+                       0, 0, 0);
+
+       Rect mouse_rect(mouse_x, mouse_y, mouse_cursor.get_width(), mouse_cursor.get_height());
+       invalidate_region(mouse_rect);
+
+       gfx_update(uni);
+}
+
+void WindowManager::add_window(Window *win)
+{
+       if(!win || win == root_win) {
+               return;
+       }
+
+       root_win->add_child(win);
+
+       if(windows.empty()) {
+               focused_win = win;
+       }
+
+       if(win->get_managed()) {
+               create_frame(win);
+       }
+
+       windows.push_back(win);
+}
+
+void WindowManager::remove_window(Window *win)
+{
+       std::list<Window*>::iterator it;
+       it = std::find(windows.begin(), windows.end(), win);
+
+       if(it != windows.end()) {
+               windows.erase(it);
+       }
+}
+
+void WindowManager::set_focused_window(Window *win)
+{
+       if(win && win == focused_win) {
+               return;
+       }
+
+       Window *parent;
+       if(focused_win) {
+               // invalidate the frame (if any)
+               parent = focused_win->get_parent();
+               if(parent && parent != root_win) {
+                       parent->invalidate();
+                       fill_rect(parent->get_absolute_rect(), frame_ucolor[0], frame_ucolor[1], frame_ucolor[2]);
+               }
+       }
+
+       if(!win) {
+               focused_win = 0;
+               return;
+       }
+
+       if(win->get_focusable()) {
+               focused_win = win;
+               parent = focused_win->get_parent();
+               fill_rect(parent->get_absolute_rect(), frame_fcolor[0], frame_fcolor[1], frame_fcolor[2]);
+               return;
+       }
+
+       Window **children = win->get_children();
+       for(int i=0; i<win->get_children_count(); i++) {
+               if(children[0]->get_focusable()) {
+                       set_focused_window(children[0]);
+                       fill_rect(win->get_absolute_rect(), frame_fcolor[0], frame_fcolor[1], frame_fcolor[2]);
+                       return;
+               }
+       }
+
+       focused_win = 0;
+}
+
+const Window *WindowManager::get_focused_window() const
+{
+       return focused_win;
+}
+
+Window *WindowManager::get_focused_window()
+{
+       return focused_win;
+}
+
+Window *WindowManager::get_window_at_pos(int pointer_x, int pointer_y)
+{
+       Window *root_win = wm->get_root_window();
+       Window **children = root_win->get_children();
+       for(int i=root_win->get_children_count() - 1; i>=0; i--) {
+               if(children[i]->contains_point(pointer_x, pointer_y)) {
+                       return children[i];
+               }
+       }
+
+       return 0;
+}
+
+Window *WindowManager::get_root_window() const
+{
+       return root_win;
+}
+
+void WindowManager::set_focused_frame_color(int r, int g, int b)
+{
+       frame_fcolor[0] = r;
+       frame_fcolor[1] = g;
+       frame_fcolor[2] = b;
+}
+
+void WindowManager::get_focused_frame_color(int *r, int *g, int *b) const
+{
+       *r = frame_fcolor[0];
+       *g = frame_fcolor[1];
+       *b = frame_fcolor[2];
+}
+
+void WindowManager::set_unfocused_frame_color(int r, int g, int b)
+{
+       frame_ucolor[0] = r;
+       frame_ucolor[1] = g;
+       frame_ucolor[2] = b;
+}
+
+void WindowManager::get_unfocused_frame_color(int *r, int *g, int *b) const
+{
+       *r = frame_ucolor[0];
+       *g = frame_ucolor[1];
+       *b = frame_ucolor[2];
+}
+
+void WindowManager::set_background(const Pixmap *pixmap)
+{
+       if(background) {
+               delete background;
+       }
+
+       if(pixmap) {
+               background = new Pixmap(*pixmap);
+       }
+       else {
+               background = 0;
+       }
+}
+
+const Pixmap *WindowManager::get_background() const
+{
+       return background;
+}
+
+Window *WindowManager::get_grab_window() const
+{
+       return grab_win;
+}
+
+void WindowManager::grab_mouse(Window *win)
+{
+       grab_win = win;
+}
+
+void WindowManager::release_mouse()
+{
+       grab_win = 0;
+}
+
+void WindowManager::raise_window(Window *win)
+{
+       if(!win) {
+               return;
+       }
+
+       Window *parent = win->get_parent();
+       if(parent != root_win) {
+               if(parent->get_parent() == root_win) {
+                       win = parent;
+               }
+               else {
+                       return;
+               }
+       }
+
+       root_win->remove_child(win);
+       root_win->add_child(win);
+}
+
+void WindowManager::sink_window(Window *win)
+{
+       if(!win) {
+               return;
+       }
+
+       std::list<Window*>::iterator it;
+       it = std::find(windows.begin(), windows.end(), win);
+       if(it != windows.end()) {
+               windows.erase(it);
+               windows.push_front(win);
+       }
+}
+
+void WindowManager::maximize_window(Window *win)
+{
+       win->normal_rect = win->rect;
+       
+       Rect rect = get_screen_size();
+
+       Window *frame;
+       if((frame = win->get_parent())) {
+               frame->normal_rect = frame->rect;
+               frame->resize(rect.width, rect.height);
+               frame->move(rect.x, rect.y);
+
+               rect.width -= frame_thickness * 2;
+               rect.height -= frame_thickness * 2 + titlebar_thickness;
+       }
+       else {
+               win->move(0, 0);
+       }
+
+       win->resize(rect.width, rect.height);
+       win->set_state(Window::STATE_MAXIMIZED);
+}
+
+void WindowManager::unmaximize_window(Window *win)
+{
+       win->resize(win->normal_rect.width, win->normal_rect.height);
+       win->move(win->normal_rect.x, win->normal_rect.y);
+
+       Window *frame;
+       if((frame = win->get_parent())) {
+               frame->resize(frame->normal_rect.width, frame->normal_rect.height);
+               frame->move(frame->normal_rect.x, frame->normal_rect.y);
+       }
+
+       win->set_state(Window::STATE_NORMAL);
+}
+
+static void display(Window *win)
+{
+       //frame display:
+       Window *child = win->get_children()[0];
+       int r, g, b;
+       Rect abs_rect = win->get_absolute_rect();
+
+       //TODO 5 not hardcoded
+       set_text_position(abs_rect.x + 5, abs_rect.y + 15);
+       set_text_color(255, 255, 255);
+
+       if(child == wm->get_focused_window()) {
+               wm->get_focused_frame_color(&r, &g, &b);
+               fill_rect(abs_rect, r, g, b);
+       }
+       else {
+               wm->get_unfocused_frame_color(&r, &g, &b);
+               fill_rect(win->get_absolute_rect(), r, g, b);
+       }
+
+       draw_text(child->get_title());
+}
+
+static int prev_x, prev_y;
+
+static void mouse(Window *win, int bn, bool pressed, int x, int y)
+{
+       static long last_click = 0;
+
+       if(bn == 0) {
+               if(pressed) {   
+                       wm->grab_mouse(win);
+                       wm->raise_window(win);
+                       prev_x = x;
+                       prev_y = y;
+               }
+               else {
+                       long time = winnie_get_time();
+                       if((time - last_click) < DCLICK_INTERVAL) {
+                               Window *child = win->get_children()[0];
+                               Window::State state = child->get_state();
+                               if(state == Window::STATE_MAXIMIZED) {
+                                       wm->unmaximize_window(child);
+                               }
+                               else if(state == Window::STATE_NORMAL) {
+                                       wm->maximize_window(child);
+                               }
+                       }
+                       last_click = time;
+
+                       wm->release_mouse();
+               }
+       }
+}
+
+static void motion(Window *win, int x, int y)
+{
+       int left_bn = get_button(0);
+
+       if(left_bn) {
+               int dx = x - prev_x;
+               int dy = y - prev_y;
+               prev_x = x - dx;
+               prev_y = y - dy;
+
+               if(win->get_children()[0]->get_state() != Window::STATE_MAXIMIZED) {
+                       Rect rect = win->get_rect();
+                       win->move(rect.x + dx, rect.y + dy);
+               }
+       }
+}
diff --git a/libwinnie/src/wm.h b/libwinnie/src/wm.h
new file mode 100644 (file)
index 0000000..46f4857
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+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>
+*/
+
+#ifndef WM_H_
+#define WM_H_
+
+#include <list>
+
+#include "geom.h"
+#include "pixmap.h"
+#include "winnie.h"
+
+class Window;
+
+bool init_window_manager();
+void destroy_window_manager(); 
+
+class WindowManager {
+private:
+       std::list<Window*> windows;
+
+       std::list<Rect> dirty_rects;
+
+       int bg_color[3];
+       int frame_thickness;
+       int titlebar_thickness;
+       int frame_fcolor[3];
+       int frame_ucolor[3];
+
+       Window *root_win;
+       Window *focused_win;
+       Window *grab_win;
+
+       Pixmap mouse_cursor;
+       Pixmap *background;
+
+       void create_frame(Window *win);
+       void destroy_frame(Window *win);
+
+public:
+       WindowManager();
+       ~WindowManager();
+
+       void invalidate_region(const Rect &rect);
+       void process_windows();
+
+       void add_window(Window *win);
+       void remove_window(Window *win);
+
+       void set_focused_window(Window *win);
+       const Window *get_focused_window() const;
+       Window *get_focused_window();
+
+       Window *get_window_at_pos(int pointer_x, int pointer_y);
+       Window *get_root_window() const;
+
+       void set_focused_frame_color(int r, int g, int b);
+       void get_focused_frame_color(int *r, int *g, int *b) const;
+
+       void set_unfocused_frame_color(int r, int g, int b);
+       void get_unfocused_frame_color(int *r, int *g, int *b) const;
+
+       void set_background(const Pixmap *pixmap);
+       const Pixmap *get_background() const;
+
+       Window *get_grab_window() const;
+
+       void grab_mouse(Window *win);
+       void release_mouse();
+
+       void raise_window(Window *win);
+       void sink_window(Window *win);
+
+       void maximize_window(Window *win);
+       void unmaximize_window(Window *win);
+};
+
+extern WindowManager *wm;
+
+#endif // WM_H_
diff --git a/winnie/Makefile b/winnie/Makefile
new file mode 100644 (file)
index 0000000..64a9cf5
--- /dev/null
@@ -0,0 +1,34 @@
+src = $(wildcard src/*.cc) $(wildcard src/fbdev/*.cc) $(wildcard src/sdl/*.cc)
+obj = $(src:.cc=.o)
+dep = $(obj:.o=.d)
+bin = wserver
+
+dbg = -g
+opt = -O0
+inc = -Isrc -I../libwinnie/src
+
+backend = SDL
+
+ifeq ($(backend), SDL)
+       def = -DWINNIE_SDL
+       libs = -lSDL
+else
+       def = -DWINNIE_FBDEV
+endif
+
+CXX = g++
+CXXFLAGS = -pedantic -Wall $(dbg) $(opt) $(inc) $(def) `freetype-config --cflags`
+LDFLAGS = -L../libwinnie/ $(libs) `freetype-config --libs` -lrt -lwinnie
+
+$(bin): $(obj)
+       $(CXX) -o $@ $(obj) $(LDFLAGS) -Wl,-rpath=../libwinnie
+
+-include $(dep)
+
+%.d: %.cc
+       @$(CPP) $(CXXFLAGS) $< -MM -MT $(@:.d=.o) >$@
+
+.PHONY: clean
+clean:
+       rm -f $(obj) $(bin) $(dep)
+
diff --git a/winnie/README b/winnie/README
new file mode 100644 (file)
index 0000000..2106da1
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+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>
+*/
+
+The winnie server application.
diff --git a/winnie/src/main.cc b/winnie/src/main.cc
new file mode 100644 (file)
index 0000000..3c1c504
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+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>
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "winnie.h"
+
+static void display(Window *win);
+static void keyboard(Window *win, int key, bool pressed);
+static void button(Window *win, int bn, bool pressed, int x, int y);
+static void motion(Window *win, int x, int y);
+static void cleanup();
+
+int main()
+{
+       if(!winnie_init()) {
+               exit(1);
+       }
+
+       atexit(cleanup);
+
+       Window *win1 = new Window;
+       win1->set_title("Clipping the win title");
+       win1->move(200, 100);
+       win1->resize(200, 300);
+       win1->set_display_callback(display);
+       win1->set_keyboard_callback(keyboard);
+       win1->set_mouse_button_callback(button);
+       win1->set_mouse_motion_callback(motion);
+
+       Window *win2 = new Window;
+       win2->set_title("window 2");
+       win2->move(300, 100);
+       win2->resize(200, 300);
+       win2->set_display_callback(display);
+       win2->set_keyboard_callback(keyboard);
+       win2->set_mouse_button_callback(button);
+       win2->set_mouse_motion_callback(motion);
+
+       wm->add_window(win1);
+       wm->add_window(win2);
+
+       Pixmap bg;
+       if(!(bg.load("data/bg.ppm"))) {
+               fprintf(stderr, "failed to load pixmap\n");
+       }
+
+       wm->set_background(&bg);
+
+       while(1) {
+               process_events();
+       }
+}
+
+static void display(Window *win)
+{
+       fill_rect(win->get_absolute_rect(), 128, 128, 128);
+}
+
+static void keyboard(Window *win, int key, bool pressed)
+{
+       switch(key) {
+       case 'q':
+               exit(0);
+       }
+}
+
+static void button(Window *win, int bn, bool pressed, int x, int y)
+{
+       printf("WINDOW(%p) button %d %s\n", (void*)win, bn, pressed ? "press" : "release");
+}
+
+static void motion(Window *win, int x, int y)
+{
+       printf("WINDOW(%p) motion %d %d\n", (void*)win, x, y);
+}
+
+static void cleanup()
+{
+       winnie_shutdown();
+}