Timer on modeline: how to update modeline every second?












2














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.



Any help or ideas would be much appreciated, thanks :)










share|improve this question





























    2














    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.



    Any help or ideas would be much appreciated, thanks :)










    share|improve this question



























      2












      2








      2







      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.



      Any help or ideas would be much appreciated, thanks :)










      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.



      Any help or ideas would be much appreciated, thanks :)







      mode-line timers






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited 2 hours ago

























      asked 6 hours ago









      jamesmaj

      335




      335






















          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
            3 hours ago












          • 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
            2 hours ago










          • 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
            2 hours ago





















          0














          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)
          (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 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
              3 hours ago












            • 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
              2 hours ago










            • 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
              2 hours ago


















            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
              3 hours ago












            • 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
              2 hours ago










            • 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
              2 hours ago
















            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 5 hours ago









            lawlist

            10.4k11062




            10.4k11062












            • 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
              3 hours ago












            • 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
              2 hours ago










            • 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
              2 hours ago




















            • 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
              3 hours ago












            • 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
              2 hours ago










            • 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
              2 hours ago


















            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
            3 hours ago






            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
            3 hours ago














            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
            2 hours ago




            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
            2 hours ago












            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
            2 hours ago






            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
            2 hours ago













            0














            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)
            (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 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


























              0














              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)
              (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 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
























                0












                0








                0






                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)
                (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 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)
                (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 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










                answered 2 hours ago









                jamesmaj

                335




                335






























                    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.





                    Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


                    Please pay close attention to the following guidance:


                    • 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

                    Eastern Orthodox Church

                    Zagreb

                    Understanding the information contained in the Deep Space Network XML data?