Tk Source Code

View Ticket
Login
Ticket UUID: 3531366
Title: Cursor blink cannot be switched off in ttk widgets
Type: Bug Version: 8.6.10
Submitter: Created on: 2012-06-01 16:11:28
Subsystem: 88. Themed Tk Assigned To: fvogel
Priority: 6 Severity: Minor
Status: Closed Last Modified: 2023-07-08 13:20:40
Resolution: Fixed Closed By: fvogel
    Closed on: 2023-07-08 13:20:40
Description:
The ttk text entry widgets (e.g., ttk::entry, ttk::combobox) do not support the -insertOffTime option so it is not possible to stop cursor blink.

Using non-ttk widgets it is possible to stop cursor blink by putting *insertOffTime: 0 in the .Xdefaults file; but there doesn't appear to be any way to do this for the ttk widgets.

The problem appears in file generic/ttk/ttkBlink.c which has a TODO on this topic.
User Comments: fvogel added on 2023-07-08 13:20:40:

With [d0a86f93] users can now override on and off default times with values obtained from the option database (if such values are specified). Now merged.

I'm adding a post-vote note to TIP #675 recording this.


fvogel added on 2023-07-01 12:10:10:

TIP #675 now merged into trunk.

Users can now adjust the blink time in Ttk widgets through:

ttk::style configure . -insertofftime $ontime_ms -insertontime $offtime_ms

Switching blinkin off is obtained through:

ttk::style configure . -insertofftime 0

I'll now have a look at finding a way to initialize blink on/off times by values that can be found in the options database, as proposed during the vote on TIP #675.


bll added on 2023-06-13 20:00:22:
You could always ship the linux cursorblink.tcl code in a not-maintained/ directory.

Then it can be up to the user to copy it to $HOME/.config/tk/ (and update the code to check there instead of whatever path it is using now).

fvogel added on 2023-06-13 19:44:56:

For the records, see also discussion in [1dc430ad59] about using the system settings.


fvogel added on 2023-06-12 22:59:33:

Implementation improved in the tip-675 branch (which is the same as branch bug-3531366fff).

I have written TIP #675 for this. Comments welcome.


fvogel added on 2023-06-11 09:56:44:

Patch committed in branch bug-3531366fff, see [517df9a7d1]. Will work on this more, the patch works but is only really a quick and dirty thing.


fvogel added on 2023-06-08 20:54:55:

I'm attaching a quick patch allowing to set the off time of Ttk cursors (application-wide), through a style default. This is just a proof of concept, not at all a full-fledged thing but it works.

Demo:

package require Tk
pack [ttk::entry .ee]    ; # cursor blinks
focus -force .ee         ; # see cursor blinking
ttk::style configure . -insertofftime 0  ; # stop cursor blink


mnsummerfield added on 2023-06-06 18:32:42:
Perhaps the problem with these patches is that they are too ambitious.
Why not simply read the existing insertOffTime value and use that. This way blinking will be on and at the same rate as for non-themed widgets (so most people won't notice any difference). But for those who can't work with blinking cursors and who specifically set insertOffTime to 0 it will "just work". No need to work out the platform defaults and automate it all, and which won't be as robust as just using the existing insertOffTime value.

mnsummerfield added on 2023-06-06 18:05:31:
Applying the patches myself isn't pratical. I'd have to do it for every single Tk release and I'd be out of sync with the official released version.
I've tried changing the Resolution from Fixed (since it isn't) to Remind.

bll added on 2023-06-06 16:09:53:
The attached patches retrieve the cursor blink settings from the system, and there is no implementation of "insertOffTime" within these patches, as it's not really needed.  

I do not know if any other work has been done to implement "insertOffTime".

These patches have been sitting here for two years and none of the main developers have added them to the base code.  The resolution of this ticket seems incorrect.

My recommendation is to make a collection of good patches, apply them to Tk and build Tk yourself.  This is a lot of work.

mnsummerfield added on 2023-06-06 15:05:50:
My understanding was that Tcl/Tk >=8.7 would respect the users cursor blinking preferences.

But running this program (with or without the `option add` line) has an entry (presumably a ttk::entry) with a blinking cursor:

#!/usr/bin/env wish
option add *insertOffTime 0
set filename [tk_getOpenFile]
puts $filename
exit 

I have tested this on Debian 11 using Xfce with Tcl v8.7a5/Tk v8.7 and Tcl v9.0a3/Tk v8.7.

bll added on 2021-06-09 14:34:35:
Attached patch for version 8.7

bll added on 2020-12-22 18:13:53:
Attached patch file for 8.6.11

fvogel added on 2020-10-07 19:41:27:
> Fran├žois: Assigning for review.

Sorry, may I defer to someone else on this one please? Jan, perhaps?

bll added on 2020-10-07 14:49:33:
It appears that for Linux and many of the systems, the cursor off-time is
calculated or hard-coded.  Having a setting of 1200ms on Linux has an on-time
of 1200ms, but the off-time is much shorter.

I suppose the off time could be calculated 
to get a closer match to what the system does.

bll added on 2020-10-06 15:42:03:
Fran├žois: Assigning for review.

Files modified: 
  generic/ttk/ttkBlink.c
  generic/tkIntPlatDecls.h
  win/tkWinCursor.c
  macosx/tkMacOSXCursor.c
  unix/tkUnixCursor.c
New files:
  library/ttk/cursorblink.tcl    # helper routine for unix

No new functionality is introduced.
The current cursor settings are retrieved from the system.
This is easy on Windows and Mac OS. 
For unix it is much more difficult due to the plethora of desktop managers.

I use a cursor off period of zero to indicate no blinking for Tk.
ttkBlink.c must handle this setting itself, as the Tcl_CreateTimerHandler
does not work with a timer of zero ms.

On Mac OS, to change the cursor to non-blinking:
  defaults write -g NSTextInsertionPointBlinkPeriodOn 9999999
  defaults write -g NSTextInsertionPointBlinkPeriodOff 1
This seems to work.  A setting of zero for the off period does not work.
To reset:
  defaults delete -g NSTextInsertionPointBlinkPeriodOn
  defaults delete -g NSTextInsertionPointBlinkPeriodOff
Mac OS defaults are unknown, if NSTextInsertionPointBlinkPeriodOn/Off is not
set, the Tk defaults are used.

On Windows: 
  Control Panel / Keyboard / Cursor Blink Rate
Windows 10:
  Settings / Search for: Blink

Unix varies by desktop manager:
I have many of these installed, if you outline a test to try, I can
run it and let you know the results.

Doing this for unix introduces some overhead.  As the cursor initialization
happens once only, I decided that the overhead was worthwhile.

And this browser's cursor is stuck with a 100ms/100ms timer right now, and
it's driving me crazy.

bll added on 2020-10-05 14:43:56:
My current thinking is that the X11 code could be populated to use the attached
script (cursorblink.tcl). 

- The cursorblink.tcl script must be installed in a place where it can 
  be located.
- Tcl is already available, so there's no extra load time for tclsh.
- The script must be sourced, so there is:
  - stat() to check to make sure the file is available 
  - source the script (which is an open() and read and parse and close() ).
  - run the procedure and get the data.
    ( Is it easier to get the return value or use global variables? )
    Executing the procedure involves running one to two external programs
    to fetch the information from the system.

Some overhead.

bll added on 2020-10-02 18:58:57:
Implementation of system blink time retrieval in bug-3531366 .

It appears that the initialization of the cursor is only run once, so 
implementing a unix version of the code is possible.  

But the unix version would be very expensive, requiring checks to see
which window manager is in use, and possibly two to three executions of external
programs to retrieve the blink settings from the window manager.

Note that Mac OS defaults are unknown, and retrieval is only possible if the
blink on/off time is set.

bll added on 2020-09-30 19:49:29:
Well, I'm wrong about Linux.  I can fetch xfce settings from dbus, but it
does not appear that gnome publishes the gnome settings in dbus.

I suppose a little script could be run one time only at startup:
  if (xfce)
    xfconf-query ...
  if (gnome)
    gsettings get ...
  if (kde)
    no-idea-how-kde-does-it
That's rather expensive though.

bll added on 2020-09-30 16:04:36:
Could create a helper routine:
This is for windows:

#include <stdio.h>
#include <stdlib.h>
#include <windows.h>

int
TkpCursorBlinkEnabled ()
{
    HKEY hKey;
    LPCWSTR szSubKey = L"Control Panel\\Desktop";
    LPCWSTR szCursorBlink = L"CursorBlinkRate";
    DWORD dwSize = 40;
    wchar_t lBuffer[40];
    char pBuffer[40];
    int rc;
    size_t ccount = 0;
    LSTATUS status;

    rc = 1;
    status =  RegOpenKeyExW (HKEY_CURRENT_USER, szSubKey, 0L, KEY_READ, &hKey);
    if (status == ERROR_SUCCESS) {
      status = RegQueryValueExW (hKey, szCursorBlink, NULL, NULL, (LPBYTE) lBuffer, &dwSize);
      wcstombs_s (&ccount, pBuffer, (wcslen(lBuffer)+1)*2, lBuffer, _TRUNCATE);
      printf ("v-status: %d\n", status);
      RegCloseKey(hKey);
      if (strcmp (pBuffer, "-1") == 0) {
         rc = 0;
      }
    } else {
       printf ("status: %d\n", status);
    }
    return rc;
}

int
main (int argc, char *argv []) {
    int rc = TkpCursorBlinkEnabled ();
    printf ("rc=%d\n", rc);
}

bll added on 2020-09-30 14:55:32:
Linux has a bazillion desktop managers.
When using the popular desktop managers, these settings should be accessible
via dbus.

XFCE / xfconf-query :

xfconf-query -c xsettings -p /Net/CursorBlinkTime # time
xfconf-query -c xsettings -p /Net/CursorBlink  # true/false

gnome and variants / gsettings : 

$ gsettings list-keys org.gnome.desktop.interface | grep blink
cursor-blink-timeout
cursor-blink-time
cursor-blink

$ gsettings get org.gnome.desktop.interface cursor-blink-timeout
10
$ gsettings get org.gnome.desktop.interface cursor-blink-time
1200
$ gsettings get org.gnome.desktop.interface cursor-blink
true

bll added on 2020-09-30 14:37:59:
On Mac OS:

defaults write -g NSTextInsertionPointBlinkPeriodOn -float 200
defaults write -g NSTextInsertionPointBlinkPeriodOff -float 200
defaults delete -g NSTextInsertionPointBlinkPeriodOn # to reset
defaults delete -g NSTextInsertionPointBlinkPeriodOff # to reset

These are not set if the defaults are in use.

bll added on 2020-09-30 14:30:30:
On Windows:

Computer\HKEY_CURRENT_USER\Control Panel\Desktop\CursorBlinkRate

-1 turns off the blink.
Ranges from 1200 (slow) to 200 (fast).
On/Off times appear to be the same.

bll added on 2020-09-30 14:18:51:
Or I suppose it could be added to the option database (yuck!).

bll added on 2020-09-30 14:05:10:
Another request for this:

https://groups.google.com/d/topic/comp.lang.tcl/l-z45mITv60/discussion

possibilities:
1) Introduce a 'ttk' command
2) As suggested, a ttk specific parameter to the 'tk' command.
3) Use: ttk::style configure . -insertofftime 0
   just like all of the other defaults that ttk uses.
   But a change in style reverts the setting.

fvogel added on 2019-05-04 07:31:17:

Hmmm...

ttkBlink.c implements an application-wide cursor blinking scheme, not a widget-specific one: GetCursorManager() is called with corePtr->interp. And GetCursorManager() associates a single key "ttk::CursorManager" with a pointer on a CursorManager resource that is shared among everything known by the interp. There is no specific cursor blinking scheme at the ttk widget level, therefore the approach I proposed below is not good (it would control all cursor blinkings by controlling any of them in a specific ttk widget -> clumsy and inappropriate).

So we need a proper way to control the ttk app-wide cursor blinking scheme. In Tk the "tk" command would be appropriate for these kind of things, but what is the equivalent in ttk?

Should we add, say, "tk ttkinsertofftime ?value?" and "tk ttkinsertontime ?value?" ?


fvogel added on 2019-05-03 21:46:05:
This feature looks rather straightforward to add in the implementation at the widget level, that is adding an -insertofftime / -insertontime option in the ttk::entry, ttk::spinbox and ttk::combobox widgets.

Then the option database (or .Xdefaults file) containing *insertOffTime: 0 would apply this to all Ttk widgets in addition to the Tk widgets (I think - needs to be tested, any thoughts?).

I don't believe this should be a style property: users wanting to switch blinking off need this feature independently of the style of their choice.

fvogel added on 2017-04-04 20:39:41:

[c7046ba187] is a duplicate of this ticket.


dkf added on 2012-06-06 04:05:06:
The fact that it's got a TODO would be a fair indication that fixing this ought to be done. Don't know if it should be a style property or not...

added on 2012-06-06 00:24:23:
I thought I'd add some rationale. First is that this functionality has been supported for years using insertOffTime for non-themed widgets. Second, even Microsoft finally recognized that some users cannot use software with blinking cursors and since Windows 2000 have provided a system-wide setting to switch off cursor blink. (And which the ttk widgets do not respect.) Apple have not been so considerate. For more about cursor blinking see for example: http://www.jurta.org/en/prog/noblink
I know that most people really like cursor blink since it helps them locate where they are. But a significant minority cannot work with blinking cursors. So I really hope you'll once more allow Tk to respect user preferences (just as you do for colors and fonts) with regard blinking.

Attachments: