Add 2010 to copyright years.
[bpt/emacs.git] / lisp / org / org-clock.el
index 9ab943a..1447411 100644 (file)
@@ -1,11 +1,12 @@
 ;;; org-clock.el --- The time clocking code for Org-mode
 
-;; Copyright (C) 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+;; Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010
+;;   Free Software Foundation, Inc.
 
 ;; Author: Carsten Dominik <carsten at orgmode dot org>
 ;; Keywords: outlines, hypermedia, calendar, wp
 ;; Homepage: http://orgmode.org
-;; Version: 6.15d
+;; Version: 6.33x
 ;;
 ;; This file is part of GNU Emacs.
 ;;
   :tag "Org Clock"
   :group 'org-progress)
 
-(defcustom org-clock-into-drawer 2
+(defcustom org-clock-into-drawer org-log-into-drawer
   "Should clocking info be wrapped into a drawer?
-When t, clocking info will always be inserted into a :CLOCK: drawer.
+When t, clocking info will always be inserted into a :LOGBOOK: drawer.
 If necessary, the drawer will be created.
 When nil, the drawer will not be created, but used when present.
 When an integer and the number of clocking entries in an item
-reaches or exceeds this number, a drawer will be created."
+reaches or exceeds this number, a drawer will be created.
+When a string, it names the drawer to be used.
+
+The default for this variable is the value of `org-log-into-drawer',
+which see."
   :group 'org-todo
   :group 'org-clock
   :type '(choice
          (const :tag "Always" t)
          (const :tag "Only when drawer exists" nil)
-         (integer :tag "When at least N clock entries")))
+         (integer :tag "When at least N clock entries")
+         (const :tag "Into LOGBOOK drawer" "LOGBOOK")
+         (string :tag "Into Drawer named...")))
 
 (defcustom org-clock-out-when-done t
-  "When non-nil, the clock will be stopped when the relevant entry is marked DONE.
+  "When non-nil, clock will be stopped when the clocked entry is marked DONE.
 A nil value means, clock will keep running until stopped explicitly with
 `C-c C-x C-o', or until the clock is started in a different item."
   :group 'org-clock
@@ -79,11 +86,29 @@ state to switch it to."
          (string :tag "State")
          (symbol :tag "Function")))
 
+(defcustom org-clock-out-switch-to-state nil
+  "Set task to a special todo state after clocking out.
+The value should be the state to which the entry should be
+switched. If the value is a function, it must take one
+parameter (the current TODO state of the item) and return the
+state to switch it to."
+  :group 'org-clock
+  :group 'org-todo
+  :type '(choice
+         (const :tag "Don't force a state" nil)
+         (string :tag "State")
+         (symbol :tag "Function")))
+
 (defcustom org-clock-history-length 5
   "Number of clock tasks to remember in history."
   :group 'org-clock
   :type 'integer)
 
+(defcustom org-clock-goto-may-find-recent-task t
+  "Non-nil means, `org-clock-goto' can go to recent task if no active clock."
+  :group 'org-clock
+  :type 'boolean)
+
 (defcustom org-clock-heading-function nil
   "When non-nil, should be a function to create `org-clock-heading'.
 This is the string shown in the mode line when a clock is running.
@@ -92,59 +117,149 @@ The function is called with point at the beginning of the headline."
   :type 'function)
 
 (defcustom org-clock-string-limit 0
-  "Maximum length of clock strings in the modeline. 0 means no limit"
+  "Maximum length of clock strings in the modeline. 0 means no limit."
   :group 'org-clock
   :type 'integer)
 
 (defcustom org-clock-in-resume nil
-  "If non-nil, when clocking into a task with a clock entry which
-has not been closed, resume the clock from that point"
+  "If non-nil, resume clock when clocking into task with open clock.
+When clocking into a task with a clock entry which has not been closed,
+the clock can be resumed from that point."
   :group 'org-clock
   :type 'boolean)
 
 (defcustom org-clock-persist nil
-  "When non-nil, save the running clock when emacs is closed, and
-  resume it next time emacs is started.
+  "When non-nil, save the running clock when emacs is closed.
+The clock is resumed when emacs restarts.
 When this is t, both the running clock, and the entire clock
 history are saved.  When this is the symbol `clock', only the
 running clock is saved.
 
 When Emacs restarts with saved clock information, the file containing the
 running clock as well as all files mentioned in the clock history will
-be visited."
+be visited.
+All this depends on running `org-clock-persistence-insinuate' in .emacs"
   :group 'org-clock
   :type '(choice
          (const :tag "Just the running clock" clock)
+         (const :tag "Just the history" history)
          (const :tag "Clock and history" t)
          (const :tag "No persistence" nil)))
 
 (defcustom org-clock-persist-file (convert-standard-filename
                                   "~/.emacs.d/org-clock-save.el")
-  "File to save clock data to"
+  "File to save clock data to."
   :group 'org-clock
   :type 'string)
 
 (defcustom org-clock-persist-query-save nil
-  "When non-nil, ask before saving the current clock on exit"
+  "When non-nil, ask before saving the current clock on exit."
   :group 'org-clock
   :type 'boolean)
 
 (defcustom org-clock-persist-query-resume t
-  "When non-nil, ask before resuming any stored clock during
-load."
+  "When non-nil, ask before resuming any stored clock during load."
   :group 'org-clock
   :type 'boolean)
 
+(defcustom org-clock-sound nil
+  "Sound that will used for notifications.
+Possible values:
+
+nil        no sound played.
+t          standard Emacs beep
+file name  play this sound file.  If not possible, fall back to beep"
+  :group 'org-clock
+  :type '(choice
+         (const :tag "No sound" nil)
+         (const :tag "Standard beep" t)
+         (file :tag "Play sound file")))
+
+(defcustom org-clock-modeline-total 'auto
+  "Default setting for the time included for the modeline clock.
+This can be overruled locally using the CLOCK_MODELINE_TOTAL property.
+Allowed values are:
+
+current  Only the time in the current instance of the clock
+today    All time clocked into this task today
+repeat   All time clocked into this task since last repeat
+all      All time ever recorded for this task
+auto     Automatically, either `all', or `repeat' for repeating tasks"
+  :group 'org-clock
+  :type '(choice
+         (const :tag "Current clock" current)
+         (const :tag "Today's task time" today)
+         (const :tag "Since last repeat" repeat)
+         (const :tag "All task time" all)
+         (const :tag "Automatically, `all' or since `repeat'" auto)))
+
+(defcustom org-show-notification-handler nil
+  "Function or program to send notification with.
+The function or program will be called with the notification
+string as argument."
+  :group 'org-clock
+  :type '(choice
+         (string :tag "Program")
+         (function :tag "Function")))
+
+(defcustom org-clock-clocktable-default-properties '(:maxlevel 2 :scope file)
+  "Default properties for new clocktables."
+  :group 'org-clock
+  :type 'plist)
+
+(defcustom org-clock-idle-time nil
+  "When non-nil, resolve open clocks if the user is idle more than X minutes."
+  :group 'org-clock
+  :type '(choice
+         (const :tag "Never" nil)
+         (integer :tag "After N minutes")))
+
+(defcustom org-clock-auto-clock-resolution 'when-no-clock-is-running
+  "When to automatically resolve open clocks found in Org buffers."
+  :group 'org-clock
+  :type '(choice
+         (const :tag "Never" nil)
+         (const :tag "Always" t)
+         (const :tag "When no clock is running" when-no-clock-is-running)))
+
+(defvar org-clock-in-prepare-hook nil
+  "Hook run when preparing the clock.
+This hook is run before anything happens to the task that
+you want to clock in.  For example, you can use this hook
+to add an effort property.")
+(defvar org-clock-in-hook nil
+  "Hook run when starting the clock.")
+(defvar org-clock-out-hook nil
+  "Hook run when stopping the current clock.")
+
+(defvar org-clock-cancel-hook nil
+  "Hook run when cancelling the current clock.")
+(defvar org-clock-goto-hook nil
+  "Hook run when selecting the currently clocked-in entry.")
+(defvar org-clock-has-been-used nil
+  "Has the clock been used during the current Emacs session?")
+
 ;;; The clock for measuring work time.
 
 (defvar org-mode-line-string "")
 (put 'org-mode-line-string 'risky-local-variable t)
 
-(defvar org-mode-line-timer nil)
-(defvar org-clock-heading "")
+(defvar org-clock-mode-line-timer nil)
+(defvar org-clock-idle-timer nil)
+(defvar org-clock-heading) ; defined in org.el
 (defvar org-clock-heading-for-remember "")
 (defvar org-clock-start-time "")
 
+(defvar org-clock-left-over-time nil
+  "If non-nil, user cancelled a clock; this is when leftover time started.")
+
+(defvar org-clock-effort ""
+  "Effort estimate of the currently clocking task")
+
+(defvar org-clock-total-time nil
+  "Holds total time, spent previously on currently clocked item.
+This does not include the time in the currently running clock.")
+
 (defvar org-clock-history nil
   "List of marker pointing to recent clocked tasks.")
 
@@ -156,8 +271,18 @@ of a different task.")
 (defvar org-clock-interrupted-task (make-marker)
   "Marker pointing to the task that has been interrupted by the current clock.")
 
-(defvar org-clock-mode-map (make-sparse-keymap))
-(define-key org-clock-mode-map [mode-line mouse-2] 'org-clock-goto)
+(defvar org-clock-mode-line-map (make-sparse-keymap))
+(define-key org-clock-mode-line-map [mode-line mouse-2] 'org-clock-goto)
+(define-key org-clock-mode-line-map [mode-line mouse-1] 'org-clock-menu)
+
+(defun org-clock-menu ()
+  (interactive)
+  (popup-menu
+   '("Clock"
+     ["Clock out" org-clock-out t]
+     ["Change effort estimate" org-clock-modify-effort-estimate t]
+     ["Go to clock entry" org-clock-goto t]
+     ["Switch task" (lambda () (interactive) (org-clock-in '(4))) :active t :keys "C-u C-c C-x C-i"])))
 
 (defun org-clock-history-push (&optional pos buffer)
   "Push a marker to the clock history."
@@ -179,6 +304,7 @@ of a different task.")
 (defun org-clock-save-markers-for-cut-and-paste (beg end)
   "Save relative positions of markers in region."
   (org-check-and-save-marker org-clock-marker beg end)
+  (org-check-and-save-marker org-clock-hd-marker beg end)
   (org-check-and-save-marker org-clock-default-task beg end)
   (org-check-and-save-marker org-clock-interrupted-task beg end)
   (mapc (lambda (m) (org-check-and-save-marker m beg end))
@@ -187,7 +313,7 @@ of a different task.")
 (defun org-clock-select-task (&optional prompt)
   "Select a task that recently was associated with clocking."
   (interactive)
-  (let (sel-list rpl file task (i 0) s)
+  (let (sel-list rpl (i 0) s)
     (save-window-excursion
       (org-switch-to-buffer-other-window
        (get-buffer-create "*Clock Task Select*"))
@@ -225,8 +351,11 @@ of a different task.")
        (t (error "Invalid task choice %c" rpl))))))
 
 (defun org-clock-insert-selection-line (i marker)
+  "Insert a line for the clock selection menu.
+And return a cons cell with the selection character integer and the marker
+pointing to it."
   (when (marker-buffer marker)
-    (let (file cat task)
+    (let (file cat task heading prefix)
       (with-current-buffer (org-base-buffer (marker-buffer marker))
        (save-excursion
          (save-restriction
@@ -236,33 +365,459 @@ of a different task.")
                  cat (or (org-get-category)
                          (progn (org-refresh-category-properties)
                                 (org-get-category)))
-                 task (org-get-heading 'notags)))))
+                 heading (org-get-heading 'notags)
+                 prefix (save-excursion
+                          (org-back-to-heading t)
+                          (looking-at "\\*+ ")
+                          (match-string 0))
+                 task (substring
+                       (org-fontify-like-in-org-mode
+                        (concat prefix heading)
+                        org-odd-levels-only)
+                       (length prefix))))))
       (when (and cat task)
        (insert (format "[%c] %-15s %s\n" i cat task))
        (cons i marker)))))
 
-(defun org-update-mode-line ()
-  (let* ((delta (- (time-to-seconds (current-time))
-                  (time-to-seconds org-clock-start-time)))
-        (h (floor delta 3600))
-        (m (floor (- delta (* 3600 h)) 60)))
-    (setq org-mode-line-string
-         (org-propertize
-          (let ((clock-string (format (concat "-[" org-time-clocksum-format " (%s)]")
-                                      h m org-clock-heading))
-                (help-text "Org-mode clock is running. Mouse-2 to go there."))
-            (if (and (> org-clock-string-limit 0)
-                     (> (length clock-string) org-clock-string-limit))
-                (org-propertize (substring clock-string 0 org-clock-string-limit)
-                            'help-echo (concat help-text ": " org-clock-heading))
-              (org-propertize clock-string 'help-echo help-text)))
-          'local-map org-clock-mode-map
-          'mouse-face (if (featurep 'xemacs) 'highlight 'mode-line-highlight)))
-    (force-mode-line-update)))
+(defun org-clock-get-clock-string ()
+  "Form a clock-string, that will be show in the mode line.
+If an effort estimate was defined for current item, use
+01:30/01:50 format (clocked/estimated).
+If not, show simply the clocked time like 01:50."
+  (let* ((clocked-time (org-clock-get-clocked-time))
+        (h (floor clocked-time 60))
+        (m (- clocked-time (* 60 h))))
+    (if (and org-clock-effort)
+       (let* ((effort-in-minutes (org-hh:mm-string-to-minutes org-clock-effort))
+              (effort-h (floor effort-in-minutes 60))
+              (effort-m (- effort-in-minutes (* effort-h 60))))
+         (format (concat "-[" org-time-clocksum-format "/" org-time-clocksum-format " (%s)]")
+                 h m effort-h effort-m  org-clock-heading))
+      (format (concat "-[" org-time-clocksum-format " (%s)]")
+             h m org-clock-heading))))
+
+(defun org-clock-update-mode-line ()
+  (setq org-mode-line-string
+       (org-propertize
+        (let ((clock-string (org-clock-get-clock-string))
+              (help-text "Org-mode clock is running.\nmouse-1 shows a menu\nmouse-2 will jump to task"))
+          (if (and (> org-clock-string-limit 0)
+                   (> (length clock-string) org-clock-string-limit))
+              (org-propertize (substring clock-string 0 org-clock-string-limit)
+                              'help-echo (concat help-text ": " org-clock-heading))
+            (org-propertize clock-string 'help-echo help-text)))
+        'local-map org-clock-mode-line-map
+        'mouse-face (if (featurep 'xemacs) 'highlight 'mode-line-highlight)
+        'face 'org-mode-line-clock))
+  (if org-clock-effort (org-clock-notify-once-if-expired))
+  (force-mode-line-update))
+
+(defun org-clock-get-clocked-time ()
+  "Get the clocked time for the current item in minutes.
+The time returned includes the time spent on this task in
+previous clocking intervals."
+  (let ((currently-clocked-time
+        (floor (- (org-float-time)
+                  (org-float-time org-clock-start-time)) 60)))
+    (+ currently-clocked-time (or org-clock-total-time 0))))
+
+(defun org-clock-modify-effort-estimate (&optional value)
+ "Add to or set the effort estimate of the item currently being clocked.
+VALUE can be a number of minutes, or a string with format hh:mm or mm.
+When the string starts with a + or a - sign, the current value of the effort
+property will be changed by that amount.
+This will update the \"Effort\" property of currently clocked item, and
+the mode line."
+ (interactive)
+ (when (org-clock-is-active)
+   (let ((current org-clock-effort) sign)
+     (unless value
+       ;; Prompt user for a value or a change
+       (setq value
+            (read-string
+             (format "Set effort (hh:mm or mm%s): "
+                     (if current
+                         (format ", prefix + to add to %s" org-clock-effort)
+                       "")))))
+     (when (stringp value)
+       ;; A string.  See if it is a delta
+       (setq sign (string-to-char value))
+       (if (member sign '(?- ?+))
+          (setq current (org-hh:mm-string-to-minutes (substring current 1)))
+        (setq current 0))
+       (setq value (org-hh:mm-string-to-minutes value))
+       (if (equal ?- sign)
+          (setq value (- current value))
+        (if (equal ?+ sign) (setq value (+ current value)))))
+     (setq value (max 0 value)
+          org-clock-effort (org-minutes-to-hh:mm-string value))
+     (org-entry-put org-clock-marker "Effort" org-clock-effort)
+     (org-clock-update-mode-line)
+     (message "Effort is now %s" org-clock-effort))))
+
+(defvar org-clock-notification-was-shown nil
+  "Shows if we have shown notification already.")
+
+(defun org-clock-notify-once-if-expired ()
+  "Show notification if we spent more time than we estimated before.
+Notification is shown only once."
+  (when (marker-buffer org-clock-marker)
+    (let ((effort-in-minutes (org-hh:mm-string-to-minutes org-clock-effort))
+         (clocked-time (org-clock-get-clocked-time)))
+      (if (>= clocked-time effort-in-minutes)
+         (unless org-clock-notification-was-shown
+           (setq org-clock-notification-was-shown t)
+           (org-notify
+            (format "Task '%s' should be finished by now. (%s)"
+                    org-clock-heading org-clock-effort) t))
+       (setq org-clock-notification-was-shown nil)))))
+
+(defun org-notify (notification &optional play-sound)
+  "Send a NOTIFICATION and maybe PLAY-SOUND."
+  (org-show-notification notification)
+  (if play-sound (org-clock-play-sound)))
+
+(defun org-show-notification (notification)
+  "Show notification.
+Use `org-show-notification-handler' if defined,
+use libnotify if available, or fall back on a message."
+  (cond ((functionp org-show-notification-handler)
+        (funcall org-show-notification-handler notification))
+       ((stringp org-show-notification-handler)
+        (start-process "emacs-timer-notification" nil
+                       org-show-notification-handler notification))
+       ((org-program-exists "notify-send")
+        (start-process "emacs-timer-notification" nil
+                       "notify-send" notification))
+       ;; Maybe the handler will send a message, so only use message as
+       ;; a fall back option
+       (t (message "%s" notification))))
+
+(defun org-clock-play-sound ()
+  "Play sound as configured by `org-clock-sound'.
+Use alsa's aplay tool if available."
+  (cond
+   ((not org-clock-sound))
+   ((eq org-clock-sound t) (beep t) (beep t))
+   ((stringp org-clock-sound)
+    (let ((file (expand-file-name org-clock-sound)))
+      (if (file-exists-p file)
+         (if (org-program-exists "aplay")
+             (start-process "org-clock-play-notification" nil
+                            "aplay" file)
+           (condition-case nil
+               (play-sound-file file)
+             (error (beep t) (beep t)))))))))
+
+(defun org-program-exists (program-name)
+  "Checks whenever we can locate program and launch it."
+  (if (eq system-type 'gnu/linux)
+      (= 0 (call-process "which" nil nil nil program-name))))
 
 (defvar org-clock-mode-line-entry nil
   "Information for the modeline about the running clock.")
 
+(defun org-find-open-clocks (file)
+  "Search through the given file and find all open clocks."
+  (let ((buf (or (get-file-buffer file)
+                (find-file-noselect file)))
+       clocks)
+    (with-current-buffer buf
+      (save-excursion
+       (goto-char (point-min))
+       (while (re-search-forward "CLOCK: \\(\\[.*?\\]\\)$" nil t)
+         (push (cons (copy-marker (1- (match-end 1)) t)
+                     (org-time-string-to-time (match-string 1))) clocks))))
+    clocks))
+
+(defsubst org-is-active-clock (clock)
+  "Return t if CLOCK is the currently active clock."
+  (and (org-clock-is-active)
+       (= org-clock-marker (car clock))))
+
+(defmacro org-with-clock-position (clock &rest forms)
+  "Evaluate FORMS with CLOCK as the current active clock."
+  `(with-current-buffer (marker-buffer (car ,clock))
+     (save-excursion
+       (save-restriction
+        (widen)
+        (goto-char (car ,clock))
+        (beginning-of-line)
+        ,@forms))))
+
+(put 'org-with-clock-position 'lisp-indent-function 1)
+
+(defmacro org-with-clock (clock &rest forms)
+  "Evaluate FORMS with CLOCK as the current active clock.
+This macro also protects the current active clock from being altered."
+  `(org-with-clock-position ,clock
+     (let ((org-clock-start-time (cdr ,clock))
+          (org-clock-total-time)
+          (org-clock-history)
+          (org-clock-effort)
+          (org-clock-marker (car ,clock))
+          (org-clock-hd-marker (save-excursion
+                                 (outline-back-to-heading t)
+                                 (point-marker))))
+       ,@forms)))
+
+(put 'org-with-clock 'lisp-indent-function 1)
+
+(defsubst org-clock-clock-in (clock &optional resume)
+  "Clock in to the clock located by CLOCK.
+If necessary, clock-out of the currently active clock."
+  (org-with-clock-position clock
+    (let ((org-clock-in-resume (or resume org-clock-in-resume)))
+      (org-clock-in))))
+
+(defsubst org-clock-clock-out (clock &optional fail-quietly at-time)
+  "Clock out of the clock located by CLOCK."
+  (let ((temp (copy-marker (car clock)
+                          (marker-insertion-type (car clock)))))
+    (if (org-is-active-clock clock)
+       (org-clock-out fail-quietly at-time)
+      (org-with-clock clock
+       (org-clock-out fail-quietly at-time)))
+    (setcar clock temp)))
+
+(defsubst org-clock-clock-cancel (clock)
+  "Cancel the clock located by CLOCK."
+  (let ((temp (copy-marker (car clock)
+                          (marker-insertion-type (car clock)))))
+    (if (org-is-active-clock clock)
+       (org-clock-cancel)
+      (org-with-clock clock
+       (org-clock-cancel)))
+    (setcar clock temp)))
+
+(defvar org-clock-clocking-in nil)
+(defvar org-clock-resolving-clocks nil)
+(defvar org-clock-resolving-clocks-due-to-idleness nil)
+
+(defun org-clock-resolve-clock (clock resolve-to &optional close-p
+                                     restart-p fail-quietly)
+  "Resolve `CLOCK' given the time `RESOLVE-TO', and the present.
+`CLOCK' is a cons cell of the form (MARKER START-TIME).
+This routine can do one of many things:
+
+  if `RESOLVE-TO' is nil
+    if `CLOSE-P' is non-nil, give an error
+    if this clock is the active clock, cancel it
+    else delete the clock line (as if it never happened)
+    if `RESTART-P' is non-nil, start a new clock
+
+  else if `RESOLVE-TO' is the symbol `now'
+    if `RESTART-P' is non-nil, give an error
+    if `CLOSE-P' is non-nil, clock out the entry and
+       if this clock is the active clock, stop it
+    else if this clock is the active clock, do nothing
+    else if there is no active clock, resume this clock
+    else ask to cancel the active clock, and if so,
+         resume this clock after cancelling it
+
+  else if `RESOLVE-TO' is some date in the future
+    give an error about `RESOLVE-TO' being invalid
+
+  else if `RESOLVE-TO' is some date in the past
+    if `RESTART-P' is non-nil, give an error
+    if `CLOSE-P' is non-nil, enter a closing time and
+       if this clock is the active clock, stop it
+    else if this clock is the active clock, enter a
+       closing time, stop the current clock, then
+       start a new clock for the same item
+    else just enter a closing time for this clock
+       and then start a new clock for the same item"
+  (let ((org-clock-resolving-clocks t))
+    (cond
+     ((null resolve-to)
+      (org-clock-clock-cancel clock)
+      (if (and restart-p (not org-clock-clocking-in))
+         (org-clock-clock-in clock)))
+
+     ((eq resolve-to 'now)
+      (if restart-p
+         (error "RESTART-P is not valid here"))
+      (if (or close-p org-clock-clocking-in)
+         (org-clock-clock-out clock fail-quietly)
+       (unless (org-is-active-clock clock)
+         (org-clock-clock-in clock t))))
+
+     ((not (time-less-p resolve-to (current-time)))
+      (error "RESOLVE-TO must refer to a time in the past"))
+
+     (t
+      (if restart-p
+         (error "RESTART-P is not valid here"))
+      (org-clock-clock-out clock fail-quietly resolve-to)
+      (unless org-clock-clocking-in
+       (if close-p
+           (setq org-clock-left-over-time resolve-to)
+         (org-clock-clock-in clock)))))))
+
+(defun org-clock-resolve (clock &optional prompt-fn last-valid fail-quietly)
+  "Resolve an open org-mode clock.
+An open clock was found, with `dangling' possibly being non-nil.
+If this function was invoked with a prefix argument, non-dangling
+open clocks are ignored.  The given clock requires some sort of
+user intervention to resolve it, either because a clock was left
+dangling or due to an idle timeout.  The clock resolution can
+either be:
+
+  (a) deleted, the user doesn't care about the clock
+  (b) restarted from the current time (if no other clock is open)
+  (c) closed, giving the clock X minutes
+  (d) closed and then restarted
+  (e) resumed, as if the user had never left
+
+The format of clock is (CONS MARKER START-TIME), where MARKER
+identifies the buffer and position the clock is open at (and
+thus, the heading it's under), and START-TIME is when the clock
+was started."
+  (assert clock)
+  (let* ((ch
+         (save-window-excursion
+           (save-excursion
+             (unless org-clock-resolving-clocks-due-to-idleness
+               (org-with-clock clock (org-clock-goto))
+               (with-current-buffer (marker-buffer (car clock))
+                 (goto-char (car clock))
+                 (if org-clock-into-drawer
+                     (let ((logbook
+                            (if (stringp org-clock-into-drawer)
+                                (concat ":" org-clock-into-drawer ":")
+                              ":LOGBOOK:")))
+                       (ignore-errors
+                         (outline-flag-region
+                          (save-excursion
+                            (outline-back-to-heading t)
+                            (search-forward logbook)
+                            (goto-char (match-beginning 0)))
+                          (save-excursion
+                            (outline-back-to-heading t)
+                            (search-forward logbook)
+                            (search-forward ":END:")
+                            (goto-char (match-end 0)))
+                          nil))))))
+             (let (char-pressed)
+               (while (null char-pressed)
+                 (setq char-pressed
+                       (read-char (concat (funcall prompt-fn clock)
+                                          " [(kK)eep (sS)ubtract (C)ancel]? ")
+                                  nil 45)))
+               char-pressed))))
+        (default (floor (/ (org-float-time
+                            (time-subtract (current-time) last-valid)) 60)))
+        (keep (and (memq ch '(?k ?K))
+                   (read-number "Keep how many minutes? " default)))
+        (subtractp (memq ch '(?s ?S)))
+        (barely-started-p (< (- (org-float-time last-valid)
+                                (org-float-time (cdr clock))) 45))
+        (start-over (and subtractp barely-started-p)))
+    (if (or (null ch)
+           (not (memq ch '(?k ?K ?s ?S ?C))))
+       (message "")
+      (org-clock-resolve-clock
+       clock (cond
+             ((or (eq ch ?C)
+                  ;; If the time on the clock was less than a minute before
+                  ;; the user went away, and they've ask to subtract all the
+                  ;; time...
+                  start-over)
+              nil)
+             (subtractp
+              last-valid)
+             ((= keep default)
+              'now)
+             (t
+              (time-add last-valid (seconds-to-time (* 60 keep)))))
+       (memq ch '(?K ?S))
+       (and start-over
+           (not (memq ch '(?K ?S ?C))))
+       fail-quietly))))
+
+(defun org-resolve-clocks (&optional also-non-dangling-p prompt-fn last-valid)
+  "Resolve all currently open org-mode clocks.
+If `also-non-dangling-p' is non-nil, also ask to resolve
+non-dangling (i.e., currently open and valid) clocks."
+  (interactive "P")
+  (unless org-clock-resolving-clocks
+    (let ((org-clock-resolving-clocks t))
+      (dolist (file (org-files-list))
+       (let ((clocks (org-find-open-clocks file)))
+         (dolist (clock clocks)
+           (let ((dangling (or (not (org-clock-is-active))
+                               (/= (car clock) org-clock-marker))))
+             (unless (and (not dangling) (not also-non-dangling-p))
+               (org-clock-resolve
+                clock
+                (or prompt-fn
+                    (function
+                     (lambda (clock)
+                       (format
+                        "Dangling clock started %d mins ago"
+                        (floor
+                         (/ (- (org-float-time (current-time))
+                               (org-float-time (cdr clock))) 60))))))
+                (or last-valid
+                    (cdr clock)))))))))))
+
+(defun org-emacs-idle-seconds ()
+  "Return the current Emacs idle time in seconds, or nil if not idle."
+  (let ((idle-time (current-idle-time)))
+    (if idle-time
+       (org-float-time idle-time)
+      0)))
+
+(defun org-mac-idle-seconds ()
+  "Return the current Mac idle time in seconds"
+  (string-to-number (shell-command-to-string "ioreg -c IOHIDSystem | perl -ane 'if (/Idle/) {$idle=(pop @F)/1000000000; print $idle; last}'")))
+
+(defun org-x11-idle-seconds ()
+  "Return the current X11 idle time in seconds"
+  (/ (string-to-number (shell-command-to-string "x11idle")) 1000))
+
+(defun org-user-idle-seconds ()
+  "Return the number of seconds the user has been idle for.
+This routine returns a floating point number."
+  (if (or (eq system-type 'darwin) (eq window-system 'x))
+      (let ((emacs-idle (org-emacs-idle-seconds)))
+       ;; If Emacs has been idle for longer than the user's
+       ;; `org-clock-idle-time' value, check whether the whole system has
+       ;; really been idle for that long.
+       (if (> emacs-idle (* 60 org-clock-idle-time))
+           (min emacs-idle (if (eq system-type 'darwin)
+                               (org-mac-idle-seconds)
+                             (org-x11-idle-seconds)))
+         emacs-idle))
+    (org-emacs-idle-seconds)))
+
+(defvar org-clock-user-idle-seconds)
+
+(defun org-resolve-clocks-if-idle ()
+  "Resolve all currently open org-mode clocks.
+This is performed after `org-clock-idle-time' minutes, to check
+if the user really wants to stay clocked in after being idle for
+so long."
+  (when (and org-clock-idle-time (not org-clock-resolving-clocks)
+            org-clock-marker)
+    (let ((org-clock-user-idle-seconds (org-user-idle-seconds))
+         (org-clock-user-idle-start
+          (time-subtract (current-time)
+                         (seconds-to-time org-clock-user-idle-seconds)))
+         (org-clock-resolving-clocks-due-to-idleness t))
+      (if (> org-clock-user-idle-seconds (* 60 org-clock-idle-time))
+         (org-clock-resolve
+          (cons org-clock-marker
+                org-clock-start-time)
+          (function
+           (lambda (clock)
+             (format "Clocked in & idle for %.1f mins"
+                     (/ (org-float-time
+                         (time-subtract (current-time)
+                                        org-clock-user-idle-start))
+                        60.0))))
+          org-clock-user-idle-start)))))
+
 (defun org-clock-in (&optional select)
   "Start the clock on the current item.
 If necessary, clock-out of the currently active clock.
@@ -271,9 +826,21 @@ clock into.  When SELECT is `C-u C-u', clock into the current task and mark
 is as the default task, a special task that will always be offered in
 the clocking selection, associated with the letter `d'."
   (interactive "P")
+  (setq org-clock-notification-was-shown nil)
   (catch 'abort
-    (let ((interrupting (marker-buffer org-clock-marker))
-         ts selected-task target-pos)
+    (let ((interrupting (and (not org-clock-resolving-clocks-due-to-idleness)
+                            (marker-buffer org-clock-marker)))
+         ts selected-task target-pos (msg-extra "")
+         (left-over (and (not org-clock-resolving-clocks)
+                         org-clock-left-over-time)))
+      (when (and org-clock-auto-clock-resolution
+                (or (not interrupting)
+                    (eq t org-clock-auto-clock-resolution))
+                (not org-clock-clocking-in)
+                (not org-clock-resolving-clocks))
+       (setq org-clock-left-over-time nil)
+       (let ((org-clock-clocking-in t))
+         (org-resolve-clocks)))        ; check if any clocks are dangling
       (when (equal select '(4))
        (setq selected-task (org-clock-select-task "Clock-in on task: "))
        (if selected-task
@@ -286,14 +853,17 @@ the clocking selection, associated with the letter `d'."
                     (marker-position org-clock-marker)
                     (marker-buffer org-clock-marker))
        (org-clock-out t))
-
+      
       (when (equal select '(16))
        ;; Mark as default clocking task
-       (save-excursion
-         (org-back-to-heading t)
-         (move-marker org-clock-default-task (point))))
-
-      (setq target-pos (point))  ;; we want to clock in at this location
+       (org-clock-mark-default-task))
+      
+      ;; Clock in at which position?
+      (setq target-pos
+           (if (and (eobp) (not (org-on-heading-p)))
+               (point-at-bol 0)
+             (point)))
+      (run-hooks 'org-clock-in-prepare-hook)
       (save-excursion
        (when (and selected-task (marker-buffer selected-task))
          ;; There is a selected task, move to the correct buffer
@@ -332,19 +902,22 @@ the clocking selection, associated with the letter `d'."
                        (t "???")))
            (setq org-clock-heading (org-propertize org-clock-heading
                                                    'face nil))
-           (org-clock-find-position)
+           (org-clock-find-position org-clock-in-resume)
            (cond
             ((and org-clock-in-resume
                   (looking-at
-                   (concat "^[ \\t]* " org-clock-string
+                   (concat "^[ \t]* " org-clock-string
                            " \\[\\([0-9]\\{4\\}-[0-9]\\{2\\}-[0-9]\\{2\\}"
-                           " +\\sw+ +[012][0-9]:[0-5][0-9]\\)\\][ \t]*$")))
+                           " +\\sw+\.? +[012][0-9]:[0-5][0-9]\\)\\][ \t]*$")))
              (message "Matched %s" (match-string 1))
              (setq ts (concat "[" (match-string 1) "]"))
              (goto-char (match-end 1))
              (setq org-clock-start-time
                    (apply 'encode-time
-                          (org-parse-time-string (match-string 1)))))
+                          (org-parse-time-string (match-string 1))))
+             (setq org-clock-effort (org-get-effort))
+             (setq org-clock-total-time (org-clock-sum-current-item
+                                         (org-clock-get-sum-start))))
             ((eq org-clock-in-resume 'auto-restart)
              ;; called from org-clock-load during startup,
              ;; do not interrupt, but warn!
@@ -353,23 +926,99 @@ the clocking selection, associated with the letter `d'."
              (sit-for 2)
              (throw 'abort nil))
             (t
-             (insert "\n") (backward-char 1)
+             (insert-before-markers "\n")
+             (backward-char 1)
              (org-indent-line-function)
+             (when (and (save-excursion
+                          (end-of-line 0)
+                          (org-in-item-p)))
+               (beginning-of-line 1)
+               (org-indent-line-to (- (org-get-indentation) 2)))
              (insert org-clock-string " ")
-             (setq org-clock-start-time (current-time))
-             (setq ts (org-insert-time-stamp org-clock-start-time 'with-hm 'inactive))))
+             (setq org-clock-effort (org-get-effort))
+             (setq org-clock-total-time (org-clock-sum-current-item
+                                         (org-clock-get-sum-start)))
+             (setq org-clock-start-time
+                   (or (and left-over
+                            (y-or-n-p
+                             (format
+                              "You stopped another clock %d mins ago; start this one from then? "
+                              (/ (- (org-float-time (current-time))
+                                    (org-float-time left-over)) 60)))
+                            left-over)
+                       (current-time)))
+             (setq ts (org-insert-time-stamp org-clock-start-time
+                                             'with-hm 'inactive))))
            (move-marker org-clock-marker (point) (buffer-base-buffer))
+           (move-marker org-clock-hd-marker
+                        (save-excursion (org-back-to-heading t) (point))
+                        (buffer-base-buffer))
+           (setq org-clock-has-been-used t)
            (or global-mode-string (setq global-mode-string '("")))
            (or (memq 'org-mode-line-string global-mode-string)
                (setq global-mode-string
                      (append global-mode-string '(org-mode-line-string))))
-           (org-update-mode-line)
-           (setq org-mode-line-timer
-                 (run-with-timer 60 60 'org-update-mode-line))
-           (message "Clock started at %s" ts)))))))
-
-(defun org-clock-find-position ()
-  "Find the location where the next clock line should be inserted."
+           (org-clock-update-mode-line)
+           (when org-clock-mode-line-timer
+             (cancel-timer org-clock-mode-line-timer)
+             (setq org-clock-mode-line-timer nil))
+           (setq org-clock-mode-line-timer
+                 (run-with-timer 60 60 'org-clock-update-mode-line))
+           (when org-clock-idle-timer
+             (cancel-timer org-clock-idle-timer)
+             (setq org-clock-idle-timer nil))
+           (setq org-clock-idle-timer
+                 (run-with-timer 60 60 'org-resolve-clocks-if-idle))
+           (message "Clock starts at %s - %s" ts msg-extra)
+           (run-hooks 'org-clock-in-hook)))))))
+
+(defun org-clock-mark-default-task ()
+  "Mark current task as default task."
+  (interactive)
+  (save-excursion
+    (org-back-to-heading t)
+    (move-marker org-clock-default-task (point))))
+
+(defvar msg-extra)
+(defun org-clock-get-sum-start ()
+  "Return the time from which clock times should be counted.
+This is for the currently running clock as it is displayed
+in the mode line.  This function looks at the properties
+LAST_REPEAT and in particular CLOCK_MODELINE_TOTAL and the
+corresponding variable `org-clock-modeline-total' and then
+decides which time to use."
+  (let ((cmt (or (org-entry-get nil "CLOCK_MODELINE_TOTAL")
+                (symbol-name org-clock-modeline-total)))
+       (lr (org-entry-get nil "LAST_REPEAT")))
+    (cond
+     ((equal cmt "current")
+      (setq msg-extra "showing time in current clock instance")
+      (current-time))
+     ((equal cmt "today")
+      (setq msg-extra "showing today's task time.")
+      (let* ((dt (decode-time (current-time))))
+       (setq dt (append (list 0 0 0) (nthcdr 3 dt)))
+       (if org-extend-today-until
+           (setf (nth 2 dt) org-extend-today-until))
+       (apply 'encode-time dt)))
+     ((or (equal cmt "all")
+         (and (or (not cmt) (equal cmt "auto"))
+              (not lr)))
+      (setq msg-extra "showing entire task time.")
+      nil)
+     ((or (equal cmt "repeat")
+         (and (or (not cmt) (equal cmt "auto"))
+              lr))
+      (setq msg-extra "showing task time since last repeat.")
+      (if (not lr)
+         nil
+       (org-time-string-to-time lr)))
+     (t nil))))
+
+(defun org-clock-find-position (find-unclosed)
+  "Find the location where the next clock line should be inserted.
+When FIND-UNCLOSED is non-nil, first check if there is an unclosed clock
+line and position cursor in that line."
   (org-back-to-heading t)
   (catch 'exit
     (let ((beg (save-excursion
@@ -379,12 +1028,25 @@ the clocking selection, associated with the letter `d'."
          (end (progn (outline-next-heading) (point)))
          (re (concat "^[ \t]*" org-clock-string))
          (cnt 0)
-         first last)
+         (drawer (if (stringp org-clock-into-drawer)
+                     org-clock-into-drawer "LOGBOOK"))
+         first last ind-last)
       (goto-char beg)
+      (when (and find-unclosed
+                (re-search-forward
+                 (concat "^[ \t]* " org-clock-string
+                         " \\[\\([0-9]\\{4\\}-[0-9]\\{2\\}-[0-9]\\{2\\}"
+                         " +\\sw+ +[012][0-9]:[0-5][0-9]\\)\\][ \t]*$")
+                 end t))
+       (beginning-of-line 1)
+       (throw 'exit t))
       (when (eobp) (newline) (setq end (max (point) end)))
-      (when (re-search-forward "^[ \t]*:CLOCK:" end t)
+      (when (re-search-forward (concat "^[ \t]*:" drawer ":") end t)
        ;; we seem to have a CLOCK drawer, so go there.
        (beginning-of-line 2)
+       (or org-log-states-order-reversed
+           (and (re-search-forward org-property-end-re nil t)
+                (goto-char (match-beginning 0))))
        (throw 'exit t))
       ;; Lets count the CLOCK lines
       (goto-char beg)
@@ -393,20 +1055,27 @@ the clocking selection, associated with the letter `d'."
              last (match-beginning 0)
              cnt (1+ cnt)))
       (when (and (integerp org-clock-into-drawer)
+                last
                 (>= (1+ cnt) org-clock-into-drawer))
        ;; Wrap current entries into a new drawer
        (goto-char last)
+       (setq ind-last (org-get-indentation))
        (beginning-of-line 2)
-       (if (org-at-item-p) (org-end-of-item))
+       (if (and (>= (org-get-indentation) ind-last)
+                (org-at-item-p))
+           (org-end-of-item))
        (insert ":END:\n")
        (beginning-of-line 0)
-       (org-indent-line-function)
+       (org-indent-line-to ind-last)
        (goto-char first)
-       (insert ":CLOCK:\n")
+       (insert ":" drawer ":\n")
        (beginning-of-line 0)
        (org-indent-line-function)
        (org-flag-drawer t)
        (beginning-of-line 2)
+       (or org-log-states-order-reversed
+           (and (re-search-forward org-property-end-re nil t)
+                (goto-char (match-beginning 0))))
        (throw 'exit nil))
 
       (goto-char beg)
@@ -415,62 +1084,89 @@ the clocking selection, associated with the letter `d'."
        ;; Planning info, skip to after it
        (beginning-of-line 2)
        (or (bolp) (newline)))
-      (when (eq t org-clock-into-drawer)
-       (insert ":CLOCK:\n:END:\n")
-       (beginning-of-line 0)
+      (when (or (eq org-clock-into-drawer t)
+               (stringp org-clock-into-drawer)
+               (and (integerp org-clock-into-drawer)
+                    (< org-clock-into-drawer 2)))
+       (insert ":" drawer ":\n:END:\n")
+       (beginning-of-line -1)
        (org-indent-line-function)
-       (beginning-of-line 0)
        (org-flag-drawer t)
+       (beginning-of-line 2)
        (org-indent-line-function)
-       (beginning-of-line 2)))))
+       (beginning-of-line)
+       (or org-log-states-order-reversed
+           (and (re-search-forward org-property-end-re nil t)
+                (goto-char (match-beginning 0))))))))
 
-(defun org-clock-out (&optional fail-quietly)
+(defun org-clock-out (&optional fail-quietly at-time)
   "Stop the currently running clock.
 If there is no running clock, throw an error, unless FAIL-QUIETLY is set."
   (interactive)
   (catch 'exit
-  (if (not (marker-buffer org-clock-marker))
-      (if fail-quietly (throw 'exit t) (error "No active clock")))
-  (let (ts te s h m remove)
-    (save-excursion
-      (set-buffer (marker-buffer org-clock-marker))
-      (save-restriction
-       (widen)
-       (goto-char org-clock-marker)
-       (beginning-of-line 1)
-       (if (and (looking-at (concat "[ \t]*" org-keyword-time-regexp))
-                (equal (match-string 1) org-clock-string))
-           (setq ts (match-string 2))
-         (if fail-quietly (throw 'exit nil) (error "Clock start time is gone")))
-       (goto-char (match-end 0))
-       (delete-region (point) (point-at-eol))
-       (insert "--")
-       (setq te (org-insert-time-stamp (current-time) 'with-hm 'inactive))
-       (setq s (- (time-to-seconds (apply 'encode-time (org-parse-time-string te)))
-                  (time-to-seconds (apply 'encode-time (org-parse-time-string ts))))
-             h (floor (/ s 3600))
-             s (- s (* 3600 h))
-             m (floor (/ s 60))
-             s (- s (* 60 s)))
-       (insert " => " (format "%2d:%02d" h m))
-       (when (setq remove (and org-clock-out-remove-zero-time-clocks
-                               (= (+ h m) 0)))
+    (if (not (marker-buffer org-clock-marker))
+       (if fail-quietly (throw 'exit t) (error "No active clock")))
+    (let (ts te s h m remove)
+      (save-excursion
+       (set-buffer (marker-buffer org-clock-marker))
+       (save-restriction
+         (widen)
+         (goto-char org-clock-marker)
          (beginning-of-line 1)
+         (if (and (looking-at (concat "[ \t]*" org-keyword-time-regexp))
+                  (equal (match-string 1) org-clock-string))
+             (setq ts (match-string 2))
+           (if fail-quietly (throw 'exit nil) (error "Clock start time is gone")))
+         (goto-char (match-end 0))
          (delete-region (point) (point-at-eol))
-         (and (looking-at "\n") (> (point-max) (1+ (point)))
-              (delete-char 1)))
-       (move-marker org-clock-marker nil)
-       (when org-log-note-clock-out
-         (org-add-log-setup 'clock-out nil nil nil
-                            (concat "# Task: " (org-get-heading t) "\n\n")))
-       (when org-mode-line-timer
-         (cancel-timer org-mode-line-timer)
-         (setq org-mode-line-timer nil))
-       (setq global-mode-string
-             (delq 'org-mode-line-string global-mode-string))
-       (force-mode-line-update)
-       (message (concat "Clock stopped at %s after HH:MM = " org-time-clocksum-format "%s") te h m
-                (if remove " => LINE REMOVED" "")))))))
+         (insert "--")
+         (setq te (org-insert-time-stamp (or at-time (current-time))
+                                         'with-hm 'inactive))
+         (setq s (- (org-float-time (apply 'encode-time (org-parse-time-string te)))
+                    (org-float-time (apply 'encode-time (org-parse-time-string ts))))
+               h (floor (/ s 3600))
+               s (- s (* 3600 h))
+               m (floor (/ s 60))
+               s (- s (* 60 s)))
+         (insert " => " (format "%2d:%02d" h m))
+         (when (setq remove (and org-clock-out-remove-zero-time-clocks
+                                 (= (+ h m) 0)))
+           (beginning-of-line 1)
+           (delete-region (point) (point-at-eol))
+           (and (looking-at "\n") (> (point-max) (1+ (point)))
+                (delete-char 1)))
+         (move-marker org-clock-marker nil)
+         (move-marker org-clock-hd-marker nil)
+         (when org-log-note-clock-out
+           (org-add-log-setup 'clock-out nil nil nil nil
+                              (concat "# Task: " (org-get-heading t) "\n\n")))
+         (when org-clock-mode-line-timer
+           (cancel-timer org-clock-mode-line-timer)
+           (setq org-clock-mode-line-timer nil))
+         (when org-clock-idle-timer
+           (cancel-timer org-clock-idle-timer)
+           (setq org-clock-idle-timer nil))
+         (setq global-mode-string
+               (delq 'org-mode-line-string global-mode-string))
+         (when org-clock-out-switch-to-state
+           (save-excursion
+             (org-back-to-heading t)
+             (let ((org-inhibit-logging t))
+               (cond
+                ((functionp org-clock-out-switch-to-state)
+                 (looking-at org-complex-heading-regexp)
+                 (let ((newstate (funcall org-clock-out-switch-to-state
+                                          (match-string 2))))
+                   (if newstate (org-todo newstate))))
+                ((and org-clock-out-switch-to-state
+                      (not (looking-at (concat outline-regexp "[ \t]*"
+                                               org-clock-out-switch-to-state
+                                               "\\>"))))
+                 (org-todo org-clock-out-switch-to-state))))))
+         (force-mode-line-update)
+         (message (concat "Clock stopped at %s after HH:MM = " org-time-clocksum-format "%s") te h m
+                  (if remove " => LINE REMOVED" ""))
+          (run-hooks 'org-clock-out-hook))))))
 
 (defun org-clock-cancel ()
   "Cancel the running clock be removing the start timestamp."
@@ -480,38 +1176,52 @@ If there is no running clock, throw an error, unless FAIL-QUIETLY is set."
   (save-excursion
     (set-buffer (marker-buffer org-clock-marker))
     (goto-char org-clock-marker)
-    (delete-region (1- (point-at-bol)) (point-at-eol)))
+    (delete-region (1- (point-at-bol)) (point-at-eol))
+    ;; Just in case, remove any empty LOGBOOK left over
+    (org-remove-empty-drawer-at "LOGBOOK" (point)))
+  (move-marker org-clock-marker nil)
+  (move-marker org-clock-hd-marker nil)
   (setq global-mode-string
        (delq 'org-mode-line-string global-mode-string))
   (force-mode-line-update)
-  (message "Clock canceled"))
+  (message "Clock canceled")
+  (run-hooks 'org-clock-cancel-hook))
 
 (defun org-clock-goto (&optional select)
-  "Go to the currently clocked-in entry.
-With prefix arg SELECT, offer recently clocked tasks."
-  (interactive "P")
-  (let ((m (if select
-              (org-clock-select-task "Select task to go to: ")
-            org-clock-marker)))
-    (if (not (marker-buffer m))
-       (if select
-           (error "No task selected")
-         (error "No active clock")))
+  "Go to the currently clocked-in entry, or to the most recently clocked one.
+With prefix arg SELECT, offer recently clocked tasks for selection."
+  (interactive "@P")
+  (let* ((recent nil)
+        (m (cond
+            (select
+             (or (org-clock-select-task "Select task to go to: ")
+                 (error "No task selected")))
+            ((marker-buffer org-clock-marker) org-clock-marker)
+            ((and org-clock-goto-may-find-recent-task
+                  (car org-clock-history)
+                  (marker-buffer (car org-clock-history)))
+             (setq recent t)
+             (car org-clock-history))
+            (t (error "No active or recent clock task")))))
     (switch-to-buffer (marker-buffer m))
     (if (or (< m (point-min)) (> m (point-max))) (widen))
     (goto-char m)
     (org-show-entry)
-    (org-back-to-heading)
+    (org-back-to-heading t)
     (org-cycle-hide-drawers 'children)
-    (recenter)))
+    (recenter)
+    (if recent
+       (message "No running clock, this is the most recently clocked task"))
+    (run-hooks 'org-clock-goto-hook)))
 
 (defvar org-clock-file-total-minutes nil
   "Holds the file total time in minutes, after a call to `org-clock-sum'.")
-  (make-variable-buffer-local 'org-clock-file-total-minutes)
+(make-variable-buffer-local 'org-clock-file-total-minutes)
 
 (defun org-clock-sum (&optional tstart tend)
   "Sum the times for each subtree.
-Puts the resulting times in minutes as a text property on each headline."
+Puts the resulting times in minutes as a text property on each headline.
+TSTART and TEND can mark a time range to be considered."
   (interactive)
   (let* ((bmp (buffer-modified-p))
         (re (concat "^\\(\\*+\\)[ \t]\\|^[ \t]*"
@@ -523,6 +1233,10 @@ Puts the resulting times in minutes as a text property on each headline."
         (level 0)
         ts te dt
         time)
+    (if (stringp tstart) (setq tstart (org-time-string-to-seconds tstart)))
+    (if (stringp tend) (setq tend (org-time-string-to-seconds tend)))
+    (if (consp tstart) (setq tstart (org-float-time tstart)))
+    (if (consp tend) (setq tend (org-float-time tend)))
     (remove-text-properties (point-min) (point-max) '(:org-clock-minutes t))
     (save-excursion
       (goto-char (point-max))
@@ -532,9 +1246,9 @@ Puts the resulting times in minutes as a text property on each headline."
          ;; Two time stamps
          (setq ts (match-string 2)
                te (match-string 3)
-               ts (time-to-seconds
+               ts (org-float-time
                    (apply 'encode-time (org-parse-time-string ts)))
-               te (time-to-seconds
+               te (org-float-time
                    (apply 'encode-time (org-parse-time-string te)))
                ts (if tstart (max ts tstart) ts)
                te (if tend (min te tend) te)
@@ -557,12 +1271,20 @@ Puts the resulting times in minutes as a text property on each headline."
       (setq org-clock-file-total-minutes (aref ltimes 0)))
     (set-buffer-modified-p bmp)))
 
+(defun org-clock-sum-current-item (&optional tstart)
+  "Returns time, clocked on current item in total"
+  (save-excursion
+    (save-restriction
+      (org-narrow-to-subtree)
+      (org-clock-sum tstart)
+      org-clock-file-total-minutes)))
+
 (defun org-clock-display (&optional total-only)
   "Show subtree times in the entire buffer.
 If TOTAL-ONLY is non-nil, only show the total time for the entire file
 in the echo area."
   (interactive)
-  (org-remove-clock-overlays)
+  (org-clock-remove-overlays)
   (let (time h m p)
     (org-clock-sum)
     (unless total-only
@@ -574,26 +1296,33 @@ in the echo area."
                            (point) :org-clock-minutes)))
          (goto-char p)
          (when (setq time (get-text-property p :org-clock-minutes))
-           (org-put-clock-overlay time (funcall outline-level))))
+           (org-clock-put-overlay time (funcall outline-level))))
        (setq h (/ org-clock-file-total-minutes 60)
              m (- org-clock-file-total-minutes (* 60 h)))
        ;; Arrange to remove the overlays upon next change.
        (when org-remove-highlights-with-change
-         (org-add-hook 'before-change-functions 'org-remove-clock-overlays
+         (org-add-hook 'before-change-functions 'org-clock-remove-overlays
                        nil 'local))))
-    (message (concat "Total file time: " org-time-clocksum-format " (%d hours and %d minutes)") h m h m)))
+    (if org-time-clocksum-use-fractional
+       (message (concat "Total file time: " org-time-clocksum-fractional-format
+                        " (%d hours and %d minutes)")
+                (/ (+ (* h 60.0) m) 60.0) h m)
+      (message (concat "Total file time: " org-time-clocksum-format
+                      " (%d hours and %d minutes)") h m h m))))
 
 (defvar org-clock-overlays nil)
 (make-variable-buffer-local 'org-clock-overlays)
 
-(defun org-put-clock-overlay (time &optional level)
+(defun org-clock-put-overlay (time &optional level)
   "Put an overlays on the current line, displaying TIME.
 If LEVEL is given, prefix time with a corresponding number of stars.
 This creates a new overlay and stores it in `org-clock-overlays', so that it
 will be easy to remove."
   (let* ((c 60) (h (floor (/ time 60))) (m (- time (* 60 h)))
         (l (if level (org-get-valid-level level 0) 0))
-        (fmt (concat "%s " org-time-clocksum-format "%s"))
+        (fmt (concat "%s " (if org-time-clocksum-use-fractional
+                               org-time-clocksum-fractional-format
+                             org-time-clocksum-format) "%s"))
         (off 0)
         ov tx)
     (org-move-to-column c)
@@ -602,10 +1331,15 @@ will be easy to remove."
     (setq ov (org-make-overlay (1- (point)) (point-at-eol))
          tx (concat (buffer-substring (1- (point)) (point))
                     (make-string (+ off (max 0 (- c (current-column)))) ?.)
-                    (org-add-props (format fmt
-                                           (make-string l ?*) h m
-                                           (make-string (- 16 l) ?\ ))
-                        '(face secondary-selection))
+                    (org-add-props (if org-time-clocksum-use-fractional
+                                       (format fmt
+                                               (make-string l ?*)
+                                               (/ (+ (* h 60.0) m) 60.0)
+                                               (make-string (- 16 l) ?\ ))
+                                     (format fmt
+                                             (make-string l ?*) h m
+                                             (make-string (- 16 l) ?\ )))
+                        (list 'face 'org-clock-overlay))
                     ""))
     (if (not (featurep 'xemacs))
        (org-overlay-put ov 'display tx)
@@ -613,7 +1347,7 @@ will be easy to remove."
       (org-overlay-put ov 'end-glyph (make-glyph tx)))
     (push ov org-clock-overlays)))
 
-(defun org-remove-clock-overlays (&optional beg end noremove)
+(defun org-clock-remove-overlays (&optional beg end noremove)
   "Remove the occur highlights from the buffer.
 BEG and END are ignored.  If NOREMOVE is nil, remove this function
 from the `before-change-functions' in the current buffer."
@@ -623,7 +1357,7 @@ from the `before-change-functions' in the current buffer."
     (setq org-clock-overlays nil)
     (unless noremove
       (remove-hook 'before-change-functions
-                  'org-remove-clock-overlays 'local))))
+                  'org-clock-remove-overlays 'local))))
 
 (defvar state) ;; dynamically scoped into this function
 (defun org-clock-out-if-current ()
@@ -632,7 +1366,10 @@ This is used to stop the clock after a TODO entry is marked DONE,
 and is only done if the variable `org-clock-out-when-done' is not nil."
   (when (and org-clock-out-when-done
             (member state org-done-keywords)
-            (equal (marker-buffer org-clock-marker) (current-buffer))
+            (equal (or (buffer-base-buffer (marker-buffer org-clock-marker))
+                       (marker-buffer org-clock-marker))
+                   (or (buffer-base-buffer (current-buffer))
+                       (current-buffer)))
             (< (point) org-clock-marker)
             (> (save-excursion (outline-next-heading) (point))
                org-clock-marker))
@@ -671,14 +1408,14 @@ will be updated.  If not, a new clocktable will be inserted.
 When called with a prefix argument, move to the first clock table in the
 buffer and update it."
   (interactive "P")
-  (org-remove-clock-overlays)
+  (org-clock-remove-overlays)
   (when arg
     (org-find-dblock "clocktable")
     (org-show-entry))
   (if (org-in-clocktable-p)
       (goto-char (org-in-clocktable-p))
-    (org-create-dblock (list :name "clocktable"
-                            :maxlevel 2 :scope 'file)))
+    (org-create-dblock (append (list :name "clocktable")
+                              org-clock-clocktable-default-properties)))
   (org-update-dblock))
 
 (defun org-in-clocktable-p ()
@@ -723,6 +1460,7 @@ the returned times will be formatted strings."
       (setq date (calendar-gregorian-from-absolute
                  (calendar-absolute-from-iso (list w 1 y))))
       (setq d (nth 1 date) month (car date) y (nth 2 date)
+           dow 1
            key 'week))
      ((string-match "^\\([0-9]+\\)-\\([0-9]\\{1,2\\}\\)-\\([0-9]\\{1,2\\}\\)$" skey)
       (setq y (string-to-number (match-string 1 skey))
@@ -799,7 +1537,7 @@ the currently selected interval size."
         ((string-match "\\([0-9]+\\)\\(-\\([wW]?\\)\\([0-9]\\{1,2\\}\\)\\(-\\([0-9]\\{1,2\\}\\)\\)?\\)?" s)
          ;;               1        1  2   3       3  4                4  5   6                6  5   2
          (setq y (string-to-number (match-string 1 s))
-                wp (and (match-end 3) (match-string 3 s))
+               wp (and (match-end 3) (match-string 3 s))
                mw (and (match-end 4) (string-to-number (match-string 4 s)))
                d (and (match-end 6) (string-to-number (match-string 6 s))))
          (cond
@@ -840,11 +1578,12 @@ the currently selected interval size."
           (maxlevel (or (plist-get params :maxlevel) 3))
           (step (plist-get params :step))
           (emph (plist-get params :emphasize))
+          (timestamp (plist-get params :timestamp))
           (ts (plist-get params :tstart))
           (te (plist-get params :tend))
           (block (plist-get params :block))
           (link (plist-get params :link))
-          ipos time p level hlc hdl content recalc formula pcol
+          ipos time p level hlc hdl tsp props content recalc formula pcol
           cc beg end pos tbl tbl1 range-text rm-file-column scope-is-list st)
       (setq org-clock-file-total-minutes nil)
       (when step
@@ -862,9 +1601,9 @@ the currently selected interval size."
       (when (and te (listp te))
        (setq te (format "%4d-%02d-%02d" (nth 2 te) (car te) (nth 1 te))))
       ;; Now the times are strings we can parse.
-      (if ts (setq ts (time-to-seconds
+      (if ts (setq ts (org-float-time
                       (apply 'encode-time (org-parse-time-string ts)))))
-      (if te (setq te (time-to-seconds
+      (if te (setq te (org-float-time
                       (apply 'encode-time (org-parse-time-string te)))))
       (move-marker ins (point))
       (setq ipos (point))
@@ -949,10 +1688,18 @@ the currently selected interval size."
                                       (save-match-data
                                         (org-make-org-heading-search-string
                                          (match-string 2))))
-                              (match-string 2))))
+                              (match-string 2)))
+                       tsp (when timestamp
+                             (setq props (org-entry-properties (point)))
+                             (or (cdr (assoc "SCHEDULED" props))
+                                 (cdr (assoc "TIMESTAMP" props))
+                                 (cdr (assoc "DEADLINE" props))
+                                 (cdr (assoc "TIMESTAMP_IA" props)))))
                  (if (and (not multifile) (= level 1)) (push "|-" tbl))
                  (push (concat
-                        "| " (int-to-string level) "|" hlc hdl hlc " |"
+                        "| " (int-to-string level) "|"
+                        (if timestamp (concat tsp "|") "")
+                        hlc hdl hlc " |"
                         (make-string (1- level) ?|)
                         hlc (org-minutes-to-hh:mm-string time) hlc
                         " |") tbl))))))
@@ -971,12 +1718,12 @@ the currently selected interval size."
                (if block (concat ", for " range-text ".") "")
                "\n\n"))
           (if scope-is-list "|File" "")
-          "|L|Headline|Time|\n")
+          "|L|" (if timestamp "Timestamp|" "") "Headline|Time|\n")
          (setq total-time (or total-time org-clock-file-total-minutes))
          (insert-before-markers
           "|-\n|"
           (if scope-is-list "|" "")
-          "|"
+          (if timestamp "|Timestamp|" "|")
           "*Total time*| *"
           (org-minutes-to-hh:mm-string (or total-time 0))
           "*|\n|-\n")
@@ -1007,7 +1754,7 @@ the currently selected interval size."
               (t (error "invalid formula in clocktable")))
            ;; Should we rescue an old formula?
            (when (stringp (setq content (plist-get params :content)))
-             (when (string-match "^\\(#\\+TBLFM:.*\\)" content)
+             (when (string-match "^\\([ \t]*#\\+TBLFM:.*\\)" content)
                (setq recalc t)
                (insert "\n" (match-string 1 (plist-get params :content)))
                (beginning-of-line 0))))
@@ -1034,9 +1781,9 @@ the currently selected interval size."
     (when block
       (setq cc (org-clock-special-range block nil t)
            ts (car cc) te (nth 1 cc) range-text (nth 2 cc)))
-    (if ts (setq ts (time-to-seconds
+    (if ts (setq ts (org-float-time
                     (apply 'encode-time (org-parse-time-string ts)))))
-    (if te (setq te (time-to-seconds
+    (if te (setq te (org-float-time
                     (apply 'encode-time (org-parse-time-string te)))))
     (setq p1 (plist-put p1 :header ""))
     (setq p1 (plist-put p1 :step nil))
@@ -1044,10 +1791,10 @@ the currently selected interval size."
     (while (< ts te)
       (or (bolp) (insert "\n"))
       (setq p1 (plist-put p1 :tstart (format-time-string
-                                     (car org-time-stamp-formats)
+                                     (org-time-stamp-format nil t)
                                      (seconds-to-time ts))))
       (setq p1 (plist-put p1 :tend (format-time-string
-                                   (car org-time-stamp-formats)
+                                   (org-time-stamp-format nil t)
                                    (seconds-to-time (setq ts (+ ts step))))))
       (insert "\n" (if (eq step0 'day) "Daily report: " "Weekly report starting on: ")
              (plist-get p1 :tstart) "\n")
@@ -1090,11 +1837,17 @@ This function is made for clock tables."
                        tot))))
        0))))
 
+(defvar org-clock-loaded nil
+  "Was the clock file loaded?")
+
 (defun org-clock-save ()
   "Persist various clock-related data to disk.
 The details of what will be saved are regulated by the variable
 `org-clock-persist'."
-  (when org-clock-persist
+  (when (and org-clock-persist
+             (or org-clock-loaded
+                org-clock-has-been-used
+                (not (file-exists-p org-clock-persist-file))))
     (let (b)
       (with-current-buffer (find-file (expand-file-name org-clock-persist-file))
        (progn
@@ -1103,7 +1856,8 @@ The details of what will be saved are regulated by the variable
          (insert (format ";; org-persist.el - %s at %s\n"
                          system-name (format-time-string
                                       (cdr org-time-stamp-formats))))
-         (if (and (setq b (marker-buffer org-clock-marker))
+         (if (and (memq org-clock-persist '(t clock))
+                  (setq b (marker-buffer org-clock-marker))
                   (setq b (or (buffer-base-buffer b) b))
                   (buffer-live-p b)
                   (buffer-file-name b)
@@ -1117,7 +1871,8 @@ The details of what will be saved are regulated by the variable
                      "))\n"))
          ;; Store clocked task history. Tasks are stored reversed to make
          ;; reading simpler
-         (when (and org-clock-history (eq org-clock-persist t))
+         (when (and (memq org-clock-persist '(t history))
+                    org-clock-history)
            (insert
             "(setq stored-clock-history '("
             (mapconcat
@@ -1133,12 +1888,8 @@ The details of what will be saved are regulated by the variable
          (save-buffer)
          (kill-buffer (current-buffer)))))))
 
-(defvar org-clock-loaded nil
-  "Was the clock file loaded?")
-
 (defun org-clock-load ()
-  "Load various clock-related data from disk, optionally resuming
-a stored clock"
+  "Load clock-related data from disk, maybe resuming a stored clock."
   (when (and org-clock-persist (not org-clock-loaded))
     (let ((filename (expand-file-name org-clock-persist-file))
          (org-clock-in-resume 'auto-restart)
@@ -1174,9 +1925,10 @@ a stored clock"
          (when (file-exists-p (car resume-clock))
            (with-current-buffer (find-file (car resume-clock))
              (goto-char (cdr resume-clock))
-             (org-clock-in)
-             (if (org-invisible-p)
-                 (org-show-context)))))))))
+             (let ((org-clock-auto-clock-resolution nil))
+               (org-clock-in)
+               (if (org-invisible-p)
+                   (org-show-context))))))))))
 
 ;;;###autoload
 (defun org-clock-persistence-insinuate ()
@@ -1184,6 +1936,9 @@ a stored clock"
   (add-hook 'org-mode-hook 'org-clock-load)
   (add-hook 'kill-emacs-hook 'org-clock-save))
 
+;; Suggested bindings
+(org-defkey org-mode-map "\C-c\C-x\C-e" 'org-clock-modify-effort-estimate)
+
 (provide 'org-clock)
 
 ;; arch-tag: 7b42c5d4-9b36-48be-97c0-66a869daed4c