examples/microwindows: add mwdemo demo application

This ports mwdemo.c from Microwindows as a standalone NuttX example
application.  mwdemo is the primary Win32 API demo in the Microwindows
project, featuring 3D graphics, window controls, timer-driven
animation, and bitmap image rendering.

The demo runs on both qemu-intel64:mw and sim:mw configurations.

Signed-off-by: Acfboy <AcfboyU@outlook.com>

examples/microwindows: address review, clean up mwdemo.

- Replace minimal copyright notice with full Apache 2.0 license header
- Use angle brackets for system and microwindows includes
- Remove OS-specific dead code (DOS_TURBOC, RTEMS, EMSCRIPTEN/MULTIAPP)
- Drop unused demo-mode macros and their corresponding dead code paths
  (IMAGE, CLIENT3D, CLIPDEMO, ARCDEMO).  Keep a fixed GRAPH3D+CONTROLS
  configuration as the single NuttX demo.
- Add g_ prefix to global variable (image -> g_image)
- Move demoWndData typedef from mid-file to Private Types section
- Merge WinMain body into main() and remove the WinMain indirection
- Removed unused images.

Signed-off-by: Acfboy <AcfboyU@outlook.com>
This commit is contained in:
Acfboy 2026-07-27 09:04:25 +08:00 committed by Alin Jerpelea
parent ae601e2892
commit ce49ac9053
5 changed files with 540 additions and 0 deletions

View file

@ -0,0 +1,26 @@
config EXAMPLES_MICROWINDOWS
tristate "Microwindows example"
default n
depends on GRAPHICS_MICROWINDOWS
depends on MICROWINDOWS_MWIN
---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

View file

@ -0,0 +1,25 @@
############################################################################
# apps/examples/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_EXAMPLES_MICROWINDOWS),)
CONFIGURED_APPS += $(APPDIR)/examples/microwindows
endif

View file

@ -0,0 +1,55 @@
############################################################################
# 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 = $(CONFIG_EXAMPLES_MICROWINDOWS)
MAINSRC = mwdemo_main.c
CSRCS += mwdemo.c
MW_IMAGES = penguin microwin
CSRCS += $(MW_IMAGES:%=$(MW_IMGDIR)/%.c)
# Generate image .c files from .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)/%.c: $(MW_SRC)/images/demos/mwin/%.bmp $(MW_CONVBMP)
mkdir -p $(MW_IMGDIR)
$(CURDIR)/$(MW_CONVBMP) -o $@ $<
clean::
$(call DELFILE, $(MW_IMAGES:%=$(MW_IMGDIR)/%.c))
$(Q) rmdir $(MW_IMGDIR) 2>/dev/null || true
$(call DELFILE, $(MW_CONVBMP))
CFLAGS += -Wno-undef
CFLAGS += -DNOGDI
include $(APPDIR)/Application.mk

View file

@ -0,0 +1,333 @@
/****************************************************************************
* apps/examples/microwindows/mwdemo.c
*
* Copyright (c) 1999, 2000, 2001, 2010 Greg Haerr <greg@censoft.com>
* 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.
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <stdlib.h>
#include <uni_std.h>
#define MWINCLUDECOLORS
#include <windows.h>
#include <device.h>
#include <graph3d.h>
/****************************************************************************
* Private Types
****************************************************************************/
typedef struct
{
int startdegrees;
int enddegrees;
} demoWndData;
typedef demoWndData *pdemoWndData;
/****************************************************************************
* Private Data
****************************************************************************/
extern MWIMAGEHDR image_penguin;
PMWIMAGEHDR g_image = &image_penguin;
#define APPCLASS "test"
#define APPCHILD "test2"
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg, WPARAM wp, LPARAM lp);
LRESULT CALLBACK ChildWndProc(HWND hwnd, UINT uMsg, WPARAM wp, LPARAM lp);
/****************************************************************************
* Private Functions
****************************************************************************/
int MwUserInit(int ac, char **av)
{
/* test user init procedure - do nothing */
return 0;
}
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);
wc.lpfnWndProc = (WNDPROC) ChildWndProc;
wc.lpszClassName = APPCHILD;
return RegisterClass(&wc);
}
HWND CreateAppWindow(void)
{
HWND hwnd;
static int nextid = 1;
int width;
int 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 (hwnd && (nextid & 03) != 2)
{
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);
}
return hwnd;
}
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);
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, g_image->width,
g_image->height);
hbmpOrg = SelectObject(hdcMem, hbmp);
/* draw onto offscreen dc */
DrawDIB(hdcMem, 0, 0, g_image);
/* blit offscreen with physical screen */
StretchBlt(ps.hdc, 0, 0, rc.right * 4 / 5,
rc.bottom * 4 / 5, hdcMem,
0, 0, g_image->width, g_image->height, MWROP_COPY);
DeleteObject(SelectObject(hdcMem, hbmpOrg));
DeleteDC(hdcMem);
EndPaint(hwnd, &ps);
break;
default:
return DefWindowProc(hwnd, msg, wp, lp);
}
return 0;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
{
PAINTSTRUCT ps;
HDC hdc;
RECT rc;
static int countup = 1;
int id;
static vec1 gx;
static vec1 gy;
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;
SetTimer(hwnd, 1, (50 + random() % 250), NULL);
break;
case WM_TIMER:
pData = (pdemoWndData)(LONG_PTR)GetWindowLongPtr(hwnd, 0);
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));
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;
case WM_ERASEBKGND:
if ((GetWindowLong(hwnd, GWL_ID) & 03) == 1)
{
return 1;
}
return DefWindowProc(hwnd, msg, wp, lp);
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
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(-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;
}
paint3(hdc);
EndPaint(hwnd, &ps);
break;
case WM_MOUSEMOVE:
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;
}
break;
case WM_LBUTTONDOWN:
break;
case WM_LBUTTONUP:
break;
case WM_RBUTTONDOWN:
break;
default:
return DefWindowProc(hwnd, msg, wp, lp);
}
return 0;
}

View file

@ -0,0 +1,101 @@
/****************************************************************************
* apps/examples/microwindows/mwdemo_main.c
*
* 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.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <time.h>
#include <stdlib.h>
#include <uni_std.h>
#include <windows.h>
/****************************************************************************
* Private Data
****************************************************************************/
extern MWIMAGEHDR image_microwin;
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
extern int RegisterAppClass(HINSTANCE hInstance);
extern HWND CreateAppWindow(void);
#define APPCLASS "test"
#define APPCHILD "test2"
/****************************************************************************
* Public Functions
****************************************************************************/
int main(int argc, FAR char *argv[])
{
MSG msg;
HWND hwnd;
RECT rc;
invoke_WinMain_Start(argc, argv);
srandom(time(NULL));
RegisterAppClass(0);
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);
CreateAppWindow();
CreateAppWindow();
CreateAppWindow();
CreateAppWindow();
CreateAppWindow();
CreateAppWindow();
CreateAppWindow();
CreateAppWindow();
/* set background wallpaper */
MwSetDesktopWallpaper(&image_microwin);
hwnd = CreateAppWindow();
GetWindowRect(hwnd, &rc);
OffsetRect(&rc, 50, 50);
MoveWindow(hwnd, rc.left, rc.top,
rc.bottom - rc.top,
rc.right - rc.left, TRUE);
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
invoke_WinMain_End();
return 0;
}