1 /* Implements elisp-programmable dialog boxes -- MS Windows interface.
2 Copyright (C) 1998 Kirill M. Katsnelson <kkm@kis.ru>
3 Copyright (C) 2000 Ben Wing.
5 This file is part of XEmacs.
7 XEmacs is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by the
9 Free Software Foundation; either version 2, or (at your option) any
12 XEmacs is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 You should have received a copy of the GNU General Public License
18 along with XEmacs; see the file COPYING. If not, write to
19 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA. */
22 /* Synched up with: Not in FSF. */
25 Initially written by kkm, May 1998
32 #include "console-msw.h"
40 Lisp_Object Qdialog_box_error;
42 static Lisp_Object Q_initial_directory;
43 static Lisp_Object Q_initial_filename;
44 static Lisp_Object Q_filter_list;
45 static Lisp_Object Q_title;
46 static Lisp_Object Q_allow_multi_select;
47 static Lisp_Object Q_create_prompt_on_nonexistent;
48 static Lisp_Object Q_overwrite_prompt;
49 static Lisp_Object Q_file_must_exist;
50 static Lisp_Object Q_no_network_button;
51 static Lisp_Object Q_no_read_only_return;
53 /* List containing all dialog data structures of currently popped up
55 static Lisp_Object Vdialog_data_list;
57 /* List of popup frames wanting keyboard traversal handled */
58 static Lisp_Object Vpopup_frame_list;
60 Lisp_Object Vdefault_file_dialog_filter_alist;
62 /* DLUs per character metrics */
63 #define X_DLU_PER_CHAR 4
64 #define Y_DLU_PER_CHAR 8
69 All buttons have height of 15 DLU. The minimum width for a button is 32 DLU,
70 but it can be expanded to accommodate its text, so the width is calculated as
71 8 DLU per button plus 4 DLU per character.
72 max (32, 6 * text_length). The factor of six is rather empirical, but it
73 works better than 8 which comes from the definition of a DLU. Buttons are
74 spaced with 6 DLU gap. Minimum distance from the button to the left or right
75 dialog edges is 6 DLU, and the distance between the dialog bottom edge and
79 #define X_MIN_BUTTON 32
80 #define X_BUTTON_MARGIN 8
82 #define X_BUTTON_SPACING 6
83 #define X_BUTTON_FROM_EDGE 6
84 #define Y_BUTTON_FROM_EDGE 7
89 Text distance from left and right edges is the same as for buttons, and the
90 top margin is 11 DLU. The static control has height of 2 DLU per control
91 plus 8 DLU per each line of text. Distance between the bottom edge of the
92 control and the button row is 15 DLU. Minimum width of the static control
93 is 100 DLU, thus giving minimum dialog weight of 112 DLU. Maximum width is
94 300 DLU, and, if the text is wider than that, the text is wrapped on the
95 next line. Each character in the text is considered 4 DLU wide.
98 #define X_MIN_TEXT 100
99 #define X_AVE_TEXT 200
100 #define X_MAX_TEXT 300
101 #define X_TEXT_FROM_EDGE X_BUTTON_FROM_EDGE
102 #define Y_TEXT_FROM_EDGE 11
103 #define Y_TEXT_MARGIN 2
104 #define Y_TEXT_FROM_BUTTON 15
106 #define X_MIN_TEXT_CHAR (X_MIN_TEXT / X_DLU_PER_CHAR)
107 #define X_AVE_TEXT_CHAR (X_AVE_TEXT / X_DLU_PER_CHAR)
108 #define X_MAX_TEXT_CHAR (X_MAX_TEXT / X_DLU_PER_CHAR)
113 First we calculate the minimum width of the button row, excluding "from
114 edge" distances. Note that the static control text can be narrower than
115 X_AVE_TEXT only if both text and button row are narrower than that (so,
116 even if text *can* be wrapped into 2 rows narrower than ave width, it is not
117 done). Let WBR denote the width of the button row.
119 Next, the width of the static field is determined.
120 First, if all lines of text fit into max (WBR, X_MAX_TEXT), the width of the
121 control is the same as the width of the longest line.
122 Second, if all lines of text are narrower than X_MIN_TEXT, then width of
123 the control is set to X_MIN_TEXT.
124 Otherwise, width is set to max(WBR, X_AVE_TEXT). In this case, line wrapping will
127 If width of the text control is larger than that of the button row, then the
128 latter is centered across the dialog, by giving it extra edge
129 margins. Otherwise, minimal margins are given to the button row.
132 #define ID_ITEM_BIAS 32
135 mswindows_register_popup_frame (Lisp_Object frame)
137 Vpopup_frame_list = Fcons (frame, Vpopup_frame_list);
141 mswindows_unregister_popup_frame (Lisp_Object frame)
143 Vpopup_frame_list = delq_no_quit (frame, Vpopup_frame_list);
146 /* Dispatch message to any dialog boxes. Return non-zero if dispatched. */
148 mswindows_is_dialog_msg (MSG *msg)
150 LIST_LOOP_2 (data, Vdialog_data_list)
152 if (IsDialogMessage (XMSWINDOWS_DIALOG_ID (data)->hwnd, msg))
157 LIST_LOOP_2 (popup, Vpopup_frame_list)
159 HWND hwnd = FRAME_MSWINDOWS_HANDLE (XFRAME (popup));
160 /* This is a windows feature that allows dialog type
161 processing to be applied to standard windows containing
163 if (IsDialogMessage (hwnd, msg))
171 mark_mswindows_dialog_id (Lisp_Object obj)
173 struct mswindows_dialog_id *data = XMSWINDOWS_DIALOG_ID (obj);
174 mark_object (data->frame);
175 return data->callbacks;
178 DEFINE_LRECORD_IMPLEMENTATION ("mswindows-dialog-id", mswindows_dialog_id,
179 mark_mswindows_dialog_id, 0, 0, 0, 0, 0,
180 struct mswindows_dialog_id);
182 /* Dialog procedure */
184 dialog_proc (HWND hwnd, UINT msg, WPARAM w_param, LPARAM l_param)
189 SetWindowLong (hwnd, DWL_USER, l_param);
195 VOID_TO_LISP (data, GetWindowLong (hwnd, DWL_USER));
196 Vdialog_data_list = delq_no_quit (data, Vdialog_data_list);
202 Lisp_Object fn, arg, data;
203 struct mswindows_dialog_id *did;
205 VOID_TO_LISP (data, GetWindowLong (hwnd, DWL_USER));
206 did = XMSWINDOWS_DIALOG_ID (data);
207 if (w_param != IDCANCEL) /* user pressed escape */
209 assert (w_param >= ID_ITEM_BIAS
211 < XVECTOR_LENGTH (did->callbacks) + ID_ITEM_BIAS);
213 get_gui_callback (XVECTOR_DATA (did->callbacks)
214 [w_param - ID_ITEM_BIAS],
216 mswindows_enqueue_misc_user_event (did->frame, fn, arg);
219 mswindows_enqueue_misc_user_event (did->frame, Qrun_hooks,
220 Qmenu_no_selection_hook);
221 /* #### need to error-protect! will do so when i merge in
223 va_run_hook_with_args (Qdelete_dialog_box_hook, 1, data);
225 DestroyWindow (hwnd);
235 /* Helper function which converts the supplied string STRING into Unicode and
236 pushes it at the end of DYNARR */
238 push_lisp_string_as_unicode (unsigned_char_dynarr* dynarr, Lisp_Object string)
240 Extbyte *mbcs_string;
241 Charcount length = XSTRING_CHAR_LENGTH (string);
244 TO_EXTERNAL_FORMAT (LISP_STRING, string,
245 C_STRING_ALLOCA, mbcs_string,
247 uni_string = alloca_array (WCHAR, length + 1);
248 length = MultiByteToWideChar (CP_ACP, 0, mbcs_string, -1,
249 uni_string, sizeof(WCHAR) * (length + 1));
250 Dynarr_add_many (dynarr, uni_string, sizeof(WCHAR) * length);
253 /* Helper function which converts the supplied string STRING into Unicode and
254 pushes it at the end of DYNARR */
256 push_bufbyte_string_as_unicode (unsigned_char_dynarr* dynarr, Bufbyte *string,
259 Extbyte *mbcs_string;
260 Charcount length = bytecount_to_charcount (string, len);
263 TO_EXTERNAL_FORMAT (C_STRING, string,
264 C_STRING_ALLOCA, mbcs_string,
266 uni_string = alloca_array (WCHAR, length + 1);
267 length = MultiByteToWideChar (CP_ACP, 0, mbcs_string, -1,
268 uni_string, sizeof(WCHAR) * (length + 1));
269 Dynarr_add_many (dynarr, uni_string, sizeof(WCHAR) * length);
272 /* Given button TEXT, return button width in DLU */
274 button_width (Lisp_Object text)
276 unsigned int width = X_DLU_PER_CHAR * XSTRING_CHAR_LENGTH (text);
277 return max (X_MIN_BUTTON, width);
280 /* Unwind protection routine frees a dynarr opaqued into arg */
282 free_dynarr_opaque_ptr (Lisp_Object arg)
284 Dynarr_free (get_opaque_ptr (arg));
288 /* Unwind protection decrements dialog count */
290 dialog_popped_down (Lisp_Object arg)
297 #define ALIGN_TEMPLATE \
299 unsigned int slippage = Dynarr_length (template) & 3; \
301 Dynarr_add_many (template, &zeroes, slippage); \
308 } common_dialog_errors[] =
310 { CDERR_DIALOGFAILURE, "CDERR_DIALOGFAILURE" },
311 { CDERR_FINDRESFAILURE, "CDERR_FINDRESFAILURE" },
312 { CDERR_INITIALIZATION, "CDERR_INITIALIZATION" },
313 { CDERR_LOADRESFAILURE, "CDERR_LOADRESFAILURE" },
314 { CDERR_LOADSTRFAILURE, "CDERR_LOADSTRFAILURE" },
315 { CDERR_LOCKRESFAILURE, "CDERR_LOCKRESFAILURE" },
316 { CDERR_MEMALLOCFAILURE, "CDERR_MEMALLOCFAILURE" },
317 { CDERR_MEMLOCKFAILURE, "CDERR_MEMLOCKFAILURE" },
318 { CDERR_NOHINSTANCE, "CDERR_NOHINSTANCE" },
319 { CDERR_NOHOOK, "CDERR_NOHOOK" },
320 { CDERR_NOTEMPLATE, "CDERR_NOTEMPLATE" },
321 { CDERR_REGISTERMSGFAIL, "CDERR_REGISTERMSGFAIL" },
322 { CDERR_STRUCTSIZE, "CDERR_STRUCTSIZE" },
323 { PDERR_CREATEICFAILURE, "PDERR_CREATEICFAILURE" },
324 { PDERR_DEFAULTDIFFERENT, "PDERR_DEFAULTDIFFERENT" },
325 { PDERR_DNDMMISMATCH, "PDERR_DNDMMISMATCH" },
326 { PDERR_GETDEVMODEFAIL, "PDERR_GETDEVMODEFAIL" },
327 { PDERR_INITFAILURE, "PDERR_INITFAILURE" },
328 { PDERR_LOADDRVFAILURE, "PDERR_LOADDRVFAILURE" },
329 { PDERR_NODEFAULTPRN, "PDERR_NODEFAULTPRN" },
330 { PDERR_NODEVICES, "PDERR_NODEVICES" },
331 { PDERR_PARSEFAILURE, "PDERR_PARSEFAILURE" },
332 { PDERR_PRINTERNOTFOUND, "PDERR_PRINTERNOTFOUND" },
333 { PDERR_RETDEFFAILURE, "PDERR_RETDEFFAILURE" },
334 { PDERR_SETUPFAILURE, "PDERR_SETUPFAILURE" },
335 { CFERR_MAXLESSTHANMIN, "CFERR_MAXLESSTHANMIN" },
336 { CFERR_NOFONTS, "CFERR_NOFONTS" },
337 { FNERR_BUFFERTOOSMALL, "FNERR_BUFFERTOOSMALL" },
338 { FNERR_INVALIDFILENAME, "FNERR_INVALIDFILENAME" },
339 { FNERR_SUBCLASSFAILURE, "FNERR_SUBCLASSFAILURE" },
340 { FRERR_BUFFERLENGTHZERO, "FRERR_BUFFERLENGTHZERO" },
350 CALLBACK handle_directory_proc (HWND hwnd, UINT msg,
351 LPARAM lParam, LPARAM lpData)
353 TCHAR szDir[MAX_PATH];
354 struct param_data* pd = (struct param_data*)lpData;
357 case BFFM_INITIALIZED:
358 // WParam is TRUE since you are passing a path.
359 // It would be FALSE if you were passing a pidl.
360 SendMessage(hwnd, BFFM_SETSELECTION, TRUE, (LPARAM)pd->fname);
363 case BFFM_SELCHANGED:
364 // Set the status window to the currently selected path.
365 if (SHGetPathFromIDList((LPITEMIDLIST) lParam, szDir)) {
366 SendMessage(hwnd, BFFM_SETSTATUSTEXT, 0, (LPARAM)szDir);
370 case BFFM_VALIDATEFAILED:
374 pd->unknown_fname = xstrdup((char*)lParam);
384 handle_directory_dialog_box (struct frame *f, Lisp_Object keys)
386 Lisp_Object ret = Qnil;
390 struct param_data pd;
395 bi.lParam = (LPARAM)&pd;
396 bi.hwndOwner = FRAME_MSWINDOWS_HANDLE (f);
397 bi.pszDisplayName = 0;
399 bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_STATUSTEXT | BIF_EDITBOX;
400 bi.lpfn = handle_directory_proc;
402 LOCAL_FILE_FORMAT_TO_TSTR (Fexpand_file_name (build_string (""), Qnil),
406 EXTERNAL_PROPERTY_LIST_LOOP_3 (key, value, keys)
408 if (EQ (key, Q_title))
410 CHECK_STRING (value);
411 LISP_STRING_TO_EXTERNAL (value, bi.lpszTitle, Qmswindows_tstr);
413 else if (EQ (key, Q_initial_directory))
414 LOCAL_FILE_FORMAT_TO_TSTR (Fexpand_file_name (value, Qnil),
416 else if (EQ (key, Q_initial_filename))
418 else if (EQ (key, Q_file_must_exist))
422 bi.ulFlags |= BIF_VALIDATE;
425 bi.ulFlags &= ~BIF_VALIDATE;
428 syntax_error ("Unrecognized directory dialog keyword", key);
432 if (SHGetMalloc(&pMalloc) == NOERROR)
434 pidl = SHBrowseForFolder(&bi);
436 TCHAR* szDir = alloca (MAX_PATH);
438 if (SHGetPathFromIDList(pidl, szDir)) {
439 ret = tstr_to_local_file_format (szDir);
442 pMalloc->lpVtbl->Free(pMalloc, pidl);
443 pMalloc->lpVtbl->Release(pMalloc);
446 else if (pd.unknown_fname != 0) {
447 ret = tstr_to_local_file_format (pd.unknown_fname);
448 xfree(pd.unknown_fname);
454 signal_type_error (Qdialog_box_error,
455 "Unable to create folder browser",
461 handle_file_dialog_box (struct frame *f, Lisp_Object keys)
468 ofn.lStructSize = sizeof (ofn);
469 ofn.Flags = OFN_EXPLORER;
470 ofn.hwndOwner = FRAME_MSWINDOWS_HANDLE (f);
471 ofn.lpstrFile = fnbuf;
472 ofn.nMaxFile = sizeof (fnbuf) / XETCHAR_SIZE;
473 xetcscpy (fnbuf, XETEXT (""));
475 LOCAL_FILE_FORMAT_TO_TSTR (Fexpand_file_name (build_string (""), Qnil),
476 ofn.lpstrInitialDir);
479 EXTERNAL_PROPERTY_LIST_LOOP_3 (key, value, keys)
481 if (EQ (key, Q_initial_filename))
485 CHECK_STRING (value);
486 LOCAL_FILE_FORMAT_TO_TSTR (value, fnout);
487 xetcscpy (fnbuf, fnout);
489 else if (EQ (key, Q_title))
491 CHECK_STRING (value);
492 LISP_STRING_TO_EXTERNAL (value, ofn.lpstrTitle, Qmswindows_tstr);
494 else if (EQ (key, Q_initial_directory))
495 LOCAL_FILE_FORMAT_TO_TSTR (Fexpand_file_name (value, Qnil),
496 ofn.lpstrInitialDir);
497 else if (EQ (key, Q_file_must_exist))
500 ofn.Flags |= OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST;
502 ofn.Flags &= ~(OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST);
505 syntax_error ("Unrecognized file-dialog keyword", key);
509 if (!GetOpenFileName (&ofn))
511 DWORD err = CommDlgExtendedError ();
521 for (i = 0; i < countof (common_dialog_errors); i++)
523 if (common_dialog_errors[i].errmess == err)
524 signal_type_error (Qdialog_box_error,
525 "Creating file-dialog-box",
527 (common_dialog_errors[i].errname));
530 signal_type_error (Qdialog_box_error,
531 "Unknown common dialog box error???",
536 return tstr_to_local_file_format (ofn.lpstrFile);
540 handle_question_dialog_box (struct frame *f, Lisp_Object keys)
542 Lisp_Object_dynarr *dialog_items = Dynarr_new (Lisp_Object);
543 unsigned_char_dynarr *template = Dynarr_new (unsigned_char);
544 unsigned int button_row_width = 0;
545 unsigned int text_width, text_height;
546 Lisp_Object question = Qnil, title = Qnil;
548 int unbind_count = specpdl_depth ();
549 record_unwind_protect (free_dynarr_opaque_ptr,
550 make_opaque_ptr (dialog_items));
551 record_unwind_protect (free_dynarr_opaque_ptr,
552 make_opaque_ptr (template));
554 /* A big NO NEED to GCPRO gui_items stored in the array: they are just
555 pointers into KEYS list, which is GC-protected by the caller */
558 EXTERNAL_PROPERTY_LIST_LOOP_3 (key, value, keys)
560 if (EQ (key, Q_question))
562 CHECK_STRING (value);
565 else if (EQ (key, Q_title))
567 CHECK_STRING (value);
570 else if (EQ (key, Q_buttons))
572 Lisp_Object item_cons;
574 /* Parse each item in the dialog into gui_item structs,
575 and stuff a dynarr of these. Calculate button row width
577 EXTERNAL_LIST_LOOP (item_cons, value)
579 if (!NILP (XCAR (item_cons)))
582 gui_parse_item_keywords (XCAR (item_cons));
583 Dynarr_add (dialog_items, gitem);
584 button_row_width += button_width (XGUI_ITEM (gitem)->name)
589 button_row_width -= X_BUTTON_MARGIN;
592 syntax_error ("Unrecognized question-dialog keyword", key);
596 if (Dynarr_length (dialog_items) == 0)
597 syntax_error ("Dialog descriptor provides no buttons", keys);
600 syntax_error ("Dialog descriptor provides no question", keys);
602 /* Determine the final width layout */
604 Bufbyte *p = XSTRING_DATA (question);
605 Charcount string_max = 0, this_length = 0;
608 Emchar ch = charptr_emchar (p);
611 if (ch == (Emchar)'\n' || ch == (Emchar)'\0')
613 string_max = max (this_length, string_max);
619 if (ch == (Emchar)'\0')
623 if (string_max * X_DLU_PER_CHAR > max (X_MAX_TEXT, button_row_width))
624 text_width = X_AVE_TEXT;
625 else if (string_max * X_DLU_PER_CHAR < X_MIN_TEXT)
626 text_width = X_MIN_TEXT;
628 text_width = string_max * X_DLU_PER_CHAR;
629 text_width = max (text_width, button_row_width);
632 /* Now calculate the height for the text control */
634 Bufbyte *p = XSTRING_DATA (question);
635 Charcount break_at = text_width / X_DLU_PER_CHAR;
636 Charcount char_pos = 0;
640 while ((ch = charptr_emchar (p)) != (Emchar) '\0')
643 char_pos += ch != (Emchar) '\n';
644 if (ch == (Emchar) '\n' || char_pos == break_at)
650 text_height = Y_TEXT_MARGIN + Y_DLU_PER_CHAR * num_lines;
653 /* Ok, now we are ready to stuff the dialog template and lay out controls */
656 DLGITEMTEMPLATE item_tem;
658 const unsigned int zeroes = 0;
659 const unsigned int ones = 0xFFFFFFFF;
660 const WORD static_class_id = 0x0082;
661 const WORD button_class_id = 0x0080;
663 /* Create and stuff in DLGTEMPLATE header */
664 dlg_tem.style = (DS_CENTER | DS_MODALFRAME | DS_SETFONT
665 | WS_CAPTION | WS_POPUP | WS_VISIBLE);
666 dlg_tem.dwExtendedStyle = 0;
667 dlg_tem.cdit = Dynarr_length (dialog_items) + 1;
670 dlg_tem.cx = text_width + 2 * X_TEXT_FROM_EDGE;
671 dlg_tem.cy = (Y_TEXT_FROM_EDGE + text_height + Y_TEXT_FROM_BUTTON
672 + Y_BUTTON + Y_BUTTON_FROM_EDGE);
673 Dynarr_add_many (template, &dlg_tem, sizeof (dlg_tem));
675 /* We want no menu and standard class */
676 Dynarr_add_many (template, &zeroes, 4);
678 /* And the third is the dialog title. "XEmacs" unless one is supplied.
679 Note that the string must be in Unicode. */
681 Dynarr_add_many (template, L"XEmacs", 14);
683 push_lisp_string_as_unicode (template, title);
685 /* We want standard dialog font */
686 Dynarr_add_many (template, L"\x08MS Shell Dlg", 28);
688 /* Next add text control. */
689 item_tem.style = WS_CHILD | WS_VISIBLE | SS_LEFT | SS_NOPREFIX;
690 item_tem.dwExtendedStyle = 0;
691 item_tem.x = X_TEXT_FROM_EDGE;
692 item_tem.y = Y_TEXT_FROM_EDGE;
693 item_tem.cx = text_width;
694 item_tem.cy = text_height;
695 item_tem.id = 0xFFFF;
698 Dynarr_add_many (template, &item_tem, sizeof (item_tem));
700 /* Right after class id follows */
701 Dynarr_add_many (template, &ones, 2);
702 Dynarr_add_many (template, &static_class_id, sizeof (static_class_id));
704 /* Next thing to add is control text, as Unicode string */
705 push_lisp_string_as_unicode (template, question);
707 /* Specify 0 length creation data */
708 Dynarr_add_many (template, &zeroes, 2);
710 /* Now it's the button time */
711 item_tem.y = Y_TEXT_FROM_EDGE + text_height + Y_TEXT_FROM_BUTTON;
712 item_tem.x = X_BUTTON_FROM_EDGE + (button_row_width < text_width
713 ? (text_width - button_row_width) / 2
715 item_tem.cy = Y_BUTTON;
716 item_tem.dwExtendedStyle = 0;
718 for (i = 0; i < Dynarr_length (dialog_items); ++i)
720 Lisp_Object* gui_item = Dynarr_atp (dialog_items, i);
721 Lisp_Gui_Item *pgui_item = XGUI_ITEM (*gui_item);
723 item_tem.style = (WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON
724 | (gui_item_active_p (*gui_item) ? 0 : WS_DISABLED));
725 item_tem.cx = button_width (pgui_item->name);
726 /* Item ids are indices into dialog_items plus offset, to avoid having
727 items by reserved ids (IDOK, IDCANCEL) */
728 item_tem.id = i + ID_ITEM_BIAS;
731 Dynarr_add_many (template, &item_tem, sizeof (item_tem));
733 /* Right after 0xFFFF and class id atom follows */
734 Dynarr_add_many (template, &ones, 2);
735 Dynarr_add_many (template, &button_class_id, sizeof (button_class_id));
737 /* Next thing to add is control text, as Unicode string */
739 Lisp_Object ctext = pgui_item->name;
741 Bufbyte *trans = (Bufbyte *) alloca (2 * XSTRING_LENGTH (ctext) + 3);
744 memcpy (trans, XSTRING_DATA (ctext), XSTRING_LENGTH (ctext) + 1);
746 mswindows_translate_menu_or_dialog_item (trans,
747 XSTRING_LENGTH (ctext),
748 2 * XSTRING_LENGTH (ctext) + 3,
751 push_bufbyte_string_as_unicode (template, trans, translen);
754 /* Specify 0 length creation data. */
755 Dynarr_add_many (template, &zeroes, 2);
757 item_tem.x += item_tem.cx + X_BUTTON_SPACING;
761 /* Now the Windows dialog structure is ready. We need to prepare a
762 data structure for the new dialog, which will contain callbacks
763 and the frame for these callbacks. This structure has to be
764 GC-protected and thus it is put into a statically protected
767 Lisp_Object dialog_data;
769 struct mswindows_dialog_id *did =
770 alloc_lcrecord_type (struct mswindows_dialog_id,
771 &lrecord_mswindows_dialog_id);
773 XSETMSWINDOWS_DIALOG_ID (dialog_data, did);
775 did->frame = wrap_frame (f);
776 did->callbacks = make_vector (Dynarr_length (dialog_items), Qunbound);
777 for (i = 0; i < Dynarr_length (dialog_items); i++)
778 XVECTOR_DATA (did->callbacks) [i] =
779 XGUI_ITEM (*Dynarr_atp (dialog_items, i))->callback;
781 /* Woof! Everything is ready. Pop pop pop in now! */
783 CreateDialogIndirectParam (NULL,
784 (LPDLGTEMPLATE) Dynarr_atp (template, 0),
785 FRAME_MSWINDOWS_HANDLE (f), dialog_proc,
786 (LPARAM) LISP_TO_VOID (dialog_data));
788 /* Something went wrong creating the dialog */
789 signal_type_error (Qdialog_box_error, "Creating dialog", keys);
791 Vdialog_data_list = Fcons (dialog_data, Vdialog_data_list);
793 /* Cease protection and free dynarrays */
794 unbind_to (unbind_count, Qnil);
800 mswindows_make_dialog_box_internal (struct frame* f, Lisp_Object type,
803 int unbind_count = specpdl_depth ();
804 record_unwind_protect (dialog_popped_down, Qnil);
807 if (EQ (type, Qfile))
808 return unbind_to (unbind_count, handle_file_dialog_box (f, keys));
809 else if (EQ (type, Qdirectory))
810 return unbind_to (unbind_count, handle_directory_dialog_box (f, keys));
811 else if (EQ (type, Qquestion))
812 return unbind_to (unbind_count, handle_question_dialog_box (f, keys));
813 else if (EQ (type, Qprint))
814 return unbind_to (unbind_count, mswindows_handle_print_dialog_box (f, keys));
815 else if (EQ (type, Qpage_setup))
816 return unbind_to (unbind_count,
817 mswindows_handle_page_setup_dialog_box (f, keys));
819 signal_type_error (Qunimplemented, "Dialog box type", type);
824 console_type_create_dialog_mswindows (void)
826 CONSOLE_HAS_METHOD (mswindows, make_dialog_box_internal);
830 syms_of_dialog_mswindows (void)
832 INIT_LRECORD_IMPLEMENTATION (mswindows_dialog_id);
834 DEFKEYWORD (Q_initial_directory);
835 DEFKEYWORD (Q_initial_filename);
836 DEFKEYWORD (Q_filter_list);
837 DEFKEYWORD (Q_title);
838 DEFKEYWORD (Q_allow_multi_select);
839 DEFKEYWORD (Q_create_prompt_on_nonexistent);
840 DEFKEYWORD (Q_overwrite_prompt);
841 DEFKEYWORD (Q_file_must_exist);
842 DEFKEYWORD (Q_no_network_button);
843 DEFKEYWORD (Q_no_read_only_return);
846 DEFERROR_STANDARD (Qdialog_box_error, Qinvalid_operation);
850 vars_of_dialog_mswindows (void)
852 Vpopup_frame_list = Qnil;
853 staticpro (&Vpopup_frame_list);
855 Vdialog_data_list = Qnil;
856 staticpro (&Vdialog_data_list);
858 DEFVAR_LISP ("default-file-dialog-filter-alist",
859 &Vdefault_file_dialog_filter_alist /*
861 Vdefault_file_dialog_filter_alist =
862 list5 (Fcons (build_string ("Text Files"), build_string ("*.txt")),
863 Fcons (build_string ("C Files"), build_string ("*.c;*.h")),
864 Fcons (build_string ("Elisp Files"), build_string ("*.el")),
865 Fcons (build_string ("HTML Files"), build_string ("*.html;*.html")),
866 Fcons (build_string ("All Files"), build_string ("*.*")));