From: Eleni Maria Stea Date: Sun, 31 Mar 2013 22:29:13 +0000 (+0300) Subject: created libwinnie (library), winnie (the server application) and clients X-Git-Url: https://eleni.mutantstargoat.com/git/?p=winnie;a=commitdiff_plain;h=7b5d2df884abb7084d71f17cc29a618c0b6f47ef created libwinnie (library), winnie (the server application) and clients --- diff --git a/.bzrignore b/.bzrignore index 94ca2b4..a438335 100644 --- a/.bzrignore +++ b/.bzrignore @@ -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 index 0000000..df1e0e9 --- /dev/null +++ b/libwinnie/Makefile @@ -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 index 0000000..b83f62c --- /dev/null +++ b/libwinnie/README @@ -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 . + +Author: Eleni Maria Stea +*/ + +The winnie library. diff --git a/libwinnie/src/event.h b/libwinnie/src/event.h new file mode 100644 index 0000000..2207c1b --- /dev/null +++ b/libwinnie/src/event.h @@ -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 . + +Author: Eleni Maria Stea +*/ + +#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 index 0000000..00e12cd --- /dev/null +++ b/libwinnie/src/fbdev/event.cc @@ -0,0 +1,60 @@ +/* +winnie - an experimental window system + +Copyright (C) 2013 Eleni Maria Stea + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +Author: Eleni Maria Stea +*/ + +#ifdef WINNIE_FBDEV +#include + +#include +#include +#include + +#include "event.h" +#include "wm.h" +#include "keyboard.h" +#include "mouse.h" + +void process_events() +{ + int keyb_fd = get_keyboard_fd(); + int mouse_fd = get_mouse_fd(); + + for(;;) { + wm->process_windows(); + + fd_set read_set; + + FD_ZERO(&read_set); + FD_SET(keyb_fd, &read_set); + FD_SET(mouse_fd, &read_set); + + int maxfd = keyb_fd > mouse_fd ? keyb_fd : mouse_fd; + + while(select(maxfd + 1, &read_set, 0, 0, 0) == -1 && errno == EINTR); + + if(FD_ISSET(keyb_fd, &read_set)) { + process_keyboard_event(); + } + if(FD_ISSET(mouse_fd, &read_set)) { + process_mouse_event(); + } + } +} +#endif // WINNIE_FBDEV diff --git a/libwinnie/src/fbdev/gfx.cc b/libwinnie/src/fbdev/gfx.cc new file mode 100644 index 0000000..ff86d9c --- /dev/null +++ b/libwinnie/src/fbdev/gfx.cc @@ -0,0 +1,221 @@ +/* +winnie - an experimental window system + +Copyright (C) 2013 Eleni Maria Stea + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +Author: Eleni Maria Stea +*/ + +#ifdef WINNIE_FBDEV +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#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; iscreen_rect.width * 4; + dptr += gfx->screen_rect.width * 4; + } +} + +void wait_vsync() +{ + unsigned long arg = 0; + if(ioctl(dev_fd, FBIO_WAITFORVSYNC, &arg) == -1) { +// printf("ioctl error %s\n", strerror(errno)); + } +} + +void get_rgb_order(int *r, int *g, int *b) +{ + *r = rgb_order[0]; + *g = rgb_order[1]; + *b = rgb_order[2]; +} + +#endif // WINNIE_FBDEV diff --git a/libwinnie/src/fbdev/keyboard.cc b/libwinnie/src/fbdev/keyboard.cc new file mode 100644 index 0000000..22f129a --- /dev/null +++ b/libwinnie/src/fbdev/keyboard.cc @@ -0,0 +1,140 @@ +/* +winnie - an experimental window system + +Copyright (C) 2013 Eleni Maria Stea + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +Author: Eleni Maria Stea +*/ + +#ifdef WINNIE_FBDEV +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "keyboard.h" +#include "shalloc.h" +#include "window.h" +#include "winnie.h" +#include "wm.h" + +struct Keyboard { + int dev_fd; + enum {RAW, CANONICAL} ttystate; +}; + +static Keyboard *keyboard; + +bool init_keyboard() +{ + if(!(keyboard = (Keyboard*)sh_malloc(sizeof *keyboard))) { + return false; + } + + get_subsys()->keyboard_offset = (int)((char*)keyboard - (char*)get_pool()); + + keyboard->ttystate = keyboard->CANONICAL; + keyboard->dev_fd = -1; + + if((keyboard->dev_fd = open("/dev/tty", O_RDWR)) == -1) { + fprintf(stderr, "Cannot open /dev/tty : %s\n", strerror(errno)); + return false; + } + + struct termios buf; + + if(tcgetattr(keyboard->dev_fd, &buf) < 0) { + fprintf(stderr, "Cannot get the tty parameters : %s\n", strerror(errno)); + return false; + } + + buf.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG); + buf.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON); + buf.c_cflag &= ~(CSIZE | PARENB); + buf.c_cflag |= CS8; + buf.c_oflag &= ~(OPOST); + + if(tcsetattr(keyboard->dev_fd, TCSAFLUSH, &buf) < 0) { + return false; + } + + keyboard->ttystate = keyboard->RAW; + return true; +} + +void destroy_keyboard() +{ + struct termios buf; + + if(tcgetattr(keyboard->dev_fd, &buf) < 0) { + fprintf(stderr, "Cannot get the tty parameters : %s\n", strerror(errno)); + } + + buf.c_lflag |= (ECHO | ICANON | IEXTEN | ISIG); + buf.c_iflag |= (BRKINT | ICRNL | INPCK | ISTRIP | IXON); + buf.c_cflag |= (CSIZE | PARENB); + buf.c_cflag &= CS8; + buf.c_oflag |= (OPOST); + + if(tcsetattr(keyboard->dev_fd, TCSAFLUSH, &buf) < 0) { + fprintf(stderr, "Cannot set the tty parameters : %s\n", strerror(errno)); + } + + keyboard->ttystate = keyboard->CANONICAL; + + if(keyboard->dev_fd != -1) { + close(keyboard->dev_fd); + keyboard->dev_fd = -1; + } + + sh_free(keyboard); +} + +int get_keyboard_fd() +{ + return keyboard->dev_fd; +} + +void process_keyboard_event() +{ + char key; + if(read(keyboard->dev_fd, &key, 1) < 1) { + return; + } + + if(key == 'q') { + exit(0); + } + + Window *focused_win = wm->get_focused_window(); + if(focused_win) { + KeyboardFuncType keyb_callback = focused_win->get_keyboard_callback(); + if(keyb_callback) { + keyb_callback(focused_win, key, true); //TODO: true?? + } + } + + /* TODO: + * - handle system-wide key combinations (alt-tab?) + * - otherwise send keypress/release to focused window + */ +} +#endif // WINNIE_FBDEV diff --git a/libwinnie/src/fbdev/mouse.cc b/libwinnie/src/fbdev/mouse.cc new file mode 100644 index 0000000..1fb2d55 --- /dev/null +++ b/libwinnie/src/fbdev/mouse.cc @@ -0,0 +1,202 @@ +/* +winnie - an experimental window system + +Copyright (C) 2013 Eleni Maria Stea + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +Author: Eleni Maria Stea +*/ + +#ifdef WINNIE_FBDEV +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#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; ibnstate >> 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 index 0000000..53181db --- /dev/null +++ b/libwinnie/src/geom.cc @@ -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 . + +Author: Eleni Maria Stea +*/ + +#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 index 0000000..220069d --- /dev/null +++ b/libwinnie/src/geom.h @@ -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 . + +Author: Eleni Maria Stea +*/ + +#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 index 0000000..b72e43b --- /dev/null +++ b/libwinnie/src/gfx.cc @@ -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 . + +Author: Eleni Maria Stea +*/ + +#include + +#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= 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= 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. + +Author: Eleni Maria Stea +*/ + +#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 index 0000000..548ddbb --- /dev/null +++ b/libwinnie/src/keyboard.h @@ -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 . + +Author: Eleni Maria Stea +*/ + +#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 index 0000000..6fbe711 --- /dev/null +++ b/libwinnie/src/mouse.h @@ -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 . + +Author: Eleni Maria Stea +*/ + +#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 index 0000000..f64934e --- /dev/null +++ b/libwinnie/src/mouse_cursor.h @@ -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 . + +Author: Eleni Maria Stea +*/ + +#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 index 0000000..8e50fa3 --- /dev/null +++ b/libwinnie/src/pixmap.cc @@ -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 . + +Author: Eleni Maria Stea +*/ + +#include +#include +#include +#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. + +Author: Eleni Maria Stea +*/ + +#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 index 0000000..685c323 --- /dev/null +++ b/libwinnie/src/sdl/event.cc @@ -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 . + +Author: Eleni Maria Stea +*/ + +#ifdef WINNIE_SDL +#include +#include + +#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 index 0000000..7e098b9 --- /dev/null +++ b/libwinnie/src/sdl/gfx.cc @@ -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 . + +Author: Eleni Maria Stea +*/ + +#ifdef WINNIE_SDL +#include +#include +#include + +#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; iscreen_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 index 0000000..2290213 --- /dev/null +++ b/libwinnie/src/sdl/keyboard.cc @@ -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 . + +Author: Eleni Maria Stea +*/ + +#ifdef WINNIE_SDL +#include + +#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 index 0000000..3ba98a0 --- /dev/null +++ b/libwinnie/src/sdl/mouse.cc @@ -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 . + +Author: Eleni Maria Stea +*/ + +#ifdef WINNIE_SDL +#include + +#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 index 0000000..1ab8920 --- /dev/null +++ b/libwinnie/src/semaphore.h @@ -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 . + +Author: Eleni Maria Stea +*/ + +#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 index 0000000..5d4715a --- /dev/null +++ b/libwinnie/src/shalloc.cc @@ -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 . + +Author: Eleni Maria Stea +*/ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#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 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::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. + +Author: Eleni Maria Stea +*/ + +#ifndef SHALLOC_H_ +#define SHALLOC_H_ + +#include + +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 index 0000000..7dbae5d --- /dev/null +++ b/libwinnie/src/text.cc @@ -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 . + +Author: Eleni Maria Stea +*/ + +#include +#include + +#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; irows; 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; jwidth; 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 index 0000000..a94388a --- /dev/null +++ b/libwinnie/src/text.h @@ -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 . + +Author: Eleni Maria Stea +*/ + +#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 index 0000000..04f72cd --- /dev/null +++ b/libwinnie/src/window.cc @@ -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 . + +Author: Eleni Maria Stea +*/ + +#include +#include //TODO +#include + +#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; iremove_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; idraw(&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::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 index 0000000..b5cc360 --- /dev/null +++ b/libwinnie/src/window.h @@ -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 . + +Author: Eleni Maria Stea +*/ + +#ifndef WINDOW_H_ +#define WINDOW_H_ + +#include + +#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 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 index 0000000..ffbe94d --- /dev/null +++ b/libwinnie/src/winnie.cc @@ -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 . + +Author: Eleni Maria Stea +*/ + +#include + +#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 index 0000000..899357c --- /dev/null +++ b/libwinnie/src/winnie.h @@ -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 . + +Author: Eleni Maria Stea +*/ + +#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 index 0000000..621a23f --- /dev/null +++ b/libwinnie/src/wm.cc @@ -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 . + +Author: Eleni Maria Stea +*/ + +#include +#include +#include +#include // 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::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::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::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; iget_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::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 index 0000000..46f4857 --- /dev/null +++ b/libwinnie/src/wm.h @@ -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 . + +Author: Eleni Maria Stea +*/ + +#ifndef WM_H_ +#define WM_H_ + +#include + +#include "geom.h" +#include "pixmap.h" +#include "winnie.h" + +class Window; + +bool init_window_manager(); +void destroy_window_manager(); + +class WindowManager { +private: + std::list windows; + + std::list 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 index 0000000..64a9cf5 --- /dev/null +++ b/winnie/Makefile @@ -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 index 0000000..2106da1 --- /dev/null +++ b/winnie/README @@ -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 . + +Author: Eleni Maria Stea +*/ + +The winnie server application. diff --git a/winnie/src/main.cc b/winnie/src/main.cc new file mode 100644 index 0000000..3c1c504 --- /dev/null +++ b/winnie/src/main.cc @@ -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 . + +Author: Eleni Maria Stea +*/ + +#include +#include +#include + +#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(); +}