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 /* Declared in general-slots.h
46 static Lisp_Object Q_title;
48 static Lisp_Object Q_allow_multi_select;
49 static Lisp_Object Q_create_prompt_on_nonexistent;
50 static Lisp_Object Q_overwrite_prompt;
51 static Lisp_Object Q_file_must_exist;
52 static Lisp_Object Q_no_network_button;
53 static Lisp_Object Q_no_read_only_return;
55 /* List containing all dialog data structures of currently popped up
57 static Lisp_Object Vdialog_data_list;
59 /* List of popup frames wanting keyboard traversal handled */
60 static Lisp_Object Vpopup_frame_list;
62 Lisp_Object Vdefault_file_dialog_filter_alist;
64 /* DLUs per character metrics */
65 #define X_DLU_PER_CHAR 4
66 #define Y_DLU_PER_CHAR 8
71 All buttons have height of 15 DLU. The minimum width for a button is 32 DLU,
72 but it can be expanded to accommodate its text, so the width is calculated as
73 8 DLU per button plus 4 DLU per character.
74 max (32, 6 * text_length). The factor of six is rather empirical, but it
75 works better than 8 which comes from the definition of a DLU. Buttons are
76 spaced with 6 DLU gap. Minimum distance from the button to the left or right
77 dialog edges is 6 DLU, and the distance between the dialog bottom edge and
81 #define X_MIN_BUTTON 32
82 #define X_BUTTON_MARGIN 8
84 #define X_BUTTON_SPACING 6
85 #define X_BUTTON_FROM_EDGE 6
86 #define Y_BUTTON_FROM_EDGE 7
91 Text distance from left and right edges is the same as for buttons, and the
92 top margin is 11 DLU. The static control has height of 2 DLU per control
93 plus 8 DLU per each line of text. Distance between the bottom edge of the
94 control and the button row is 15 DLU. Minimum width of the static control
95 is 100 DLU, thus giving minimum dialog weight of 112 DLU. Maximum width is
96 300 DLU, and, if the text is wider than that, the text is wrapped on the
97 next line. Each character in the text is considered 4 DLU wide.
100 #define X_MIN_TEXT 100
101 #define X_AVE_TEXT 200
102 #define X_MAX_TEXT 300
103 #define X_TEXT_FROM_EDGE X_BUTTON_FROM_EDGE
104 #define Y_TEXT_FROM_EDGE 11
105 #define Y_TEXT_MARGIN 2
106 #define Y_TEXT_FROM_BUTTON 15
108 #define X_MIN_TEXT_CHAR (X_MIN_TEXT / X_DLU_PER_CHAR)
109 #define X_AVE_TEXT_CHAR (X_AVE_TEXT / X_DLU_PER_CHAR)
110 #define X_MAX_TEXT_CHAR (X_MAX_TEXT / X_DLU_PER_CHAR)
115 First we calculate the minimum width of the button row, excluding "from
116 edge" distances. Note that the static control text can be narrower than
117 X_AVE_TEXT only if both text and button row are narrower than that (so,
118 even if text *can* be wrapped into 2 rows narrower than ave width, it is not
119 done). Let WBR denote the width of the button row.
121 Next, the width of the static field is determined.
122 First, if all lines of text fit into max (WBR, X_MAX_TEXT), the width of the
123 control is the same as the width of the longest line.
124 Second, if all lines of text are narrower than X_MIN_TEXT, then width of
125 the control is set to X_MIN_TEXT.
126 Otherwise, width is set to max(WBR, X_AVE_TEXT). In this case, line wrapping will
129 If width of the text control is larger than that of the button row, then the
130 latter is centered across the dialog, by giving it extra edge
131 margins. Otherwise, minimal margins are given to the button row.
134 #define ID_ITEM_BIAS 32
137 mswindows_register_popup_frame (Lisp_Object frame)
139 Vpopup_frame_list = Fcons (frame, Vpopup_frame_list);
143 mswindows_unregister_popup_frame (Lisp_Object frame)
145 Vpopup_frame_list = delq_no_quit (frame, Vpopup_frame_list);
148 /* Dispatch message to any dialog boxes. Return non-zero if dispatched. */
150 mswindows_is_dialog_msg (MSG *msg)
152 LIST_LOOP_2 (data, Vdialog_data_list)
154 if (IsDialogMessage (XMSWINDOWS_DIALOG_ID (data)->hwnd, msg))
159 LIST_LOOP_2 (popup, Vpopup_frame_list)
161 HWND hwnd = FRAME_MSWINDOWS_HANDLE (XFRAME (popup));
162 /* This is a windows feature that allows dialog type
163 processing to be applied to standard windows containing
165 if (IsDialogMessage (hwnd, msg))
173 mark_mswindows_dialog_id (Lisp_Object obj)
175 struct mswindows_dialog_id *data = XMSWINDOWS_DIALOG_ID (obj);
176 mark_object (data->frame);
177 return data->callbacks;
180 DEFINE_LRECORD_IMPLEMENTATION ("mswindows-dialog-id", mswindows_dialog_id,
181 mark_mswindows_dialog_id, 0, 0, 0, 0, 0,
182 struct mswindows_dialog_id);
184 /* Dialog procedure */
186 dialog_proc (HWND hwnd, UINT msg, WPARAM w_param, LPARAM l_param)
191 SetWindowLong (hwnd, DWL_USER, l_param);
197 VOID_TO_LISP (data, GetWindowLong (hwnd, DWL_USER));
198 Vdialog_data_list = delq_no_quit (data, Vdialog_data_list);
204 Lisp_Object fn, arg, data;
205 struct mswindows_dialog_id *did;
207 VOID_TO_LISP (data, GetWindowLong (hwnd, DWL_USER));
208 did = XMSWINDOWS_DIALOG_ID (data);
209 if (w_param != IDCANCEL) /* user pressed escape */
211 assert (w_param >= ID_ITEM_BIAS
213 < XVECTOR_LENGTH (did->callbacks) + ID_ITEM_BIAS);
215 get_gui_callback (XVECTOR_DATA (did->callbacks)
216 [w_param - ID_ITEM_BIAS],
218 mswindows_enqueue_misc_user_event (did->frame, fn, arg);
221 mswindows_enqueue_misc_user_event (did->frame, Qrun_hooks,
222 Qmenu_no_selection_hook);
223 /* #### need to error-protect! will do so when i merge in
225 va_run_hook_with_args (Qdelete_dialog_box_hook, 1, data);
227 DestroyWindow (hwnd);
237 /* Helper function which converts the supplied string STRING into Unicode and
238 pushes it at the end of DYNARR */
240 push_lisp_string_as_unicode (unsigned_char_dynarr* dynarr, Lisp_Object string)
242 Extbyte *mbcs_string;
243 Charcount length = XSTRING_CHAR_LENGTH (string);
246 TO_EXTERNAL_FORMAT (LISP_STRING, string,
247 C_STRING_ALLOCA, mbcs_string,
249 uni_string = alloca_array (WCHAR, length + 1);
250 length = MultiByteToWideChar (CP_ACP, 0, mbcs_string, -1,
251 uni_string, sizeof(WCHAR) * (length + 1));
252 Dynarr_add_many (dynarr, uni_string, sizeof(WCHAR) * length);
255 /* Helper function which converts the supplied string STRING into Unicode and
256 pushes it at the end of DYNARR */
258 push_bufbyte_string_as_unicode (unsigned_char_dynarr* dynarr, Bufbyte *string,
261 Extbyte *mbcs_string;
262 Charcount length = bytecount_to_charcount (string, len);
265 TO_EXTERNAL_FORMAT (C_STRING, string,
266 C_STRING_ALLOCA, mbcs_string,
268 uni_string = alloca_array (WCHAR, length + 1);
269 length = MultiByteToWideChar (CP_ACP, 0, mbcs_string, -1,
270 uni_string, sizeof(WCHAR) * (length + 1));
271 Dynarr_add_many (dynarr, uni_string, sizeof(WCHAR) * length);
274 /* Given button TEXT, return button width in DLU */
276 button_width (Lisp_Object text)
278 unsigned int width = X_DLU_PER_CHAR * XSTRING_CHAR_LENGTH (text);
279 return max (X_MIN_BUTTON, width);
282 /* Unwind protection routine frees a dynarr opaqued into arg */
284 free_dynarr_opaque_ptr (Lisp_Object arg)
286 Dynarr_free (get_opaque_ptr (arg));
290 /* Unwind protection decrements dialog count */
292 dialog_popped_down (Lisp_Object arg)
299 #define ALIGN_TEMPLATE \
301 unsigned int slippage = Dynarr_length (template) & 3; \
303 Dynarr_add_many (template, &zeroes, slippage); \
310 } common_dialog_errors[] =
312 { CDERR_DIALOGFAILURE, "CDERR_DIALOGFAILURE" },
313 { CDERR_FINDRESFAILURE, "CDERR_FINDRESFAILURE" },
314 { CDERR_INITIALIZATION, "CDERR_INITIALIZATION" },
315 { CDERR_LOADRESFAILURE, "CDERR_LOADRESFAILURE" },
316 { CDERR_LOADSTRFAILURE, "CDERR_LOADSTRFAILURE" },
317 { CDERR_LOCKRESFAILURE, "CDERR_LOCKRESFAILURE" },
318 { CDERR_MEMALLOCFAILURE, "CDERR_MEMALLOCFAILURE" },
319 { CDERR_MEMLOCKFAILURE, "CDERR_MEMLOCKFAILURE" },
320 { CDERR_NOHINSTANCE, "CDERR_NOHINSTANCE" },
321 { CDERR_NOHOOK, "CDERR_NOHOOK" },
322 { CDERR_NOTEMPLATE, "CDERR_NOTEMPLATE" },
323 { CDERR_REGISTERMSGFAIL, "CDERR_REGISTERMSGFAIL" },
324 { CDERR_STRUCTSIZE, "CDERR_STRUCTSIZE" },
325 { PDERR_CREATEICFAILURE, "PDERR_CREATEICFAILURE" },
326 { PDERR_DEFAULTDIFFERENT, "PDERR_DEFAULTDIFFERENT" },
327 { PDERR_DNDMMISMATCH, "PDERR_DNDMMISMATCH" },
328 { PDERR_GETDEVMODEFAIL, "PDERR_GETDEVMODEFAIL" },
329 { PDERR_INITFAILURE, "PDERR_INITFAILURE" },
330 { PDERR_LOADDRVFAILURE, "PDERR_LOADDRVFAILURE" },
331 { PDERR_NODEFAULTPRN, "PDERR_NODEFAULTPRN" },
332 { PDERR_NODEVICES, "PDERR_NODEVICES" },
333 { PDERR_PARSEFAILURE, "PDERR_PARSEFAILURE" },
334 { PDERR_PRINTERNOTFOUND, "PDERR_PRINTERNOTFOUND" },
335 { PDERR_RETDEFFAILURE, "PDERR_RETDEFFAILURE" },
336 { PDERR_SETUPFAILURE, "PDERR_SETUPFAILURE" },
337 { CFERR_MAXLESSTHANMIN, "CFERR_MAXLESSTHANMIN" },
338 { CFERR_NOFONTS, "CFERR_NOFONTS" },
339 { FNERR_BUFFERTOOSMALL, "FNERR_BUFFERTOOSMALL" },
340 { FNERR_INVALIDFILENAME, "FNERR_INVALIDFILENAME" },
341 { FNERR_SUBCLASSFAILURE, "FNERR_SUBCLASSFAILURE" },
342 { FRERR_BUFFERLENGTHZERO, "FRERR_BUFFERLENGTHZERO" },
352 CALLBACK handle_directory_proc (HWND hwnd, UINT msg,
353 LPARAM lParam, LPARAM lpData)
355 TCHAR szDir[MAX_PATH];
356 struct param_data* pd = (struct param_data*)lpData;
359 case BFFM_INITIALIZED:
360 // WParam is TRUE since you are passing a path.
361 // It would be FALSE if you were passing a pidl.
362 SendMessage(hwnd, BFFM_SETSELECTION, TRUE, (LPARAM)pd->fname);
365 case BFFM_SELCHANGED:
366 // Set the status window to the currently selected path.
367 if (SHGetPathFromIDList((LPITEMIDLIST) lParam, szDir)) {
368 SendMessage(hwnd, BFFM_SETSTATUSTEXT, 0, (LPARAM)szDir);
372 case BFFM_VALIDATEFAILED:
376 pd->unknown_fname = xstrdup((char*)lParam);
386 handle_directory_dialog_box (struct frame *f, Lisp_Object keys)
388 Lisp_Object ret = Qnil;
392 struct param_data pd;
397 bi.lParam = (LPARAM)&pd;
398 bi.hwndOwner = FRAME_MSWINDOWS_HANDLE (f);
399 bi.pszDisplayName = 0;
401 bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_STATUSTEXT | BIF_EDITBOX;
402 bi.lpfn = handle_directory_proc;
404 LOCAL_FILE_FORMAT_TO_TSTR (Fexpand_file_name (build_string (""), Qnil),
408 EXTERNAL_PROPERTY_LIST_LOOP_3 (key, value, keys)
410 if (EQ (key, Q_title))
412 CHECK_STRING (value);
413 LISP_STRING_TO_EXTERNAL (value, bi.lpszTitle, Qmswindows_tstr);
415 else if (EQ (key, Q_initial_directory))
416 LOCAL_FILE_FORMAT_TO_TSTR (Fexpand_file_name (value, Qnil),
418 else if (EQ (key, Q_initial_filename))
420 else if (EQ (key, Q_file_must_exist))
424 bi.ulFlags |= BIF_VALIDATE;
427 bi.ulFlags &= ~BIF_VALIDATE;
430 syntax_error ("Unrecognized directory dialog keyword", key);
434 if (SHGetMalloc(&pMalloc) == NOERROR)
436 pidl = SHBrowseForFolder(&bi);
438 TCHAR* szDir = alloca (MAX_PATH);
440 if (SHGetPathFromIDList(pidl, szDir)) {
441 ret = tstr_to_local_file_format (szDir);
444 pMalloc->lpVtbl->Free(pMalloc, pidl);
445 pMalloc->lpVtbl->Release(pMalloc);
448 else if (pd.unknown_fname != 0) {
449 ret = tstr_to_local_file_format (pd.unknown_fname);
450 xfree(pd.unknown_fname);
456 signal_type_error (Qdialog_box_error,
457 "Unable to create folder browser",
463 handle_file_dialog_box (struct frame *f, Lisp_Object keys)
470 ofn.lStructSize = sizeof (ofn);
471 ofn.Flags = OFN_EXPLORER;
472 ofn.hwndOwner = FRAME_MSWINDOWS_HANDLE (f);
473 ofn.lpstrFile = fnbuf;
474 ofn.nMaxFile = sizeof (fnbuf) / XETCHAR_SIZE;
475 xetcscpy (fnbuf, XETEXT (""));
477 LOCAL_FILE_FORMAT_TO_TSTR (Fexpand_file_name (build_string (""), Qnil),
478 ofn.lpstrInitialDir);
481 EXTERNAL_PROPERTY_LIST_LOOP_3 (key, value, keys)
483 if (EQ (key, Q_initial_filename))
487 CHECK_STRING (value);
488 LOCAL_FILE_FORMAT_TO_TSTR (value, fnout);
489 xetcscpy (fnbuf, fnout);
491 else if (EQ (key, Q_title))
493 CHECK_STRING (value);
494 LISP_STRING_TO_EXTERNAL (value, ofn.lpstrTitle, Qmswindows_tstr);
496 else if (EQ (key, Q_initial_directory))
497 LOCAL_FILE_FORMAT_TO_TSTR (Fexpand_file_name (value, Qnil),
498 ofn.lpstrInitialDir);
499 else if (EQ (key, Q_file_must_exist))
502 ofn.Flags |= OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST;
504 ofn.Flags &= ~(OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST);
507 syntax_error ("Unrecognized file-dialog keyword", key);
511 if (!GetOpenFileName (&ofn))
513 DWORD err = CommDlgExtendedError ();
523 for (i = 0; i < countof (common_dialog_errors); i++)
525 if (common_dialog_errors[i].errmess == err)
526 signal_type_error (Qdialog_box_error,
527 "Creating file-dialog-box",
529 (common_dialog_errors[i].errname));
532 signal_type_error (Qdialog_box_error,
533 "Unknown common dialog box error???",
538 return tstr_to_local_file_format (ofn.lpstrFile);
542 handle_question_dialog_box (struct frame *f, Lisp_Object keys)
544 Lisp_Object_dynarr *dialog_items = Dynarr_new (Lisp_Object);
545 unsigned_char_dynarr *template = Dynarr_new (unsigned_char);
546 unsigned int button_row_width = 0;
547 unsigned int text_width, text_height;
548 Lisp_Object question = Qnil, title = Qnil;
550 int unbind_count = specpdl_depth ();
551 record_unwind_protect (free_dynarr_opaque_ptr,
552 make_opaque_ptr (dialog_items));
553 record_unwind_protect (free_dynarr_opaque_ptr,
554 make_opaque_ptr (template));
556 /* A big NO NEED to GCPRO gui_items stored in the array: they are just
557 pointers into KEYS list, which is GC-protected by the caller */
560 EXTERNAL_PROPERTY_LIST_LOOP_3 (key, value, keys)
562 if (EQ (key, Q_question))
564 CHECK_STRING (value);
567 else if (EQ (key, Q_title))
569 CHECK_STRING (value);
572 else if (EQ (key, Q_buttons))
574 Lisp_Object item_cons;
576 /* Parse each item in the dialog into gui_item structs,
577 and stuff a dynarr of these. Calculate button row width
579 EXTERNAL_LIST_LOOP (item_cons, value)
581 if (!NILP (XCAR (item_cons)))
584 gui_parse_item_keywords (XCAR (item_cons));
585 Dynarr_add (dialog_items, gitem);
586 button_row_width += button_width (XGUI_ITEM (gitem)->name)
591 button_row_width -= X_BUTTON_MARGIN;
594 syntax_error ("Unrecognized question-dialog keyword", key);
598 if (Dynarr_length (dialog_items) == 0)
599 syntax_error ("Dialog descriptor provides no buttons", keys);
602 syntax_error ("Dialog descriptor provides no question", keys);
604 /* Determine the final width layout */
606 Bufbyte *p = XSTRING_DATA (question);
607 Charcount string_max = 0, this_length = 0;
610 Emchar ch = charptr_emchar (p);
613 if (ch == (Emchar)'\n' || ch == (Emchar)'\0')
615 string_max = max (this_length, string_max);
621 if (ch == (Emchar)'\0')
625 if (string_max * X_DLU_PER_CHAR > max (X_MAX_TEXT, button_row_width))
626 text_width = X_AVE_TEXT;
627 else if (string_max * X_DLU_PER_CHAR < X_MIN_TEXT)
628 text_width = X_MIN_TEXT;
630 text_width = string_max * X_DLU_PER_CHAR;
631 text_width = max (text_width, button_row_width);
634 /* Now calculate the height for the text control */
636 Bufbyte *p = XSTRING_DATA (question);
637 Charcount break_at = text_width / X_DLU_PER_CHAR;
638 Charcount char_pos = 0;
642 while ((ch = charptr_emchar (p)) != (Emchar) '\0')
645 char_pos += ch != (Emchar) '\n';
646 if (ch == (Emchar) '\n' || char_pos == break_at)
652 text_height = Y_TEXT_MARGIN + Y_DLU_PER_CHAR * num_lines;
655 /* Ok, now we are ready to stuff the dialog template and lay out controls */
658 DLGITEMTEMPLATE item_tem;
660 const unsigned int zeroes = 0;
661 const unsigned int ones = 0xFFFFFFFF;
662 const WORD static_class_id = 0x0082;
663 const WORD button_class_id = 0x0080;
665 /* Create and stuff in DLGTEMPLATE header */
666 dlg_tem.style = (DS_CENTER | DS_MODALFRAME | DS_SETFONT
667 | WS_CAPTION | WS_POPUP | WS_VISIBLE);
668 dlg_tem.dwExtendedStyle = 0;
669 dlg_tem.cdit = Dynarr_length (dialog_items) + 1;
672 dlg_tem.cx = text_width + 2 * X_TEXT_FROM_EDGE;
673 dlg_tem.cy = (Y_TEXT_FROM_EDGE + text_height + Y_TEXT_FROM_BUTTON
674 + Y_BUTTON + Y_BUTTON_FROM_EDGE);
675 Dynarr_add_many (template, &dlg_tem, sizeof (dlg_tem));
677 /* We want no menu and standard class */
678 Dynarr_add_many (template, &zeroes, 4);
680 /* And the third is the dialog title. "XEmacs" unless one is supplied.
681 Note that the string must be in Unicode. */
683 Dynarr_add_many (template, L"XEmacs", 14);
685 push_lisp_string_as_unicode (template, title);
687 /* We want standard dialog font */
688 Dynarr_add_many (template, L"\x08MS Shell Dlg", 28);
690 /* Next add text control. */
691 item_tem.style = WS_CHILD | WS_VISIBLE | SS_LEFT | SS_NOPREFIX;
692 item_tem.dwExtendedStyle = 0;
693 item_tem.x = X_TEXT_FROM_EDGE;
694 item_tem.y = Y_TEXT_FROM_EDGE;
695 item_tem.cx = text_width;
696 item_tem.cy = text_height;
697 item_tem.id = 0xFFFF;
700 Dynarr_add_many (template, &item_tem, sizeof (item_tem));
702 /* Right after class id follows */
703 Dynarr_add_many (template, &ones, 2);
704 Dynarr_add_many (template, &static_class_id, sizeof (static_class_id));
706 /* Next thing to add is control text, as Unicode string */
707 push_lisp_string_as_unicode (template, question);
709 /* Specify 0 length creation data */
710 Dynarr_add_many (template, &zeroes, 2);
712 /* Now it's the button time */
713 item_tem.y = Y_TEXT_FROM_EDGE + text_height + Y_TEXT_FROM_BUTTON;
714 item_tem.x = X_BUTTON_FROM_EDGE + (button_row_width < text_width
715 ? (text_width - button_row_width) / 2
717 item_tem.cy = Y_BUTTON;
718 item_tem.dwExtendedStyle = 0;
720 for (i = 0; i < Dynarr_length (dialog_items); ++i)
722 Lisp_Object* gui_item = Dynarr_atp (dialog_items, i);
723 Lisp_Gui_Item *pgui_item = XGUI_ITEM (*gui_item);
725 item_tem.style = (WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON
726 | (gui_item_active_p (*gui_item) ? 0 : WS_DISABLED));
727 item_tem.cx = button_width (pgui_item->name);
728 /* Item ids are indices into dialog_items plus offset, to avoid having
729 items by reserved ids (IDOK, IDCANCEL) */
730 item_tem.id = i + ID_ITEM_BIAS;
733 Dynarr_add_many (template, &item_tem, sizeof (item_tem));
735 /* Right after 0xFFFF and class id atom follows */
736 Dynarr_add_many (template, &ones, 2);
737 Dynarr_add_many (template, &button_class_id, sizeof (button_class_id));
739 /* Next thing to add is control text, as Unicode string */
741 Lisp_Object ctext = pgui_item->name;
743 Bufbyte *trans = (Bufbyte *) alloca (2 * XSTRING_LENGTH (ctext) + 3);
746 memcpy (trans, XSTRING_DATA (ctext), XSTRING_LENGTH (ctext) + 1);
748 mswindows_translate_menu_or_dialog_item (trans,
749 XSTRING_LENGTH (ctext),
750 2 * XSTRING_LENGTH (ctext) + 3,
753 push_bufbyte_string_as_unicode (template, trans, translen);
756 /* Specify 0 length creation data. */
757 Dynarr_add_many (template, &zeroes, 2);
759 item_tem.x += item_tem.cx + X_BUTTON_SPACING;
763 /* Now the Windows dialog structure is ready. We need to prepare a
764 data structure for the new dialog, which will contain callbacks
765 and the frame for these callbacks. This structure has to be
766 GC-protected and thus it is put into a statically protected
769 Lisp_Object dialog_data;
771 struct mswindows_dialog_id *did =
772 alloc_lcrecord_type (struct mswindows_dialog_id,
773 &lrecord_mswindows_dialog_id);
775 XSETMSWINDOWS_DIALOG_ID (dialog_data, did);
777 did->frame = wrap_frame (f);
778 did->callbacks = make_vector (Dynarr_length (dialog_items), Qunbound);
779 for (i = 0; i < Dynarr_length (dialog_items); i++)
780 XVECTOR_DATA (did->callbacks) [i] =
781 XGUI_ITEM (*Dynarr_atp (dialog_items, i))->callback;
783 /* Woof! Everything is ready. Pop pop pop in now! */
785 CreateDialogIndirectParam (NULL,
786 (LPDLGTEMPLATE) Dynarr_atp (template, 0),
787 FRAME_MSWINDOWS_HANDLE (f), dialog_proc,
788 (LPARAM) LISP_TO_VOID (dialog_data));
790 /* Something went wrong creating the dialog */
791 signal_type_error (Qdialog_box_error, "Creating dialog", keys);
793 Vdialog_data_list = Fcons (dialog_data, Vdialog_data_list);
795 /* Cease protection and free dynarrays */
796 unbind_to (unbind_count, Qnil);
802 mswindows_make_dialog_box_internal (struct frame* f, Lisp_Object type,
805 int unbind_count = specpdl_depth ();
806 record_unwind_protect (dialog_popped_down, Qnil);
809 if (EQ (type, Qfile))
810 return unbind_to (unbind_count, handle_file_dialog_box (f, keys));
811 else if (EQ (type, Qdirectory))
812 return unbind_to (unbind_count, handle_directory_dialog_box (f, keys));
813 else if (EQ (type, Qquestion))
814 return unbind_to (unbind_count, handle_question_dialog_box (f, keys));
815 else if (EQ (type, Qprint))
816 return unbind_to (unbind_count, mswindows_handle_print_dialog_box (f, keys));
817 else if (EQ (type, Qpage_setup))
818 return unbind_to (unbind_count,
819 mswindows_handle_page_setup_dialog_box (f, keys));
821 signal_type_error (Qunimplemented, "Dialog box type", type);
826 console_type_create_dialog_mswindows (void)
828 CONSOLE_HAS_METHOD (mswindows, make_dialog_box_internal);
832 syms_of_dialog_mswindows (void)
834 INIT_LRECORD_IMPLEMENTATION (mswindows_dialog_id);
836 DEFKEYWORD (Q_initial_directory);
837 DEFKEYWORD (Q_initial_filename);
838 DEFKEYWORD (Q_filter_list);
839 DEFKEYWORD (Q_title);
840 DEFKEYWORD (Q_allow_multi_select);
841 DEFKEYWORD (Q_create_prompt_on_nonexistent);
842 DEFKEYWORD (Q_overwrite_prompt);
843 DEFKEYWORD (Q_file_must_exist);
844 DEFKEYWORD (Q_no_network_button);
845 DEFKEYWORD (Q_no_read_only_return);
848 DEFERROR_STANDARD (Qdialog_box_error, Qinvalid_operation);
852 vars_of_dialog_mswindows (void)
854 Vpopup_frame_list = Qnil;
855 staticpro (&Vpopup_frame_list);
857 Vdialog_data_list = Qnil;
858 staticpro (&Vdialog_data_list);
860 DEFVAR_LISP ("default-file-dialog-filter-alist",
861 &Vdefault_file_dialog_filter_alist /*
863 Vdefault_file_dialog_filter_alist =
864 list5 (Fcons (build_string ("Text Files"), build_string ("*.txt")),
865 Fcons (build_string ("C Files"), build_string ("*.c;*.h")),
866 Fcons (build_string ("Elisp Files"), build_string ("*.el")),
867 Fcons (build_string ("HTML Files"), build_string ("*.html;*.html")),
868 Fcons (build_string ("All Files"), build_string ("*.*")));