x-popup-dialog fixed, almost.

This commit is contained in:
Eli Zaretskii 2013-09-29 21:38:56 +03:00
parent 0fe3602a28
commit 0afa0aabd8
7 changed files with 204 additions and 298 deletions

View file

@ -1376,6 +1376,141 @@ no quit occurs and `x-popup-menu' returns nil. */)
return selection;
}
#ifdef HAVE_MENUS
DEFUN ("x-popup-dialog", Fx_popup_dialog, Sx_popup_dialog, 2, 3, 0,
doc: /* Pop up a dialog box and return user's selection.
POSITION specifies which frame to use.
This is normally a mouse button event or a window or frame.
If POSITION is t, it means to use the frame the mouse is on.
The dialog box appears in the middle of the specified frame.
CONTENTS specifies the alternatives to display in the dialog box.
It is a list of the form (DIALOG ITEM1 ITEM2...).
Each ITEM is a cons cell (STRING . VALUE).
The return value is VALUE from the chosen item.
An ITEM may also be just a string--that makes a nonselectable item.
An ITEM may also be nil--that means to put all preceding items
on the left of the dialog box and all following items on the right.
\(By default, approximately half appear on each side.)
If HEADER is non-nil, the frame title for the box is "Information",
otherwise it is "Question".
If the user gets rid of the dialog box without making a valid choice,
for instance using the window manager, then this produces a quit and
`x-popup-dialog' does not return. */)
(Lisp_Object position, Lisp_Object contents, Lisp_Object header)
{
struct frame *f = NULL;
Lisp_Object window;
/* Decode the first argument: find the window or frame to use. */
if (EQ (position, Qt)
|| (CONSP (position) && (EQ (XCAR (position), Qmenu_bar)
|| EQ (XCAR (position), Qtool_bar))))
{
#if 0 /* Using the frame the mouse is on may not be right. */
/* Use the mouse's current position. */
struct frame *new_f = SELECTED_FRAME ();
Lisp_Object bar_window;
enum scroll_bar_part part;
Time time;
Lisp_Object x, y;
(*mouse_position_hook) (&new_f, 1, &bar_window, &part, &x, &y, &time);
if (new_f != 0)
XSETFRAME (window, new_f);
else
window = selected_window;
#endif
window = selected_window;
}
else if (CONSP (position))
{
Lisp_Object tem = XCAR (position);
if (CONSP (tem))
window = Fcar (XCDR (position));
else
{
tem = Fcar (XCDR (position)); /* EVENT_START (position) */
window = Fcar (tem); /* POSN_WINDOW (tem) */
}
}
else if (WINDOWP (position) || FRAMEP (position))
window = position;
else
window = Qnil;
/* Decode where to put the menu. */
if (FRAMEP (window))
f = XFRAME (window);
else if (WINDOWP (window))
{
CHECK_LIVE_WINDOW (window);
f = XFRAME (WINDOW_FRAME (XWINDOW (window)));
}
else
/* ??? Not really clean; should be CHECK_WINDOW_OR_FRAME,
but I don't want to make one now. */
CHECK_WINDOW (window);
/* Force a redisplay before showing the dialog. If a frame is created
just before showing the dialog, its contents may not have been fully
drawn, as this depends on timing of events from the X server. Redisplay
is not done when a dialog is shown. If redisplay could be done in the
X event loop (i.e. the X event loop does not run in a signal handler)
this would not be needed.
Do this before creating the widget value that points to Lisp
string contents, because Fredisplay may GC and relocate them. */
Fredisplay (Qt);
#if defined (USE_X_TOOLKIT) || defined (USE_GTK)
if (FRAME_WINDOW_P (f))
return xw_popup_dialog (f, header, contents);
else
#endif
#if defined (HAVE_NTGUI) && defined (HAVE_DIALOGS)
if (FRAME_W32_P (f))
return w32_popup_dialog (f, header, contents);
else
#endif
#ifdef HAVE_NS
if (FRAME_NS_P (f))
return ns_popup_dialog (position, header, contents);
else
#endif
/* Display a menu with these alternatives
in the middle of frame F. */
{
Lisp_Object x, y, frame, newpos;
int frame_width, frame_height;
if (FRAME_WINDOW_P (f))
{
frame_width = FRAME_PIXEL_WIDTH (f);
frame_height = FRAME_PIXEL_HEIGHT (f);
}
else
{
frame_width = FRAME_COLS (f);
frame_height = FRAME_LINES (f);
}
XSETFRAME (frame, f);
XSETINT (x, frame_width / 2);
XSETINT (y, frame_height / 2);
newpos = list2 (list2 (x, y), frame);
return Fx_popup_menu (newpos,
list2 (Fcar (contents), contents));
}
}
#endif /* HAVE_MENUS */
void
syms_of_menu (void)
{
@ -1384,4 +1519,8 @@ syms_of_menu (void)
menu_items_inuse = Qnil;
defsubr (&Sx_popup_menu);
#ifdef HAVE_MENUS
defsubr (&Sx_popup_dialog);
#endif
}

View file

@ -1452,7 +1452,7 @@ - (NSRect) frame
Lisp_Object
ns_popup_dialog (Lisp_Object position, Lisp_Object contents, Lisp_Object header)
ns_popup_dialog (Lisp_Object position, Lisp_Object header, Lisp_Object contents)
{
id dialog;
Lisp_Object window, tem, title;
@ -1919,34 +1919,6 @@ - (Lisp_Object)runDialogAt: (NSPoint)p
}
DEFUN ("x-popup-dialog", Fx_popup_dialog, Sx_popup_dialog, 2, 3, 0,
doc: /* Pop up a dialog box and return user's selection.
POSITION specifies which frame to use.
This is normally a mouse button event or a window or frame.
If POSITION is t, it means to use the frame the mouse is on.
The dialog box appears in the middle of the specified frame.
CONTENTS specifies the alternatives to display in the dialog box.
It is a list of the form (DIALOG ITEM1 ITEM2...).
Each ITEM is a cons cell (STRING . VALUE).
The return value is VALUE from the chosen item.
An ITEM may also be just a string--that makes a nonselectable item.
An ITEM may also be nil--that means to put all preceding items
on the left of the dialog box and all following items on the right.
\(By default, approximately half appear on each side.)
If HEADER is non-nil, the frame title for the box is "Information",
otherwise it is "Question".
If the user gets rid of the dialog box without making a valid choice,
for instance using the window manager, then this produces a quit and
`x-popup-dialog' does not return. */)
(Lisp_Object position, Lisp_Object contents, Lisp_Object header)
{
return ns_popup_dialog (position, contents, header);
}
DEFUN ("menu-or-popup-active-p", Fmenu_or_popup_active_p, Smenu_or_popup_active_p, 0, 0, 0,
doc: /* Return t if a menu or popup dialog is active. */)
(void)
@ -1968,7 +1940,6 @@ Each ITEM is a cons cell (STRING . VALUE).
update menus there. */
trackingMenu = 1;
#endif
defsubr (&Sx_popup_dialog);
defsubr (&Sns_reset_menu);
defsubr (&Smenu_or_popup_active_p);

View file

@ -850,8 +850,8 @@ extern void find_and_call_menu_selection (struct frame *f,
extern Lisp_Object find_and_return_menu_selection (struct frame *f,
bool keymaps,
void *client_data);
extern Lisp_Object ns_popup_dialog (Lisp_Object position, Lisp_Object contents,
Lisp_Object header);
extern Lisp_Object ns_popup_dialog (Lisp_Object position, Lisp_Object header,
Lisp_Object contents);
#define NSAPP_DATA2_RUNASSCRIPT 10
extern void ns_run_ascript (void);

View file

@ -115,129 +115,34 @@ static int fill_in_menu (HMENU, widget_value *);
void w32_free_menu_strings (HWND);
#ifdef HAVE_MENUS
DEFUN ("x-popup-dialog", Fx_popup_dialog, Sx_popup_dialog, 2, 3, 0,
doc: /* Pop up a dialog box and return user's selection.
POSITION specifies which frame to use.
This is normally a mouse button event or a window or frame.
If POSITION is t, it means to use the frame the mouse is on.
The dialog box appears in the middle of the specified frame.
CONTENTS specifies the alternatives to display in the dialog box.
It is a list of the form (TITLE ITEM1 ITEM2...).
Each ITEM is a cons cell (STRING . VALUE).
The return value is VALUE from the chosen item.
An ITEM may also be just a string--that makes a nonselectable item.
An ITEM may also be nil--that means to put all preceding items
on the left of the dialog box and all following items on the right.
\(By default, approximately half appear on each side.)
If HEADER is non-nil, the frame title for the box is "Information",
otherwise it is "Question". */)
(Lisp_Object position, Lisp_Object contents, Lisp_Object header)
#ifdef HAVE_DIALOGS
Lisp_Object
w32_popup_dialog (struct frame *f, Lisp_Object header, Lisp_Object contents)
{
struct frame *f = NULL;
Lisp_Object window;
/* Decode the first argument: find the window or frame to use. */
if (EQ (position, Qt)
|| (CONSP (position) && (EQ (XCAR (position), Qmenu_bar)
|| EQ (XCAR (position), Qtool_bar))))
{
#if 0 /* Using the frame the mouse is on may not be right. */
/* Use the mouse's current position. */
struct frame *new_f = SELECTED_FRAME ();
Lisp_Object bar_window;
enum scroll_bar_part part;
Time time;
Lisp_Object x, y;
(*mouse_position_hook) (&new_f, 1, &bar_window, &part, &x, &y, &time);
if (new_f != 0)
XSETFRAME (window, new_f);
else
window = selected_window;
#endif
window = selected_window;
}
else if (CONSP (position))
{
Lisp_Object tem = XCAR (position);
if (CONSP (tem))
window = Fcar (XCDR (position));
else
{
tem = Fcar (XCDR (position)); /* EVENT_START (position) */
window = Fcar (tem); /* POSN_WINDOW (tem) */
}
}
else if (WINDOWP (position) || FRAMEP (position))
window = position;
else
window = Qnil;
/* Decode where to put the menu. */
if (FRAMEP (window))
f = XFRAME (window);
else if (WINDOWP (window))
{
CHECK_LIVE_WINDOW (window);
f = XFRAME (WINDOW_FRAME (XWINDOW (window)));
}
else
/* ??? Not really clean; should be CHECK_WINDOW_OR_FRAME,
but I don't want to make one now. */
CHECK_WINDOW (window);
Lisp_Object title;
char *error_name;
Lisp_Object selection;
check_window_system (f);
#ifndef HAVE_DIALOGS
/* Decode the dialog items from what was specified. */
title = Fcar (contents);
CHECK_STRING (title);
{
/* Handle simple Yes/No choices as MessageBox popups. */
if (is_simple_dialog (contents))
return simple_dialog_show (f, contents, header);
else
{
/* Display a menu with these alternatives
in the middle of frame F. */
Lisp_Object x, y, frame, newpos;
XSETFRAME (frame, f);
XSETINT (x, FRAME_PIXEL_WIDTH (f) / 2);
XSETINT (y, FRAME_PIXEL_HEIGHT (f) / 2);
newpos = Fcons (Fcons (x, Fcons (y, Qnil)), Fcons (frame, Qnil));
return Fx_popup_menu (newpos,
Fcons (Fcar (contents), Fcons (contents, Qnil)));
}
}
#else /* HAVE_DIALOGS */
{
Lisp_Object title;
char *error_name;
Lisp_Object selection;
list_of_panes (Fcons (contents, Qnil));
/* Decode the dialog items from what was specified. */
title = Fcar (contents);
CHECK_STRING (title);
/* Display them in a dialog box. */
block_input ();
selection = w32_dialog_show (f, 0, title, header, &error_name);
unblock_input ();
list_of_panes (Fcons (contents, Qnil));
discard_menu_items ();
FRAME_DISPLAY_INFO (f)->grabbed = 0;
/* Display them in a dialog box. */
block_input ();
selection = w32_dialog_show (f, 0, title, header, &error_name);
unblock_input ();
discard_menu_items ();
FRAME_DISPLAY_INFO (f)->grabbed = 0;
if (error_name) error (error_name);
return selection;
}
#endif /* HAVE_DIALOGS */
if (error_name) error (error_name);
return selection;
}
#endif /* HAVE_DIALOGS */
/* Activate the menu bar of frame F.
This is called from keyboard.c when it gets the
@ -1724,9 +1629,6 @@ syms_of_w32menu (void)
DEFSYM (Qdebug_on_next_call, "debug-on-next-call");
defsubr (&Smenu_or_popup_active_p);
#ifdef HAVE_MENUS
defsubr (&Sx_popup_dialog);
#endif
}
/*

View file

@ -798,6 +798,10 @@ typedef char guichar_t;
#define GUI_SDATA(x) ((guichar_t*) SDATA (x))
#if defined HAVE_DIALOGS
extern Lisp_Object w32_popup_dialog (struct frame *, Lisp_Object, Lisp_Object);
#endif
extern void syms_of_w32term (void);
extern void syms_of_w32menu (void);
extern void syms_of_w32fns (void);

View file

@ -192,149 +192,6 @@ mouse_position_for_popup (struct frame *f, int *x, int *y)
#endif /* HAVE_X_WINDOWS */
#ifdef HAVE_MENUS
DEFUN ("x-popup-dialog", Fx_popup_dialog, Sx_popup_dialog, 2, 3, 0,
doc: /* Pop up a dialog box and return user's selection.
POSITION specifies which frame to use.
This is normally a mouse button event or a window or frame.
If POSITION is t, it means to use the frame the mouse is on.
The dialog box appears in the middle of the specified frame.
CONTENTS specifies the alternatives to display in the dialog box.
It is a list of the form (DIALOG ITEM1 ITEM2...).
Each ITEM is a cons cell (STRING . VALUE).
The return value is VALUE from the chosen item.
An ITEM may also be just a string--that makes a nonselectable item.
An ITEM may also be nil--that means to put all preceding items
on the left of the dialog box and all following items on the right.
\(By default, approximately half appear on each side.)
If HEADER is non-nil, the frame title for the box is "Information",
otherwise it is "Question".
If the user gets rid of the dialog box without making a valid choice,
for instance using the window manager, then this produces a quit and
`x-popup-dialog' does not return. */)
(Lisp_Object position, Lisp_Object contents, Lisp_Object header)
{
struct frame *f = NULL;
Lisp_Object window;
/* Decode the first argument: find the window or frame to use. */
if (EQ (position, Qt)
|| (CONSP (position) && (EQ (XCAR (position), Qmenu_bar)
|| EQ (XCAR (position), Qtool_bar))))
{
#if 0 /* Using the frame the mouse is on may not be right. */
/* Use the mouse's current position. */
struct frame *new_f = SELECTED_FRAME ();
Lisp_Object bar_window;
enum scroll_bar_part part;
Time time;
Lisp_Object x, y;
(*mouse_position_hook) (&new_f, 1, &bar_window, &part, &x, &y, &time);
if (new_f != 0)
XSETFRAME (window, new_f);
else
window = selected_window;
#endif
window = selected_window;
}
else if (CONSP (position))
{
Lisp_Object tem = XCAR (position);
if (CONSP (tem))
window = Fcar (XCDR (position));
else
{
tem = Fcar (XCDR (position)); /* EVENT_START (position) */
window = Fcar (tem); /* POSN_WINDOW (tem) */
}
}
else if (WINDOWP (position) || FRAMEP (position))
window = position;
else
window = Qnil;
/* Decode where to put the menu. */
if (FRAMEP (window))
f = XFRAME (window);
else if (WINDOWP (window))
{
CHECK_LIVE_WINDOW (window);
f = XFRAME (WINDOW_FRAME (XWINDOW (window)));
}
else
/* ??? Not really clean; should be CHECK_WINDOW_OR_FRAME,
but I don't want to make one now. */
CHECK_WINDOW (window);
check_window_system (f);
/* Force a redisplay before showing the dialog. If a frame is created
just before showing the dialog, its contents may not have been fully
drawn, as this depends on timing of events from the X server. Redisplay
is not done when a dialog is shown. If redisplay could be done in the
X event loop (i.e. the X event loop does not run in a signal handler)
this would not be needed.
Do this before creating the widget value that points to Lisp
string contents, because Fredisplay may GC and relocate them. */
Fredisplay (Qt);
#if ! defined (USE_X_TOOLKIT) && ! defined (USE_GTK)
/* Display a menu with these alternatives
in the middle of frame F. */
{
Lisp_Object x, y, frame, newpos;
XSETFRAME (frame, f);
XSETINT (x, FRAME_PIXEL_WIDTH (f) / 2);
XSETINT (y, FRAME_PIXEL_HEIGHT (f) / 2);
newpos = list2 (list2 (x, y), frame);
return Fx_popup_menu (newpos,
list2 (Fcar (contents), contents));
}
#else
{
Lisp_Object title;
const char *error_name;
Lisp_Object selection;
ptrdiff_t specpdl_count = SPECPDL_INDEX ();
/* Decode the dialog items from what was specified. */
title = Fcar (contents);
CHECK_STRING (title);
record_unwind_protect_void (unuse_menu_items);
if (NILP (Fcar (Fcdr (contents))))
/* No buttons specified, add an "Ok" button so users can pop down
the dialog. Also, the lesstif/motif version crashes if there are
no buttons. */
contents = list2 (title, Fcons (build_string ("Ok"), Qt));
list_of_panes (list1 (contents));
/* Display them in a dialog box. */
block_input ();
selection = xdialog_show (f, 0, title, header, &error_name);
unblock_input ();
unbind_to (specpdl_count, Qnil);
discard_menu_items ();
if (error_name) error ("%s", error_name);
return selection;
}
#endif
}
#ifndef MSDOS
#if defined USE_GTK || defined USE_MOTIF
@ -2170,6 +2027,41 @@ xdialog_show (struct frame *f,
return Qnil;
}
Lisp_Object
xw_popup_dialog (struct frame *f, Lisp_Object header, Lisp_Object contents)
{
Lisp_Object title;
const char *error_name;
Lisp_Object selection;
ptrdiff_t specpdl_count = SPECPDL_INDEX ();
check_window_system (f);
/* Decode the dialog items from what was specified. */
title = Fcar (contents);
CHECK_STRING (title);
record_unwind_protect_void (unuse_menu_items);
if (NILP (Fcar (Fcdr (contents))))
/* No buttons specified, add an "Ok" button so users can pop down
the dialog. Also, the lesstif/motif version crashes if there are
no buttons. */
contents = list2 (title, Fcons (build_string ("Ok"), Qt));
list_of_panes (list1 (contents));
/* Display them in a dialog box. */
block_input ();
selection = xdialog_show (f, 0, title, header, &error_name);
unblock_input ();
unbind_to (specpdl_count, Qnil);
discard_menu_items ();
if (error_name) error ("%s", error_name);
return selection;
}
#else /* not USE_X_TOOLKIT && not USE_GTK */
/* The frame of the last activated non-toolkit menu bar.
@ -2531,8 +2423,6 @@ xmenu_show (struct frame *f, int x, int y, bool for_click, bool keymaps,
#endif /* not USE_X_TOOLKIT */
#endif /* HAVE_MENUS */
#ifndef MSDOS
/* Detect if a dialog or menu has been posted. MSDOS has its own
implementation on msdos.c. */
@ -2574,8 +2464,4 @@ syms_of_xmenu (void)
Ffset (intern_c_string ("accelerate-menu"),
intern_c_string (Sx_menu_bar_open_internal.symbol_name));
#endif
#ifdef HAVE_MENUS
defsubr (&Sx_popup_dialog);
#endif
}

View file

@ -1035,6 +1035,10 @@ extern void x_free_dpy_colors (Display *, Screen *, Colormap,
/* Defined in xmenu.c */
#if defined USE_X_TOOLKIT || defined USE_GTK
extern Lisp_Object xw_popup_dialog (struct frame *, Lisp_Object, Lisp_Object);
#endif
#if defined USE_GTK || defined USE_MOTIF
extern void x_menu_set_in_use (int);
#endif