New focus management interface
focus-in-hook and focus-out-hook don't accurately reflect actual user-visible focus states. Add a new focus interface and mark the old one obsolete. * doc/lispref/frames.texi (Input Focus): Document new focus functions. Remove references to the now-obsolete focus hooks. * lisp/frame.el (frame-focus-state): New function. (after-focus-change-function): New variable. (focus-in-hook, focus-out-hook): Move to lisp from C; mark obsolete. * lisp/term/xterm.el (xterm-translate-focus-in) (xterm-translate-focus-out): Track tty focus in `tty-focus-state' terminal parameter; call `after-focus-change-function'. (xterm--suspend-tty-function): New function. * src/frame.c (Fhandle_switch_frame): Update docstring; don't call focus hooks. (focus-in-hook, focus-out-hook): Remove: moved to lisp. (syms_of_frame): Remove unread_switch_frame; add Vunread_switch_frame. * src/keyboard.c: (Finternal_handle_focus_in): New function. (make_lispy_event): Always report focus events to lisp; don't translate them to switch events sometimes. Lisp can take care of creating synthetic switch-frame events via `internal-handle-focus-in'. * src/w32term.c (x_focus_changed): Remove switch-avoidance logic: just directly report focus changes to lisp. * src/xterm.c (x_focus_changed): Remove switch-avoidance logic: just directly report focus changes to lisp.
This commit is contained in:
parent
a20fe5a7e3
commit
2f6c682061
8 changed files with 219 additions and 124 deletions
|
@ -2702,14 +2702,22 @@ This function returns the selected frame.
|
|||
Some window systems and window managers direct keyboard input to the
|
||||
window object that the mouse is in; others require explicit clicks or
|
||||
commands to @dfn{shift the focus} to various window objects. Either
|
||||
way, Emacs automatically keeps track of which frame has the focus. To
|
||||
way, Emacs automatically keeps track of which frames have focus. To
|
||||
explicitly switch to a different frame from a Lisp function, call
|
||||
@code{select-frame-set-input-focus}.
|
||||
|
||||
Lisp programs can also switch frames temporarily by calling the
|
||||
function @code{select-frame}. This does not alter the window system's
|
||||
concept of focus; rather, it escapes from the window manager's control
|
||||
until that control is somehow reasserted.
|
||||
The plural ``frames'' in the previous paragraph is deliberate: while
|
||||
Emacs itself has only one selected frame, Emacs can have frames on
|
||||
many different terminals (recall that a connection to a window system
|
||||
counts as a terminal), and each terminal has its own idea of which
|
||||
frame has input focus. When you set the input focus to a frame, you
|
||||
set the focus for that frame's terminal, but frames on other terminals
|
||||
may still remain focused.
|
||||
|
||||
Lisp programs can switch frames temporarily by calling the function
|
||||
@code{select-frame}. This does not alter the window system's concept
|
||||
of focus; rather, it escapes from the window manager's control until
|
||||
that control is somehow reasserted.
|
||||
|
||||
When using a text terminal, only one frame can be displayed at a time
|
||||
on the terminal, so after a call to @code{select-frame}, the next
|
||||
|
@ -2720,11 +2728,11 @@ before the buffer name (@pxref{Mode Line Variables}).
|
|||
|
||||
@defun select-frame-set-input-focus frame &optional norecord
|
||||
This function selects @var{frame}, raises it (should it happen to be
|
||||
obscured by other frames) and tries to give it the X server's focus.
|
||||
On a text terminal, the next redisplay displays the new frame on the
|
||||
entire terminal screen. The optional argument @var{norecord} has the
|
||||
same meaning as for @code{select-frame} (see below). The return value
|
||||
of this function is not significant.
|
||||
obscured by other frames) and tries to give it the window system's
|
||||
focus. On a text terminal, the next redisplay displays the new frame
|
||||
on the entire terminal screen. The optional argument @var{norecord}
|
||||
has the same meaning as for @code{select-frame} (see below).
|
||||
The return value of this function is not significant.
|
||||
@end defun
|
||||
|
||||
Ideally, the function described next should focus a frame without also
|
||||
|
@ -2772,17 +2780,31 @@ could switch to a different terminal without switching back when
|
|||
you're done.
|
||||
@end deffn
|
||||
|
||||
Emacs cooperates with the window system by arranging to select frames as
|
||||
the server and window manager request. It does so by generating a
|
||||
special kind of input event, called a @dfn{focus} event, when
|
||||
appropriate. The command loop handles a focus event by calling
|
||||
@code{handle-switch-frame}. @xref{Focus Events}.
|
||||
Emacs cooperates with the window system by arranging to select frames
|
||||
as the server and window manager request. When a window system
|
||||
informs Emacs that one of its frames has been selected, Emacs
|
||||
internally generates a @dfn{focus-in} event. Focus events are
|
||||
normally handled by @code{handle-focus-in}.
|
||||
|
||||
@deffn Command handle-focus-in event
|
||||
This function handles focus-in events from window systems and
|
||||
terminals that support explicit focus notifications. It updates the
|
||||
per-frame focus flags that @code{frame-focus-state} queries and calls
|
||||
@code{after-focus-change-function}. In addition, it generates a
|
||||
@code{switch-frame} event in order to switch the Emacs notion of the
|
||||
selected frame to the frame most recently focused in some terminal.
|
||||
It's important to note that this switching of the Emacs selected frame
|
||||
to the most recently focused frame does not mean that other frames do
|
||||
not continue to have the focus in their respective terminals. Do not
|
||||
invoke this function yourself: instead, attach logic to
|
||||
@code{after-focus-change-function}.
|
||||
@end deffn
|
||||
|
||||
@deffn Command handle-switch-frame frame
|
||||
This function handles a focus event by selecting frame @var{frame}.
|
||||
|
||||
Focus events normally do their job by invoking this command.
|
||||
Don't call it for any other reason.
|
||||
This function handles a switch-frame event, which Emacs generates for
|
||||
itself upon focus notification or under various other circumstances
|
||||
involving an input event arriving at a different frame from the last
|
||||
event. Do not invoke this function yourself.
|
||||
@end deffn
|
||||
|
||||
@defun redirect-frame-focus frame &optional focus-frame
|
||||
|
@ -2816,14 +2838,42 @@ The redirection lasts until @code{redirect-frame-focus} is called to
|
|||
change it.
|
||||
@end defun
|
||||
|
||||
@defvar focus-in-hook
|
||||
This is a normal hook run when an Emacs frame gains input focus. The
|
||||
frame gaining focus is selected when this hook is run.
|
||||
@end defvar
|
||||
@defun frame-focus-state frame
|
||||
This function retrieves the last known focus state of @var{frame}.
|
||||
|
||||
@defvar focus-out-hook
|
||||
This is a normal hook run when an Emacs frame has lost input focus and
|
||||
no other Emacs frame has gained input focus instead.
|
||||
It returns @code{nil} if the frame is known not to be focused,
|
||||
@code{t} if the frame is known to be focused, or @code{unknown} if
|
||||
Emacs does not know the focus state of the frame. (You may see this
|
||||
last state in TTY frames running on terminals that do not support
|
||||
explicit focus notifications.)
|
||||
@end defun
|
||||
|
||||
@defvar after-focus-change-function
|
||||
This function is an extension point that code can use to receive a
|
||||
notification that focus has changed.
|
||||
|
||||
This function is called with no arguments when Emacs notices that the
|
||||
set of focused frames may have changed. Code wanting to do something
|
||||
when frame focus changes should use @code{add-function} to add a
|
||||
function to this one, and in this added function, re-scan the set of
|
||||
focused frames, calling @code{frame-focus-state} to retrieve the last
|
||||
known focus state of each frame. Focus events are delivered
|
||||
asynchronously, and frame input focus according to an external system
|
||||
may not correspond to the notion of the Emacs selected frame.
|
||||
Multiple frames may appear to have input focus simultaneously due to
|
||||
focus event delivery differences, the presence of multiple Emacs
|
||||
terminals, and other factors, and code should be robust in the face of
|
||||
this situation.
|
||||
|
||||
Depending on window system, focus events may also be delivered
|
||||
repeatedly and with different focus states before settling to the
|
||||
expected values. Code relying on focus notifications should
|
||||
``debounce'' any user-visible updates arising from focus changes,
|
||||
perhaps by deferring work until redisplay.
|
||||
|
||||
This function may be called in arbitrary contexts, including from
|
||||
inside @code{read-event}, so take the same care as you might when
|
||||
writing a process filter.
|
||||
@end defvar
|
||||
|
||||
@defopt focus-follows-mouse
|
||||
|
|
6
etc/NEWS
6
etc/NEWS
|
@ -582,6 +582,12 @@ manual for more details.
|
|||
|
||||
* Lisp Changes in Emacs 27.1
|
||||
|
||||
+++
|
||||
** New focus state inspection interface: `focus-in-hook' and
|
||||
`focus-out-hook' are marked obsolete. Instead, attach to
|
||||
`after-focus-change-function' using `add-function' and inspect the
|
||||
focus state of each frame using `frame-focus-state'.
|
||||
|
||||
+++
|
||||
** Emacs now requests and recognizes focus-change notifications from
|
||||
terminals that support the feature, meaning that `focus-in-hook'
|
||||
|
|
110
lisp/frame.el
110
lisp/frame.el
|
@ -129,22 +129,104 @@ appended when the minibuffer frame is created."
|
|||
;; Gildea@x.org says it is ok to ask questions before terminating.
|
||||
(save-buffers-kill-emacs))))
|
||||
|
||||
(defun handle-focus-in (&optional _event)
|
||||
"Handle a focus-in event.
|
||||
Focus-in events are usually bound to this function.
|
||||
Focus-in events occur when a frame has focus, but a switch-frame event
|
||||
is not generated.
|
||||
This function runs the hook `focus-in-hook'."
|
||||
(interactive "e")
|
||||
(run-hooks 'focus-in-hook))
|
||||
(defun frame-focus-state (&optional frame)
|
||||
"Return FRAME's last known focus state.
|
||||
Return nil if the frame is definitely known not be focused, t if
|
||||
the frame is known to be focused, and 'unknown if we don't know. If
|
||||
FRAME is nil, query the selected frame."
|
||||
(let* ((frame (or frame (selected-frame)))
|
||||
(tty-top-frame (tty-top-frame frame)))
|
||||
(if (not tty-top-frame)
|
||||
(frame-parameter frame 'last-focus-update)
|
||||
;; All tty frames are frame-visible-p if the terminal is
|
||||
;; visible, so check whether the frame is the top tty frame
|
||||
;; before checking visibility.
|
||||
(cond ((not (eq tty-top-frame frame)) nil)
|
||||
((not (frame-visible-p frame)) nil)
|
||||
(t (let ((tty-focus-state
|
||||
(terminal-parameter frame 'tty-focus-state)))
|
||||
(cond ((eq tty-focus-state 'focused) t)
|
||||
((eq tty-focus-state 'defocused) nil)
|
||||
(t 'unknown))))))))
|
||||
|
||||
(defun handle-focus-out (&optional _event)
|
||||
"Handle a focus-out event.
|
||||
Focus-out events are usually bound to this function.
|
||||
Focus-out events occur when no frame has focus.
|
||||
This function runs the hook `focus-out-hook'."
|
||||
(defvar after-focus-change-function #'ignore
|
||||
"Function called after frame focus may have changed.
|
||||
|
||||
This function is called with no arguments when Emacs notices that
|
||||
the set of focused frames may have changed. Code wanting to do
|
||||
something when frame focus changes should use `add-function' to
|
||||
add a function to this one, and in this added function, re-scan
|
||||
the set of focused frames, calling `frame-focus-state' to
|
||||
retrieve the last known focus state of each frame. Focus events
|
||||
are delivered asynchronously, and frame input focus according to
|
||||
an external system may not correspond to the notion of the Emacs
|
||||
selected frame. Multiple frames may appear to have input focus
|
||||
simultaneously due to focus event delivery differences, the
|
||||
presence of multiple Emacs terminals, and other factors, and code
|
||||
should be robust in the face of this situation.
|
||||
|
||||
Depending on window system, focus events may also be delivered
|
||||
repeatedly and with different focus states before settling to the
|
||||
expected values. Code relying on focus notifications should
|
||||
\"debounce\" any user-visible updates arising from focus changes,
|
||||
perhaps by deferring work until redisplay.
|
||||
|
||||
This function may be called in arbitrary contexts, including from
|
||||
inside `read-event', so take the same care as you might when
|
||||
writing a process filter.")
|
||||
|
||||
(defvar focus-in-hook nil
|
||||
"Normal hook run when a frame gains focus.
|
||||
The frame gaining focus is selected at the time this hook is run.
|
||||
|
||||
This hook is obsolete. Despite its name, this hook may be run in
|
||||
situations other than when a frame obtains input focus: for
|
||||
example, we also run this hook when switching the selected frame
|
||||
internally to handle certain input events (like mouse wheel
|
||||
scrolling) even when the user's notion of input focus
|
||||
hasn't changed.
|
||||
|
||||
Prefer using `after-focus-change-function'.")
|
||||
(make-obsolete-variable
|
||||
'focus-in-hook "after-focus-change-function" "27.1" 'set)
|
||||
|
||||
(defvar focus-out-hook nil
|
||||
"Normal hook run when all frames lost input focus.
|
||||
|
||||
This hook is obsolete; see `focus-in-hook'. Depending on timing,
|
||||
this hook may be delivered when a frame does in fact have focus.
|
||||
Prefer `after-focus-change-function'.")
|
||||
(make-obsolete-variable
|
||||
'focus-out-hook "after-focus-change-function" "27.1" 'set)
|
||||
|
||||
(defun handle-focus-in (event)
|
||||
"Handle a focus-in event.
|
||||
Focus-in events are bound to this function; do not change this
|
||||
binding. Focus-in events occur when a frame receives focus from
|
||||
the window system."
|
||||
;; N.B. tty focus goes down a different path; see xterm.el.
|
||||
(interactive "e")
|
||||
(run-hooks 'focus-out-hook))
|
||||
(unless (eq (car-safe event) 'focus-in)
|
||||
(error "handle-focus-in should handle focus-in events"))
|
||||
(internal-handle-focus-in event)
|
||||
(let ((frame (nth 1 event)))
|
||||
(setf (frame-parameter frame 'last-focus-update) t)
|
||||
(run-hooks 'focus-in-hook)
|
||||
(funcall after-focus-change-function)))
|
||||
|
||||
(defun handle-focus-out (event)
|
||||
"Handle a focus-out event.
|
||||
Focus-out events are bound to this function; do not change this
|
||||
binding. Focus-out events occur when a frame loses focus, but
|
||||
that's not the whole story: see `after-focus-change-function'."
|
||||
;; N.B. tty focus goes down a different path; see xterm.el.
|
||||
(interactive "e")
|
||||
(unless (eq (car event) 'focus-out)
|
||||
(error "handle-focus-out should handle focus-out events"))
|
||||
(let ((frame (nth 1 event)))
|
||||
(setf (frame-parameter frame 'last-focus-update) nil)
|
||||
(run-hooks 'focus-out-hook)
|
||||
(funcall after-focus-change-function)))
|
||||
|
||||
(defun handle-move-frame (event)
|
||||
"Handle a move-frame event.
|
||||
|
|
|
@ -115,13 +115,20 @@ Return the pasted text as a string."
|
|||
;; notifications) instead of read-event (which can't).
|
||||
|
||||
(defun xterm-translate-focus-in (_prompt)
|
||||
(handle-focus-in)
|
||||
(setf (terminal-parameter nil 'tty-focus-state) 'focused)
|
||||
(funcall after-focus-change-function)
|
||||
[])
|
||||
|
||||
(defun xterm-translate-focus-out (_prompt)
|
||||
(handle-focus-out)
|
||||
(setf (terminal-parameter nil 'tty-focus-state) 'defocused)
|
||||
(funcall after-focus-change-function)
|
||||
[])
|
||||
|
||||
(defun xterm--suspend-tty-function (_tty)
|
||||
;; We can't know what happens to the tty after we're suspended
|
||||
(setf (terminal-parameter nil 'tty-focus-state) nil)
|
||||
(funcall after-focus-change-function))
|
||||
|
||||
;; Similarly, we want to transparently slurp the entirety of a
|
||||
;; bracketed paste and encapsulate it into a single event. We used to
|
||||
;; just slurp up the bracketed paste content in the event handler, but
|
||||
|
|
25
src/frame.c
25
src/frame.c
|
@ -1455,23 +1455,15 @@ This function returns FRAME, or nil if FRAME has been deleted. */)
|
|||
DEFUN ("handle-switch-frame", Fhandle_switch_frame, Shandle_switch_frame, 1, 1, "^e",
|
||||
doc: /* Handle a switch-frame event EVENT.
|
||||
Switch-frame events are usually bound to this function.
|
||||
A switch-frame event tells Emacs that the window manager has requested
|
||||
that the user's events be directed to the frame mentioned in the event.
|
||||
This function selects the selected window of the frame of EVENT.
|
||||
|
||||
If EVENT is frame object, handle it as if it were a switch-frame event
|
||||
to that frame. */)
|
||||
A switch-frame event is an event Emacs sends itself to
|
||||
indicate that input is arriving in a new frame. It does not
|
||||
necessarily represent user-visible input focus. */)
|
||||
(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 value;
|
||||
return do_switch_frame (event, 0, 0, Qnil);
|
||||
}
|
||||
|
||||
DEFUN ("selected-frame", Fselected_frame, Sselected_frame, 0, 0, 0,
|
||||
|
@ -5888,15 +5880,6 @@ when the mouse is over clickable text. */);
|
|||
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.
|
||||
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 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. */);
|
||||
|
|
|
@ -5331,45 +5331,10 @@ make_lispy_event (struct input_event *event)
|
|||
}
|
||||
|
||||
case FOCUS_IN_EVENT:
|
||||
{
|
||||
/* Notification of a FocusIn event. The frame receiving the
|
||||
focus is in event->frame_or_window. Generate a
|
||||
switch-frame event if necessary. */
|
||||
|
||||
Lisp_Object frame = event->frame_or_window;
|
||||
Lisp_Object focus = FRAME_FOCUS_FRAME (XFRAME (frame));
|
||||
if (FRAMEP (focus))
|
||||
frame = focus;
|
||||
bool switching
|
||||
= (
|
||||
#ifdef HAVE_X11
|
||||
! NILP (event->arg)
|
||||
&&
|
||||
#endif
|
||||
!EQ (frame, internal_last_event_frame)
|
||||
&& !EQ (frame, selected_frame));
|
||||
internal_last_event_frame = frame;
|
||||
|
||||
return (switching ? make_lispy_switch_frame (frame)
|
||||
: make_lispy_focus_in (frame));
|
||||
}
|
||||
return make_lispy_focus_in (event->frame_or_window);
|
||||
|
||||
case FOCUS_OUT_EVENT:
|
||||
{
|
||||
#ifdef HAVE_WINDOW_SYSTEM
|
||||
|
||||
Display_Info *di;
|
||||
Lisp_Object frame = event->frame_or_window;
|
||||
bool focused = false;
|
||||
|
||||
for (di = x_display_list; di && ! focused; di = di->next)
|
||||
focused = di->x_highlight_frame != 0;
|
||||
|
||||
return focused ? Qnil
|
||||
: make_lispy_focus_out (frame);
|
||||
|
||||
#endif /* HAVE_WINDOW_SYSTEM */
|
||||
}
|
||||
return make_lispy_focus_out (event->frame_or_window);
|
||||
|
||||
/* A simple keystroke. */
|
||||
case ASCII_KEYSTROKE_EVENT:
|
||||
|
@ -6637,6 +6602,31 @@ has the same base event type and all the specified modifiers. */)
|
|||
error ("Invalid base event");
|
||||
}
|
||||
|
||||
DEFUN ("internal-handle-focus-in", Finternal_handle_focus_in,
|
||||
Sinternal_handle_focus_in, 1, 1, 0,
|
||||
doc: /* Internally handle focus-in events, possibly generating
|
||||
an artifical switch-frame event. */)
|
||||
(Lisp_Object event)
|
||||
{
|
||||
Lisp_Object frame;
|
||||
if (!EQ (CAR_SAFE (event), Qfocus_in) ||
|
||||
!CONSP (XCDR (event)) ||
|
||||
!FRAMEP ((frame = XCAR (XCDR (event)))))
|
||||
error ("invalid focus-in event");
|
||||
|
||||
/* Conceptually, the concept of window manager focus on a particular
|
||||
frame and the Emacs selected frame shouldn't be related, but for a
|
||||
long time, we automatically switched the selected frame in response
|
||||
to focus events, so let's keep doing that. */
|
||||
bool switching = (!EQ (frame, internal_last_event_frame)
|
||||
&& !EQ (frame, selected_frame));
|
||||
internal_last_event_frame = frame;
|
||||
if (switching || !NILP (unread_switch_frame))
|
||||
unread_switch_frame = make_lispy_switch_frame (frame);
|
||||
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
/* Try to recognize SYMBOL as a modifier name.
|
||||
Return the modifier flag bit, or 0 if not recognized. */
|
||||
|
||||
|
@ -11277,6 +11267,7 @@ syms_of_keyboard (void)
|
|||
defsubr (&Scurrent_idle_time);
|
||||
defsubr (&Sevent_symbol_parse_modifiers);
|
||||
defsubr (&Sevent_convert_list);
|
||||
defsubr (&Sinternal_handle_focus_in);
|
||||
defsubr (&Sread_key_sequence);
|
||||
defsubr (&Sread_key_sequence_vector);
|
||||
defsubr (&Srecursive_edit);
|
||||
|
|
|
@ -2886,20 +2886,6 @@ x_focus_changed (int type, int state, struct w32_display_info *dpyinfo,
|
|||
{
|
||||
x_new_focus_frame (dpyinfo, frame);
|
||||
dpyinfo->w32_focus_event_frame = frame;
|
||||
|
||||
/* Don't stop displaying the initial startup message
|
||||
for a switch-frame event we don't need. */
|
||||
if (NILP (Vterminal_frame)
|
||||
&& CONSP (Vframe_list)
|
||||
&& !NILP (XCDR (Vframe_list)))
|
||||
{
|
||||
bufp->arg = Qt;
|
||||
}
|
||||
else
|
||||
{
|
||||
bufp->arg = Qnil;
|
||||
}
|
||||
|
||||
bufp->kind = FOCUS_IN_EVENT;
|
||||
XSETFRAME (bufp->frame_or_window, frame);
|
||||
}
|
||||
|
|
10
src/xterm.c
10
src/xterm.c
|
@ -4387,16 +4387,6 @@ x_focus_changed (int type, int state, struct x_display_info *dpyinfo, struct fra
|
|||
{
|
||||
x_new_focus_frame (dpyinfo, frame);
|
||||
dpyinfo->x_focus_event_frame = frame;
|
||||
|
||||
/* Don't stop displaying the initial startup message
|
||||
for a switch-frame event we don't need. */
|
||||
/* When run as a daemon, Vterminal_frame is always NIL. */
|
||||
bufp->arg = (((NILP (Vterminal_frame)
|
||||
|| ! FRAME_X_P (XFRAME (Vterminal_frame))
|
||||
|| EQ (Fdaemonp (), Qt))
|
||||
&& CONSP (Vframe_list)
|
||||
&& !NILP (XCDR (Vframe_list)))
|
||||
? Qt : Qnil);
|
||||
bufp->kind = FOCUS_IN_EVENT;
|
||||
XSETFRAME (bufp->frame_or_window, frame);
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue