From: Jacek Caban jacek@codeweavers.com
Signed-off-by: Jacek Caban jacek@codeweavers.com --- dlls/winemac.drv/dllmain.c | 174 +++++++++++++++++++++++++++++++++ dlls/winemac.drv/macdrv_main.c | 9 ++ dlls/winemac.drv/unixlib.h | 16 ++- dlls/winemac.drv/window.c | 168 +------------------------------ 4 files changed, 202 insertions(+), 165 deletions(-)
diff --git a/dlls/winemac.drv/dllmain.c b/dlls/winemac.drv/dllmain.c index 4bedb2aaf61..675820b28cd 100644 --- a/dlls/winemac.drv/dllmain.c +++ b/dlls/winemac.drv/dllmain.c @@ -22,13 +22,187 @@ #include <stdarg.h> #include "macdrv.h" #include "shellapi.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(macdrv);
HMODULE macdrv_module = 0;
+struct quit_info { + HWND *wins; + UINT capacity; + UINT count; + UINT done; + DWORD flags; + BOOL result; + BOOL replied; +}; + + +static BOOL CALLBACK get_process_windows(HWND hwnd, LPARAM lp) +{ + struct quit_info *qi = (struct quit_info*)lp; + DWORD pid; + + NtUserGetWindowThread(hwnd, &pid); + if (pid == GetCurrentProcessId()) + { + if (qi->count >= qi->capacity) + { + UINT new_cap = qi->capacity * 2; + HWND *new_wins = HeapReAlloc(GetProcessHeap(), 0, qi->wins, new_cap * sizeof(*qi->wins)); + if (!new_wins) return FALSE; + qi->wins = new_wins; + qi->capacity = new_cap; + } + + qi->wins[qi->count++] = hwnd; + } + + return TRUE; +} + +static void quit_reply(int reply) +{ + struct quit_result_params params = { .result = reply }; + MACDRV_CALL(quit_result, ¶ms); +} + + +static void CALLBACK quit_callback(HWND hwnd, UINT msg, ULONG_PTR data, LRESULT result) +{ + struct quit_info *qi = (struct quit_info*)data; + + qi->done++; + + if (msg == WM_QUERYENDSESSION) + { + TRACE("got WM_QUERYENDSESSION result %ld from win %p (%u of %u done)\n", result, + hwnd, qi->done, qi->count); + + if (!result && !IsWindow(hwnd)) + { + TRACE("win %p no longer exists; ignoring apparent refusal\n", hwnd); + result = TRUE; + } + + if (!result && qi->result) + { + qi->result = FALSE; + + /* On the first FALSE from WM_QUERYENDSESSION, we already know the + ultimate reply. Might as well tell Cocoa now. */ + if (!qi->replied) + { + qi->replied = TRUE; + TRACE("giving quit reply %d\n", qi->result); + quit_reply(qi->result); + } + } + + if (qi->done >= qi->count) + { + UINT i; + + qi->done = 0; + for (i = 0; i < qi->count; i++) + { + TRACE("sending WM_ENDSESSION to win %p result %d flags 0x%08x\n", qi->wins[i], + qi->result, qi->flags); + if (!SendMessageCallbackW(qi->wins[i], WM_ENDSESSION, qi->result, qi->flags, + quit_callback, (ULONG_PTR)qi)) + { + WARN("failed to send WM_ENDSESSION to win %p; error 0x%08x\n", + qi->wins[i], GetLastError()); + quit_callback(qi->wins[i], WM_ENDSESSION, (ULONG_PTR)qi, 0); + } + } + } + } + else /* WM_ENDSESSION */ + { + TRACE("finished WM_ENDSESSION for win %p (%u of %u done)\n", hwnd, qi->done, qi->count); + + if (qi->done >= qi->count) + { + if (!qi->replied) + { + TRACE("giving quit reply %d\n", qi->result); + quit_reply(qi->result); + } + + TRACE("%sterminating process\n", qi->result ? "" : "not "); + if (qi->result) + TerminateProcess(GetCurrentProcess(), 0); + + HeapFree(GetProcessHeap(), 0, qi->wins); + HeapFree(GetProcessHeap(), 0, qi); + } + } +} + + +/*********************************************************************** + * macdrv_app_quit_request + */ +NTSTATUS WINAPI macdrv_app_quit_request(void *arg, ULONG size) +{ + struct app_quit_request_params *params = arg; + struct quit_info *qi; + UINT i; + + qi = HeapAlloc(GetProcessHeap(), 0, sizeof(*qi)); + if (!qi) + goto fail; + + qi->capacity = 32; + qi->wins = HeapAlloc(GetProcessHeap(), 0, qi->capacity * sizeof(*qi->wins)); + qi->count = qi->done = 0; + + if (!qi->wins || !EnumWindows(get_process_windows, (LPARAM)qi)) + goto fail; + + qi->flags = params->flags; + qi->result = TRUE; + qi->replied = FALSE; + + for (i = 0; i < qi->count; i++) + { + TRACE("sending WM_QUERYENDSESSION to win %p\n", qi->wins[i]); + if (!SendMessageCallbackW(qi->wins[i], WM_QUERYENDSESSION, 0, qi->flags, + quit_callback, (ULONG_PTR)qi)) + { + DWORD error = GetLastError(); + BOOL invalid = (error == ERROR_INVALID_WINDOW_HANDLE); + if (invalid) + TRACE("failed to send WM_QUERYENDSESSION to win %p because it's invalid; assuming success\n", + qi->wins[i]); + else + WARN("failed to send WM_QUERYENDSESSION to win %p; error 0x%08x; assuming refusal\n", + qi->wins[i], error); + quit_callback(qi->wins[i], WM_QUERYENDSESSION, (ULONG_PTR)qi, invalid); + } + } + + /* quit_callback() will clean up qi */ + return 0; + +fail: + WARN("failed to allocate window list\n"); + if (qi) + { + HeapFree(GetProcessHeap(), 0, qi->wins); + HeapFree(GetProcessHeap(), 0, qi); + } + quit_reply(FALSE); + return 0; +} + typedef NTSTATUS (WINAPI *kernel_callback)(void *params, ULONG size); static const kernel_callback kernel_callbacks[] = { + macdrv_app_quit_request, macdrv_dnd_query_drag, macdrv_dnd_query_drop, macdrv_dnd_query_exited, diff --git a/dlls/winemac.drv/macdrv_main.c b/dlls/winemac.drv/macdrv_main.c index 61195d408c8..ddd4f03fd31 100644 --- a/dlls/winemac.drv/macdrv_main.c +++ b/dlls/winemac.drv/macdrv_main.c @@ -628,6 +628,14 @@ static NTSTATUS macdrv_ime_using_input_method(void *arg) }
+static NTSTATUS macdrv_quit_result(void *arg) +{ + struct quit_result_params *params = arg; + macdrv_quit_reply(params->result); + return 0; +} + + const unixlib_entry_t __wine_unix_call_funcs[] = { macdrv_dnd_get_data, @@ -640,6 +648,7 @@ const unixlib_entry_t __wine_unix_call_funcs[] = macdrv_ime_using_input_method, macdrv_init, macdrv_notify_icon, + macdrv_quit_result, };
C_ASSERT( ARRAYSIZE(__wine_unix_call_funcs) == unix_funcs_count ); diff --git a/dlls/winemac.drv/unixlib.h b/dlls/winemac.drv/unixlib.h index 0bfc61321d0..894ab699c13 100644 --- a/dlls/winemac.drv/unixlib.h +++ b/dlls/winemac.drv/unixlib.h @@ -31,6 +31,7 @@ enum macdrv_funcs unix_ime_using_input_method, unix_init, unix_notify_icon, + unix_quit_result, unix_funcs_count };
@@ -92,10 +93,17 @@ struct notify_icon_params struct _NOTIFYICONDATAW *data; };
+/* macdrv_quit_result params */ +struct quit_result_params +{ + int result; +}; + /* driver client callbacks exposed with KernelCallbackTable interface */ enum macdrv_client_funcs { - client_func_dnd_query_drag = NtUserDriverCallbackFirst, + client_func_app_quit_request = NtUserDriverCallbackFirst, + client_func_dnd_query_drag, client_func_dnd_query_drop, client_func_dnd_query_exited, client_func_ime_query_char_rect, @@ -103,6 +111,12 @@ enum macdrv_client_funcs client_func_last };
+/* macdrv_app_quit_request params */ +struct app_quit_request_params +{ + UINT flags; +}; + /* macdrv_dnd_query_drag params */ struct dnd_query_drag_params { diff --git a/dlls/winemac.drv/window.c b/dlls/winemac.drv/window.c index 2f473730b2f..072bdf606d4 100644 --- a/dlls/winemac.drv/window.c +++ b/dlls/winemac.drv/window.c @@ -2653,114 +2653,6 @@ void macdrv_reassert_window_position(HWND hwnd) }
-struct quit_info { - HWND *wins; - UINT capacity; - UINT count; - UINT done; - DWORD flags; - BOOL result; - BOOL replied; -}; - - -static BOOL CALLBACK get_process_windows(HWND hwnd, LPARAM lp) -{ - struct quit_info *qi = (struct quit_info*)lp; - DWORD pid; - - NtUserGetWindowThread(hwnd, &pid); - if (pid == GetCurrentProcessId()) - { - if (qi->count >= qi->capacity) - { - UINT new_cap = qi->capacity * 2; - HWND *new_wins = realloc(qi->wins, new_cap * sizeof(*qi->wins)); - if (!new_wins) return FALSE; - qi->wins = new_wins; - qi->capacity = new_cap; - } - - qi->wins[qi->count++] = hwnd; - } - - return TRUE; -} - - -static void CALLBACK quit_callback(HWND hwnd, UINT msg, ULONG_PTR data, LRESULT result) -{ - struct quit_info *qi = (struct quit_info*)data; - - qi->done++; - - if (msg == WM_QUERYENDSESSION) - { - TRACE("got WM_QUERYENDSESSION result %ld from win %p (%u of %u done)\n", result, - hwnd, qi->done, qi->count); - - if (!result && !IsWindow(hwnd)) - { - TRACE("win %p no longer exists; ignoring apparent refusal\n", hwnd); - result = TRUE; - } - - if (!result && qi->result) - { - qi->result = FALSE; - - /* On the first FALSE from WM_QUERYENDSESSION, we already know the - ultimate reply. Might as well tell Cocoa now. */ - if (!qi->replied) - { - qi->replied = TRUE; - TRACE("giving quit reply %d\n", qi->result); - macdrv_quit_reply(qi->result); - } - } - - if (qi->done >= qi->count) - { - UINT i; - - qi->done = 0; - for (i = 0; i < qi->count; i++) - { - TRACE("sending WM_ENDSESSION to win %p result %d flags 0x%08x\n", qi->wins[i], - qi->result, qi->flags); - if (!SendMessageCallbackW(qi->wins[i], WM_ENDSESSION, qi->result, qi->flags, - quit_callback, (ULONG_PTR)qi)) - { - WARN("failed to send WM_ENDSESSION to win %p; error 0x%08x\n", - qi->wins[i], GetLastError()); - quit_callback(qi->wins[i], WM_ENDSESSION, (ULONG_PTR)qi, 0); - } - } - } - } - else /* WM_ENDSESSION */ - { - TRACE("finished WM_ENDSESSION for win %p (%u of %u done)\n", hwnd, qi->done, qi->count); - - if (qi->done >= qi->count) - { - if (!qi->replied) - { - TRACE("giving quit reply %d\n", qi->result); - macdrv_quit_reply(qi->result); - } - - TRACE("%sterminating process\n", qi->result ? "" : "not "); - if (qi->result) - TerminateProcess(GetCurrentProcess(), 0); - - free(qi->wins); - free(qi); - } - } -} - - /*********************************************************************** * macdrv_app_quit_requested * @@ -2768,66 +2660,14 @@ static void CALLBACK quit_callback(HWND hwnd, UINT msg, ULONG_PTR data, LRESULT */ void macdrv_app_quit_requested(const macdrv_event *event) { - struct quit_info *qi; - UINT i; + struct app_quit_request_params params = { .flags = 0 };
TRACE("reason %d\n", event->app_quit_requested.reason);
- qi = malloc(sizeof(*qi)); - if (!qi) - goto fail; - - qi->capacity = 32; - qi->wins = malloc(qi->capacity * sizeof(*qi->wins)); - qi->count = qi->done = 0; - - if (!qi->wins || !EnumWindows(get_process_windows, (LPARAM)qi)) - goto fail; + if (event->app_quit_requested.reason == QUIT_REASON_LOGOUT) + params.flags = ENDSESSION_LOGOFF;
- switch (event->app_quit_requested.reason) - { - case QUIT_REASON_LOGOUT: - default: - qi->flags = ENDSESSION_LOGOFF; - break; - case QUIT_REASON_RESTART: - case QUIT_REASON_SHUTDOWN: - qi->flags = 0; - break; - } - - qi->result = TRUE; - qi->replied = FALSE; - - for (i = 0; i < qi->count; i++) - { - TRACE("sending WM_QUERYENDSESSION to win %p\n", qi->wins[i]); - if (!SendMessageCallbackW(qi->wins[i], WM_QUERYENDSESSION, 0, qi->flags, - quit_callback, (ULONG_PTR)qi)) - { - DWORD error = GetLastError(); - BOOL invalid = (error == ERROR_INVALID_WINDOW_HANDLE); - if (invalid) - TRACE("failed to send WM_QUERYENDSESSION to win %p because it's invalid; assuming success\n", - qi->wins[i]); - else - WARN("failed to send WM_QUERYENDSESSION to win %p; error 0x%08x; assuming refusal\n", - qi->wins[i], error); - quit_callback(qi->wins[i], WM_QUERYENDSESSION, (ULONG_PTR)qi, invalid); - } - } - - /* quit_callback() will clean up qi */ - return; - -fail: - WARN("failed to allocate window list\n"); - if (qi) - { - free(qi->wins); - free(qi); - } - macdrv_quit_reply(FALSE); + macdrv_client_func(client_func_app_quit_request, ¶ms, sizeof(params)); }