Commit ea6c880a authored by Martin Rudalics's avatar Martin Rudalics

Frame movement, focus and hook related changes

New hook `move-frame-functions'.  Run `focus-in-hook'
after switching to frame that gets focus.  Don't run
XMoveWindow for GTK.

* lisp/frame.el (handle-move-frame, frame-size-changed-p): New

* src/frame.c (do_switch_frame): Simplify code.
(Fhandle_switch_frame): Switch frame before running
(Vfocus_in_hook, Vfocus_out_hook): Clarify doc-strings.
(Vmove_frame_functions): New hook variable.
* src/keyboard.c (kbd_buffer_get_event): Handle
(head_table): Add Qmove_frame entry.
(syms_of_keyboard): Add Qmove_frame.
(keys_of_keyboard): Define key for `move-frame'.
* src/termhooks.h (event_kind): Add MOVE_FRAME_EVENT.
* src/w32term.c (w32_read_socket): Create MOVE_FRAME_EVENT.
* src/window.c (run_window_size_change_functions): Record size of
FRAME's minibuffer window too.
* src/xterm.c (handle_one_xevent): Create MOVE_FRAME_EVENT.
(x_set_offset): For GTK call gtk_widget_move instead of
parent 0eef8e9a
......@@ -144,6 +144,13 @@ Focus-out events occur when no frame has focus.
This function runs the hook `focus-out-hook'."
(interactive "e")
(run-hooks 'focus-out-hook))
(defun handle-move-frame (event)
"Handle a move-frame event.
This function runs the abnormal hook `move-frame-functions'."
(interactive "e")
(let ((frame (posn-window (event-start event))))
(run-hook-with-args 'move-frame-functions frame)))
;;;; Arrangement of frames at startup
......@@ -1483,6 +1490,29 @@ keys and their meanings."
for frames = (cdr (assq 'frames attributes))
if (memq frame frames) return attributes))
(defun frame-size-changed-p (&optional frame)
"Return non-nil when the size of FRAME has changed.
More precisely, return non-nil when the inner width or height of
FRAME has changed since `window-size-change-functions' was run
for FRAME."
(let* ((frame (window-normalize-frame frame))
(root (frame-root-window frame))
(mini (minibuffer-window frame))
(mini-height-before-size-change 0)
(mini-height 0))
;; FRAME's minibuffer window counts iff it's on FRAME and FRAME is
;; not a minibuffer-only frame.
(when (and (eq (window-frame mini) frame) (not (eq mini root)))
(setq mini-height-before-size-change
(window-pixel-height-before-size-change mini))
(setq mini-height (window-pixel-height mini)))
;; Return non-nil when either the width of the root or the sum of
;; the heights of root and minibuffer window changed.
(or (/= (window-pixel-width-before-size-change root)
(window-pixel-width root))
(/= (+ (window-pixel-height-before-size-change root)
(+ (window-pixel-height root) mini-height)))))
;;;; Frame/display capabilities.
......@@ -1107,7 +1107,7 @@ affects all frames on the same terminal device. */)
do_switch_frame (Lisp_Object frame, int track, int for_deletion, Lisp_Object norecord)
struct frame *sf = SELECTED_FRAME ();
struct frame *sf = SELECTED_FRAME (), *f;
/* If FRAME is a switch-frame event, extract the frame we should
switch to. */
......@@ -1120,10 +1120,10 @@ do_switch_frame (Lisp_Object frame, int track, int for_deletion, Lisp_Object nor
a switch-frame event to arrive after a frame is no longer live,
especially when deleting the initial frame during startup. */
CHECK_FRAME (frame);
if (! FRAME_LIVE_P (XFRAME (frame)))
f = XFRAME (frame);
if (!FRAME_LIVE_P (f))
return Qnil;
if (sf == XFRAME (frame))
else if (f == sf)
return frame;
/* If a frame's focus has been redirected toward the currently
......@@ -1156,11 +1156,11 @@ do_switch_frame (Lisp_Object frame, int track, int for_deletion, Lisp_Object nor
#else /* ! 0 */
/* Instead, apply it only to the frame we're pointing to. */
if (track && FRAME_WINDOW_P (XFRAME (frame)))
if (track && FRAME_WINDOW_P (f))
Lisp_Object focus, xfocus;
xfocus = x_get_focus_frame (XFRAME (frame));
xfocus = x_get_focus_frame (f);
if (FRAMEP (xfocus))
focus = FRAME_FOCUS_FRAME (XFRAME (xfocus));
......@@ -1168,8 +1168,7 @@ do_switch_frame (Lisp_Object frame, int track, int for_deletion, Lisp_Object nor
/* Redirect frame focus also when FRAME has its minibuffer
window on the selected frame (see Bug#24500). */
|| (NILP (focus)
&& EQ (FRAME_MINIBUF_WINDOW (f), sf->selected_window)))
Fredirect_frame_focus (xfocus, frame);
......@@ -1179,9 +1178,8 @@ do_switch_frame (Lisp_Object frame, int track, int for_deletion, Lisp_Object nor
if (!for_deletion && FRAME_HAS_MINIBUF_P (sf))
resize_mini_window (XWINDOW (FRAME_MINIBUF_WINDOW (sf)), 1);
struct frame *f = XFRAME (frame);
struct tty_display_info *tty = FRAME_TTY (f);
Lisp_Object top_frame = tty->top_frame;
......@@ -1209,7 +1207,7 @@ do_switch_frame (Lisp_Object frame, int track, int for_deletion, Lisp_Object nor
if (! FRAME_MINIBUF_ONLY_P (XFRAME (selected_frame)))
last_nonminibuf_frame = XFRAME (selected_frame);
Fselect_window (XFRAME (frame)->selected_window, norecord);
Fselect_window (f->selected_window, norecord);
/* We want to make sure that the next event generates a frame-switch
event to the appropriate frame. This seems kludgy to me, but
......@@ -1253,12 +1251,15 @@ If EVENT is frame object, handle it as if it were a switch-frame event
to that frame. */)
(Lisp_Object event)
Lisp_Object value;
/* Preserve prefix arg that the command loop just cleared. */
kset_prefix_arg (current_kboard, Vcurrent_prefix_arg);
run_hook (Qmouse_leave_buffer_hook);
/* `switch-frame' implies a focus in. */
value = do_switch_frame (event, 0, 0, Qnil);
call1 (intern ("handle-focus-in"), event);
return do_switch_frame (event, 0, 0, Qnil);
return value;
DEFUN ("selected-frame", Fselected_frame, Sselected_frame, 0, 0, 0,
......@@ -1709,8 +1710,6 @@ delete_frame (Lisp_Object frame, Lisp_Object force)
promise that the terminal of the frame must be valid until we
have called the window-system-dependent frame destruction
routine. */
struct terminal *terminal;
block_input ();
......@@ -5121,13 +5120,19 @@ The pointer becomes visible again when the mouse is moved. */);
Vmake_pointer_invisible = Qt;
DEFVAR_LISP ("focus-in-hook", Vfocus_in_hook,
doc: /* Normal hook run when a frame gains input focus. */);
doc: /* Normal hook run when a frame gains input focus.
The frame gaining focus is selected at the time this hook is run. */);
Vfocus_in_hook = Qnil;
DEFVAR_LISP ("focus-out-hook", Vfocus_out_hook,
doc: /* Normal hook run when a frame loses input focus. */);
doc: /* Normal hook run when all frames lost input focus. */);
Vfocus_out_hook = Qnil;
DEFVAR_LISP ("move-frame-functions", Vmove_frame_functions,
doc: /* Functions run after a frame was moved.
The functions are run with one arg, the frame that moved. */);
Vmove_frame_functions = Qnil;
DEFVAR_LISP ("delete-frame-functions", Vdelete_frame_functions,
doc: /* Functions run before deleting a frame.
The functions are run with one arg, the frame to be deleted.
......@@ -4056,6 +4056,14 @@ kbd_buffer_get_event (KBOARD **kbp,
kbd_fetch_ptr = event + 1;
#if defined (HAVE_X11) || defined (HAVE_NTGUI)
else if (event->kind == MOVE_FRAME_EVENT)
/* Make an event (move-frame (FRAME)). */
obj = list2 (Qmove_frame, list1 (event->ie.frame_or_window));
kbd_fetch_ptr = event + 1;
else if (event->kind == XWIDGET_EVENT)
......@@ -4068,6 +4076,11 @@ kbd_buffer_get_event (KBOARD **kbp,
obj = make_lispy_event (&event->ie);
kbd_fetch_ptr = event + 1;
else if (event->kind == SELECT_WINDOW_EVENT)
obj = list2 (Qselect_window, list1 (event->ie.frame_or_window));
kbd_fetch_ptr = event + 1;
/* If this event is on a different frame, return a switch-frame this
......@@ -10977,6 +10990,7 @@ static const struct event_head head_table[] = {
{SYMBOL_INDEX (Qfocus_in), SYMBOL_INDEX (Qfocus_in)},
{SYMBOL_INDEX (Qfocus_out), SYMBOL_INDEX (Qfocus_out)},
{SYMBOL_INDEX (Qmove_frame), SYMBOL_INDEX (Qmove_frame)},
{SYMBOL_INDEX (Qdelete_frame), SYMBOL_INDEX (Qdelete_frame)},
{SYMBOL_INDEX (Qiconify_frame), SYMBOL_INDEX (Qiconify_frame)},
{SYMBOL_INDEX (Qmake_frame_visible), SYMBOL_INDEX (Qmake_frame_visible)},
......@@ -11149,6 +11163,7 @@ syms_of_keyboard (void)
DEFSYM (Qswitch_frame, "switch-frame");
DEFSYM (Qfocus_in, "focus-in");
DEFSYM (Qfocus_out, "focus-out");
DEFSYM (Qmove_frame, "move-frame");
DEFSYM (Qdelete_frame, "delete-frame");
DEFSYM (Qiconify_frame, "iconify-frame");
DEFSYM (Qmake_frame_visible, "make-frame-visible");
......@@ -11895,6 +11910,8 @@ keys_of_keyboard (void)
initial_define_lispy_key (Vspecial_event_map, "focus-out",
initial_define_lispy_key (Vspecial_event_map, "move-frame",
/* Mark the pointers in the kboard objects.
......@@ -202,6 +202,9 @@ enum event_kind
/* Generated when a frame is moved. */
/* Generated when mouse moves over window not currently selected. */
......@@ -5038,7 +5038,11 @@ w32_read_socket (struct terminal *terminal,
f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
if (f && !FRAME_ICONIFIED_P (f))
x_real_positions (f, &f->left_pos, &f->top_pos);
inev.kind = MOVE_FRAME_EVENT;
XSETFRAME (inev.frame_or_window, f);
check_visibility = 1;
......@@ -3314,6 +3314,9 @@ run_window_size_change_functions (Lisp_Object frame)
Lisp_Object functions = Vwindow_size_change_functions;
/* Here we implicitly exclude the possibility that the height of
FRAME and its minibuffer window both change leaving the height
of FRAME's root window alone. */
|| window_size_changed (r))
while (CONSP (functions))
......@@ -3324,6 +3327,12 @@ run_window_size_change_functions (Lisp_Object frame)
window_set_before_size_change_sizes (r);
/* Record size of FRAME's minibuffer window too. */
......@@ -8614,8 +8614,23 @@ handle_one_xevent (struct x_display_info *dpyinfo,
&& gtk_widget_get_mapped (FRAME_GTK_OUTER_WIDGET (f)))
int old_left = f->left_pos;
int old_top = f->top_pos;
Lisp_Object frame = Qnil;
XSETFRAME (frame, f);
x_real_positions (f, &f->left_pos, &f->top_pos);
if (old_left != f->left_pos || old_top != f->top_pos)
#ifdef HAVE_X_I18N
if (FRAME_XIC (f) && (FRAME_XIC_STYLE (f) & XIMStatusArea))
xic_set_statusarea (f);
......@@ -10088,8 +10103,13 @@ x_set_offset (struct frame *f, register int xoff, register int yoff, int change_
modified_top += FRAME_X_OUTPUT (f)->move_offset_top;
#ifdef USE_GTK
gtk_window_move (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
modified_left, modified_top);
modified_left, modified_top);
x_sync_with_move (f, f->left_pos, f->top_pos,
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment