/* Generic frame functions.
- Copyright (C) 1989, 1992, 1993 Free Software Foundation.
+ Copyright (C) 1993 Free Software Foundation.
This file is part of GNU Emacs.
#include <stdio.h>
-#include "config.h"
+#include <config.h>
#include "lisp.h"
#include "frame.h"
+#include "termhooks.h"
#ifdef MULTI_FRAME
#include "buffer.h"
#include "window.h"
-#include "termhooks.h"
/* These help us bind and responding to switch-frame events. */
#include "commands.h"
extern Lisp_Object Vminibuffer_list;
extern Lisp_Object get_minibuffer ();
+extern Lisp_Object Fhandle_switch_frame ();
+extern Lisp_Object Fredirect_frame_focus ();
\f
DEFUN ("framep", Fframep, Sframep, 1, 1, 0,
"Return non-nil if OBJECT is a frame.\n\
f->param_alist = Qnil;
f->scroll_bars = Qnil;
f->condemned_scroll_bars = Qnil;
+ f->face_alist = Qnil;
root_window = make_window ();
if (mini_p)
a newly-created, never-selected window. */
XFASTINT (XWINDOW (f->selected_window)->use_time) = ++window_select_count;
- Vframe_list = Fcons (frame, Vframe_list);
-
return f;
}
\f
make_terminal_frame ()
{
register struct frame *f;
+ Lisp_Object frame;
Vframe_list = Qnil;
f = make_frame (1);
+
+ XSET (frame, Lisp_Frame, f);
+ Vframe_list = Fcons (frame, Vframe_list);
+
f->name = build_string ("terminal");
FRAME_SET_VISIBLE (f, 1);
f->display.nothing = 1; /* Nonzero means frame isn't deleted. */
}
\f
DEFUN ("select-frame", Fselect_frame, Sselect_frame, 1, 2, "e",
- "Select the frame FRAME. FRAME's selected window becomes \"the\"\n\
-selected window. If the optional parameter NO-ENTER is non-nil, don't\n\
-focus on that frame.\n\
-\n\
-This function is interactive, and may be bound to the ``switch-frame''\n\
-event; when invoked this way, it switches to the frame named in the\n\
-event. When called from lisp, FRAME may be a ``switch-frame'' event;\n\
-if it is, select the frame named in the event.\n\
+ "Select the frame FRAME.\n\
+Subsequent editing commands apply to its selected window.\n\
+The selection of FRAME lasts until the next time the user does\n\
+something to select a different frame, or until the next time this\n\
+function is called.")
+ (frame, no_enter)
+ Lisp_Object frame, no_enter;
+{
+ return Fhandle_switch_frame (frame, no_enter);
+}
+
+
+DEFUN ("handle-switch-frame", Fhandle_switch_frame, Shandle_switch_frame, 1, 2, "e",
+ "Handle a switch-frame event EVENT.\n\
+Switch-frame events are usually bound to this function.\n\
+A switch-frame event tells Emacs that the window manager has requested\n\
+that the user's events be directed to the frame mentioned in the event.\n\
+This function selects the selected window of the frame of EVENT.\n\
\n\
-Changing the selected frame can change focus redirections. See\n\
-`redirect-frame-focus' for details.")
+If EVENT is frame object, handle it as if it were a switch-frame event\n\
+to that frame.")
(frame, no_enter)
Lisp_Object frame, no_enter;
{
last_nonminibuf_frame = selected_frame;
Fselect_window (XFRAME (frame)->selected_window);
-
- /* I think this should be done with a hook. */
-#ifdef HAVE_X_WINDOWS
- if (FRAME_X_P (XFRAME (frame))
- && NILP (no_enter))
- {
- Ffocus_frame (frame);
- }
-#endif
choose_minibuf_frame ();
/* We want to make sure that the next event generates a frame-switch
- event to the appropriate frame. This seems kludgey to me, but
+ event to the appropriate frame. This seems kludgy to me, but
before you take it out, make sure that evaluating something like
(select-window (frame-root-window (new-frame))) doesn't end up
with your typing being interpreted in the new frame instead of
return prev;
}
+
DEFUN ("next-frame", Fnext_frame, Snext_frame, 0, 2, 0,
"Return the next frame in the frame list after FRAME.\n\
By default, skip minibuffer-only frames.\n\
If omitted, FRAME defaults to the selected frame.\n\
-If optional argument MINIFRAME is non-nil, include minibuffer-only frames.\n\
+If optional argument MINIFRAME is nil, exclude minibuffer-only frames.\n\
If MINIFRAME is a window, include only frames using that window for their\n\
minibuffer.\n\
If MINIFRAME is non-nil and not a window, include all frames.")
return next_frame (frame, miniframe);
}
+DEFUN ("previous-frame", Fprevious_frame, Sprevious_frame, 0, 2, 0,
+ "Return the previous frame in the frame list before FRAME.\n\
+By default, skip minibuffer-only frames.\n\
+If omitted, FRAME defaults to the selected frame.\n\
+If optional argument MINIFRAME is nil, exclude minibuffer-only frames.\n\
+If MINIFRAME is a window, include only frames using that window for their\n\
+minibuffer.\n\
+If MINIFRAME is non-nil and not a window, include all frames.")
+ (frame, miniframe)
+ Lisp_Object frame, miniframe;
+{
+ Lisp_Object tail;
+
+ if (NILP (frame))
+ XSET (frame, Lisp_Frame, selected_frame);
+ else
+ CHECK_LIVE_FRAME (frame, 0);
+
+ return prev_frame (frame, miniframe);
+}
\f
-DEFUN ("delete-frame", Fdelete_frame, Sdelete_frame, 0, 1, "",
+/* Return 1 if it is ok to delete frame F;
+ 0 if all frames aside from F are invisible.
+ (Exception: if F is the terminal frame, and we are using X, return 1.) */
+
+static int
+other_visible_frames (f)
+ FRAME_PTR f;
+{
+ /* We know the selected frame is visible,
+ so if F is some other frame, it can't be the sole visible one. */
+ if (f == selected_frame)
+ {
+ Lisp_Object frames;
+ int count = 0;
+
+ for (frames = Vframe_list;
+ CONSP (frames);
+ frames = XCONS (frames)->cdr)
+ {
+ Lisp_Object this = XCONS (frames)->car;
+
+ /* Verify that the frame's window still exists
+ and we can still talk to it. And note any recent change
+ in visibility. */
+#ifdef HAVE_X_WINDOWS
+ if (FRAME_X_P (XFRAME (this)))
+ {
+ x_sync (this);
+ FRAME_SAMPLE_VISIBILITY (XFRAME (this));
+ }
+#endif
+
+ if (FRAME_VISIBLE_P (XFRAME (this))
+ || FRAME_ICONIFIED_P (XFRAME (this))
+ /* Allow deleting the terminal frame when at least
+ one X frame exists! */
+ || (FRAME_X_P (XFRAME (this)) && !FRAME_X_P (f)))
+ count++;
+ }
+ return count > 1;
+ }
+ return 1;
+}
+
+DEFUN ("delete-frame", Fdelete_frame, Sdelete_frame, 0, 2, "",
"Delete FRAME, permanently eliminating it from use.\n\
If omitted, FRAME defaults to the selected frame.\n\
-A frame may not be deleted if its minibuffer is used by other frames.")
- (frame)
- Lisp_Object frame;
+A frame may not be deleted if its minibuffer is used by other frames.\n\
+Normally, you may not delete a frame if all other frames are invisible,\n\
+but if the second optional argument FORCE is non-nil, you may do so.")
+ (frame, force)
+ Lisp_Object frame, force;
{
struct frame *f;
if (! FRAME_LIVE_P (f))
return Qnil;
- /* Are there any other frames besides this one? */
- if (f == selected_frame && EQ (next_frame (frame, Qt), frame))
- error ("Attempt to delete the only frame");
+ if (NILP (force) && !other_visible_frames (f))
+ error ("Attempt to delete the sole visible or iconified frame");
/* Does this frame have a minibuffer, and is it the surrogate
minibuffer for any other frame? */
/* Don't let the frame remain selected. */
if (f == selected_frame)
- Fselect_frame (next_frame (frame, Qt), Qnil);
+ Fhandle_switch_frame (next_frame (frame, Qt), Qnil);
/* Don't allow minibuf_window to remain on a deleted frame. */
if (EQ (f->minibuffer_window, minibuf_window))
DEFUN ("mouse-position", Fmouse_position, Smouse_position, 0, 0, 0,
"Return a list (FRAME X . Y) giving the current mouse frame and position.\n\
+The position is given in character cells, where (0, 0) is the\n\
+upper-left corner.\n\
If Emacs is running on a mouseless terminal or hasn't been programmed\n\
to read the mouse position, it returns the selected frame for FRAME\n\
and nil for X and Y.")
Lisp_Object x, y;
unsigned long long_dummy;
+ f = selected_frame;
+ x = y = Qnil;
+
+ /* It's okay for the hook to refrain from storing anything. */
if (mouse_position_hook)
(*mouse_position_hook) (&f,
&lispy_dummy, &party_dummy,
&x, &y,
&long_dummy);
- else
- {
- f = selected_frame;
- x = y = Qnil;
- }
XSET (lispy_dummy, Lisp_Frame, f);
- return Fcons (lispy_dummy, Fcons (make_number (x), make_number (y)));
+ return Fcons (lispy_dummy, Fcons (x, y));
}
DEFUN ("set-mouse-position", Fset_mouse_position, Sset_mouse_position, 3, 3, 0,
- "Move the mouse pointer to the center of cell (X,Y) in FRAME.\n\
+ "Move the mouse pointer to the center of character cell (X,Y) in FRAME.\n\
WARNING: If you use this under X, you should do `unfocus-frame' afterwards.")
(frame, x, y)
Lisp_Object frame, x, y;
}
\f
DEFUN ("make-frame-visible", Fmake_frame_visible, Smake_frame_visible,
- 0, 1, 0,
+ 0, 1, "",
"Make the frame FRAME visible (assuming it is an X-window).\n\
-Also raises the frame so that nothing obscures it.\n\
If omitted, FRAME defaults to the currently selected frame.")
(frame)
Lisp_Object frame;
/* I think this should be done with a hook. */
#ifdef HAVE_X_WINDOWS
if (FRAME_X_P (XFRAME (frame)))
- x_make_frame_visible (XFRAME (frame));
+ {
+ FRAME_SAMPLE_VISIBILITY (XFRAME (frame));
+ x_make_frame_visible (XFRAME (frame));
+ }
#endif
return frame;
}
DEFUN ("make-frame-invisible", Fmake_frame_invisible, Smake_frame_invisible,
- 0, 1, "",
+ 0, 2, "",
"Make the frame FRAME invisible (assuming it is an X-window).\n\
-If omitted, FRAME defaults to the currently selected frame.")
- (frame)
- Lisp_Object frame;
+If omitted, FRAME defaults to the currently selected frame.\n\
+Normally you may not make FRAME invisible if all other frames are invisible,\n\
+but if the second optional argument FORCE is non-nil, you may do so.")
+ (frame, force)
+ Lisp_Object frame, force;
{
if (NILP (frame))
XSET (frame, Lisp_Frame, selected_frame);
CHECK_LIVE_FRAME (frame, 0);
+ if (NILP (force) && !other_visible_frames (XFRAME (frame)))
+ error ("Attempt to make invisible the sole visible or iconified frame");
+
+ /* Don't let the frame remain selected. */
+ if (XFRAME (frame) == selected_frame)
+ Fhandle_switch_frame (next_frame (frame, Qt), Qnil);
+
+ /* Don't allow minibuf_window to remain on a deleted frame. */
+ if (EQ (XFRAME (frame)->minibuffer_window, minibuf_window))
+ {
+ Fset_window_buffer (selected_frame->minibuffer_window,
+ XWINDOW (minibuf_window)->buffer);
+ minibuf_window = selected_frame->minibuffer_window;
+ }
+
/* I think this should be done with a hook. */
#ifdef HAVE_X_WINDOWS
if (FRAME_X_P (XFRAME (frame)))
CHECK_LIVE_FRAME (frame, 0);
+ /* Don't let the frame remain selected. */
+ if (XFRAME (frame) == selected_frame)
+ Fhandle_switch_frame (next_frame (frame, Qt), Qnil);
+
+ /* Don't allow minibuf_window to remain on a deleted frame. */
+ if (EQ (XFRAME (frame)->minibuffer_window, minibuf_window))
+ {
+ Fset_window_buffer (selected_frame->minibuffer_window,
+ XWINDOW (minibuf_window)->buffer);
+ minibuf_window = selected_frame->minibuffer_window;
+ }
+
/* I think this should be done with a hook. */
#ifdef HAVE_X_WINDOWS
if (FRAME_X_P (XFRAME (frame)))
{
CHECK_LIVE_FRAME (frame, 0);
+ FRAME_SAMPLE_VISIBILITY (XFRAME (frame));
+
if (FRAME_VISIBLE_P (XFRAME (frame)))
return Qt;
if (FRAME_ICONIFIED_P (XFRAME (frame)))
Lisp_Object frame;
{
CHECK_LIVE_FRAME (frame, 0);
-
+
+ /* Do like the documentation says. */
+ Fmake_frame_visible (frame);
+
if (frame_raise_lower_hook)
(*frame_raise_lower_hook) (XFRAME (frame), 1);
(frame, focus_frame)
Lisp_Object frame, focus_frame;
{
- CHECK_LIVE_FRAME (frame, 0);
+ /* Note that we don't check for a live frame here. It's reasonable
+ to redirect the focus of a frame you're about to delete, if you
+ know what other frame should receive those keystrokes. */
+ CHECK_FRAME (frame, 0);
if (! NILP (focus_frame))
CHECK_LIVE_FRAME (focus_frame, 1);
XFRAME (frame)->focus_frame = focus_frame;
+ /* I think this should be done with a hook. */
+#ifdef HAVE_X_WINDOWS
+ if (!NILP (focus_frame) && ! EQ (focus_frame, frame)
+ && FRAME_X_P (XFRAME (focus_frame)))
+ Ffocus_frame (focus_frame);
+#endif
+
if (frame_rehighlight_hook)
(*frame_rehighlight_hook) ();
error ("Surrogate minibuffer windows must be minibuffer windows.");
if (FRAME_HAS_MINIBUF_P (f) || FRAME_MINIBUF_ONLY_P (f))
- error ("Can't change the surrogate minibuffer of a frame with its own minibuffer.");
+ error ("can't change the surrogate minibuffer of a frame with its own minibuffer");
/* Install the chosen minibuffer window, with proper buffer. */
f->minibuffer_window = val;
DEFUN ("frame-pixel-height", Fframe_pixel_height,
Sframe_pixel_height, 0, 1, 0,
- "Return a FRAME's heightin pixels.\n\
-For a terminal frame, the result really gives the sizes in characters.\n\
+ "Return a FRAME's height in pixels.\n\
+For a terminal frame, the result really gives the height in characters.\n\
If FRAME is omitted, the selected frame is used.")
(frame)
Lisp_Object frame;
DEFUN ("frame-pixel-width", Fframe_pixel_width,
Sframe_pixel_width, 0, 1, 0,
"Return FRAME's width in pixels.\n\
-For a terminal frame, the result really gives the sizes in characters.\n\
+For a terminal frame, the result really gives the width in characters.\n\
If FRAME is omitted, the selected frame is used.")
(frame)
Lisp_Object frame;
if (FRAME_X_P (f))
{
if (XINT (rows) != f->width)
- x_set_window_size (f, f->width, XINT (rows));
+ x_set_window_size (f, 1, f->width, XINT (rows));
}
else
#endif
if (FRAME_X_P (f))
{
if (XINT (cols) != f->width)
- x_set_window_size (f, XINT (cols), f->height);
+ x_set_window_size (f, 1, XINT (cols), f->height);
}
else
#endif
if (FRAME_X_P (f))
{
if (XINT (rows) != f->height || XINT (cols) != f->width)
- x_set_window_size (f, XINT (cols), XINT (rows));
+ x_set_window_size (f, 1, XINT (cols), XINT (rows));
}
else
#endif
DEFUN ("set-frame-position", Fset_frame_position,
Sset_frame_position, 3, 3, 0,
"Sets position of FRAME in pixels to XOFFSET by YOFFSET.\n\
-If XOFFSET or YOFFSET are negative, they are interpreted relative to\n\
-the leftmost or bottommost position FRAME could occupy without going\n\
-off the screen.")
+This is actually the position of the upper left corner of the frame.\n\
+Negative values for XOFFSET or YOFFSET are interpreted relative to\n\
+the rightmost or bottommost possible position (that stays within the screen).")
(frame, xoffset, yoffset)
Lisp_Object frame, xoffset, yoffset;
{
}
\f
-#ifndef HAVE_X11
-DEFUN ("rubber-band-rectangle", Frubber_band_rectangle, Srubber_band_rectangle,
- 3, 3, "",
- "Ask user to specify a window position and size on FRAME with the mouse.\n\
-Arguments are FRAME, NAME and GEO. NAME is a name to be displayed as\n\
-the purpose of this rectangle. GEO is an X-windows size spec that can\n\
-specify defaults for some sizes/positions. If GEO specifies everything,\n\
-the mouse is not used.\n\
-Returns a list of five values: (FRAME LEFT TOP WIDTH HEIGHT).")
- (frame, name, geo)
- Lisp_Object frame;
- Lisp_Object name;
- Lisp_Object geo;
-{
- int vals[4];
- Lisp_Object nums[4];
- int i;
-
- CHECK_FRAME (frame, 0);
- CHECK_STRING (name, 1);
- CHECK_STRING (geo, 2);
-
- switch (XFRAME (frame)->output_method)
- {
- case output_x_window:
- x_rubber_band (XFRAME (frame), &vals[0], &vals[1], &vals[2], &vals[3],
- XSTRING (geo)->data, XSTRING (name)->data);
- break;
-
- default:
- return Qnil;
- }
-
- for (i = 0; i < 4; i++)
- XFASTINT (nums[i]) = vals[i];
- return Fcons (frame, Flist (4, nums));
- return Qnil;
-}
-#endif /* not HAVE_X11 */
-\f
choose_minibuf_frame ()
{
/* For lowest-level minibuf, put it on currently selected frame
defsubr (&Sframep);
defsubr (&Sframe_live_p);
+ defsubr (&Shandle_switch_frame);
defsubr (&Sselect_frame);
defsubr (&Sselected_frame);
defsubr (&Swindow_frame);
defsubr (&Sframe_selected_window);
defsubr (&Sframe_list);
defsubr (&Snext_frame);
+ defsubr (&Sprevious_frame);
defsubr (&Sdelete_frame);
defsubr (&Smouse_position);
defsubr (&Sset_mouse_position);
defsubr (&Sset_frame_width);
defsubr (&Sset_frame_size);
defsubr (&Sset_frame_position);
-#ifndef HAVE_X11
- defsubr (&Srubber_band_rectangle);
-#endif /* HAVE_X11 */
}
keys_of_frame ()
{
- initial_define_lispy_key (global_map, "switch-frame", "select-frame");
+ initial_define_lispy_key (global_map, "switch-frame", "handle-switch-frame");
}
\f
#else /* not MULTI_FRAME */
XFASTINT (tem) = 0;
return tem;
}
+DEFUN ("framep", Fframep, Sframep, 1, 1, 0,
+ "Return non-nil if OBJECT is a frame.\n\
+Value is t for a termcap frame (a character-only terminal),\n\
+`x' for an Emacs frame that is really an X window.\n\
+Also see `live-frame-p'.")
+ (object)
+ Lisp_Object object;
+{
+ return Qnil;
+}
DEFUN ("set-frame-height", Fset_frame_height, Sset_frame_height, 2, 3, 0,
"Specify that the frame FRAME has LINES lines.\n\
return Qnil;
}
+DEFUN ("mouse-position", Fmouse_position, Smouse_position, 0, 0, 0,
+ "Return a list (FRAME X . Y) giving the current mouse frame and position.\n\
+The position is given in character cells, where (0, 0) is the\n\
+upper-left corner.\n\
+If Emacs is running on a mouseless terminal or hasn't been programmed\n\
+to read the mouse position, it returns the selected frame for FRAME\n\
+and nil for X and Y.")
+ ()
+{
+ FRAME_PTR f;
+ Lisp_Object lispy_dummy;
+ enum scroll_bar_part party_dummy;
+ Lisp_Object x, y;
+ unsigned long long_dummy;
+
+ f = selected_frame;
+ x = y = Qnil;
+
+ /* It's okay for the hook to refrain from storing anything. */
+ if (mouse_position_hook)
+ (*mouse_position_hook) (&f,
+ &lispy_dummy, &party_dummy,
+ &x, &y,
+ &long_dummy);
+
+ /* Always return nil for frame. */
+ return Fcons (Qnil, Fcons (x, y));
+}
+
syms_of_frame ()
{
defsubr (&Sselected_frame);
+ defsubr (&Sframep);
defsubr (&Sframe_char_height);
defsubr (&Sframe_char_width);
defsubr (&Sframe_pixel_height);
Ffset (intern ("screen-height"), intern ("frame-height"));
defsubr (&Sframe_width);
Ffset (intern ("screen-width"), intern ("frame-width"));
+ defsubr (&Smouse_position);
}
keys_of_frame ()