dmime: Include dmobject.h in dmime_private.h.
[wine.git] / dlls / winemac.drv / dllmain.c
blob8812426cc440a21e120519912b97184059960cef
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;
31 struct quit_info {
32 HWND *wins;
33 UINT capacity;
34 UINT count;
35 UINT done;
36 DWORD flags;
37 BOOL result;
38 BOOL replied;
42 static BOOL CALLBACK get_process_windows(HWND hwnd, LPARAM lp)
44 struct quit_info *qi = (struct quit_info*)lp;
45 DWORD pid;
47 NtUserGetWindowThread(hwnd, &pid);
48 if (pid == GetCurrentProcessId())
50 if (qi->count >= qi->capacity)
52 UINT new_cap = qi->capacity * 2;
53 HWND *new_wins = HeapReAlloc(GetProcessHeap(), 0, qi->wins, new_cap * sizeof(*qi->wins));
54 if (!new_wins) return FALSE;
55 qi->wins = new_wins;
56 qi->capacity = new_cap;
59 qi->wins[qi->count++] = hwnd;
62 return TRUE;
65 #include "pshpack1.h"
67 typedef struct
69 BYTE bWidth;
70 BYTE bHeight;
71 BYTE bColorCount;
72 BYTE bReserved;
73 WORD wPlanes;
74 WORD wBitCount;
75 DWORD dwBytesInRes;
76 WORD nID;
77 } GRPICONDIRENTRY;
79 typedef struct
81 WORD idReserved;
82 WORD idType;
83 WORD idCount;
84 GRPICONDIRENTRY idEntries[1];
85 } GRPICONDIR;
87 #include "poppack.h"
89 static void quit_reply(int reply)
91 struct quit_result_params params = { .result = reply };
92 MACDRV_CALL(quit_result, &params);
96 static void CALLBACK quit_callback(HWND hwnd, UINT msg, ULONG_PTR data, LRESULT result)
98 struct quit_info *qi = (struct quit_info*)data;
100 qi->done++;
102 if (msg == WM_QUERYENDSESSION)
104 TRACE("got WM_QUERYENDSESSION result %Id from win %p (%u of %u done)\n", result,
105 hwnd, qi->done, qi->count);
107 if (!result && !IsWindow(hwnd))
109 TRACE("win %p no longer exists; ignoring apparent refusal\n", hwnd);
110 result = TRUE;
113 if (!result && qi->result)
115 qi->result = FALSE;
117 /* On the first FALSE from WM_QUERYENDSESSION, we already know the
118 ultimate reply. Might as well tell Cocoa now. */
119 if (!qi->replied)
121 qi->replied = TRUE;
122 TRACE("giving quit reply %d\n", qi->result);
123 quit_reply(qi->result);
127 if (qi->done >= qi->count)
129 UINT i;
131 qi->done = 0;
132 for (i = 0; i < qi->count; i++)
134 TRACE("sending WM_ENDSESSION to win %p result %d flags 0x%08lx\n", qi->wins[i],
135 qi->result, qi->flags);
136 if (!SendMessageCallbackW(qi->wins[i], WM_ENDSESSION, qi->result, qi->flags,
137 quit_callback, (ULONG_PTR)qi))
139 WARN("failed to send WM_ENDSESSION to win %p; error 0x%08lx\n",
140 qi->wins[i], RtlGetLastWin32Error());
141 quit_callback(qi->wins[i], WM_ENDSESSION, (ULONG_PTR)qi, 0);
146 else /* WM_ENDSESSION */
148 TRACE("finished WM_ENDSESSION for win %p (%u of %u done)\n", hwnd, qi->done, qi->count);
150 if (qi->done >= qi->count)
152 if (!qi->replied)
154 TRACE("giving quit reply %d\n", qi->result);
155 quit_reply(qi->result);
158 TRACE("%sterminating process\n", qi->result ? "" : "not ");
159 if (qi->result)
160 TerminateProcess(GetCurrentProcess(), 0);
162 HeapFree(GetProcessHeap(), 0, qi->wins);
163 HeapFree(GetProcessHeap(), 0, qi);
169 /***********************************************************************
170 * macdrv_app_quit_request
172 NTSTATUS WINAPI macdrv_app_quit_request(void *arg, ULONG size)
174 struct app_quit_request_params *params = arg;
175 struct quit_info *qi;
176 UINT i;
178 qi = HeapAlloc(GetProcessHeap(), 0, sizeof(*qi));
179 if (!qi)
180 goto fail;
182 qi->capacity = 32;
183 qi->wins = HeapAlloc(GetProcessHeap(), 0, qi->capacity * sizeof(*qi->wins));
184 qi->count = qi->done = 0;
186 if (!qi->wins || !EnumWindows(get_process_windows, (LPARAM)qi))
187 goto fail;
189 qi->flags = params->flags;
190 qi->result = TRUE;
191 qi->replied = FALSE;
193 for (i = 0; i < qi->count; i++)
195 TRACE("sending WM_QUERYENDSESSION to win %p\n", qi->wins[i]);
196 if (!SendMessageCallbackW(qi->wins[i], WM_QUERYENDSESSION, 0, qi->flags,
197 quit_callback, (ULONG_PTR)qi))
199 DWORD error = RtlGetLastWin32Error();
200 BOOL invalid = (error == ERROR_INVALID_WINDOW_HANDLE);
201 if (invalid)
202 TRACE("failed to send WM_QUERYENDSESSION to win %p because it's invalid; assuming success\n",
203 qi->wins[i]);
204 else
205 WARN("failed to send WM_QUERYENDSESSION to win %p; error 0x%08lx; assuming refusal\n",
206 qi->wins[i], error);
207 quit_callback(qi->wins[i], WM_QUERYENDSESSION, (ULONG_PTR)qi, invalid);
211 /* quit_callback() will clean up qi */
212 return 0;
214 fail:
215 WARN("failed to allocate window list\n");
216 if (qi)
218 HeapFree(GetProcessHeap(), 0, qi->wins);
219 HeapFree(GetProcessHeap(), 0, qi);
221 quit_reply(FALSE);
222 return 0;
225 /***********************************************************************
226 * get_first_resource
228 * Helper for create_app_icon_images(). Enum proc for EnumResourceNamesW()
229 * which just gets the handle for the first resource and stops further
230 * enumeration.
232 static BOOL CALLBACK get_first_resource(HMODULE module, LPCWSTR type, LPWSTR name, LONG_PTR lparam)
234 HRSRC *res_info = (HRSRC*)lparam;
236 *res_info = FindResourceW(module, name, (LPCWSTR)RT_GROUP_ICON);
237 return FALSE;
241 /***********************************************************************
242 * macdrv_app_icon
244 static NTSTATUS WINAPI macdrv_app_icon(void *arg, ULONG size)
246 struct app_icon_entry entries[64];
247 HRSRC res_info;
248 HGLOBAL res_data;
249 GRPICONDIR *icon_dir;
250 unsigned count;
251 int i;
253 TRACE("()\n");
255 count = 0;
257 res_info = NULL;
258 EnumResourceNamesW(NULL, (LPCWSTR)RT_GROUP_ICON, get_first_resource, (LONG_PTR)&res_info);
259 if (!res_info)
261 WARN("found no RT_GROUP_ICON resource\n");
262 return 0;
265 if (!(res_data = LoadResource(NULL, res_info)))
267 WARN("failed to load RT_GROUP_ICON resource\n");
268 return 0;
271 if (!(icon_dir = LockResource(res_data)))
273 WARN("failed to lock RT_GROUP_ICON resource\n");
274 goto cleanup;
277 for (i = 0; i < icon_dir->idCount && count < ARRAYSIZE(entries); i++)
279 struct app_icon_entry *entry = &entries[count];
280 int width = icon_dir->idEntries[i].bWidth;
281 int height = icon_dir->idEntries[i].bHeight;
282 BOOL found_better_bpp = FALSE;
283 int j;
284 LPCWSTR name;
285 HGLOBAL icon_res_data;
286 BYTE *icon_bits;
288 if (!width) width = 256;
289 if (!height) height = 256;
291 /* If there's another icon at the same size but with better
292 color depth, skip this one. We end up making CGImages that
293 are all 32 bits per pixel, so Cocoa doesn't get the original
294 color depth info to pick the best representation itself. */
295 for (j = 0; j < icon_dir->idCount; j++)
297 int jwidth = icon_dir->idEntries[j].bWidth;
298 int jheight = icon_dir->idEntries[j].bHeight;
300 if (!jwidth) jwidth = 256;
301 if (!jheight) jheight = 256;
303 if (j != i && jwidth == width && jheight == height &&
304 icon_dir->idEntries[j].wBitCount > icon_dir->idEntries[i].wBitCount)
306 found_better_bpp = TRUE;
307 break;
311 if (found_better_bpp) continue;
313 name = MAKEINTRESOURCEW(icon_dir->idEntries[i].nID);
314 res_info = FindResourceW(NULL, name, (LPCWSTR)RT_ICON);
315 if (!res_info)
317 WARN("failed to find RT_ICON resource %d with ID %hd\n", i, icon_dir->idEntries[i].nID);
318 continue;
321 icon_res_data = LoadResource(NULL, res_info);
322 if (!icon_res_data)
324 WARN("failed to load icon %d with ID %hd\n", i, icon_dir->idEntries[i].nID);
325 continue;
328 icon_bits = LockResource(icon_res_data);
329 if (icon_bits)
331 static const BYTE png_magic[] = { 0x89, 0x50, 0x4e, 0x47 };
333 entry->width = width;
334 entry->height = height;
335 entry->size = icon_dir->idEntries[i].dwBytesInRes;
337 if (!memcmp(icon_bits, png_magic, sizeof(png_magic)))
339 entry->png = (UINT_PTR)icon_bits;
340 entry->icon = 0;
341 count++;
343 else
345 HICON icon = CreateIconFromResourceEx(icon_bits, icon_dir->idEntries[i].dwBytesInRes,
346 TRUE, 0x00030000, width, height, 0);
347 if (icon)
349 entry->icon = HandleToUlong(icon);
350 entry->png = 0;
351 count++;
353 else
354 WARN("failed to create icon %d from resource with ID %hd\n", i, icon_dir->idEntries[i].nID);
357 else
358 WARN("failed to lock RT_ICON resource %d with ID %hd\n", i, icon_dir->idEntries[i].nID);
360 FreeResource(icon_res_data);
363 cleanup:
364 FreeResource(res_data);
366 return NtCallbackReturn(entries, count * sizeof(entries[0]), 0);
369 typedef NTSTATUS (WINAPI *kernel_callback)(void *params, ULONG size);
370 static const kernel_callback kernel_callbacks[] =
372 macdrv_app_icon,
373 macdrv_app_quit_request,
374 macdrv_dnd_query_drag,
375 macdrv_dnd_query_drop,
376 macdrv_dnd_query_exited,
379 C_ASSERT(NtUserDriverCallbackFirst + ARRAYSIZE(kernel_callbacks) == client_func_last);
382 static BOOL process_attach(void)
384 struct init_params params;
385 void **callback_table;
387 struct localized_string *str;
388 struct localized_string strings[] = {
389 { .id = STRING_MENU_WINE },
390 { .id = STRING_MENU_ITEM_HIDE_APPNAME },
391 { .id = STRING_MENU_ITEM_HIDE },
392 { .id = STRING_MENU_ITEM_HIDE_OTHERS },
393 { .id = STRING_MENU_ITEM_SHOW_ALL },
394 { .id = STRING_MENU_ITEM_QUIT_APPNAME },
395 { .id = STRING_MENU_ITEM_QUIT },
397 { .id = STRING_MENU_WINDOW },
398 { .id = STRING_MENU_ITEM_MINIMIZE },
399 { .id = STRING_MENU_ITEM_ZOOM },
400 { .id = STRING_MENU_ITEM_ENTER_FULL_SCREEN },
401 { .id = STRING_MENU_ITEM_BRING_ALL_TO_FRONT },
403 { .id = 0 }
406 if (__wine_init_unix_call()) return FALSE;
408 for (str = strings; str->id; str++)
409 str->len = LoadStringW(macdrv_module, str->id, (WCHAR *)&str->str, 0);
410 params.strings = strings;
412 if (MACDRV_CALL(init, &params)) return FALSE;
414 callback_table = NtCurrentTeb()->Peb->KernelCallbackTable;
415 memcpy( callback_table + NtUserDriverCallbackFirst, kernel_callbacks, sizeof(kernel_callbacks) );
416 return TRUE;
419 BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, void *reserved)
421 if (reason != DLL_PROCESS_ATTACH) return TRUE;
423 DisableThreadLibraryCalls(instance);
424 macdrv_module = instance;
425 return process_attach();
428 int CDECL wine_notify_icon(DWORD msg, NOTIFYICONDATAW *data)
430 struct notify_icon_params params = { .msg = msg, .data = data };
431 return MACDRV_CALL(notify_icon, &params);