diff --git a/Make.defs b/Make.defs index ab79ce71cb5..2f784a7647f 100644 --- a/Make.defs +++ b/Make.defs @@ -130,6 +130,18 @@ endif CFLAGS += ${INCDIR_PREFIX}"$(APPDIR)$(DELIM)include" CXXFLAGS += ${INCDIR_PREFIX}"$(APPDIR)$(DELIM)include" +# EXPORTED_INCLUDES lists include directories that must be available to +# applications built out of tree from the NuttX export package. Each +# entry is prefixed with ${INCDIR_PREFIX} (i.e. -I) and is added +# to CFLAGS/CXXFLAGS so that it takes effect in the in-tree build as +# well. The content of the listed directories is copied to the include +# directory of the export package by the export target in apps/Makefile. +# Components should append their public include directories in their +# Make.defs. + +CFLAGS += $(EXPORTED_INCLUDES) +CXXFLAGS += $(EXPORTED_INCLUDES) + NUTTXLIB ?= $(call CONVERT_PATH,$(TOPDIR)$(DELIM)staging) # SPLITVARIABLE - Split long variables into specified batches diff --git a/Makefile b/Makefile index 5a357053891..74cb37da32b 100644 --- a/Makefile +++ b/Makefile @@ -206,6 +206,13 @@ ifneq ($(BUILTIN_REGISTRY),) done endif endif + $(Q) for inc in $(EXPORTED_INCLUDES) ; do \ + inc=$${inc#"$(INCDIR_PREFIX)"}; \ + if [ -d "$${inc}" ]; then \ + mkdir -p "${EXPORTDIR}"$(DELIM)include || exit 1; \ + cp -Rf "$${inc}"$(DELIM). "${EXPORTDIR}"$(DELIM)include || exit 1; \ + fi \ + done endif .depdirs: $(foreach SDIR, $(CONFIGURED_APPS), $(SDIR)_depend) diff --git a/examples/nanoxcalc/Kconfig b/examples/nanoxcalc/Kconfig new file mode 100644 index 00000000000..5b2fa079cd0 --- /dev/null +++ b/examples/nanoxcalc/Kconfig @@ -0,0 +1,28 @@ +config EXAMPLES_NANOXCALC + tristate "Nano-X calculator example" + default n + depends on MICROWINDOWS_NANOX && LIBC_FLOATINGPOINT + ---help--- + Enable the Nano-X calculator example application. It is a + port of the nxcalc demo from Microwindows which connects to + the Nano-X server started by examples/nanoxterm and shows + a calculator keypad operated by the mouse or keyboard. + +if EXAMPLES_NANOXCALC + +config EXAMPLES_NANOXCALC_PROGNAME + string "Program name" + default "nanoxcalc" + ---help--- + This is the name of the program that will be used when the NSH ELF + program is installed. + +config EXAMPLES_NANOXCALC_PRIORITY + int "Nano-X calculator task priority" + default 100 + +config EXAMPLES_NANOXCALC_STACKSIZE + int "Nano-X calculator stack size" + default 16384 + +endif diff --git a/examples/nanoxcalc/Make.defs b/examples/nanoxcalc/Make.defs new file mode 100644 index 00000000000..c3081015861 --- /dev/null +++ b/examples/nanoxcalc/Make.defs @@ -0,0 +1,25 @@ +############################################################################ +# apps/examples/nanoxcalc/Make.defs +# +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. The +# ASF licenses this file to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance with the +# License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +############################################################################ + +ifneq ($(CONFIG_EXAMPLES_NANOXCALC),) +CONFIGURED_APPS += $(APPDIR)/examples/nanoxcalc +endif diff --git a/examples/nanoxcalc/Makefile b/examples/nanoxcalc/Makefile new file mode 100644 index 00000000000..7a703a39814 --- /dev/null +++ b/examples/nanoxcalc/Makefile @@ -0,0 +1,35 @@ +############################################################################ +# apps/examples/nanoxcalc/Makefile +# +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. The +# ASF licenses this file to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance with the +# License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +############################################################################ + +include $(APPDIR)/Make.defs + +PROGNAME = $(CONFIG_EXAMPLES_NANOXCALC_PROGNAME) +PRIORITY = $(CONFIG_EXAMPLES_NANOXCALC_PRIORITY) +STACKSIZE = $(CONFIG_EXAMPLES_NANOXCALC_STACKSIZE) +MODULE = $(CONFIG_EXAMPLES_NANOXCALC) + +# Port of the upstream nxcalc demo (src/demos/nanox/nxcalc.c) +MAINSRC = nxcalc.c +CFLAGS += -Wno-undef + + +include $(APPDIR)/Application.mk diff --git a/examples/nanoxcalc/nxcalc.c b/examples/nanoxcalc/nxcalc.c new file mode 100644 index 00000000000..8a7936dcf66 --- /dev/null +++ b/examples/nanoxcalc/nxcalc.c @@ -0,0 +1,510 @@ +/**************************************************************************** + * apps/examples/nanoxcalc/nxcalc.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * nxcalc - Simple graphical calculator for Microwindows / Nano-X + * + * Inspired by the nxclock example (Greg Haerr). + * + * Run inside an environment where the Nano-X server is available. + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ +#include +#include +#include +#include +#include +#include "nano-X.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ +#define WIN_W 160 +#define WIN_H 200 +#define DISP_H 35 +#define COLS 4 +#define ROWS 5 +static GR_WINDOW_ID win; +static GR_GC_ID gc_text; +static GR_GC_ID gc_button; +static GR_GC_ID gc_button_press; +static GR_GC_ID gc_border; + +/* calculator state */ + +static char display[128]; +static double acc = 0.0; +static char pending_op = 0; +static int entering = 0; +static int dot_entered = 0; + +/* button layout */ + +static char *btn_labels[] = +{ + "C", "<-", "+/-", "/", "7", "8", "9", "*", + "4", "5", "6", "-", "1", "2", "3", "+", + "0", ".", "=", NULL +}; + +static GR_RECT btn_rects[ROWS][COLS]; + +/* function prototypes */ + +static void redraw(void); +static void press_button(const char *label); +static void compute_equal(void); +static void apply_pending(double val); + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static double display_to_double(void) +{ + if (strlen(display) == 0) + { + return 0.0; + } + + return strtod(display, NULL); +} + +static void set_display_from_double(double v) +{ + char buf[128]; + double iv; + + if (fabs(v) < 1e-12) + { + v = 0.0; + } + + if (modf(v, &iv) == 0.0) + { + snprintf(buf, sizeof(buf), "%.0f", v); + } + else + { + snprintf(buf, sizeof(buf), "%.10g", v); + } + + strncpy(display, buf, sizeof(display) - 1); + display[sizeof(display) - 1] = '\0'; +} + +/* ========================= MAIN ========================= */ + +int main(int argc, char **argv) +{ + GR_EVENT event; + int r; + int c; + int idx; + + if (GrOpen() < 0) + { + fprintf(stderr, "nxcalc: cannot open Nano-X\n"); + return 1; + } + + win = GrNewWindowEx(GR_WM_PROPS_APPWINDOW, "nxcalc", GR_ROOT_WINDOW_ID, 10, + 10, WIN_W, WIN_H, GrGetSysColor(GR_COLOR_WINDOW)); + + GrSelectEvents(win, + GR_EVENT_MASK_EXPOSURE | GR_EVENT_MASK_BUTTON_DOWN | + GR_EVENT_MASK_BUTTON_UP | GR_EVENT_MASK_CLOSE_REQ); + + gc_text = GrNewGC(); + gc_button = GrNewGC(); + gc_button_press = GrNewGC(); + gc_border = GrNewGC(); + + GrSetGCForeground(gc_text, GrGetSysColor(GR_COLOR_WINDOWTEXT)); + GrSetGCBackground(gc_text, GrGetSysColor(GR_COLOR_WINDOW)); + + GrSetGCForeground(gc_button, GrGetSysColor(GR_COLOR_BTNFACE)); + GrSetGCBackground(gc_button, GrGetSysColor(GR_COLOR_WINDOW)); + + GrSetGCForeground(gc_button_press, GrGetSysColor(GR_COLOR_BTNSHADOW)); + GrSetGCBackground(gc_button_press, GrGetSysColor(GR_COLOR_WINDOW)); + + GrSetGCForeground(gc_border, GrGetSysColor(GR_COLOR_BTNTEXT)); + GrSetGCBackground(gc_border, GrGetSysColor(GR_COLOR_WINDOW)); + + /* init state */ + + display[0] = '\0'; + acc = 0.0; + pending_op = 0; + entering = 0; + dot_entered = 0; + + /* layout buttons */ + + int grid_x = 12; + int grid_y = DISP_H + 10; + int grid_w = WIN_W - 20; + int grid_h = WIN_H - DISP_H - 20; + int cell_w = grid_w / COLS; + int cell_h = grid_h / ROWS; + + idx = 0; + for (r = 0; r < ROWS; r++) + { + for (c = 0; c < COLS; c++) + { + int x = grid_x + c * cell_w; + int y = grid_y + r * cell_h; + btn_rects[r][c].x = x; + btn_rects[r][c].y = y; + btn_rects[r][c].width = cell_w - 6; + btn_rects[r][c].height = cell_h - 6; + idx++; + } + } + + GrMapWindow(win); + set_display_from_double(0.0); + redraw(); + + while (1) + { + GrGetNextEvent(&event); + switch (event.type) + { + case GR_EVENT_TYPE_EXPOSURE: + { + redraw(); + break; + } + + case GR_EVENT_TYPE_BUTTON_DOWN: + { + int mx = event.button.x; + int my = event.button.y; + int found = 0; + for (r = 0; r < ROWS && !found; r++) + { + for (c = 0; c < COLS && !found; c++) + { + GR_RECT *rc = &btn_rects[r][c]; + if (mx >= rc->x && mx <= rc->x + rc->width && + my >= rc->y && my <= rc->y + rc->height) + { + GrFillRect(win, gc_button_press, rc->x, rc->y, + rc->width, rc->height); + found = 1; + } + } + } + break; + } + + case GR_EVENT_TYPE_BUTTON_UP: + { + int mx = event.button.x; + int my = event.button.y; + int found = 0; + for (r = 0; r < ROWS && !found; r++) + { + for (c = 0; c < COLS && !found; c++) + { + GR_RECT *rc = &btn_rects[r][c]; + if (mx >= rc->x && mx <= rc->x + rc->width && + my >= rc->y && my <= rc->y + rc->height) + { + idx = r * COLS + c; + const char *lbl = (idx < + (int)(sizeof(btn_labels) / + sizeof(btn_labels[0]))? + btn_labels[idx] : NULL); + if (lbl) + { + press_button(lbl); + redraw(); + } + + found = 1; + } + } + } + break; + } + + case GR_EVENT_TYPE_CLOSE_REQ: + { + GrClose(); + return 0; + } + } + } + + return 0; +} + +/* ========================= UI DRAWING ========================= */ + +static void redraw(void) +{ + int r; + int c; + int idx; + int tw; + int th; + int tb; + + /* display area */ + + GrSetGCForeground(gc_button, GrGetSysColor(GR_COLOR_WINDOW)); + GrFillRect(win, gc_button, 5, 5, WIN_W - 10, DISP_H - 10); + GrSetGCForeground(gc_border, GrGetSysColor(GR_COLOR_BTNSHADOW)); + GrRect(win, gc_border, 5, 5, WIN_W - 11, DISP_H - 10); + + /* display text (right aligned) */ + + GrGetGCTextSize(gc_text, display, strlen(display), GR_TFTOP, &tw, + &th, &tb); + + int x = WIN_W - 12 - tw; + if (x < 10) + { + x = 10; + } + + GrText(win, gc_text, x, 5 + (DISP_H / 2) - 10, display, strlen(display), + GR_TFTOP); + + /* draw buttons */ + + idx = 0; + GrSetGCForeground(gc_button, GrGetSysColor(GR_COLOR_BTNFACE)); + for (r = 0; r < ROWS; r++) + { + for (c = 0; c < COLS; c++) + { + GR_RECT *rc = &btn_rects[r][c]; + char *lbl = (idx < + (int)(sizeof(btn_labels) / + sizeof(btn_labels[0]))? btn_labels[idx] : NULL); + + GrSetGCForeground(gc_button, GrGetSysColor(GR_COLOR_WINDOW)); + GrFillRect(win, gc_button, rc->x, rc->y, rc->width, rc->height); + GrSetGCForeground(gc_border, GrGetSysColor(GR_COLOR_BTNSHADOW)); + GrRect(win, gc_border, rc->x, rc->y, rc->width, rc->height); + + if (lbl) + { + GrGetGCTextSize(gc_text, lbl, strlen(lbl), GR_TFTOP, &tw, &th, + &tb); + GrText(win, gc_text, rc->x + rc->width / 2 - tw / 2, + rc->y + rc->height / 2 - 6, lbl, strlen(lbl), GR_TFTOP); + } + + idx++; + } + } + + GrFlush(); +} + +/* ========================= LOGIC ========================= */ + +static void press_button(const char *label) +{ + char tmp[128]; + double val; + + if (strcmp(label, "C") == 0) + { + display[0] = '\0'; + acc = 0.0; + pending_op = 0; + entering = 0; + dot_entered = 0; + set_display_from_double(0.0); + return; + } + + if (strcmp(label, "<-") == 0) + { + int l = strlen(display); + if (l > 0) + { + if (display[l - 1] == '.') + { + dot_entered = 0; + } + + display[l - 1] = '\0'; + if (strlen(display) == 0) + { + set_display_from_double(0.0); + } + } + + entering = (strlen(display) > 0); + return; + } + + if (strcmp(label, "+/-") == 0) + { + if (display[0] == '-') + { + memmove(display, display + 1, strlen(display)); + } + else + { + if (strlen(display) == 0 || strcmp(display, "0") == 0) + { + return; + } + + snprintf(tmp, sizeof(tmp), "-%s", display); + strncpy(display, tmp, sizeof(display) - 1); + } + + return; + } + + if (strcmp(label, "+") == 0 || strcmp(label, "-") == 0 || strcmp(label, + "*") == 0 || strcmp(label, "/") == 0) + { + val = display_to_double(); + if (pending_op == 0) + { + acc = val; + } + else + { + apply_pending(val); + } + + pending_op = label[0]; + entering = 0; + dot_entered = 0; + set_display_from_double(acc); + return; + } + + if (strcmp(label, "=") == 0) + { + compute_equal(); + return; + } + + if (strcmp(label, ".") == 0) + { + if (!dot_entered) + { + if (!entering) + { + strcpy(display, "0."); + entering = 1; + } + else + { + strncat(display, ".", sizeof(display) - strlen(display) - 1); + } + + dot_entered = 1; + } + + return; + } + + if (strlen(label) == 1 && isdigit((unsigned char)label[0])) + { + if (!entering) + { + display[0] = label[0]; + display[1] = '\0'; + entering = 1; + } + else + { + if (strcmp(display, "0") == 0 && label[0] != '0' && !dot_entered) + { + display[0] = label[0]; + display[1] = '\0'; + } + else if (strlen(display) < sizeof(display) - 2) + { + strncat(display, label, 1); + } + } + + return; + } +} + +static void apply_pending(double val) +{ + if (pending_op == '+') + { + acc = acc + val; + } + else if (pending_op == '-') + { + acc = acc - val; + } + else if (pending_op == '*') + { + acc = acc * val; + } + else if (pending_op == '/') + { + if (val == 0.0) + { + strncpy(display, "Error", sizeof(display) - 1); + display[sizeof(display) - 1] = '\0'; + pending_op = 0; + entering = 0; + dot_entered = 0; + redraw(); + return; + } + else + { + acc = acc / val; + } + } +} + +static void compute_equal(void) +{ + double val = display_to_double(); + + if (pending_op != 0) + { + apply_pending(val); + pending_op = 0; + set_display_from_double(acc); + entering = 0; + dot_entered = 0; + } + else + { + set_display_from_double(val); + } +} diff --git a/examples/nanoxterm/Kconfig b/examples/nanoxterm/Kconfig new file mode 100644 index 00000000000..d608de2c568 --- /dev/null +++ b/examples/nanoxterm/Kconfig @@ -0,0 +1,29 @@ +config EXAMPLES_NANOXTERM + tristate "Nano-X terminal emulator example" + default n + depends on MICROWINDOWS_NANOX && PSEUDOTERM && LIBC_EXECFUNCS + ---help--- + Enable the Nano-X terminal emulator example application. It is + a port of the nxterm demo from Microwindows. It starts the + Nano-X server, connects to it and creates a + terminal window that runs an NSH shell instance on a pseudo + terminal. + +if EXAMPLES_NANOXTERM + +config EXAMPLES_NANOXTERM_PROGNAME + string "Program name" + default "nanoxterm" + ---help--- + This is the name of the program that will be used when the NSH ELF + program is installed. + +config EXAMPLES_NANOXTERM_PRIORITY + int "Nano-X terminal emulator task priority" + default 100 + +config EXAMPLES_NANOXTERM_STACKSIZE + int "Nano-X terminal emulator stack size" + default 16384 + +endif diff --git a/examples/nanoxterm/Make.defs b/examples/nanoxterm/Make.defs new file mode 100644 index 00000000000..41807c0b597 --- /dev/null +++ b/examples/nanoxterm/Make.defs @@ -0,0 +1,25 @@ +############################################################################ +# apps/examples/nanoxterm/Make.defs +# +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. The +# ASF licenses this file to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance with the +# License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +############################################################################ + +ifneq ($(CONFIG_EXAMPLES_NANOXTERM),) +CONFIGURED_APPS += $(APPDIR)/examples/nanoxterm +endif diff --git a/examples/nanoxterm/Makefile b/examples/nanoxterm/Makefile new file mode 100644 index 00000000000..0a10792e9e9 --- /dev/null +++ b/examples/nanoxterm/Makefile @@ -0,0 +1,41 @@ +############################################################################ +# apps/examples/nanoxterm/Makefile +# +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. The +# ASF licenses this file to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance with the +# License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +############################################################################ + +include $(APPDIR)/Make.defs + +PROGNAME = $(CONFIG_EXAMPLES_NANOXTERM_PROGNAME) +PRIORITY = $(CONFIG_EXAMPLES_NANOXTERM_PRIORITY) +STACKSIZE = $(CONFIG_EXAMPLES_NANOXTERM_STACKSIZE) +MODULE = $(CONFIG_EXAMPLES_NANOXTERM) + +# Port of the upstream nxterm demo (src/demos/nanox/nxterm.c). On NuttX +# the pty child runs an NSH instance (nsh_consolemain) instead of exec'ing +# /bin/sh, since flat builds have no filesystem binaries. +MAINSRC = nxterm.c +CFLAGS += -Wno-undef + +ifneq ($(CONFIG_MICROWINDOWS_NANOX_NONETWORK),) +CFLAGS += -DNONETWORK=1 +endif + + +include $(APPDIR)/Application.mk diff --git a/examples/nanoxterm/nxterm.c b/examples/nanoxterm/nxterm.c new file mode 100644 index 00000000000..464150cf62b --- /dev/null +++ b/examples/nanoxterm/nxterm.c @@ -0,0 +1,2595 @@ +/**************************************************************************** + * apps/examples/nanoxterm/nxterm.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * nxterm - terminal emulator for Nano-X + * + * Ported from the Microwindows nxterm demo (src/demos/nanox/nxterm.c): + * + * (C) 1994,95,96 by Torsten Scherer (TeSche) + * itschere@techfak.uni-bielefeld.de + * + * - quite some changes for W1R1 + * - yet more changes for W1R2 + * + * TeSche 01/96: + * - supports W_ICON & W_CLOSE + * - supports /etc/utmp logging for SunOS4 and Linux + * - supports catching of console output for SunOS4 + * Phx 02-06/96: + * - supports NetBSD-Amiga + * Eero 11/97: + * - unsetenv(DISPLAY), setenv(LINES, COLUMNS). + * - Add new text modes (you need to use terminfo...). + * Eero 2/98: + * - Implemented fg/bgcolor setting. With monochrome server it changes + * bgmode variable, which tells in which mode to draw to screen + * (M_CLEAR/M_DRAW) and affects F_REVERSE settings. + * - Added a couple of checks. + * 1/23/10 ghaerr + * - added support for UNIX98 ptys (Linux default) + * - added ngterm terminal type and environment variable + * + * TODO: + * - Allocate and set sensible window palette for fg/bg color setting. + * - add scroll-region ('cs') command. Fairly many programs + * can take advantage of that. + * - Add xterm like mouse event to terminfo key event conversion... :) + * + * Georg 16th Nov 2013: + * - Added ANSI emulation with color support and scrolling region support + * tested the emulation with the Nano editor. + * made ANSI the default, select vt52 with -5 command line switch + * - 8th Dec 2013: improved ANSI emulation and Nano support + * - 15th Dec 2013: added reading program from command line for Linux + * use double quotes when calling from a script e.g.: + * bin/nano-X & bin/nxterm "ls -l *.sh >test.log" & sleep 10000 + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MWINCLUDECOLORS +#include "nano-X.h" +#include "uni_std.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ +#define GR_COLOR_WHITESMOKE MWRGB(245, 245, 245) +#define GR_COLOR_GAINSBORO MWRGB(220, 220, 220) +#define GR_COLOR_ANTIQUEWHITE MWRGB(250, 235, 215) +#define GR_COLOR_BLANCHEDALMOND MWRGB(255, 235, 205) +#define GR_COLOR_LAVENDER MWRGB(230, 230, 250) +#define GR_COLOR_WHITE MWRGB(255, 255, 255) +#define _XOPEN_SOURCE 600 +#define stdcol 80 +#define stdrow 50 +#define KBDBUF 10240 +#define TITLE "nxterm" +#define stdforeground BLACK +#define stdbackground LTGRAY +#define LINEBUF stdcol +#define fonh fi.height +#define fonw fi.maxwidth +#define ANSI 0 +#define VT52 1 +#define _ ((unsigned)0) +#define X ((unsigned)1) +#define MASK7(a, b, c, d, e, f, \ + g) (((((((((((((a * 2) + b) * 2) + c) * 2) + d) * 2) + e) * \ + 2) + f) * 2) + g) << 9) +/* NuttX has no filesystem shell binary, so the pty child runs an NSH + * instance directly instead of exec'ing /bin/sh. + */ + +extern int nsh_consolemain(int argc, char *argv[]); + +/* NuttX fork() does not preserve the child's stack-local variables (the + * child may only exec/_exit per POSIX), so the pty name must live in + * static storage to be readable by the forked child. + */ + +static char ptyname[50]; + +/* globals + */ + +GR_WINDOW_ID w1; +GR_GC_ID gc1; +GR_FONT_ID regFont; + +/* GR_FONT_ID boldFont; */ + +GR_SCREEN_INFO si; +GR_FONT_INFO fi; + +GR_WINDOW_INFO wi; +GR_GC_INFO gi; +GR_BOOL havefocus = GR_FALSE; +pid_t pid; +short winw; +short winh; +int termfd; +int visualbell; +int fgcolor[12] = +{ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11 +}; + +int bgcolor[12] = +{ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11 +}; + +int scrolledFlag; + +int scrolltop; +int scrollbottom; +int ReverseMode = 0; +int semicolonflag = 0; +int nobracket = 0; +int roundbracket = 0; +int savex; +int savey; +char *startprogram; + +/* the terminal code, almost like VT52 */ + +int termtype = ANSI; +int bgmode; +int escstate; +int curx; +int cury; +int curon; +int curvis; +int saved_x; +int saved_y; +int wrap; +int style; +int col; +int row; +int colmask = 0x7f; +int rowmask = 0x7f; +int sbufcnt = 0; +int sbufx; +int sbufy; +char lineBuffer[LINEBUF + 1]; +char *sbuf = lineBuffer; + +int term_init(void); +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +void sflush(void); +void lineRedraw(void); +void sadd(char c); +void show_cursor(void); +void draw_cursor(void); +void hide_cursor(void); +void vscrollup(int lines); +void vscrolldown(int lines); +void esc5(unsigned char c); +void esc4(unsigned char c); +void esc3(unsigned char c); +void esc2(unsigned char c); +void esc1(unsigned char c); +void esc0(unsigned char c); +void esc100(unsigned char c); +void printc(unsigned char c); +void init(void); +void term(void); +void usage(void); +int do_special_key(unsigned char *buffer, int key, int modifiers); +int do_special_key_ansi(unsigned char *buffer, int key, int modifiers); +void pos_xaxis(int c); +void pos_yaxis(int c); +void rendition(int escvalue); + +/* **************************************************************************/ + +void sflush(void) +{ + if (sbufcnt) + { + GrText(w1, gc1, sbufx * fonw, sbufy * fonh, sbuf, sbufcnt, GR_TFTOP); + sbufcnt = 0; + } +} + +void lineRedraw(void) +{ + GrSetGCForeground(gc1, gi.background); + GrFillRect(w1, gc1, curx * fonw, cury * fonh, (col - curx) * fonw, fonh); + GrSetGCForeground(gc1, gi.foreground); + + if (sbufcnt) + { + sbuf[sbufcnt] = 0; + GrText(w1, gc1, sbufx * fonw, sbufy * fonh, sbuf, sbufcnt, GR_TFTOP); + } +} + +void sadd(char c) +{ + if (sbufcnt == LINEBUF) + { + sflush(); + } + + if (!sbufcnt) + { + sbufx = curx; + sbufy = cury; + } + + sbuf[sbufcnt++] = c; +} + +void show_cursor(void) +{ + GrSetGCMode(gc1, GR_MODE_XOR); + GrSetGCForeground(gc1, WHITE); + GrFillRect(w1, gc1, curx * fonw, cury * fonh + 1, fonw, fonh - 1); + GrSetGCForeground(gc1, gi.foreground); + GrSetGCMode(gc1, GR_MODE_COPY); +} + +void draw_cursor(void) +{ + if (curon) + { + if (!curvis) + { + curvis = 1; + show_cursor(); + } + } +} + +void hide_cursor(void) +{ + if (curvis) + { + curvis = 0; + show_cursor(); + } +} + +/* VVV */ + +void vscrollup(int lines) +{ + hide_cursor(); + GrCopyArea(w1, gc1, 0, scrolltop * fonh, winw, + (scrollbottom - (scrolltop - 1) - lines - 1) * fonh, w1, 0, + (scrolltop + lines) * fonh, MWROP_COPY); + GrSetGCForeground(gc1, gi.background); + GrFillRect(w1, gc1, 0, (scrollbottom - lines) * fonh, winw, lines * fonh); + GrSetGCForeground(gc1, gi.foreground); +} + +void vscrolldown(int lines) +{ + hide_cursor(); + + /* FIXME add for loop */ + + GrCopyArea(w1, gc1, 0, (scrolltop + lines) * fonh, winw, + (scrollbottom - scrolltop - lines) * fonh, w1, 0, scrolltop * fonh, + MWROP_COPY); + GrSetGCForeground(gc1, gi.background); + GrFillRect(w1, gc1, 0, scrolltop * fonh, winw, lines * fonh); + GrSetGCForeground(gc1, gi.foreground); +} + +void esc5(unsigned char c) +{ + GrSetGCBackground(gc1, c); + GrGetGCInfo(gc1, &gi); + escstate = 0; +} + +void esc4(unsigned char c) +{ + GrSetGCForeground(gc1, c); + GrGetGCInfo(gc1, &gi); + escstate = 0; +} + +void esc3(unsigned char c) +{ + curx = (c - 32) & colmask; + if (curx >= col) + { + curx = col - 1; + } + else if (curx < 0) + { + curx = 0; + } + + escstate = 0; +} + +void esc2(unsigned char c) +{ + cury = (c - 32) & rowmask; + if (cury >= row) + { + cury = row - 1; + } + else if (cury < 0) + { + cury = 0; + } + + escstate = 3; +} + +void esc1(unsigned char c) +{ + escstate = 0; + + /* detect ANSI / VT100 codes */ + + if (c == '[') + { + escstate = 10; + return; + } + + if (c == '(') + { + escstate = 10; + roundbracket = 1; + return; + } + + if (termtype == ANSI) + { + /* no bracket code - just ESC+letter + * so read no further char just do esc100 and terminate + * ESC state to read new sequence or unescaped chars. + */ + + nobracket = 1; + esc100(c); + escstate = 0; + return; + } + + /* now vt52 codes */ + + switch (c) + { + case 'A': + { + hide_cursor(); + if ((cury -= 1) < 0) + { + cury = 0; + } + break; + } + + case 'B': + { + hide_cursor(); + if ((cury += 1) >= row) + { + cury = row - 1; + } + break; + } + + case 'C': + { + hide_cursor(); + if ((curx += 1) >= col) + { + curx = col - 1; + } + break; + } + + case 'D': + { + hide_cursor(); + if ((curx -= 1) < 0) + { + curx = 0; + } + break; + } + + case 'E': + { + GrClearWindow(w1, 0); + curx = 0; + cury = 0; + break; + } + + case 'H': + { + curx = 0; + cury = 0; + break; + } + + case 'I': + { + scrolledFlag = 1; + if ((cury -= 1) < 0) + { + cury = 0; + vscrollup(1); + } + break; + } + + case 'J': + { + if (cury < row - 1) + { + GrSetGCForeground(gc1, gi.background); + GrFillRect(w1, gc1, 0, (cury + 1) * fonh, winw, + (row - 1 - cury) * fonh); + GrSetGCForeground(gc1, gi.foreground); + } + + GrSetGCForeground(gc1, gi.background); + GrFillRect(w1, gc1, curx * fonw, cury * fonh, (col - curx) * fonw, + fonh); + GrSetGCForeground(gc1, gi.foreground); + break; + } + + case 'K': + { + GrSetGCForeground(gc1, gi.background); + GrFillRect(w1, gc1, curx * fonw, cury * fonh, (col - curx) * fonw, + fonh); + GrSetGCForeground(gc1, gi.foreground); + break; + } + + case 'L': + { + if (cury < row - 1) + { + vscrollup(1); + } + + curx = 0; + break; + } + + case 'M': + { + if (cury < row - 1) + { + vscrollup(1); + } + + curx = 0; + break; + } + + case 'Y': + { + escstate = 2; + break; + } + + case 'b': + { + escstate = 4; + break; + } + + case 'c': + { + escstate = 5; + break; + } + + case 'd': + + { + if (cury > 0) + { + GrSetGCForeground(gc1, gi.background); + GrFillRect(w1, gc1, 0, 0, winw, cury * fonh); + GrSetGCForeground(gc1, gi.foreground); + } + + if (curx > 0) + { + GrSetGCForeground(gc1, gi.background); + GrFillRect(w1, gc1, 0, cury * fonh, curx * fonw, fonh); + GrSetGCForeground(gc1, gi.foreground); + } + break; + } + + case 'e': + { + curon = 1; + break; + } + + case 'f': + { + curon = 0; + break; + } + + case 'j': + { + saved_x = curx; + saved_y = cury; + break; + } + + case 'k': + { + curx = saved_x; + cury = saved_y; + break; + } + + case 'l': + { + GrSetGCForeground(gc1, gi.background); + GrFillRect(w1, gc1, 0, cury * fonh, winw, fonh); + GrSetGCForeground(gc1, gi.foreground); + curx = 0; + break; + } + + case 'o': + { + if (curx > 0) + { + GrSetGCForeground(gc1, gi.background); + GrFillRect(w1, gc1, 0, cury * fonh, curx * fonw, fonh); + GrSetGCForeground(gc1, gi.foreground); + } + break; + } + + case 'p': + { + if (!ReverseMode) + { + GrSetGCForeground(gc1, gi.background); + GrSetGCBackground(gc1, gi.foreground); + ReverseMode = 1; + } + break; + } + + case 'q': + { + if (ReverseMode) + { + GrSetGCForeground(gc1, gi.foreground); + GrSetGCBackground(gc1, gi.background); + ReverseMode = 0; + } + break; + } + + case 'v': + { + wrap = 1; + break; + } + + case 'w': + { + wrap = 0; + break; + } + + /* and these are the extensions not in VT52 */ + + case 'G': + { + break; + } + + case 'g': + + /* GrSetGCFont(gc1, boldFont); */ + + { + break; + } + + case 'h': + + { + break; + } + + case 'i': + { + break; + } + + /* j, k and l are already used */ + + case 'm': + { + break; + } + + /* these ones aren't yet on the termcap entries */ + + case 'n': + { + break; + } + + /* o, p and q are already used */ + + case 'r': + { + break; + } + + case 's': + { + break; + } + + case 't': + { + break; + } + + default: + { + break; + } + } +} + +void pos_xaxis(int c) +{ + curx = c & colmask; + if (curx >= col) + { + curx = col - 1; + } + else if (curx < 0) + { + curx = 0; + } +} + +void pos_yaxis(int c) +{ + cury = c & rowmask; + + if (cury >= scrollbottom) + { + cury = scrollbottom - 1; + } + else if (cury < scrolltop) + { + cury = scrolltop - 1; + } +} + +void rendition(int escvalue) +{ + if (escvalue == 0) + { + GrSetGCForeground(gc1, stdforeground); + GrSetGCBackground(gc1, stdbackground); + ReverseMode = 0; + } + else if (escvalue == 7) + { + if (!ReverseMode) + { + GrSetGCForeground(gc1, gi.background); + GrSetGCBackground(gc1, gi.foreground); + ReverseMode = 1; + } + } + else if (escvalue == 27) + { + if (ReverseMode) + { + GrSetGCForeground(gc1, gi.foreground); + GrSetGCBackground(gc1, gi.background); + ReverseMode = 0; + } + } + else if ((escvalue > 29) && (escvalue < 38)) + { + switch (escvalue) + { + case 30: + { + GrSetGCForeground(gc1, BLACK); + break; + } + + case 31: + { + GrSetGCForeground(gc1, RED); + break; + } + + case 32: + { + GrSetGCForeground(gc1, GREEN); + break; + } + + case 33: + { + GrSetGCForeground(gc1, BROWN); + break; + } + + case 34: + { + GrSetGCForeground(gc1, BLUE); + break; + } + + case 35: + { + GrSetGCForeground(gc1, MAGENTA); + break; + } + + case 36: + { + GrSetGCForeground(gc1, CYAN); + break; + } + + case 37: + { + GrSetGCForeground(gc1, WHITE); + break; + } + + case 39: + { + GrSetGCForeground(gc1, stdforeground); + break; + } + } + } + else if ((escvalue > 39) && (escvalue < 49)) + { + switch (escvalue) + { + case 40: + { + GrSetGCBackground(gc1, BLACK); + break; + } + + case 41: + { + GrSetGCBackground(gc1, RED); + break; + } + + case 42: + { + GrSetGCBackground(gc1, GREEN); + break; + } + + case 43: + { + GrSetGCBackground(gc1, BROWN); + break; + } + + case 44: + { + GrSetGCBackground(gc1, BLUE); + break; + } + + case 45: + { + GrSetGCBackground(gc1, MAGENTA); + break; + } + + case 46: + { + GrSetGCBackground(gc1, CYAN); + break; + } + + case 47: + { + GrSetGCBackground(gc1, WHITE); + break; + } + + case 49: + { + GrSetGCBackground(gc1, stdbackground); + break; + } + } + } +} + +void esc100(unsigned char c) +{ + int y; + int yy; + char buf[32]; + + /* leave escstate=10 till done. This states gets this function called. */ + + static int escvalue1; + static int escvalue2; + static int escvalue3; + static char valuebuffer[3]; + + valuebuffer[2] = '\0'; + + if (c == '?') + { + return; + } + + if (nobracket == 1) + { + /* fall through */ + } + else if (roundbracket == 1) + + /* fall through */ + + { + } + else if ((c > 0x2F) && (c < ':')) + { + if (valuebuffer[0] != '\0') + { + valuebuffer[1] = c; + } + else + { + valuebuffer[0] = c; + } + + return; + } + else if (c == ';') + { + if (semicolonflag == 0) + { + escvalue1 = atoi(valuebuffer); + semicolonflag++; + valuebuffer[0] = '\0'; + valuebuffer[1] = '\0'; + return; + } + else if (semicolonflag == 1) + { + escvalue2 = atoi(valuebuffer); + semicolonflag++; + valuebuffer[0] = '\0'; + valuebuffer[1] = '\0'; + return; + } + } + else if (((c > '@') && (c < '[')) || ((c > 0x60) && (c < '{'))) /* is it a + * letter? */ + { + if (semicolonflag == 0) + { + escvalue1 = atoi(valuebuffer); + escvalue2 = 0; + escvalue3 = 0; + } + else if (semicolonflag == 1) + { + escvalue2 = atoi(valuebuffer); + escvalue3 = 0; + } + else if (semicolonflag == 2) + { + escvalue3 = atoi(valuebuffer); + } + + escstate = 0; + valuebuffer[0] = '\0'; + valuebuffer[1] = '\0'; + } + else + { + return; + } + + /* fall through now if letter received */ + + /* now interpret the ESC sequence */ + +/* the cursor positions: cury,curx are zero based, so 0,0 is home position + * also if command asks to position to 5 this has to be 4 + * y is the row/line position, x is the column position + * fonh = fi.height = height of character or line in pixel + * fonw = fi.maxwidth = width of character in pixel + * winw = width of line in pixel + * winh = height of screen in pixel + * col = number of columns for current screen width + * row = number of lines for current screen height + * scrolltop, scrollbottom = upper and lower scroll region limit in + * lines/rows + */ + + if (nobracket == 1) + { + if (c == '8') + + /* HOME will reduce by one below, so add here! */ + + { + escvalue1 = savey + 1; + escvalue2 = savex + 1; + c = 'H'; + } + else if (c == '7') + { + savex = curx; + savey = cury; + c = '!'; + } + else if (c == 'M') /* reverse index, same as cursor up but scroll + * display at top */ + { + if (cury <= scrolltop) + { + escvalue1 = 1; + c = 'L'; + } + else + { + cury--; + pos_yaxis(cury); + c = '!'; + } + } + else if (c == 'D') /* index, same as cursor down but scroll display at + * bottom */ + { + if ((cury + 1) > scrollbottom) + { + escvalue1 = 1; + c = 'M'; + } + else + { + cury++; + pos_yaxis(cury); + c = '!'; + } + } + } + + nobracket = 0; + + if (roundbracket == 1) + { + c = 0; + roundbracket = 0; + } + + switch (c) + { + case 'A': + { + if (escvalue1 == 0) + { + escvalue1 = 1; + } + + hide_cursor(); + if ((cury -= escvalue1) < 0) + { + /* cury = 0; */ + + cury = scrolltop - 1; + } + break; + } + + case 'B': + { + if (escvalue1 == 0) + { + escvalue1 = 1; + } + + hide_cursor(); + if ((cury += escvalue1) >= row) + { + /* cury = row - 1; */ + + cury = scrollbottom - 1; + } + break; + } + + case 'C': + { + if (escvalue1 == 0) + { + escvalue1 = 1; + } + + hide_cursor(); + if ((curx += escvalue1) >= col) + { + curx = col - 1; + } + break; + } + + case 'D': + { + if (escvalue1 == 0) + { + escvalue1 = 1; + } + + hide_cursor(); + if ((curx -= escvalue1) < 0) + { + curx = 0; + } + break; + } + + case 'J': + { + if (escvalue1 == 0) /* erase from current cursor to end + * of page/scrollbottom */ + { + if (cury < scrollbottom - 1) + { + GrSetGCForeground(gc1, gi.background); + GrFillRect(w1, gc1, 0, (cury + 1) * fonh, winw, + (scrollbottom - 1 - cury) * fonh); + GrSetGCForeground(gc1, gi.foreground); + } + + GrSetGCForeground(gc1, gi.background); + GrFillRect(w1, gc1, curx * fonw, cury * fonh, + (col - curx) * fonw, fonh); + GrSetGCForeground(gc1, gi.foreground); + break; + } + else if (escvalue1 == 1) /* erase from home/scrolltop to + * cursor */ + { + if (cury < scrollbottom - 1) /* erase area from top to line + * above current line */ + { + GrSetGCForeground(gc1, gi.background); + GrFillRect(w1, gc1, 0, scrolltop, winw, (cury + 1) * fonh); + GrSetGCForeground(gc1, gi.foreground); + } + + GrSetGCForeground(gc1, gi.background); + GrFillRect(w1, gc1, 0, cury * fonh, curx * fonw, fonh); + GrSetGCForeground(gc1, gi.foreground); + break; + } + else if (escvalue1 == 2) /* erase entire page - leave cursor + * untouched */ + + /* GrClearWindow(w1, 0); + * erase just the scrolling area + */ + + { + GrSetGCForeground(gc1, gi.background); + GrFillRect(w1, gc1, 0, scrolltop, winw, (scrollbottom) * fonh); + GrSetGCForeground(gc1, gi.foreground); + break; + } + } + + case 'K': + { + if (escvalue1 == 0) + { + GrSetGCForeground(gc1, gi.background); + GrFillRect(w1, gc1, curx * fonw, cury * fonh, + (col - curx) * fonw, fonh); + GrSetGCForeground(gc1, gi.foreground); + break; + } + else if (escvalue1 == 1) + { + GrSetGCForeground(gc1, gi.background); + GrFillRect(w1, gc1, 0, cury * fonh, curx * fonw, fonh); + GrSetGCForeground(gc1, gi.foreground); + break; + } + else if (escvalue1 == 2) /* erase entire line - leave cursor + * untouched */ + { + GrSetGCForeground(gc1, gi.background); + GrFillRect(w1, gc1, 0, cury * fonh, winw, fonh); + GrSetGCForeground(gc1, gi.foreground); + break; + } + } + + case 'P':/* erase number of characters after and including the cursor + * and move remaining to this position */ + { + if (escvalue1 == 0) + { + escvalue1 = 1; + } + + GrSetGCForeground(gc1, gi.background); + + /* copy remaining chars on line to cursor position */ + + GrCopyArea(w1, gc1, curx * fonw, cury * fonh, + (col - curx - escvalue1) * fonw, fonh, w1, + (curx + escvalue1) * fonw, cury * fonh, MWROP_COPY); + + /* clear space at end of line */ + + GrFillRect(w1, gc1, (col - escvalue1) * fonw, cury * fonh, + (escvalue1) * fonw, fonh); + GrSetGCForeground(gc1, gi.foreground); + break; + } + + case 'L': + { + if (escvalue1 == 0) + { + escvalue1 = 1; + } + + y = cury; + yy = stdrow - 1; + + /* XXX */ + + hide_cursor(); + + /* copy from cursor the number of lines down */ + + while (--yy >= y) + { + GrCopyArea(w1, gc1, 0, (yy + escvalue1) * fonh, winw - 0, fonh, + w1, 0, yy * fonh, MWROP_COPY); + } + + /* clear number of lines starting at cursor position */ + + GrSetGCForeground(gc1, gi.background); + GrFillRect(w1, gc1, 0, cury * fonh, winw, escvalue1 * fonh); + GrSetGCForeground(gc1, gi.foreground); + break; + } + + case 'M': + + { + if (escvalue1 == 0) + { + escvalue1 = 1; + } + + GrCopyArea(w1, gc1, 0, cury * fonh, winw, + (scrollbottom - cury - escvalue1) * fonh, w1, 0, + (cury + escvalue1) * fonh, MWROP_COPY); + + /* clear number of lines starting from scrollbottom up */ + + GrSetGCForeground(gc1, gi.background); + GrFillRect(w1, gc1, 0, (scrollbottom - escvalue1) * fonh, winw, + escvalue1 * fonh); + GrSetGCForeground(gc1, gi.foreground); + break; + } + + case 'S': + { + if (escvalue1 == 0) + { + escvalue1 = 1; + } + + vscrollup(escvalue1); + break; + } + + case 'T': + { + if (escvalue1 == 0) + { + escvalue1 = 1; + } + + vscrolldown(escvalue1); + break; + } + + case 'H': + case 'f': + { + if (escvalue1 > 0) + { + escvalue1--; + } + + if (escvalue2 > 0) + { + escvalue2--; + } + + pos_yaxis(escvalue1); + pos_xaxis(escvalue2); + break; + } + + case 'E': + { + if (escvalue1 == 0) + { + escvalue1 = 1; + } + + hide_cursor(); + if ((cury += escvalue1) >= scrollbottom) + { + cury = scrollbottom - 1; + } + + curx = 0; + break; + } + + case 'F': + { + if (escvalue1 == 0) + { + escvalue1 = 1; + } + + hide_cursor(); + if ((cury -= escvalue1) < 0) + { + cury = 0; + } + + curx = 0; + break; + } + + case 'd': + { + if (escvalue1 > 0) + { + escvalue1--; + } + + pos_yaxis(escvalue1); + break; + } + + case '`': + case 'G': + { + if (escvalue1 > 0) + { + escvalue1--; + } + + pos_xaxis(escvalue1); + break; + } + + case 'e': + { + if (escvalue1 > 0) + { + escvalue1--; + } + + pos_yaxis(escvalue1 + cury); + break; + } + + case 'a': + { + if (escvalue1 > 0) + { + escvalue1--; + } + + pos_xaxis(escvalue1 + curx); + break; + } + + case 'm': + + /* may be more values, do just up to three here + * foreground colors run from 30 to 37, background from 40 to 47 + */ + + { + rendition(escvalue1); + if (escvalue2 != 0) + { + rendition(escvalue2); + } + + if (escvalue3 != 0) + { + rendition(escvalue3); + } + + escvalue1 = 0; + escvalue2 = 0; + escvalue3 = 0; + GrGetGCInfo(gc1, &gi); + break; + } + + case 's': + { + saved_x = curx; + saved_y = cury; + break; + } + + case 'u': + { + curx = saved_x; + cury = saved_y; + break; + } + + case 'r': + { + if ((escvalue1 > -1) && (escvalue2 <= (winh - 1))) + { + scrolltop = escvalue1; + scrollbottom = escvalue2; + } + break; + } + + case 'h': + { + if (escvalue1 == 7) + { + wrap = 1; + } + + if (escvalue1 == 25) + { + show_cursor(); + } + break; + } + + case 'l': + { + if (escvalue1 == 7) + { + wrap = 0; + } + + if (escvalue1 == 25) + { + hide_cursor(); + } + break; + } + + case 'n': + { + sprintf(buf, "\033[%d;%dR", cury + 1, curx + 1); + write(termfd, buf, strlen(buf)); + break; + } + + default: + { + break; + } + } +} + +/* un-escaped character print routine + */ + +void esc0(unsigned char c) +{ + switch (c) + { + case 0: + { + /* printing \000 on a terminal means "do nothing". + * But since we use \000 as string terminator none + * of the characters that follow were printed. + * + * perl -e 'printf("a%ca", 0);' + * + * said 'a' in a wterm, but should say 'aa'. This + * bug screwed up most ncurses programs. + */ + + break; + } + + case 7: + { + if (visualbell) + { + /* w_setmode(win, M_INVERS); + * w_pbox(win, 0, 0, winw, winh); + * w_test(win, 0, 0); + * w_pbox(win, 0, 0, winw, winh); + */ + } + else + { + GrBell(); + } + break; + } + + case 8: + { + hide_cursor(); + if ((curx -= 1) < 0) + { + curx = 0; + } + + pos_xaxis(curx); + break; + } + + case 9: + { + int borg; + int i; + + borg = (((curx >> 3) + 1) << 3); + if (borg >= col) + { + borg = col - 1; + } + + borg = borg - curx; + for (i = 0; i < borg; ++i) + { + sadd(' '); + } + + if ((curx = ((curx >> 3) + 1) << 3) >= col) + { + curx = col - 1; + } + + pos_xaxis(curx); + } + break; + + case 10: + { + sflush(); + if (++cury >= scrollbottom) + { + /* scroll before moving cursor, then reduce and add again */ + + cury--; + vscrollup(1); + cury++; + + /* set cursor into lowest line (cury zero based so -1) */ + + cury = scrollbottom - 1; + + /* cury = row-1; */ + } + + pos_yaxis(cury); + break; + } + + case 13: + { + sflush(); + curx = 0; + pos_xaxis(curx); + break; + } + + case 27: + { + sflush(); + semicolonflag = 0; + escstate = 1; + break; + } + + case 127: + { + break; + } + + default: + { + sadd(c); + if (++curx >= col) + { + sflush(); + if (!wrap) + { + curx = col - 1; + } + else + { + curx = 0; + if (++cury >= scrollbottom) + { + vscrollup(1); + } + } + } + break; + } + } +} + +void printc(unsigned char c) +{ + switch (escstate) + { + case 0: + { + esc0(c); + break; + } + + case 1: + { + sflush(); + esc1(c); + break; + } + + case 2: + { + sflush(); + esc2(c); + break; + } + + case 3: + { + sflush(); + esc3(c); + break; + } + + case 4: + { + sflush(); + esc4(c); + break; + } + + case 5: + { + sflush(); + esc5(c); + break; + } + + case 10: + { + sflush(); + esc100(c); + break; + } + + default: + { + escstate = 0; + break; + } + } +} + +void init(void) +{ + curx = saved_x = 0; + cury = saved_y = 0; + wrap = 1; + curon = 1; + curvis = 0; + escstate = 0; +} + +/* general code... + */ + +void term(void) +{ + long in; + long l; + GR_EVENT_KEYSTROKE *kp; + int bufflen; + int gotexpose = 0; + GR_EVENT wevent; + unsigned char buf[KBDBUF]; + + if (startprogram) + { + usleep(1000); + write(termfd, startprogram, strlen(startprogram)); + write(termfd, "\r", 1); + } + + while (42) + { + if (havefocus) + { + draw_cursor(); + } + + GrGetNextEvent(&wevent); + + switch (wevent.type) + { + case GR_EVENT_TYPE_CLOSE_REQ: + { + GrClose(); + exit(0); + break; + } + + case GR_EVENT_TYPE_KEY_DOWN: + { + /* deal with special keys */ + + kp = (GR_EVENT_KEYSTROKE *)&wevent; + if (kp->ch & MWKEY_NONASCII_MASK) + { + if (termtype == ANSI) + { + bufflen = do_special_key_ansi(buf, kp->ch, + kp->modifiers); + } + else + { + bufflen = do_special_key(buf, kp->ch, kp->modifiers); + } + } + else + { + *buf = kp->ch & 0xff; + bufflen = 1; + } + + if (bufflen > 0) + { + write(termfd, buf, bufflen); + } + break; + } + + case GR_EVENT_TYPE_FOCUS_IN: + { + havefocus = GR_TRUE; + break; + } + + case GR_EVENT_TYPE_FOCUS_OUT: + { + havefocus = GR_FALSE; + hide_cursor(); + break; + } + + case GR_EVENT_TYPE_UPDATE: + { + /* if we get temporarily unmapped (moved), + * set cursor state off. + */ + + if (wevent.update.utype == GR_UPDATE_UNMAPTEMP) + { + hide_cursor(); + } + break; + } + + case GR_EVENT_TYPE_EXPOSURE: + { + if (!gotexpose) + { + GrRegisterInput(termfd); + gotexpose = GR_TRUE; + } + break; + } + + case GR_EVENT_TYPE_FDINPUT: + { + if (!gotexpose) + { + break; + } + + hide_cursor(); + if ((in = read(termfd, buf, sizeof(buf))) > 0) + { + for (l = 0; l < in; l++) + { + printc(buf[l]); + } + + sflush(); + } + break; + } + + case GR_EVENT_TYPE_NONE: + case GR_EVENT_TYPE_TIMEOUT: + { + break; + } + + default: + { + hide_cursor(); + break; + } + } + } +} + +int do_special_key(unsigned char *buffer, int key, int modifier) +{ + /* handle vt52 keys here */ + + int len; + char *str; + char locbuff[32]; + + switch (key) + { + case MWKEY_LEFT: + { + str = "\033D"; + len = 2; + break; + } + + case MWKEY_RIGHT: + { + str = "\033C"; + len = 2; + break; + } + + case MWKEY_UP: + { + if (scrolledFlag) + { + str = ""; + len = 0; + scrolledFlag = 0; + } + else + { + str = "\033A"; + len = 2; + } + break; + } + + case MWKEY_DOWN: + { + str = "\033B"; + len = 2; + break; + } + + case MWKEY_KP0: + { + str = "\033\077\160"; + len = 3; + break; + } + + case MWKEY_KP1: + { + str = "\033\077\161"; + len = 3; + break; + } + + case MWKEY_KP2: + { + str = "\033\077\162"; + len = 3; + break; + } + + case MWKEY_KP3: + { + str = "\033\077\163"; + len = 3; + break; + } + + case MWKEY_KP4: + { + str = "\033\077\164"; + len = 3; + break; + } + + case MWKEY_KP5: + { + str = "\033\077\165"; + len = 3; + break; + } + + case MWKEY_KP6: + { + str = "\033\077\166"; + len = 3; + break; + } + + case MWKEY_KP7: + { + str = "\033\077\167"; + len = 3; + break; + } + + case MWKEY_KP8: + { + str = "\033\077\170"; + len = 3; + break; + } + + case MWKEY_KP9: + { + str = "\033\077\161"; + len = 3; + break; + } + + case MWKEY_KP_PERIOD: + { + str = "\033\077\156"; + len = 3; + break; + } + + case MWKEY_KP_ENTER: + { + str = "\033\077\115"; + len = 3; + break; + } + + case MWKEY_DELETE: + { + str = "\033C\177"; + len = 3; + break; + } + + case MWKEY_F1 ... MWKEY_F12: + { + if (modifier & MWKMOD_LMETA) + { + locbuff[0] = 033; + locbuff[1] = 'c'; + locbuff[2] = (char)bgcolor[key - MWKEY_F1]; + locbuff[3] = '\0'; + str = locbuff; + len = 3; + } + else if (modifier & MWKMOD_RMETA) + { + locbuff[0] = 033; + locbuff[1] = 'b'; + locbuff[2] = (char)fgcolor[key - MWKEY_F1]; + locbuff[3] = '\0'; + str = locbuff; + len = 3; + } + else + { + switch (key) + { + case MWKEY_F1: + { + str = "\033Y"; + len = 2; + break; + } + + case MWKEY_F2: + { + str = "\033P"; + len = 2; + break; + } + + case MWKEY_F3: + { + str = "\033Q"; + len = 2; + break; + } + + case MWKEY_F4: + { + str = "\033R"; + len = 2; + break; + } + + case MWKEY_F5: + { + str = "\033S"; + len = 2; + break; + } + + case MWKEY_F6: + { + str = "\033T"; + len = 2; + break; + } + + case MWKEY_F7: + { + str = "\033U"; + len = 2; + break; + } + + case MWKEY_F8: + { + str = "\033V"; + len = 2; + break; + } + + case MWKEY_F9: + { + str = "\033W"; + len = 2; + break; + } + + case MWKEY_F10: + { + str = "\033X"; + len = 2; + break; + } + } + } + } + + default: + { + len = 0; + } + } + + buffer[0] = '\0'; + if (len > 0) + { + strcpy((char *)buffer, str); + } + + return len; +} + +int do_special_key_ansi(unsigned char *buffer, int key, int modifier) +{ + int len; + char *str; + char locbuff[32]; + + switch (key) + { + case MWKEY_LEFT: + { + str = "\033[D"; + len = 3; + break; + } + + case MWKEY_RIGHT: + { + str = "\033[C"; + len = 3; + break; + } + + case MWKEY_UP: + { + if (scrolledFlag) + { + str = ""; + len = 0; + scrolledFlag = 0; + } + else + { + str = "\033[A"; + len = 3; + } + break; + } + + case MWKEY_DOWN: + { + str = "\033[B"; + len = 3; + break; + } + + case MWKEY_HOME: + { + str = "\033[H"; + len = 3; + break; + } + + case MWKEY_INSERT: + { + str = "\033[2~"; + len = 4; + break; + } + + case MWKEY_KP0: + { + str = "\033Op"; + len = 3; + break; + } + + case MWKEY_END: + { + str = "\033[F"; + len = 3; + break; + } + + case MWKEY_KP1: + { + str = "\033Oq"; + len = 3; + break; + } + + case MWKEY_KP2: + { + str = "\033Or"; + len = 3; + break; + } + + case MWKEY_PAGEDOWN: + { + str = "\033[6~"; + len = 4; + break; + } + + case MWKEY_KP3: + { + str = "\033Os"; + len = 3; + break; + } + + case MWKEY_KP4: + { + str = "\033Ot"; + len = 3; + break; + } + + case MWKEY_KP5: + { + str = "\033Ou"; + len = 3; + break; + } + + case MWKEY_KP6: + { + str = "\033Ov"; + len = 3; + break; + } + + case MWKEY_KP7: + { + str = "\033Ow"; + len = 3; + break; + } + + case MWKEY_KP8: + { + str = "\033Ox"; + len = 3; + break; + } + + case MWKEY_PAGEUP: + { + str = "\033[5~"; + len = 4; + break; + } + + case MWKEY_KP9: + { + str = "\033Oy"; + len = 3; + break; + } + +/* case MWKEY_KP_PERIOD: + * str="\033On"; + * len=3; + * break; + */ + + case MWKEY_KP_ENTER: + { + str = "\033OM"; + len = 3; + break; + } + + case MWKEY_KP_PERIOD: + case MWKEY_DELETE: + { + str = "\033[3~"; + len = 4; + break; + } + + case MWKEY_F1 ... MWKEY_F12: + { + if (modifier & MWKMOD_LMETA) + { + /* we set background color */ + + locbuff[0] = 033; + locbuff[1] = 'c'; + locbuff[2] = (char)bgcolor[key - MWKEY_F1]; + locbuff[3] = '\0'; + str = locbuff; + len = 3; + } + else if (modifier & MWKMOD_RMETA) + { + /* we set foreground color */ + + locbuff[0] = 033; + locbuff[1] = 'b'; + locbuff[2] = (char)fgcolor[key - MWKEY_F1]; + locbuff[3] = '\0'; + str = locbuff; + len = 3; + } + else + { + switch (key) + { + case MWKEY_F1: + { + str = "\033OP"; + len = 3; + break; + } + + case MWKEY_F2: + { + str = "\033OQ"; + len = 3; + break; + } + + case MWKEY_F3: + { + str = "\033OR"; + len = 3; + break; + } + + case MWKEY_F4: + { + str = "\033OS"; + len = 3; + break; + } + + case MWKEY_F5: + { + str = "\033[15~"; + len = 5; + break; + } + + case MWKEY_F6: + { + str = "\033[17~"; + len = 5; + break; + } + + case MWKEY_F7: + { + str = "\033[18~"; + len = 5; + break; + } + + case MWKEY_F8: + { + str = "\033[19~"; + len = 5; + break; + } + + case MWKEY_F9: + { + str = "\033[20~"; + len = 5; + break; + } + + case MWKEY_F10: + { + str = "\033[21~"; + len = 5; + break; + } + + case MWKEY_F11: + { + str = "\033[22~"; + len = 5; + break; + } + + case MWKEY_F12: + { + str = "\033[23~"; + len = 5; + break; + } + } + } + } + + /* fall thru */ + + default: + { + len = 0; + } + } + + buffer[0] = '\0'; + if (len > 0) + { + strcpy((char *)buffer, str); + } + + return len; +} + +void usage(void) +{ + GrError("usage: nxterm [-v5] [command]]\n"); + exit(1); +} + +static void *mysignal(int signum, void *handler) +{ + struct sigaction sa; + struct sigaction so; + + sa.sa_handler = handler; + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_RESTART; + sigaction(signum, &sa, &so); + + return so.sa_handler; +} + +static void sigpipe(int sig) +{ + GrClose(); + kill(-pid, SIGHUP); + _exit(sig); +} + +static void sigchild(int sig) +{ + GrClose(); + _exit(sig); +} + +static void sigquit(int sig) +{ + signal(sig, SIG_IGN); + GrClose(); + kill(-pid, SIGHUP); +} + +#ifndef NONETWORK +extern int nanox_server_main(int argc, char *argv[]); +#endif + +int main(int argc, char **argv) +{ + GR_CURSOR_ID c1; + GR_BITMAP bitmap1fg[7]; + GR_BITMAP bitmap1bg[7]; + +#ifndef NONETWORK + /* Start the Nano-X server as a separate task; GrOpen() below retries + * the connection while the server comes up. + */ + + task_create("nanoxserver", 100, 65536, nanox_server_main, NULL); +#endif + + argv++; + while (*argv && **argv == '-') + { + switch (*(*argv + 1)) + { + case '5': + { + termtype = VT52; + argv++; + break; + } + + case 'v': + { + visualbell = 1; + argv++; + break; + } + + default: + { + usage(); + } + } + } + + /* now *argv either points to a program to start or is zero + */ + + if (*argv) + { + startprogram = *argv++; + } + + if (GrOpen() < 0) + { + GrError("cannot open graphics\n"); + exit(1); + } + + GrGetScreenInfo(&si); + + col = stdcol; + row = stdrow; + scrolltop = 0; + scrollbottom = row; + + regFont = GrCreateFontEx(GR_FONT_SYSTEM_FIXED, 0, 0, NULL); + /* regFont = GrCreateFontEx(GR_FONT_OEM_FIXED, 0, 0, NULL); + *boldFont = GrCreateFontEx(GR_FONT_SYSTEM_FIXED, 0, 0, NULL); + */ + + GrGetFontInfo(regFont, &fi); + winw = col * fi.maxwidth; + winh = row * fi.height; + w1 = GrNewWindowEx(GR_WM_PROPS_APPWINDOW, TITLE, GR_ROOT_WINDOW_ID, -1, -1, + winw, winh, stdbackground); + + GrSelectEvents(w1, + GR_EVENT_MASK_BUTTON_DOWN | GR_EVENT_MASK_EXPOSURE | + GR_EVENT_MASK_KEY_DOWN | GR_EVENT_MASK_FOCUS_IN | + GR_EVENT_MASK_FOCUS_OUT | GR_EVENT_MASK_UPDATE | + GR_EVENT_MASK_CLOSE_REQ); + GrMapWindow(w1); + + gc1 = GrNewGC(); + GrSetGCFont(gc1, regFont); + + bitmap1fg[0] = MASK7(_, _, X, _, X, _, _); + bitmap1fg[1] = MASK7(_, _, _, X, _, _, _); + bitmap1fg[2] = MASK7(_, _, _, X, _, _, _); + bitmap1fg[3] = MASK7(_, _, _, X, _, _, _); + bitmap1fg[4] = MASK7(_, _, _, X, _, _, _); + bitmap1fg[5] = MASK7(_, _, _, X, _, _, _); + bitmap1fg[6] = MASK7(_, _, X, _, X, _, _); + + bitmap1bg[0] = MASK7(_, X, X, X, X, X, _); + bitmap1bg[1] = MASK7(_, _, X, X, X, _, _); + bitmap1bg[2] = MASK7(_, _, X, X, X, _, _); + bitmap1bg[3] = MASK7(_, _, X, X, X, _, _); + bitmap1bg[4] = MASK7(_, _, X, X, X, _, _); + bitmap1bg[5] = MASK7(_, _, X, X, X, _, _); + bitmap1bg[6] = MASK7(_, X, X, X, X, X, _); + + c1 = GrNewCursor(7, 7, 3, 3, stdforeground, stdbackground, bitmap1fg, + bitmap1bg); + GrSetWindowCursor(w1, c1); + GrSetGCForeground(gc1, stdforeground); + GrSetGCBackground(gc1, stdbackground); + GrGetWindowInfo(w1, &wi); + GrGetGCInfo(gc1, &gi); + + /* create pty, SIGCHLD handler set afterwards in case of grantpt() called */ + + termfd = term_init(); + if (termfd < 0) + { + GrClose(); + exit(1); + } + + mysignal(SIGTERM, sigquit); + mysignal(SIGHUP, sigquit); + mysignal(SIGQUIT, sigquit); + mysignal(SIGPIPE, sigpipe); + mysignal(SIGCHLD, sigchild); + mysignal(SIGINT, SIG_IGN); + + /* just in case we're started in the background */ + + signal(SIGTTOU, SIG_IGN); + + init(); + term(); + return 0; +} + +int term_init(void) +{ + int tfd; + int ptfd; + pid_t child; + int status; + posix_spawnattr_t attr; + posix_spawn_file_actions_t file_actions; + char *const argv[] = + { + CONFIG_SYSTEM_NSH_PROGNAME, NULL + }; + + tfd = posix_openpt(O_RDWR | O_NOCTTY | O_NONBLOCK); + if (tfd < 0) + { + GrError("Can't create pty /dev/ptmx\n"); + return -1; + } + + strcpy(ptyname, ptsname(tfd)); + + signal(SIGCHLD, SIG_DFL); + grantpt(tfd); + unlockpt(tfd); + + if ((ptfd = open(ptyname, O_RDWR)) < 0) + { + GrError("Can't open %s\n", ptyname); + return -1; + } + + posix_spawnattr_init(&attr); + posix_spawnattr_setstacksize(&attr, CONFIG_SYSTEM_NSH_STACKSIZE); + + posix_spawn_file_actions_init(&file_actions); + posix_spawn_file_actions_addclose(&file_actions, STDIN_FILENO); + posix_spawn_file_actions_addclose(&file_actions, STDOUT_FILENO); + posix_spawn_file_actions_addclose(&file_actions, STDERR_FILENO); + posix_spawn_file_actions_adddup2(&file_actions, ptfd, STDIN_FILENO); + posix_spawn_file_actions_adddup2(&file_actions, ptfd, STDOUT_FILENO); + posix_spawn_file_actions_adddup2(&file_actions, ptfd, STDERR_FILENO); + posix_spawn_file_actions_addclose(&file_actions, ptfd); + + status = posix_spawn(&child, CONFIG_SYSTEM_NSH_PROGNAME, &file_actions, + &attr, argv, environ); + + posix_spawn_file_actions_destroy(&file_actions); + close(ptfd); + + if (status != 0) + { + GrError("Error: posix_spawn returned %d\n", status); + return -1; + } + + return tfd; +} diff --git a/graphics/microwindows/Kconfig b/graphics/microwindows/Kconfig index 9d5f0cb8c43..ff0a954e2f1 100644 --- a/graphics/microwindows/Kconfig +++ b/graphics/microwindows/Kconfig @@ -128,4 +128,34 @@ config MICROWINDOWS_MWIN a high-level windowing API similar to the Microsoft Windows API with window management, controls, and standard dialogs. +config MICROWINDOWS_NANOX + bool "Nano-X (X11 API) client/server support" + default n + depends on MICROWINDOWS_NANOX_NONETWORK || (NET_LOCAL && NET_LOCAL_STREAM) + ---help--- + Build the Nano-X server core and the Nano-X client library. + The Nano-X server runs as a separate task and provides the + X11-like API (GrXXX calls) to client applications which + connect to it through a local stream socket. Alternatively, + with MICROWINDOWS_NANOX_NONETWORK, the client applications + are linked directly with the server and run in the same task. + +config MICROWINDOWS_NANOX_NONETWORK + bool "Link Nano-X applications directly with the server" + default n + ---help--- + Build the Nano-X client library and server in the linked-in + (NONETWORK) mode: client applications are linked directly + with the server, so no network stack or socket is required + and the memory footprint is minimal. Only a single client + application can be active at a time. + +config MICROWINDOWS_NANOX_NANOWM + bool "Built-in Nano-X window manager" + default n + depends on MICROWINDOWS_NANOX + ---help--- + Link the built-in window manager (wm*.c, nxdraw.c) into the + Nano-X server, providing window decorations (title bar, 3D + frame), cascaded placement, move/resize and focus handling. endif # GRAPHICS_MICROWINDOWS diff --git a/graphics/microwindows/Make.defs b/graphics/microwindows/Make.defs index 935abf66b6e..db124fcfaa9 100644 --- a/graphics/microwindows/Make.defs +++ b/graphics/microwindows/Make.defs @@ -25,8 +25,7 @@ CONFIGURED_APPS += $(APPDIR)/graphics/microwindows # It allows `microwindows/src/include` import. -CFLAGS += ${INCDIR_PREFIX}$(APPDIR)/graphics/microwindows/microwindows/src/include -CXXFLAGS += ${INCDIR_PREFIX}$(APPDIR)/graphics/microwindows/microwindows/src/include +EXPORTED_INCLUDES += ${INCDIR_PREFIX}$(APPDIR)/graphics/microwindows/microwindows/src/include CFLAGS += -DMWCONFIG_FILE='"mwconfig.nuttx"' diff --git a/graphics/microwindows/Makefile b/graphics/microwindows/Makefile index 2ea7e4c1a8f..7d2553dcb90 100644 --- a/graphics/microwindows/Makefile +++ b/graphics/microwindows/Makefile @@ -153,4 +153,72 @@ CFLAGS += -DNOGDI endif +ifneq ($(CONFIG_MICROWINDOWS_NANOX),) + +MW_NANOX_DRAW_SRCS = microwindows/src/nanox/nxdraw.c +MW_NANOX_DRAW_SRCS += microwindows/src/nanox/nxutil.c +MW_NANOX_DRAW_SRCS += microwindows/src/nanox/nxtransform.c +MW_NANOX_DRAW_SRCS += microwindows/src/nanox/nxpaintnc.c + +MW_NANOX_WM_SRCS = microwindows/src/nanox/wmaction.c +MW_NANOX_WM_SRCS += microwindows/src/nanox/wmclients.c +MW_NANOX_WM_SRCS += microwindows/src/nanox/wmevents.c +MW_NANOX_WM_SRCS += microwindows/src/nanox/wmutil.c + +MW_NANOX_SERVER_SRCS = microwindows/src/nanox/srvmain.c +MW_NANOX_SERVER_SRCS += microwindows/src/nanox/srvfunc.c +MW_NANOX_SERVER_SRCS += microwindows/src/nanox/srvutil.c +MW_NANOX_SERVER_SRCS += microwindows/src/nanox/srvevent.c +MW_NANOX_SERVER_SRCS += microwindows/src/nanox/srvclip.c + +ifeq ($(CONFIG_MICROWINDOWS_NANOX_NONETWORK),y) + +# NONETWORK mode: the client application is linked directly with the +# server and runs in the same task, without a network socket. Only a +# single client can be active at a time. +CFLAGS += -DNONETWORK=1 + +ifneq ($(CONFIG_MICROWINDOWS_NANOX_NANOWM),) +CFLAGS += -DNANOWM=1 +CSRCS += $(MW_NANOX_WM_SRCS) +endif + +CSRCS += $(MW_NANOX_DRAW_SRCS) $(MW_NANOX_SERVER_SRCS) +CSRCS += microwindows/src/nanox/srvnonet.c + +else + +# Network client/server mode: each client connects to the server +# through a local stream socket. NX_PER_CLIENT_DATA enables the +# per-task client data (POSIX per-thread key) so that several client +# tasks can run at the same time in the flat build. + +MW_NANOX_CLIENT_SRCS = $(MW_NANOX_DRAW_SRCS) +MW_NANOX_CLIENT_SRCS += microwindows/src/nanox/client.c +MW_NANOX_CLIENT_SRCS += microwindows/src/nanox/clientfb.c +MW_NANOX_CLIENT_SRCS += microwindows/src/nanox/nxproto.c +MW_NANOX_CLIENT_SRCS += microwindows/src/drivers/osdep.c + +MW_NANOX_SERVER_SRCS += microwindows/src/nanox/srvnet.c + +# The server main() is renamed to nanox_server_main() and invoked from +# the nanoxterm example, which starts the server as a separate task. +microwindows/src/nanox/srvmain.c_CFLAGS += -Dmain=nanox_server_main + +CFLAGS += -DNX_PER_CLIENT_DATA=1 +ifneq ($(CONFIG_MICROWINDOWS_NANOX_NANOWM),) +CFLAGS += -DNANOWM=1 + +# Rename the server-side GrXXX symbols to SVR_GrXXX, since the server +# and the client code are linked into a single image. +$(foreach src,$(MW_NANOX_WM_SRCS),$(eval $(src)_CFLAGS += -include microwindows/src/nanox/serv.h)) +CSRCS += $(MW_NANOX_WM_SRCS) +endif + +CSRCS += $(MW_NANOX_CLIENT_SRCS) $(MW_NANOX_SERVER_SRCS) + +endif + +endif + include $(APPDIR)/Application.mk