From 5057414aefd4d2c869fc9937b48dfdd1910fb573 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Fri, 11 Nov 2011 10:52:51 +0800 Subject: [PATCH] Usermode/AxWin3 - Added menu render code (with hilights) - Note, due to the slowness of the final blit, hilight is VERY laggy --- .../Applications/axwin3_src/Interface/main.c | 2 +- Usermode/Applications/axwin3_src/WM/Makefile | 1 + .../axwin3_src/WM/include/wm_messages.h | 6 + Usermode/Applications/axwin3_src/WM/ipc.c | 13 +- Usermode/Applications/axwin3_src/WM/main.c | 2 + .../axwin3_src/WM/renderer_menu.c | 351 ++++++++++++++---- .../axwin3_src/WM/renderer_widget.c | 14 +- .../axwin3_src/WM/renderer_widget_decorator.c | 10 +- Usermode/Applications/axwin3_src/WM/wm.c | 6 +- .../Applications/axwin3_src/WM/wm_input.c | 24 +- .../axwin3_src/libaxwin3.so_src/r_menu.c | 12 +- 11 files changed, 349 insertions(+), 92 deletions(-) diff --git a/Usermode/Applications/axwin3_src/Interface/main.c b/Usermode/Applications/axwin3_src/Interface/main.c index 0065686b..b4f01995 100644 --- a/Usermode/Applications/axwin3_src/Interface/main.c +++ b/Usermode/Applications/axwin3_src/Interface/main.c @@ -99,7 +99,7 @@ void mainmenu_run_dialog(void *unused) void create_mainmenu(void) { - gSystemMenu = AxWin3_Menu_Create(gSidebar); + gSystemMenu = AxWin3_Menu_Create(NULL); AxWin3_Menu_AddItem(gSystemMenu, "Text &Editor\tWin+E", mainmenu_app_textedit, NULL, 0, NULL); AxWin3_Menu_AddItem(gSystemMenu, NULL, NULL, NULL, 0, NULL); diff --git a/Usermode/Applications/axwin3_src/WM/Makefile b/Usermode/Applications/axwin3_src/WM/Makefile index 60c3920d..986ed6d6 100644 --- a/Usermode/Applications/axwin3_src/WM/Makefile +++ b/Usermode/Applications/axwin3_src/WM/Makefile @@ -10,6 +10,7 @@ OBJ := main.o input.o video.o ipc.o image.o OBJ += wm.o wm_input.o wm_render.o wm_render_text.o OBJ += renderer_classes.o renderer_passthru.o renderer_background.o OBJ += renderer_widget.o renderer_widget_decorator.o +OBJ += renderer_menu.o LDFLAGS += -limage_sif -luri -lnet diff --git a/Usermode/Applications/axwin3_src/WM/include/wm_messages.h b/Usermode/Applications/axwin3_src/WM/include/wm_messages.h index 4b7708d0..e4b46225 100644 --- a/Usermode/Applications/axwin3_src/WM/include/wm_messages.h +++ b/Usermode/Applications/axwin3_src/WM/include/wm_messages.h @@ -37,6 +37,12 @@ struct sWndMsg_Resize uint16_t W, H; }; +struct sWndMsg_MouseMove +{ + int16_t X, Y; + int16_t dX, dY; +}; + struct sWndMsg_MouseButton { uint16_t X, Y; diff --git a/Usermode/Applications/axwin3_src/WM/ipc.c b/Usermode/Applications/axwin3_src/WM/ipc.c index aa02016c..da56149b 100644 --- a/Usermode/Applications/axwin3_src/WM/ipc.c +++ b/Usermode/Applications/axwin3_src/WM/ipc.c @@ -284,10 +284,19 @@ int IPC_Msg_CreateWin(tIPC_Client *Client, tAxWin_IPCMessage *Msg) // - Sanity checks // > +1 is for NULL byte on string - if( Msg->Size < sizeof(tIPCMsg_CreateWin) + 1 ) + if( Msg->Size < sizeof(*info) + 1 ) { + _SysDebug("IPC_Msg_CreateWin: Size check 1 failed"); return -1; - if( info->Renderer[Msg->Size - sizeof(tIPCMsg_CreateWin)] != '\0' ) + } + if( info->Renderer[Msg->Size - sizeof(*info) - 1] != '\0' ) { + _SysDebug("IPC_Msg_CreateWin: Size check 2 failed"); + _SysDebug("info = {"); + _SysDebug(" .NewWinID = %i", info->NewWinID); + _SysDebug(" .RendererArg = %i", info->RendererArg); + _SysDebug(" .Renderer = '%.*s'", Msg->Size - sizeof(*info), info->Renderer); + _SysDebug("}"); return -1; + } // - Get the parent window ID parent = IPC_int_GetWindow(Client, Msg->Window); diff --git a/Usermode/Applications/axwin3_src/WM/main.c b/Usermode/Applications/axwin3_src/WM/main.c index 5b0e5ff3..a2e1fdae 100644 --- a/Usermode/Applications/axwin3_src/WM/main.c +++ b/Usermode/Applications/axwin3_src/WM/main.c @@ -13,6 +13,7 @@ // === IMPORTS === extern void Video_Setup(void); extern void WM_Initialise(void); +extern int Renderer_Menu_Init(void); extern int Renderer_Widget_Init(void); extern int Renderer_Background_Init(void); extern void WM_Update(void); @@ -56,6 +57,7 @@ int main(int argc, char *argv[]) IPC_Init(); Input_Init(); + Renderer_Menu_Init(); Renderer_Widget_Init(); Renderer_Background_Init(); WM_Initialise(); diff --git a/Usermode/Applications/axwin3_src/WM/renderer_menu.c b/Usermode/Applications/axwin3_src/WM/renderer_menu.c index bf8b8453..d4e078bd 100644 --- a/Usermode/Applications/axwin3_src/WM/renderer_menu.c +++ b/Usermode/Applications/axwin3_src/WM/renderer_menu.c @@ -6,7 +6,11 @@ * - Pop-up menu window class/renderer */ #include +#include #include +#include +#include +#include // === STRUCTURES === typedef struct sMenuItem @@ -29,13 +33,38 @@ typedef struct sMenuItem typedef struct sMenuWindowInfo { int MaxLabelWidth; - int MinLabelWidth; - + int MaxShortcutWidth; + int CachedW; + + int HilightedItem; + int MaxItems; int nItems; tMenuItem *Items[]; } tMenuWindowInfo; +// === PROTOTYPES === +void Renderer_Menu_Init(void); +tWindow *Renderer_Menu_Create(int Argument); +void Renderer_Menu_Redraw(tWindow *Window); + int Renderer_Menu_HandleMessage(tWindow *Window, int Msg, int Length, void *Data); + +// === CONSTANTS === +const int ciMenu_Gap = 10; // Gap between label and shortcut +const int ciMenu_TopPadding = 2; +const int ciMenu_BottomPadding = 2; +const int ciMenu_LeftPadding = 2; +const int ciMenu_RightPadding = 2; +const int ciMenu_FontHeight = 16; +const int ciMenu_ItemHeight = 20; +const int ciMenu_SpacerHeight = 5; +const tColour cMenu_BackgroundColour = 0xCCCCCC; +const tColour cMenu_BorderColour = 0x000000; +const tColour cMenu_SpacerColour = 0x404040; +const tColour cMenu_LabelColour = 0x000000; +const tColour cMenu_ShortcutColour = 0x404040; +const tColour cMenu_HilightColour = 0xE0E0E0; + // === GLOBALS === tWMRenderer gRenderer_Menu = { .Name = "Menu", @@ -43,6 +72,7 @@ tWMRenderer gRenderer_Menu = { .Redraw = Renderer_Menu_Redraw, .HandleMessage = Renderer_Menu_HandleMessage }; +tFont *gMenu_Font = NULL; // System monospace // === CODE === void Renderer_Menu_Init(void) @@ -61,101 +91,282 @@ tWindow *Renderer_Menu_Create(int Argument) ret = WM_CreateWindowStruct(sizeof(*info) + Argument*sizeof(info->Items[0])); info = ret->RendererInfo; info->MaxItems = Argument; + info->HilightedItem = -1; + + _SysDebug("Renderer_Menu_Create: ->MaxItems = %i", info->MaxItems); return ret; } void Renderer_Menu_Redraw(tWindow *Window) { - // TODO: Implement Renderer_Menu_Redraw - + tMenuWindowInfo *info = Window->RendererInfo; + int w, h, y, i; + _SysDebug("TODO: Implement Renderer_Menu_Redraw"); + +// _SysDebug("info->nItems = %i", info->nItems); + + w = info->CachedW; + h = ciMenu_TopPadding + ciMenu_BottomPadding; + for( i = 0; i < info->nItems; i ++ ) + { + if( !info->Items[i] ) continue; + + if(info->Items[i]->Label) + h += ciMenu_ItemHeight; + else + h += ciMenu_SpacerHeight; + } + +// _SysDebug("w = %i, h = %i", w, h); + // - Resize window to contain all items + WM_ResizeWindow(Window, w, h); // - Move the window such that it is on screen // > Make sure to catch if the menu can't fit fully onscreen + // - Clear + WM_Render_FillRect(Window, 0, 0, w, h, cMenu_BackgroundColour); + WM_Render_DrawRect(Window, 0, 0, w, h, cMenu_BorderColour); + // - Render each item + y = ciMenu_TopPadding; + for( i = 0; i < info->nItems; i ++ ) + { + tMenuItem *item = info->Items[i]; + + // Unused slot + if(!item) continue; + + // Spacer + if(!item->Label) + { + WM_Render_FillRect(Window, + 1, y + ciMenu_SpacerHeight/2, + w-2, 1, + cMenu_SpacerColour + ); + y += ciMenu_SpacerHeight; + continue ; + } + + // Hilight + if( info->HilightedItem == i ) + { + WM_Render_FillRect(Window, + 1, y, + w-2, ciMenu_ItemHeight, + cMenu_HilightColour + ); + } + + // Text + WM_Render_DrawText(Window, + ciMenu_LeftPadding, y, + w, ciMenu_ItemHeight, + gMenu_Font, + cMenu_LabelColour, + item->Label + ); + // Underline + if(item->UnderlineW) + { + WM_Render_FillRect(Window, + ciMenu_LeftPadding + item->UnderlineX, y + ciMenu_FontHeight + 1, + item->UnderlineW, 1, + cMenu_LabelColour + ); + } + + // Shortcut key + if(item->Shortcut) + { + WM_Render_DrawText(Window, + w - item->ShortcutWidth - ciMenu_RightPadding, y, + w, ciMenu_ItemHeight, + gMenu_Font, + cMenu_ShortcutColour, + item->Shortcut + ); + } + + y += ciMenu_ItemHeight; + } +} + +int Renderer_Menu_int_AddItem(tWindow *Window, int Length, void *Data) +{ + tMenuWindowInfo *info = Window->RendererInfo; + tMenuMsg_AddItem *req = Data; + tMenuItem *item; + + // Sanity checking + // - Message length + if(Length < sizeof(*req) + 1 || req->Label[Length-sizeof(*req)-1] != '\0') { + _SysDebug("Renderer_Menu_int_AddItem: Size checks failed"); + return -1; + } + // - ID Number + if(req->ID >= info->MaxItems) { + _SysDebug("Renderer_Menu_int_AddItem: ID (%i) >= MaxItems (%i)", + req->ID, info->MaxItems); + return -1; + } + + // Don't overwrite + if(info->Items[req->ID]) return 0; + // Bookkeeping + if(req->ID >= info->nItems) info->nItems = req->ID + 1; + // Allocate + item = malloc(sizeof(tMenuItem)+strlen(req->Label)); + info->Items[req->ID] = item; + + if(req->Label[0] == '\0') + { + // Spacer + item->Label = NULL; + + return 0; + } + + // Actual item + char *dest = item->Data; + char *src = req->Label; + int ofs = 0; + + // - Main label + item->KeyOffset = -1; + item->Label = dest; + for(ofs = 0; *src && *src != '\t'; ofs ++) + { + if(*src == '&') { + *dest = '\0'; + item->KeyOffset = ofs; + src ++; + } + else { + *dest++ = *src++; + } + } + *dest++ = '\0'; + // - Key combo / Shortcut + if(*src) + { + src ++; + item->Shortcut = dest; + strcpy(item->Shortcut, src); + } + else + { + item->Shortcut = NULL; + } + + // Get dimensions + // - Underline (hotkey) + if(item->KeyOffset == -1) + { + item->UnderlineX = 0; + item->UnderlineW = 0; + } + else + { + char tmp = item->Label[item->KeyOffset]; + // Get width of preceding substring + item->Label[item->KeyOffset] = '\0'; + WM_Render_GetTextDims(NULL, item->Label, &item->UnderlineX, NULL); + // Get the width of the underlined character + // TODO: Fix for high UTF-8 characters + item->Label[item->KeyOffset] = tmp; + tmp = item->Label[item->KeyOffset+1]; + item->Label[item->KeyOffset+1] = '\0'; + WM_Render_GetTextDims( + NULL, item->Label+item->KeyOffset, + &item->UnderlineW, NULL + ); + item->Label[item->KeyOffset+1] = tmp; + } + // - Labels + WM_Render_GetTextDims(NULL, item->Label, &item->LabelWidth, NULL); + if(item->Shortcut) + WM_Render_GetTextDims(NULL, item->Shortcut, &item->ShortcutWidth, NULL); + else + item->ShortcutWidth = 0; + + if( item->LabelWidth > info->MaxLabelWidth ) + info->MaxLabelWidth = item->LabelWidth; + if( item->ShortcutWidth > info->MaxShortcutWidth ) + info->MaxShortcutWidth = item->ShortcutWidth; + + if( info->MaxLabelWidth + info->MaxShortcutWidth + ciMenu_Gap > info->CachedW ) + { + info->CachedW = ciMenu_LeftPadding + info->MaxLabelWidth + + ciMenu_Gap + info->MaxShortcutWidth + + ciMenu_RightPadding; + // TODO: Smarter height? + WM_ResizeWindow(Window, info->CachedW, info->nItems*ciMenu_ItemHeight); + } + + return 0; } int Renderer_Menu_HandleMessage(tWindow *Window, int Msg, int Length, void *Data) { switch(Msg) { - case MSG_MENU_ADDITEM: { - tMenuMsg_AddItem *req = Data; - tMenuItem *item; - if(Length < sizeof(*req) + 1) return -1; - if(req->Label[Length-sizeof(*req)] != '\0') return -1; - - if(info->Items[req->ID]) break; - item = malloc(sizeof(tMenuItem)+strlen(req->Label)); - info->Items[req->ID] = item; - - if(req->Label[0] == '\0') + case WNDMSG_MOUSEMOVE: { + tMenuWindowInfo *info = Window->RendererInfo; + struct sWndMsg_MouseMove *msg = Data; + int new_hilight; + + if(Length < sizeof(*msg)) return -1; + + if( msg->X < 0 || msg->X >= Window->W ) { - // Spacer - item->Label = NULL; + new_hilight = -1; } else { - // Actual item - char *dest = item->Data; - char *src = req->Label; - int ofs = 0; - // - Main label - item->KeyOffset = -1; - item->Label = dest; - for(ofs = 0; *src && *src != '\t'; ofs ++) + int i, y; + y = msg->Y; + new_hilight = -1; + for( i = 0; i < info->nItems; i ++ ) { - if(*src == '&') { - *dest = '\0'; - item->KeyOffset = ofs; - src ++; + if( !info->Items[i] ) continue; + + if( !info->Items[i]->Label ) + { + // Spacer - doesn't hilight + if(y < ciMenu_SpacerHeight) { + new_hilight = -1; + break; + } + y -= ciMenu_SpacerHeight; } - else { - *dest++ = *src++; + else + { + // Normal item, set the hilight + if(y < ciMenu_ItemHeight) { + new_hilight = i; + break; + } + y -= ciMenu_ItemHeight; } } - *dest = '\0'; - // - Key combo / Shortcut - if(*src) - { - src ++; - item->Shortcut = dest; - strcpy(item->Shortcut, src); - } - else - { - item->Shortcut = NULL; - } - - // Get dimensions - // - Underline (hotkey) - if(item->KeyOffset == -1) - { - item->UnderlineX = 0; - item->UnderlineW = 0; - } - else - { - char tmp = item->Label[item->KeyOffset]; - item->Label[item->KeyOffset] = '\0'; - WM_Render_GetTextDims(NULL, item->Label, &item->UnderlineX, NULL); - item->Label[item->KeyOffset] = tmp; - tmp = item->Label[item->KeyOffset+1]; - item->Label[item->KeyOffset+1] = '\0'; - WM_Render_GetTextDims(NULL, item->Label+item->KeyOffset, &item->UnderlineW, NULL); - item->Label[item->KeyOffset+1] = tmp; - } - // - Labels - WM_Render_GetTextDims(NULL, item->Label, &item->LabelWidth, NULL); - if(item->Shortcut) - WM_Render_GetTextDims(NULL, item->Shortcut, &item->ShortcutWidth, NULL); - else - item->ShortcutWidth = 0; } - - break; } + + if( new_hilight != info->HilightedItem ) + { + info->HilightedItem = new_hilight; + WM_Invalidate(Window); + } + + return 0; } + + // Manipulation messages + case MSG_MENU_ADDITEM: + _SysDebug("MSG_MENU_ADDITEM"); + return Renderer_Menu_int_AddItem(Window, Length, Data); // Only message to pass to client case MSG_MENU_SELECT: diff --git a/Usermode/Applications/axwin3_src/WM/renderer_widget.c b/Usermode/Applications/axwin3_src/WM/renderer_widget.c index 00768902..2c47bb7e 100644 --- a/Usermode/Applications/axwin3_src/WM/renderer_widget.c +++ b/Usermode/Applications/axwin3_src/WM/renderer_widget.c @@ -182,8 +182,8 @@ void Widget_UpdateDimensions(tElement *Element) dynWith /= nChildren - nFixed; } - _SysDebug("%i - nChildren = %i, nFixed = %i, dynWith = %i, fixedSize = %i", - Element->ID, nChildren, nFixed, dynWith, fixedSize); +// _SysDebug("%i - nChildren = %i, nFixed = %i, dynWith = %i, fixedSize = %i", +// Element->ID, nChildren, nFixed, dynWith, fixedSize); // Get the cross size if( Element->Flags & ELEFLAG_VERTICAL ) @@ -256,8 +256,8 @@ void Widget_UpdatePosition(tElement *Element) if( Element->Flags & ELEFLAG_NORENDER ) return ; - _SysDebug("Widget_UpdatePosition: (Element=%p(%i Type=%i Flags=0x%x))", - Element, Element->ID, Element->Type, Element->Flags); +// _SysDebug("Widget_UpdatePosition: (Element=%p(%i Type=%i Flags=0x%x))", +// Element, Element->ID, Element->Type, Element->Flags); // Initialise x = Element->CachedX + Element->PaddingL; @@ -288,7 +288,7 @@ void Widget_UpdatePosition(tElement *Element) - Element->PaddingT - Element->PaddingB; } - _SysDebug(" Widget_UpdatePosition[%i]: newX = %i, newY = %i", Element->ID, newX, newY); +// _SysDebug(" Widget_UpdatePosition[%i]: newX = %i, newY = %i", Element->ID, newX, newY); // Check for changes, and don't update if there was no change if( newX != child->CachedX || newY != child->CachedY ) @@ -524,6 +524,10 @@ int Renderer_Widget_HandleMessage(tWindow *Target, int Msg, int Len, void *Data) return 0; } + case WNDMSG_MOUSEMOVE: { + _SysDebug("TODO: Support widget mouse move events"); + return 0; } + case WNDMSG_MOUSEBTN: { struct sWndMsg_MouseButton *msg = Data; tWidgetMsg_MouseBtn client_msg; diff --git a/Usermode/Applications/axwin3_src/WM/renderer_widget_decorator.c b/Usermode/Applications/axwin3_src/WM/renderer_widget_decorator.c index ec70a565..e66da733 100644 --- a/Usermode/Applications/axwin3_src/WM/renderer_widget_decorator.c +++ b/Usermode/Applications/axwin3_src/WM/renderer_widget_decorator.c @@ -20,11 +20,11 @@ // === CODE === void Widget_Decorator_RenderWidget(tWindow *Window, tElement *Element) { - _SysDebug("Widget_Decorator_RenderWidget: (Element={Type:%i,(%i,%i) %ix%i})", - Element->Type, - Element->CachedX, Element->CachedY, - Element->CachedW, Element->CachedH - ); +// _SysDebug("Widget_Decorator_RenderWidget: (Element={Type:%i,(%i,%i) %ix%i})", +// Element->Type, +// Element->CachedX, Element->CachedY, +// Element->CachedW, Element->CachedH +// ); #if BORDER_EVERYTHING WM_Render_DrawRect( diff --git a/Usermode/Applications/axwin3_src/WM/wm.c b/Usermode/Applications/axwin3_src/WM/wm.c index bfa86b10..41691554 100644 --- a/Usermode/Applications/axwin3_src/WM/wm.c +++ b/Usermode/Applications/axwin3_src/WM/wm.c @@ -171,8 +171,9 @@ int WM_SendMessage(tWindow *Source, tWindow *Dest, int Message, int Length, void void WM_Invalidate(tWindow *Window) { + _SysDebug("Invalidating %p", Window); // Don't invalidate twice (speedup) - if( !(Window->Flags & WINFLAG_CLEAN) ) return; +// if( !(Window->Flags & WINFLAG_CLEAN) ) return; // Mark for re-render Window->Flags &= ~WINFLAG_CLEAN; @@ -217,7 +218,8 @@ void WM_int_BlitWindow(tWindow *Window) // Ignore hidden windows if( !(Window->Flags & WINFLAG_SHOW) ) return ; - + + _SysDebug("Blit %p to (%i,%i) %ix%i", Window, Window->X, Window->Y, Window->W, Window->H); Video_Blit(Window->RenderBuffer, Window->X, Window->Y, Window->W, Window->H); for( child = Window->FirstChild; child; child = child->NextSibling ) diff --git a/Usermode/Applications/axwin3_src/WM/wm_input.c b/Usermode/Applications/axwin3_src/WM/wm_input.c index 8f51703a..991b74ee 100644 --- a/Usermode/Applications/axwin3_src/WM/wm_input.c +++ b/Usermode/Applications/axwin3_src/WM/wm_input.c @@ -37,8 +37,30 @@ tWindow *WM_int_GetWindowAtPos(int X, int Y) void WM_Input_MouseMoved(int OldX, int OldY, int NewX, int NewY) { - // TODO: Mouse motion events + tWindow *win, *newWin; + struct sWndMsg_MouseMove msg; + + win = WM_int_GetWindowAtPos(OldX, OldY); + msg.X = NewX - win->X; + msg.Y = NewY - win->Y; + msg.dX = NewX - OldX; + msg.dY = NewY - OldY; + WM_SendMessage(NULL, win, WNDMSG_MOUSEMOVE, sizeof(msg), &msg); + + // If the new coordinates are not in a new window + // NOTE: Should this handle crossing over a small window? + // - Nah, no need + newWin = WM_int_GetWindowAtPos(NewX, NewY); + if(win == newWin) return; + // TODO: Send mouseup to match mousedown if the cursor moves out of a window? + + win = newWin; + msg.X = NewX - win->X; + msg.Y = NewY - win->Y; + msg.dX = NewX - OldX; + msg.dY = NewY - OldY; + WM_SendMessage(NULL, win, WNDMSG_MOUSEMOVE, sizeof(msg), &msg); } void WM_Input_MouseButton(int X, int Y, int ButtonIndex, int Pressed) diff --git a/Usermode/Applications/axwin3_src/libaxwin3.so_src/r_menu.c b/Usermode/Applications/axwin3_src/libaxwin3.so_src/r_menu.c index e7bd2bf8..78fa169a 100644 --- a/Usermode/Applications/axwin3_src/libaxwin3.so_src/r_menu.c +++ b/Usermode/Applications/axwin3_src/libaxwin3.so_src/r_menu.c @@ -10,7 +10,6 @@ #include #include #include "include/internal.h" -#include "include/ipc.h" #include // === TYPES === @@ -96,16 +95,17 @@ tAxWin3_MenuItem *AxWin3_Menu_AddItem( ret->SubMenu = SubMenu; { - tAxWin_IPCMessage *msg; tMenuMsg_AddItem *req; - msg = AxWin3_int_AllocateIPCMessage(Menu, MSG_MENU_ADDITEM, 0, sizeof(*req)+strlen(Label)); - req = (void*)msg->Data; + int data_size; + if(!Label) Label = ""; + data_size = sizeof(*req)+strlen(Label)+1; + req = malloc(data_size); req->ID = ret->ID; req->Flags = Flags; req->SubMenuID = AxWin3_int_GetWindowID(SubMenu); strcpy(req->Label, Label); - AxWin3_int_SendIPCMessage(msg); - free(msg); + AxWin3_SendMessage(Menu, Menu, MSG_MENU_ADDITEM, data_size, req); + free(req); } return ret; -- 2.20.1