winex11: Create a global vulkan instance for xrandr.
[wine.git] / dlls / compstui / compstui_main.c
blob108ef64bd78d28a69b79c702bcd12cc9011d775d
1 /*
2 * Implementation of the Common Property Sheets User Interface
4 * Copyright 2006 Detlef Riekenberg
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 <assert.h>
22 #include <stdarg.h>
23 #include <stdlib.h>
24 #include <string.h>
26 #define COBJMACROS
28 #include "windef.h"
29 #include "winbase.h"
30 #include "winuser.h"
31 #include "commctrl.h"
32 #include "ddk/compstui.h"
34 #include "wine/debug.h"
35 #include "wine/list.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(compstui);
39 static HMODULE compstui_hmod;
41 typedef struct
43 WORD size;
44 WORD flags;
45 union
47 WCHAR *titleW;
48 char *titleA;
50 HWND parent;
51 HINSTANCE hinst;
52 union
54 HICON hicon;
55 ULONG_PTR icon_id;
57 } PROPSHEETUI_INFO_HEADERAW;
59 struct propsheet
61 int pages_cnt;
62 HANDLE pages[100];
63 struct list funcs;
66 struct propsheetpage
68 HPROPSHEETPAGE hpsp;
69 DLGPROC dlg_proc;
72 struct propsheetfunc
74 struct list entry;
75 HANDLE handle;
76 PFNPROPSHEETUI func;
77 LPARAM lparam;
78 BOOL unicode;
79 ULONG_PTR user_data;
80 ULONG_PTR result;
83 #define HANDLE_FIRST 0x43440001
84 static struct cps_data
86 enum
88 HANDLE_FREE = 0,
89 HANDLE_PROPSHEET,
90 HANDLE_PROPSHEETPAGE,
91 HANDLE_PROPSHEETFUNC,
92 } type;
93 union
95 void *data;
96 struct cps_data *next_free;
97 struct propsheet *ps;
98 struct propsheetpage *psp;
99 struct propsheetfunc *psf;
101 } handles[0x1000];
102 static struct cps_data *first_free_handle = handles;
104 static CRITICAL_SECTION handles_cs;
105 static CRITICAL_SECTION_DEBUG handles_cs_debug =
107 0, 0, &handles_cs,
108 { &handles_cs_debug.ProcessLocksList, &handles_cs_debug.ProcessLocksList },
109 0, 0, { (DWORD_PTR)(__FILE__ ": handles_cs") }
111 static CRITICAL_SECTION handles_cs = { &handles_cs_debug, -1, 0, 0, 0, 0 };
113 static LONG_PTR WINAPI cps_callback(HANDLE hcps, UINT func, LPARAM lparam1, LPARAM lparam2);
115 static struct cps_data* get_handle_data(HANDLE handle)
117 struct cps_data *ret;
119 if ((ULONG_PTR)handle < HANDLE_FIRST || (ULONG_PTR)handle >= HANDLE_FIRST + ARRAY_SIZE(handles))
120 return NULL;
122 ret = &handles[(ULONG_PTR)handle - HANDLE_FIRST];
123 return ret->type == HANDLE_FREE ? NULL : ret;
126 static HANDLE alloc_handle(struct cps_data **cps_data, int type)
128 void *data = NULL;
130 switch(type)
132 case HANDLE_PROPSHEET:
133 data = calloc(1, sizeof(struct propsheet));
134 break;
135 case HANDLE_PROPSHEETPAGE:
136 data = calloc(1, sizeof(struct propsheetpage));
137 break;
138 case HANDLE_PROPSHEETFUNC:
139 data = calloc(1, sizeof(struct propsheetfunc));
140 break;
143 if (!data)
144 return NULL;
146 EnterCriticalSection(&handles_cs);
148 if (first_free_handle >= handles + ARRAY_SIZE(handles))
150 LeaveCriticalSection(&handles_cs);
151 FIXME("out of handles\n");
152 free(data);
153 return NULL;
156 *cps_data = first_free_handle;
157 if ((*cps_data)->next_free)
158 first_free_handle = (*cps_data)->next_free;
159 else
160 first_free_handle = (*cps_data) + 1;
161 LeaveCriticalSection(&handles_cs);
163 (*cps_data)->type = type;
164 (*cps_data)->data = data;
165 return (HANDLE)(HANDLE_FIRST + ((*cps_data) - handles));
168 static void free_handle(HANDLE handle)
170 struct cps_data *data = get_handle_data(handle);
172 if (!data)
173 return;
175 data->type = HANDLE_FREE;
176 free(data->data);
178 EnterCriticalSection(&handles_cs);
179 data->next_free = first_free_handle;
180 first_free_handle = data;
181 LeaveCriticalSection(&handles_cs);
184 static HANDLE add_hpropsheetpage(HANDLE hcps, HPROPSHEETPAGE hpsp)
186 struct cps_data *cps_data = get_handle_data(hcps);
187 struct cps_data *cpsp_data;
188 HANDLE ret;
190 if (!cps_data || !hpsp)
191 return 0;
193 if (cps_data->type != HANDLE_PROPSHEET)
195 FIXME("unsupported handle type %d\n", cps_data->type);
196 return 0;
199 if (cps_data->ps->pages_cnt == ARRAY_SIZE(cps_data->ps->pages))
200 return 0;
202 ret = alloc_handle(&cpsp_data, HANDLE_PROPSHEETPAGE);
203 if (!ret)
204 return 0;
205 cpsp_data->psp->hpsp = hpsp;
207 cps_data->ps->pages[cps_data->ps->pages_cnt++] = ret;
208 return ret;
211 static HANDLE add_propsheetfunc(HANDLE hcps, PFNPROPSHEETUI func, LPARAM lparam, BOOL unicode)
213 struct cps_data *cps_data = get_handle_data(hcps);
214 struct cps_data *cpsf_data;
215 PROPSHEETUI_INFO info, callback_info;
216 HANDLE ret;
217 LONG lret;
219 if (!cps_data || !func)
220 return 0;
222 if (cps_data->type != HANDLE_PROPSHEET)
224 FIXME("unsupported handle type %d\n", cps_data->type);
225 return 0;
228 ret = alloc_handle(&cpsf_data, HANDLE_PROPSHEETFUNC);
229 if (!ret)
230 return 0;
231 cpsf_data->psf->handle = ret;
232 cpsf_data->psf->func = func;
233 cpsf_data->psf->unicode = unicode;
234 cpsf_data->psf->lparam = lparam;
236 memset(&info, 0, sizeof(info));
237 info.cbSize = sizeof(info);
238 info.Version = PROPSHEETUI_INFO_VERSION;
239 info.Flags = unicode ? PSUIINFO_UNICODE : 0;
240 info.Reason = PROPSHEETUI_REASON_INIT;
241 info.hComPropSheet = hcps;
242 info.pfnComPropSheet = cps_callback;
243 info.lParamInit = lparam;
245 callback_info = info;
246 lret = func(&callback_info, lparam);
247 cpsf_data->psf->user_data = callback_info.UserData;
248 cpsf_data->psf->result = callback_info.Result;
249 if (lret <= 0)
251 callback_info = info;
252 callback_info.Reason = PROPSHEETUI_REASON_DESTROY;
253 callback_info.UserData = cpsf_data->psf->user_data;
254 callback_info.Result = cpsf_data->psf->result;
255 free_handle(ret);
256 func(&callback_info, 0);
257 return 0;
260 list_add_tail(&cps_data->ps->funcs, &cpsf_data->psf->entry);
261 return ret;
264 static HANDLE add_propsheetpage(HANDLE hcps, void *psp, PSPINFO *info,
265 DLGPROC dlg_proc, BOOL unicode)
267 struct cps_data *cps_data = get_handle_data(hcps);
268 struct cps_data *cpsp_data;
269 HPROPSHEETPAGE hpsp;
270 HANDLE ret;
272 if (!cps_data)
273 return 0;
275 if (cps_data->type != HANDLE_PROPSHEET)
277 FIXME("unsupported handle type %d\n", cps_data->type);
278 return 0;
281 if (cps_data->ps->pages_cnt == ARRAY_SIZE(cps_data->ps->pages))
282 return 0;
284 ret = alloc_handle(&cpsp_data, HANDLE_PROPSHEETPAGE);
285 if (!ret)
286 return 0;
288 info->cbSize = sizeof(*info);
289 info->wReserved = 0;
290 info->hComPropSheet = hcps;
291 info->hCPSUIPage = ret;
292 info->pfnComPropSheet = cps_callback;
294 if (unicode)
295 hpsp = CreatePropertySheetPageW((PROPSHEETPAGEW*)psp);
296 else
297 hpsp = CreatePropertySheetPageA((PROPSHEETPAGEA*)psp);
298 if (!hpsp)
300 free_handle(ret);
301 return 0;
304 cpsp_data->psp->hpsp = hpsp;
305 cpsp_data->psp->dlg_proc = dlg_proc;
306 cps_data->ps->pages[cps_data->ps->pages_cnt++] = ret;
307 return ret;
310 static INT_PTR CALLBACK propsheetpage_dlg_procW(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
312 if (msg == WM_INITDIALOG)
314 PROPSHEETPAGEW *psp = (PROPSHEETPAGEW*)lparam;
315 PSPINFO *info = (PSPINFO*)((BYTE*)lparam + psp->dwSize - sizeof(*info));
316 struct cps_data *cpsp_data = get_handle_data(info->hCPSUIPage);
318 psp->dwSize -= sizeof(*info);
319 psp->pfnDlgProc = cpsp_data->psp->dlg_proc;
320 SetWindowLongPtrW(hwnd, DWLP_DLGPROC, (LONG_PTR)psp->pfnDlgProc);
321 return psp->pfnDlgProc(hwnd, msg, wparam, lparam);
324 return FALSE;
327 static HANDLE add_propsheetpageW(HANDLE hcps, PROPSHEETPAGEW *psp)
329 PROPSHEETPAGEW *psp_copy;
330 PSPINFO *info;
331 HANDLE ret;
333 if (!psp || psp->dwSize < PROPSHEETPAGEW_V1_SIZE)
334 return 0;
336 psp_copy = (PROPSHEETPAGEW*)malloc(psp->dwSize + sizeof(*info));
337 if (!psp_copy)
338 return 0;
339 memcpy(psp_copy, psp, psp->dwSize);
340 psp_copy->dwSize += sizeof(*info);
341 psp_copy->pfnDlgProc = propsheetpage_dlg_procW;
343 info = (PSPINFO*)((BYTE*)psp_copy + psp->dwSize);
344 ret = add_propsheetpage(hcps, psp_copy, info, psp->pfnDlgProc, TRUE);
345 free(psp_copy);
346 return ret;
349 static INT_PTR CALLBACK propsheetpage_dlg_procA(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
351 if (msg == WM_INITDIALOG)
353 PROPSHEETPAGEA *psp = (PROPSHEETPAGEA*)lparam;
354 PSPINFO *info = (PSPINFO*)((BYTE*)lparam + psp->dwSize - sizeof(*info));
355 struct cps_data *cpsp_data = get_handle_data(info->hCPSUIPage);
357 psp->dwSize -= sizeof(*info);
358 psp->pfnDlgProc = cpsp_data->psp->dlg_proc;
359 SetWindowLongPtrA(hwnd, DWLP_DLGPROC, (LONG_PTR)psp->pfnDlgProc);
360 return psp->pfnDlgProc(hwnd, msg, wparam, lparam);
363 return FALSE;
366 static HANDLE add_propsheetpageA(HANDLE hcps, PROPSHEETPAGEA *psp)
368 PROPSHEETPAGEA *psp_copy;
369 PSPINFO *info;
370 HANDLE ret;
372 if (!psp || psp->dwSize < PROPSHEETPAGEW_V1_SIZE)
373 return 0;
375 psp_copy = (PROPSHEETPAGEA*)malloc(psp->dwSize + sizeof(*info));
376 if (!psp_copy)
377 return 0;
378 memcpy(psp_copy, psp, psp->dwSize);
379 psp_copy->dwSize += sizeof(*info);
380 psp_copy->pfnDlgProc = propsheetpage_dlg_procA;
382 info = (PSPINFO*)((BYTE*)psp_copy + psp->dwSize);
383 ret = add_propsheetpage(hcps, psp_copy, info, psp->pfnDlgProc, FALSE);
384 free(psp_copy);
385 return ret;
388 static LONG_PTR WINAPI cps_callback(HANDLE hcps, UINT func, LPARAM lparam1, LPARAM lparam2)
390 TRACE("(%p, %u, %Ix, %Ix\n", hcps, func, lparam1, lparam2);
392 switch(func)
394 case CPSFUNC_ADD_HPROPSHEETPAGE:
395 return (LONG_PTR)add_hpropsheetpage(hcps, (HPROPSHEETPAGE)lparam1);
396 case CPSFUNC_ADD_PFNPROPSHEETUIA:
397 case CPSFUNC_ADD_PFNPROPSHEETUIW:
398 return (LONG_PTR)add_propsheetfunc(hcps, (PFNPROPSHEETUI)lparam1,
399 lparam2, func == CPSFUNC_ADD_PFNPROPSHEETUIW);
400 case CPSFUNC_ADD_PROPSHEETPAGEA:
401 return (LONG_PTR)add_propsheetpageA(hcps, (PROPSHEETPAGEA*)lparam1);
402 case CPSFUNC_ADD_PROPSHEETPAGEW:
403 return (LONG_PTR)add_propsheetpageW(hcps, (PROPSHEETPAGEW*)lparam1);
404 case CPSFUNC_ADD_PCOMPROPSHEETUIA:
405 case CPSFUNC_ADD_PCOMPROPSHEETUIW:
406 case CPSFUNC_DELETE_HCOMPROPSHEET:
407 case CPSFUNC_SET_HSTARTPAGE:
408 case CPSFUNC_GET_PAGECOUNT:
409 case CPSFUNC_SET_RESULT:
410 case CPSFUNC_GET_HPSUIPAGES:
411 case CPSFUNC_LOAD_CPSUI_STRINGA:
412 case CPSFUNC_LOAD_CPSUI_STRINGW:
413 case CPSFUNC_LOAD_CPSUI_ICON:
414 case CPSFUNC_GET_PFNPROPSHEETUI_ICON:
415 case CPSFUNC_INSERT_PSUIPAGEA:
416 case CPSFUNC_INSERT_PSUIPAGEW:
417 case CPSFUNC_SET_PSUIPAGE_TITLEA:
418 case CPSFUNC_SET_PSUIPAGE_TITLEW:
419 case CPSFUNC_SET_PSUIPAGE_ICON:
420 case CPSFUNC_SET_DATABLOCK:
421 case CPSFUNC_QUERY_DATABLOCK:
422 case CPSFUNC_SET_DMPUB_HIDEBITS:
423 case CPSFUNC_IGNORE_CPSUI_PSN_APPLY:
424 case CPSFUNC_DO_APPLY_CPSUI:
425 case CPSFUNC_SET_FUSION_CONTEXT:
426 FIXME("func not supported %d\n", func);
427 return 0;
428 default:
429 ERR("unknown func: %d\n", func);
430 return 0;
434 static LONG create_property_sheetW(struct propsheet *ps, PROPSHEETUI_INFO_HEADERAW *header)
436 HPROPSHEETPAGE hpsp[100];
437 PROPSHEETHEADERW psh;
438 WCHAR title[256];
439 LONG_PTR ret;
440 int i, len;
442 if (!ps->pages_cnt)
443 return ERR_CPSUI_NO_PROPSHEETPAGE;
445 memset(&psh, 0, sizeof(psh));
446 psh.dwSize = sizeof(psh);
447 if (header->flags & PSUIHDRF_NOAPPLYNOW)
448 psh.dwFlags |= PSH_NOAPPLYNOW;
449 psh.hwndParent = header->parent;
450 psh.hInstance = header->hinst;
451 psh.pszCaption = title;
453 if (!(header->flags & PSUIHDRF_USEHICON) && !header->icon_id)
454 header->icon_id = IDI_CPSUI_OPTION;
456 if (header->flags & PSUIHDRF_USEHICON)
458 psh.dwFlags |= PSH_USEHICON;
459 psh.hIcon = header->hicon;
461 else if (header->icon_id >= IDI_CPSUI_ICONID_FIRST &&
462 header->icon_id <= IDI_CPSUI_ICONID_LAST)
464 FIXME("icon not implemented: %Id\n", header->icon_id);
466 else
468 psh.dwFlags |= PSH_USEICONID;
469 psh.pszIcon = (WCHAR*)header->icon_id;
472 if (header->titleW)
473 wcscpy_s(title, ARRAY_SIZE(title), header->titleW);
474 else
475 LoadStringW(compstui_hmod, IDS_CPSUI_OPTIONS, title, ARRAY_SIZE(title));
477 if ((header->flags & PSUIHDRF_DEFTITLE) &&
478 (!header->titleW || !(header->flags & PSUIHDRF_EXACT_PTITLE)))
480 len = wcslen(title);
481 if (len < ARRAY_SIZE(title) - 1)
483 title[len++] = ' ';
484 LoadStringW(compstui_hmod, IDS_CPSUI_DEFAULT, title + len, ARRAY_SIZE(title) - len);
488 if ((header->flags & PSUIHDRF_PROPTITLE) &&
489 (!header->titleW || !(header->flags & PSUIHDRF_EXACT_PTITLE)))
491 len = wcslen(title);
492 if (len < ARRAY_SIZE(title) - 1)
494 title[len++] = ' ';
495 LoadStringW(compstui_hmod, IDS_CPSUI_PROPERTIES, title + len, ARRAY_SIZE(title) - len);
499 psh.nPages = ps->pages_cnt;
500 psh.phpage = hpsp;
501 for (i = 0; i < ps->pages_cnt; i++)
502 hpsp[i] = get_handle_data(ps->pages[i])->psp->hpsp;
504 ret = PropertySheetW(&psh);
506 switch(ret)
508 case -1:
509 return ERR_CPSUI_GETLASTERROR;
510 case ID_PSREBOOTSYSTEM:
511 return CPSUI_REBOOTSYSTEM;
512 case ID_PSRESTARTWINDOWS:
513 return CPSUI_RESTARTWINDOWS;
514 default:
515 return CPSUI_OK;
519 static LONG create_prop_dlg(HWND hwnd, PFNPROPSHEETUI callback, LPARAM lparam, DWORD *res, BOOL unicode)
521 PROPSHEETUI_INFO info, callback_info;
522 PROPSHEETUI_INFO_HEADERAW header;
523 struct cps_data *cps_data;
524 HANDLE cps_handle;
525 LONG ret;
526 int i;
528 if (!callback || !(cps_handle = alloc_handle(&cps_data, HANDLE_PROPSHEET)))
530 SetLastError(0);
531 return ERR_CPSUI_GETLASTERROR;
533 list_init(&cps_data->ps->funcs);
535 memset(&info, 0, sizeof(info));
536 info.cbSize = sizeof(info);
537 info.lParamInit = lparam;
538 callback_info = info;
539 callback_info.Reason = PROPSHEETUI_REASON_BEFORE_INIT;
540 callback(&callback_info, lparam);
542 info.Version = PROPSHEETUI_INFO_VERSION;
543 info.Flags = unicode ? PSUIINFO_UNICODE : 0;
544 info.hComPropSheet = cps_handle;
545 info.pfnComPropSheet = cps_callback;
546 callback_info = info;
547 callback_info.Reason = PROPSHEETUI_REASON_INIT;
548 ret = callback(&callback_info, lparam);
549 info.UserData = callback_info.UserData;
550 info.Result = callback_info.Result;
551 if (ret <= 0)
553 ret = ERR_CPSUI_GETLASTERROR;
554 goto destroy;
557 memset(&header, 0, sizeof(header));
558 header.size = sizeof(header);
559 header.parent = hwnd;
560 callback_info = info;
561 callback_info.Reason = PROPSHEETUI_REASON_GET_INFO_HEADER;
562 ret = callback(&callback_info, (LPARAM)&header);
563 info.UserData = callback_info.UserData;
564 info.Result = callback_info.Result;
565 if (ret <= 0)
567 ret = ERR_CPSUI_GETLASTERROR;
568 goto destroy;
571 ret = create_property_sheetW(cps_data->ps, &header);
573 destroy:
574 info.Reason = PROPSHEETUI_REASON_DESTROY;
575 while (!list_empty(&cps_data->ps->funcs))
577 struct propsheetfunc *func = LIST_ENTRY(list_head(&cps_data->ps->funcs),
578 struct propsheetfunc, entry);
580 list_remove(&func->entry);
582 callback_info = info;
583 callback_info.Flags = func->unicode ? PSUIINFO_UNICODE : 0;
584 callback_info.lParamInit = func->lparam;
585 callback_info.UserData = func->user_data;
586 callback_info.Result = func->result;
587 func->func(&callback_info, ret <= 0 ? 0 : 0x100);
588 free_handle(func->handle);
591 callback_info = info;
592 callback(&callback_info, ret <= 0 ? 0 : 0x100);
594 for (i = 0; i < cps_data->ps->pages_cnt; i++)
595 free_handle(cps_data->ps->pages[i]);
596 free_handle(cps_handle);
598 if (res) *res = callback_info.Result;
599 return ret;
602 /******************************************************************
603 * CommonPropertySheetUIA (COMPSTUI.@)
606 LONG WINAPI CommonPropertySheetUIA(HWND hWnd, PFNPROPSHEETUI pfnPropSheetUI, LPARAM lparam, LPDWORD pResult)
608 FIXME("(%p, %p, 0x%Ix, %p)\n", hWnd, pfnPropSheetUI, lparam, pResult);
609 return CPSUI_CANCEL;
612 /******************************************************************
613 * CommonPropertySheetUIW (COMPSTUI.@)
616 LONG WINAPI CommonPropertySheetUIW(HWND hwnd, PFNPROPSHEETUI callback, LPARAM lparam, LPDWORD res)
618 TRACE("(%p, %p, 0x%Ix, %p)\n", hwnd, callback, lparam, res);
619 return create_prop_dlg(hwnd, callback, lparam, res, TRUE);
622 /******************************************************************
623 * GetCPSUIUserData (COMPSTUI.@)
626 ULONG_PTR WINAPI GetCPSUIUserData(HWND hDlg)
628 FIXME("(%p): stub\n", hDlg);
629 return 0;
632 /******************************************************************
633 * SetCPSUIUserData (COMPSTUI.@)
636 BOOL WINAPI SetCPSUIUserData(HWND hDlg, ULONG_PTR UserData )
638 FIXME("(%p, %08Ix): stub\n", hDlg, UserData);
639 return TRUE;
642 BOOL WINAPI DllMain(HINSTANCE hinst, DWORD reason, void *reserved)
644 if (reason == DLL_PROCESS_ATTACH)
645 compstui_hmod = hinst;
646 return TRUE;