From 7b1c79c80575c55356c486c4c2a99e182609477a Mon Sep 17 00:00:00 2001 From: Pavel Pisa Date: Fri, 5 Jun 2026 18:11:29 +0200 Subject: [PATCH 1/6] graphics/microwindows: introduce Microwidows/Nano-X graphics support to NuttX The Microwidows/Nano-X (https://microwindows.org/) is project developed and maintained by Gregory Haerr. It is heavily extended from predecessor NanoGUI and supports multiple APIs. The initial integration build only core parts engine, drivers and basic/included precompiled bitmap fonts. The source files are derived from list provided by Objects.rules files in appropriate Microwindows directories. The build requires fix includes in src/engine/devfont.c where #include is missing for strcasecmp(). Only dummy keyboard and mouse drivers are compiled. Screen driver has to be implemented/ported for NuttX FrameBuffer device API. Signed-off-by: Pavel Pisa --- graphics/microwindows/.gitignore | 2 + graphics/microwindows/Kconfig | 10 ++++ graphics/microwindows/Make.defs | 40 ++++++++++++++ graphics/microwindows/Makefile | 89 ++++++++++++++++++++++++++++++++ 4 files changed, 141 insertions(+) create mode 100644 graphics/microwindows/.gitignore create mode 100644 graphics/microwindows/Kconfig create mode 100644 graphics/microwindows/Make.defs create mode 100644 graphics/microwindows/Makefile diff --git a/graphics/microwindows/.gitignore b/graphics/microwindows/.gitignore new file mode 100644 index 00000000000..0cb9c84040c --- /dev/null +++ b/graphics/microwindows/.gitignore @@ -0,0 +1,2 @@ +/microwindows +/*.zip diff --git a/graphics/microwindows/Kconfig b/graphics/microwindows/Kconfig new file mode 100644 index 00000000000..28d74096fa6 --- /dev/null +++ b/graphics/microwindows/Kconfig @@ -0,0 +1,10 @@ +# +# For a description of the syntax of this configuration file, +# see the file kconfig-language.txt in the NuttX tools repository. +# + +menuconfig GRAPHICS_MICROWINDOWS + bool "Microwindows or the Nano-X Window System" + default n + ---help--- + Enable Microwindows or the Nano-X Window System diff --git a/graphics/microwindows/Make.defs b/graphics/microwindows/Make.defs new file mode 100644 index 00000000000..6d42431b366 --- /dev/null +++ b/graphics/microwindows/Make.defs @@ -0,0 +1,40 @@ +############################################################################ +# apps/graphics/microwindows/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_GRAPHICS_MICROWINDOWS),) +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 + +CFLAGS += -DHAVE_FNT_SUPPORT=1 +CFLAGS += -DUNIX=1 + +CFLAGS += -DSCREEN_PIXTYPE=MWPF_TRUECOLORARGB +CFLAGS += -DSCREEN_DEPTH=8 + +CFLAGS += -DKEYBOARD=NOKBD +CFLAGS += -DMOUSE=NOMOUSE + +endif diff --git a/graphics/microwindows/Makefile b/graphics/microwindows/Makefile new file mode 100644 index 00000000000..1e5b38735bc --- /dev/null +++ b/graphics/microwindows/Makefile @@ -0,0 +1,89 @@ +############################################################################ +# apps/graphics/microwindows/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 + +# LVGL graphic library + +MICROWINDOWS_DIR = . +MICROWINDOWS_DIR_NAME = microwindows + +#-include ./lvgl/lvgl.mk + +# Set up build configuration and environment + +WD := ${shell echo $(CURDIR) | sed -e 's/ /\\ /g'} + +MICROWINDOWS_COMMIT_HASH := 8809effdd0dfe6c2ac8fd0f455a31407e8495a93 + +#CONFIG_GRAPH_MICROWINDOWS_URL ?= "https://codeload.github.com/ghaerr/microwindows/zip/refs/heads/master" +CONFIG_GRAPH_MICROWINDOWS_URL ?= https://codeload.github.com/ghaerr/microwindows/zip/$(MICROWINDOWS_COMMIT_HASH) + +MICROWINDOWS_TARBALL := microwindows-$(MICROWINDOWS_COMMIT_HASH).zip + +MICROWINDOWS_UNPACKNAME = microwindows +UNPACK ?= unzip -o $(if $(V),,-q) +CURL ?= curl -L $(if $(V),,-Ss) + +MICROWINDOWS_UNPACKDIR = $(WD)/$(MICROWINDOWS_UNPACKNAME) + +$(MICROWINDOWS_TARBALL): + $(ECHO_BEGIN)"Downloading: $(MICROWINDOWS_TARBALL)" + $(Q) $(CURL) -o $(MICROWINDOWS_TARBALL) $(CONFIG_GRAPH_MICROWINDOWS_URL) + $(ECHO_END) + +$(MICROWINDOWS_UNPACKNAME): $(MICROWINDOWS_TARBALL) + $(ECHO_BEGIN)"Unpacking: $(MICROWINDOWS_TARBALL) -> $(MICROWINDOWS_UNPACKNAME)" + $(Q) $(UNPACK) $(MICROWINDOWS_TARBALL) + $(Q) mv microwindows-$(MICROWINDOWS_COMMIT_HASH) $(MICROWINDOWS_UNPACKNAME) + $(Q) touch $(MICROWINDOWS_UNPACKNAME) + $(ECHO_END) + +# Download and unpack tarball if no git repo found +ifeq ($(wildcard $(MICROWINDOWS_UNPACKNAME)/.git),) +context:: $(MICROWINDOWS_UNPACKNAME) +endif + +CFLAGS += -DRTEMS=0 -DPSP=0 -D__ECOS=0 -D__MINGW32__=0 +CFLAGS += -DELKS=0 -D_MINIX=0 -DMSDOS=0 -DLINUX=0 +CFLAGS += -DMACOSX=0 -DTRIMEDIA=0 + +CFLAGS += -Wno-undef +CFLAGS += -Wno-shadow + +MW_DIR_OBJ = $(WD)/$(MICROWINDOWS_DIR_NAME)/src + +-include microwindows/src/engine/Objects.rules +-include microwindows/src/drivers/Objects.rules +-include microwindows/src/fonts/Objects.rules + +CSRCS += $(MW_CORE_OBJS:%.o=%.c) + +#$(error EXTOBJS=$(EXTOBJS)) + +include $(APPDIR)/Application.mk + +ifeq ($(wildcard $(MICROWINDOWS_UNPACKNAME)/.git),) +distclean:: + $(call DELDIR, $(MICROWINDOWS_UNPACKNAME)) + $(call DELFILE, $(MICROWINDOWS_TARBALL)) +endif From 8877bb49cfe9d4af1c499132997b294d324432cf Mon Sep 17 00:00:00 2001 From: Acfboy Date: Thu, 11 Jun 2026 12:04:45 +0800 Subject: [PATCH 2/6] graphics/microwindows: implement nuttx fb driver for mw Signed-off-by: Acfboy --- examples/microwindows/Kconfig | 25 +++++ examples/microwindows/Make.defs | 25 +++++ examples/microwindows/Makefile | 34 ++++++ examples/microwindows/mwexample.c | 21 ++++ graphics/microwindows/Make.defs | 8 ++ graphics/microwindows/Makefile | 2 + graphics/microwindows/mwin-local/scr_nuttx.c | 104 +++++++++++++++++++ 7 files changed, 219 insertions(+) create mode 100644 examples/microwindows/Kconfig create mode 100644 examples/microwindows/Make.defs create mode 100644 examples/microwindows/Makefile create mode 100644 examples/microwindows/mwexample.c create mode 100644 graphics/microwindows/mwin-local/scr_nuttx.c diff --git a/examples/microwindows/Kconfig b/examples/microwindows/Kconfig new file mode 100644 index 00000000000..f4b1d110786 --- /dev/null +++ b/examples/microwindows/Kconfig @@ -0,0 +1,25 @@ +config EXAMPLES_MICROWINDOWS + tristate "Microwindows example" + default n + depends on GRAPHICS_MICROWINDOWS + ---help--- + Enable the Microwindows example application + +if EXAMPLES_MICROWINDOWS + +config EXAMPLES_MICROWINDOWS_PROGNAME + string "Program name" + default "mwexample" + ---help--- + This is the name of the program that will be used when the NSH ELF + program is installed. + +config EXAMPLES_MICROWINDOWS_PRIORITY + int "Microwindows task priority" + default 100 + +config EXAMPLES_MICROWINDOWS_STACKSIZE + int "Microwindows stack size" + default 32768 + +endif diff --git a/examples/microwindows/Make.defs b/examples/microwindows/Make.defs new file mode 100644 index 00000000000..51ff2f8fd1f --- /dev/null +++ b/examples/microwindows/Make.defs @@ -0,0 +1,25 @@ +############################################################################ +# apps/examples/hello/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_MICROWINDOWS),) +CONFIGURED_APPS += $(APPDIR)/examples/microwindows +endif diff --git a/examples/microwindows/Makefile b/examples/microwindows/Makefile new file mode 100644 index 00000000000..3f6dee4750a --- /dev/null +++ b/examples/microwindows/Makefile @@ -0,0 +1,34 @@ +############################################################################ +# apps/examples/microwindows/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_MICROWINDOWS_PROGNAME) +PRIORITY = $(CONFIG_EXAMPLES_MICROWINDOWS_PRIORITY) +STACKSIZE = $(CONFIG_EXAMPLES_MICROWINDOWS_STACKSIZE) +MODULE = y + +MAINSRC = mwexample.c + +CFLAGS += -Wno-undef + +include $(APPDIR)/Application.mk diff --git a/examples/microwindows/mwexample.c b/examples/microwindows/mwexample.c new file mode 100644 index 00000000000..c4edd9f09b5 --- /dev/null +++ b/examples/microwindows/mwexample.c @@ -0,0 +1,21 @@ +#include +#include +#include +#include "device.h" + +int main(int argc, FAR char *argv[]) +{ + PSD psd = GdOpenScreen(); + if (!psd) { + printf("GdOpenScreen failed\n"); + return 1; + } + + GdSetForegroundColor(psd, MWRGB(255, 0, 0)); + GdFillRect(psd, 20, 20, 20, 20); + + sleep(5); + + GdCloseScreen(psd); + return 0; +} diff --git a/graphics/microwindows/Make.defs b/graphics/microwindows/Make.defs index 6d42431b366..b93b7a5ee15 100644 --- a/graphics/microwindows/Make.defs +++ b/graphics/microwindows/Make.defs @@ -27,6 +27,11 @@ CONFIGURED_APPS += $(APPDIR)/graphics/microwindows CFLAGS += ${INCDIR_PREFIX}$(APPDIR)/graphics/microwindows/microwindows/src/include CXXFLAGS += ${INCDIR_PREFIX}$(APPDIR)/graphics/microwindows/microwindows/src/include +CFLAGS += ${INCDIR_PREFIX}$(APPDIR)/graphics/microwindows/microwindows/src/drivers + +ifeq ($(CONFIG_VIDEO_FB),) +$(error Microwindows requires CONFIG_VIDEO_FB=y) +endif CFLAGS += -DHAVE_FNT_SUPPORT=1 CFLAGS += -DUNIX=1 @@ -34,6 +39,9 @@ CFLAGS += -DUNIX=1 CFLAGS += -DSCREEN_PIXTYPE=MWPF_TRUECOLORARGB CFLAGS += -DSCREEN_DEPTH=8 +KEYBOARD = NOKBD +MOUSE = NOMOUSE + CFLAGS += -DKEYBOARD=NOKBD CFLAGS += -DMOUSE=NOMOUSE diff --git a/graphics/microwindows/Makefile b/graphics/microwindows/Makefile index 1e5b38735bc..ca9d5e94d32 100644 --- a/graphics/microwindows/Makefile +++ b/graphics/microwindows/Makefile @@ -71,12 +71,14 @@ CFLAGS += -Wno-undef CFLAGS += -Wno-shadow MW_DIR_OBJ = $(WD)/$(MICROWINDOWS_DIR_NAME)/src +MW_LOCAL_DIR := mwin-local -include microwindows/src/engine/Objects.rules -include microwindows/src/drivers/Objects.rules -include microwindows/src/fonts/Objects.rules CSRCS += $(MW_CORE_OBJS:%.o=%.c) +CSRCS += $(MW_LOCAL_DIR)/scr_nuttx.c #$(error EXTOBJS=$(EXTOBJS)) diff --git a/graphics/microwindows/mwin-local/scr_nuttx.c b/graphics/microwindows/mwin-local/scr_nuttx.c new file mode 100644 index 00000000000..e77dbdaa244 --- /dev/null +++ b/graphics/microwindows/mwin-local/scr_nuttx.c @@ -0,0 +1,104 @@ +#include +#include +#include +#include +#include +#include "device.h" +#include "genfont.h" +#include "genmem.h" +#include "fb.h" + +static int fb = -1; + +static PSD fb_open(PSD psd); +static void fb_close(PSD psd); + +SCREENDEVICE scrdev = { + 0, 0, 0, 0, 0, 0, 0, NULL, 0, NULL, 0, 0, 0, 0, 0, 0, + gen_fonts, + fb_open, + fb_close, + NULL, + gen_getscreeninfo, + gen_allocatememgc, + gen_mapmemgc, + gen_freememgc, + gen_setportrait, + NULL, + NULL +}; + +static PSD fb_open(PSD psd) +{ + struct fb_videoinfo_s vinfo; + struct fb_planeinfo_s pinfo; + PSUBDRIVER subdriver; + + fb = open("/dev/fb0", O_RDWR); + if (fb < 0) + { + EPRINTF("Error: cannot open /dev/fb0. Check CONFIG_VIDEO_FB\n"); + return NULL; + } + + if (ioctl(fb, FBIOGET_VIDEOINFO, &vinfo) < 0 || + ioctl(fb, FBIOGET_PLANEINFO, &pinfo) < 0) + { + EPRINTF("Error: cannot read framebuffer info\n"); + goto fail; + } + + if (vinfo.xres == 0 || vinfo.yres == 0) + { + EPRINTF("Error: zero resolution\n"); + goto fail; + } + + psd->xres = psd->xvirtres = vinfo.xres; + psd->yres = psd->yvirtres = vinfo.yres; + psd->bpp = pinfo.bpp; + psd->planes = 1; + psd->pitch = pinfo.stride; + psd->size = pinfo.fblen; + psd->ncolors = (psd->bpp >= 24) ? (1 << 24) : (1 << psd->bpp); + psd->flags = PSF_SCREEN | PSF_ADDRMMAP; + psd->portrait = MWPORTRAIT_NONE; + + psd->pixtype = SCREEN_PIXTYPE; + psd->data_format = set_data_format(psd); + + psd->addr = mmap(NULL, psd->size, PROT_READ | PROT_WRITE, MAP_SHARED, fb, 0); + if (psd->addr == MAP_FAILED) + { + EPRINTF("Error: mmap failed\n"); + goto fail; + } + + subdriver = select_fb_subdriver(psd); + if (!subdriver) + { + EPRINTF("Error: no subdriver for %dbpp\n", psd->bpp); + goto fail; + } + set_subdriver(psd, subdriver); + + return psd; + +fail: + if (fb >= 0) + { + close(fb); + fb = -1; + } + return NULL; +} + +static void fb_close(PSD psd) +{ + if (fb >= 0) + { + munmap(psd->addr, psd->size); + close(fb); + fb = -1; + } +} From 29058f0c70020ab4f925b1b8618d4f65b9dd762e Mon Sep 17 00:00:00 2001 From: Acfboy Date: Fri, 12 Jun 2026 11:52:07 +0800 Subject: [PATCH 3/6] graphics/microwindows: implement nuttx keyboard and mouse driver for mw Signed-off-by: Acfboy --- examples/microwindows/mwexample.c | 137 +++++++- graphics/microwindows/Make.defs | 8 +- graphics/microwindows/Makefile | 2 + graphics/microwindows/mwin-local/kbd_nuttx.c | 316 +++++++++++++++++++ graphics/microwindows/mwin-local/mou_nuttx.c | 142 +++++++++ 5 files changed, 594 insertions(+), 11 deletions(-) create mode 100644 graphics/microwindows/mwin-local/kbd_nuttx.c create mode 100644 graphics/microwindows/mwin-local/mou_nuttx.c diff --git a/examples/microwindows/mwexample.c b/examples/microwindows/mwexample.c index c4edd9f09b5..e16159840ef 100644 --- a/examples/microwindows/mwexample.c +++ b/examples/microwindows/mwexample.c @@ -1,21 +1,148 @@ #include #include +#include #include #include "device.h" +#include "genfont.h" + +#define TEXTBOX_H 60 +#define RECT_SIZE 20 +#define MAX_TEXT 256 + +static PSD psd; +static MWCOORD screen_w, screen_h; +static MWCOORD textbox_y; +static PMWCOREFONT cfont; +static char textbuf[MAX_TEXT]; +static int textlen = 0; + +static void draw_textbox(void) +{ + GdSetForegroundColor(psd, MWRGB(255, 255, 255)); + GdFillRect(psd, 0, textbox_y, screen_w, TEXTBOX_H); + GdSetForegroundColor(psd, MWRGB(0, 0, 0)); + GdFillRect(psd, 0, textbox_y, screen_w, 2); + GdFillRect(psd, 0, textbox_y + TEXTBOX_H - 2, screen_w, 2); + + if (textlen > 0) { + GdSetForegroundColor(psd, MWRGB(0, 0, 0)); + GdSetBackgroundColor(psd, MWRGB(255, 255, 255)); + GdText(psd, (PMWFONT)cfont, 8, textbox_y + 8, textbuf, textlen, MWTF_ASCII | MWTF_TOP); + } + + MWCOORD tw = 0, th = 0, tb = 0; + GdGetTextSize((PMWFONT)cfont, textbuf, textlen, &tw, &th, &tb, MWTF_ASCII); + GdSetForegroundColor(psd, MWRGB(0, 0, 0)); + GdFillRect(psd, 8 + tw, textbox_y + 8, 2, th > 0 ? th : 16); +} + +static void draw_mouse_rect(MWCOORD x, MWCOORD y) +{ + int rx = x - RECT_SIZE / 2; + int ry = y - RECT_SIZE / 2; + if (rx < 0) rx = 0; + if (ry < 0) ry = 0; + if (rx + RECT_SIZE > screen_w) rx = screen_w - RECT_SIZE; + if (ry + RECT_SIZE > textbox_y) ry = textbox_y - RECT_SIZE; + GdSetForegroundColor(psd, MWRGB(255, 0, 0)); + GdFillRect(psd, rx, ry, RECT_SIZE, RECT_SIZE); +} int main(int argc, FAR char *argv[]) { - PSD psd = GdOpenScreen(); + psd = GdOpenScreen(); if (!psd) { printf("GdOpenScreen failed\n"); return 1; } - GdSetForegroundColor(psd, MWRGB(255, 0, 0)); - GdFillRect(psd, 20, 20, 20, 20); + screen_w = psd->xres; + screen_h = psd->yres; + textbox_y = screen_h - TEXTBOX_H; + + cfont = psd->builtin_fonts; - sleep(5); + int mousefd = GdOpenMouse(); + if (mousefd < 0) { + printf("GdOpenMouse failed, continuing without mouse\n"); + mousefd = -1; + } + int kbd_fd = GdOpenKeyboard(); + if (kbd_fd < 0) { + printf("GdOpenKeyboard failed, continuing without keyboard\n"); + kbd_fd = -1; + } + + GdSetForegroundColor(psd, MWRGB(0, 0, 0)); + GdFillRect(psd, 0, 0, screen_w, screen_h); + + draw_textbox(); + + printf("Mouse+keyboard test. Click to draw, type to input, ESC to quit.\n"); + + fd_set fds; + struct timeval timeout; + MWCOORD mx, my; + int buttons, last_buttons = 0; + int maxfd = 0; + if (mousefd > maxfd) maxfd = mousefd; + if (kbd_fd > maxfd) maxfd = kbd_fd; + + while (1) { + FD_ZERO(&fds); + if (mousefd >= 0) FD_SET(mousefd, &fds); + if (kbd_fd >= 0) FD_SET(kbd_fd, &fds); + + timeout.tv_sec = 10; + timeout.tv_usec = 0; + + int ret = select(maxfd + 1, &fds, NULL, NULL, &timeout); + if (ret < 0) { + break; + } + if (ret == 0) { + continue; + } + + if (mousefd >= 0 && FD_ISSET(mousefd, &fds)) { + if (GdReadMouse(&mx, &my, &buttons) > 0) { + if (buttons && !last_buttons) { + draw_mouse_rect(mx, my); + } + last_buttons = buttons; + } + } + + if (kbd_fd >= 0 && FD_ISSET(kbd_fd, &fds)) { + MWKEY key; + MWKEYMOD mods; + MWSCANCODE scancode; + int kret = GdReadKeyboard(&key, &mods, &scancode); + if (kret == KBD_KEYPRESS) { + if (key == MWKEY_ENTER) { + break; + } + + if (key == MWKEY_BACKSPACE) { + if (textlen > 0) { + textlen--; + textbuf[textlen] = '\0'; + draw_textbox(); + } + } else if (key >= 32 && key < 127) { + if (textlen < MAX_TEXT - 1) { + textbuf[textlen++] = key; + textbuf[textlen] = '\0'; + draw_textbox(); + } + } + } + } + } + + if (kbd_fd >= 0) GdCloseKeyboard(); + if (mousefd >= 0) GdCloseMouse(); GdCloseScreen(psd); return 0; -} +} \ No newline at end of file diff --git a/graphics/microwindows/Make.defs b/graphics/microwindows/Make.defs index b93b7a5ee15..d5931558c56 100644 --- a/graphics/microwindows/Make.defs +++ b/graphics/microwindows/Make.defs @@ -33,16 +33,12 @@ ifeq ($(CONFIG_VIDEO_FB),) $(error Microwindows requires CONFIG_VIDEO_FB=y) endif +HAVE_FNT_SUPPORT = Y CFLAGS += -DHAVE_FNT_SUPPORT=1 +CFLAGS += -DHAVE_FILEIO=1 CFLAGS += -DUNIX=1 CFLAGS += -DSCREEN_PIXTYPE=MWPF_TRUECOLORARGB CFLAGS += -DSCREEN_DEPTH=8 -KEYBOARD = NOKBD -MOUSE = NOMOUSE - -CFLAGS += -DKEYBOARD=NOKBD -CFLAGS += -DMOUSE=NOMOUSE - endif diff --git a/graphics/microwindows/Makefile b/graphics/microwindows/Makefile index ca9d5e94d32..a98741f8182 100644 --- a/graphics/microwindows/Makefile +++ b/graphics/microwindows/Makefile @@ -79,6 +79,8 @@ MW_LOCAL_DIR := mwin-local CSRCS += $(MW_CORE_OBJS:%.o=%.c) CSRCS += $(MW_LOCAL_DIR)/scr_nuttx.c +CSRCS += $(MW_LOCAL_DIR)/mou_nuttx.c +CSRCS += $(MW_LOCAL_DIR)/kbd_nuttx.c #$(error EXTOBJS=$(EXTOBJS)) diff --git a/graphics/microwindows/mwin-local/kbd_nuttx.c b/graphics/microwindows/mwin-local/kbd_nuttx.c new file mode 100644 index 00000000000..6f139eeeb2f --- /dev/null +++ b/graphics/microwindows/mwin-local/kbd_nuttx.c @@ -0,0 +1,316 @@ +#include +#include +#include +#include +#include +#include "device.h" +#include "mwtypes.h" + +enum kbd_mode_e + { + KBD_MODE_NONE = 0, + KBD_MODE_EVENT = 1, + KBD_MODE_RAW = 2, + }; + +static int kbd_fd = -1; +static enum kbd_mode_e g_kbd_mode = KBD_MODE_NONE; +static MWKEYMOD modifiers = 0; + +static bool g_pending_release = false; +static uint8_t g_last_raw_key = 0; + +/* Standard keyboard_event_s paths, eg. sim */ +static const char *g_kbd_event_paths[] = { + "/dev/kbd", + "/dev/kbd0", + "/dev/kbd1", + "/dev/ukeyboard", + NULL +}; + +/* Legacy raw character paths, eg. qemu */ +static const char *g_kbd_raw_paths[] = { + "/dev/kbda", + "/dev/kbdb", + NULL +}; + +static int nuttxkbd_Open(KBDDEVICE * pkd); +static void nuttxkbd_Close(void); +static void nuttxkbd_GetModifierInfo(MWKEYMOD * mods, MWKEYMOD * curmods); +static int nuttxkbd_Read(MWKEY * kbuf, MWKEYMOD * mods, MWSCANCODE * scancode); + +KBDDEVICE kbddev = { + nuttxkbd_Open, + nuttxkbd_Close, + nuttxkbd_GetModifierInfo, + nuttxkbd_Read, + NULL +}; + +static MWKEY translate_keycode(uint32_t code) +{ + switch (code) + { + case KEYCODE_BACKDEL: + return MWKEY_BACKSPACE; + case KEYCODE_FWDDEL: + return MWKEY_DELETE; + case KEYCODE_HOME: + return MWKEY_HOME; + case KEYCODE_END: + return MWKEY_END; + case KEYCODE_LEFT: + return MWKEY_LEFT; + case KEYCODE_RIGHT: + return MWKEY_RIGHT; + case KEYCODE_UP: + return MWKEY_UP; + case KEYCODE_DOWN: + return MWKEY_DOWN; + case KEYCODE_PAGEUP: + return MWKEY_PAGEUP; + case KEYCODE_PAGEDOWN: + return MWKEY_PAGEDOWN; + case KEYCODE_INSERT: + return MWKEY_INSERT; + case KEYCODE_ENTER: + return MWKEY_ENTER; + case KEYCODE_F1: + return MWKEY_F1; + case KEYCODE_F2: + return MWKEY_F2; + case KEYCODE_F3: + return MWKEY_F3; + case KEYCODE_F4: + return MWKEY_F4; + case KEYCODE_F5: + return MWKEY_F5; + case KEYCODE_F6: + return MWKEY_F6; + case KEYCODE_F7: + return MWKEY_F7; + case KEYCODE_F8: + return MWKEY_F8; + case KEYCODE_F9: + return MWKEY_F9; + case KEYCODE_F10: + return MWKEY_F10; + case KEYCODE_F11: + return MWKEY_F11; + case KEYCODE_F12: + return MWKEY_F12; + case KEYCODE_CAPSLOCK: + return MWKEY_CAPSLOCK; + case KEYCODE_NUMLOCK: + return MWKEY_NUMLOCK; + case KEYCODE_SCROLLLOCK: + return MWKEY_SCROLLOCK; + case KEYCODE_PAUSE: + return MWKEY_PAUSE; + case KEYCODE_PRTSCRN: + return MWKEY_PRINT; + case KEYCODE_MENU: + return MWKEY_MENU; + + default: + if (code < 128) + { + return (MWKEY) code; + } + return MWKEY_UNKNOWN; + } +} + +static void update_modifiers(MWKEY key, int press) +{ + MWKEYMOD mask = 0; + + switch (key) + { + case MWKEY_LSHIFT: + mask = MWKMOD_LSHIFT; + break; + case MWKEY_RSHIFT: + mask = MWKMOD_RSHIFT; + break; + case MWKEY_LCTRL: + mask = MWKMOD_LCTRL; + break; + case MWKEY_RCTRL: + mask = MWKMOD_RCTRL; + break; + case MWKEY_LALT: + mask = MWKMOD_LALT; + break; + case MWKEY_RALT: + mask = MWKMOD_RALT; + break; + case MWKEY_LMETA: + mask = MWKMOD_LMETA; + break; + case MWKEY_RMETA: + mask = MWKMOD_RMETA; + break; + case MWKEY_NUMLOCK: + mask = MWKMOD_NUM; + break; + case MWKEY_CAPSLOCK: + mask = MWKMOD_CAPS; + break; + } + + if (mask) + { + if (press) + { + modifiers |= mask; + } + else + { + modifiers &= ~mask; + } + } +} + +static MWKEY raw_byte_to_mwkey(uint8_t ch) +{ + if (ch < 128) + { + return (MWKEY) ch; + } + return MWKEY_UNKNOWN; +} + +static int nuttxkbd_Open(KBDDEVICE *pkd) +{ + int i; + useconds_t delay = 1000; + + if (kbd_fd >= 0) + { + close(kbd_fd); + kbd_fd = -1; + } + + g_kbd_mode = KBD_MODE_NONE; + g_pending_release = false; + modifiers = 0; + + /* Retry with exponential backoff to wait for asynchronously loaded input + * device drivers (e.g. USB HID) to register their device nodes. */ + while (delay <= 1024000) + { + for (i = 0; g_kbd_event_paths[i]; i++) + { + kbd_fd = open(g_kbd_event_paths[i], O_RDONLY | O_NONBLOCK); + if (kbd_fd >= 0) + { + g_kbd_mode = KBD_MODE_EVENT; + return DRIVER_OKFILEDESC(kbd_fd); + } + } + + for (i = 0; g_kbd_raw_paths[i]; i++) + { + kbd_fd = open(g_kbd_raw_paths[i], O_RDONLY | O_NONBLOCK); + if (kbd_fd >= 0) + { + g_kbd_mode = KBD_MODE_RAW; + g_pending_release = false; + return DRIVER_OKFILEDESC(kbd_fd); + } + } + + usleep(delay); + delay *= 2; + } + + return DRIVER_FAIL; +} + +static void nuttxkbd_Close(void) +{ + if (kbd_fd >= 0) + { + close(kbd_fd); + kbd_fd = -1; + } + modifiers = 0; + g_kbd_mode = KBD_MODE_NONE; + g_pending_release = false; +} + +static void nuttxkbd_GetModifierInfo(MWKEYMOD *mods, MWKEYMOD *curmods) +{ + if (mods) + { + *mods = MWKMOD_SHIFT | + MWKMOD_CTRL | MWKMOD_ALT | MWKMOD_META | MWKMOD_NUM | MWKMOD_CAPS; + } + if (curmods) + { + *curmods = modifiers; + } +} + +static int nuttxkbd_Read(MWKEY *kbuf, MWKEYMOD *mods, MWSCANCODE *scancode) +{ + if (g_kbd_mode == KBD_MODE_EVENT) + { + struct keyboard_event_s event; + int n; + + n = read(kbd_fd, &event, sizeof(event)); + if (n < (int)sizeof(event)) + { + return KBD_NODATA; + } + + MWKEY key = translate_keycode(event.code); + int press = (event.type == KEYBOARD_PRESS); + + update_modifiers(key, press); + + *kbuf = key; + *mods = modifiers; + *scancode = 0; + + return press ? KBD_KEYPRESS : KBD_KEYRELEASE; + } + else + { + uint8_t ch; + int n; + + if (g_pending_release) + { + g_pending_release = false; + *kbuf = (MWKEY) g_last_raw_key; + *mods = modifiers; + *scancode = 0; + return KBD_KEYRELEASE; + } + + n = read(kbd_fd, &ch, 1); + if (n < 1) + { + return KBD_NODATA; + } + + MWKEY key = raw_byte_to_mwkey(ch); + if (key == MWKEY_UNKNOWN) + { + return KBD_NODATA; + } + + g_pending_release = true; + g_last_raw_key = ch; + + *kbuf = key; + *mods = modifiers; + *scancode = 0; + return KBD_KEYPRESS; + } +} diff --git a/graphics/microwindows/mwin-local/mou_nuttx.c b/graphics/microwindows/mwin-local/mou_nuttx.c new file mode 100644 index 00000000000..090b97e59fc --- /dev/null +++ b/graphics/microwindows/mwin-local/mou_nuttx.c @@ -0,0 +1,142 @@ +#include +#include +#include +#include +#include +#include "device.h" + +#define SCALE 3 +#define THRESH 5 + +#define TYPE_REALMOUSE 1 +#define TYPE_TOUCHSCREEN 0 +#define MOUSE_DEVICE_PATH "/dev/mouse0" +#define TOUCHSCREEN_DEVICE_PATH "/dev/input0" + +static int fd = -1; +static int mouse_type = TYPE_TOUCHSCREEN; + +static int nuttxmouse_Open(MOUSEDEVICE * pmd); +static void nuttxmouse_Close(void); +static int nuttxmouse_GetButtonInfo(void); +static void nuttxmouse_GetDefaultAccel(int *pscale, int *pthresh); +static int nuttxmouse_Read(MWCOORD * dx, MWCOORD * dy, MWCOORD * dz, int *bp); + +MOUSEDEVICE mousedev = { + nuttxmouse_Open, + nuttxmouse_Close, + nuttxmouse_GetButtonInfo, + nuttxmouse_GetDefaultAccel, + nuttxmouse_Read, + NULL, + MOUSE_NORMAL +}; + +static int nuttxmouse_Open(MOUSEDEVICE *pmd) +{ + useconds_t delay = 1000; + + /* Retry with exponential backoff to wait for asynchronously loaded input + * device drivers (e.g. USB HID) to register their device nodes. */ + while (delay <= 1024000) + { + fd = open(MOUSE_DEVICE_PATH, O_RDONLY | O_NONBLOCK); + if (fd >= 0) + { + mouse_type = TYPE_REALMOUSE; + return DRIVER_OKFILEDESC(fd); + } + + fd = open(TOUCHSCREEN_DEVICE_PATH, O_RDONLY | O_NONBLOCK); + if (fd >= 0) + { + mouse_type = TYPE_TOUCHSCREEN; + return DRIVER_OKFILEDESC(fd); + } + + usleep(delay); + delay *= 2; + } + + return MOUSE_FAIL; +} + +static void nuttxmouse_Close(void) +{ + if (fd >= 0) + { + close(fd); + fd = -1; + } +} + +static int nuttxmouse_GetButtonInfo(void) +{ + if (mouse_type == TYPE_REALMOUSE) + { + return MWBUTTON_L | MWBUTTON_M | MWBUTTON_R | MWBUTTON_SCROLLUP | + MWBUTTON_SCROLLDN; + } + else + { + return MWBUTTON_L; + } +} + +static void nuttxmouse_GetDefaultAccel(int *pscale, int *pthresh) +{ + *pscale = SCALE; + *pthresh = THRESH; +} + +static int nuttxmouse_Read(MWCOORD *dx, MWCOORD *dy, MWCOORD *dz, int *bp) +{ + if (mouse_type == TYPE_REALMOUSE) + { + struct mouse_report_s report; + int n = read(fd, &report, sizeof(report)); + if (n <= 0) + return MOUSE_NODATA; + + *dx = report.x; + *dy = report.y; + *dz = report.wheel; + + *bp = 0; + if (report.buttons & MOUSE_BUTTON_1) + *bp |= MWBUTTON_L; + if (report.buttons & MOUSE_BUTTON_2) + *bp |= MWBUTTON_R; + if (report.buttons & MOUSE_BUTTON_3) + *bp |= MWBUTTON_M; + + if (report.wheel > 0) + *bp |= MWBUTTON_SCROLLUP; + if (report.wheel < 0) + *bp |= MWBUTTON_SCROLLDN; + + return MOUSE_ABSPOS; + } + else + { + struct touch_sample_s sample; + int n = read(fd, &sample, sizeof(sample)); + if (n <= 0) + return MOUSE_NODATA; + + *dx = sample.point[0].x; + *dy = sample.point[0].y; + *dz = 0; + + uint8_t flags = sample.point[0].flags; + if (flags & (TOUCH_DOWN | TOUCH_MOVE)) + { + *bp = MWBUTTON_L; + } + else + { + *bp = 0; + } + return MOUSE_ABSPOS; + } +} From b500978d0b339ced516cd328cb483f354622be14 Mon Sep 17 00:00:00 2001 From: Acfboy Date: Sun, 14 Jun 2026 23:35:32 +0800 Subject: [PATCH 4/6] graphics/microwindows: port mwdemo to examples/microwindows Signed-off-by: Acfboy --- examples/microwindows/Makefile | 24 +- examples/microwindows/mwdemo.c | 532 ++++++++++++++++++++++++++++ examples/microwindows/mwdemo_main.c | 25 ++ examples/microwindows/mwexample.c | 148 -------- graphics/microwindows/Makefile | 39 +- 5 files changed, 617 insertions(+), 151 deletions(-) create mode 100644 examples/microwindows/mwdemo.c create mode 100644 examples/microwindows/mwdemo_main.c delete mode 100644 examples/microwindows/mwexample.c diff --git a/examples/microwindows/Makefile b/examples/microwindows/Makefile index 3f6dee4750a..fa7d5bec2d7 100644 --- a/examples/microwindows/Makefile +++ b/examples/microwindows/Makefile @@ -27,8 +27,28 @@ PRIORITY = $(CONFIG_EXAMPLES_MICROWINDOWS_PRIORITY) STACKSIZE = $(CONFIG_EXAMPLES_MICROWINDOWS_STACKSIZE) MODULE = y -MAINSRC = mwexample.c +MAINSRC = mwdemo_main.c +CSRCS += mwdemo.c +CSRCS += images/microwin.c -CFLAGS += -Wno-undef +# Generate microwin.c from microwin.bmp +MW_SRC = $(APPDIR)/graphics/microwindows/microwindows/src +MW_IMGDIR = images +MW_CONVBMP = convbmp$(HOSTEXEEXT) + +$(MW_CONVBMP): $(MW_SRC)/images/tools/convbmp.c + $(HOSTCC) $(HOSTCFLAGS) -I$(MW_SRC)/include $< -o $@ + +$(MW_IMGDIR)/microwin.c: $(MW_SRC)/images/demos/mwin/microwin.bmp $(MW_CONVBMP) + mkdir -p $(MW_IMGDIR) + $(CURDIR)/$(MW_CONVBMP) -o $@ $< + +clean:: + $(call DELFILE, $(MW_IMGDIR)/microwin.c) + $(Q) rmdir $(MW_IMGDIR) 2>/dev/null || true + $(call DELFILE, $(MW_CONVBMP)) + +CFLAGS += -Wno-undef +CFLAGS += -DNOGDI include $(APPDIR)/Application.mk diff --git a/examples/microwindows/mwdemo.c b/examples/microwindows/mwdemo.c new file mode 100644 index 00000000000..4ef298ec9c0 --- /dev/null +++ b/examples/microwindows/mwdemo.c @@ -0,0 +1,532 @@ + +/* + * Copyright (c) 1999, 2000, 2001, 2010 Greg Haerr + * Portions Copyright (c) 2002 by Koninklijke Philips Electronics N.V. + * + * Demo program for Microwindows + * + * GB: 10-14-2004: Modified to store degrees data on each window, + * for new Timers features. + */ +#include +#include +#include +#include "uni_std.h" +#define MWINCLUDECOLORS +#include "windows.h" +#include "device.h" + +#if DOS_TURBOC +unsigned _stklen = 4096; +#endif + +/* define either GRAPH3D demo or CHILD control demo*/ +#define GRAPH3D 1 /* 3d graphics demo (requires floating point) */ +#define CONTROLS 0 /* win32 controls demo */ + +/* add clipping to GRAPH3D demo*/ +#define CLIPDEMO 0 /* set for region clipping demo */ + +/* CONTROLS demo options*/ +#define ARCDEMO 1 /* add arc drawing to CONTROLS demo */ +#define USEBLIT 1 /* use blit rather than DrawDIB() */ +#define IMAGE 0 /* add 256 color image to CONTROLS demo */ + +/* test timer system with either demo*/ +#define TIMERDEMO 1 /* set for WM_TIMER demo */ + +/* not used*/ +#define CLIENT3D 0 /* old client draw test */ + +#if RTEMS +# undef GRAPH3D +# undef CONTROLS +# define CONTROLS 1 /* win32 controls demo */ +# undef IMAGE +# define IMAGE 1 /* 256 color image demo */ +# undef USEBLIT +# define USEBLIT 0 + /* use blit rather than DrawDIB() */ +#endif + +#if GRAPH3D +# include "graph3d.h" +#endif + +extern MWIMAGEHDR image_car8; +extern MWIMAGEHDR image_zion208; +extern MWIMAGEHDR image_penguin; +extern MWIMAGEHDR image_under4; +extern MWIMAGEHDR image_microwin; +extern MWIMAGEHDR image_cs1; +extern MWIMAGEHDR image_rle8; + +#if CONTROLS +# if ELKS | MSDOS +PMWIMAGEHDR image = &image_cs1; /* 2 color bitmap for 16 color systems */ +# else +PMWIMAGEHDR image = &image_penguin; +# endif +#endif + +#if IMAGE +PMWIMAGEHDR image2 = &image_zion208; +#endif + +#define APPCLASS "test" +#define APPCHILD "test2" + +/* forward decls*/ +LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg, WPARAM wp, LPARAM lp); +LRESULT CALLBACK ChildWndProc(HWND hwnd, UINT uMsg, WPARAM wp, LPARAM lp); + +int MwUserInit(int ac, char **av) +{ + /* test user init procedure - do nothing */ + return 0; +} + +static int RegisterAppClass(HINSTANCE hInstance) +{ + WNDCLASS wc; + + /* register builtin controls and dialog classes */ + MwInitializeDialogs(hInstance); + + wc.style = CS_DBLCLKS | CS_VREDRAW | CS_HREDRAW; + wc.lpfnWndProc = (WNDPROC) WndProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = sizeof(LONG_PTR); + wc.hInstance = 0; + wc.hIcon = 0; /* LoadIcon(GetHInstance(), MAKEINTRESOURCE( + * 1)); */ + wc.hCursor = LoadCursor(NULL, IDC_ARROW); + wc.hbrBackground = (HBRUSH) GetStockObject(LTGRAY_BRUSH); + wc.lpszMenuName = NULL; + wc.lpszClassName = APPCLASS; + RegisterClass(&wc); + +#if CONTROLS + wc.lpfnWndProc = (WNDPROC) ChildWndProc; + wc.lpszClassName = APPCHILD; + return RegisterClass(&wc); +#endif + return 1; +} + +static HWND CreateAppWindow(void) +{ + HWND hwnd; + static int nextid = 1; + int width, height; + RECT r; + GetWindowRect(GetDesktopWindow(), &r); + width = height = r.right / 2; + + hwnd = CreateWindowEx(0L, APPCLASS, + "Microwindows Application", + WS_OVERLAPPEDWINDOW | WS_VISIBLE, + CW_USEDEFAULT, CW_USEDEFAULT, + width, height, + NULL, (HMENU) (LONG_PTR) nextid++, NULL, NULL); + +#if CONTROLS + if (hwnd +# if GRAPH3D + && (nextid & 03) != 2 +# endif + ) + { + CreateWindowEx(0L, APPCHILD, + "", + WS_BORDER | WS_CHILD | WS_VISIBLE, + 4, 4, width / 3 - 6, height / 3, + hwnd, (HMENU) 2, NULL, NULL); + CreateWindowEx(0L, APPCHILD, + "", + WS_BORDER | WS_CHILD | WS_VISIBLE, + width / 3, height / 3, width / 3 - 6, height / 3, + hwnd, (HMENU) 3, NULL, NULL); + CreateWindowEx(0L, APPCHILD, + "", + WS_BORDER | WS_CHILD | WS_VISIBLE, + width * 3 / 5, height * 3 / 5, + width * 2 / 3, height * 2 / 3, + hwnd, (HMENU) 4, NULL, NULL); + CreateWindowEx(0L, "EDIT", + "OK", + WS_BORDER | WS_CHILD | WS_VISIBLE, + width * 5 / 8, 10, 100, 18, hwnd, (HMENU) 5, NULL, NULL); + CreateWindowEx(0L, "PROGBAR", + "OK", + WS_BORDER | WS_CHILD | WS_VISIBLE, + width * 5 / 8, 32, 100, 18, hwnd, (HMENU) 6, NULL, NULL); + + HWND hlist = CreateWindowEx(0L, "LISTBOX", + "OK", + WS_HSCROLL | WS_VSCROLL | WS_BORDER | WS_CHILD + | WS_VISIBLE, + width * 5 / 8, 54, 100, 48, + hwnd, (HMENU) 7, NULL, NULL); + SendMessage(hlist, LB_ADDSTRING, 0, (LPARAM) (LPSTR) "Cherry"); + SendMessage(hlist, LB_ADDSTRING, 0, (LPARAM) (LPSTR) "Apple"); + SendMessage(hlist, LB_ADDSTRING, 0, (LPARAM) (LPSTR) "Orange"); + + CreateWindowEx(0L, "BUTTON", + "Cancel", + BS_AUTOCHECKBOX | WS_CHILD | WS_VISIBLE, + width * 5 / 8 + 50, 106, 50, 14, + hwnd, (HMENU) 8, NULL, NULL); + } +#endif + return hwnd; +} + +#if CONTROLS +LRESULT CALLBACK ChildWndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) +{ + RECT rc; + PAINTSTRUCT ps; + + switch (msg) + { + case WM_PAINT: + BeginPaint(hwnd, &ps); + GetClientRect(hwnd, &rc); +# if USEBLIT + { + HDC hdcMem; + HBITMAP hbmp, hbmpOrg; + + /* redirect painting to offscreen dc, then use blit function */ + hdcMem = CreateCompatibleDC(ps.hdc); + /* + * Note: rc.right, rc.bottom happens to be smaller than image + * width/height. We use the image size, so we can stretchblit + * from the whole image. + */ + hbmp = CreateCompatibleBitmap(hdcMem, image->width, image->height); + hbmpOrg = SelectObject(hdcMem, hbmp); + + /* draw onto offscreen dc */ + DrawDIB(hdcMem, 0, 0, image); + + /* blit offscreen with physical screen */ + // BitBlt(ps.hdc, 0, 0, rc.right*4/5, rc.bottom*4/5, hdcMem, + // 0, 0, MWROP_COPY); + StretchBlt(ps.hdc, 0, 0, rc.right * 4 / 5, rc.bottom * 4 / 5, hdcMem, + 0, 0, image->width, image->height, MWROP_COPY); + DeleteObject(SelectObject(hdcMem, hbmpOrg)); + DeleteDC(hdcMem); + } +# else + DrawDIB(ps.hdc, rc.left, rc.top, image); +# endif + EndPaint(hwnd, &ps); + break; + default: + return DefWindowProc(hwnd, msg, wp, lp); + } + return (0); +} +#endif + +typedef struct + { + int startdegrees; + int enddegrees; + unsigned long reserved; + } demoWndData, *pdemoWndData; + +LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) +{ + PAINTSTRUCT ps; + HDC hdc; +#if CLIENT3D | IMAGE | GRAPH3D + RECT rc; +#endif +#if GRAPH3D + static int countup = 1; + int id; + static vec1 gx, gy; +#endif + static POINT mousept; + pdemoWndData pData; + + switch (msg) + { + case WM_CREATE: + pData = (pdemoWndData) malloc(sizeof(demoWndData)); + SetWindowLongPtr(hwnd, 0, (LONG_PTR) pData); + mousept.x = 60; + mousept.y = 20; + pData->startdegrees = 0; + pData->enddegrees = 30; +#if TIMERDEMO + SetTimer(hwnd, 1, (50 + random() % 250), NULL); +#endif + break; + + case WM_TIMER: + pData = (pdemoWndData) (LONG_PTR) GetWindowLongPtr(hwnd, 0); +#if GRAPH3D + GetClientRect(hwnd, &rc); + if (countup) + { + mousept.y += 20; + if (mousept.y >= rc.bottom) + { + mousept.y -= 20; + countup = 0; + } + } + else + { + mousept.y -= 20; + if (mousept.y < 20) + { + mousept.y += 20; + countup = 1; + } + } + SendMessage(hwnd, WM_MOUSEMOVE, 0, MAKELONG(mousept.x, mousept.y)); +#elif ARCDEMO + pData->startdegrees += 10; + if (pData->startdegrees >= 360) + pData->startdegrees = 0; + pData->enddegrees += 15; + if (pData->enddegrees >= 360) + pData->enddegrees = 0; + InvalidateRect(hwnd, NULL, TRUE); +#endif + break; + case WM_DESTROY: + KillTimer(hwnd, 1); + pData = (pdemoWndData) (LONG_PTR) GetWindowLongPtr(hwnd, 0); + free(pData); + SetWindowLongPtr(hwnd, 0, (LONG_PTR) 0); + break; + case WM_SIZE: + break; + case WM_MOVE: + break; + +#if CLIENT3D + case WM_SETFOCUS: + PostMessage((HWND) wp, WM_PAINT, 0, 0L); + break; + case WM_KILLFOCUS: + PostMessage((HWND) wp, WM_PAINT, 0, 0L); + break; + case WM_ERASEBKGND: + if (GetFocus() != hwnd) + return DefWindowProc(hwnd, msg, wp, lp); + return 1; +#endif +#if GRAPH3D + case WM_ERASEBKGND: + if ((GetWindowLong(hwnd, GWL_ID) & 03) == 1) + { + return 1; + } + return DefWindowProc(hwnd, msg, wp, lp); +#endif + case WM_PAINT: + hdc = BeginPaint(hwnd, &ps); + +#if CLIENT3D + if (GetFocus() == hwnd) + { + GetClientRect(hwnd, &rc); + Draw3dShadow(hdc, rc.left, rc.top, + rc.right - rc.left, rc.bottom - rc.top, + GetSysColor(COLOR_3DDKSHADOW), + GetSysColor(COLOR_3DLIGHT)); + InflateRect(&rc, -1, -1); + FillRect(hdc, &rc, GetStockObject(GRAY_BRUSH)); + } +#endif +#if IMAGE + GetClientRect(hwnd, &rc); + DrawDIB(hdc, rc.left + 2, rc.top + 2, image2); +#endif +#if GRAPH3D + id = (int)GetWindowLong(hwnd, GWL_ID) & 03; + init3(hdc, id == 1 ? hwnd : NULL); + switch (id) + { + case 0: + rose(1.0, 7, 13); + break; + case 1: + /* look3(0.5, 0.7, 1.5); */ + /* look3(0.2, -2 * gy, 1.0+gx); */ + look3(-2 * gx, -2 * gy, 1.2); + drawgrid(-8.0, 8.0, 10, -8.0, 8.0, 10); + break; + case 2: + setcolor3(BLACK); + circle3(1.0); + break; + case 3: + setcolor3(BLUE); + daisy(1.0, 20); + break; + } +# if CLIPDEMO + if (id == 1) + { + HRGN hrgn, hrgn2; + + /* create circular clip region for effect */ + GetClientRect(hwnd, &rc); + InflateRect(&rc, -80, -80); + switch ((int)GetWindowLong(hwnd, GWL_ID)) + { + default: + hrgn = CreateEllipticRgnIndirect(&rc); + break; + case 5: + hrgn = CreateRoundRectRgn(rc.left, rc.top, + rc.right, rc.bottom, 100, 100); + break; + case 2: + hrgn = CreateRectRgnIndirect(&rc); + break; + } + + /* erase background, clip out blit area */ + GetClientRect(hwnd, &rc); + hrgn2 = CreateRectRgnIndirect(&rc); + SelectClipRgn(hdc, hrgn2); + ExtSelectClipRgn(hdc, hrgn, RGN_XOR); + DeleteObject(hrgn2); + + GetClientRect(hwnd, &rc); + FillRect(hdc, &rc, GetStockObject(BLACK_BRUSH)); + + /* clip in only blit area */ + SelectClipRgn(hdc, hrgn); + DeleteObject(hrgn); + } +# endif /* CLIPDEMO */ + paint3(hdc); +#elif ARCDEMO + { + int x, y, w, h; + RECT rc; + + if (hdc != NULL) + { + pData = (pdemoWndData) GetWindowLongPtr(hwnd, 0); + GetWindowRect(hwnd, &rc); + rc.top += 13; + InflateRect(&rc, -3, -3); + /* Ellipse(hdc, 0, 0, rc.right-rc.left, rc.bottom-rc.top); */ + /* Arc(hdc, 0, 0, rc.right-rc.left, rc.bottom-rc.top, 0,0, 0,0); */ + /* Pie(hdc, 0, 0, rc.right-rc.left, rc.bottom-rc.top, 0,0, 0,0); */ + + x = rc.left; + y = rc.top; + w = rc.right - rc.left; + h = rc.bottom - rc.top; + w += 10; + GdSetForegroundColor(hdc->psd, RGB(0, 255, 0)); + GdArcAngle(hdc->psd, x + w / 2, y + h / 2, w / 2, h / 2, + pData->startdegrees * 64, pData->enddegrees * 64, MWPIE); + GdSetForegroundColor(hdc->psd, RGB(0, 0, 0)); + GdArcAngle(hdc->psd, x + w / 2, y + h / 2, w / 2, h / 2, + pData->startdegrees * 64, pData->enddegrees * 64, + MWARCOUTLINE); + /* GdSetForegroundColor(hdc->psd, RGB(255,255,255))); */ + /* GdPoint(hdc->psd, x+w/2, y+h/2); */ + } + EndPaint(hwnd, &ps); + break; + } +#endif /* ARCDEMO */ + EndPaint(hwnd, &ps); + break; + + case WM_MOUSEMOVE: +#if GRAPH3D + pData = (pdemoWndData) (LONG_PTR) GetWindowLongPtr(hwnd, 0); + if ((GetWindowLong(hwnd, GWL_ID) & 03) == 1) + { + POINT pt; + + POINTSTOPOINT(pt, lp); + GetClientRect(hwnd, &rc); + gx = (vec1) pt.x / rc.right; + gy = (vec1) pt.y / rc.bottom; + InvalidateRect(hwnd, NULL, FALSE); + mousept.x = pt.x; + mousept.y = pt.y; + } +#endif + break; + case WM_LBUTTONDOWN: + break; + case WM_LBUTTONUP: + break; + case WM_RBUTTONDOWN: + break; + default: + return DefWindowProc(hwnd, msg, wp, lp); + } + return 0; +} + +#if EMSCRIPTEN && MULTIAPP +# define WinMain mwdemo_WinMain +#endif + +int WINAPI +WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, + int nShowCmd) +{ + MSG msg; + HWND hwnd; + RECT rc; + + srandom(time(NULL)); + RegisterAppClass(hInstance); + GetWindowRect(GetDesktopWindow(), &rc); + + /* create penguin window */ + CreateWindowEx(0L, APPCHILD, "", WS_BORDER | WS_VISIBLE, + rc.right - 130 - 1, rc.bottom - 153 - 1, 130, 153, + GetDesktopWindow(), (HMENU) 1000, NULL, NULL); + +#if CONTROLS + CreateAppWindow(); + CreateAppWindow(); + CreateAppWindow(); + CreateAppWindow(); + CreateAppWindow(); + CreateAppWindow(); + CreateAppWindow(); + CreateAppWindow(); +#endif +#if !MULTIAPP + /* set background wallpaper */ + MwSetDesktopWallpaper(&image_microwin); + /* MwSetDesktopWallpaper(&image_under4); */ + /* MwSetDesktopWallpaper(&image_car8); */ +#endif + + hwnd = CreateAppWindow(); + GetWindowRect(hwnd, &rc); + OffsetRect(&rc, 50, 50); + MoveWindow(hwnd, rc.left, rc.top, rc.bottom - rc.top, + rc.right - rc.left, TRUE); + +#if !MULTIAPP + while (GetMessage(&msg, NULL, 0, 0)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } +#endif + return 0; +} diff --git a/examples/microwindows/mwdemo_main.c b/examples/microwindows/mwdemo_main.c new file mode 100644 index 00000000000..1bcd7764fa1 --- /dev/null +++ b/examples/microwindows/mwdemo_main.c @@ -0,0 +1,25 @@ + +/**************************************************************************** + * apps/examples/microwindows/mwdemo_main.c + * + * NuttX entry point for mwdemo (Microwindows Win32 API demo) + ****************************************************************************/ + +#include +#include "windows.h" + +extern int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, + LPSTR lpCmdLine, int nShowCmd); + +int mwdemo_main(int argc, FAR char *argv[]) +{ + int ret; + + invoke_WinMain_Start(argc, (char **)argv); + + ret = WinMain(0, NULL, (LPSTR) (argc > 0 ? argv[0] : ""), 0); + + invoke_WinMain_End(); + + return ret; +} diff --git a/examples/microwindows/mwexample.c b/examples/microwindows/mwexample.c deleted file mode 100644 index e16159840ef..00000000000 --- a/examples/microwindows/mwexample.c +++ /dev/null @@ -1,148 +0,0 @@ -#include -#include -#include -#include -#include "device.h" -#include "genfont.h" - -#define TEXTBOX_H 60 -#define RECT_SIZE 20 -#define MAX_TEXT 256 - -static PSD psd; -static MWCOORD screen_w, screen_h; -static MWCOORD textbox_y; -static PMWCOREFONT cfont; -static char textbuf[MAX_TEXT]; -static int textlen = 0; - -static void draw_textbox(void) -{ - GdSetForegroundColor(psd, MWRGB(255, 255, 255)); - GdFillRect(psd, 0, textbox_y, screen_w, TEXTBOX_H); - GdSetForegroundColor(psd, MWRGB(0, 0, 0)); - GdFillRect(psd, 0, textbox_y, screen_w, 2); - GdFillRect(psd, 0, textbox_y + TEXTBOX_H - 2, screen_w, 2); - - if (textlen > 0) { - GdSetForegroundColor(psd, MWRGB(0, 0, 0)); - GdSetBackgroundColor(psd, MWRGB(255, 255, 255)); - GdText(psd, (PMWFONT)cfont, 8, textbox_y + 8, textbuf, textlen, MWTF_ASCII | MWTF_TOP); - } - - MWCOORD tw = 0, th = 0, tb = 0; - GdGetTextSize((PMWFONT)cfont, textbuf, textlen, &tw, &th, &tb, MWTF_ASCII); - GdSetForegroundColor(psd, MWRGB(0, 0, 0)); - GdFillRect(psd, 8 + tw, textbox_y + 8, 2, th > 0 ? th : 16); -} - -static void draw_mouse_rect(MWCOORD x, MWCOORD y) -{ - int rx = x - RECT_SIZE / 2; - int ry = y - RECT_SIZE / 2; - if (rx < 0) rx = 0; - if (ry < 0) ry = 0; - if (rx + RECT_SIZE > screen_w) rx = screen_w - RECT_SIZE; - if (ry + RECT_SIZE > textbox_y) ry = textbox_y - RECT_SIZE; - GdSetForegroundColor(psd, MWRGB(255, 0, 0)); - GdFillRect(psd, rx, ry, RECT_SIZE, RECT_SIZE); -} - -int main(int argc, FAR char *argv[]) -{ - psd = GdOpenScreen(); - if (!psd) { - printf("GdOpenScreen failed\n"); - return 1; - } - - screen_w = psd->xres; - screen_h = psd->yres; - textbox_y = screen_h - TEXTBOX_H; - - cfont = psd->builtin_fonts; - - int mousefd = GdOpenMouse(); - if (mousefd < 0) { - printf("GdOpenMouse failed, continuing without mouse\n"); - mousefd = -1; - } - - int kbd_fd = GdOpenKeyboard(); - if (kbd_fd < 0) { - printf("GdOpenKeyboard failed, continuing without keyboard\n"); - kbd_fd = -1; - } - - GdSetForegroundColor(psd, MWRGB(0, 0, 0)); - GdFillRect(psd, 0, 0, screen_w, screen_h); - - draw_textbox(); - - printf("Mouse+keyboard test. Click to draw, type to input, ESC to quit.\n"); - - fd_set fds; - struct timeval timeout; - MWCOORD mx, my; - int buttons, last_buttons = 0; - int maxfd = 0; - if (mousefd > maxfd) maxfd = mousefd; - if (kbd_fd > maxfd) maxfd = kbd_fd; - - while (1) { - FD_ZERO(&fds); - if (mousefd >= 0) FD_SET(mousefd, &fds); - if (kbd_fd >= 0) FD_SET(kbd_fd, &fds); - - timeout.tv_sec = 10; - timeout.tv_usec = 0; - - int ret = select(maxfd + 1, &fds, NULL, NULL, &timeout); - if (ret < 0) { - break; - } - if (ret == 0) { - continue; - } - - if (mousefd >= 0 && FD_ISSET(mousefd, &fds)) { - if (GdReadMouse(&mx, &my, &buttons) > 0) { - if (buttons && !last_buttons) { - draw_mouse_rect(mx, my); - } - last_buttons = buttons; - } - } - - if (kbd_fd >= 0 && FD_ISSET(kbd_fd, &fds)) { - MWKEY key; - MWKEYMOD mods; - MWSCANCODE scancode; - int kret = GdReadKeyboard(&key, &mods, &scancode); - if (kret == KBD_KEYPRESS) { - if (key == MWKEY_ENTER) { - break; - } - - if (key == MWKEY_BACKSPACE) { - if (textlen > 0) { - textlen--; - textbuf[textlen] = '\0'; - draw_textbox(); - } - } else if (key >= 32 && key < 127) { - if (textlen < MAX_TEXT - 1) { - textbuf[textlen++] = key; - textbuf[textlen] = '\0'; - draw_textbox(); - } - } - } - } - } - - if (kbd_fd >= 0) GdCloseKeyboard(); - if (mousefd >= 0) GdCloseMouse(); - GdCloseScreen(psd); - return 0; -} \ No newline at end of file diff --git a/graphics/microwindows/Makefile b/graphics/microwindows/Makefile index a98741f8182..6d0b8f5e022 100644 --- a/graphics/microwindows/Makefile +++ b/graphics/microwindows/Makefile @@ -33,7 +33,7 @@ MICROWINDOWS_DIR_NAME = microwindows WD := ${shell echo $(CURDIR) | sed -e 's/ /\\ /g'} -MICROWINDOWS_COMMIT_HASH := 8809effdd0dfe6c2ac8fd0f455a31407e8495a93 +MICROWINDOWS_COMMIT_HASH := 1e71398cc6f650687f406547230c33788eeaf9c7 #CONFIG_GRAPH_MICROWINDOWS_URL ?= "https://codeload.github.com/ghaerr/microwindows/zip/refs/heads/master" CONFIG_GRAPH_MICROWINDOWS_URL ?= https://codeload.github.com/ghaerr/microwindows/zip/$(MICROWINDOWS_COMMIT_HASH) @@ -82,6 +82,43 @@ CSRCS += $(MW_LOCAL_DIR)/scr_nuttx.c CSRCS += $(MW_LOCAL_DIR)/mou_nuttx.c CSRCS += $(MW_LOCAL_DIR)/kbd_nuttx.c +ifneq ($(CONFIG_EXAMPLES_MICROWINDOWS),) + +# Win32 API used by mwdemo.c +MWIN_CORE_SRCS = microwindows/src/mwin/winmain.c +MWIN_CORE_SRCS += microwindows/src/mwin/winuser.c +MWIN_CORE_SRCS += microwindows/src/mwin/wingdi.c +MWIN_CORE_SRCS += microwindows/src/mwin/winexpos.c +MWIN_CORE_SRCS += microwindows/src/mwin/winclip.c +MWIN_CORE_SRCS += microwindows/src/mwin/winevent.c +MWIN_CORE_SRCS += microwindows/src/mwin/windefw.c +MWIN_CORE_SRCS += microwindows/src/mwin/winrgn.c +MWIN_CORE_SRCS += microwindows/src/mwin/winfont.c +MWIN_CORE_SRCS += microwindows/src/mwin/winsbar.c +MWIN_CORE_SRCS += microwindows/src/mwin/winres.c + +# mwin winlib +WINLIB_SRCS = microwindows/src/mwin/winlib/draw3d.c +WINLIB_SRCS += microwindows/src/mwin/winlib/fastfill.c +WINLIB_SRCS += microwindows/src/mwin/winlib/windlg.c +WINLIB_SRCS += microwindows/src/mwin/winlib/graph3d.c +WINLIB_SRCS += microwindows/src/mwin/winlib/caret.c +WINLIB_SRCS += microwindows/src/mwin/winlib/static.c +WINLIB_SRCS += microwindows/src/mwin/winlib/button.c +WINLIB_SRCS += microwindows/src/mwin/winlib/newedit.c +WINLIB_SRCS += microwindows/src/mwin/winlib/newlistbox.c +WINLIB_SRCS += microwindows/src/mwin/winlib/combobox.c +WINLIB_SRCS += microwindows/src/mwin/winlib/progbar.c +WINLIB_SRCS += microwindows/src/mwin/winlib/scrlbar.c +WINLIB_SRCS += microwindows/src/mwin/winlib/medit.c +WINLIB_SRCS += microwindows/src/mwin/winlib/ptinsid.c +WINLIB_SRCS += microwindows/src/mwin/winlib/insetr.c + +CSRCS += $(MWIN_CORE_SRCS) $(WINLIB_SRCS) +CFLAGS += -DNOGDI + +endif + #$(error EXTOBJS=$(EXTOBJS)) include $(APPDIR)/Application.mk From 912cf7c3d5e3abceba421444222988cb9fa9eb40 Mon Sep 17 00:00:00 2001 From: Acfboy Date: Mon, 15 Jun 2026 17:16:45 +0800 Subject: [PATCH 5/6] graphics/microwindows: fix main function in mwdemo_main.c Signed-off-by: Acfboy --- examples/microwindows/mwdemo_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/microwindows/mwdemo_main.c b/examples/microwindows/mwdemo_main.c index 1bcd7764fa1..08da63cda5c 100644 --- a/examples/microwindows/mwdemo_main.c +++ b/examples/microwindows/mwdemo_main.c @@ -11,7 +11,7 @@ extern int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd); -int mwdemo_main(int argc, FAR char *argv[]) +int main(int argc, FAR char *argv[]) { int ret; From 238c5262b522ba657adc20f798f3074a7c5b1b34 Mon Sep 17 00:00:00 2001 From: Acfboy Date: Thu, 9 Jul 2026 21:33:16 +0800 Subject: [PATCH 6/6] graphics/microwindows: support more demo images Signed-off-by: Acfboy --- examples/microwindows/Makefile | 9 +++++---- graphics/microwindows/Makefile | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/examples/microwindows/Makefile b/examples/microwindows/Makefile index fa7d5bec2d7..181b63d9e76 100644 --- a/examples/microwindows/Makefile +++ b/examples/microwindows/Makefile @@ -29,9 +29,10 @@ MODULE = y MAINSRC = mwdemo_main.c CSRCS += mwdemo.c -CSRCS += images/microwin.c +MW_IMAGES = car8 zion208 penguin under4 cs1 rle8 microwin +CSRCS += $(MW_IMAGES:%=$(MW_IMGDIR)/%.c) -# Generate microwin.c from microwin.bmp +# Generate image .c files from .bmp MW_SRC = $(APPDIR)/graphics/microwindows/microwindows/src MW_IMGDIR = images MW_CONVBMP = convbmp$(HOSTEXEEXT) @@ -39,12 +40,12 @@ MW_CONVBMP = convbmp$(HOSTEXEEXT) $(MW_CONVBMP): $(MW_SRC)/images/tools/convbmp.c $(HOSTCC) $(HOSTCFLAGS) -I$(MW_SRC)/include $< -o $@ -$(MW_IMGDIR)/microwin.c: $(MW_SRC)/images/demos/mwin/microwin.bmp $(MW_CONVBMP) +$(MW_IMGDIR)/%.c: $(MW_SRC)/images/demos/mwin/%.bmp $(MW_CONVBMP) mkdir -p $(MW_IMGDIR) $(CURDIR)/$(MW_CONVBMP) -o $@ $< clean:: - $(call DELFILE, $(MW_IMGDIR)/microwin.c) + $(call DELFILE, $(MW_IMAGES:%=$(MW_IMGDIR)/%.c)) $(Q) rmdir $(MW_IMGDIR) 2>/dev/null || true $(call DELFILE, $(MW_CONVBMP)) diff --git a/graphics/microwindows/Makefile b/graphics/microwindows/Makefile index 6d0b8f5e022..a99959d973d 100644 --- a/graphics/microwindows/Makefile +++ b/graphics/microwindows/Makefile @@ -33,7 +33,7 @@ MICROWINDOWS_DIR_NAME = microwindows WD := ${shell echo $(CURDIR) | sed -e 's/ /\\ /g'} -MICROWINDOWS_COMMIT_HASH := 1e71398cc6f650687f406547230c33788eeaf9c7 +MICROWINDOWS_COMMIT_HASH := 7a2ff57052d8663cbca4863709a8ee75bf9fa0c2 #CONFIG_GRAPH_MICROWINDOWS_URL ?= "https://codeload.github.com/ghaerr/microwindows/zip/refs/heads/master" CONFIG_GRAPH_MICROWINDOWS_URL ?= https://codeload.github.com/ghaerr/microwindows/zip/$(MICROWINDOWS_COMMIT_HASH)