From 18c26d81cde21b841a8f5f81b81118e5f8c6b07d Mon Sep 17 00:00:00 2001 From: =?utf8?q?Jan=20Dj=C3=A4rv?= Date: Tue, 16 Jul 2013 13:41:06 +0200 Subject: [PATCH] Stop cursor blink after blink-cursor-blinks (10), stop timers when not blinking. * etc/NEWS: Document blink-cursor-blinks and blink timers stopped. * lisp/frame.el (blink-cursor-blinks): New defcustom. (blink-cursor-blinks-done): New defvar. (blink-cursor-start): Set blink-cursor-blinks-done to 1. (blink-cursor-timer-function): Check if number of blinks has been done on X and NS. (blink-cursor-suspend, blink-cursor-check): New defuns. * src/frame.c (Fhandle_focus_in, Fhandle_focus_out): New functions. (Fhandle_switch_frame): Call Fhandle_focus_in. (syms_of_frame): defsubr handle-focus-in/out. * src/keyboard.c (Qfocus_in, Qfocus_out): New static objects. (make_lispy_focus_in, make_lispy_focus_out): Declare and define. (kbd_buffer_get_event): For FOCUS_IN, make a focus_in event if no switch frame event is made. Check ! NILP (event->arg) if X11 (moved from xterm.c). Make focus_out event for FOCUS_OUT_EVENT if NS or X11 and there is a focused frame. (head_table): Add focus-in and focus-out. (keys_of_keyboard): Add focus-in and focus-out to Vspecial_event_map, bind to handle-focus-in/out. * src/nsterm.m (windowDidResignKey): If this is the focused frame, generate FOCUS_OUT_EVENT. * src/termhooks.h (enum event_kind): Add FOCUS_OUT_EVENT. * src/xterm.c (x_focus_changed): Always generate FOCUS_IN_EVENT. Set event->arg to Qt if switch-event shall be generated. Generate FOCUS_OUT_EVENT for FocusOut if this is the focused frame. --- etc/ChangeLog | 4 +++ etc/NEWS | 5 ++++ lisp/ChangeLog | 9 +++++++ lisp/frame.el | 44 +++++++++++++++++++++++++++++++- src/ChangeLog | 25 ++++++++++++++++++ src/frame.c | 23 +++++++++++++++++ src/keyboard.c | 68 +++++++++++++++++++++++++++++++++++++++++-------- src/nsterm.m | 7 ++--- src/termhooks.h | 2 ++ src/xterm.c | 13 ++++++++-- 10 files changed, 184 insertions(+), 16 deletions(-) diff --git a/etc/ChangeLog b/etc/ChangeLog index 02b13e1294..d477f8e3d3 100644 --- a/etc/ChangeLog +++ b/etc/ChangeLog @@ -1,3 +1,7 @@ +2013-07-16 Jan Djärv + + * NEWS: Document blink-cursor-blinks and blink timers stopped. + 2013-07-13 Eli Zaretskii * NEWS: Document prefer-utf-8 and the new attributes diff --git a/etc/NEWS b/etc/NEWS index 869277fa84..46aaf18513 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -122,6 +122,11 @@ monitor, use the new functions above. Similar notes also apply to Generic commands are interactive functions whose implementation can be selected among several alternatives, as a matter of user preference. +** The blink cursor stops blinking after 10 blinks (default) on X and NS. +You can change the default by customizing the variable blink-cursor-blinks. +Also timers for blinking are stopped when no blinking is done, so Emacs does +not consume CPU cycles. + * Editing Changes in Emacs 24.4 diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 5949dcdbd0..d1613283bb 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -1,3 +1,12 @@ +2013-07-16 Jan Djärv + + * frame.el (blink-cursor-blinks): New defcustom. + (blink-cursor-blinks-done): New defvar. + (blink-cursor-start): Set blink-cursor-blinks-done to 1. + (blink-cursor-timer-function): Check if number of blinks has been + done on X and NS. + (blink-cursor-suspend, blink-cursor-check): New defuns. + 2013-07-15 Glenn Morris * edmacro.el (edmacro-format-keys): Fix previous change. diff --git a/lisp/frame.el b/lisp/frame.el index 3ac24a509a..a37d118955 100644 --- a/lisp/frame.el +++ b/lisp/frame.el @@ -1671,6 +1671,16 @@ left untouched. FRAME nil or omitted means use the selected frame." :type 'number :group 'cursor) +(defcustom blink-cursor-blinks 10 + "How many times to blink before using a solid cursor on NS and X. +Use 0 or negative value to blink forever." + :version "24.4" + :type 'integer + :group 'cursor) + +(defvar blink-cursor-blinks-done 1 + "Number of blinks done since we started blinking on NS and X") + (defvar blink-cursor-idle-timer nil "Timer started after `blink-cursor-delay' seconds of Emacs idle time. The function `blink-cursor-start' is called when the timer fires.") @@ -1688,6 +1698,7 @@ command starts, by installing a pre-command hook." (when (null blink-cursor-timer) ;; Set up the timer first, so that if this signals an error, ;; blink-cursor-end is not added to pre-command-hook. + (setq blink-cursor-blinks-done 1) (setq blink-cursor-timer (run-with-timer blink-cursor-interval blink-cursor-interval 'blink-cursor-timer-function)) @@ -1696,7 +1707,15 @@ command starts, by installing a pre-command hook." (defun blink-cursor-timer-function () "Timer function of timer `blink-cursor-timer'." - (internal-show-cursor nil (not (internal-show-cursor-p)))) + (internal-show-cursor nil (not (internal-show-cursor-p))) + ;; Each blink is two calls to this function. + (when (memq window-system '(x ns)) + (setq blink-cursor-blinks-done (1+ blink-cursor-blinks-done)) + (when (and (> blink-cursor-blinks 0) + (<= (* 2 blink-cursor-blinks) blink-cursor-blinks-done)) + (blink-cursor-suspend) + (add-hook 'post-command-hook 'blink-cursor-check)))) + (defun blink-cursor-end () "Stop cursor blinking. @@ -1709,6 +1728,29 @@ itself as a pre-command hook." (cancel-timer blink-cursor-timer) (setq blink-cursor-timer nil))) +(defun blink-cursor-suspend () + "Suspend cursor blinking on NS and X. +This is called when no frame has focus and timers can be suspended. +Timers are restarted by `blink-cursor-check', which is called when a +frame receives focus." + (when (memq window-system '(x ns)) + (blink-cursor-end) + (when blink-cursor-idle-timer + (cancel-timer blink-cursor-idle-timer) + (setq blink-cursor-idle-timer nil)))) + +(defun blink-cursor-check () + "Check if cursot blinking shall be restarted. +This is done when a frame gets focus. Blink timers may be stopped by +`blink-cursor-suspend'." + (when (and blink-cursor-mode + (not blink-cursor-idle-timer)) + (remove-hook 'post-command-hook 'blink-cursor-check) + (setq blink-cursor-idle-timer + (run-with-idle-timer blink-cursor-delay + blink-cursor-delay + 'blink-cursor-start)))) + (define-obsolete-variable-alias 'blink-cursor 'blink-cursor-mode "22.1") (define-minor-mode blink-cursor-mode diff --git a/src/ChangeLog b/src/ChangeLog index 4d819413b4..7c3548c4f8 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,28 @@ +2013-07-16 Jan Djärv + + * xterm.c (x_focus_changed): Always generate FOCUS_IN_EVENT. + Set event->arg to Qt if switch-event shall be generated. + Generate FOCUS_OUT_EVENT for FocusOut if this is the focused frame. + + * termhooks.h (enum event_kind): Add FOCUS_OUT_EVENT. + + * nsterm.m (windowDidResignKey): If this is the focused frame, generate + FOCUS_OUT_EVENT. + + * keyboard.c (Qfocus_in, Qfocus_out): New static objects. + (make_lispy_focus_in, make_lispy_focus_out): Declare and define. + (kbd_buffer_get_event): For FOCUS_IN, make a focus_in event if no + switch frame event is made. Check ! NILP (event->arg) if X11 (moved + from xterm.c). Make focus_out event for FOCUS_OUT_EVENT if NS or X11 + and there is a focused frame. + (head_table): Add focus-in and focus-out. + (keys_of_keyboard): Add focus-in and focus-out to Vspecial_event_map, + bind to handle-focus-in/out. + + * frame.c (Fhandle_focus_in, Fhandle_focus_out): New functions. + (Fhandle_switch_frame): Call Fhandle_focus_in. + (syms_of_frame): defsubr handle-focus-in/out. + 2013-07-16 Paul Eggert Fix porting bug to older POSIXish platforms (Bug#14862). diff --git a/src/frame.c b/src/frame.c index f2cbfaa321..5bd9f77775 100644 --- a/src/frame.c +++ b/src/frame.c @@ -887,6 +887,26 @@ This function returns FRAME, or nil if FRAME has been deleted. */) return do_switch_frame (frame, 1, 0, norecord); } +DEFUN ("handle-focus-in", Fhandle_focus_in, Shandle_focus_in, 1, 1, "e", + doc: /* 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 checks if blink-cursor timers should be turned on again. */) + (Lisp_Object event) +{ + call0 (intern ("blink-cursor-check")); +} + +DEFUN ("handle-focus-out", Fhandle_focus_out, Shandle_focus_out, 1, 1, "e", + doc: /* 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 checks if blink-cursor timers should be turned off. */) + (Lisp_Object event) +{ + call0 (intern ("blink-cursor-suspend")); +} DEFUN ("handle-switch-frame", Fhandle_switch_frame, Shandle_switch_frame, 1, 1, "e", doc: /* Handle a switch-frame event EVENT. @@ -902,6 +922,7 @@ to that frame. */) /* Preserve prefix arg that the command loop just cleared. */ kset_prefix_arg (current_kboard, Vcurrent_prefix_arg); Frun_hooks (1, &Qmouse_leave_buffer_hook); + Fhandle_focus_in (event); // switch-frame implies a focus in. return do_switch_frame (event, 0, 0, Qnil); } @@ -4449,6 +4470,8 @@ automatically. See also `mouse-autoselect-window'. */); defsubr (&Swindow_system); defsubr (&Smake_terminal_frame); defsubr (&Shandle_switch_frame); + defsubr (&Shandle_focus_in); + defsubr (&Shandle_focus_out); defsubr (&Sselect_frame); defsubr (&Sselected_frame); defsubr (&Sframe_list); diff --git a/src/keyboard.c b/src/keyboard.c index f6bc7f308e..5cdb87818c 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -295,6 +295,7 @@ static struct input_event * volatile kbd_store_ptr; static Lisp_Object Qmouse_movement; static Lisp_Object Qscroll_bar_movement; Lisp_Object Qswitch_frame; +static Lisp_Object Qfocus_in, Qfocus_out; static Lisp_Object Qdelete_frame; static Lisp_Object Qiconify_frame; static Lisp_Object Qmake_frame_visible; @@ -420,6 +421,8 @@ static Lisp_Object modify_event_symbol (ptrdiff_t, int, Lisp_Object, Lisp_Object, const char *const *, Lisp_Object *, ptrdiff_t); static Lisp_Object make_lispy_switch_frame (Lisp_Object); +static Lisp_Object make_lispy_focus_in (Lisp_Object); +static Lisp_Object make_lispy_focus_out (Lisp_Object); static bool help_char_p (Lisp_Object); static void save_getcjmp (sys_jmp_buf); static void restore_getcjmp (sys_jmp_buf); @@ -4061,17 +4064,45 @@ kbd_buffer_get_event (KBOARD **kbp, switch-frame event if necessary. */ Lisp_Object frame, focus; - frame = event->frame_or_window; - focus = FRAME_FOCUS_FRAME (XFRAME (frame)); - if (FRAMEP (focus)) - frame = focus; + frame = event->frame_or_window; + focus = FRAME_FOCUS_FRAME (XFRAME (frame)); + if (FRAMEP (focus)) + frame = focus; - if (!EQ (frame, internal_last_event_frame) - && !EQ (frame, selected_frame)) - obj = make_lispy_switch_frame (frame); - internal_last_event_frame = frame; - kbd_fetch_ptr = event + 1; - } + if ( +#ifdef HAVE_X11 + ! NILP (event->arg) + && +#endif + !EQ (frame, internal_last_event_frame) + && !EQ (frame, selected_frame)) + obj = make_lispy_switch_frame (frame); + else + obj = make_lispy_focus_in (frame); + + internal_last_event_frame = frame; + kbd_fetch_ptr = event + 1; + } + else if (event->kind == FOCUS_OUT_EVENT) + { +#if defined(HAVE_NS) || defined (HAVE_X11) + +#ifdef HAVE_NS + struct ns_display_info *di; +#else + struct x_display_info *di; +#endif + Lisp_Object rest, frame = event->frame_or_window; + bool focused = false; + + for (di = x_display_list; di && ! focused; di = di->next) + focused = di->x_highlight_frame != 0; + + if (! focused) obj = make_lispy_focus_out (frame); +#endif /* HAVE_NS || HAVE_X11 */ + + kbd_fetch_ptr = event + 1; + } #ifdef HAVE_DBUS else if (event->kind == DBUS_EVENT) { @@ -6052,6 +6083,17 @@ make_lispy_switch_frame (Lisp_Object frame) { return list2 (Qswitch_frame, frame); } + +static Lisp_Object +make_lispy_focus_in (Lisp_Object frame) +{ + return list2 (Qfocus_in, frame); +} +static Lisp_Object +make_lispy_focus_out (Lisp_Object frame) +{ + return list2 (Qfocus_out, frame); +} /* Manipulating modifiers. */ @@ -10911,6 +10953,8 @@ static const struct event_head head_table[] = { {&Qmouse_movement, "mouse-movement", &Qmouse_movement}, {&Qscroll_bar_movement, "scroll-bar-movement", &Qmouse_movement}, {&Qswitch_frame, "switch-frame", &Qswitch_frame}, + {&Qfocus_in, "focus-in", &Qfocus_in}, + {&Qfocus_out, "focus-out", &Qfocus_out}, {&Qdelete_frame, "delete-frame", &Qdelete_frame}, {&Qiconify_frame, "iconify-frame", &Qiconify_frame}, {&Qmake_frame_visible, "make-frame-visible", &Qmake_frame_visible}, @@ -11725,6 +11769,10 @@ keys_of_keyboard (void) initial_define_lispy_key (Vspecial_event_map, "language-change", "ignore"); #endif + initial_define_lispy_key (Vspecial_event_map, "focus-in", + "handle-focus-in"); + initial_define_lispy_key (Vspecial_event_map, "focus-out", + "handle-focus-out"); } /* Mark the pointers in the kboard objects. diff --git a/src/nsterm.m b/src/nsterm.m index 340ef3b00a..c91e68f37a 100644 --- a/src/nsterm.m +++ b/src/nsterm.m @@ -5746,9 +5746,10 @@ not_in_argv (NSString *arg) /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */ { struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe); + BOOL is_focus_frame = dpyinfo->x_focus_frame == emacsframe; NSTRACE (windowDidResignKey); - if (dpyinfo->x_focus_frame == emacsframe) + if (is_focus_frame) dpyinfo->x_focus_frame = 0; ns_frame_rehighlight (emacsframe); @@ -5761,10 +5762,10 @@ not_in_argv (NSString *arg) x_set_frame_alpha (emacsframe); } - if (emacs_event) + if (emacs_event && is_focus_frame) { [self deleteWorkingText]; - emacs_event->kind = FOCUS_IN_EVENT; + emacs_event->kind = FOCUS_OUT_EVENT; EV_TRAILER ((id)nil); } } diff --git a/src/termhooks.h b/src/termhooks.h index 0190478c25..b49a7bc706 100644 --- a/src/termhooks.h +++ b/src/termhooks.h @@ -172,6 +172,8 @@ enum event_kind `switch-frame' events in kbd_buffer_get_event, if necessary. */ FOCUS_IN_EVENT, + FOCUS_OUT_EVENT, + /* Generated when mouse moves over window not currently selected. */ SELECT_WINDOW_EVENT, diff --git a/src/xterm.c b/src/xterm.c index f1a18d3bf3..74e495e564 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -3439,9 +3439,15 @@ x_focus_changed (int type, int state, struct x_display_info *dpyinfo, struct fra && CONSP (Vframe_list) && !NILP (XCDR (Vframe_list))) { - bufp->kind = FOCUS_IN_EVENT; - XSETFRAME (bufp->frame_or_window, frame); + bufp->arg = Qt; } + else + { + bufp->arg = Qnil; + } + + bufp->kind = FOCUS_IN_EVENT; + XSETFRAME (bufp->frame_or_window, frame); } frame->output_data.x->focus_state |= state; @@ -3459,6 +3465,9 @@ x_focus_changed (int type, int state, struct x_display_info *dpyinfo, struct fra { dpyinfo->x_focus_event_frame = 0; x_new_focus_frame (dpyinfo, 0); + + bufp->kind = FOCUS_OUT_EVENT; + XSETFRAME (bufp->frame_or_window, frame); } #ifdef HAVE_X_I18N -- 2.20.1