Timer on modeline: how to update modeline every second?












3















As part of my custom mode-line, I've included a feature that displays a countdown timer (timers are created using the chronos package) when it recognises that there is one running.



Works great, but the problem I have is that the mode-line only refreshes when I enter keypresses into Emacs. It will not update in the background (say I work in the browser for a bit but Emacs is still visible).



Is there any good way to force the mode-line to redisplay each second, so that the timer display stays up to date?



Screenshot of mode-line
Screenshot



Relevant code
This is appended to the format-mode-line list:



(if (>= (length chronos--timers-list) 2)
(list " timer|" (propertize (my-timer-display) 'face 'my-red-face) "| ")
"")


The my-timer-display decides whether or not to show the timer. I think this might be the best place to get Emacs to start forcing redisplays.



(defun my-timer-display ()
"Return the lowest timer, avoiding the --now-- time, in the chronos timers list"
(if (string= (chronos--message (nth 0 (chronos--sort-by-expiry))) chronos-now-message)
(my-print-timer 1)
(my-print-timer 0)))


The my-print-timer function referenced just returns the xth timer in the chronos timers list. I won't include it as I don't think it's relevant to the question.










share|improve this question





























    3















    As part of my custom mode-line, I've included a feature that displays a countdown timer (timers are created using the chronos package) when it recognises that there is one running.



    Works great, but the problem I have is that the mode-line only refreshes when I enter keypresses into Emacs. It will not update in the background (say I work in the browser for a bit but Emacs is still visible).



    Is there any good way to force the mode-line to redisplay each second, so that the timer display stays up to date?



    Screenshot of mode-line
    Screenshot



    Relevant code
    This is appended to the format-mode-line list:



    (if (>= (length chronos--timers-list) 2)
    (list " timer|" (propertize (my-timer-display) 'face 'my-red-face) "| ")
    "")


    The my-timer-display decides whether or not to show the timer. I think this might be the best place to get Emacs to start forcing redisplays.



    (defun my-timer-display ()
    "Return the lowest timer, avoiding the --now-- time, in the chronos timers list"
    (if (string= (chronos--message (nth 0 (chronos--sort-by-expiry))) chronos-now-message)
    (my-print-timer 1)
    (my-print-timer 0)))


    The my-print-timer function referenced just returns the xth timer in the chronos timers list. I won't include it as I don't think it's relevant to the question.










    share|improve this question



























      3












      3








      3








      As part of my custom mode-line, I've included a feature that displays a countdown timer (timers are created using the chronos package) when it recognises that there is one running.



      Works great, but the problem I have is that the mode-line only refreshes when I enter keypresses into Emacs. It will not update in the background (say I work in the browser for a bit but Emacs is still visible).



      Is there any good way to force the mode-line to redisplay each second, so that the timer display stays up to date?



      Screenshot of mode-line
      Screenshot



      Relevant code
      This is appended to the format-mode-line list:



      (if (>= (length chronos--timers-list) 2)
      (list " timer|" (propertize (my-timer-display) 'face 'my-red-face) "| ")
      "")


      The my-timer-display decides whether or not to show the timer. I think this might be the best place to get Emacs to start forcing redisplays.



      (defun my-timer-display ()
      "Return the lowest timer, avoiding the --now-- time, in the chronos timers list"
      (if (string= (chronos--message (nth 0 (chronos--sort-by-expiry))) chronos-now-message)
      (my-print-timer 1)
      (my-print-timer 0)))


      The my-print-timer function referenced just returns the xth timer in the chronos timers list. I won't include it as I don't think it's relevant to the question.










      share|improve this question
















      As part of my custom mode-line, I've included a feature that displays a countdown timer (timers are created using the chronos package) when it recognises that there is one running.



      Works great, but the problem I have is that the mode-line only refreshes when I enter keypresses into Emacs. It will not update in the background (say I work in the browser for a bit but Emacs is still visible).



      Is there any good way to force the mode-line to redisplay each second, so that the timer display stays up to date?



      Screenshot of mode-line
      Screenshot



      Relevant code
      This is appended to the format-mode-line list:



      (if (>= (length chronos--timers-list) 2)
      (list " timer|" (propertize (my-timer-display) 'face 'my-red-face) "| ")
      "")


      The my-timer-display decides whether or not to show the timer. I think this might be the best place to get Emacs to start forcing redisplays.



      (defun my-timer-display ()
      "Return the lowest timer, avoiding the --now-- time, in the chronos timers list"
      (if (string= (chronos--message (nth 0 (chronos--sort-by-expiry))) chronos-now-message)
      (my-print-timer 1)
      (my-print-timer 0)))


      The my-print-timer function referenced just returns the xth timer in the chronos timers list. I won't include it as I don't think it's relevant to the question.







      mode-line timers






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Jan 2 at 15:26









      Drew

      47.3k462104




      47.3k462104










      asked Jan 2 at 2:02









      jamesmajjamesmaj

      485




      485






















          2 Answers
          2






          active

          oldest

          votes


















          2














          I try not to use standard timers that repeat because they can affect performance while typing or scrolling. An idle-timer only fires once each time an idle occurs. Therefore, I would suggest setting up a system that runs an idle timer while Emacs has focus and a standard timer when Emacs loses focus. Since that is outside the scope of the question, I will leave that to the O.P. to investigate ...



          To try out the following example, start with emacs -Q, open two or more windows and evaluate the following two lines of code. E.g., place both lines of code in the *scratch* buffer and type M-x eval-buffer.



          The extra set of parentheses used in the example as part of the mode-line-format is not necessary for this example, but is helpful to remind us that we can include additional components of the mode-line (as elements of the list) if so desired.



          Note that this example uses the optional argument for force-mode-line-update to operate on all visible windows.



          (setq-default mode-line-format '((:eval (format-time-string "%m/%d/%Y @ %1I:%M:%S %p"))))

          (run-with-timer 0 1 #'(lambda () (force-mode-line-update t)))





          share|improve this answer
























          • After learning about timer.el from this answer decided to implement a solution like so: ` (progn` ` (cancel-function-timers 'force-mode-line-update)` ` (run-at-time 0.5 nil '(lambda () (force-mode-line-update t)))` ` (list " timer|" (propertize (my-timer-display) 'face 'my-red-face) "| "))` This fits in the true condition for the mode-line-format list.

            – jamesmaj
            Jan 2 at 4:58













          • Unsure on stackoverflow ettiquite. Should I mark this as the answer, or should I create my own detailed answer and give credit to this answer?

            – jamesmaj
            Jan 2 at 5:06











          • I will not be saddened if you write-up your own alternative answer. If you think that the question title and/or body need to be clarified so that this thread helps future forum searches, then please feel free to do so.

            – lawlist
            Jan 2 at 5:07





















          1














          Thanks to @lawlist for directing me to timer.el. A solution I implemented uses timer.el's run-at-time.



          I replaced the format-line-list item with:



          (if (< (length chronos--timers-list) 2)
          ""
          (cancel-function-timers 'force-mode-line-update)
          (run-at-time 0.5 nil '(lambda () (force-mode-line-update t)))
          (list " timer|" (propertize (my-timer-display) 'face 'my-red-face) "| ")))


          This means that if a timer is running, I ask Emacs to update the mode-line in another 0.5s. This sets a timer. To prevent timers building up if I trigger multiple mode-line refreshes within the 0.5s interval I delete any previous timers first (cancel-function-timers).



          I found that if I used a 1s interval, it would sometimes skip a second if I was typing in Emacs. Reducing to 0.5s makes it act/feel smoother.






          share|improve this answer

























            Your Answer








            StackExchange.ready(function() {
            var channelOptions = {
            tags: "".split(" "),
            id: "583"
            };
            initTagRenderer("".split(" "), "".split(" "), channelOptions);

            StackExchange.using("externalEditor", function() {
            // Have to fire editor after snippets, if snippets enabled
            if (StackExchange.settings.snippets.snippetsEnabled) {
            StackExchange.using("snippets", function() {
            createEditor();
            });
            }
            else {
            createEditor();
            }
            });

            function createEditor() {
            StackExchange.prepareEditor({
            heartbeatType: 'answer',
            autoActivateHeartbeat: false,
            convertImagesToLinks: false,
            noModals: true,
            showLowRepImageUploadWarning: true,
            reputationToPostImages: null,
            bindNavPrevention: true,
            postfix: "",
            imageUploader: {
            brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
            contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
            allowUrls: true
            },
            onDemand: true,
            discardSelector: ".discard-answer"
            ,immediatelyShowMarkdownHelp:true
            });


            }
            });














            draft saved

            draft discarded


















            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2femacs.stackexchange.com%2fquestions%2f46846%2ftimer-on-modeline-how-to-update-modeline-every-second%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown

























            2 Answers
            2






            active

            oldest

            votes








            2 Answers
            2






            active

            oldest

            votes









            active

            oldest

            votes






            active

            oldest

            votes









            2














            I try not to use standard timers that repeat because they can affect performance while typing or scrolling. An idle-timer only fires once each time an idle occurs. Therefore, I would suggest setting up a system that runs an idle timer while Emacs has focus and a standard timer when Emacs loses focus. Since that is outside the scope of the question, I will leave that to the O.P. to investigate ...



            To try out the following example, start with emacs -Q, open two or more windows and evaluate the following two lines of code. E.g., place both lines of code in the *scratch* buffer and type M-x eval-buffer.



            The extra set of parentheses used in the example as part of the mode-line-format is not necessary for this example, but is helpful to remind us that we can include additional components of the mode-line (as elements of the list) if so desired.



            Note that this example uses the optional argument for force-mode-line-update to operate on all visible windows.



            (setq-default mode-line-format '((:eval (format-time-string "%m/%d/%Y @ %1I:%M:%S %p"))))

            (run-with-timer 0 1 #'(lambda () (force-mode-line-update t)))





            share|improve this answer
























            • After learning about timer.el from this answer decided to implement a solution like so: ` (progn` ` (cancel-function-timers 'force-mode-line-update)` ` (run-at-time 0.5 nil '(lambda () (force-mode-line-update t)))` ` (list " timer|" (propertize (my-timer-display) 'face 'my-red-face) "| "))` This fits in the true condition for the mode-line-format list.

              – jamesmaj
              Jan 2 at 4:58













            • Unsure on stackoverflow ettiquite. Should I mark this as the answer, or should I create my own detailed answer and give credit to this answer?

              – jamesmaj
              Jan 2 at 5:06











            • I will not be saddened if you write-up your own alternative answer. If you think that the question title and/or body need to be clarified so that this thread helps future forum searches, then please feel free to do so.

              – lawlist
              Jan 2 at 5:07


















            2














            I try not to use standard timers that repeat because they can affect performance while typing or scrolling. An idle-timer only fires once each time an idle occurs. Therefore, I would suggest setting up a system that runs an idle timer while Emacs has focus and a standard timer when Emacs loses focus. Since that is outside the scope of the question, I will leave that to the O.P. to investigate ...



            To try out the following example, start with emacs -Q, open two or more windows and evaluate the following two lines of code. E.g., place both lines of code in the *scratch* buffer and type M-x eval-buffer.



            The extra set of parentheses used in the example as part of the mode-line-format is not necessary for this example, but is helpful to remind us that we can include additional components of the mode-line (as elements of the list) if so desired.



            Note that this example uses the optional argument for force-mode-line-update to operate on all visible windows.



            (setq-default mode-line-format '((:eval (format-time-string "%m/%d/%Y @ %1I:%M:%S %p"))))

            (run-with-timer 0 1 #'(lambda () (force-mode-line-update t)))





            share|improve this answer
























            • After learning about timer.el from this answer decided to implement a solution like so: ` (progn` ` (cancel-function-timers 'force-mode-line-update)` ` (run-at-time 0.5 nil '(lambda () (force-mode-line-update t)))` ` (list " timer|" (propertize (my-timer-display) 'face 'my-red-face) "| "))` This fits in the true condition for the mode-line-format list.

              – jamesmaj
              Jan 2 at 4:58













            • Unsure on stackoverflow ettiquite. Should I mark this as the answer, or should I create my own detailed answer and give credit to this answer?

              – jamesmaj
              Jan 2 at 5:06











            • I will not be saddened if you write-up your own alternative answer. If you think that the question title and/or body need to be clarified so that this thread helps future forum searches, then please feel free to do so.

              – lawlist
              Jan 2 at 5:07
















            2












            2








            2







            I try not to use standard timers that repeat because they can affect performance while typing or scrolling. An idle-timer only fires once each time an idle occurs. Therefore, I would suggest setting up a system that runs an idle timer while Emacs has focus and a standard timer when Emacs loses focus. Since that is outside the scope of the question, I will leave that to the O.P. to investigate ...



            To try out the following example, start with emacs -Q, open two or more windows and evaluate the following two lines of code. E.g., place both lines of code in the *scratch* buffer and type M-x eval-buffer.



            The extra set of parentheses used in the example as part of the mode-line-format is not necessary for this example, but is helpful to remind us that we can include additional components of the mode-line (as elements of the list) if so desired.



            Note that this example uses the optional argument for force-mode-line-update to operate on all visible windows.



            (setq-default mode-line-format '((:eval (format-time-string "%m/%d/%Y @ %1I:%M:%S %p"))))

            (run-with-timer 0 1 #'(lambda () (force-mode-line-update t)))





            share|improve this answer













            I try not to use standard timers that repeat because they can affect performance while typing or scrolling. An idle-timer only fires once each time an idle occurs. Therefore, I would suggest setting up a system that runs an idle timer while Emacs has focus and a standard timer when Emacs loses focus. Since that is outside the scope of the question, I will leave that to the O.P. to investigate ...



            To try out the following example, start with emacs -Q, open two or more windows and evaluate the following two lines of code. E.g., place both lines of code in the *scratch* buffer and type M-x eval-buffer.



            The extra set of parentheses used in the example as part of the mode-line-format is not necessary for this example, but is helpful to remind us that we can include additional components of the mode-line (as elements of the list) if so desired.



            Note that this example uses the optional argument for force-mode-line-update to operate on all visible windows.



            (setq-default mode-line-format '((:eval (format-time-string "%m/%d/%Y @ %1I:%M:%S %p"))))

            (run-with-timer 0 1 #'(lambda () (force-mode-line-update t)))






            share|improve this answer












            share|improve this answer



            share|improve this answer










            answered Jan 2 at 2:34









            lawlistlawlist

            10.5k11062




            10.5k11062













            • After learning about timer.el from this answer decided to implement a solution like so: ` (progn` ` (cancel-function-timers 'force-mode-line-update)` ` (run-at-time 0.5 nil '(lambda () (force-mode-line-update t)))` ` (list " timer|" (propertize (my-timer-display) 'face 'my-red-face) "| "))` This fits in the true condition for the mode-line-format list.

              – jamesmaj
              Jan 2 at 4:58













            • Unsure on stackoverflow ettiquite. Should I mark this as the answer, or should I create my own detailed answer and give credit to this answer?

              – jamesmaj
              Jan 2 at 5:06











            • I will not be saddened if you write-up your own alternative answer. If you think that the question title and/or body need to be clarified so that this thread helps future forum searches, then please feel free to do so.

              – lawlist
              Jan 2 at 5:07





















            • After learning about timer.el from this answer decided to implement a solution like so: ` (progn` ` (cancel-function-timers 'force-mode-line-update)` ` (run-at-time 0.5 nil '(lambda () (force-mode-line-update t)))` ` (list " timer|" (propertize (my-timer-display) 'face 'my-red-face) "| "))` This fits in the true condition for the mode-line-format list.

              – jamesmaj
              Jan 2 at 4:58













            • Unsure on stackoverflow ettiquite. Should I mark this as the answer, or should I create my own detailed answer and give credit to this answer?

              – jamesmaj
              Jan 2 at 5:06











            • I will not be saddened if you write-up your own alternative answer. If you think that the question title and/or body need to be clarified so that this thread helps future forum searches, then please feel free to do so.

              – lawlist
              Jan 2 at 5:07



















            After learning about timer.el from this answer decided to implement a solution like so: ` (progn` ` (cancel-function-timers 'force-mode-line-update)` ` (run-at-time 0.5 nil '(lambda () (force-mode-line-update t)))` ` (list " timer|" (propertize (my-timer-display) 'face 'my-red-face) "| "))` This fits in the true condition for the mode-line-format list.

            – jamesmaj
            Jan 2 at 4:58







            After learning about timer.el from this answer decided to implement a solution like so: ` (progn` ` (cancel-function-timers 'force-mode-line-update)` ` (run-at-time 0.5 nil '(lambda () (force-mode-line-update t)))` ` (list " timer|" (propertize (my-timer-display) 'face 'my-red-face) "| "))` This fits in the true condition for the mode-line-format list.

            – jamesmaj
            Jan 2 at 4:58















            Unsure on stackoverflow ettiquite. Should I mark this as the answer, or should I create my own detailed answer and give credit to this answer?

            – jamesmaj
            Jan 2 at 5:06





            Unsure on stackoverflow ettiquite. Should I mark this as the answer, or should I create my own detailed answer and give credit to this answer?

            – jamesmaj
            Jan 2 at 5:06













            I will not be saddened if you write-up your own alternative answer. If you think that the question title and/or body need to be clarified so that this thread helps future forum searches, then please feel free to do so.

            – lawlist
            Jan 2 at 5:07







            I will not be saddened if you write-up your own alternative answer. If you think that the question title and/or body need to be clarified so that this thread helps future forum searches, then please feel free to do so.

            – lawlist
            Jan 2 at 5:07













            1














            Thanks to @lawlist for directing me to timer.el. A solution I implemented uses timer.el's run-at-time.



            I replaced the format-line-list item with:



            (if (< (length chronos--timers-list) 2)
            ""
            (cancel-function-timers 'force-mode-line-update)
            (run-at-time 0.5 nil '(lambda () (force-mode-line-update t)))
            (list " timer|" (propertize (my-timer-display) 'face 'my-red-face) "| ")))


            This means that if a timer is running, I ask Emacs to update the mode-line in another 0.5s. This sets a timer. To prevent timers building up if I trigger multiple mode-line refreshes within the 0.5s interval I delete any previous timers first (cancel-function-timers).



            I found that if I used a 1s interval, it would sometimes skip a second if I was typing in Emacs. Reducing to 0.5s makes it act/feel smoother.






            share|improve this answer






























              1














              Thanks to @lawlist for directing me to timer.el. A solution I implemented uses timer.el's run-at-time.



              I replaced the format-line-list item with:



              (if (< (length chronos--timers-list) 2)
              ""
              (cancel-function-timers 'force-mode-line-update)
              (run-at-time 0.5 nil '(lambda () (force-mode-line-update t)))
              (list " timer|" (propertize (my-timer-display) 'face 'my-red-face) "| ")))


              This means that if a timer is running, I ask Emacs to update the mode-line in another 0.5s. This sets a timer. To prevent timers building up if I trigger multiple mode-line refreshes within the 0.5s interval I delete any previous timers first (cancel-function-timers).



              I found that if I used a 1s interval, it would sometimes skip a second if I was typing in Emacs. Reducing to 0.5s makes it act/feel smoother.






              share|improve this answer




























                1












                1








                1







                Thanks to @lawlist for directing me to timer.el. A solution I implemented uses timer.el's run-at-time.



                I replaced the format-line-list item with:



                (if (< (length chronos--timers-list) 2)
                ""
                (cancel-function-timers 'force-mode-line-update)
                (run-at-time 0.5 nil '(lambda () (force-mode-line-update t)))
                (list " timer|" (propertize (my-timer-display) 'face 'my-red-face) "| ")))


                This means that if a timer is running, I ask Emacs to update the mode-line in another 0.5s. This sets a timer. To prevent timers building up if I trigger multiple mode-line refreshes within the 0.5s interval I delete any previous timers first (cancel-function-timers).



                I found that if I used a 1s interval, it would sometimes skip a second if I was typing in Emacs. Reducing to 0.5s makes it act/feel smoother.






                share|improve this answer















                Thanks to @lawlist for directing me to timer.el. A solution I implemented uses timer.el's run-at-time.



                I replaced the format-line-list item with:



                (if (< (length chronos--timers-list) 2)
                ""
                (cancel-function-timers 'force-mode-line-update)
                (run-at-time 0.5 nil '(lambda () (force-mode-line-update t)))
                (list " timer|" (propertize (my-timer-display) 'face 'my-red-face) "| ")))


                This means that if a timer is running, I ask Emacs to update the mode-line in another 0.5s. This sets a timer. To prevent timers building up if I trigger multiple mode-line refreshes within the 0.5s interval I delete any previous timers first (cancel-function-timers).



                I found that if I used a 1s interval, it would sometimes skip a second if I was typing in Emacs. Reducing to 0.5s makes it act/feel smoother.







                share|improve this answer














                share|improve this answer



                share|improve this answer








                edited Jan 2 at 15:28









                Drew

                47.3k462104




                47.3k462104










                answered Jan 2 at 5:25









                jamesmajjamesmaj

                485




                485






























                    draft saved

                    draft discarded




















































                    Thanks for contributing an answer to Emacs Stack Exchange!


                    • Please be sure to answer the question. Provide details and share your research!

                    But avoid



                    • Asking for help, clarification, or responding to other answers.

                    • Making statements based on opinion; back them up with references or personal experience.


                    To learn more, see our tips on writing great answers.




                    draft saved


                    draft discarded














                    StackExchange.ready(
                    function () {
                    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2femacs.stackexchange.com%2fquestions%2f46846%2ftimer-on-modeline-how-to-update-modeline-every-second%23new-answer', 'question_page');
                    }
                    );

                    Post as a guest















                    Required, but never shown





















































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown

































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown







                    Popular posts from this blog

                    Can a sorcerer learn a 5th-level spell early by creating spell slots using the Font of Magic feature?

                    Does disintegrating a polymorphed enemy still kill it after the 2018 errata?

                    A Topological Invariant for $pi_3(U(n))$