Index: include/wine/server_protocol.h =================================================================== RCS file: /home/wine/wine/include/wine/server_protocol.h,v retrieving revision 1.128 diff -u -r1.128 server_protocol.h --- include/wine/server_protocol.h 31 Mar 2005 15:36:57 -0000 1.128 +++ include/wine/server_protocol.h 13 Apr 2005 17:40:44 -0000 @@ -32,7 +32,8 @@ struct request_max_size { - int pad[16]; + int pad[26]; + //int pad[16]; }; typedef void *obj_handle_t; @@ -3202,6 +3203,260 @@ #define SET_GLOBAL_TASKMAN_WINDOW 0x04 +struct set_menu_info_request +{ + struct request_header __header; + user_handle_t handle; + unsigned int mask; + unsigned int style; + unsigned int cymax; + unsigned int hbrback; + unsigned int context_help_id; + unsigned int menu_data; + unsigned int flags; + user_handle_t hwnd; + rectangle_t rect; + user_handle_t sysmenu_owner; + user_handle_t owner; + unsigned int focus_item; +}; +struct set_menu_info_reply +{ + struct reply_header __header; + unsigned int style; + unsigned int cymax; + unsigned int hbrback; + unsigned int context_help_id; + unsigned int menu_data; + unsigned int flags; + user_handle_t hwnd; + rectangle_t rect; + user_handle_t sysmenu_owner; + user_handle_t owner; + unsigned int focus_item; + unsigned int nitems; +}; + + +struct insert_menu_item_request +{ + struct request_header __header; + user_handle_t handle; + unsigned int pos; + unsigned int mask; + unsigned int type; + unsigned int state; + unsigned int id; + user_handle_t submenu; + unsigned int bmpchecked; + unsigned int bmpunchecked; + unsigned int item_data; + unsigned int bmpitem; + rectangle_t rect; + /* VARARG(type_data,bytes); */ +}; +struct insert_menu_item_reply +{ + struct reply_header __header; +}; + + +struct set_menu_item_info_request +{ + struct request_header __header; + user_handle_t handle; + unsigned int pos; + unsigned int mask; + unsigned int type; + unsigned int state; + unsigned int id; + user_handle_t submenu; + unsigned int bmpchecked; + unsigned int bmpunchecked; + unsigned int item_data; + unsigned int bmpitem; + rectangle_t rect; + /* VARARG(type_data,bytes); */ +}; +struct set_menu_item_info_reply +{ + struct reply_header __header; + user_handle_t handle; + unsigned int pos; + unsigned int type; + unsigned int state; + unsigned int id; + user_handle_t submenu; + unsigned int bmpchecked; + unsigned int bmpunchecked; + unsigned int item_data; + unsigned int bmpitem; + rectangle_t rect; + unsigned int type_data_size; + /* VARARG(type_data,bytes); */ +}; + + +struct get_menu_request +{ + struct request_header __header; + user_handle_t handle; +}; +struct get_menu_reply +{ + struct reply_header __header; + unsigned int size; + /* VARARG(menu,bytes); */ +}; + + +struct check_menu_radio_item_request +{ + struct request_header __header; + user_handle_t handle; + unsigned int first; + unsigned int last; + unsigned int check; + unsigned int mask; +}; +struct check_menu_radio_item_reply +{ + struct reply_header __header; +}; + + +struct create_menu_request +{ + struct request_header __header; + unsigned int flags; +}; +struct create_menu_reply +{ + struct reply_header __header; + user_handle_t handle; +}; + + +struct remove_menu_item_request +{ + struct request_header __header; + user_handle_t handle; + unsigned int pos; + unsigned int mask; + unsigned int destroy; +}; +struct remove_menu_item_reply +{ + struct reply_header __header; +}; + + +struct destroy_menu_request +{ + struct request_header __header; + user_handle_t handle; +}; +struct destroy_menu_reply +{ + struct reply_header __header; +}; + + +struct set_menu_rects_request +{ + struct request_header __header; + user_handle_t handle; + rectangle_t menu_rect; + /* VARARG(menu_item_rects,bytes); */ +}; +struct set_menu_rects_reply +{ + struct reply_header __header; +}; + + +struct get_default_menu_item_request +{ + struct request_header __header; + user_handle_t handle; + unsigned int pos; + unsigned int mask; +}; +struct get_default_menu_item_reply +{ + struct reply_header __header; + unsigned int item; +}; + + +struct set_default_menu_item_request +{ + struct request_header __header; + user_handle_t handle; + unsigned int pos; + unsigned int mask; +}; +struct set_default_menu_item_reply +{ + struct reply_header __header; +}; + + +struct find_submenu_request +{ + struct request_header __header; + user_handle_t handle; + user_handle_t submenu; +}; +struct find_submenu_reply +{ + struct reply_header __header; + user_handle_t handle; + unsigned int pos; +}; + + +struct hide_subpopup_request +{ + struct request_header __header; + user_handle_t handle; +}; +struct hide_subpopup_reply +{ + struct reply_header __header; + user_handle_t submenu; + user_handle_t hwnd; +}; + + +struct find_parent_menu_request +{ + struct request_header __header; + user_handle_t topmost; + user_handle_t child; +}; +struct find_parent_menu_reply +{ + struct reply_header __header; + user_handle_t parent; +}; + +#define SET_MI_CHECK 0x10000000 +#define SET_MI_UNCHECK 0x20000000 +#define SET_MI_ENABLED 0x40000000 +#define SET_MI_GRAYED 0x80000000 +#define SET_MI_DISABLED 0x01000000 +#define SET_MI_HILITE 0x02000000 +#define SET_MI_UNHILITE 0x04000000 +#define SET_MI_BYPOS 0x08000000 +#define SET_MI_RECT 0x00100000 +#define SET_MI_FLAGS 0x00200000 +#define SET_MI_HWND 0x00400000 +#define SET_MI_SYSMENU 0x00800000 +#define SET_MI_OWNER 0x00010000 +#define SET_MI_FOCUSITEM 0x00020000 + + struct adjust_token_privileges_request { struct request_header __header; @@ -3481,6 +3736,20 @@ REQ_set_clipboard_info, REQ_open_token, REQ_set_global_windows, + REQ_set_menu_info, + REQ_insert_menu_item, + REQ_set_menu_item_info, + REQ_get_menu, + REQ_check_menu_radio_item, + REQ_create_menu, + REQ_remove_menu_item, + REQ_destroy_menu, + REQ_set_menu_rects, + REQ_get_default_menu_item, + REQ_set_default_menu_item, + REQ_find_submenu, + REQ_hide_subpopup, + REQ_find_parent_menu, REQ_adjust_token_privileges, REQ_get_token_privileges, REQ_duplicate_token, @@ -3676,6 +3945,20 @@ struct set_clipboard_info_request set_clipboard_info_request; struct open_token_request open_token_request; struct set_global_windows_request set_global_windows_request; + struct set_menu_info_request set_menu_info_request; + struct insert_menu_item_request insert_menu_item_request; + struct set_menu_item_info_request set_menu_item_info_request; + struct get_menu_request get_menu_request; + struct check_menu_radio_item_request check_menu_radio_item_request; + struct create_menu_request create_menu_request; + struct remove_menu_item_request remove_menu_item_request; + struct destroy_menu_request destroy_menu_request; + struct set_menu_rects_request set_menu_rects_request; + struct get_default_menu_item_request get_default_menu_item_request; + struct set_default_menu_item_request set_default_menu_item_request; + struct find_submenu_request find_submenu_request; + struct hide_subpopup_request hide_subpopup_request; + struct find_parent_menu_request find_parent_menu_request; struct adjust_token_privileges_request adjust_token_privileges_request; struct get_token_privileges_request get_token_privileges_request; struct duplicate_token_request duplicate_token_request; @@ -3869,6 +4152,20 @@ struct set_clipboard_info_reply set_clipboard_info_reply; struct open_token_reply open_token_reply; struct set_global_windows_reply set_global_windows_reply; + struct set_menu_info_reply set_menu_info_reply; + struct insert_menu_item_reply insert_menu_item_reply; + struct set_menu_item_info_reply set_menu_item_info_reply; + struct get_menu_reply get_menu_reply; + struct check_menu_radio_item_reply check_menu_radio_item_reply; + struct create_menu_reply create_menu_reply; + struct remove_menu_item_reply remove_menu_item_reply; + struct destroy_menu_reply destroy_menu_reply; + struct set_menu_rects_reply set_menu_rects_reply; + struct get_default_menu_item_reply get_default_menu_item_reply; + struct set_default_menu_item_reply set_default_menu_item_reply; + struct find_submenu_reply find_submenu_reply; + struct hide_subpopup_reply hide_subpopup_reply; + struct find_parent_menu_reply find_parent_menu_reply; struct adjust_token_privileges_reply adjust_token_privileges_reply; struct get_token_privileges_reply get_token_privileges_reply; struct duplicate_token_reply duplicate_token_reply; @@ -3877,6 +4174,6 @@ struct set_mailslot_info_reply set_mailslot_info_reply; }; -#define SERVER_PROTOCOL_VERSION 166 +#define SERVER_PROTOCOL_VERSION 168 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */ Index: server/Makefile.in =================================================================== RCS file: /home/wine/wine/server/Makefile.in,v retrieving revision 1.54 diff -u -r1.54 Makefile.in --- server/Makefile.in 30 Mar 2005 19:02:15 -0000 1.54 +++ server/Makefile.in 13 Apr 2005 17:40:44 -0000 @@ -24,6 +24,7 @@ mailslot.c \ main.c \ mapping.c \ + menu.c \ mutex.c \ named_pipe.c \ object.c \ Index: server/protocol.def =================================================================== RCS file: /home/wine/wine/server/protocol.def,v retrieving revision 1.127 diff -u -r1.127 protocol.def --- server/protocol.def 31 Mar 2005 15:36:57 -0000 1.127 +++ server/protocol.def 13 Apr 2005 17:40:45 -0000 @@ -48,7 +48,8 @@ /* this is used to construct the generic_request union */ struct request_max_size { - int pad[16]; /* the max request size is 16 ints */ + int pad[26]; /* the max request size is 16 ints */ + //int pad[16]; /* the max request size is 16 ints */ }; typedef void *obj_handle_t; @@ -2248,6 +2249,190 @@ #define SET_GLOBAL_SHELL_WINDOWS 0x01 /* set both main shell and listview windows */ #define SET_GLOBAL_PROGMAN_WINDOW 0x02 #define SET_GLOBAL_TASKMAN_WINDOW 0x04 + +/* Set/get menu info */ +@REQ(set_menu_info) + user_handle_t handle; + unsigned int mask; + unsigned int style; + unsigned int cymax; + unsigned int hbrback; + unsigned int context_help_id; + unsigned int menu_data; + unsigned int flags; + user_handle_t hwnd; + rectangle_t rect; + user_handle_t sysmenu_owner; + user_handle_t owner; + unsigned int focus_item; +@REPLY + unsigned int style; + unsigned int cymax; + unsigned int hbrback; + unsigned int context_help_id; + unsigned int menu_data; + unsigned int flags; + user_handle_t hwnd; + rectangle_t rect; + user_handle_t sysmenu_owner; + user_handle_t owner; + unsigned int focus_item; + unsigned int nitems; +@END + +/* Insert meuu item */ +@REQ(insert_menu_item) + user_handle_t handle; + unsigned int pos; + unsigned int mask; + unsigned int type; + unsigned int state; + unsigned int id; + user_handle_t submenu; + unsigned int bmpchecked; + unsigned int bmpunchecked; + unsigned int item_data; + unsigned int bmpitem; + rectangle_t rect; + VARARG(type_data,bytes); +@REPLY +@END + +/* Set/get meuu item info */ +@REQ(set_menu_item_info) + user_handle_t handle; + unsigned int pos; + unsigned int mask; + unsigned int type; + unsigned int state; + unsigned int id; + user_handle_t submenu; + unsigned int bmpchecked; + unsigned int bmpunchecked; + unsigned int item_data; + unsigned int bmpitem; + rectangle_t rect; + VARARG(type_data,bytes); +@REPLY + user_handle_t handle; + unsigned int pos; + unsigned int type; + unsigned int state; + unsigned int id; + user_handle_t submenu; + unsigned int bmpchecked; + unsigned int bmpunchecked; + unsigned int item_data; + unsigned int bmpitem; + rectangle_t rect; + unsigned int type_data_size; + VARARG(type_data,bytes); +@END + +/* Get menu */ +@REQ(get_menu) + user_handle_t handle; +@REPLY + unsigned int size; + VARARG(menu,bytes); +@END + +/* check menu radio item */ +@REQ(check_menu_radio_item) + user_handle_t handle; + unsigned int first; + unsigned int last; + unsigned int check; + unsigned int mask; +@REPLY +@END + +/* Create a menu */ +@REQ(create_menu) + unsigned int flags; +@REPLY + user_handle_t handle; +@END + +/* remove menu item */ +@REQ(remove_menu_item) + user_handle_t handle; + unsigned int pos; + unsigned int mask; + unsigned int destroy; +@REPLY +@END + +/* destroy menu */ +@REQ(destroy_menu) + user_handle_t handle; +@REPLY +@END + +/* set menu item rects */ +@REQ(set_menu_rects) + user_handle_t handle; + rectangle_t menu_rect; + VARARG(menu_item_rects,bytes); +@REPLY +@END + +/* get default menu item */ +@REQ(get_default_menu_item) + user_handle_t handle; + unsigned int pos; + unsigned int mask; +@REPLY + unsigned int item; +@END + +/* set default menu item */ +@REQ(set_default_menu_item) + user_handle_t handle; + unsigned int pos; + unsigned int mask; +@REPLY +@END + +/* set default menu item */ +@REQ(find_submenu) + user_handle_t handle; + user_handle_t submenu; +@REPLY + user_handle_t handle; + unsigned int pos; +@END + +/* set default menu item */ +@REQ(hide_subpopup) + user_handle_t handle; +@REPLY + user_handle_t submenu; /* hmenu of active submenu */ + user_handle_t hwnd; /* hwnd of active submenu */ +@END + +/* set default menu item */ +@REQ(find_parent_menu) + user_handle_t topmost; /* topmost menu */ + user_handle_t child; /* child menu */ +@REPLY + user_handle_t parent; +@END + +#define SET_MI_CHECK 0x10000000 +#define SET_MI_UNCHECK 0x20000000 +#define SET_MI_ENABLED 0x40000000 +#define SET_MI_GRAYED 0x80000000 +#define SET_MI_DISABLED 0x01000000 +#define SET_MI_HILITE 0x02000000 +#define SET_MI_UNHILITE 0x04000000 +#define SET_MI_BYPOS 0x08000000 +#define SET_MI_RECT 0x00100000 +#define SET_MI_FLAGS 0x00200000 +#define SET_MI_HWND 0x00400000 +#define SET_MI_SYSMENU 0x00800000 +#define SET_MI_OWNER 0x00010000 +#define SET_MI_FOCUSITEM 0x00020000 /* Adjust the privileges held by a token */ @REQ(adjust_token_privileges) Index: server/request.h =================================================================== RCS file: /home/wine/wine/server/request.h,v retrieving revision 1.110 diff -u -r1.110 request.h --- server/request.h 30 Mar 2005 19:02:15 -0000 1.110 +++ server/request.h 13 Apr 2005 17:40:45 -0000 @@ -285,6 +285,20 @@ DECL_HANDLER(set_clipboard_info); DECL_HANDLER(open_token); DECL_HANDLER(set_global_windows); +DECL_HANDLER(set_menu_info); +DECL_HANDLER(insert_menu_item); +DECL_HANDLER(set_menu_item_info); +DECL_HANDLER(get_menu); +DECL_HANDLER(check_menu_radio_item); +DECL_HANDLER(create_menu); +DECL_HANDLER(remove_menu_item); +DECL_HANDLER(destroy_menu); +DECL_HANDLER(set_menu_rects); +DECL_HANDLER(get_default_menu_item); +DECL_HANDLER(set_default_menu_item); +DECL_HANDLER(find_submenu); +DECL_HANDLER(hide_subpopup); +DECL_HANDLER(find_parent_menu); DECL_HANDLER(adjust_token_privileges); DECL_HANDLER(get_token_privileges); DECL_HANDLER(duplicate_token); @@ -479,6 +493,20 @@ (req_handler)req_set_clipboard_info, (req_handler)req_open_token, (req_handler)req_set_global_windows, + (req_handler)req_set_menu_info, + (req_handler)req_insert_menu_item, + (req_handler)req_set_menu_item_info, + (req_handler)req_get_menu, + (req_handler)req_check_menu_radio_item, + (req_handler)req_create_menu, + (req_handler)req_remove_menu_item, + (req_handler)req_destroy_menu, + (req_handler)req_set_menu_rects, + (req_handler)req_get_default_menu_item, + (req_handler)req_set_default_menu_item, + (req_handler)req_find_submenu, + (req_handler)req_hide_subpopup, + (req_handler)req_find_parent_menu, (req_handler)req_adjust_token_privileges, (req_handler)req_get_token_privileges, (req_handler)req_duplicate_token, Index: server/trace.c =================================================================== RCS file: /home/wine/wine/server/trace.c,v retrieving revision 1.232 diff -u -r1.232 trace.c --- server/trace.c 31 Mar 2005 15:36:57 -0000 1.232 +++ server/trace.c 13 Apr 2005 17:40:45 -0000 @@ -2659,6 +2659,210 @@ fprintf( stderr, " old_taskman_window=%p", req->old_taskman_window ); } +static void dump_set_menu_info_request( const struct set_menu_info_request *req ) +{ + fprintf( stderr, " handle=%p,", req->handle ); + fprintf( stderr, " mask=%08x,", req->mask ); + fprintf( stderr, " style=%08x,", req->style ); + fprintf( stderr, " cymax=%08x,", req->cymax ); + fprintf( stderr, " hbrback=%08x,", req->hbrback ); + fprintf( stderr, " context_help_id=%08x,", req->context_help_id ); + fprintf( stderr, " menu_data=%08x,", req->menu_data ); + fprintf( stderr, " flags=%08x,", req->flags ); + fprintf( stderr, " hwnd=%p,", req->hwnd ); + fprintf( stderr, " rect=" ); + dump_rectangle( &req->rect ); + fprintf( stderr, "," ); + fprintf( stderr, " sysmenu_owner=%p,", req->sysmenu_owner ); + fprintf( stderr, " owner=%p,", req->owner ); + fprintf( stderr, " focus_item=%08x", req->focus_item ); +} + +static void dump_set_menu_info_reply( const struct set_menu_info_reply *req ) +{ + fprintf( stderr, " style=%08x,", req->style ); + fprintf( stderr, " cymax=%08x,", req->cymax ); + fprintf( stderr, " hbrback=%08x,", req->hbrback ); + fprintf( stderr, " context_help_id=%08x,", req->context_help_id ); + fprintf( stderr, " menu_data=%08x,", req->menu_data ); + fprintf( stderr, " flags=%08x,", req->flags ); + fprintf( stderr, " hwnd=%p,", req->hwnd ); + fprintf( stderr, " rect=" ); + dump_rectangle( &req->rect ); + fprintf( stderr, "," ); + fprintf( stderr, " sysmenu_owner=%p,", req->sysmenu_owner ); + fprintf( stderr, " owner=%p,", req->owner ); + fprintf( stderr, " focus_item=%08x,", req->focus_item ); + fprintf( stderr, " nitems=%08x", req->nitems ); +} + +static void dump_insert_menu_item_request( const struct insert_menu_item_request *req ) +{ + fprintf( stderr, " handle=%p,", req->handle ); + fprintf( stderr, " pos=%08x,", req->pos ); + fprintf( stderr, " mask=%08x,", req->mask ); + fprintf( stderr, " type=%08x,", req->type ); + fprintf( stderr, " state=%08x,", req->state ); + fprintf( stderr, " id=%08x,", req->id ); + fprintf( stderr, " submenu=%p,", req->submenu ); + fprintf( stderr, " bmpchecked=%08x,", req->bmpchecked ); + fprintf( stderr, " bmpunchecked=%08x,", req->bmpunchecked ); + fprintf( stderr, " item_data=%08x,", req->item_data ); + fprintf( stderr, " bmpitem=%08x,", req->bmpitem ); + fprintf( stderr, " rect=" ); + dump_rectangle( &req->rect ); + fprintf( stderr, "," ); + fprintf( stderr, " type_data=" ); + dump_varargs_bytes( cur_size ); +} + +static void dump_set_menu_item_info_request( const struct set_menu_item_info_request *req ) +{ + fprintf( stderr, " handle=%p,", req->handle ); + fprintf( stderr, " pos=%08x,", req->pos ); + fprintf( stderr, " mask=%08x,", req->mask ); + fprintf( stderr, " type=%08x,", req->type ); + fprintf( stderr, " state=%08x,", req->state ); + fprintf( stderr, " id=%08x,", req->id ); + fprintf( stderr, " submenu=%p,", req->submenu ); + fprintf( stderr, " bmpchecked=%08x,", req->bmpchecked ); + fprintf( stderr, " bmpunchecked=%08x,", req->bmpunchecked ); + fprintf( stderr, " item_data=%08x,", req->item_data ); + fprintf( stderr, " bmpitem=%08x,", req->bmpitem ); + fprintf( stderr, " rect=" ); + dump_rectangle( &req->rect ); + fprintf( stderr, "," ); + fprintf( stderr, " type_data=" ); + dump_varargs_bytes( cur_size ); +} + +static void dump_set_menu_item_info_reply( const struct set_menu_item_info_reply *req ) +{ + fprintf( stderr, " handle=%p,", req->handle ); + fprintf( stderr, " pos=%08x,", req->pos ); + fprintf( stderr, " type=%08x,", req->type ); + fprintf( stderr, " state=%08x,", req->state ); + fprintf( stderr, " id=%08x,", req->id ); + fprintf( stderr, " submenu=%p,", req->submenu ); + fprintf( stderr, " bmpchecked=%08x,", req->bmpchecked ); + fprintf( stderr, " bmpunchecked=%08x,", req->bmpunchecked ); + fprintf( stderr, " item_data=%08x,", req->item_data ); + fprintf( stderr, " bmpitem=%08x,", req->bmpitem ); + fprintf( stderr, " rect=" ); + dump_rectangle( &req->rect ); + fprintf( stderr, "," ); + fprintf( stderr, " type_data_size=%08x,", req->type_data_size ); + fprintf( stderr, " type_data=" ); + dump_varargs_bytes( cur_size ); +} + +static void dump_get_menu_request( const struct get_menu_request *req ) +{ + fprintf( stderr, " handle=%p", req->handle ); +} + +static void dump_get_menu_reply( const struct get_menu_reply *req ) +{ + fprintf( stderr, " size=%08x,", req->size ); + fprintf( stderr, " menu=" ); + dump_varargs_bytes( cur_size ); +} + +static void dump_check_menu_radio_item_request( const struct check_menu_radio_item_request *req ) +{ + fprintf( stderr, " handle=%p,", req->handle ); + fprintf( stderr, " first=%08x,", req->first ); + fprintf( stderr, " last=%08x,", req->last ); + fprintf( stderr, " check=%08x,", req->check ); + fprintf( stderr, " mask=%08x", req->mask ); +} + +static void dump_create_menu_request( const struct create_menu_request *req ) +{ + fprintf( stderr, " flags=%08x", req->flags ); +} + +static void dump_create_menu_reply( const struct create_menu_reply *req ) +{ + fprintf( stderr, " handle=%p", req->handle ); +} + +static void dump_remove_menu_item_request( const struct remove_menu_item_request *req ) +{ + fprintf( stderr, " handle=%p,", req->handle ); + fprintf( stderr, " pos=%08x,", req->pos ); + fprintf( stderr, " mask=%08x,", req->mask ); + fprintf( stderr, " destroy=%08x", req->destroy ); +} + +static void dump_destroy_menu_request( const struct destroy_menu_request *req ) +{ + fprintf( stderr, " handle=%p", req->handle ); +} + +static void dump_set_menu_rects_request( const struct set_menu_rects_request *req ) +{ + fprintf( stderr, " handle=%p,", req->handle ); + fprintf( stderr, " menu_rect=" ); + dump_rectangle( &req->menu_rect ); + fprintf( stderr, "," ); + fprintf( stderr, " menu_item_rects=" ); + dump_varargs_bytes( cur_size ); +} + +static void dump_get_default_menu_item_request( const struct get_default_menu_item_request *req ) +{ + fprintf( stderr, " handle=%p,", req->handle ); + fprintf( stderr, " pos=%08x,", req->pos ); + fprintf( stderr, " mask=%08x", req->mask ); +} + +static void dump_get_default_menu_item_reply( const struct get_default_menu_item_reply *req ) +{ + fprintf( stderr, " item=%08x", req->item ); +} + +static void dump_set_default_menu_item_request( const struct set_default_menu_item_request *req ) +{ + fprintf( stderr, " handle=%p,", req->handle ); + fprintf( stderr, " pos=%08x,", req->pos ); + fprintf( stderr, " mask=%08x", req->mask ); +} + +static void dump_find_submenu_request( const struct find_submenu_request *req ) +{ + fprintf( stderr, " handle=%p,", req->handle ); + fprintf( stderr, " submenu=%p", req->submenu ); +} + +static void dump_find_submenu_reply( const struct find_submenu_reply *req ) +{ + fprintf( stderr, " handle=%p,", req->handle ); + fprintf( stderr, " pos=%08x", req->pos ); +} + +static void dump_hide_subpopup_request( const struct hide_subpopup_request *req ) +{ + fprintf( stderr, " handle=%p", req->handle ); +} + +static void dump_hide_subpopup_reply( const struct hide_subpopup_reply *req ) +{ + fprintf( stderr, " submenu=%p,", req->submenu ); + fprintf( stderr, " hwnd=%p", req->hwnd ); +} + +static void dump_find_parent_menu_request( const struct find_parent_menu_request *req ) +{ + fprintf( stderr, " topmost=%p,", req->topmost ); + fprintf( stderr, " child=%p", req->child ); +} + +static void dump_find_parent_menu_reply( const struct find_parent_menu_reply *req ) +{ + fprintf( stderr, " parent=%p", req->parent ); +} + static void dump_adjust_token_privileges_request( const struct adjust_token_privileges_request *req ) { fprintf( stderr, " handle=%p,", req->handle ); @@ -2927,6 +3131,20 @@ (dump_func)dump_set_clipboard_info_request, (dump_func)dump_open_token_request, (dump_func)dump_set_global_windows_request, + (dump_func)dump_set_menu_info_request, + (dump_func)dump_insert_menu_item_request, + (dump_func)dump_set_menu_item_info_request, + (dump_func)dump_get_menu_request, + (dump_func)dump_check_menu_radio_item_request, + (dump_func)dump_create_menu_request, + (dump_func)dump_remove_menu_item_request, + (dump_func)dump_destroy_menu_request, + (dump_func)dump_set_menu_rects_request, + (dump_func)dump_get_default_menu_item_request, + (dump_func)dump_set_default_menu_item_request, + (dump_func)dump_find_submenu_request, + (dump_func)dump_hide_subpopup_request, + (dump_func)dump_find_parent_menu_request, (dump_func)dump_adjust_token_privileges_request, (dump_func)dump_get_token_privileges_request, (dump_func)dump_duplicate_token_request, @@ -3118,6 +3336,20 @@ (dump_func)dump_set_clipboard_info_reply, (dump_func)dump_open_token_reply, (dump_func)dump_set_global_windows_reply, + (dump_func)dump_set_menu_info_reply, + (dump_func)0, + (dump_func)dump_set_menu_item_info_reply, + (dump_func)dump_get_menu_reply, + (dump_func)0, + (dump_func)dump_create_menu_reply, + (dump_func)0, + (dump_func)0, + (dump_func)0, + (dump_func)dump_get_default_menu_item_reply, + (dump_func)0, + (dump_func)dump_find_submenu_reply, + (dump_func)dump_hide_subpopup_reply, + (dump_func)dump_find_parent_menu_reply, (dump_func)dump_adjust_token_privileges_reply, (dump_func)dump_get_token_privileges_reply, (dump_func)dump_duplicate_token_reply, @@ -3309,6 +3541,20 @@ "set_clipboard_info", "open_token", "set_global_windows", + "set_menu_info", + "insert_menu_item", + "set_menu_item_info", + "get_menu", + "check_menu_radio_item", + "create_menu", + "remove_menu_item", + "destroy_menu", + "set_menu_rects", + "get_default_menu_item", + "set_default_menu_item", + "find_submenu", + "hide_subpopup", + "find_parent_menu", "adjust_token_privileges", "get_token_privileges", "duplicate_token", Index: server/user.h =================================================================== RCS file: /home/wine/wine/server/user.h,v retrieving revision 1.27 diff -u -r1.27 user.h --- server/user.h 22 Feb 2005 19:42:35 -0000 1.27 +++ server/user.h 13 Apr 2005 17:40:45 -0000 @@ -33,6 +33,7 @@ enum user_object { USER_WINDOW = 1, + USER_MENU, USER_HOOK }; --- /dev/null 2005-04-12 16:59:36.148198192 -0400 +++ server/menu.c 2005-01-10 20:32:16.000000000 -0500 @@ -0,0 +1,924 @@ +/* + * Server-side menu handling + * + * Copyright (C) 2004 Ulrich Czekalla for CodeWeavers Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "config.h" +#include "wine/port.h" + +#include +#include + +#include "object.h" +#include "request.h" +#include "user.h" +#include "unicode.h" +#include "winuser.h" + +struct menu +{ + user_handle_t handle; + unsigned int style; + unsigned int cymax; + unsigned int hbrback; + unsigned int context_help_id; + unsigned int menu_data; + + unsigned int flags; + user_handle_t hwnd; /* handle of window containing menu */ + rectangle_t rect; + user_handle_t sysmenu_owner; + user_handle_t owner; + unsigned int nitems; /* number of items in menu */ + + struct menu_item* items; /* array of menu items */ + unsigned char* type_data; /* type data buffer */ + unsigned int type_data_size; + unsigned int refcnt; /* reference count */ + unsigned int focus_item; +}; + +struct menu_item +{ + unsigned int type; + unsigned int state; + unsigned int id; + user_handle_t submenu; + unsigned int bmpchecked; + unsigned int bmpunchecked; + unsigned int item_data; + unsigned int type_data; /* offset into type_data buffer */ + unsigned int type_data_size; + unsigned int bmpitem; + + rectangle_t rect; +}; + +#define MF_DELETED 0x10000000 +#define INVALID_TYPEDATA_OFFSET 0xFFFFFFFF + + /* (other menu->FocusedItem values give the position of the focused item) */ +#define NO_SELECTED_ITEM 0xffff + +#define MENU_ITEM_TYPE(flags) \ + ((flags) & (MF_STRING | MF_BITMAP | MF_OWNERDRAW | MF_SEPARATOR)) + +#define IS_STRING_ITEM(flags) (MENU_ITEM_TYPE ((flags)) == MF_STRING) + +#define MENU_ITEM_TYPEDATA(pmenu, offset) \ + (unsigned char*)(offset == INVALID_TYPEDATA_OFFSET ? NULL : \ + (unsigned char*)pmenu->type_data + offset) + +static void destroy_menu(struct menu *pmenu); + + +/* replace menu data in memory block */ +static unsigned char* replace_data(unsigned char** base, unsigned int* size, + int* offset, unsigned int sel_size, unsigned char* data, unsigned int data_size) +{ + assert((offset < 0) || ((unsigned int)offset + sel_size < *size)); + + if (*offset < 0) /* insert at end */ + { + unsigned char* newbase = mem_alloc(*size + data_size); + + if (!newbase) /* out of memory */ + { + set_error(STATUS_NO_MEMORY); + return NULL; + } + + if (*size) + memcpy(newbase, *base, *size); + + memcpy(newbase + *size, data, data_size); + + free(*base); + *base = newbase; + *offset = *size; + *size += data_size; + } + else if (sel_size != data_size) + { + unsigned char* newbase = mem_alloc(*size + data_size); + + if (!newbase) /* out of memory */ + { + set_error(STATUS_NO_MEMORY); + return NULL; + } + + memcpy(newbase, *base, *offset); + if (data_size) + memcpy(newbase + *offset, data, data_size); + memcpy(newbase + *offset + data_size, *base + *offset + sel_size, + *size - *offset - sel_size); + + free(*base); + *base = newbase; + *size += data_size - sel_size; + + if (!data_size) + *offset = INVALID_TYPEDATA_OFFSET; + } + else + { + memcpy(*base + *offset, data, data_size); + } + + return *base; +} + + +/* retrive a pointer to a menu given its handle */ +static struct menu *get_menu(user_handle_t handle) +{ + struct menu *ret = get_user_object(handle, USER_MENU); + if (!ret) set_error(STATUS_INVALID_HANDLE); + return ret; +} + +/* increment menu reference count */ +int menu_addref(user_handle_t handle) +{ + struct menu* pmenu = get_menu(handle); + + if (pmenu) + pmenu->refcnt++; + + return pmenu != NULL; +} + + +/* increment menu reference count */ +int menu_release(user_handle_t handle) +{ + struct menu* pmenu = get_menu(handle); + + if (pmenu) + { + pmenu->refcnt--; + + if (!pmenu->refcnt && (pmenu->flags & MF_DELETED)) + destroy_menu(pmenu); + } + + return pmenu != NULL; +} + + +/* find a menu item */ +static struct menu_item *menu_find_menu_item(struct menu **pmenu, + unsigned int *pos, unsigned int mask) +{ + struct menu_item* pitem = NULL; + + if (mask & SET_MI_BYPOS) + { + if (*pos < (*pmenu)->nitems) + pitem = &(*pmenu)->items[*pos]; + } + else + { + unsigned int i; + + struct menu_item* pi = (*pmenu)->items; + for (i = 0; i < (*pmenu)->nitems; i++, pi++) + { + if (pi->id == *pos) + { + *pos = i; + pitem = pi; + break; + } + else if ((pi->type & MF_POPUP) && pi->submenu) + { + struct menu *psubmenu = get_menu(pi->submenu); + + if (psubmenu) + { + struct menu_item *subitem = menu_find_menu_item(&psubmenu, pos, mask); + + if (subitem) + { + *pmenu = psubmenu; + pitem = subitem; + break; + } + } + } + } + } + + if (!pitem) + set_error(STATUS_NOT_FOUND); + + return pitem; +} + + +/* set menu item info */ +static void set_menu_item_info(struct menu* pmenu, struct menu_item* pitem, + unsigned int pos, unsigned int mask, struct menu_item* data) +{ + if (mask & MIIM_TYPE ) + { + replace_data(&pmenu->type_data, &pmenu->type_data_size, + &pitem->type_data, pitem->type_data_size, (unsigned char*)data->type_data, data->type_data_size); + pitem->type_data_size = data->type_data_size; + + /* make only MENU_ITEM_TYPE bits in pitem->type equal data->type */ + pitem->type &= ~MENU_ITEM_TYPE(pitem->type); + pitem->type |= MENU_ITEM_TYPE(data->type); + } + + if (mask & MIIM_FTYPE ) + { + /* free the string when the type is changing */ + if ((!IS_STRING_ITEM(data->type)) && IS_STRING_ITEM(pitem->type) && + pitem->type_data != INVALID_TYPEDATA_OFFSET) + { + replace_data(&pmenu->type_data, &pmenu->type_data_size, + &pitem->type_data, pitem->type_data_size, NULL, 0); + } + + pitem->type &= ~MENU_ITEM_TYPE(pitem->type); + pitem->type |= MENU_ITEM_TYPE(data->type); + + if (IS_STRING_ITEM(pitem->type) && !pitem->type_data == INVALID_TYPEDATA_OFFSET) + pitem->type |= MF_SEPARATOR; + } + + if (mask & MIIM_STRING) + { + if (IS_STRING_ITEM(pitem->type)) + { + replace_data(&pmenu->type_data, &pmenu->type_data_size, + &pitem->type_data, pitem->type_data_size, (unsigned char*)data->type_data, data->type_data_size); + pitem->type_data_size = data->type_data_size; + } + } + + if (mask & MIIM_STATE) + { + /* FIXME: MFS_DEFAULT do we have to reset the other menu items? */ + pitem->state = data->state; + } + + if (mask & MIIM_ID) + pitem->id = data->id; + + if (mask & MIIM_SUBMENU) + { + if (pitem->submenu) + menu_release(pitem->submenu); + + pitem->submenu = data->submenu; + + if (pitem->submenu) + { + struct menu* psubmenu = get_menu(pitem->submenu); + + if (psubmenu) + { + psubmenu->flags |= MF_POPUP; + pitem->type |= MF_POPUP; + menu_addref(pitem->submenu); + } + else + /* FIXME: Return an error ? */ + pitem->type &= ~MF_POPUP; + } + else + pitem->type &= ~MF_POPUP; + } + + if (mask & MIIM_CHECKMARKS) + { + if (data->type & MFT_RADIOCHECK) + pitem->type |= MFT_RADIOCHECK; + + pitem->bmpchecked = data->bmpchecked; + pitem->bmpunchecked = data->bmpunchecked; + } + + if (mask & MIIM_DATA) + pitem->item_data = data->item_data; + + if (mask & SET_MI_CHECK) + pitem->state |= MF_CHECKED; + else if (mask & SET_MI_UNCHECK) + pitem->state &= ~MF_CHECKED; + + if (mask & SET_MI_GRAYED) + pitem->state &= ~MF_DISABLED | MF_GRAYED; + else if (mask & SET_MI_DISABLED) + pitem->state &= MF_DISABLED | ~MF_GRAYED; + else if (mask & SET_MI_ENABLED) + pitem->state &= ~(MF_DISABLED | MF_GRAYED); +} + + +/* create a new menu structure */ +static struct menu *create_menu() +{ + struct menu *pmenu; + + if (!(pmenu = mem_alloc(sizeof(struct menu)))) + return NULL; + + ZeroMemory(pmenu, sizeof(struct menu)); + + if (!(pmenu->handle = alloc_user_handle(pmenu, USER_MENU))) + { + free(pmenu); + return NULL; + } + + return pmenu; +} + + +/* remove menu item */ +static void remove_menu_item(struct menu *pmenu, unsigned int pos, + unsigned int mask, unsigned int destroy) +{ + unsigned int items_size; + int item_offset; + struct menu_item* pitem; + + if (!(pitem = menu_find_menu_item(&pmenu, &pos, mask))) + return; + + /* free menu item type data */ + replace_data(&pmenu->type_data, &pmenu->type_data_size, + &pitem->type_data, pitem->type_data_size, NULL, 0); + + /* free submenu if necessary */ + if (destroy && (pitem->type & MF_POPUP) && pitem->submenu) + destroy_menu(get_menu(pitem->submenu)); + + items_size = pmenu->nitems * sizeof(struct menu_item); + item_offset = pos * sizeof(struct menu_item); + + replace_data((unsigned char**)&pmenu->items, &items_size, &item_offset, sizeof(struct menu_item), NULL, 0); + + pmenu->nitems--; +} + + +/* destroy a menu */ +static void destroy_menu(struct menu *pmenu) +{ + unsigned int i; + struct menu_item* pitems; + + pitems = pmenu->items; + + for (i = 0; i < pmenu->nitems; i++, pitems++) + { + if ((pitems->type & MF_POPUP) && (pitems->submenu)) + { + /* if this menu's refcount has gone to zero we no longer + need to keep reference to its submenus */ + if (!pmenu->refcnt) + menu_release(pitems->submenu); + + /* even if our ref count is not zero we need to + recurse in order to set MF_DELETED */ + destroy_menu(get_menu(pitems->submenu)); + } + } + + if (pmenu->refcnt) + pmenu->flags |= MF_DELETED; + else + { + if (pmenu->items) + free(pmenu->items); + + if (pmenu->type_data) + free(pmenu->type_data); + + free_user_handle(pmenu->handle); + + free(pmenu); + } +} + + +/* get default menu item */ +unsigned int get_default_menu_item(user_handle_t hmenu, unsigned int bypos, unsigned int mask) +{ + struct menu *pmenu; + unsigned int item = -1; + + if ((pmenu = get_menu(hmenu)) != NULL) + { + unsigned int i; + + /* reset all default-item flags */ + for (i = 0; i < pmenu->nitems; i++, item++) + if (pmenu->items[i].state & MFS_DEFAULT) + break; + + if (i < pmenu->nitems) + { + struct menu_item *pitem = &pmenu->items[i]; + + /* default: don't return disabled items */ + if ((!(GMDI_USEDISABLED & mask)) && (pitem->state & MFS_DISABLED)) + return -1; + + /* search recursively when needed */ + if ((pitem->type & MF_POPUP) && (mask & GMDI_GOINTOPOPUPS)) + { + UINT ret = get_default_menu_item(pitem->submenu, bypos, mask); + + if (ret != -1) + return ret; + /*else when item not found in submenu, return the popup item */ + } + + if (bypos) + item = i; + else + item = pitem->id; + } + } + + return item; +} + + +/* insert menu item */ +static struct menu_item* insert_menu_item(struct menu *pmenu, unsigned int* newpos, int mask) +{ + unsigned int items_size; + int item_offset; + struct menu_item newitem; + int pos = *newpos; + + /* Initialize empty item */ + memset(&newitem, 0, sizeof(newitem)); + newitem.type_data = INVALID_TYPEDATA_OFFSET; + + /* Find where to insert new item */ + if (mask & SET_MI_BYPOS) + { + if (pos > pmenu->nitems) + pos = -1; + } + else + { + if (!menu_find_menu_item(&pmenu, &pos, mask)) + pos = -1; + } + + items_size = pmenu->nitems * sizeof(struct menu_item); + item_offset = pos < 0 ? -1 : pos * sizeof(struct menu_item); + + replace_data((unsigned char**)&pmenu->items, &items_size, &item_offset, 0, + (unsigned char*)&newitem, sizeof(newitem)); + + pmenu->nitems++; + *newpos = pos < 0 ? pmenu->nitems : pos; + + assert(((unsigned char*)pmenu->items + item_offset) == (unsigned char*)&pmenu->items[*newpos]); + + return &pmenu->items[*newpos]; +} + + +/* set default menu item */ +static void set_default_menu_item(struct menu *pmenu, struct menu_item *pitem) +{ + unsigned int i; + + /* reset all default-item flags */ + for (i = 0; i < pmenu->nitems; i++) + pmenu->items[i].state &= ~MFS_DEFAULT; + + if (pitem) + pitem->state |= MFS_DEFAULT; +} + + +static unsigned int find_submenu(user_handle_t* hmenu, user_handle_t htarget) +{ + unsigned int i; + struct menu* pmenu; + + pmenu = get_menu(hmenu); + if (pmenu) + { + for (i = 0; i < pmenu->nitems; i++) + { + if (!(pmenu->items[i].type & MF_POPUP)) + continue; + + if (pmenu->items[i].submenu == htarget) + return i; + else + { + user_handle_t hsubmenu = pmenu->items[i].submenu; + unsigned int pos = find_submenu(&hsubmenu, htarget); + + if (pos != NO_SELECTED_ITEM) + { + *hmenu = hsubmenu; + return pos; + } + } + } + } + + return NO_SELECTED_ITEM; +} + + +/* set menu item info */ +DECL_HANDLER(set_menu_item_info) +{ + struct menu *pmenu; + struct menu_item data; + struct menu_item *pitem; + unsigned int pos = req->pos; + + if (!(pmenu = get_menu(req->handle))) + return; + + if (!(pitem = menu_find_menu_item(&pmenu, &pos, req->mask))) + return; + + /* set old values */ + reply->handle = pmenu->handle; + reply->pos = pos; + reply->type = pitem->type; + reply->state = pitem->state; + reply->id = pitem->id; + reply->submenu = pitem->submenu; + reply->bmpchecked = pitem->bmpchecked; + reply->bmpunchecked = pitem->bmpunchecked; + reply->item_data = pitem->item_data; + reply->type_data_size = pitem->type_data_size; + + if (pitem->type_data_size) + { + unsigned int maxsize = get_reply_max_size(); + + if (maxsize) + set_reply_data(MENU_ITEM_TYPEDATA(pmenu,pitem->type_data), + pitem->type_data_size < maxsize ? pitem->type_data_size: maxsize); + } + + reply->bmpitem = pitem->bmpitem; + reply->rect = pitem->rect; + + if (req->mask & ~SET_MI_BYPOS) + { + data.type = req->type; + data.state = req->state; + data.id = req->id; + data.submenu = req->submenu; + data.bmpchecked = req->bmpchecked; + data.bmpunchecked = req->bmpunchecked; + data.item_data = req->item_data; + data.type_data = (unsigned int)get_req_data(); + data.type_data_size = get_req_data_size(); + data.bmpitem = req->bmpitem; + data.rect = req->rect; + + set_menu_item_info(pmenu, pitem, pos, req->mask, &data); + } +} + + +/* check menu radio item */ +DECL_HANDLER(check_menu_radio_item) +{ + struct menu *pmenu; + unsigned int mifirst = req->first; + unsigned int milast = req->last; + unsigned int micheck = req->check; + + if (!(pmenu = get_menu(req->handle))) + return; + + if (!menu_find_menu_item(&pmenu, &micheck, req->mask)) + return; + + if (!menu_find_menu_item(&pmenu, &milast, req->mask)) + return; + + if (!menu_find_menu_item(&pmenu, &mifirst, req->mask)) + return; + + if (mifirst > milast || micheck > milast || micheck < mifirst) + { + set_error(STATUS_NOT_FOUND); + return; + } + + while (mifirst <= milast) + { + if (mifirst == micheck) + { + pmenu->items[mifirst].type |= MFT_RADIOCHECK; + pmenu->items[mifirst].state |= MFS_CHECKED; + } + else + { + pmenu->items[mifirst].type &= ~MFT_RADIOCHECK; + pmenu->items[mifirst].state &= ~MFS_CHECKED; + } + + mifirst++; + } +} + + +/* create a menu */ +DECL_HANDLER(create_menu) +{ + struct menu *pmenu; + + reply->handle = 0; + + if ((pmenu = create_menu())) + { + pmenu->flags = req->flags; + reply->handle = pmenu->handle; + } +} + + +/* remove menu item */ +DECL_HANDLER(remove_menu_item) +{ + struct menu *pmenu = get_menu(req->handle); + + if (pmenu) + remove_menu_item(pmenu, req->pos, req->mask, req->destroy); +} + + +/* destroy a menu */ +DECL_HANDLER(destroy_menu) +{ + struct menu *pmenu = get_menu(req->handle); + + if (pmenu) + destroy_menu(pmenu); +} + + +/* cache menu item rects */ +DECL_HANDLER(set_menu_rects) +{ + struct menu *pmenu = get_menu(req->handle); + + if (pmenu) + { + rectangle_t* prects; + unsigned int i; + + if (pmenu->nitems != get_req_data_size() / sizeof(rectangle_t)) + set_error(STATUS_INVALID_PARAMETER); /* FIXME: What error should be set? */ + + prects = (rectangle_t*)get_req_data(); + + for (i = 0; i < pmenu->nitems; i++) + pmenu->items[i].rect = prects[i]; + + pmenu->rect = req->menu_rect; + } +} + + +/* get default menu item */ +DECL_HANDLER(get_default_menu_item) +{ + reply->item = get_default_menu_item(req->handle, req->pos, req->mask); +} + +/* get/set menu info */ +DECL_HANDLER(set_menu_info) +{ + struct menu *pmenu = get_menu(req->handle); + + if (pmenu) + { + reply->hbrback = pmenu->hbrback; + reply->context_help_id = pmenu->context_help_id; + reply->cymax = pmenu->cymax; + reply->menu_data = pmenu->menu_data; + reply->style = pmenu->style; + reply->nitems = pmenu->nitems; + reply->flags = pmenu->flags; + reply->hwnd = pmenu->hwnd; + reply->rect = pmenu->rect; + reply->sysmenu_owner = pmenu->sysmenu_owner; + reply->owner = pmenu->owner; + reply->focus_item = pmenu->focus_item; + reply->nitems = pmenu->nitems; + + if (req->mask & MIM_BACKGROUND) pmenu->hbrback = req->hbrback; + if (req->mask & MIM_HELPID) pmenu->context_help_id = req->context_help_id; + if (req->mask & MIM_MAXHEIGHT) pmenu->cymax = req->cymax; + if (req->mask & MIM_MENUDATA) pmenu->menu_data = req->menu_data; + if (req->mask & MIM_STYLE) pmenu->style = req->style; + if (req->mask & SET_MI_FLAGS) pmenu->flags = req->flags; + if (req->mask & SET_MI_HWND) pmenu->hwnd = req->hwnd; + if (req->mask & SET_MI_RECT) pmenu->rect = req->rect; + if (req->mask & SET_MI_SYSMENU) pmenu->sysmenu_owner = req->sysmenu_owner; + if (req->mask & SET_MI_OWNER) pmenu->owner = req->owner; + + if (req->mask & SET_MI_FOCUSITEM) + { + if (pmenu->focus_item != NO_SELECTED_ITEM) + { + pmenu->items[pmenu->focus_item].state &= ~(MF_HILITE|MF_MOUSESELECT); + pmenu->focus_item = NO_SELECTED_ITEM; + } + + if (req->focus_item != NO_SELECTED_ITEM && req->focus_item < pmenu->nitems) + { + pmenu->focus_item = req->focus_item; + if (!(pmenu->items[pmenu->focus_item].type & MF_SEPARATOR)) + pmenu->items[pmenu->focus_item].state |= MF_HILITE; + } + } + } +} + +/* insert a new menu item */ +DECL_HANDLER(insert_menu_item) +{ + struct menu *pmenu; + struct menu_item *pitem; + struct menu_item data; + unsigned int pos = req->pos; + + pmenu = get_menu(req->handle); + if (pmenu) + { + pitem = insert_menu_item(pmenu, &pos, req->mask); + if (pitem != NULL) + { + data.type = req->type; + data.state = req->state; + data.id = req->id; + data.submenu = req->submenu; + data.bmpchecked = req->bmpchecked; + data.bmpunchecked = req->bmpunchecked; + data.item_data = req->item_data; + data.type_data = (unsigned int)get_req_data(); + data.type_data_size = get_req_data_size(); + data.bmpitem = req->bmpitem; + data.rect = req->rect; + + set_menu_item_info(pmenu, pitem, pos, req->mask, &data); + } + } +} + + +/* set default menu item */ +DECL_HANDLER(set_default_menu_item) +{ + struct menu *pmenu; + struct menu_item *pitem = NULL; + unsigned int pos = req->pos; + + pmenu = get_menu(req->handle); + if (pmenu) + { + if (pos != 0xFFFFFFFF) + pitem = menu_find_menu_item(&pmenu, &pos, req->mask); + + set_default_menu_item(pmenu, pitem); + } +} + + +/* get entire menu in one bulk fetch */ +DECL_HANDLER(get_menu) +{ + unsigned int size; + struct menu *pmenu; + unsigned int items_offset, type_data_offset; + + pmenu = get_menu(req->handle); + if (pmenu) + { + size = sizeof(struct menu); + size += pmenu->nitems * sizeof(struct menu_item); + size += pmenu->type_data_size; + reply->size = size; + + if (size < get_reply_max_size()) + { + unsigned char* data = mem_alloc(size); + + if (!data) /* out of memory */ + { + set_error(STATUS_NO_MEMORY); + return; + } + + items_offset = sizeof(struct menu); + type_data_offset = items_offset + pmenu->nitems * sizeof(struct menu_item); + + memcpy(data, pmenu, sizeof(struct menu)); + memcpy(data + items_offset, pmenu->items, pmenu->nitems * sizeof(struct menu_item)); + memcpy(data + type_data_offset, pmenu->type_data, pmenu->type_data_size); + + /* fixup menu pointers */ + pmenu = (struct menu*)data; + pmenu->items = (struct menu_item*)items_offset; + pmenu->type_data = (unsigned char*)type_data_offset; + + set_reply_data(data, size); + } + } +} + + +/* find submenu position */ +DECL_HANDLER(find_submenu) +{ + reply->handle = req->handle; + reply->pos = find_submenu(&reply->handle, req->submenu); +} + +/* hide and reset active submenu */ +DECL_HANDLER(hide_subpopup) +{ + struct menu *pmenu; + struct menu* psubmenu; + + pmenu = get_menu(req->handle); + if (pmenu) + { + reply->submenu = 0; + reply->hwnd = 0; + + if (pmenu->focus_item != NO_SELECTED_ITEM) + { + if ((pmenu->items[pmenu->focus_item].type & MF_POPUP) && + (pmenu->items[pmenu->focus_item].state & MF_MOUSESELECT)) + { + reply->submenu = pmenu->items[pmenu->focus_item].submenu; + + psubmenu = get_menu(reply->submenu); + if (psubmenu) + reply->hwnd = psubmenu->hwnd; + } + + pmenu->items[pmenu->focus_item].state &= ~(MF_HILITE|MF_MOUSESELECT); + pmenu->focus_item = NO_SELECTED_ITEM; + } + } +} + + +/* hide and reset active submenu */ +DECL_HANDLER(find_parent_menu) +{ + struct menu* pmenu; + user_handle_t parent = req->topmost; + user_handle_t next = req->topmost; + user_handle_t child = req->child; + + reply->parent = 0; + + while ((pmenu = get_menu(parent)) && + (pmenu->focus_item != NO_SELECTED_ITEM) && + (pmenu->items[pmenu->focus_item].type & MF_POPUP) && + (pmenu->items[pmenu->focus_item].state & MF_MOUSESELECT)) + { + next = pmenu->items[pmenu->focus_item].submenu; + if (child == next) + { + reply->parent = parent; + break; + } + parent = next; + } +}