Mercurial > hg > xemacs-beta
comparison lisp/dialog.el @ 442:abe6d1db359e r21-2-36
Import from CVS: tag r21-2-36
author | cvs |
---|---|
date | Mon, 13 Aug 2007 11:35:02 +0200 |
parents | 41ff10fd062f |
children | 576fb035e263 |
comparison
equal
deleted
inserted
replaced
441:72a7cfa4a488 | 442:abe6d1db359e |
---|---|
1 ;;; dialog.el --- Dialog-box support for XEmacs | 1 ;;; dialog.el --- Dialog-box support for XEmacs |
2 | 2 |
3 ;; Copyright (C) 1991-4, 1997 Free Software Foundation, Inc. | 3 ;; Copyright (C) 1991-4, 1997 Free Software Foundation, Inc. |
4 ;; Copyright (C) 2000 Ben Wing. | |
4 | 5 |
5 ;; Maintainer: XEmacs Development Team | 6 ;; Maintainer: XEmacs Development Team |
6 ;; Keywords: extensions, internal, dumped | 7 ;; Keywords: extensions, internal, dumped |
7 | 8 |
8 ;; This file is part of XEmacs. | 9 ;; This file is part of XEmacs. |
26 | 27 |
27 ;;; Commentary: | 28 ;;; Commentary: |
28 | 29 |
29 ;; This file is dumped with XEmacs (when dialog boxes are compiled in). | 30 ;; This file is dumped with XEmacs (when dialog boxes are compiled in). |
30 | 31 |
32 ;; Dialog boxes are non-modal at the C level, but made modal at the | |
33 ;; Lisp level via hacks in functions such as yes-or-no-p-dialog-box | |
34 ;; below. Perhaps there should be truly modal dialog boxes | |
35 ;; implemented at the C level for safety. All code using dialog boxes | |
36 ;; should be careful to assume that the environment, for example the | |
37 ;; current buffer, might be completely different after returning from | |
38 ;; yes-or-no-p-dialog-box, but such code is difficult to write and test. | |
39 | |
31 ;;; Code: | 40 ;;; Code: |
32 (defun yes-or-no-p-dialog-box (prompt) | 41 (defun yes-or-no-p-dialog-box (prompt) |
33 "Ask user a \"y or n\" question with a popup dialog box. | 42 "Ask user a yes-or-no question with a popup dialog box. |
34 Returns t if answer is \"yes\". | 43 Return t if the answer is \"yes\". |
35 Takes one argument, which is the string to display to ask the question." | 44 Takes one argument, which is the string to display to ask the question." |
36 (let ((echo-keystrokes 0) | 45 (save-selected-frame |
37 event) | 46 (make-dialog-box 'question |
38 (popup-dialog-box | 47 :question prompt |
39 ;; "Non-violent language please!" says Robin. | 48 :modal t |
40 (cons prompt '(["Yes" yes t] ["No" no t] nil ["Cancel" abort t]))) | 49 :buttons '(["Yes" (dialog-box-finish t)] |
41 ; (cons prompt '(["Yes" yes t] ["No" no t] nil ["Abort" abort t]))) | 50 ["No" (dialog-box-finish nil)] |
42 (catch 'ynp-done | 51 nil |
43 (while t | 52 ["Cancel" (dialog-box-cancel)])))) |
44 (setq event (next-command-event event)) | 53 |
45 (cond ((and (misc-user-event-p event) (eq (event-object event) 'yes)) | 54 ;; FSF has a similar function `x-popup-dialog'. |
46 (throw 'ynp-done t)) | |
47 ((and (misc-user-event-p event) (eq (event-object event) 'no)) | |
48 (throw 'ynp-done nil)) | |
49 ((and (misc-user-event-p event) | |
50 (or (eq (event-object event) 'abort) | |
51 (eq (event-object event) 'menu-no-selection-hook))) | |
52 (signal 'quit nil)) | |
53 ((button-release-event-p event) ;; don't beep twice | |
54 nil) | |
55 (t | |
56 (beep) | |
57 (message "please answer the dialog box"))))))) | |
58 | |
59 (defun yes-or-no-p-maybe-dialog-box (prompt) | |
60 "Ask user a yes-or-no question. Return t if answer is yes. | |
61 The question is asked with a dialog box or the minibuffer, as appropriate. | |
62 Takes one argument, which is the string to display to ask the question. | |
63 It should end in a space; `yes-or-no-p' adds `(yes or no) ' to it. | |
64 The user must confirm the answer with RET, | |
65 and can edit it until it as been confirmed." | |
66 (if (should-use-dialog-box-p) | |
67 (yes-or-no-p-dialog-box prompt) | |
68 (yes-or-no-p-minibuf prompt))) | |
69 | |
70 (defun y-or-n-p-maybe-dialog-box (prompt) | |
71 "Ask user a \"y or n\" question. Return t if answer is \"y\". | |
72 Takes one argument, which is the string to display to ask the question. | |
73 The question is asked with a dialog box or the minibuffer, as appropriate. | |
74 It should end in a space; `y-or-n-p' adds `(y or n) ' to it. | |
75 No confirmation of the answer is requested; a single character is enough. | |
76 Also accepts Space to mean yes, or Delete to mean no." | |
77 (if (should-use-dialog-box-p) | |
78 (yes-or-no-p-dialog-box prompt) | |
79 (y-or-n-p-minibuf prompt))) | |
80 | |
81 (if (fboundp 'popup-dialog-box) | |
82 (progn | |
83 (fset 'yes-or-no-p 'yes-or-no-p-maybe-dialog-box) | |
84 (fset 'y-or-n-p 'y-or-n-p-maybe-dialog-box))) | |
85 | |
86 ;; this is call-compatible with the horribly-named FSF Emacs function | |
87 ;; `x-popup-dialog'. I refuse to use that name. | |
88 (defun get-dialog-box-response (position contents) | 55 (defun get-dialog-box-response (position contents) |
89 ;; by Stig@hackvan.com | |
90 ;; modified by pez@atlantic2.sbi.com | |
91 "Pop up a dialog box and return user's selection. | 56 "Pop up a dialog box and return user's selection. |
92 POSITION specifies which frame to use. | 57 POSITION specifies which frame to use. |
93 This is normally an event or a window or frame. | 58 This is normally an event or a window or frame. |
94 If POSITION is t or nil, it means to use the frame the mouse is on. | 59 If POSITION is t or nil, it means to use the frame the mouse is on. |
95 The dialog box appears in the middle of the specified frame. | 60 The dialog box appears in the middle of the specified frame. |
107 (select-frame (event-frame position))) | 72 (select-frame (event-frame position))) |
108 ((framep position) | 73 ((framep position) |
109 (select-frame position)) | 74 (select-frame position)) |
110 ((windowp position) | 75 ((windowp position) |
111 (select-window position))) | 76 (select-window position))) |
112 (let ((dbox (cons (car contents) | 77 (make-dialog-box 'question |
113 (mapcar #'(lambda (x) | 78 :question (car contents) |
114 (cond | 79 :modal t |
115 ((null x) | 80 :buttons |
116 nil) | 81 (mapcar #'(lambda (x) |
117 ((stringp x) | 82 (cond |
118 `[,x 'ignore nil]) ;this will never get | 83 ((null x) |
119 ;selected | 84 nil) |
120 (t | 85 ((stringp x) |
121 `[,(car x) (throw 'result ',(cdr x)) t]))) | 86 ;;this will never get selected |
122 (cdr contents)) | 87 `[,x 'ignore nil]) |
123 ))) | 88 (t |
124 (catch 'result | 89 `[,(car x) (dialog-box-finish ',(cdr x)) t]))) |
125 (popup-dialog-box dbox) | 90 (cdr contents)))) |
126 (dispatch-event (next-command-event))))) | |
127 | 91 |
128 (defun message-box (fmt &rest args) | 92 (defun message-box (fmt &rest args) |
129 "Display a message, in a dialog box if possible. | 93 "Display a message, in a dialog box if possible. |
130 If the selected device has no dialog-box support, use the echo area. | 94 If the selected device has no dialog-box support, use the echo area. |
131 The arguments are the same as to `format'. | 95 The arguments are the same as to `format'. |
136 (progn | 100 (progn |
137 (clear-message nil) | 101 (clear-message nil) |
138 nil) | 102 nil) |
139 (let ((str (apply 'format fmt args))) | 103 (let ((str (apply 'format fmt args))) |
140 (if (device-on-window-system-p) | 104 (if (device-on-window-system-p) |
141 (get-dialog-box-response nil (list str (cons "OK" t))) | 105 (get-dialog-box-response nil (list str (cons "%_OK" t))) |
142 (display-message 'message str)) | 106 (display-message 'message str)) |
143 str))) | 107 str))) |
144 | 108 |
145 (defun message-or-box (fmt &rest args) | 109 (defun message-or-box (fmt &rest args) |
146 "Display a message in a dialog box or in the echo area.\n\ | 110 "Display a message in a dialog box or in the echo area. |
147 If this command was invoked with the mouse, use a dialog box.\n\ | 111 If this command was invoked with the mouse, use a dialog box. |
148 Otherwise, use the echo area. | 112 Otherwise, use the echo area. |
149 The arguments are the same as to `format'. | 113 The arguments are the same as to `format'. |
150 | 114 |
151 If the only argument is nil, clear any existing message; let the | 115 If the only argument is nil, clear any existing message; let the |
152 minibuffer contents show." | 116 minibuffer contents show." |
153 (if (should-use-dialog-box-p) | 117 (if (should-use-dialog-box-p) |
154 (apply 'message-box fmt args) | 118 (apply 'message-box fmt args) |
155 (apply 'message fmt args))) | 119 (apply 'message fmt args))) |
156 | 120 |
121 (defun make-dialog-box (type &rest cl-keys) | |
122 "Pop up a dialog box. | |
123 TYPE is a symbol, the type of dialog box. Remaining arguments are | |
124 keyword-value pairs, specifying the particular characteristics of the | |
125 dialog box. The allowed keywords are particular to each type, but | |
126 some standard keywords are common to many types: | |
127 | |
128 :title | |
129 The title of the dialog box's window. | |
130 | |
131 :modal | |
132 If true, indicates that XEmacs will wait until the user is \"done\" | |
133 with the dialog box (usually, this means that a response has been | |
134 given). Typically, the response is returned. NOTE: Some dialog | |
135 boxes are always modal. If the dialog box is modal, `make-dialog-box' | |
136 returns immediately. The return value will be either nil or a | |
137 dialog box handle of some sort, e.g. a frame for type `general'. | |
138 | |
139 --------------------------------------------------------------------------- | |
140 | |
141 Recognized types are | |
142 | |
143 general | |
144 A dialog box consisting of an XEmacs glyph, typically a `layout' | |
145 widget specifying a dialog box arrangement. This is the most | |
146 general and powerful dialog box type, but requires more work than | |
147 the other types below. | |
148 | |
149 question | |
150 A simple dialog box that displays a question and contains one or | |
151 more user-defined buttons to specify possible responses. (This is | |
152 compatible with the old built-in dialog boxes formerly specified | |
153 using `popup-dialog-box'.) | |
154 | |
155 file | |
156 A file dialog box, of the type typically used in the window system | |
157 XEmacs is running on. | |
158 | |
159 color | |
160 A color picker. | |
161 | |
162 find | |
163 A find dialog box. | |
164 | |
165 font | |
166 A font chooser. | |
167 | |
168 print | |
169 A dialog box used when printing (e.g. number of pages, printer). | |
170 | |
171 page-setup | |
172 A dialog box for setting page options (e.g. margins) for printing. | |
173 | |
174 replace | |
175 A find/replace dialog box. | |
176 | |
177 mswindows-message | |
178 An MS Windows-specific standard dialog box type similar to `question'. | |
179 | |
180 --------------------------------------------------------------------------- | |
181 | |
182 For type `general': | |
183 | |
184 This type creates a frame and puts the specified widget layout in it. | |
185 \(Currently this is done by eliminating all areas but the gutter and placing | |
186 the layout there; but this is an implementation detail and may change.) | |
187 | |
188 The keywords allowed for `general' are | |
189 | |
190 :spec | |
191 The widget spec -- anything that can be passed to `make-glyph'. | |
192 | |
193 :title | |
194 The title of the frame. | |
195 :parent | |
196 The frame is made a child of this frame (defaults to the selected frame). | |
197 | |
198 :properties | |
199 Additional properties of the frame, as well as `dialog-frame-plist'. | |
200 | |
201 --------------------------------------------------------------------------- | |
202 | |
203 For type `question': | |
204 | |
205 The keywords allowed are | |
206 | |
207 :modal | |
208 t or nil. When t, the dialog box callback should exit the dialog box | |
209 using the functions `dialog-box-finish' or `dialog-box-cancel'. | |
210 :title | |
211 The title of the frame. | |
212 :question | |
213 A string, the question. | |
214 :buttons | |
215 A list, describing the buttons below the question. Each of these is a | |
216 vector, the syntax of which is essentially the same as that of popup menu | |
217 items. They may have any of the following forms: | |
218 | |
219 [ \"name\" callback <active-p> ] | |
220 [ \"name\" callback <active-p> \"suffix\" ] | |
221 [ \"name\" callback :<keyword> <value> :<keyword> <value> ... ] | |
222 | |
223 The name is the string to display on the button; it is filtered through the | |
224 resource database, so it is possible for resources to override what string | |
225 is actually displayed. | |
226 | |
227 Accelerators can be indicated in the string by putting the sequence | |
228 \"%_\" before the character corresponding to the key that will invoke | |
229 the button. Uppercase and lowercase accelerators are equivalent. The | |
230 sequence \"%%\" is also special, and is translated into a single %. | |
231 | |
232 If the `callback' of a button is a symbol, then it must name a command. | |
233 It will be invoked with `call-interactively'. If it is a list, then it is | |
234 evaluated with `eval'. | |
235 | |
236 One (and only one) of the buttons may be `nil'. This marker means that all | |
237 following buttons should be flushright instead of flushleft. | |
238 | |
239 Though the keyword/value syntax is supported for dialog boxes just as in | |
240 popup menus, the only keyword which is both meaningful and fully implemented | |
241 for dialog box buttons is `:active'. | |
242 | |
243 --------------------------------------------------------------------------- | |
244 | |
245 For type `file': | |
246 | |
247 The keywords allowed are | |
248 | |
249 :initial-filename | |
250 The initial filename to be placed in the dialog box (defaults to nothing). | |
251 :initial-directory | |
252 The initial directory to be selected in the dialog box (defaults to the | |
253 current buffer's `default-directory). | |
254 :filter-list | |
255 A list of (filter-desc filter ...) | |
256 :title | |
257 The title of the dialog box (defaults to \"Open\"). | |
258 :allow-multi-select t or nil | |
259 :create-prompt-on-nonexistent t or nil | |
260 :overwrite-prompt t or nil | |
261 :file-must-exist t or nil | |
262 :no-network-button t or nil | |
263 :no-read-only-return t or nil | |
264 | |
265 --------------------------------------------------------------------------- | |
266 | |
267 For type `print': | |
268 | |
269 This invokes the Windows standard Print dialog. | |
270 This dialog is usually invoked when the user selects the Print command. | |
271 After the user presses OK, the program should start actual printout. | |
272 | |
273 The keywords allowed are | |
274 | |
275 :device | |
276 An 'msprinter device. | |
277 :print-settings | |
278 A printer settings object. | |
279 | |
280 Exactly one of these keywords must be given. | |
281 | |
282 The function brings up the Print dialog, where the user can | |
283 select a different printer and/or change printer options. Connection | |
284 name can change as a result of selecting a different printer device. If | |
285 a printer is specified, then changes are stored into the settings object | |
286 currently selected into that printer. If a settings object is supplied, | |
287 then changes are recorded into it, and, it it is selected into a | |
288 printer, then changes are propagated to that printer | |
289 too. | |
290 | |
291 Return value is nil if the user has canceled the dialog. Otherwise, it | |
292 is a new plist, with the following properties: | |
293 name Printer device name, even if unchanged by the user. | |
294 from-page First page to print, 1-based. If not specified by the user, | |
295 then this value is not included in the plist. | |
296 to-page Last page to print, inclusive, 1-based. If not specified by | |
297 the user, then this value is not included in the plist. | |
298 copies Number of copies to print. Always returned. | |
299 | |
300 The DEVICE is destroyed and an error is signaled in case of | |
301 initialization problem with the new printer. | |
302 | |
303 See also the `page-setup' and `print-setup' dialog boxes. | |
304 | |
305 --------------------------------------------------------------------------- | |
306 | |
307 For type `page-setup': | |
308 | |
309 This invokes the Windows standard Page Setup dialog. | |
310 This dialog is usually invoked in response to the Page Setup command, and | |
311 used to chose such parameters as page orientation, print margins etc. | |
312 Note that this dialog contains the \"Printer\" button, which invokes | |
313 the Printer Setup dialog (see `msprinter-print-setup-dialog') so that the | |
314 user can update the printer options or even select a different printer | |
315 as well. | |
316 | |
317 The keywords allowed are | |
318 | |
319 :device | |
320 An 'msprinter device. | |
321 :print-settings | |
322 A printer settings object. | |
323 :properties | |
324 A plist of job properties. | |
325 | |
326 Exactly one of these keywords must be given. | |
327 | |
328 The function brings up the Page Setup dialog, where the user | |
329 can select a different printer and/or change printer options. | |
330 Connection name can change as a result of selecting a different printer | |
331 device. If a printer is specified, then changes are stored into the | |
332 settings object currently selected into that printer. If a settings | |
333 object is supplied, then changes are recorded into it, and, it it is | |
334 selected into a printer, then changes are propagated to that printer | |
335 too. | |
336 | |
337 :properties specifies a plist of job properties; | |
338 see `default-msprinter-frame-plist' for the complete list. The plist | |
339 is used to initialize the dialog. | |
340 | |
341 Return value is nil if the user has canceled the dialog. Otherwise, | |
342 it is a new plist, containing the new list of properties. | |
343 | |
344 The DEVICE is destroyed and an error is signaled in case of | |
345 initialization problem with the new printer. | |
346 | |
347 See also the `print' and `print-setup' dialogs. | |
348 | |
349 --------------------------------------------------------------------------- | |
350 | |
351 For type `print-setup': | |
352 | |
353 This invokes the Windows standard Print Setup dialog. | |
354 This dialog is usually invoked when the user selects the Printer Setup | |
355 command. | |
356 | |
357 The keywords allowed are | |
358 | |
359 :device | |
360 An 'msprinter device. | |
361 :print-settings | |
362 A printer settings object. | |
363 | |
364 Exactly one of these keywords must be given. | |
365 | |
366 The function brings up the Print Setup dialog, where the user | |
367 can select a different printer and/or change printer options. | |
368 Connection name can change as a result of selecting a different printer | |
369 device. If a printer is specified, then changes are stored into the | |
370 settings object currently selected into that printer. If a settings | |
371 object is supplied, then changes are recorded into it, and, it it is | |
372 selected into a printer, then changes are propagated to that printer | |
373 too. | |
374 | |
375 Return value is nil if the user has canceled the dialog. Otherwise, it | |
376 is a new plist, with the following properties: | |
377 name Printer device name, even if unchanged by the user. | |
378 | |
379 The printer device is destroyed and an error is signaled if new printer | |
380 is selected by the user, but cannot be initialized. | |
381 | |
382 See also the `print' and `page-setup' dialogs. | |
383 | |
384 --------------------------------------------------------------------------- | |
385 | |
386 For type `mswindows-message': | |
387 | |
388 The keywords allowed are | |
389 | |
390 :title | |
391 The title of the dialog box. | |
392 :message | |
393 The string to display. | |
394 :flags | |
395 A symbol or list of symbols: | |
396 | |
397 -- To specify the buttons in the message box: | |
398 | |
399 abortretryignore | |
400 The message box contains three push buttons: Abort, Retry, and Ignore. | |
401 ok | |
402 The message box contains one push button: OK. This is the default. | |
403 okcancel | |
404 The message box contains two push buttons: OK and Cancel. | |
405 retrycancel | |
406 The message box contains two push buttons: Retry and Cancel. | |
407 yesno | |
408 The message box contains two push buttons: Yes and No. | |
409 yesnocancel | |
410 The message box contains three push buttons: Yes, No, and Cancel. | |
411 | |
412 | |
413 -- To display an icon in the message box: | |
414 | |
415 iconexclamation, iconwarning | |
416 An exclamation-point icon appears in the message box. | |
417 iconinformation, iconasterisk | |
418 An icon consisting of a lowercase letter i in a circle appears in | |
419 the message box. | |
420 iconquestion | |
421 A question-mark icon appears in the message box. | |
422 iconstop, iconerror, iconhand | |
423 A stop-sign icon appears in the message box. | |
424 | |
425 | |
426 -- To indicate the default button: | |
427 | |
428 defbutton1 | |
429 The first button is the default button. This is the default. | |
430 defbutton2 | |
431 The second button is the default button. | |
432 defbutton3 | |
433 The third button is the default button. | |
434 defbutton4 | |
435 The fourth button is the default button. | |
436 | |
437 | |
438 -- To indicate the modality of the dialog box: | |
439 | |
440 applmodal | |
441 The user must respond to the message box before continuing work in | |
442 the window identified by the hWnd parameter. However, the user can | |
443 move to the windows of other applications and work in those windows. | |
444 Depending on the hierarchy of windows in the application, the user | |
445 may be able to move to other windows within the application. All | |
446 child windows of the parent of the message box are automatically | |
447 disabled, but popup windows are not. This is the default. | |
448 systemmodal | |
449 Same as applmodal except that the message box has the WS_EX_TOPMOST | |
450 style. Use system-modal message boxes to notify the user of serious, | |
451 potentially damaging errors that require immediate attention (for | |
452 example, running out of memory). This flag has no effect on the | |
453 user's ability to interact with windows other than those associated | |
454 with hWnd. | |
455 taskmodal | |
456 Same as applmodal except that all the top-level windows belonging to | |
457 the current task are disabled if the hWnd parameter is NULL. Use | |
458 this flag when the calling application or library does not have a | |
459 window handle available but still needs to prevent input to other | |
460 windows in the current application without suspending other | |
461 applications. | |
462 | |
463 | |
464 In addition, you can specify the following flags: | |
465 | |
466 default-desktop-only | |
467 The desktop currently receiving input must be a default desktop; | |
468 otherwise, the function fails. A default desktop is one an | |
469 application runs on after the user has logged on. | |
470 help | |
471 Adds a Help button to the message box. Choosing the Help button or | |
472 pressing F1 generates a Help event. | |
473 right | |
474 The text is right-justified. | |
475 rtlreading | |
476 Displays message and caption text using right-to-left reading order | |
477 on Hebrew and Arabic systems. | |
478 setforeground | |
479 The message box becomes the foreground window. Internally, Windows | |
480 calls the SetForegroundWindow function for the message box. | |
481 topmost | |
482 The message box is created with the WS_EX_TOPMOST window style. | |
483 service-notification | |
484 Windows NT only: The caller is a service notifying the user of an | |
485 event. The function displays a message box on the current active | |
486 desktop, even if there is no user logged on to the computer. If | |
487 this flag is set, the hWnd parameter must be NULL. This is so the | |
488 message box can appear on a desktop other than the desktop | |
489 corresponding to the hWnd. | |
490 | |
491 | |
492 The return value is one of the following menu-item values returned by | |
493 the dialog box: | |
494 | |
495 abort | |
496 Abort button was selected. | |
497 cancel | |
498 Cancel button was selected. | |
499 ignore | |
500 Ignore button was selected. | |
501 no | |
502 No button was selected. | |
503 ok | |
504 OK button was selected. | |
505 retry | |
506 Retry button was selected. | |
507 yes | |
508 Yes button was selected. | |
509 | |
510 If a message box has a Cancel button, the function returns the | |
511 `cancel' value if either the ESC key is pressed or the Cancel button | |
512 is selected. If the message box has no Cancel button, pressing ESC has | |
513 no effect." | |
514 (flet ((dialog-box-modal-loop (thunk) | |
515 (let* ((frames (frame-list)) | |
516 (result | |
517 ;; ok, this is extremely tricky. normally a modal | |
518 ;; dialog will pop itself down using (dialog-box-finish) | |
519 ;; or (dialog-box-cancel), which throws back to this | |
520 ;; catch. but question dialog boxes pop down themselves | |
521 ;; regardless, so a badly written question dialog box | |
522 ;; that does not use (dialog-box-finish) could seriously | |
523 ;; wedge us. furthermore, we disable all other frames | |
524 ;; in order to implement modality; we need to restore | |
525 ;; them before the dialog box is destroyed, because | |
526 ;; otherwise windows at least will notice that no top- | |
527 ;; level window can have the focus and will shift the | |
528 ;; focus to a different app, raising it and obscuring us. | |
529 ;; so we create `delete-dialog-box-hook', which is | |
530 ;; called right *before* the dialog box gets destroyed. | |
531 ;; here, we put a hook on it, and when it's our dialog | |
532 ;; box and not someone else's that's being destroyed, | |
533 ;; we reenable all the frames and remove the hook. | |
534 ;; BUT ... we still have to deal with exiting the | |
535 ;; modal loop in case it doesn't happen before us. | |
536 ;; we can't do this until after the callbacks for this | |
537 ;; dialog box get executed, and that doesn't happen until | |
538 ;; after the dialog box is destroyed. so to keep things | |
539 ;; synchronous, we enqueue an eval event, which goes into | |
540 ;; the same queue as the misc-user events encapsulating | |
541 ;; the dialog callbacks and will go after it (because | |
542 ;; destroying the dialog box happens after processing | |
543 ;; its selection). if the dialog boxes are written | |
544 ;; properly, we don't see this eval event, because we've | |
545 ;; already exited our modal loop. (Thus, we make sure the | |
546 ;; function given in this eval event is actually defined | |
547 ;; and does nothing.) If we do see it, though, we know | |
548 ;; that we encountered a badly written dialog box and | |
549 ;; need to exit now. Currently we just return nil, but | |
550 ;; maybe we should signal an error or issue a warning. | |
551 (catch 'internal-dialog-box-finish | |
552 (let ((id (eval thunk)) | |
553 (sym (gensym))) | |
554 (fset sym | |
555 `(lambda (did) | |
556 (when (eq ',id did) | |
557 (mapc 'enable-frame ',frames) | |
558 (enqueue-eval-event | |
559 'internal-make-dialog-box-exit did) | |
560 (remove-hook 'delete-dialog-box-hook | |
561 ',sym)))) | |
562 (add-hook 'delete-dialog-box-hook sym) | |
563 (mapc 'disable-frame frames) | |
564 (block nil | |
565 (while t | |
566 (let ((event (next-event))) | |
567 (if (and (eval-event-p event) | |
568 (eq (event-function event) | |
569 'internal-make-dialog-box-exit) | |
570 (eq (event-object event) id)) | |
571 (return '(nil)) | |
572 (dispatch-event event))))))))) | |
573 (if (listp result) | |
574 (car result) | |
575 (signal 'quit nil))))) | |
576 (case type | |
577 (general | |
578 (cl-parsing-keywords | |
579 ((:title "XEmacs") | |
580 (:parent (selected-frame)) | |
581 :modal | |
582 :properties | |
583 :spec) | |
584 () | |
585 (flet ((create-dialog-box-frame () | |
586 (let* ((ftop (frame-property cl-parent 'top)) | |
587 (fleft (frame-property cl-parent 'left)) | |
588 (fwidth (frame-pixel-width cl-parent)) | |
589 (fheight (frame-pixel-height cl-parent)) | |
590 (fonth (font-height (face-font 'default))) | |
591 (fontw (font-width (face-font 'default))) | |
592 (cl-properties (append cl-properties | |
593 dialog-frame-plist)) | |
594 (dfheight (plist-get cl-properties 'height)) | |
595 (dfwidth (plist-get cl-properties 'width)) | |
596 (unmapped (plist-get cl-properties | |
597 'initially-unmapped)) | |
598 (gutter-spec cl-spec) | |
599 (name (or (plist-get cl-properties 'name) "XEmacs")) | |
600 (frame nil)) | |
601 (plist-remprop cl-properties 'initially-unmapped) | |
602 ;; allow the user to just provide a glyph | |
603 (or (glyphp cl-spec) (setq cl-spec (make-glyph cl-spec))) | |
604 (setq gutter-spec (copy-sequence "\n")) | |
605 (set-extent-begin-glyph (make-extent 0 1 gutter-spec) | |
606 cl-spec) | |
607 ;; under FVWM at least, if I don't specify the | |
608 ;; initial position, it ends up always at (0, 0). | |
609 ;; xwininfo doesn't tell me that there are any | |
610 ;; program-specified position hints, so it must be | |
611 ;; an FVWM bug. So just be smashing and position in | |
612 ;; the center of the selected frame. | |
613 (setq frame | |
614 (make-frame | |
615 (append cl-properties | |
616 `(popup ,cl-parent initially-unmapped t | |
617 menubar-visible-p nil | |
618 has-modeline-p nil | |
619 default-toolbar-visible-p nil | |
620 top-gutter-visible-p t | |
621 top-gutter-height , | |
622 (* dfheight fonth) | |
623 top-gutter ,gutter-spec | |
624 minibuffer none | |
625 name ,name | |
626 modeline-shadow-thickness 0 | |
627 vertical-scrollbar-visible-p nil | |
628 horizontal-scrollbar-visible-p nil | |
629 unsplittable t | |
630 left ,(+ fleft (- (/ fwidth 2) | |
631 (/ (* dfwidth | |
632 fontw) | |
633 2))) | |
634 top ,(+ ftop (- (/ fheight 2) | |
635 (/ (* dfheight | |
636 fonth) | |
637 2))))))) | |
638 (set-face-foreground 'modeline [default foreground] frame) | |
639 (set-face-background 'modeline [default background] frame) | |
640 (unless unmapped (make-frame-visible frame)) | |
641 (let ((newbuf (generate-new-buffer " *dialog box*"))) | |
642 (set-buffer-dedicated-frame newbuf frame) | |
643 (set-frame-property frame 'dialog-box-buffer newbuf) | |
644 (with-current-buffer newbuf | |
645 (setq frame-title-format cl-title) | |
646 (make-local-hook 'delete-frame-hook) | |
647 (add-hook 'delete-frame-hook | |
648 #'(lambda (frame) | |
649 (kill-buffer | |
650 (frame-property | |
651 frame | |
652 'dialog-box-buffer)))))) | |
653 frame))) | |
654 (if cl-modal | |
655 (dialog-box-modal-loop '(create-dialog-box-frame)) | |
656 (create-dialog-box-frame))))) | |
657 (question | |
658 (cl-parsing-keywords | |
659 ((:modal nil)) | |
660 t | |
661 (remf cl-keys :modal) | |
662 (if cl-modal | |
663 (dialog-box-modal-loop `(make-dialog-box-internal ',type | |
664 ',cl-keys)) | |
665 (make-dialog-box-internal type cl-keys)))) | |
666 (t | |
667 (make-dialog-box-internal type cl-keys))))) | |
668 | |
669 (defun dialog-box-finish (result) | |
670 "Exit a modal dialog box, returning RESULT. | |
671 This is meant to be executed from a dialog box callback function." | |
672 (throw 'internal-dialog-box-finish (list result))) | |
673 | |
674 (defun dialog-box-cancel () | |
675 "Cancel a modal dialog box. | |
676 This is meant to be executed from a dialog box callback function." | |
677 (throw 'internal-dialog-box-finish 'cancel)) | |
678 | |
679 ;; an eval event, used as a trigger inside of the dialog modal loop. | |
680 (defun internal-make-dialog-box-exit (did) | |
681 nil) | |
682 | |
683 (make-obsolete 'popup-dialog-box 'make-dialog-box) | |
684 (defun popup-dialog-box (desc) | |
685 "Obsolete equivalent of (make-dialog-box 'question ...). | |
686 | |
687 \(popup-dialog-box (QUESTION BUTTONS ...) | |
688 | |
689 is equivalent to | |
690 | |
691 \(make-dialog-box 'question :question QUESTION :buttons BUTTONS)" | |
692 (check-argument-type 'stringp (car desc)) | |
693 (or (consp (cdr desc)) | |
694 (error 'syntax-error | |
695 "Dialog descriptor must supply at least one button" | |
696 desc)) | |
697 (make-dialog-box 'question :question (car desc) :buttons (cdr desc))) | |
698 | |
157 ;;; dialog.el ends here | 699 ;;; dialog.el ends here |