Index: generic/tk.decls
===================================================================
RCS file: /cvsroot/tktoolkit/tk/generic/tk.decls,v
retrieving revision 1.26
diff -u -r1.26 tk.decls
--- generic/tk.decls	17 Mar 2004 18:15:42 -0000	1.26
+++ generic/tk.decls	27 Apr 2005 11:43:14 -0000
@@ -1262,6 +1262,13 @@
     int Tk_PhotoSetSize(Tcl_Interp *interp, Tk_PhotoHandle handle,
 	    int width, int height)
 }
+# TIP#245
+declare 269 generic {
+    long Tk_GetUserInactiveTime(Display *dpy)
+}
+declare 270 generic {
+    void Tk_ResetUserInactiveTime(Display *dpy)
+}
 
 # Define the platform specific public Tk interface.  These functions are
 # only available on the designated platform.
Index: generic/tkCmds.c
===================================================================
RCS file: /cvsroot/tktoolkit/tk/generic/tkCmds.c,v
retrieving revision 1.35
diff -u -r1.35 tkCmds.c
--- generic/tkCmds.c	12 Nov 2004 23:53:12 -0000	1.35
+++ generic/tkCmds.c	27 Apr 2005 11:43:14 -0000
@@ -619,11 +619,11 @@
     Tk_Window tkwin;
     static CONST char *optionStrings[] = {
 	"appname",	"caret",	"scaling",	"useinputmethods",
-	"windowingsystem",		NULL
+	"windowingsystem",		"inactive",	NULL
     };
     enum options {
 	TK_APPNAME,	TK_CARET,	TK_SCALING,	TK_USE_IM,
-	TK_WINDOWINGSYSTEM
+	TK_WINDOWINGSYSTEM,		TK_INACTIVE
     };
 
     tkwin = (Tk_Window) clientData;
@@ -846,6 +846,47 @@
 	    Tcl_SetStringObj(Tcl_GetObjResult(interp), windowingsystem, -1);
 	    break;
 	}
+        case TK_INACTIVE: {
+	    int skip;
+	    
+	    skip = TkGetDisplayOf(interp, objc - 2, objv + 2, &tkwin);
+	    if (skip < 0) {
+		 return TCL_ERROR;
+	    }
+	    if (objc - skip == 2) {
+		long inactive;
+
+		inactive = (Tcl_IsSafe(interp) ? -1 :
+			    Tk_GetUserInactiveTime(Tk_Display(tkwin)));
+		Tcl_SetObjResult(interp, Tcl_NewLongObj(inactive));
+
+	    } else if (objc - skip == 3) {
+		char *string;
+
+		string = Tcl_GetStringFromObj(objv[objc-1], NULL);
+		if (strcmp(string, "reset") != 0) {
+		    Tcl_Obj *msg = Tcl_NewStringObj("bad option \"", -1);
+		    Tcl_AppendStringsToObj(msg, string,
+					   "\": must be reset", NULL);
+		    Tcl_SetObjResult(interp, msg);
+		    return TCL_ERROR;
+		}
+		if (Tcl_IsSafe(interp)) {
+		    Tcl_SetResult(interp,
+				  "resetting the user inactivity timer "
+				  "is not allowed in a safe interpreter",
+				  TCL_STATIC);
+		    return TCL_ERROR;
+		}
+		Tk_ResetUserInactiveTime(Tk_Display(tkwin));
+		Tcl_ResetResult(interp);
+	    } else {
+		Tcl_WrongNumArgs(interp, 2, objv,
+				 "?-displayof window? ?reset?");
+		return TCL_ERROR;
+	    }
+	    break;
+	}
     }
     return TCL_OK;
 }
Index: macosx/tkMacOSXXStubs.c
===================================================================
RCS file: /cvsroot/tktoolkit/tk/macosx/tkMacOSXXStubs.c,v
retrieving revision 1.7
diff -u -r1.7 tkMacOSXXStubs.c
--- macosx/tkMacOSXXStubs.c	13 Nov 2004 03:41:47 -0000	1.7
+++ macosx/tkMacOSXXStubs.c	27 Apr 2005 11:43:14 -0000
@@ -30,6 +30,8 @@
 #include "tkPort.h"
 #include "tkMacOSXEvent.h"
 
+#include <IOKit/IOKitLib.h>
+
 /*
  * Because this file is still under major development Debugger statements are
  * used through out this file.  The define TCL_DEBUG will decide whether
@@ -963,3 +965,98 @@
 #endif
     return macScreenName;
 }
+
+/*
+ *----------------------------------------------------------------------
+ * 
+ * Tk_GetUserInactiveTime --
+ *
+ *	Return the number of milliseconds the user was inactive.
+ *
+ * Results:
+ *	The number of milliseconds the user has been inactive,
+ *	or -1 if querying the inactive time is not supported.
+ *
+ * Side effects:
+ *	None.
+ *----------------------------------------------------------------------
+ */
+
+long
+Tk_GetUserInactiveTime(Display *dpy)
+{
+    io_registry_entry_t regEntry;
+    CFMutableDictionaryRef props = NULL;
+    CFTypeRef timeObj;
+    long ret = -1l;
+    uint64_t time;
+
+    regEntry = IOServiceGetMatchingService(kIOMasterPortDefault,
+	    IOServiceMatching("IOHIDSystem"));
+
+    if (regEntry == NULL) {
+	return -1l;
+    }
+
+    IOReturn result = IORegistryEntryCreateCFProperties(regEntry, &props,
+	    kCFAllocatorDefault, 0);
+    IOObjectRelease(regEntry);
+
+    if (result != KERN_SUCCESS || props == NULL) {
+	return -1l;
+    }
+
+    timeObj = CFDictionaryGetValue(props, CFSTR("HIDIdleTime"));
+
+    if (timeObj) {
+	CFRetain(timeObj);
+	CFTypeID type = CFGetTypeID(timeObj);
+
+	if (type == CFDataGetTypeID()) { /* Jaguar */
+	    CFDataGetBytes((CFDataRef) timeObj,
+		CFRangeMake(0, sizeof(time)),
+		(UInt8 *) &time);
+	    /* Convert nanoseconds to milliseconds. */
+	    //ret /= kMillisecondScale;
+	    ret = (long)(time/kMillisecondScale);
+	} else if (type == CFNumberGetTypeID()) { /* Panther+ */
+	    CFNumberGetValue((CFNumberRef)timeObj,
+		kCFNumberSInt64Type,
+		&time);
+	    /* Convert nanoseconds to milliseconds. */
+	    //ret /= kMillisecondScale;
+	    ret = (long)(time/kMillisecondScale);
+	} else {
+	    ret = -1l;
+	}
+
+	CFRelease(timeObj);
+    }
+    /* Cleanup */
+    CFRelease(props);
+
+    return ret;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tk_ResetUserInactiveTime --
+ *
+ *	Reset the user inactivity timer
+ *
+ * Results:
+ *	none
+ *
+ * Side effects:
+ *	The user inactivity timer of the underlaying windowing system
+ *	is reset to zero.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+Tk_ResetUserInactiveTime(Display *dpy)
+{
+    UpdateSystemActivity(0);
+}
Index: macosx/Wish.pbproj/project.pbxproj
===================================================================
RCS file: /cvsroot/tktoolkit/tk/macosx/Wish.pbproj/project.pbxproj,v
retrieving revision 1.38
diff -u -r1.38 project.pbxproj
--- macosx/Wish.pbproj/project.pbxproj	9 Apr 2005 11:19:00 -0000	1.38
+++ macosx/Wish.pbproj/project.pbxproj	27 Apr 2005 11:43:15 -0000
@@ -101,6 +101,36 @@
 //4C2
 //4C3
 //4C4
+//950
+//951
+//952
+//953
+//954
+		95911CC7081532D8006F6BCB = {
+			isa = PBXFileReference;
+			lastKnownFileType = wrapper.framework;
+			name = IOKit.framework;
+			path = /System/Library/Frameworks/IOKit.framework;
+			refType = 0;
+			sourceTree = "<absolute>";
+		};
+		95911CC8081532D8006F6BCB = {
+			fileRef = 95911CC7081532D8006F6BCB;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
+		95911CC9081532D8006F6BCB = {
+			fileRef = 95911CC7081532D8006F6BCB;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
+//950
+//951
+//952
+//953
+//954
 //F50
 //F51
 //F52
@@ -2175,6 +2205,7 @@
 				F51D903E0181474301DC9062,
 				F537567E016C3ADB01DC9062,
 				F50D96130196176E01DC9062,
+				95911CC9081532D8006F6BCB,
 			);
 			isa = PBXFrameworksBuildPhase;
 			runOnlyForDeploymentPostprocessing = 0;
@@ -3083,6 +3114,7 @@
 		};
 		F537567C016C3ADB01DC9062 = {
 			children = (
+				95911CC7081532D8006F6BCB,
 				F50D96120196176E01DC9062,
 				F5875C7B016FEF1D01DC9062,
 				F537567D016C3ADB01DC9062,
@@ -3435,6 +3467,7 @@
 				F53756A7016C4DD401DC9062,
 				F50D96140196176E01DC9062,
 				F5877FB9031F9F49016F146B,
+				95911CC8081532D8006F6BCB,
 			);
 			isa = PBXFrameworksBuildPhase;
 			runOnlyForDeploymentPostprocessing = 0;
Index: unix/configure.in
===================================================================
RCS file: /cvsroot/tktoolkit/tk/unix/configure.in,v
retrieving revision 1.99
diff -u -r1.99 configure.in
--- unix/configure.in	10 Jan 2005 18:57:41 -0000	1.99
+++ unix/configure.in	27 Apr 2005 11:43:15 -0000
@@ -283,6 +283,29 @@
 fi
 
 #--------------------------------------------------------------------
+# Check whether the header and library for the XScreenSaver
+# extension are available, and set HAVE_XSS if so.
+# XScreenSaver is needed for Tk_GetUserInactiveTime().
+#--------------------------------------------------------------------
+AC_MSG_CHECKING([for XScreenSaver support])
+tk_oldCFlags=$CFLAGS
+CFLAGS="$CFLAGS $XINCLUDES"
+tk_oldLibs=$LIBS
+LIBS="$LIBS $XLIBSW -lXss -lXext"
+AC_TRY_LINK([
+#include <X11/Xlib.h>
+#include <X11/extensions/scrnsaver.h>
+] , [
+XScreenSaverAllocInfo();
+], [
+AC_MSG_RESULT(yes)
+XLIBSW="$XLIBSW -lXss -lXext"
+AC_DEFINE([HAVE_XSS])
+], AC_MSG_RESULT(no))
+CFLAGS=$tk_oldCFlags
+LIBS=$tk_oldLibs
+
+#--------------------------------------------------------------------
 #	Check for freetype / fontconfig / Xft support.
 #--------------------------------------------------------------------
 
Index: unix/tkUnix.c
===================================================================
RCS file: /cvsroot/tktoolkit/tk/unix/tkUnix.c,v
retrieving revision 1.6
diff -u -r1.6 tkUnix.c
--- unix/tkUnix.c	26 Oct 2004 13:15:09 -0000	1.6
+++ unix/tkUnix.c	27 Apr 2005 11:43:15 -0000
@@ -14,6 +14,9 @@
  */
 
 #include <tkInt.h>
+#ifdef HAVE_XSS
+#include <X11/extensions/scrnsaver.h>
+#endif
 
 /*
  *----------------------------------------------------------------------
@@ -165,3 +168,65 @@
 	dataPtr += lineStride;
     }
 }
+
+/*
+ *----------------------------------------------------------------------
+ * 
+ * Tk_GetUserInactiveTime --
+ *
+ *	Return the number of milliseconds the user was inactive.
+ *
+ * Results:
+ *	The number of milliseconds since the user's latest interaction
+ *	with the system on the given display, or -1 if the
+ *	XScreenSaver extension is not supported by the client
+ *	libraries or the X server implementation.
+ *
+ * Side effects:
+ *	None.
+ *----------------------------------------------------------------------
+ */
+
+long
+Tk_GetUserInactiveTime(dpy)
+     Display *dpy;	/* The display for which to query the inactive time */
+{
+    long inactivetime = -1;
+#ifdef HAVE_XSS
+    int event_base;
+    int error_base;
+
+    if (XScreenSaverQueryExtension(dpy, &event_base, &error_base)) {
+	XScreenSaverInfo *info;
+	info = XScreenSaverAllocInfo();
+	XScreenSaverQueryInfo(dpy, DefaultRootWindow(dpy), info);
+	inactivetime = info->idle;
+	XFree(info);
+    }
+#endif /* HAVE_XSS */
+    return inactivetime;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tk_ResetUserInactiveTime --
+ *
+ *	Reset the user inactivity timer
+ *
+ * Results:
+ *	none
+ *
+ * Side effects:
+ *	The user inactivity timer of the underlaying windowing system
+ *	is reset to zero.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+Tk_ResetUserInactiveTime(dpy)
+     Display *dpy;
+{
+    XResetScreenSaver(dpy);
+}
Index: win/tkWinX.c
===================================================================
RCS file: /cvsroot/tktoolkit/tk/win/tkWinX.c,v
retrieving revision 1.45
diff -u -r1.45 tkWinX.c
--- win/tkWinX.c	4 Mar 2005 01:13:03 -0000	1.45
+++ win/tkWinX.c	27 Apr 2005 11:43:15 -0000
@@ -13,6 +13,14 @@
  * RCS: @(#) $Id: tkWinX.c,v 1.45 2005/03/04 01:13:03 hobbs Exp $
  */
 
+/*
+ * Make sure the SendInput API is available:
+ */
+#if (_WIN32_WINNT <= 0x0400)
+#undef _WIN32_WINNT
+#define _WIN32_WINNT 0x0401
+#endif
+
 #include "tkWinInt.h"
 
 /*
@@ -1837,3 +1845,84 @@
 	}
     }
 }
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tk_GetUserInactiveTime --
+ *
+ *	Return the number of milliseconds the user was inactive.
+ *
+ * Results:
+ *	Milliseconds of user inactive time or -1 if the user32.dll doesn't
+ *	have the symbol GetLastInputInfo or GetLastInputInfo returns an
+ *	error.
+ *
+ * Side effects:
+ *	None.
+ *----------------------------------------------------------------------
+ */
+
+long
+Tk_GetUserInactiveTime(dpy)
+     Display *dpy;            /* Ignored on Windows */
+{
+    struct tagLASTINPUTINFO {
+	UINT cbSize;
+	DWORD dwTime;
+    } li;
+    static FARPROC pfnGetLastInputInfo = NULL;
+    static int initinfo = 0;
+    
+    if (!initinfo) {
+	HMODULE hMod = GetModuleHandleA("USER32.DLL");
+	initinfo = 1;
+	if (hMod){
+	    pfnGetLastInputInfo =
+		GetProcAddress(hMod, "GetLastInputInfo");
+        }
+    }
+    if (pfnGetLastInputInfo == NULL) {
+	return -1;
+    }
+    li.cbSize = sizeof(li);
+    if ( !(BOOL)(pfnGetLastInputInfo)(&li) ) {
+	return -1;
+    }
+    /* last input info is in milliseconds, since restart time. */
+    return (GetTickCount()-li.dwTime);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tk_ResetUserInactiveTime --
+ *
+ *	Reset the user inactivity timer
+ *
+ * Results:
+ *	none
+ *
+ * Side effects:
+ *	The user inactivity timer of the underlaying windowing system
+ *	is reset to zero.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+Tk_ResetUserInactiveTime(dpy)
+    Display *dpy;
+{
+    INPUT inp;
+    
+    inp.type=INPUT_MOUSE;
+    inp.mi.dx=0;
+    inp.mi.dy=0;
+    inp.mi.mouseData=0;
+    inp.mi.dwFlags=MOUSEEVENTF_MOVE;
+    inp.mi.time=0;
+    inp.mi.dwExtraInfo=NULL;
+    
+    SendInput(1, &inp, sizeof(inp));
+}
