Commit c701734c authored by Jacek Caban's avatar Jacek Caban Committed by Alexandre Julliard

winemac: Use unixlib interface for macdrv_app_quit_request.

parent 80e24bcc
......@@ -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, &params);
}
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,
......
......@@ -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 );
......
......@@ -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
{
......
......@@ -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, &params, sizeof(params));
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment