libnslog: portability fixes for plan9
by ori@eigenstate.org
>From be21e1a1d3ffa0b3baa073bdb4b04c80af7f7bee
From: Ori Bernstein <ori(a)eigenstate.org>
Date: Sun, 22 Mar 2020 18:08:23 -0700
Subject: [PATCH] portability fixes for plan9
this fixes 3 issues:
- First off, the plan 9 C compilers don't handle GNU style varargs,
so we switch over to c99 style.
- Second, the __attribute((format, printf) is a GNU C extension,
so we only define it for GNU C. For plan 9, we use the varargck
pragma to do the same thing.
- Third, 0 length arrays aren't portable, so we use C99 flexible
array members.
diff -urN a/include/nslog/nslog.h b/include/nslog/nslog.h
--- a/include/nslog/nslog.h Sun Feb 23 01:49:32 2020
+++ b/include/nslog/nslog.h Sun Mar 22 18:08:23 2020
@@ -17,6 +17,13 @@
#include <stdarg.h>
+#if defined(__GNUC__)
+# define PRINTF(fmt, args) __attribute__ ((format (printf, 2, 3)))
+#elif defined(_PLAN9)
+# pragma varargck nslog__log argpos 2
+# define PRINTF(pos, args)
+#endif
+
/**
* Log levels
*
@@ -181,7 +188,7 @@
* \param logmsg The log message itself (printf format string)
* \param args The arguments for the log message
*/
-#define NSLOG(catname, level, logmsg, args...) \
+#define NSLOG(catname, level, ...) \
do { \
if (NSLOG_LEVEL_##level >= NSLOG_COMPILED_MIN_LEVEL) { \
static nslog_entry_context_t _nslog_ctx = { \
@@ -193,7 +200,7 @@
sizeof(__PRETTY_FUNCTION__) - 1, \
__LINE__, \
}; \
- nslog__log(&_nslog_ctx, logmsg, ##args); \
+ nslog__log(&_nslog_ctx, __VA_ARGS__); \
} \
} while(0)
@@ -209,7 +216,7 @@
*/
void nslog__log(nslog_entry_context_t *ctx,
const char *pattern,
- ...) __attribute__ ((format (printf, 2, 3)));
+ ...) PRINTF(2, 3);
/**
* Log error types
diff -urN a/src/core.c b/src/core.c
--- a/src/core.c Sun Feb 23 01:49:32 2020
+++ b/src/core.c Sun Mar 22 18:08:23 2020
@@ -19,7 +19,7 @@
static struct nslog_cork_chain {
struct nslog_cork_chain *next;
nslog_entry_context_t context;
- char message[0]; /* NUL terminated */
+ char message[]; /* NUL terminated */
} *nslog__cork_chain = NULL, *nslog__cork_chain_last = NULL;
static nslog_callback nslog__cb = NULL;
3 years, 8 months
libwapcaplet portability fixes (re: plan 9 port)
by ori@eigenstate.org
Hey,
I'm one of the people who's been helping port netsurf to
plan9, and I've started rebasing changes that we did against
3.9 to master, so that we can start submitting what makes sense.
First off, thanks for a wonderfully portable codebase -- it's
great how small the patches are to get most of the libraries
working.
I'm hoping that we can get things to the point where we need to
carry very few patches forward, though I don't expect you'll want
to maintain our build system (ie, the mkfiles), so I'm going to
leave them out of patches.
Here's the first patch.
>From b02d1e93846df7f135bc8c1c82c9a2e3291480cf
From: Ori Bernstein <ori(a)eigenstate.org>
Date: Sun, 22 Mar 2020 17:47:46 -0700
Subject: [PATCH] portability fixes for Plan 9
The plan 9 compilers are not gcc, and do not handle many
gcc extensions like expression templates. this change
replaces them with either plain macros, or with static
inline functions, which are already in use elsewhere in
the project.
diff -urN a/include/libwapcaplet/libwapcaplet.h b/include/libwapcaplet/libwapcaplet.h
--- a/include/libwapcaplet/libwapcaplet.h Sat Sep 7 06:59:40 2019
+++ b/include/libwapcaplet/libwapcaplet.h Sun Mar 22 17:47:46 2020
@@ -133,7 +133,12 @@
* @note Use this if copying the string and intending both sides to retain
* ownership.
*/
-#define lwc_string_ref(str) ({lwc_string *__lwc_s = (str); assert(__lwc_s != NULL); __lwc_s->refcnt++; __lwc_s;})
+static inline lwc_string *
+lwc_string_ref(lwc_string *str)
+{
+ str->refcnt++;
+ return str;
+}
/**
* Release a reference on an lwc_string.
@@ -177,32 +182,6 @@
((*(ret) = ((str1) == (str2))), lwc_error_ok)
/**
- * Check if two interned strings are case-insensitively equal.
- *
- * @param _str1 The first string in the comparison.
- * @param _str2 The second string in the comparison.
- * @param _ret A pointer to a boolean to be filled out with the result.
- * @return Result of operation, if not ok then value pointed to by \a ret will
- * not be valid.
- */
-#define lwc_string_caseless_isequal(_str1,_str2,_ret) ({ \
- lwc_error __lwc_err = lwc_error_ok; \
- lwc_string *__lwc_str1 = (_str1); \
- lwc_string *__lwc_str2 = (_str2); \
- bool *__lwc_ret = (_ret); \
- \
- if (__lwc_str1->insensitive == NULL) { \
- __lwc_err = lwc__intern_caseless_string(__lwc_str1); \
- } \
- if (__lwc_err == lwc_error_ok && __lwc_str2->insensitive == NULL) { \
- __lwc_err = lwc__intern_caseless_string(__lwc_str2); \
- } \
- if (__lwc_err == lwc_error_ok) \
- *__lwc_ret = (__lwc_str1->insensitive == __lwc_str2->insensitive); \
- __lwc_err; \
- })
-
-/**
* Intern a caseless copy of the passed string.
*
* @param str The string to intern the caseless copy of.
@@ -215,6 +194,30 @@
*/
extern lwc_error
lwc__intern_caseless_string(lwc_string *str);
+
+/**
+ * Check if two interned strings are case-insensitively equal.
+ *
+ * @param _str1 The first string in the comparison.
+ * @param _str2 The second string in the comparison.
+ * @param _ret A pointer to a boolean to be filled out with the result.
+ * @return Result of operation, if not ok then value pointed to by \a ret will
+ * not be valid.
+ */
+static inline lwc_error
+lwc_string_caseless_isequal(lwc_string *str1, lwc_string *str2, bool *ret)
+{
+ lwc_error err = lwc_error_ok;
+ if (str1->insensitive == NULL) {
+ err = lwc__intern_caseless_string(str1);
+ }
+ if (err == lwc_error_ok && str2->insensitive == NULL) {
+ err = lwc__intern_caseless_string(str2);
+ }
+ if (err == lwc_error_ok)
+ *ret = (str1->insensitive == str2->insensitive);
+ return err;
+}
/**
* Retrieve the data pointer for an interned string.
@@ -228,7 +231,7 @@
* in future. Any code relying on it currently should be
* modified to use ::lwc_string_length if possible.
*/
-#define lwc_string_data(str) ({assert(str != NULL); (const char *)((str)+1);})
+#define lwc_string_data(str) ((const char *)((str)+1))
/**
* Retrieve the data length for an interned string.
@@ -236,7 +239,7 @@
* @param str The string to retrieve the length of.
* @return The length of \a str.
*/
-#define lwc_string_length(str) ({assert(str != NULL); (str)->len;})
+#define lwc_string_length(str) ((str)->len)
/**
* Retrieve (or compute if unavailable) a hash value for the content of the string.
@@ -250,7 +253,7 @@
* to be stable between invocations of the program. Never use the hash
* value as a way to directly identify the value of the string.
*/
-#define lwc_string_hash_value(str) ({assert(str != NULL); (str)->hash;})
+#define lwc_string_hash_value(str) ((str)->hash)
/**
* Retrieve a hash value for the caseless content of the string.
@@ -260,8 +263,8 @@
* @return Result of operation, if not ok then value pointed to by \a ret will
* not be valid.
*/
-static inline lwc_error lwc_string_caseless_hash_value(
- lwc_string *str, lwc_hash *hash)
+static inline lwc_error
+lwc_string_caseless_hash_value(lwc_string *str, lwc_hash *hash)
{
if (str->insensitive == NULL) {
lwc_error err = lwc__intern_caseless_string(str);
3 years, 8 months
nsfb plan9 support
by ori@eigenstate.org
>From cb45b499fb048c7bfcaea0744f4303b964d48469
From: Ori Bernstein <ori(a)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 <vince(a)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); \
}
3 years, 8 months
[PATCH] make source a compatible type
by ori@eigenstate.org
>From 5b1b4fc13212991968bff51e98cba9da5552d983
From: Ori Bernstein <ori(a)eigenstate.org>
Date: Sun, 22 Mar 2020 18:04:44 -0700
Subject: [PATCH] make source a compatible type
We pass uint32_t source as an out parameter which takes an int32_t pointer,
and the plan 9 compilers complain about this. This makes the type match.
diff -urN a/bindings/hubbub/parser.c b/bindings/hubbub/parser.c
--- a/bindings/hubbub/parser.c Sat Feb 22 09:15:42 2020
+++ b/bindings/hubbub/parser.c Sun Mar 22 18:04:44 2020
@@ -642,7 +642,7 @@
static hubbub_error change_encoding(void *parser, const char *charset)
{
dom_hubbub_parser *dom_parser = (dom_hubbub_parser *) parser;
- uint32_t source;
+ int32_t source;
const char *name;
/* If we have an encoding here, it means we are *certain* */
3 years, 8 months
[PATCH] libcss portability fixes for plan9
by ori@eigenstate.org
>From 294f0ec43f6f64765d85d2e85ac9b4dafeb0e045
From: Ori Bernstein <ori(a)eigenstate.org>
Date: Sun, 22 Mar 2020 18:00:34 -0700
Subject: [PATCH] portability fixes for plan9
Several changes are made here:
- Our compilers don't like double-declared enum tags, so we rename
them to avoid conflicts.
- We don't handle static initializations of bitfields, so we
replace 2 16 bit bitfields with 2 int16_ts. This shouldn't
affect storage or performance.
- uint32_t isn't guaranteed to be compatible with css_unit,
and in fact it isn't on plan9, so we need to just pass
a uint32_t.
diff -urN a/include/libcss/errors.h b/include/libcss/errors.h
--- a/include/libcss/errors.h Mon Feb 24 02:28:58 2020
+++ b/include/libcss/errors.h Sun Mar 22 18:00:34 2020
@@ -14,8 +14,9 @@
#endif
#include <stddef.h>
+#include <libcss/errors.h>
-typedef enum css_error {
+typedef enum {
CSS_OK = 0,
CSS_NOMEM = 1,
diff -urN a/src/lex/lex.c b/src/lex/lex.c
--- a/src/lex/lex.c Mon Feb 24 02:28:58 2020
+++ b/src/lex/lex.c Sun Mar 22 18:00:34 2020
@@ -1375,7 +1375,7 @@
css_error error;
parserutils_error perror;
enum { Initial = 0, LParen = 1, W1 = 2, Quote = 3,
- URL = 4, W2 = 5, RParen = 6, String = 7 };
+ URL = 4, W2 = 5, RParen = 6, Str = 7 };
/* URI = "url(" w (string | urlchar*) w ')'
*
@@ -1518,9 +1518,9 @@
APPEND(lexer, cptr, clen);
break;
- case String:
+ case Str:
string:
- lexer->substate = String;
+ lexer->substate = Str;
error = consumeString(lexer);
if (error == CSS_INVALID) {
diff -urN a/src/parse/properties/utils.c b/src/parse/properties/utils.c
--- a/src/parse/properties/utils.c Mon Feb 24 02:28:58 2020
+++ b/src/parse/properties/utils.c Sun Mar 22 18:00:34 2020
@@ -932,7 +932,7 @@
if (token->type == CSS_TOKEN_DIMENSION) {
size_t len = lwc_string_length(token->idata);
const char *data = lwc_string_data(token->idata);
- css_unit temp_unit = CSS_UNIT_PX;
+ uint32_t temp_unit = CSS_UNIT_PX;
error = css__parse_unit_keyword(data + consumed, len - consumed,
&temp_unit);
@@ -961,7 +961,7 @@
* (e.g. "0 px")
*/
int temp_ctx = *ctx;
- css_unit temp_unit;
+ uint32_t temp_unit;
consumeWhitespace(vector, &temp_ctx);
3 years, 8 months
libnspsl -- remove bitfields
by ori@eigenstate.org
This patch will probably be something we need to carry forward
in our own port, but I'm going to submit it for discussion anyways.
Currently, the plan 9 C compilers do *not* support static initialization
of bitfields, so we need to do somethign about that. We can replace them
with an enum and flags, or we can drop them entirely. This patch does
the latter.
If you'd be willing to take some other method of removing bitfields, I'd
be happy to implement it and reduce the diff.
--- /mnt/git/object/e41d7b3c868309e0704e01e841cc80da72dd8157/tree/src/psl.inc Mon Jun 24 03:47:46 2019
+++ src/psl.inc Sun Mar 22 14:53:33 2020
@@ -9,9 +9,9 @@
*/
union pnode {
struct {
- unsigned int idx:24; /**< index of domain element in string table */
- unsigned int len:6; /**< length of domain element in string table */
- unsigned int children:1; /**< has children */
+ unsigned int idx; /**< index of domain element in string table */
+ unsigned char len; /**< length of domain element in string table */
+ unsigned char children; /**< has children */
} label;
struct {
uint16_t index; /**< index of first child node */
@@ -28,8 +28,8 @@ enum stab_entities {
* Huffman coding node
*/
struct hnode {
- uint8_t term:1; /**< non zero if the node terminates a code */
- uint8_t value:7; /**< value in node */
+ uint8_t term; /**< non zero if the node terminates a code */
+ uint8_t value; /**< value in node */
};
/**
3 years, 8 months