diff options
-rw-r--r-- | src/surface/kolibri.c | 547 |
1 files changed, 547 insertions, 0 deletions
diff --git a/src/surface/kolibri.c b/src/surface/kolibri.c new file mode 100644 index 0000000..3d0fcc1 --- /dev/null +++ b/src/surface/kolibri.c @@ -0,0 +1,547 @@ +/* + * Copyright 2016 Nina Kalinina <ninacarrot@ya.ru> + * Copyright 2016 Ashish Gupta <ashmew2@gmail.com> + * + * This file is a part of libnsfb, http://www.netsurf-browser.org/ + * Licenced under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + */ + +#include <stdbool.h> +#include <stdlib.h> + +#include "libnsfb.h" +#include "libnsfb_event.h" +#include "libnsfb_plot.h" +#include "libnsfb_plot_util.h" + +#include "nsfb.h" +#include "surface.h" +#include "palette.h" +#include "plot.h" +#include "cursor.h" + +/* Define codes for KolibriOS' events */ +#define EVENT_REDRAW (1 << 0) +#define EVENT_KEY (1 << 1) +#define EVENT_BUTTON (1 << 2) +#define EVENT_END_REQUEST (1 << 3) +#define EVENT_DESKTOP_BACK_DRAW (1 << 4) +#define EVENT_MOUSE_CHANGE (1 << 5) +#define EVENT_IPC (1 << 6) +#define EVENT_NETWORK (1 << 7) +#define EVENT_INACTIVE_NO_CURSOR (1 << 30) +#define EVENT_INACTIVE_NO_MOUSE (1 << 31) + +/* Pixel array which we need to pass around. */ +unsigned char * pixels; +unsigned previous_mouse_position, previous_mouse_buttons; + +int kolibri_get_button_id(void) +{ + uint16_t __ret; + __asm__ __volatile__ ( + "int $0x40" + :"=a"(__ret) + :"0"(17)); + + if ((__ret & 0xFF) == 0) { + return (__ret >> 8) & 0xFF; + } + else { + return -1; + } +} + +int kolibri_wait_for_event(void) +{ + uint32_t __ret; + __asm__ __volatile__ ("int $0x40":"=a"(__ret):"0"(10)); + return __ret; +} + +int kolibri_get_pressed_key(void) +{ + uint16_t __ret; + __asm__ __volatile__ ("int $0x40":"=a"(__ret):"0"(2)); + + if (!(__ret & 0xFF)) { + return (__ret >> 8) & 0xFF; + } + else { + return 0; + } +} + +void kolibri_define_window(uint16_t x1, uint16_t y1, uint16_t xsize, + uint16_t ysize, uint32_t body_color, uint32_t grab_color, + uint32_t frame_color) +{ + uint32_t a, b; + a = (x1 << 16) | xsize; + b = (y1 << 16) | ysize; + + __asm__ __volatile__ ("int $0x40" + ::"a"(0), + "b"(a), + "c"(b), + "d"(body_color), + "S"(grab_color), + "D"(frame_color)); +} + +void kolibri_window_redraw(int status) +{ + __asm__ __volatile__ ("int $0x40"::"a"(12),"b"(status)); +} + +void kolibri_set_wanted_events(uint32_t ev) +{ + __asm__ __volatile__ ("int $0x40"::"a"(40),"b"(ev)); +} + +inline void f65_32bpp(unsigned x, unsigned y, unsigned w, unsigned h, char *d) +{ + __asm__ __volatile__ ("pusha"); + __asm__ __volatile__ ("nop"::"D"(0), "c"(w*65536 + h), "d"(x*65536 + y), + "b"(d)); + __asm__ __volatile__ ("xor %eax, %eax"); + __asm__ __volatile__ ("movl %eax, %ebp"); + __asm__ __volatile__ ("pushl $32"); + __asm__ __volatile__ ("popl %esi"); + __asm__ __volatile__ ("int $0x40"::"a"(65)); + __asm__ __volatile__ ("popa"); +} + +unsigned kolibri_mouse_get_relative(void) +{ + unsigned error; + __asm__ __volatile__ ("int $0x40":"=a"(error):"a"(37), "b"(1)); + return error; +} + + +unsigned kolibri_mouse_get_buttonpress(void) +{ + unsigned error; + __asm__ __volatile__ ("int $0x40":"=a"(error):"a"(37), "b"(2)); + return error; +} + +unsigned kolibri_mouse_get_scrolldata(void) +{ + unsigned error; + __asm__ __volatile__ ("int $0x40":"=a"(error):"a"(37), "b"(7)); + return error; +} + +/* timeout is in 1/100 seconds */ +unsigned kolibri_wait_for_event_with_timeout(int timeout) +{ + unsigned event; + __asm__ __volatile__ ("int $0x40":"=a"(event):"a"(23), "b"(timeout)); + return event; +} + +unsigned kolibri_scancodes(void) +{ + unsigned error; + __asm__ __volatile__ ("int $0x40":"=a"(error):"a"(66), "b"(1), "c"(1)); + return error; +} + +void kolibri_redraw(nsfb_t *nsfb) +{ + f65_32bpp(0, 0, nsfb->width, nsfb->height, pixels + 1); +} + +unsigned kolibri_skin_get_height(void) +{ + unsigned error; + __asm__ __volatile__ ("int $0x40":"=a"(error):"a"(48), "b"(4)); + return error; +} + +unsigned kolibri_area(char *data) +{ + unsigned error; + __asm__ __volatile__ ("int $0x40":"=a"(error):"a"(9), "b"(data), + "c"(0xffffffff)); + return error; +} + + +void kolibri_fb_redraw(nsfb_t *nsfb) +{ + kolibri_window_redraw(1); + kolibri_define_window(100, 100, nsfb->width + 9, + nsfb->height + kolibri_skin_get_height(), 0x74000080, + 0x800000FF, "Netsurf for KolibriOS"); + + debug_board_write_str("f65 is mighty with 32 bpp!\n"); + + /* Here put image pixels! it's 32bpp */ + f65_32bpp(0, 0, nsfb->width, nsfb->height, pixels + 1); + kolibri_window_redraw(2); +} + +static int kolibri_surface_set_geometry(nsfb_t *nsfb, int width, int height, + enum nsfb_format_e format) +{ + + /* fail if surface already initialised */ + if (nsfb->surface_priv != NULL) + return -1; + + nsfb->width = width; + nsfb->height = height; + nsfb->format = format; + + /* We add one more byte to balance XBGR to BGRX for KolibriOS. */ + /* *4 because we only support 32bpp */ + + pixels = (char *)malloc(width * height * 4 + 1); + + /* select default sw plotters for format */ + /* Fail if plotter selection fails */ + if (select_plotters(nsfb) == false) { + return -1; + } + + return 0; +} + +static int kolibri_surface_initialise(nsfb_t *nsfb) +{ + enum nsfb_format_e fmt; + + kolibri_scancodes(); + + previous_mouse_position = 0; + previous_mouse_buttons = 0; + + debug_board_write_str("Kolibri Initialise in libnsfb.\n"); + + if (nsfb->surface_priv != NULL) { + debug_board_write_str("Surface already " + "has private surface\n. Abort\n"); + + return -1; + } + + nsfb->surface_priv = pixels; + nsfb->ptr = pixels; + nsfb->linelen = (nsfb->width * nsfb->bpp) / 8; + + debug_board_write_str("Redraw\n"); + kolibri_redraw(nsfb); + + /* This is for setting flags for MCALL 40 for events read by a window */ + kolibri_set_wanted_events(EVENT_REDRAW | + EVENT_KEY | + EVENT_BUTTON | + EVENT_MOUSE_CHANGE | + EVENT_INACTIVE_NO_CURSOR | + EVENT_INACTIVE_NO_MOUSE | + EVENT_NETWORK); + + return 0; +} + +static int kolibri_surface_finalise(nsfb_t *nsfb) +{ + nsfb = nsfb; + exit(1); + + return 0; +} + +int key_is_up(int scancode) +{ + return (scancode & 0x80) >> 7; +} + +int scan2key(int scan) +{ + + int keycode = scan & 0x0FF7F; + + /* MAIN KB - NUMS */ + if (keycode == 0x02) return NSFB_KEY_1; + if (keycode == 0x03) return NSFB_KEY_2; + if (keycode == 0x04) return NSFB_KEY_3; + if (keycode == 0x05) return NSFB_KEY_4; + if (keycode == 0x06) return NSFB_KEY_5; + if (keycode == 0x07) return NSFB_KEY_6; + if (keycode == 0x08) return NSFB_KEY_7; + if (keycode == 0x09) return NSFB_KEY_8; + if (keycode == 0x0A) return NSFB_KEY_9; + if (keycode == 0x0B) return NSFB_KEY_0; + + if (keycode == 0x10) return NSFB_KEY_q; + if (keycode == 0x11) return NSFB_KEY_w; + if (keycode == 0x12) return NSFB_KEY_e; + if (keycode == 0x13) return NSFB_KEY_r; + if (keycode == 0x14) return NSFB_KEY_t; + if (keycode == 0x15) return NSFB_KEY_y; + if (keycode == 0x16) return NSFB_KEY_u; + if (keycode == 0x17) return NSFB_KEY_i; + if (keycode == 0x18) return NSFB_KEY_o; + if (keycode == 0x19) return NSFB_KEY_p; + if (keycode == 0x1A) return NSFB_KEY_LEFTBRACKET; + if (keycode == 0x1B) return NSFB_KEY_RIGHTBRACKET; + + if (keycode == 0x1E) return NSFB_KEY_a; + if (keycode == 0x1F) return NSFB_KEY_s; + if (keycode == 0x20) return NSFB_KEY_d; + if (keycode == 0x21) return NSFB_KEY_f; + if (keycode == 0x22) return NSFB_KEY_g; + if (keycode == 0x23) return NSFB_KEY_h; + if (keycode == 0x24) return NSFB_KEY_j; + if (keycode == 0x25) return NSFB_KEY_k; + if (keycode == 0x26) return NSFB_KEY_l; + + if (keycode == 0x2C) return NSFB_KEY_z; + if (keycode == 0x2D) return NSFB_KEY_x; + if (keycode == 0x2E) return NSFB_KEY_c; + if (keycode == 0x2F) return NSFB_KEY_v; + if (keycode == 0x30) return NSFB_KEY_b; + if (keycode == 0x31) return NSFB_KEY_n; + if (keycode == 0x32) return NSFB_KEY_m; + + /* TODO: Add a TAB Key here to cycle through fields */ + if (keycode == 0x27) return NSFB_KEY_SEMICOLON; + if (keycode == 0x28) return NSFB_KEY_QUOTEDBL; + if (keycode == 0x2B) return NSFB_KEY_BACKSLASH; + if (keycode == 0x33) return NSFB_KEY_COMMA; + if (keycode == 0x34) return NSFB_KEY_PERIOD; + if (keycode == 0x35) return NSFB_KEY_SLASH; + if (keycode == 0x0C) return NSFB_KEY_MINUS; + if (keycode == 0x0D) return NSFB_KEY_EQUALS; + + if (keycode == 0x0E) return NSFB_KEY_BACKSPACE; + if (keycode == 0xE053) return NSFB_KEY_DELETE; + if (keycode == 0x2A) return NSFB_KEY_LSHIFT; + if (keycode == 0x36) return NSFB_KEY_RSHIFT; + + if (keycode == 0x1C) return NSFB_KEY_RETURN; + + if (keycode == 0xE04B) return NSFB_KEY_LEFT; + if (keycode == 0xE04D) return NSFB_KEY_RIGHT; + if (keycode == 0xE048) return NSFB_KEY_UP; + if (keycode == 0xE050) return NSFB_KEY_DOWN; + + if (keycode == 0x3F) return NSFB_KEY_F5; + + if (keycode == 0x39) return NSFB_KEY_SPACE; + if (keycode == 0x01) return NSFB_KEY_ESCAPE; + + if (keycode == 0x38) return NSFB_KEY_LALT; + if (keycode == 0x1D) return NSFB_KEY_LCTRL; + if (keycode == 0xE038) return NSFB_KEY_RALT; + if (keycode == 0xE01D) return NSFB_KEY_RCTRL; + + + if (keycode == 0xE047) return NSFB_KEY_HOME; + if (keycode == 0xE04F) return NSFB_KEY_END; + if (keycode == 0xE049) return NSFB_KEY_PAGEUP; + if (keycode == 0xE051) return NSFB_KEY_PAGEDOWN; + + return NSFB_KEY_UNKNOWN; + +} + +/* TODO: Useful for future implementation */ +int ispowerkey(int scancode) +{ + return (scancode & 0xE000) >> 15; +} + +static bool kolibri_surface_input(nsfb_t *nsfb, nsfb_event_t *event, + int timeout) +{ + int got_event; + static int scanfull = 0; + char event_num[20]; + + nsfb = nsfb; /* unused */ + + if (timeout >= 0) { + got_event = kolibri_wait_for_event_with_timeout(timeout / 10); + } else { + got_event = kolibri_wait_for_event(); + } + + if (got_event == 0) { + return false; + } + + /* sprintf(event_num, "got_event = %d\n", got_event); */ + /* debug_board_write_str(event_num); */ + + event->type = NSFB_EVENT_NONE; + + /* redraw event */ + if (got_event == 1) { + kolibri_fb_redraw(nsfb); + } + /* keypress event */ + if (got_event == 2) { + int scanz = kolibri_get_pressed_key(); + + if (scanz == 0xE0) { + scanfull = 0xE000; + return true; + } else { + scanfull = scanfull + scanz; + } + + if (key_is_up(scanfull) == 1) { + event->type = NSFB_EVENT_KEY_UP; + } else { + event->type = NSFB_EVENT_KEY_DOWN; + } + + event->value.keycode = scan2key(scanfull); + + scanfull = 0; + + return true; + } + + /* button press event */ + if (got_event == 3) { + if (kolibri_get_button_id() == 1) + kolibri_surface_finalise(nsfb); + return true; + } + + /* mouse event */ + if (got_event == 6) { + unsigned z = kolibri_mouse_get_relative(); + unsigned b = kolibri_mouse_get_buttonpress(); + int s = kolibri_mouse_get_scrolldata(); + + if (previous_mouse_position != z) { + event->type = NSFB_EVENT_MOVE_ABSOLUTE; + event->value.vector.x = (z & 0xffff0000) >> 16; + event->value.vector.y = z & 0xffff; + event->value.vector.z = 0; + previous_mouse_position = z; + } + else if (previous_mouse_buttons != b) { + unsigned diff = previous_mouse_buttons^b; + /* All high bits in the XOR represent bits that + changed */ + + if (diff & EVENT_REDRAW) { + /* Left mouse button */ + event->value.keycode = NSFB_KEY_MOUSE_1; + if (b & EVENT_REDRAW) { + event->type = NSFB_EVENT_KEY_DOWN; + } else { + event->type = NSFB_EVENT_KEY_UP; + } + } else if (diff & EVENT_KEY) { + /* Right mouse button */ + event->value.keycode = NSFB_KEY_MOUSE_3; + if (b & EVENT_KEY) { + event->type = NSFB_EVENT_KEY_DOWN; + } else { + event->type = NSFB_EVENT_KEY_UP; + } + } else if (diff & EVENT_BUTTON) { + /* Middle mouse button */ + event->value.keycode = NSFB_KEY_MOUSE_2; + if (b & EVENT_BUTTON) { + event->type = NSFB_EVENT_KEY_DOWN; + } else { + event->type = NSFB_EVENT_KEY_UP; + } + } else if (diff & EVENT_END_REQUEST) { + /* 4th mouse button (forward) */ + event->value.keycode = NSFB_KEY_MOUSE_4; + if (b & EVENT_END_REQUEST) { + event->type = NSFB_EVENT_KEY_DOWN; + } else { + event->type = NSFB_EVENT_KEY_UP; + } + } else if (diff & EVENT_DESKTOP_BACK_DRAW) { + /* 5th mouse button (back) */ + event->value.keycode = NSFB_KEY_MOUSE_5; + if (b & EVENT_DESKTOP_BACK_DRAW) { + event->type = NSFB_EVENT_KEY_DOWN; + } else { + event->type = NSFB_EVENT_KEY_UP; + } + } else { + /*The Event 6 did not match any handled cases*/ + char diffstr[40]; + sprintf(diffstr, "Unhandled case." + "Previous_mouse_buttons^b is :" + "%u", diff); + + debug_board_write_str(diffstr); + } + previous_mouse_buttons = b; + } + else if (s != 0) { + short int vert = s & 0xffff; + short int hori = s >> 16; + + event->type = NSFB_EVENT_KEY_DOWN; + + if (vert != 0) { + /*Handle vertical scroll*/ + if (vert > 0) /*SCROLL DOWN*/ + event->value.keycode = NSFB_KEY_MOUSE_5; + else /*SCROLL UP*/ + event->value.keycode = NSFB_KEY_MOUSE_4; + } + else { + /* TODO: Handle Horizontal scroll here */ + } + } + return true; + } +} + +static int kolibri_surface_claim(nsfb_t *nsfb, nsfb_bbox_t *box) +{ + /* TODO: Convert to full function from stub */ + + /* + if ((cursor != NULL) && + (cursor->plotted == true) && + (nsfb_plot_bbox_intersect(box, &cursor->loc))) { + nsfb_cursor_clear(nsfb, cursor); + } + */ + + return 0; +} + +static int kolibri_surface_cursor(nsfb_t *nsfb, struct nsfb_cursor_s *cursor) +{ + /* Convert to full function from stub */ + return true; +} + +static int kolibri_surface_update(nsfb_t *nsfb, nsfb_bbox_t *box) +{ + /* Do the window redraw here */ + kolibri_redraw(nsfb); + return 0; +} + +const nsfb_surface_rtns_t kolibri_rtns = { + .initialise = kolibri_surface_initialise, + .finalise = kolibri_surface_finalise, + .input = kolibri_surface_input, + .claim = kolibri_surface_claim, + .update = kolibri_surface_update, + .cursor = kolibri_surface_cursor, + .geometry = kolibri_surface_set_geometry, +}; + +NSFB_SURFACE_DEF(kolibri, NSFB_SURFACE_KOLIBRI, &kolibri_rtns) |