d3dx10: Add support for ID3DX10ThreadPump parameter in D3DX10CreateTextureFromFileW.
[wine.git] / dlls / winemac.drv / dllmain.c
blob0618ec83228023af2d34c8afe68eba7543b84e66
1 /*
2 * winemac.drv entry points
4 * Copyright 2022 Jacek Caban for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include "macdrv_dll.h"
22 #include "macdrv_res.h"
23 #include "shellapi.h"
24 #include "wine/debug.h"
26 WINE_DEFAULT_DEBUG_CHANNEL(macdrv);
29 HMODULE macdrv_module = 0;
30 static unixlib_handle_t macdrv_handle;
31 NTSTATUS (CDECL *macdrv_unix_call)(enum macdrv_funcs code, void *params);
33 struct quit_info {
34 HWND *wins;
35 UINT capacity;
36 UINT count;
37 UINT done;
38 DWORD flags;
39 BOOL result;
40 BOOL replied;
44 static BOOL CALLBACK get_process_windows(HWND hwnd, LPARAM lp)
46 struct quit_info *qi = (struct quit_info*)lp;
47 DWORD pid;
49 NtUserGetWindowThread(hwnd, &pid);
50 if (pid == GetCurrentProcessId())
52 if (qi->count >= qi->capacity)
54 UINT new_cap = qi->capacity * 2;
55 HWND *new_wins = HeapReAlloc(GetProcessHeap(), 0, qi->wins, new_cap * sizeof(*qi->wins));
56 if (!new_wins) return FALSE;
57 qi->wins = new_wins;
58 qi->capacity = new_cap;
61 qi->wins[qi->count++] = hwnd;
64 return TRUE;
67 #include "pshpack1.h"
69 typedef struct
71 BYTE bWidth;
72 BYTE bHeight;
73 BYTE bColorCount;
74 BYTE bReserved;
75 WORD wPlanes;
76 WORD wBitCount;
77 DWORD dwBytesInRes;
78 WORD nID;
79 } GRPICONDIRENTRY;
81 typedef struct
83 WORD idReserved;
84 WORD idType;
85 WORD idCount;
86 GRPICONDIRENTRY idEntries[1];
87 } GRPICONDIR;
89 #include "poppack.h"
91 static void quit_reply(int reply)
93 struct quit_result_params params = { .result = reply };
94 MACDRV_CALL(quit_result, &params);
98 static void CALLBACK quit_callback(HWND hwnd, UINT msg, ULONG_PTR data, LRESULT result)
100 struct quit_info *qi = (struct quit_info*)data;
102 qi->done++;
104 if (msg == WM_QUERYENDSESSION)
106 TRACE("got WM_QUERYENDSESSION result %ld from win %p (%u of %u done)\n", result,
107 hwnd, qi->done, qi->count);
109 if (!result && !IsWindow(hwnd))
111 TRACE("win %p no longer exists; ignoring apparent refusal\n", hwnd);
112 result = TRUE;
115 if (!result && qi->result)
117 qi->result = FALSE;
119 /* On the first FALSE from WM_QUERYENDSESSION, we already know the
120 ultimate reply. Might as well tell Cocoa now. */
121 if (!qi->replied)
123 qi->replied = TRUE;
124 TRACE("giving quit reply %d\n", qi->result);
125 quit_reply(qi->result);
129 if (qi->done >= qi->count)
131 UINT i;
133 qi->done = 0;
134 for (i = 0; i < qi->count; i++)
136 TRACE("sending WM_ENDSESSION to win %p result %d flags 0x%08x\n", qi->wins[i],
137 qi->result, qi->flags);
138 if (!SendMessageCallbackW(qi->wins[i], WM_ENDSESSION, qi->result, qi->flags,
139 quit_callback, (ULONG_PTR)qi))
141 WARN("failed to send WM_ENDSESSION to win %p; error 0x%08x\n",
142 qi->wins[i], GetLastError());
143 quit_callback(qi->wins[i], WM_ENDSESSION, (ULONG_PTR)qi, 0);
148 else /* WM_ENDSESSION */
150 TRACE("finished WM_ENDSESSION for win %p (%u of %u done)\n", hwnd, qi->done, qi->count);
152 if (qi->done >= qi->count)
154 if (!qi->replied)
156 TRACE("giving quit reply %d\n", qi->result);
157 quit_reply(qi->result);
160 TRACE("%sterminating process\n", qi->result ? "" : "not ");
161 if (qi->result)
162 TerminateProcess(GetCurrentProcess(), 0);
164 HeapFree(GetProcessHeap(), 0, qi->wins);
165 HeapFree(GetProcessHeap(), 0, qi);
171 /***********************************************************************
172 * macdrv_app_quit_request
174 NTSTATUS WINAPI macdrv_app_quit_request(void *arg, ULONG size)
176 struct app_quit_request_params *params = arg;
177 struct quit_info *qi;
178 UINT i;
180 qi = HeapAlloc(GetProcessHeap(), 0, sizeof(*qi));
181 if (!qi)
182 goto fail;
184 qi->capacity = 32;
185 qi->wins = HeapAlloc(GetProcessHeap(), 0, qi->capacity * sizeof(*qi->wins));
186 qi->count = qi->done = 0;
188 if (!qi->wins || !EnumWindows(get_process_windows, (LPARAM)qi))
189 goto fail;
191 qi->flags = params->flags;
192 qi->result = TRUE;
193 qi->replied = FALSE;
195 for (i = 0; i < qi->count; i++)
197 TRACE("sending WM_QUERYENDSESSION to win %p\n", qi->wins[i]);
198 if (!SendMessageCallbackW(qi->wins[i], WM_QUERYENDSESSION, 0, qi->flags,
199 quit_callback, (ULONG_PTR)qi))
201 DWORD error = GetLastError();
202 BOOL invalid = (error == ERROR_INVALID_WINDOW_HANDLE);
203 if (invalid)
204 TRACE("failed to send WM_QUERYENDSESSION to win %p because it's invalid; assuming success\n",
205 qi->wins[i]);
206 else
207 WARN("failed to send WM_QUERYENDSESSION to win %p; error 0x%08x; assuming refusal\n",
208 qi->wins[i], error);
209 quit_callback(qi->wins[i], WM_QUERYENDSESSION, (ULONG_PTR)qi, invalid);
213 /* quit_callback() will clean up qi */
214 return 0;
216 fail:
217 WARN("failed to allocate window list\n");
218 if (qi)
220 HeapFree(GetProcessHeap(), 0, qi->wins);
221 HeapFree(GetProcessHeap(), 0, qi);
223 quit_reply(FALSE);
224 return 0;
227 /***********************************************************************
228 * get_first_resource
230 * Helper for create_app_icon_images(). Enum proc for EnumResourceNamesW()
231 * which just gets the handle for the first resource and stops further
232 * enumeration.
234 static BOOL CALLBACK get_first_resource(HMODULE module, LPCWSTR type, LPWSTR name, LONG_PTR lparam)
236 HRSRC *res_info = (HRSRC*)lparam;
238 *res_info = FindResourceW(module, name, (LPCWSTR)RT_GROUP_ICON);
239 return FALSE;
243 /***********************************************************************
244 * macdrv_app_icon
246 static NTSTATUS WINAPI macdrv_app_icon(void *arg, ULONG size)
248 struct app_icon_params *params = arg;
249 struct app_icon_result *result = params->result;
250 HRSRC res_info;
251 HGLOBAL res_data;
252 GRPICONDIR *icon_dir;
253 int i;
255 TRACE("()\n");
257 result->count = 0;
259 res_info = NULL;
260 EnumResourceNamesW(NULL, (LPCWSTR)RT_GROUP_ICON, get_first_resource, (LONG_PTR)&res_info);
261 if (!res_info)
263 WARN("found no RT_GROUP_ICON resource\n");
264 return 0;
267 if (!(res_data = LoadResource(NULL, res_info)))
269 WARN("failed to load RT_GROUP_ICON resource\n");
270 return 0;
273 if (!(icon_dir = LockResource(res_data)))
275 WARN("failed to lock RT_GROUP_ICON resource\n");
276 goto cleanup;
279 for (i = 0; i < icon_dir->idCount && result->count < ARRAYSIZE(result->entries); i++)
281 struct app_icon_entry *entry = &result->entries[result->count];
282 int width = icon_dir->idEntries[i].bWidth;
283 int height = icon_dir->idEntries[i].bHeight;
284 BOOL found_better_bpp = FALSE;
285 int j;
286 LPCWSTR name;
287 HGLOBAL icon_res_data;
288 BYTE *icon_bits;
290 if (!width) width = 256;
291 if (!height) height = 256;
293 /* If there's another icon at the same size but with better
294 color depth, skip this one. We end up making CGImages that
295 are all 32 bits per pixel, so Cocoa doesn't get the original
296 color depth info to pick the best representation itself. */
297 for (j = 0; j < icon_dir->idCount; j++)
299 int jwidth = icon_dir->idEntries[j].bWidth;
300 int jheight = icon_dir->idEntries[j].bHeight;
302 if (!jwidth) jwidth = 256;
303 if (!jheight) jheight = 256;
305 if (j != i && jwidth == width && jheight == height &&
306 icon_dir->idEntries[j].wBitCount > icon_dir->idEntries[i].wBitCount)
308 found_better_bpp = TRUE;
309 break;
313 if (found_better_bpp) continue;
315 name = MAKEINTRESOURCEW(icon_dir->idEntries[i].nID);
316 res_info = FindResourceW(NULL, name, (LPCWSTR)RT_ICON);
317 if (!res_info)
319 WARN("failed to find RT_ICON resource %d with ID %hd\n", i, icon_dir->idEntries[i].nID);
320 continue;
323 icon_res_data = LoadResource(NULL, res_info);
324 if (!icon_res_data)
326 WARN("failed to load icon %d with ID %hd\n", i, icon_dir->idEntries[i].nID);
327 continue;
330 icon_bits = LockResource(icon_res_data);
331 if (icon_bits)
333 static const BYTE png_magic[] = { 0x89, 0x50, 0x4e, 0x47 };
335 entry->width = width;
336 entry->height = height;
337 entry->size = icon_dir->idEntries[i].dwBytesInRes;
339 if (!memcmp(icon_bits, png_magic, sizeof(png_magic)))
341 entry->png = icon_bits;
342 entry->icon = 0;
343 result->count++;
345 else
347 entry->icon = CreateIconFromResourceEx(icon_bits, icon_dir->idEntries[i].dwBytesInRes,
348 TRUE, 0x00030000, width, height, 0);
349 if (entry->icon)
351 entry->png = NULL;
352 result->count++;
354 else
355 WARN("failed to create icon %d from resource with ID %hd\n", i, icon_dir->idEntries[i].nID);
358 else
359 WARN("failed to lock RT_ICON resource %d with ID %hd\n", i, icon_dir->idEntries[i].nID);
361 FreeResource(icon_res_data);
364 cleanup:
365 FreeResource(res_data);
367 return 0;
370 typedef NTSTATUS (WINAPI *kernel_callback)(void *params, ULONG size);
371 static const kernel_callback kernel_callbacks[] =
373 macdrv_app_icon,
374 macdrv_app_quit_request,
375 macdrv_dnd_query_drag,
376 macdrv_dnd_query_drop,
377 macdrv_dnd_query_exited,
378 macdrv_ime_query_char_rect,
379 macdrv_ime_set_text,
382 C_ASSERT(NtUserDriverCallbackFirst + ARRAYSIZE(kernel_callbacks) == client_func_last);
385 static BOOL process_attach(void)
387 struct init_params params;
388 void **callback_table;
390 struct localized_string *str;
391 struct localized_string strings[] = {
392 { .id = STRING_MENU_WINE },
393 { .id = STRING_MENU_ITEM_HIDE_APPNAME },
394 { .id = STRING_MENU_ITEM_HIDE },
395 { .id = STRING_MENU_ITEM_HIDE_OTHERS },
396 { .id = STRING_MENU_ITEM_SHOW_ALL },
397 { .id = STRING_MENU_ITEM_QUIT_APPNAME },
398 { .id = STRING_MENU_ITEM_QUIT },
400 { .id = STRING_MENU_WINDOW },
401 { .id = STRING_MENU_ITEM_MINIMIZE },
402 { .id = STRING_MENU_ITEM_ZOOM },
403 { .id = STRING_MENU_ITEM_ENTER_FULL_SCREEN },
404 { .id = STRING_MENU_ITEM_BRING_ALL_TO_FRONT },
406 { .id = 0 }
409 if (NtQueryVirtualMemory(GetCurrentProcess(), macdrv_module, MemoryWineUnixFuncs,
410 &macdrv_handle, sizeof(macdrv_handle), NULL))
411 return FALSE;
413 for (str = strings; str->id; str++)
414 str->len = LoadStringW(macdrv_module, str->id, (WCHAR *)&str->str, 0);
415 params.strings = strings;
417 params.pNtWaitForMultipleObjects = NtWaitForMultipleObjects;
418 if (__wine_unix_call(macdrv_handle, unix_init, &params)) return FALSE;
420 callback_table = NtCurrentTeb()->Peb->KernelCallbackTable;
421 memcpy( callback_table + NtUserDriverCallbackFirst, kernel_callbacks, sizeof(kernel_callbacks) );
423 macdrv_unix_call = params.unix_call;
424 return TRUE;
427 BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, void *reserved)
429 if (reason != DLL_PROCESS_ATTACH) return TRUE;
431 DisableThreadLibraryCalls(instance);
432 macdrv_module = instance;
433 return process_attach();
436 int CDECL wine_notify_icon(DWORD msg, NOTIFYICONDATAW *data)
438 struct notify_icon_params params = { .msg = msg, .data = data };
439 return MACDRV_CALL(notify_icon, &params);