>From cb45b499fb048c7bfcaea0744f4303b964d48469
From: Ori Bernstein <o...@eigenstate.org>
Date: Sun, 22 Mar 2020 19:06:30 -0700
Subject: [PATCH] Add support for plan 9 surface, remove gcc dependency.


This adds framebuffer support for plan 9 image surfaces,
and puts macros like UNUSED and __attribute__((constructor))
behind appropriate ifdefs.
diff -urN a/include/libnsfb.h b/include/libnsfb.h
--- a/include/libnsfb.h Mon Feb 24 02:57:05 2020
+++ b/include/libnsfb.h Sun Mar 22 19:06:30 2020
@@ -42,6 +42,7 @@
     NSFB_SURFACE_LINUX, /**< Linux framebuffer surface */
     NSFB_SURFACE_ABLE, /**< ABLE framebuffer surface */
     NSFB_SURFACE_RAM, /**< RAM surface */
+    NSFB_SURFACE_PLAN9, /**< Plan 9 devdraw surface */
     NSFB_SURFACE_COUNT, /**< The number of surface kinds */
 };
 
diff -urN a/src/plot/16bpp.c b/src/plot/16bpp.c
--- a/src/plot/16bpp.c  Mon Feb 24 02:57:05 2020
+++ b/src/plot/16bpp.c  Sun Mar 22 19:06:30 2020
@@ -17,7 +17,11 @@
 #include "nsfb.h"
 #include "plot.h"
 
-#define UNUSED __attribute__((unused)) 
+#ifdef __GNUC__
+#define UNUSED __attribute__((unused))
+#else
+#define UNUSED
+#endif
 
 static inline uint16_t *get_xy_loc(nsfb_t *nsfb, int x, int y)
 {
diff -urN a/src/plot/32bpp-xbgr8888.c b/src/plot/32bpp-xbgr8888.c
--- a/src/plot/32bpp-xbgr8888.c Mon Feb 24 02:57:05 2020
+++ b/src/plot/32bpp-xbgr8888.c Sun Mar 22 19:06:30 2020
@@ -17,8 +17,11 @@
 #include "nsfb.h"
 #include "plot.h"
 
+#ifdef __GNUC__
 #define UNUSED __attribute__((unused))
-
+#else
+#define UNUSED
+#endif
 
 /**
  * Get the address of a logical location on the framebuffer
diff -urN a/src/plot/32bpp-xrgb8888.c b/src/plot/32bpp-xrgb8888.c
--- a/src/plot/32bpp-xrgb8888.c Mon Feb 24 02:57:05 2020
+++ b/src/plot/32bpp-xrgb8888.c Sun Mar 22 19:06:30 2020
@@ -17,8 +17,11 @@
 #include "nsfb.h"
 #include "plot.h"
 
+#ifdef __GNUC__
 #define UNUSED __attribute__((unused))
-
+#else
+#define UNUSED
+#endif
 
 /**
  * Get the address of a logical location on the framebuffer
diff -urN a/src/plot.h b/src/plot.h
--- a/src/plot.h        Mon Feb 24 02:57:05 2020
+++ b/src/plot.h        Sun Mar 22 19:06:30 2020
@@ -45,6 +45,9 @@
     #else
         #error "Endian determination failed"
     #endif
+#elif defined(_PLAN9)
+    /* the only supported platforms are currently little endian */
+    #define NSFB_LE_BYTE_ORDER
 #else
     #include <endian.h>
     #if defined(__BYTE_ORDER__)
diff -urN a/src/surface/plan9.c b/src/surface/plan9.c
--- a/src/surface/plan9.c       Wed Dec 31 16:00:00 1969
+++ b/src/surface/plan9.c       Sun Mar 22 19:06:30 2020
@@ -0,0 +1,772 @@
+/*
+ * Copyright 2009 Vincent Sanders <vi...@simtec.co.uk>
+ *
+ * This file is part of libnsfb, http://www.netsurf-browser.org/
+ * Licenced under the MIT License,
+ *                http://www.opensource.org/licenses/mit-license.php
+ */
+
+#define _PLAN9_SOURCE
+#define TIMEOUT_MILLISEC 1000
+
+
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <ctype.h>
+
+#include "libnsfb.h"
+#include "libnsfb_event.h"
+#include "libnsfb_plot.h"
+#include "libnsfb_plot_util.h"
+
+#include "nsfb.h"
+#include "surface.h"
+#include "plot.h"
+#include "cursor.h"
+
+/* Plan 9 includes */
+
+#include <draw.h>
+#include <event.h>
+
+static bool inited;
+static int gwidth;
+static int gheight;
+static bool perform_resize;
+
+static unsigned char *
+create_local_image(int bytes);
+Image *
+create_draw_image(int width, int height, ulong chan);
+
+/*
+ * Functions and structures for buffering of events
+ *
+ * There is no 1:1 relationship between Plan 9 events and
+ * NSFB events (nsevent). The following ringbuffer can
+ * ease the translation of one Plan 9 keyevent to multiple
+ * nsevent or one mouse event to multiple nsevents for
+ * mousebutton press/release events and movement events
+ *
+ */
+#define EVBUFSIZE 8            /* max no. of events buffered */
+
+typedef struct eventbuffer_s {
+       nsfb_event_t buffer[EVBUFSIZE];
+       int buflen;             /* how many events are in the buffer */
+       int readidx;            /* next free slot to add event */
+       int writeidx;           /* first available event to read */
+} eventbuffer_t;
+
+/**
+ * Put an nsevent on hold (fifo buffer ringbuffer)
+ * 
+ * \param evbuf                ptr to the buffer (typically in drawstate)
+ * \param nsevent      ptr to event to buffer
+ * \return             0 if buffer is full, 1 for success.
+ *
+ */
+
+int
+putevent(eventbuffer_t *evbuf, nsfb_event_t *nsevent)
+{
+       if(evbuf->buflen >= EVBUFSIZE){
+               return 0;
+       }
+       evbuf->buffer[evbuf->writeidx++] = *nsevent;
+       evbuf->buflen++;
+       if(evbuf->writeidx >= EVBUFSIZE)
+               evbuf->writeidx = 0;
+       return 1;
+}
+
+/**
+ * Get an nsevent from the bufffer (fifo ringbuffer)
+ * 
+ * \param evbuf                ptr to the buffer (typically in drawstate)
+ * \param nsevent      ptr to event to write to
+ * \return             0 if buffer is empty, 1 for success.
+ *
+ */
+
+int
+getevent(eventbuffer_t *evbuf, nsfb_event_t *nsevent)
+{
+       if(evbuf->buflen < 1){
+               return 0;       /* fail (emtpy) */
+       }
+       *nsevent = evbuf->buffer[evbuf->readidx++];
+       evbuf->buflen--;
+       if(evbuf->readidx >= EVBUFSIZE)
+               evbuf->readidx = 0;
+
+       return 1;               /* success */
+}
+
+
+/*
+ * A 'drawstate' contain all information about the
+ * the connecton to graphics in Plan 9 as well a pointer
+ * to the memory area in which the library updates the content.
+ */
+
+typedef struct drawstate_s {
+       unsigned char *localimage;      /* common buffer (client) */
+       unsigned char *updateimage;     /* part of the image to update */
+       Image *srvimage;                /* dispaly buffer (server) */
+       int imagebytes;                 /* buffer size in bytes */
+       int mousebuttons;               /* last mouse button status */
+       eventbuffer_t eventbuffer;      /* buffer of incoming events */
+} drawstate_t;
+
+
+/* Posix sleep() sleeps in seconds, and plan 9's sleep() that sleeps
+ * in milliseconds is not easily accessible in APE, so mssleep() is
+ * used to sleep a number of milliseconds, calling Posix nanosleep().
+ */
+
+int
+mssleep(int ms)                /* sleep milliseconds */
+{
+       struct timespec req, rem;
+       if (ms > 999) {
+               req.tv_sec = (int) (ms/1000);
+               req.tv_nsec = (ms - ((long)req.tv_sec * 1000)) * 1000000;
+       } else {
+               req.tv_sec = 0;
+               req.tv_nsec = ms * 1000000;
+       }
+       return nanosleep(&req, &rem);   
+}
+
+
+/* I am not sure if this routine is needed to be implemented.
+ * I think it makes a copy of the display if the resolution is
+ * changed on the fly. But I am not sure that is even supported
+ * in framebuffer mode
+ */
+
+static bool
+p9copy(nsfb_t *nsfb, nsfb_bbox_t *srcbox, nsfb_bbox_t *dstbox)
+{
+       Point srcpt;
+       Rectangle dstrect;
+       drawstate_t *drawstate = nsfb->surface_priv;
+       srcpt.x=srcbox->x0;
+       srcpt.y=srcbox->y0;
+       dstrect.min.x = dstbox->x0;
+       dstrect.min.y = dstbox->y0;
+       dstrect.max.x = dstbox->x1;
+       dstrect.max.y = dstbox->y1;
+       draw(drawstate->srvimage,
+               dstrect, 
+               drawstate->srvimage, 
+               nil, 
+               srcpt);
+       return true;
+}
+
+
+static int 
+plan9_set_geometry(nsfb_t *nsfb, int width, int height,
+               enum nsfb_format_e format)
+{
+       if(!inited) {
+               fprintf(stderr, "INITING display!\n");
+               if (initdraw(0, 0, "netsurf-fb") < 0){
+                       fprintf(stderr, "initdraw failed\n");
+                       return -1;
+               }
+               inited=true;
+       }
+       //fprintf(stderr, "DBG: plan9_set_geometry(%d,%d) - check p9copy()!\n",
+       //              width, height);
+       
+       nsfb->width = width;
+       nsfb->height = height;
+       nsfb->format = format;
+
+       gwidth=width;
+       gheight=height;
+
+       /* select default sw plotters for format */
+       select_plotters(nsfb);
+       nsfb->plotter_fns->copy = p9copy;       /* empty function */
+
+       drawstate_t *drawstate = nsfb->surface_priv;
+
+       /* sanity check bpp. */
+       if ((nsfb->bpp != 32) && (nsfb->bpp != 16) && (nsfb->bpp != 8))
+               return -1;
+
+       if (drawstate == NULL)
+               drawstate = calloc(1, sizeof(drawstate_t));
+       if (drawstate == NULL)
+               return -1;      /* no memory */
+
+       /* create local framebuffer data storage */
+       drawstate->imagebytes =
+               (nsfb->bpp * nsfb->width * nsfb->height) >> 3;
+
+       if(drawstate->localimage) free(drawstate->localimage);
+       drawstate->localimage = calloc(1, drawstate->imagebytes); 
//create_local_image(drawstate->imagebytes);
+       if(drawstate->updateimage) free(drawstate->updateimage);
+       drawstate->updateimage = calloc(1, drawstate->imagebytes); 
//create_local_image(drawstate->imagebytes);
+
+       if (drawstate->localimage == NULL || drawstate->updateimage == NULL){
+               fprintf(stderr, "Unable to allocate memory "
+                               "for local framebuffer images\n");
+               free(drawstate);
+               return -1;
+               //drawshutdown(); /* to call this? */
+       }
+
+       /* crate a draw image on server side */
+       drawstate->srvimage = create_draw_image(nsfb->width,
+                       nsfb->height, XRGB32);
+
+       if (drawstate->srvimage == NULL){
+               fprintf(stderr, "Unable to create an image "
+                               "on the display server\n");
+               free(drawstate->localimage);
+               free(drawstate->updateimage);
+               free(drawstate);
+               return -1;
+               //drawshutdown(); /* to call this? */
+       }       
+       
+       /* ensure plotting information is stored */
+       nsfb->surface_priv = drawstate;
+       nsfb->ptr = drawstate->localimage;
+       nsfb->linelen = (nsfb->width * nsfb->bpp) / 8;
+
+       return 0;
+}
+
+
+void
+eresized(int new)              /* callback also called by libdraw */
+{
+       perform_resize=true;
+       if (new && getwindow(display, Refmesg) < 0)
+               fprintf(stderr,"can't reattach to window");     
+}
+
+/* create_local_image()
+ *
+ *     Allocate a frame buffer in user space memory, that 
+ *     the rest of the framebuffer library can write to.
+ *     The contents has to be loaded from here to the server
+ *     image, when it is updated.
+ */
+
+static unsigned char *
+create_local_image(int bytes)
+{
+       unsigned char *image_data;
+
+//     fprintf(stderr, "DBG: create_local_image(%d) -> %d KB\n",
+//                     bytes, bytes>>10);
+
+       image_data = calloc(1, bytes);
+       if (image_data == NULL)
+               return NULL;
+
+       return image_data;
+}
+
+/* create_draw_image()
+ *
+ *     Creates a Plan 9 'Image' object on the display server.
+ */
+
+Image *
+create_draw_image(int width, int height, ulong chan)
+{
+       Rectangle r;
+
+//     fprintf(stderr, "DBG: create_draw_image(%d,%d, ch=%x)\n",
+//                     width, height, chan);
+       
+/*     if(bpp != 24)
+               return NULL;    */      /* is this needed? */
+
+       r.min.x = 0;
+       r.min.y = 0;
+       r.max.x = width;
+       r.max.y = height;
+
+       return allocimage(display, r, chan, 0, DWhite);
+}
+
+
+static int
+plan9_initialise(nsfb_t *nsfb)
+{
+       if(!inited)     /* if we are called before plan9_set_geometry() */
+               plan9_set_geometry(nsfb, nsfb->width, nsfb->height, 
nsfb->format);
+
+       einit(Emouse|Ekeyboard);
+       eresized(0);    /* first drawing */
+       return 0;
+}
+
+static int plan9_finalise(nsfb_t *nsfb)
+{
+       drawstate_t *drawstate = nsfb->surface_priv;
+
+//     fprintf(stderr, "DBG: plan9_finalise()\n");
+
+       if (drawstate == NULL)
+               return 0;
+       /* free local image */
+       /* --- should free allocated structures here --- */
+       /* disconnect from display server? */
+       return 0;
+}
+
+/* wait_event()                Waits about 'timeout' milliseconds for an
+ *                     event. Returns 1 if there is an event, and
+ *                     0 if timed out.
+ */
+
+static int
+wait_event(int timeout)
+{
+       int i, steps;
+
+       steps = timeout / 250;
+
+       for(i=0; i< steps; i++){
+               if(ecanread(Ekeyboard|Emouse))
+                       return 1;       /* event available */
+               mssleep(250);
+       }
+       return 0;       /* timed out */
+}
+
+/* convert from plan9 keyboard codes (runes) to NSFB keycodes */
+/* currently only handling A-Z and some special keys */
+static int
+plan9_to_nsfbkeycode(Event *evp)
+{
+       int key;        /* plan 9 key */
+       int code;       /* NSFB code */
+
+       key = evp->kbdc;
+
+//     fprintf(stderr, "DBG: kbdc = %d [%c]\n", key, key);
+
+       if (32 <= key && key <= 127)            /* space to DEL */
+               code = key;
+       else if (8 <= key && key <= 9)          /* BS, TAB */
+               code = key;
+       else if (key == 10)
+               code = NSFB_KEY_RETURN;         /* LF -> CR */
+       else if (key == 0xf011)
+               code = NSFB_KEY_LEFT;
+       else if (key == 0xf012)
+               code = NSFB_KEY_RIGHT;
+       else
+               code = NSFB_KEY_UNKNOWN;
+
+       return code;
+}
+
+/* button_changed()    Check if mouse button 'butnum' (1,2,3)
+ *                     has been pressed or released since the
+ *                     butto recording.
+ *
+ * returns             MSAME, MDOWN or MUP
+ */
+
+enum { MSAME = 0, MDOWN = 1, MUP = 2 };
+
+static int
+button_changed(int newbuttons, int oldbuttons, int butnum)
+{
+       int mask;
+
+       mask = 1 << butnum-1;   /* mask is 1,2,4 for buttons  1,2,3 */
+
+       if      (!(oldbuttons & mask) &&  (newbuttons & mask))
+                       return MDOWN;
+       else if ( (oldbuttons & mask) && !(newbuttons & mask))
+                       return MUP;
+       else
+                       return MSAME;
+}
+
+
+/* trans_plan9_event() Translate Plan 9 events (keyboard and mouse)
+ *                     to corresponding NSFB-events (see libnsfb_event.h).
+ *
+ *                     If the user presses two mouse buttons at the same
+ *                     time, and they end up in the same event, only one
+ *                     of them register. Don't know if that can happen
+ *                     (maybe that will yield two events).
+ *
+ *                     Also, the Plan 9 mouse event contains both movement
+ *                     and button information in the same event, but NSFB
+ *                     uses two differents event types for movement and
+ *                     for presses/realeases. [As there is now buffering
+ *                     of keyboard events, it would be easy to do for the
+ *                     mouse too]. The current solution will prioritise
+ *                     button changes, ignoring any movement happeing
+ *                     during a button state change. Movements are absolute
+ *                     and tend to come in swarms, so this should not be
+ *                     big problem.
+ *
+ */
+
+static void
+trans_plan9_event(nsfb_t *nsfb, nsfb_event_t *nsevent, Event *evp, int e)
+{
+       drawstate_t *drawstate = nsfb->surface_priv;
+                       /* keeping old mouse button status in drawstate */
+       int chg;        /* mouse button change (MSAME|MDOWN/MUP) */
+       nsevent->type = NSFB_EVENT_NONE;        /* default to NONE */
+       int button_changes;     /* no. of button state chnges since last mouse 
event */
+       int keycode;    /* nsfb keycode, converted from Plan 9 key code */
+
+//     fprintf(stderr, "DBG: trans_plan9_event(e == %d)\n", e);
+
+       switch (e) {
+       case Ekeyboard:
+               keycode = plan9_to_nsfbkeycode(evp);
+
+                       /* UPPER case -> (1)LSHIFT_DOWN + (2)letter + 
(3)LSHIFT_UP */
+                       /* the first event is passed through, the other two are 
buffered */
+               if(isupper(keycode)){
+                       nsevent->type = NSFB_EVENT_KEY_DOWN;    /* event 2: key 
*/
+                       nsevent->value.keycode = tolower(keycode);
+                       putevent(&drawstate->eventbuffer, nsevent);
+
+                       nsevent->type = NSFB_EVENT_KEY_UP;      /* event 3: 
SHIFT UP */
+                       nsevent->value.keycode = NSFB_KEY_LSHIFT;
+                       putevent(&drawstate->eventbuffer, nsevent);
+
+                       nsevent->type = NSFB_EVENT_KEY_DOWN;    /* event 1: 
SHIFT DOWN */
+                       nsevent->value.keycode = NSFB_KEY_LSHIFT;
+                       
+               } else {        /* LOWER case - just pass through (without 
buffring) */
+                       nsevent->type = NSFB_EVENT_KEY_DOWN;
+                       nsevent->value.keycode = keycode;
+               }
+               break;
+       case Emouse:
+               button_changes = 0;     /* no button chanes we know of so 
far... */
+
+//             fprintf(stderr, "DBG: mouse event buttons=%d, xy=(%d,%d)\n",
+//                             evp->mouse.buttons,
+//                             evp->mouse.xy.x,
+//                             evp->mouse.xy.y);
+
+               if(chg=button_changed(evp->mouse.buttons, 
drawstate->mousebuttons, 1)) {
+                       nsevent->value.keycode = NSFB_KEY_MOUSE_1;
+                       if(chg==MDOWN)
+                               nsevent->type = NSFB_EVENT_KEY_DOWN;
+                       else
+                               nsevent->type = NSFB_EVENT_KEY_UP;
+                       button_changes++;
+               }
+               if(chg=button_changed(evp->mouse.buttons, 
drawstate->mousebuttons, 2)) {
+                       nsevent->value.keycode = NSFB_KEY_MOUSE_2;
+                       if(chg==MDOWN)
+                               nsevent->type = NSFB_EVENT_KEY_DOWN;
+                       else
+                               nsevent->type = NSFB_EVENT_KEY_UP;
+                       button_changes++;
+               }
+               if(chg=button_changed(evp->mouse.buttons, 
drawstate->mousebuttons, 3)) {
+                       nsevent->value.keycode = NSFB_KEY_MOUSE_3;
+                       if(chg==MDOWN)
+                               nsevent->type = NSFB_EVENT_KEY_DOWN;
+                       else
+                               nsevent->type = NSFB_EVENT_KEY_UP;
+                       button_changes++;
+               }
+               if(evp->mouse.buttons & 8) {
+                       nsevent->value.keycode = NSFB_KEY_MOUSE_4;
+                       nsevent->type = NSFB_EVENT_KEY_DOWN;
+                       button_changes++;
+               }
+               if(evp->mouse.buttons & 16) {
+                       nsevent->value.keycode = NSFB_KEY_MOUSE_5;
+                       nsevent->type = NSFB_EVENT_KEY_DOWN;
+                       button_changes++;
+               }
+               /* save new button status, for next event to compare with */
+               drawstate->mousebuttons = evp->mouse.buttons;
+
+               if(button_changes > 0)          /* don't send motion data if 
there are  */
+                       break;                  /* button changes to take care 
of       */
+
+               /* If we got an Emouse event without mouse button state change, 
we'll   */
+               /* give back a motion event to NSFB instead.                    
        */
+
+               nsevent->type = NSFB_EVENT_MOVE_ABSOLUTE;
+               nsevent->value.vector.x = evp->mouse.xy.x - screen->r.min.x;
+               nsevent->value.vector.y = evp->mouse.xy.y - screen->r.min.y;
+               nsevent->value.vector.z = 0;
+
+               break;
+       }
+
+       return;
+}
+
+/* print debugging info about a keyboard/mouse event */
+
+void
+debug_event(nsfb_event_t *nsevent, Event *evp)
+{
+       if (nsevent->type == NSFB_EVENT_KEY_DOWN || nsevent->type == 
NSFB_EVENT_KEY_UP)
+               fprintf(stderr, "DBG: keycode %d (type = %d, kbdc=%d)\n",
+                               nsevent->value.keycode,
+                               nsevent->type,
+                               evp->kbdc);
+       else if(nsevent->type == NSFB_EVENT_MOVE_ABSOLUTE)
+               fprintf(stderr, "DBG: mouse (%d,%d) [screen r.min = (%d,%d)]\n",
+                               nsevent->value.vector.x,
+                               nsevent->value.vector.y,
+                               screen->r.min.x,
+                               screen->r.min.y);
+}
+
+/* plan9_input()
+ *
+ *     Main entry point for checking for events. It has a lot of dead
+ *     code, as I didn't manage to get event timeouts to work
+ *     properly, but I still have hope I will.
+ */
+
+static bool
+plan9_input(nsfb_t *nsfb, nsfb_event_t *nsevent, int timeout)
+{
+       if(perform_resize) {
+               perform_resize=false;
+               int w = screen->r.max.x - screen->r.min.x;
+               int h = screen->r.max.y - screen->r.min.y;
+               fprintf(stderr, "RESIZE_EVENT.\n");
+               nsevent->type = NSFB_EVENT_RESIZE;
+               nsevent->value.resize.w = w;
+               nsevent->value.resize.h = h;
+               return true;
+       }
+       drawstate_t *drawstate = nsfb->surface_priv;
+//     static int once = 0;    /* ensure etimer() is only called once */
+       int e;                  /* type of event */
+       Event ev;               /* Plan 9 event struct */
+//     static int timer_id;            /* to identify a timer event */
+
+//     fprintf(stderr, "DBG: plan9_input(timeout = %d)\n", timeout);
+
+       if (drawstate == NULL)
+               return false;
+       
+//     if (!once) {            /* start the timer */
+//             timer_id = etimer(0, TIMEOUT_MILLISEC);
+//             fprintf(stderr, "DBG: plan9_input: timer_id is %d\n",
+//                             timer_id);
+//             once++;
+//     }
+       
+       /*
+        * Check if there are buffered events from pending
+        * This happens if an earlier Plan 9 event got translated
+        * into multiple nsevent. If there are at least one
+        * waiting event return the first one */
+
+       if(getevent(&drawstate->eventbuffer, nsevent))
+               return true;    /* event is filled in nsevent */
+
+
+       /* Event checking behaviour depeding on 'timeout':
+        * timeout == 0 Check if there is an kbd/mouse event,
+        *              if not, return false.
+        * timeout > 0  Wait for a kbd/mouse event, but return
+        *              false if a timer event occurs before. (*)
+        * timeout < 0  Wait for next kbd/mouse event, ignoring
+        *              any timer events.
+        *
+        * (*) CURRENTLY sleep a bit and then return if no event.
+        */
+
+       if (timeout == 0) {
+               if(!ecanread(Ekeyboard|Emouse /* | timer_id */))
+                       return false;   /* no event to read */
+               e = event(&ev);
+       //      if(e == timer_id)       /* cannot happen as there is no timer 
event */
+       //              return false;
+       } else if (timeout > 0) {
+               /* solution using a timer event (not working) */
+               //      e = event(&ev);
+               //      if(e == timer_id)
+               //              return false;
+               //
+               /* quick and dirty solution with sleep */
+               if (wait_event(timeout)) {
+                       e = event(&ev);
+               } else {
+                       nsevent->type = NSFB_EVENT_CONTROL;
+                       nsevent->value.controlcode = NSFB_CONTROL_TIMEOUT;
+                       return true;
+               }
+       } else {
+       //      while( (e=event(&ev)) == timer_id)
+       //              ;
+               e=event(&ev);   /* only real events at the moment */
+       }
+       
+       /* from here on we have a keyboard or mouse event in (e, ev) */ 
+       
+       /* this updates 'nsevent' with info on the kbd|mouse event */
+       trans_plan9_event(nsfb, nsevent, &ev, e);
+
+//     debug_event(nsevent, &ev);      /* print debug info */
+
+       return true;    /* event was sucessfully registred */
+}
+
+/* This has something to do with the mouse pointer. Not sure if
+ * it is needed, as plan 9 has its own pointer
+ */
+static int
+plan9_claim(nsfb_t *nsfb, nsfb_bbox_t *box)
+{
+//     fprintf(stderr, "DBG: plan9_claim()\n");
+       return 0;
+}
+
+static int
+plan9_cursor(nsfb_t *nsfb, struct nsfb_cursor_s *cursor)
+{
+//     fprintf(stderr, "DBG: plan9_cursor()\n");
+       return true;
+}
+
+/* buffer_offset()
+ *
+ *     Calculate the byte offset in the locally stored
+ *     image buffer for a Point in the window.
+ */
+
+int buffer_offset(Point pt, int width, int bpp)
+{
+       return ((pt.y * width + pt.x) * bpp) >> 3;
+}
+
+/* rect_bytes()
+ *
+ *     Caluculate the number of bytes the data of a Rectangle
+ *     occupies, given the number of bitplanes.
+ */
+
+int rect_bytes(Rectangle r, int bpp)
+{
+       return ( (r.max.y-r.min.y) * (r.max.x - r.min.x) * bpp ) >> 3;
+}
+
+/* copy_image_part()
+ *
+ *     Copy data from one memory buffer to another, but copy
+ *     only data within the specified Rectangle
+ * Params:
+ *     dst     Memory buffer to copy to.
+ *     src     First byte of the image in the rectangle to copy from.
+ *     r       Rectangle of the area to copy.
+ *     width   The full width of the window/buffer in pixels.
+ *     bpp     Bitplanes (giving bytes per pixel) 
+ */
+
+void
+copy_image_part(unsigned char *dst, unsigned char *src, Rectangle r,
+               int width, int bpp)
+{
+       int rectxbytes;         /* bytes per line of the 'r' */
+       int dstbytes;           /* bytes per line in the whole window */
+       int rectheight;         /* 'r' height */
+       int y;
+
+       rectxbytes = (r.max.x - r.min.x) * bpp>>3;
+       rectheight = r.max.y - r.min.y;
+       dstbytes = width * bpp>>3;
+
+       for(y = 0; y < rectheight; y++) {
+               memcpy(dst, src, rectxbytes);
+               src += dstbytes;
+               dst += rectxbytes;
+       }
+}
+
+/* redraw_srvimage()
+ *
+ *     Redraws the image'srvimage' onto the screen image using
+ *     libdraw. Both images reside on the display server.
+ */
+
+static void
+redraw_srvimage(drawstate_t *drawstate)
+{
+       draw(screen, screen->r, drawstate->srvimage, nil, ZP);
+       flushimage(display, 1); 
+
+}
+
+/* update_and_redraw_srvimage()
+ *
+ *     Updates the internal server image using the data in the
+ *     local buffer (that the NSFB library writes to). Also
+ *     forces a redraw of the server image.
+ */
+
+static int
+update_and_redraw_srvimage(drawstate_t *drawstate, Rectangle r,
+                       int width, int height, int bpp)
+{
+       copy_image_part(drawstate->updateimage,
+                       drawstate->localimage + buffer_offset(r.min, width, 
bpp),
+                       r, width, bpp);
+
+       loadimage(drawstate->srvimage, r, drawstate->updateimage,
+                       rect_bytes(r, bpp));
+       
+       redraw_srvimage(drawstate);
+       return 0;
+}
+
+static int
+plan9_update(nsfb_t *nsfb, nsfb_bbox_t *box)
+{
+       drawstate_t *drawstate = nsfb->surface_priv;
+       Rectangle r;
+
+       r.min.x = box->x0;
+       r.min.y = box->y0;
+       r.max.x = box->x1;
+       r.max.y = box->y1;
+
+//     fprintf(stderr, "DBG: %4d KB update (%3d,%3d) to (%3d, %3d)\n",
+//             (r.max.x-r.min.x)*(r.max.y-r.min.y)*(nsfb->bpp>>3) >> 10,
+//             r.min.x, r.min.y, r.max.x, r.max.y);
+
+       update_and_redraw_srvimage(drawstate, r,
+                       nsfb->width, nsfb->height, nsfb->bpp);
+       return 0;
+}
+
+const nsfb_surface_rtns_t plan9_rtns = {
+    .initialise = plan9_initialise,
+    .finalise = plan9_finalise,
+    .input = plan9_input,
+    .claim = plan9_claim,
+    .update = plan9_update,
+    .cursor = plan9_cursor,
+    .geometry = plan9_set_geometry,
+};
+
+NSFB_SURFACE_DEF(plan9, NSFB_SURFACE_PLAN9, &plan9_rtns)
diff -urN a/src/surface.h b/src/surface.h
--- a/src/surface.h     Mon Feb 24 02:57:05 2020
+++ b/src/surface.h     Sun Mar 22 19:06:30 2020
@@ -4,6 +4,14 @@
 #include "libnsfb_plot.h"
 #include "nsfb.h"
 
+#ifdef __GNUC__
+#define REGISTER(fn)   static void fn(void) __attribute__((constructor));
+#else
+/* it'll just have to be called manually */
+#define REGISTER(fn)   void fn(void);
+#endif
+
+
 /* surface default options */
 typedef int (nsfb_surfacefn_defaults_t)(nsfb_t *nsfb);
 
@@ -48,7 +56,7 @@
 
 /* macro which adds a builtin command with no argument limits */
 #define NSFB_SURFACE_DEF(__name, __type, __rtns)                       \
-    static void __name##_register_surface(void) __attribute__((constructor)); \
+    REGISTER(__name##_register_surface); \
     void __name##_register_surface(void) {                              \
         _nsfb_register_surface(__type, __rtns, #__name);               \
     }                                                                   


Reply via email to