GNU bug report logs - #80993
[PATCH] Add support for tty scroll-bars

Please note: This is a static page, with minimal formatting, updated once a day.
Click here to see this page with the latest information and nicer formatting.

Package: emacs; Reported by: Michael Grant <mgrant@HIDDEN>; Keywords: patch; dated Fri, 8 May 2026 15:02:01 UTC; Maintainer for emacs is bug-gnu-emacs@HIDDEN.

Message received at 80993 <at> debbugs.gnu.org:


Received: (at 80993) by debbugs.gnu.org; 26 Jun 2026 11:24:03 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Fri Jun 26 07:24:02 2026
Received: from localhost ([127.0.0.1]:42176 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1wd4f9-0007FN-A6
	for submit <at> debbugs.gnu.org; Fri, 26 Jun 2026 07:24:02 -0400
Received: from eggs.gnu.org ([2001:470:142:3::10]:55850)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <eliz@HIDDEN>) id 1wd4f2-0007EC-DT
 for 80993 <at> debbugs.gnu.org; Fri, 26 Jun 2026 07:23:54 -0400
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <eliz@HIDDEN>)
 id 1wd4eu-0000Ab-FY; Fri, 26 Jun 2026 07:23:44 -0400
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=References:Subject:In-Reply-To:To:From:Date:
 mime-version; bh=zzrzzD8KhqR1Gssrc4VU54ZoEb8L7uv8OOCSfOPoQFs=; b=pFYAS3Xqp585
 qgMFlwVnSEfhUPriPN7MaxYyF8FijZaCTkJPToFBf+sZ9hrDP6xH8A/pKF2pCZ5Zv5rU6Kh+XIBN3
 QeHm+9cNv2uk9KkBvFP0X96ipVASK0hksLaomwaXJjiIEYzXqOKxZk/bDGDS0qTr59nL+YxacwpT+
 9ZIR5JDDufwOv6VQzKqZYSgO0XoNYcXYLLuSWUCueNA9eHqw4c0WkaMIhcWVWsRFwHenv0mz8PvVN
 YTPwgmSGhpSngkS0XEBA+AYrBdmeE8+v6yIoIn5+KZ0gxbfgllFjydY1DUoTVPezeEmrXxX/xw4of
 dq1SpZPsHYi24GM0B0dm+Q==;
Date: Fri, 26 Jun 2026 14:23:41 +0300
Message-Id: <86echtk0jm.fsf@HIDDEN>
From: Eli Zaretskii <eliz@HIDDEN>
To: "Michael Grant" <mgrant@HIDDEN>
In-Reply-To: <em4d86af88-748b-47d4-bac1-f0f69cc81c1b@HIDDEN>
 (mgrant@HIDDEN)
Subject: Re: bug#80993: [PATCH] Add support for tty scroll-bars
References: <af36i-emhv7cCESf@HIDDEN> <86cxyv660l.fsf@HIDDEN>
 <fe8b6d3d49ec4eb84acd8b17f164d199@HIDDEN>
 <em3c57e5aa-5711-4cdb-bea6-7d4d0fdb192e@HIDDEN> <86y0g3kuk3.fsf@HIDDEN>
 <ema77cdde2-3c43-44a3-9dfa-cf9b4596808d@HIDDEN> <86mrwjkohe.fsf@HIDDEN>
 <em84d0f793-d18c-4a7c-b86a-2f4052ce0cfe@HIDDEN>
 <ce79d9817d3e609dcb26a53f3c39e967@HIDDEN> <86h5mpkd9e.fsf@HIDDEN>
 <em4d86af88-748b-47d4-bac1-f0f69cc81c1b@HIDDEN>
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 80993
Cc: 80993 <at> debbugs.gnu.org, jared@HIDDEN
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

> From: "Michael Grant" <mgrant@HIDDEN>
> Cc: 80993 <at> debbugs.gnu.org
> Date: Fri, 26 Jun 2026 08:28:10 +0000
> X-Spam-Status: No, score=-99.0 required=5.0 autolearn=disabled
> 
> >I think using inverse-video for the scroll-bar face on TTY frames will
> >do well enough, without a need for doing what vertical-border does
> >(which consumes yet another glyph, if that's what you meant).
> >
> >Anyway, I think we've bike-shedded enough about this.  I think we all
> >agree that we should use the scroll-bar face for showing the scroll
> >bar on TTYs, so let's do that, and leave any fine-tuning of that face
> >for TTYs for later.  After all, it's a minor issue, with little or no
> >effect on the rest of the implementation.
> >
> Agreed.  inheriting inverse-video looks absolutely fine, both the gutter 
> and thumb show well.
> 
> We are doing some clean-up and a final review, there are updates needed 
> in the docs, will post that separetly after, let me post the heavy 
> lifted stuff.  Maybe later today or tomorrow.  sorry this takes so long, 
> i don't want to inundate you with version after version.

No need to apologize, there's no rush.




Information forwarded to bug-gnu-emacs@HIDDEN:
bug#80993; Package emacs. Full text available.

Message received at 80993 <at> debbugs.gnu.org:


Received: (at 80993) by debbugs.gnu.org; 26 Jun 2026 08:28:36 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Fri Jun 26 04:28:35 2026
Received: from localhost ([127.0.0.1]:41850 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1wd1vN-0005ly-Jk
	for submit <at> debbugs.gnu.org; Fri, 26 Jun 2026 04:28:35 -0400
Received: from strange.networkguild.org ([2600:3c02:e000:dd::1]:55929)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <mgrant@HIDDEN>) id 1wd1vH-0005kf-ON
 for 80993 <at> debbugs.gnu.org; Fri, 26 Jun 2026 04:28:30 -0400
Received: from auth (localhost [127.0.0.1]) (authenticated bits=0)
 by strange.networkguild.org (8.18.1/8.18.1/Debian-6) with ESMTPSA id
 65Q8SCWj505384
 (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384 bits=256 verify=NOT);
 Fri, 26 Jun 2026 04:28:19 -0400
From: "Michael Grant" <mgrant@HIDDEN>
To: "Eli Zaretskii" <eliz@HIDDEN>, "Jared Finder" <jared@HIDDEN>
Subject: Re[2]: bug#80993: [PATCH] Add support for tty scroll-bars
Date: Fri, 26 Jun 2026 08:28:10 +0000
Message-Id: <em4d86af88-748b-47d4-bac1-f0f69cc81c1b@HIDDEN>
In-Reply-To: <86h5mpkd9e.fsf@HIDDEN>
References: <af36i-emhv7cCESf@HIDDEN> <86cxyv660l.fsf@HIDDEN>
 <fe8b6d3d49ec4eb84acd8b17f164d199@HIDDEN>
 <em3c57e5aa-5711-4cdb-bea6-7d4d0fdb192e@HIDDEN> <86y0g3kuk3.fsf@HIDDEN>
 <ema77cdde2-3c43-44a3-9dfa-cf9b4596808d@HIDDEN> <86mrwjkohe.fsf@HIDDEN>
 <em84d0f793-d18c-4a7c-b86a-2f4052ce0cfe@HIDDEN>
 <ce79d9817d3e609dcb26a53f3c39e967@HIDDEN> <86h5mpkd9e.fsf@HIDDEN>
User-Agent: eMClient/10.4.0.0
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8; format=flowed
Content-Transfer-Encoding: quoted-printable
X-Virus-Scanned: clamav-milter 1.4.3 at strange.networkguild.org
X-Virus-Status: Clean
X-Spam-Status: No, score=-99.0 required=5.0 autolearn=disabled
X-Spam-Report: *  -99 ALL_TRUSTED Passed through trusted hosts only via SMTP
X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-25) on
 strange.networkguild.org
X-Spam-Score: -0.0 (/)
X-Debbugs-Envelope-To: 80993
Cc: 80993 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Reply-To: Michael Grant <mgrant@HIDDEN>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)

>I think using inverse-video for the scroll-bar face on TTY frames will
>do well enough, without a need for doing what vertical-border does
>(which consumes yet another glyph, if that's what you meant).
>
>Anyway, I think we've bike-shedded enough about this.  I think we all
>agree that we should use the scroll-bar face for showing the scroll
>bar on TTYs, so let's do that, and leave any fine-tuning of that face
>for TTYs for later.  After all, it's a minor issue, with little or no
>effect on the rest of the implementation.
>
Agreed.  inheriting inverse-video looks absolutely fine, both the gutter=20
and thumb show well.

We are doing some clean-up and a final review, there are updates needed=20
in the docs, will post that separetly after, let me post the heavy=20
lifted stuff.  Maybe later today or tomorrow.  sorry this takes so long,=20
i don't want to inundate you with version after version.




Information forwarded to bug-gnu-emacs@HIDDEN:
bug#80993; Package emacs. Full text available.

Message received at 80993 <at> debbugs.gnu.org:


Received: (at 80993) by debbugs.gnu.org; 26 Jun 2026 06:49:13 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Fri Jun 26 02:49:13 2026
Received: from localhost ([127.0.0.1]:41206 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1wd0NE-00065w-Gz
	for submit <at> debbugs.gnu.org; Fri, 26 Jun 2026 02:49:13 -0400
Received: from eggs.gnu.org ([2001:470:142:3::10]:49364)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <eliz@HIDDEN>) id 1wd0NC-00065V-Ki
 for 80993 <at> debbugs.gnu.org; Fri, 26 Jun 2026 02:49:11 -0400
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <eliz@HIDDEN>)
 id 1wd0N5-0005zf-HF; Fri, 26 Jun 2026 02:49:03 -0400
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=References:Subject:In-Reply-To:To:From:Date:
 mime-version; bh=4OQKwtv7PcqV+HrkD/JhOr+XoAozDKBrVIAPm2w27xQ=; b=HCdjyGfTCg7o
 5fx4jiiYrO/rf7LbA3hdlYX4X9VZwRgME5LOv3/NT0MK1AzusdBOQyt0LKuBaX3yGqCA2tfuVSyph
 vcl/c3EOjpUT0+ysFpLixipuvTPZr8gmYGgGNWWfeyKXGQvu/+2/VEqqedE+u1thdVgIytQFwjpbD
 ydMdikSOwB4Hz/YmbzuFMIllXvd+m6VZgSz5617toG1qr12p2M1jz1EzEO9RsPYepu/y8YbclpbpU
 WvTYjmrqjy0BAnWDm17iUf4HL/wMuzNK2Bk1ABLg/zjIJl3KHLSJu/nCgRfLkMqxC43SMpJxng6UC
 JLaaxPJTtVQid0+EszoUyg==;
Date: Fri, 26 Jun 2026 09:49:01 +0300
Message-Id: <86h5mpkd9e.fsf@HIDDEN>
From: Eli Zaretskii <eliz@HIDDEN>
To: Jared Finder <jared@HIDDEN>
In-Reply-To: <ce79d9817d3e609dcb26a53f3c39e967@HIDDEN> (message from Jared
 Finder on Thu, 25 Jun 2026 20:48:17 -0700)
Subject: Re: bug#80993: [PATCH] Add support for tty scroll-bars
References: <af36i-emhv7cCESf@HIDDEN> <86cxyv660l.fsf@HIDDEN>
 <fe8b6d3d49ec4eb84acd8b17f164d199@HIDDEN>
 <em3c57e5aa-5711-4cdb-bea6-7d4d0fdb192e@HIDDEN> <86y0g3kuk3.fsf@HIDDEN>
 <ema77cdde2-3c43-44a3-9dfa-cf9b4596808d@HIDDEN> <86mrwjkohe.fsf@HIDDEN>
 <em84d0f793-d18c-4a7c-b86a-2f4052ce0cfe@HIDDEN>
 <ce79d9817d3e609dcb26a53f3c39e967@HIDDEN>
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 80993
Cc: 80993 <at> debbugs.gnu.org, mgrant@HIDDEN
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

> Date: Thu, 25 Jun 2026 20:48:17 -0700
> From: Jared Finder <jared@HIDDEN>
> Cc: Eli Zaretskii <eliz@HIDDEN>, 80993 <at> debbugs.gnu.org
> 
> There's no problem due to how the GUI toolkits draw the scroll bar.  The 
> GTK toolkit integration looks at the scroll-bar face to determine 
> styling (aside: info docs are wrong here, we should fix)

What needs to be fixed?

> and it always draws the scroll bar with a one pixel black border, as
> far as I can tell.  We can't do this in a terminal.

That one-pixel border is specific to the toolkit.  On MS-Windows, it
isn't present.

> I suggested copying what vertical-border does because from a styling 
> perspective, it seemed to serve the exact same purpose.  Both are 
> intended to be "window decoration" for the boundary of native widgets.  
> Inheriting from mode-line-inactive or mode-line-active both seem nice 
> because existing Emacs themes will likely style TTY scroll bars 
> correctly.

I think using inverse-video for the scroll-bar face on TTY frames will
do well enough, without a need for doing what vertical-border does
(which consumes yet another glyph, if that's what you meant).

Anyway, I think we've bike-shedded enough about this.  I think we all
agree that we should use the scroll-bar face for showing the scroll
bar on TTYs, so let's do that, and leave any fine-tuning of that face
for TTYs for later.  After all, it's a minor issue, with little or no
effect on the rest of the implementation.




Information forwarded to bug-gnu-emacs@HIDDEN:
bug#80993; Package emacs. Full text available.

Message received at 80993 <at> debbugs.gnu.org:


Received: (at 80993) by debbugs.gnu.org; 26 Jun 2026 06:44:52 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Fri Jun 26 02:44:52 2026
Received: from localhost ([127.0.0.1]:41164 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1wd0J0-0005lI-R4
	for submit <at> debbugs.gnu.org; Fri, 26 Jun 2026 02:44:51 -0400
Received: from eggs.gnu.org ([2001:470:142:3::10]:48400)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <eliz@HIDDEN>) id 1wd0Ix-0005kn-5G
 for 80993 <at> debbugs.gnu.org; Fri, 26 Jun 2026 02:44:48 -0400
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <eliz@HIDDEN>)
 id 1wd0Ip-00040b-13; Fri, 26 Jun 2026 02:44:39 -0400
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=References:Subject:In-Reply-To:To:From:Date:
 mime-version; bh=p1ADX7DEYaPHkBixw2i3Nvgg+l5bNg6NCiP8T3NQCEc=; b=jxeXpjJz3fnc
 C5qzbD6bIbU5EF5MR1CNknGXcfqTy4rQdN47uTR4bQHb+1TIJaLJUJqY6xqTvSr5ulxVsb0u48nsu
 QasKnWYNFnSnF54QMLL9V/z8yN9LEXrWeZIPAA9xB/E6rW+b6oucmdJMkptwMor0f9UmR/caLl2w4
 Xg3OcO1QyEB6vrApLE/l4Ocji1GWl9OD6a6BC5qOS7Vqq409/Qid4my4nh3ridfIWO0RsKBHZ3cZU
 euyE07RygLJDF1cjsXfnOdWh/Ed9VXXBIqjalVeYSQlvIIwwlLOkRjZ/DLZ/EjJWRECmUap7l7PbG
 gUdSkfAT504iLnJ8ju/6kw==;
Date: Fri, 26 Jun 2026 09:44:36 +0300
Message-Id: <86ik75kdgr.fsf@HIDDEN>
From: Eli Zaretskii <eliz@HIDDEN>
To: "Michael Grant" <mgrant@HIDDEN>
In-Reply-To: <em84d0f793-d18c-4a7c-b86a-2f4052ce0cfe@HIDDEN>
 (mgrant@HIDDEN)
Subject: Re: bug#80993: [PATCH] Add support for tty scroll-bars
References: <af36i-emhv7cCESf@HIDDEN> <86cxyv660l.fsf@HIDDEN>
 <fe8b6d3d49ec4eb84acd8b17f164d199@HIDDEN>
 <em3c57e5aa-5711-4cdb-bea6-7d4d0fdb192e@HIDDEN> <86y0g3kuk3.fsf@HIDDEN>
 <ema77cdde2-3c43-44a3-9dfa-cf9b4596808d@HIDDEN> <86mrwjkohe.fsf@HIDDEN>
 <em84d0f793-d18c-4a7c-b86a-2f4052ce0cfe@HIDDEN>
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 80993
Cc: 80993 <at> debbugs.gnu.org, jared@HIDDEN
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

> From: "Michael Grant" <mgrant@HIDDEN>
> Cc: jared@HIDDEN, 80993 <at> debbugs.gnu.org
> Date: Thu, 25 Jun 2026 16:51:17 +0000
> X-Spam-Status: No, score=-99.0 required=5.0 autolearn=disabled
> 
> >From "Eli Zaretskii" <eliz@HIDDEN>
> >>  From: "Michael Grant" <mgrant@HIDDEN>
> >>  Date: Thu, 25 Jun 2026 08:14:51 +0000
> >>
> >>  >From "Eli Zaretskii" <eliz@HIDDEN>
> >>  >>
> >>  >A face can have a more complex definition.  I'm not sure I understand
> >>  >how using inverse-video color makes the gutter "the same color as
> >>  >background", can you explain?  What are the default colors of the TTY
> >>  >frame in your case?
> >>  >
> >>  Currently based on Jared's suggestion, the TTY scrollbar thumb is drawn
> >>  using the scroll-bar face with inverse video.   On a fresh emacs -nw -Q,
> >>  the scroll-bar face does not define an explicit black background. So the
> >>  terminal resolves it from the default face/terminal colors.  This means
> >>  that the gutter looks like the buffer background because scroll-bar has
> >>  no strong explicit background.
> >>
> >>  The thumb looks white because inverse video swaps the current/default
> >>  foreground and background.  If the buffer background is dark purple and
> >>  the normal foreground is white, inverse video gives you a white-ish
> >>  thumb on a dark purple background.
> >
> >I'm confused: are we talking about the scroll-bar face or about
> >scroll-bar-thumb face?  The latter doesn't exist in the current Emacs,
> >so why are you talking about the thumb?
> scroll-bar face, at your suggestion (sorry I thought it was Jared), I 
> removed a specific scroll-bar-face because it wasn't necessary.  Quoting 
> you from above:
> 
>  > I think it would be better to have the face definition have the same
>  > meaning as under X, where the scroll-bar face's foreground color is 
> the
>  > color of the thumb and the background is the color of the track.  This
>  > additional face is unnecessary.
> 
> So that's exactly what I did.  Removed the scroll-bar-thumb face and 
> relied on scroll-bar face which is like what X does and the gutter is 
> the background color of that face or failing that, the inverse of the 
> foreground color.  Let me be more clear... the scroll-bar foreground 
> defaults to the foreground color of the text in the buffer.  This makes 
> the thumb the color of the text in the buffer.  And the rest of the 
> scroll-bar is the same color as the background of the text, as in, the 
> same color of the buffer.
> 
> >And what do you mean by "gutter" in this context?
> The scroll-bar where the thumb isn't.  Think of an "elevator shaft" if 
> the thumb were the "elevator car".  There seems to be several terms used 
> for this, I used "gutter" like on the edge of a road and the "thumb" to 
> move something up and down the gutter.  Tell me what you want me to call 
> it and I'll conform.
> 
> >>  >From "Jared Finder" <jared@HIDDEN>
> >>   > Agreed. I would suggest inheriting (tty only, of course) from the
> >>  mode-line-inactive face.
> >>   > This is what the vertical-border face does already for drawing
> >>  dividers between windows on TTYs.
> >>
> >>  I tested this to see what it looks like using:
> >>
> >>  (set-face-attribute 'scroll-bar nil :inherit 'mode-line-inactive)
> >>
> >>  Visually it looks ok.  For me the gutter gets grey90 and the thumb
> >>  grey20 which is different from the buffer bg.  The thumb is not as
> >>  bright as the text in the buffer but it looks acceptable.  Using
> >>  mode-line-active looks a bit  better for me (honestly idk, personal
> >>  preference really) but i will settle for mode-line-inactive if you have
> >>  a preference.  I'll set it to use mode-line-active for now and you can
> >>  tell me to change it:
> >>
> >>  lisp/faces.el (+7 -4)
> >>       2934
> >>       2935 -(defface scroll-bar '((t nil))
> >>       2935 +(defface scroll-bar
> >>       2936 +  '((((type tty)) :inherit mode-line-active)
> >>       2937 +    (t nil))
> >
> >Before we change the scroll-bar face in such significant ways, and
> >make it dependent on mode line only on TTY frames, I'd like to better
> >understand the problem with the current definition.  The current
> >definition makes it have the default frame's colors, and what exactly
> >is a problem with that? and why it isn't a problem on GUI frames?
> >
> It would be nice to be able to post an image but I don't think this 
> forum supports that.  I'll try to explain again in words.

You can post images here, there's no policy against that, as long as
the format is a standard one.

> The main issue is that using the default scroll-bar face, you get the 
> same color for the gutter (the elevator shaft) of the scroll-bar as the 
> color of the background of the buffer.  It looks super minimal.  I dare 
> say some people might like it that way.  But there's a usability issue 
> in that if you literally can't see where the gutter of the scroll-bar 
> actually is, you can't easily click on it.  You might end up clicking in 
> the buffer itself and moving the point around.  You would want to click 
> above or below the thumb to page up/page down the buffer.
> 
> Using the foreground/background colors from mode-line-active for the tty 
> looks good for me (and maybe only me!).  Ok I definitely see your 
> hesitation to make the tty scroll-bar face(s) dependent on the 
> mode-line-active face by default.  What do you suggest?  instead of 
> inheriting it I could simply set the background only for the tty:
> 
>    (defface scroll-bar
>      '((((type tty)) :background "black")
>        (t nil)))
> 
> This better?  if not black, grey80 is fine choice too, matches the 
> mode-line color scheme that i see but not sure where that actually comes 
> from. hmm on reflection, this is not a good idea, let's not do that.
> 
> What about inheriting the tty scroll-bar face from the fringe?
> 
> ((((type tty)) :inherit fringe)
>        (t nil))
>      ...)
> 
> this was the best idea I could come up with.  Do you have any better 
> ideas?  Again, we could just leave it and have a floating thumb in space 
> but really i think that's a terrible UX, but up to you.

I think the following should work well:

  . define the scroll-bar face for TTY to use inverse-video
  . draw the thumb with the foreground of this face (which is the
    background of the 'default' face), and the rest of the scroll bar
    as "normal" SPC glyphs, which will produce the background of the
    scroll-bar face

This will produce a scroll bar distinguishable from the text-area, and
the thumb clearly visible inside the scroll bar.

WDYT?




Information forwarded to bug-gnu-emacs@HIDDEN:
bug#80993; Package emacs. Full text available.

Message received at 80993 <at> debbugs.gnu.org:


Received: (at 80993) by debbugs.gnu.org; 26 Jun 2026 03:48:22 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Thu Jun 25 23:48:22 2026
Received: from localhost ([127.0.0.1]:39502 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1wcxYD-0001ld-Sv
	for submit <at> debbugs.gnu.org; Thu, 25 Jun 2026 23:48:22 -0400
Received: from greenhill.hpalace.com ([192.155.80.58]:59042)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <jared@HIDDEN>) id 1wcxYA-0001lQ-Pj
 for 80993 <at> debbugs.gnu.org; Thu, 25 Jun 2026 23:48:20 -0400
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=finder.org; s=2018;
 t=1782445697; bh=XBbBXKkUOQQ8lpIzPFKNG6nwC+piNfkjiHyEUvu15tk=;
 h=Date:From:To:Cc:Subject:In-Reply-To:References:From;
 b=RQrE2CnzxvkkhgyqRNJF7Zr+zEOEP38OQ7VjLXUb6Cti9tHVQwkun+K3ZbdhnNbLj
 5iBGk74WiBHKAAFNgLzB7OXxGk57eeYbaDg4eLeqNsKZUskeTSRJdWa37h+KtrK2Wd
 5gIArGM+joLYAA1Egu4kuzPM2NFH8RR7j8tL77yV/kSxHEBFIGCjgHDIYETLg/c+62
 R/+A+qMhhV3CdCZkPfhNNGtziVoiTuFqYR8v/pttH+a8+lOr0jhTKrdXueXBf0p4sW
 Y+xZdE5W/OVb9GZDXMYitk4NlKM/wezH3qu3AJhpTNJFMR+SqjQdIZT5uPnmfa/Ti4
 D063BlBZ5NLaw==
Received: from mail.finder.org (unknown [192.155.80.58])
 by greenhill.hpalace.com (Postfix) with ESMTPSA id 7C46561F;
 Fri, 26 Jun 2026 03:48:17 +0000 (UTC)
MIME-Version: 1.0
Date: Thu, 25 Jun 2026 20:48:17 -0700
From: Jared Finder <jared@HIDDEN>
To: Michael Grant <mgrant@HIDDEN>
Subject: Re: bug#80993: [PATCH] Add support for tty scroll-bars
In-Reply-To: <em84d0f793-d18c-4a7c-b86a-2f4052ce0cfe@HIDDEN>
References: <af36i-emhv7cCESf@HIDDEN> <86cxyv660l.fsf@HIDDEN>
 <fe8b6d3d49ec4eb84acd8b17f164d199@HIDDEN>
 <em3c57e5aa-5711-4cdb-bea6-7d4d0fdb192e@HIDDEN> <86y0g3kuk3.fsf@HIDDEN>
 <ema77cdde2-3c43-44a3-9dfa-cf9b4596808d@HIDDEN> <86mrwjkohe.fsf@HIDDEN>
 <em84d0f793-d18c-4a7c-b86a-2f4052ce0cfe@HIDDEN>
Message-ID: <ce79d9817d3e609dcb26a53f3c39e967@HIDDEN>
X-Sender: jared@HIDDEN
Content-Type: text/plain; charset=US-ASCII;
 format=flowed
Content-Transfer-Encoding: 7bit
X-Spam-Score: 0.0 (/)
X-Debbugs-Envelope-To: 80993
Cc: Eli Zaretskii <eliz@HIDDEN>, 80993 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)

On 2026-06-25 09:51, Michael Grant wrote:
> From "Eli Zaretskii" <eliz@HIDDEN>
>>>  From: "Michael Grant" <mgrant@HIDDEN>
>>>  Date: Thu, 25 Jun 2026 08:14:51 +0000
>>> 
>>>  >From "Eli Zaretskii" <eliz@HIDDEN>
>>>  >>
>>>  >A face can have a more complex definition.  I'm not sure I 
>>> understand
>>>  >how using inverse-video color makes the gutter "the same color as
>>>  >background", can you explain?  What are the default colors of the 
>>> TTY
>>>  >frame in your case?
>>>  >
>>>  Currently based on Jared's suggestion, the TTY scrollbar thumb is 
>>> drawn
>>>  using the scroll-bar face with inverse video.   On a fresh emacs -nw 
>>> -Q,
>>>  the scroll-bar face does not define an explicit black background. So 
>>> the
>>>  terminal resolves it from the default face/terminal colors.  This 
>>> means
>>>  that the gutter looks like the buffer background because scroll-bar 
>>> has
>>>  no strong explicit background.
>>> 
>>>  The thumb looks white because inverse video swaps the 
>>> current/default
>>>  foreground and background.  If the buffer background is dark purple 
>>> and
>>>  the normal foreground is white, inverse video gives you a white-ish
>>>  thumb on a dark purple background.
>> 
>> I'm confused: are we talking about the scroll-bar face or about
>> scroll-bar-thumb face?  The latter doesn't exist in the current Emacs,
>> so why are you talking about the thumb?
> scroll-bar face, at your suggestion (sorry I thought it was Jared), I 
> removed a specific scroll-bar-face because it wasn't necessary.  
> Quoting you from above:
> 
>> I think it would be better to have the face definition have the same
>> meaning as under X, where the scroll-bar face's foreground color is 
>> the
>> color of the thumb and the background is the color of the track.  This
>> additional face is unnecessary.
> 
> So that's exactly what I did.  Removed the scroll-bar-thumb face and 
> relied on scroll-bar face which is like what X does and the gutter is 
> the background color of that face or failing that, the inverse of the 
> foreground color.  Let me be more clear... the scroll-bar foreground 
> defaults to the foreground color of the text in the buffer.  This makes 
> the thumb the color of the text in the buffer.  And the rest of the 
> scroll-bar is the same color as the background of the text, as in, the 
> same color of the buffer.

I think that was me, actually.

>>>  lisp/faces.el (+7 -4)
>>>       2934
>>>       2935 -(defface scroll-bar '((t nil))
>>>       2935 +(defface scroll-bar
>>>       2936 +  '((((type tty)) :inherit mode-line-active)
>>>       2937 +    (t nil))
>> 
>> Before we change the scroll-bar face in such significant ways, and
>> make it dependent on mode line only on TTY frames, I'd like to better
>> understand the problem with the current definition.  The current
>> definition makes it have the default frame's colors, and what exactly
>> is a problem with that? and why it isn't a problem on GUI frames?

There's no problem due to how the GUI toolkits draw the scroll bar.  The 
GTK toolkit integration looks at the scroll-bar face to determine 
styling (aside: info docs are wrong here, we should fix) and it always 
draws the scroll bar with a one pixel black border, as far as I can 
tell.  We can't do this in a terminal.

Also, it appears that the GTK toolkit treats an unset foreground or 
background color on the scroll-bar face to mean inherit from GTK theme 
instead of inherit from the default face.  On the Linux machines I have 
locally, the default theme has scroll bar foreground and background 
colors as shades of gray.

> It would be nice to be able to post an image but I don't think this 
> forum supports that.  I'll try to explain again in words.
> 
> The main issue is that using the default scroll-bar face, you get the 
> same color for the gutter (the elevator shaft) of the scroll-bar as the 
> color of the background of the buffer.  It looks super minimal.  I dare 
> say some people might like it that way.  But there's a usability issue 
> in that if you literally can't see where the gutter of the scroll-bar 
> actually is, you can't easily click on it.  You might end up clicking 
> in the buffer itself and moving the point around.  You would want to 
> click above or below the thumb to page up/page down the buffer.

I'd also point out that this lines up with what toolkits normally do for 
scrollbars, where the scroll bar gutter has contrast with the 
background.  This is pretty universal, in my experience.

> Using the foreground/background colors from mode-line-active for the 
> tty looks good for me (and maybe only me!).  Ok I definitely see your 
> hesitation to make the tty scroll-bar face(s) dependent on the 
> mode-line-active face by default.  What do you suggest?  instead of 
> inheriting it I could simply set the background only for the tty:
> 
>   (defface scroll-bar
>     '((((type tty)) :background "black")
>       (t nil)))
> 
> This better?  if not black, grey80 is fine choice too, matches the 
> mode-line color scheme that i see but not sure where that actually 
> comes from. hmm on reflection, this is not a good idea, let's not do 
> that.
> 
> What about inheriting the tty scroll-bar face from the fringe?
> 
> ((((type tty)) :inherit fringe)
>       (t nil))
>     ...)

I suggested copying what vertical-border does because from a styling 
perspective, it seemed to serve the exact same purpose.  Both are 
intended to be "window decoration" for the boundary of native widgets.  
Inheriting from mode-line-inactive or mode-line-active both seem nice 
because existing Emacs themes will likely style TTY scroll bars 
correctly.

   -- MJF




Information forwarded to bug-gnu-emacs@HIDDEN:
bug#80993; Package emacs. Full text available.

Message received at 80993 <at> debbugs.gnu.org:


Received: (at 80993) by debbugs.gnu.org; 25 Jun 2026 16:51:53 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Thu Jun 25 12:51:53 2026
Received: from localhost ([127.0.0.1]:34249 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1wcnIp-0004Ma-HQ
	for submit <at> debbugs.gnu.org; Thu, 25 Jun 2026 12:51:52 -0400
Received: from strange.networkguild.org ([2600:3c02:e000:dd::1]:55471)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <mgrant@HIDDEN>) id 1wcnIh-0004L8-2t
 for 80993 <at> debbugs.gnu.org; Thu, 25 Jun 2026 12:51:44 -0400
Received: from auth (localhost [127.0.0.1]) (authenticated bits=0)
 by strange.networkguild.org (8.18.1/8.18.1/Debian-6) with ESMTPSA id
 65PGpJij468547
 (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384 bits=256 verify=NOT);
 Thu, 25 Jun 2026 12:51:26 -0400
From: "Michael Grant" <mgrant@HIDDEN>
To: "Eli Zaretskii" <eliz@HIDDEN>
Subject: Re[2]: bug#80993: [PATCH] Add support for tty scroll-bars
Date: Thu, 25 Jun 2026 16:51:17 +0000
Message-Id: <em84d0f793-d18c-4a7c-b86a-2f4052ce0cfe@HIDDEN>
In-Reply-To: <86mrwjkohe.fsf@HIDDEN>
References: <af36i-emhv7cCESf@HIDDEN> <86cxyv660l.fsf@HIDDEN>
 <fe8b6d3d49ec4eb84acd8b17f164d199@HIDDEN>
 <em3c57e5aa-5711-4cdb-bea6-7d4d0fdb192e@HIDDEN> <86y0g3kuk3.fsf@HIDDEN>
 <ema77cdde2-3c43-44a3-9dfa-cf9b4596808d@HIDDEN> <86mrwjkohe.fsf@HIDDEN>
User-Agent: eMClient/10.4.0.0
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8; format=flowed
Content-Transfer-Encoding: quoted-printable
X-Virus-Scanned: clamav-milter 1.4.3 at strange.networkguild.org
X-Virus-Status: Clean
X-Spam-Status: No, score=-99.0 required=5.0 autolearn=disabled
X-Spam-Report: *  -99 ALL_TRUSTED Passed through trusted hosts only via SMTP
X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-25) on
 strange.networkguild.org
X-Spam-Score: -0.0 (/)
X-Debbugs-Envelope-To: 80993
Cc: 80993 <at> debbugs.gnu.org, jared@HIDDEN
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Reply-To: Michael Grant <mgrant@HIDDEN>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)

From "Eli Zaretskii" <eliz@HIDDEN>
>>  From: "Michael Grant" <mgrant@HIDDEN>
>>  Date: Thu, 25 Jun 2026 08:14:51 +0000
>>
>>  >From "Eli Zaretskii" <eliz@HIDDEN>
>>  >>
>>  >A face can have a more complex definition.  I'm not sure I understand
>>  >how using inverse-video color makes the gutter "the same color as
>>  >background", can you explain?  What are the default colors of the TTY
>>  >frame in your case?
>>  >
>>  Currently based on Jared's suggestion, the TTY scrollbar thumb is drawn
>>  using the scroll-bar face with inverse video.   On a fresh emacs -nw -Q=
,
>>  the scroll-bar face does not define an explicit black background. So th=
e
>>  terminal resolves it from the default face/terminal colors.  This means
>>  that the gutter looks like the buffer background because scroll-bar has
>>  no strong explicit background.
>>
>>  The thumb looks white because inverse video swaps the current/default
>>  foreground and background.  If the buffer background is dark purple and
>>  the normal foreground is white, inverse video gives you a white-ish
>>  thumb on a dark purple background.
>
>I'm confused: are we talking about the scroll-bar face or about
>scroll-bar-thumb face?  The latter doesn't exist in the current Emacs,
>so why are you talking about the thumb?
scroll-bar face, at your suggestion (sorry I thought it was Jared), I=20
removed a specific scroll-bar-face because it wasn't necessary.  Quoting=20
you from above:

 > I think it would be better to have the face definition have the same
 > meaning as under X, where the scroll-bar face's foreground color is=20
the
 > color of the thumb and the background is the color of the track.  This
 > additional face is unnecessary.

So that's exactly what I did.  Removed the scroll-bar-thumb face and=20
relied on scroll-bar face which is like what X does and the gutter is=20
the background color of that face or failing that, the inverse of the=20
foreground color.  Let me be more clear... the scroll-bar foreground=20
defaults to the foreground color of the text in the buffer.  This makes=20
the thumb the color of the text in the buffer.  And the rest of the=20
scroll-bar is the same color as the background of the text, as in, the=20
same color of the buffer.

>And what do you mean by "gutter" in this context?
The scroll-bar where the thumb isn't.  Think of an "elevator shaft" if=20
the thumb were the "elevator car".  There seems to be several terms used=20
for this, I used "gutter" like on the edge of a road and the "thumb" to=20
move something up and down the gutter.  Tell me what you want me to call=20
it and I'll conform.

>>  >From "Jared Finder" <jared@HIDDEN>
>>   > Agreed. I would suggest inheriting (tty only, of course) from the
>>  mode-line-inactive face.
>>   > This is what the vertical-border face does already for drawing
>>  dividers between windows on TTYs.
>>
>>  I tested this to see what it looks like using:
>>
>>  (set-face-attribute 'scroll-bar nil :inherit 'mode-line-inactive)
>>
>>  Visually it looks ok.  For me the gutter gets grey90 and the thumb
>>  grey20 which is different from the buffer bg.  The thumb is not as
>>  bright as the text in the buffer but it looks acceptable.  Using
>>  mode-line-active looks a bit  better for me (honestly idk, personal
>>  preference really) but i will settle for mode-line-inactive if you have
>>  a preference.  I'll set it to use mode-line-active for now and you can
>>  tell me to change it:
>>
>>  lisp/faces.el (+7 -4)
>>       2934
>>       2935 -(defface scroll-bar '((t nil))
>>       2935 +(defface scroll-bar
>>       2936 +  '((((type tty)) :inherit mode-line-active)
>>       2937 +    (t nil))
>
>Before we change the scroll-bar face in such significant ways, and
>make it dependent on mode line only on TTY frames, I'd like to better
>understand the problem with the current definition.  The current
>definition makes it have the default frame's colors, and what exactly
>is a problem with that? and why it isn't a problem on GUI frames?
>
It would be nice to be able to post an image but I don't think this=20
forum supports that.  I'll try to explain again in words.

The main issue is that using the default scroll-bar face, you get the=20
same color for the gutter (the elevator shaft) of the scroll-bar as the=20
color of the background of the buffer.  It looks super minimal.  I dare=20
say some people might like it that way.  But there's a usability issue=20
in that if you literally can't see where the gutter of the scroll-bar=20
actually is, you can't easily click on it.  You might end up clicking in=20
the buffer itself and moving the point around.  You would want to click=20
above or below the thumb to page up/page down the buffer.

Using the foreground/background colors from mode-line-active for the tty=20
looks good for me (and maybe only me!).  Ok I definitely see your=20
hesitation to make the tty scroll-bar face(s) dependent on the=20
mode-line-active face by default.  What do you suggest?  instead of=20
inheriting it I could simply set the background only for the tty:

   (defface scroll-bar
     '((((type tty)) :background "black")
       (t nil)))

This better?  if not black, grey80 is fine choice too, matches the=20
mode-line color scheme that i see but not sure where that actually comes=20
from. hmm on reflection, this is not a good idea, let's not do that.

What about inheriting the tty scroll-bar face from the fringe?

((((type tty)) :inherit fringe)
       (t nil))
     ...)

this was the best idea I could come up with.  Do you have any better=20
ideas?  Again, we could just leave it and have a floating thumb in space=20
but really i think that's a terrible UX, but up to you.





Information forwarded to bug-gnu-emacs@HIDDEN:
bug#80993; Package emacs. Full text available.

Message received at 80993 <at> debbugs.gnu.org:


Received: (at 80993) by debbugs.gnu.org; 25 Jun 2026 08:34:47 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Thu Jun 25 04:34:47 2026
Received: from localhost ([127.0.0.1]:59653 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1wcfXl-00043O-Kx
	for submit <at> debbugs.gnu.org; Thu, 25 Jun 2026 04:34:46 -0400
Received: from eggs.gnu.org ([2001:470:142:3::10]:33078)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <eliz@HIDDEN>) id 1wcfXd-00042W-NV
 for 80993 <at> debbugs.gnu.org; Thu, 25 Jun 2026 04:34:37 -0400
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <eliz@HIDDEN>)
 id 1wcfXV-00052E-By; Thu, 25 Jun 2026 04:34:25 -0400
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=References:Subject:In-Reply-To:To:From:Date:
 mime-version; bh=5cjh7WE/XYic6jmIJQj5gomPBJIvFVdwbEhdjxVN+i4=; b=CrtfIyUI6M/l
 OMTvGcCZMLvf7OmuG5u7x92Rr5UhIXY0vplUBZ49S4srISkBKzY5MSRTD0URIoTDAeevQxdzwJQ8U
 G4586InxxJNAI/4GuWFfLlULOSmmB9ZtfwpvJMRIe1HEXt58DaefLI70B3LSd5ZTrrx4+Glswl32Z
 4zeccxniKrFnnCKvGmkr5GnNooOGbrPVNN8MUAomlgsKTVxllmdB5B20iZzSpE1I5nMF8JJaKgEsu
 /GH/4+TSGoYF1Yp/0NGmvN6bspwpcXC5Pgvq83pHISESCs3CmYsDA/jvre159C2zntiTPWjkUFIab
 NTAmfL1EqDAJXvTDuxPr9w==;
Date: Thu, 25 Jun 2026 11:34:21 +0300
Message-Id: <86mrwjkohe.fsf@HIDDEN>
From: Eli Zaretskii <eliz@HIDDEN>
To: "Michael Grant" <mgrant@HIDDEN>
In-Reply-To: <ema77cdde2-3c43-44a3-9dfa-cf9b4596808d@HIDDEN>
 (mgrant@HIDDEN)
Subject: Re: bug#80993: [PATCH] Add support for tty scroll-bars
References: <af36i-emhv7cCESf@HIDDEN> <86cxyv660l.fsf@HIDDEN>
 <fe8b6d3d49ec4eb84acd8b17f164d199@HIDDEN>
 <em3c57e5aa-5711-4cdb-bea6-7d4d0fdb192e@HIDDEN> <86y0g3kuk3.fsf@HIDDEN>
 <ema77cdde2-3c43-44a3-9dfa-cf9b4596808d@HIDDEN>
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 80993
Cc: 80993 <at> debbugs.gnu.org, jared@HIDDEN
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

> From: "Michael Grant" <mgrant@HIDDEN>
> Cc: jared@HIDDEN, 80993 <at> debbugs.gnu.org
> Date: Thu, 25 Jun 2026 08:14:51 +0000
> 
> >From "Eli Zaretskii" <eliz@HIDDEN>
> >>
> >A face can have a more complex definition.  I'm not sure I understand
> >how using inverse-video color makes the gutter "the same color as
> >background", can you explain?  What are the default colors of the TTY
> >frame in your case?
> >
> Currently based on Jared's suggestion, the TTY scrollbar thumb is drawn 
> using the scroll-bar face with inverse video.   On a fresh emacs -nw -Q, 
> the scroll-bar face does not define an explicit black background. So the 
> terminal resolves it from the default face/terminal colors.  This means 
> that the gutter looks like the buffer background because scroll-bar has 
> no strong explicit background.
> 
> The thumb looks white because inverse video swaps the current/default 
> foreground and background.  If the buffer background is dark purple and 
> the normal foreground is white, inverse video gives you a white-ish 
> thumb on a dark purple background.

I'm confused: are we talking about the scroll-bar face or about
scroll-bar-thumb face?  The latter doesn't exist in the current Emacs,
so why are you talking about the thumb?

And what do you mean by "gutter" in this context?

> >From "Jared Finder" <jared@HIDDEN>
>  > Agreed. I would suggest inheriting (tty only, of course) from the 
> mode-line-inactive face.
>  > This is what the vertical-border face does already for drawing 
> dividers between windows on TTYs.
> 
> I tested this to see what it looks like using:
> 
> (set-face-attribute 'scroll-bar nil :inherit 'mode-line-inactive)
> 
> Visually it looks ok.  For me the gutter gets grey90 and the thumb 
> grey20 which is different from the buffer bg.  The thumb is not as 
> bright as the text in the buffer but it looks acceptable.  Using 
> mode-line-active looks a bit  better for me (honestly idk, personal 
> preference really) but i will settle for mode-line-inactive if you have 
> a preference.  I'll set it to use mode-line-active for now and you can 
> tell me to change it:
> 
> lisp/faces.el (+7 -4)
>      2934
>      2935 -(defface scroll-bar '((t nil))
>      2935 +(defface scroll-bar
>      2936 +  '((((type tty)) :inherit mode-line-active)
>      2937 +    (t nil))

Before we change the scroll-bar face in such significant ways, and
make it dependent on mode line only on TTY frames, I'd like to better
understand the problem with the current definition.  The current
definition makes it have the default frame's colors, and what exactly
is a problem with that? and why it isn't a problem on GUI frames?




Information forwarded to bug-gnu-emacs@HIDDEN:
bug#80993; Package emacs. Full text available.

Message received at 80993 <at> debbugs.gnu.org:


Received: (at 80993) by debbugs.gnu.org; 25 Jun 2026 08:15:22 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Thu Jun 25 04:15:21 2026
Received: from localhost ([127.0.0.1]:59616 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1wcfF0-0002Hw-1C
	for submit <at> debbugs.gnu.org; Thu, 25 Jun 2026 04:15:21 -0400
Received: from strange.networkguild.org ([2600:3c02:e000:dd::1]:43773)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <mgrant@HIDDEN>) id 1wcfEt-0002Ey-NO
 for 80993 <at> debbugs.gnu.org; Thu, 25 Jun 2026 04:15:14 -0400
Received: from auth (localhost [127.0.0.1]) (authenticated bits=0)
 by strange.networkguild.org (8.18.1/8.18.1/Debian-6) with ESMTPSA id
 65P8Eq3C392317
 (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384 bits=256 verify=NOT);
 Thu, 25 Jun 2026 04:14:59 -0400
From: "Michael Grant" <mgrant@HIDDEN>
To: "Eli Zaretskii" <eliz@HIDDEN>
Subject: Re[2]: bug#80993: [PATCH] Add support for tty scroll-bars
Date: Thu, 25 Jun 2026 08:14:51 +0000
Message-Id: <ema77cdde2-3c43-44a3-9dfa-cf9b4596808d@HIDDEN>
In-Reply-To: <86y0g3kuk3.fsf@HIDDEN>
References: <af36i-emhv7cCESf@HIDDEN> <86cxyv660l.fsf@HIDDEN>
 <fe8b6d3d49ec4eb84acd8b17f164d199@HIDDEN>
 <em3c57e5aa-5711-4cdb-bea6-7d4d0fdb192e@HIDDEN> <86y0g3kuk3.fsf@HIDDEN>
User-Agent: eMClient/10.4.0.0
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8; format=flowed
Content-Transfer-Encoding: quoted-printable
X-Virus-Scanned: clamav-milter 1.4.3 at strange.networkguild.org
X-Virus-Status: Clean
X-Spam-Status: No, score=-99.0 required=5.0 autolearn=disabled
X-Spam-Report: *  -99 ALL_TRUSTED Passed through trusted hosts only via SMTP
X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-25) on
 strange.networkguild.org
X-Spam-Score: -0.0 (/)
X-Debbugs-Envelope-To: 80993
Cc: 80993 <at> debbugs.gnu.org, jared@HIDDEN
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Reply-To: Michael Grant <mgrant@HIDDEN>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)

From "Eli Zaretskii" <eliz@HIDDEN>
>>
>A face can have a more complex definition.  I'm not sure I understand
>how using inverse-video color makes the gutter "the same color as
>background", can you explain?  What are the default colors of the TTY
>frame in your case?
>
Currently based on Jared's suggestion, the TTY scrollbar thumb is drawn=20
using the scroll-bar face with inverse video.   On a fresh emacs -nw -Q,=20
the scroll-bar face does not define an explicit black background. So the=20
terminal resolves it from the default face/terminal colors.  This means=20
that the gutter looks like the buffer background because scroll-bar has=20
no strong explicit background.

The thumb looks white because inverse video swaps the current/default=20
foreground and background.  If the buffer background is dark purple and=20
the normal foreground is white, inverse video gives you a white-ish=20
thumb on a dark purple background.

From "Jared Finder" <jared@HIDDEN>
 > Agreed. I would suggest inheriting (tty only, of course) from the=20
mode-line-inactive face.
 > This is what the vertical-border face does already for drawing=20
dividers between windows on TTYs.

I tested this to see what it looks like using:

(set-face-attribute 'scroll-bar nil :inherit 'mode-line-inactive)

Visually it looks ok.  For me the gutter gets grey90 and the thumb=20
grey20 which is different from the buffer bg.  The thumb is not as=20
bright as the text in the buffer but it looks acceptable.  Using=20
mode-line-active looks a bit  better for me (honestly idk, personal=20
preference really) but i will settle for mode-line-inactive if you have=20
a preference.  I'll set it to use mode-line-active for now and you can=20
tell me to change it:

lisp/faces.el (+7 -4)
     2934
     2935 -(defface scroll-bar '((t nil))
     2935 +(defface scroll-bar
     2936 +  '((((type tty)) :inherit mode-line-active)
     2937 +    (t nil))




Information forwarded to bug-gnu-emacs@HIDDEN:
bug#80993; Package emacs. Full text available.

Message received at 80993 <at> debbugs.gnu.org:


Received: (at 80993) by debbugs.gnu.org; 25 Jun 2026 06:23:31 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Thu Jun 25 02:23:30 2026
Received: from localhost ([127.0.0.1]:59385 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1wcdUk-0007tV-A4
	for submit <at> debbugs.gnu.org; Thu, 25 Jun 2026 02:23:30 -0400
Received: from eggs.gnu.org ([2001:470:142:3::10]:49518)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <eliz@HIDDEN>) id 1wcdUc-0007sp-G9
 for 80993 <at> debbugs.gnu.org; Thu, 25 Jun 2026 02:23:22 -0400
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <eliz@HIDDEN>)
 id 1wcdUV-0003KG-Vl; Thu, 25 Jun 2026 02:23:12 -0400
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=References:Subject:In-Reply-To:To:From:Date:
 mime-version; bh=tN1vEC0kktnFlqLIiU12mSkMvk+BPRdtASPiVOHzJ3U=; b=WnbNx/1H+PcU
 bWw5+Z5eHt4U0xZILpTwzUZE4lQqkZ93P3uG//mkxNovNADKdoCWID9PcdWMQe4iBiDbhEdPh6AYk
 ZzP4dQxthdY7rd1YKmdQFvbTD0YRkDCe1uZFU/nCRiVkhG6bpOyIHsEmtrPKAuuEGiIzsct92aI0+
 eEYQ8t5T5wE3poiTyMGvIzHUyeZT7Ukp0OqLXVXl+xtFxBni/k0z9V30O5oxjO6prid9Rvfb5t2tA
 prjhswSS0/VJa+JtLPPLQSFISDgG9ToDYkf6Ps+GhhcbSdSZCK2LTwvBqSc/MNMbxZPIFIzmTtVol
 W2qeZKYaWr6P8zp9n/Cq5w==;
Date: Thu, 25 Jun 2026 09:23:08 +0300
Message-Id: <86y0g3kuk3.fsf@HIDDEN>
From: Eli Zaretskii <eliz@HIDDEN>
To: "Michael Grant" <mgrant@HIDDEN>
In-Reply-To: <em3c57e5aa-5711-4cdb-bea6-7d4d0fdb192e@HIDDEN>
 (mgrant@HIDDEN)
Subject: Re: bug#80993: [PATCH] Add support for tty scroll-bars
References: <af36i-emhv7cCESf@HIDDEN> <86cxyv660l.fsf@HIDDEN>
 <fe8b6d3d49ec4eb84acd8b17f164d199@HIDDEN>
 <em3c57e5aa-5711-4cdb-bea6-7d4d0fdb192e@HIDDEN>
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 80993
Cc: 80993 <at> debbugs.gnu.org, jared@HIDDEN
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

> From: "Michael Grant" <mgrant@HIDDEN>
> Cc: 80993 <at> debbugs.gnu.org
> Date: Wed, 24 Jun 2026 11:17:13 +0000
> X-Spam-Status: No, score=-99.0 required=5.0 autolearn=disabled
> 
> I've fixed these things you asked about below, see comments below.  
> Sorry this took so long, it just took a while to work through and debug. 
>   Updated patch soon!
> 
>  > Date: Sun, 17 May 2026 18:56:29 -0700
>  > From: Jared Finder <jared <at> finder.org>
> >Some additional comments.
> >
> >+(defface scroll-bar-thumb
> >+  '((((type tty)) :inverse-video t)
> >+    (t nil))
> >+  "Basic face for the scroll bar thumb (draggable portion) in TTY frames.
> >+On character-based terminals, the thumb is rendered as inverse-video spaces."
> >+  :version "30.1"
> >+  :group 'frames
> >+  :group 'basic-faces)
> >
> >I think it would be better to have the face definition have the same meaning as under X, where the scroll-bar face's foreground color is the color of the thumb and the background is the color of the track.  This additional face is unnecessary.
> Ok yes, this is done.  Small consequence though.  This makes the gutter 
> the same color as the background.  Personally I like to see where the 
> gutter is.  I can set it myself of course:
> (custom-set-faces
>   '(scroll-bar ((t (:background "black"))))
> and this makes a nice dark gutter.  Should this be the reasonable 
> default for tty scrollbars? or should we leave the gutter blended into 
> the buffer?  Frankly I'd rather see the gutter, easier to click on if I 
> want to page up/down.

A face can have a more complex definition.  I'm not sure I understand
how using inverse-video color makes the gutter "the same color as
background", can you explain?  What are the default colors of the TTY
frame in your case?

> Found a couple other bugs, cleaned up some things, and merged in latest 
> version from savannah.  Will post an updated patch here shortly.

TIA




Information forwarded to bug-gnu-emacs@HIDDEN:
bug#80993; Package emacs. Full text available.

Message received at 80993 <at> debbugs.gnu.org:


Received: (at 80993) by debbugs.gnu.org; 25 Jun 2026 03:14:06 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Wed Jun 24 23:14:06 2026
Received: from localhost ([127.0.0.1]:58697 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1wcaXV-00051R-2K
	for submit <at> debbugs.gnu.org; Wed, 24 Jun 2026 23:14:06 -0400
Received: from greenhill.hpalace.com ([192.155.80.58]:45016)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <jared@HIDDEN>) id 1wcaXR-00050d-14
 for 80993 <at> debbugs.gnu.org; Wed, 24 Jun 2026 23:14:02 -0400
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=finder.org; s=2018;
 t=1782357239; bh=3rhC7I/5Ttr7uTq/TAo9DpIOnH/9paNJrmOjhYhNSfM=;
 h=Date:From:To:Cc:Subject:In-Reply-To:References:From;
 b=M/O7oC85wt5aQl4I3LsJ9pOjOJdCjAvTLdSIkSW98nDRgwMk0t8N5L5T94UdcMNrp
 KQHd/MwHeWB0bizf06OrKEvw4kuHUv/ibL2ZawJHH1WafnT7T87LmMCaTu5WUM2ayb
 0oamaoCXgc4VECef6vf53F6yHlOR4Qt6tTlXOGIoHuSREqvIFbaA+wi69MBz7ZjIDS
 ifY0IV3BKQ8ZzwJaEkEAecLGaJM0Lq3r3+m5rpK7TBpXFfUS1JKaCdSAP02X+8uvFr
 PshYtr1R6ztkoIttKagvEMn/o8gOiAbaPNQdkTPfXV9wdVTDU+Dt5G6xGpi+J+QNsO
 jwM3Tox1IH4hw==
Received: from mail.finder.org (unknown [192.155.80.58])
 by greenhill.hpalace.com (Postfix) with ESMTPSA id C1E4966C;
 Thu, 25 Jun 2026 03:13:59 +0000 (UTC)
MIME-Version: 1.0
Date: Wed, 24 Jun 2026 20:13:59 -0700
From: Jared Finder <jared@HIDDEN>
To: Michael Grant <mgrant@HIDDEN>
Subject: Re: bug#80993: [PATCH] Add support for tty scroll-bars
In-Reply-To: <em3c57e5aa-5711-4cdb-bea6-7d4d0fdb192e@HIDDEN>
References: <af36i-emhv7cCESf@HIDDEN> <86cxyv660l.fsf@HIDDEN>
 <fe8b6d3d49ec4eb84acd8b17f164d199@HIDDEN>
 <em3c57e5aa-5711-4cdb-bea6-7d4d0fdb192e@HIDDEN>
Message-ID: <adb5d8aaba48a53465197140ee8b0048@HIDDEN>
X-Sender: jared@HIDDEN
Content-Type: text/plain; charset=US-ASCII;
 format=flowed
Content-Transfer-Encoding: 7bit
X-Spam-Score: 0.0 (/)
X-Debbugs-Envelope-To: 80993
Cc: Eli Zaretskii <eliz@HIDDEN>, 80993 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)

On 2026-06-24 04:17, Michael Grant wrote:
> I've fixed these things you asked about below, see comments below.  
> Sorry this took so long, it just took a while to work through and 
> debug.  Updated patch soon!

I look forward to it!

>> From: Jared Finder <jared <at> finder.org>
>> +(defface scroll-bar-thumb
>> +  '((((type tty)) :inverse-video t)
>> +    (t nil))
>> +  "Basic face for the scroll bar thumb (draggable portion) in TTY 
>> frames.
>> +On character-based terminals, the thumb is rendered as inverse-video 
>> spaces."
>> +  :version "30.1"
>> +  :group 'frames
>> +  :group 'basic-faces)
>> 
>> I think it would be better to have the face definition have the same 
>> meaning as under X, where the scroll-bar face's foreground color is 
>> the color of the thumb and the background is the color of the track.  
>> This additional face is unnecessary.
> Ok yes, this is done.  Small consequence though.  This makes the gutter 
> the same color as the background.  Personally I like to see where the 
> gutter is.  I can set it myself of course:
> (custom-set-faces
>  '(scroll-bar ((t (:background "black"))))
> and this makes a nice dark gutter.  Should this be the reasonable 
> default for tty scrollbars? or should we leave the gutter blended into 
> the buffer?  Frankly I'd rather see the gutter, easier to click on if I 
> want to page up/down.

Agreed. I would suggest inheriting (tty only, of course) from the 
mode-line-inactive face.  This is what the vertical-border face does 
already for drawing dividers between windows on TTYs.

   -- MJF




Information forwarded to bug-gnu-emacs@HIDDEN:
bug#80993; Package emacs. Full text available.

Message received at 80993 <at> debbugs.gnu.org:


Received: (at 80993) by debbugs.gnu.org; 24 Jun 2026 11:17:51 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Wed Jun 24 07:17:50 2026
Received: from localhost ([127.0.0.1]:49781 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1wcLbx-0004Mh-GI
	for submit <at> debbugs.gnu.org; Wed, 24 Jun 2026 07:17:50 -0400
Received: from strange.networkguild.org ([2600:3c02:e000:dd::1]:39597)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <mgrant@HIDDEN>) id 1wcLbm-0004Lh-HB
 for 80993 <at> debbugs.gnu.org; Wed, 24 Jun 2026 07:17:37 -0400
Received: from auth (localhost [127.0.0.1]) (authenticated bits=0)
 by strange.networkguild.org (8.18.1/8.18.1/Debian-6) with ESMTPSA id
 65OBHFPw229814
 (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384 bits=256 verify=NOT);
 Wed, 24 Jun 2026 07:17:22 -0400
From: "Michael Grant" <mgrant@HIDDEN>
To: "Jared Finder" <jared@HIDDEN>, "Eli Zaretskii" <eliz@HIDDEN>
Subject: Re[2]: bug#80993: [PATCH] Add support for tty scroll-bars
Date: Wed, 24 Jun 2026 11:17:13 +0000
Message-Id: <em3c57e5aa-5711-4cdb-bea6-7d4d0fdb192e@HIDDEN>
In-Reply-To: <fe8b6d3d49ec4eb84acd8b17f164d199@HIDDEN>
References: <af36i-emhv7cCESf@HIDDEN> <86cxyv660l.fsf@HIDDEN>
 <fe8b6d3d49ec4eb84acd8b17f164d199@HIDDEN>
User-Agent: eMClient/10.4.0.0
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8; format=flowed
Content-Transfer-Encoding: quoted-printable
X-Virus-Scanned: clamav-milter 1.4.3 at strange.networkguild.org
X-Virus-Status: Clean
X-Spam-Status: No, score=-99.0 required=5.0 autolearn=disabled
X-Spam-Report: *  -99 ALL_TRUSTED Passed through trusted hosts only via SMTP
X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-25) on
 strange.networkguild.org
X-Spam-Score: -0.0 (/)
X-Debbugs-Envelope-To: 80993
Cc: 80993 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Reply-To: Michael Grant <mgrant@HIDDEN>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)

I've fixed these things you asked about below, see comments below. =20
Sorry this took so long, it just took a while to work through and debug.=20
  Updated patch soon!

 > Date: Sun, 17 May 2026 18:56:29 -0700
 > From: Jared Finder <jared <at> finder.org>
>Some additional comments.
>
>+(defface scroll-bar-thumb
>+  '((((type tty)) :inverse-video t)
>+    (t nil))
>+  "Basic face for the scroll bar thumb (draggable portion) in TTY frames.
>+On character-based terminals, the thumb is rendered as inverse-video spac=
es."
>+  :version "30.1"
>+  :group 'frames
>+  :group 'basic-faces)
>
>I think it would be better to have the face definition have the same meani=
ng as under X, where the scroll-bar face's foreground color is the color of =
the thumb and the background is the color of the track.  This additional f=
ace is unnecessary.
Ok yes, this is done.  Small consequence though.  This makes the gutter=20
the same color as the background.  Personally I like to see where the=20
gutter is.  I can set it myself of course:
(custom-set-faces
  '(scroll-bar ((t (:background "black"))))
and this makes a nice dark gutter.  Should this be the reasonable=20
default for tty scrollbars? or should we leave the gutter blended into=20
the buffer?  Frankly I'd rather see the gutter, easier to click on if I=20
want to page up/down.

>>>--- a/lisp/mouse.el
>>>+++ b/lisp/mouse.el
>>>@@ -865,7 +865,16 @@ mouse-position-for-drag-line
>>>  relative to the selected frame, unless the current drag operation was
>>>  produced from a touch screen event, in which event, return the positio=
n
>>>  of the active touch-screen tool relative to the same."
>>>-  (if tty (mouse-position-in-root-frame)
>>>+  (if tty
>>>+      ;; mouse-position-in-root-frame reads from the GPM mouse hook,
>>>+      ;; which is not updated by xterm mouse events.  When xterm mouse
>>>+      ;; mode is active the coordinates are stored as terminal paramete=
rs
>>>+      ;; by xterm-mouse-event; use those when available.
>>>+      (let ((xt-x (terminal-parameter nil 'xterm-mouse-x))
>>>+            (xt-y (terminal-parameter nil 'xterm-mouse-y)))
>>>+        (if (and xt-x xt-y)
>>>+            (cons xt-x xt-y)
>>>+          (mouse-position-in-root-frame)))
>>
>>Jared, any comments?  Would it be cleaner to update xtmouse such that
>>mouse_position_hook works for it?  Or some other way of supporting
>>mouse-position-in-root-frame on xtmouse?
>
>I don't think this change is needed. Local experimentation shows that mous=
e-position-in-root-frame properly reports mouse coordinates when xterm-mous=
e-mode is enabled. This is because xterm-mouse-mode sets mouse-position-fun=
ction to xterm-mouse-position-function which does exactly this transformati=
on.
>
>What am I missing here?
You were right =E2=80=94 mouse-position-in-root-frame calls mouse_position(=
true)=20
which goes through Vmouse_position_function which already calls=20
xterm-mouse-position-function, which reads the=20
xterm-mouse-x/xterm-mouse-y terminal parameters.   Reverted this.  No=20
changes to mouse.el now.

>
>
>+  (let* ((start-pos    (event-start event))
>+         (window       (nth 0 start-pos))
>+         (click-sb-row (car (nth 2 start-pos)))
>
>Here, and in other places throughout this patch nth is used instead of the =
posn utility functions like posn-window, posn-x-y, etc.  I believe the pos=
n utility functions are preferred stylistically.
Ok, I used posn where it made sense.

>
>
>+(defun xterm-mouse--tty-scroll-bar-window (x y frame)
>+  "Return the window whose TTY scroll bar column is at frame column X, ro=
w Y.
>+Returns nil if no TTY scroll bar occupies position (X, Y)."
>+  (let ((sb-side (frame-parameter frame 'vertical-scroll-bars))
>+        result)
>+    (when sb-side
>+      (walk-windows
>... and a bunch of code ...
>
>Can this just use window-at instead to get the specific window? And it wou=
ld be nice if the function coordinates_in_window properly detected the scro=
ll bar, in which case you could add a parameter to coordinates-in-window-p=
 that allows it to return scroll bar areas.  For backward compat it currentl=
y returns nil when passed scrollbar coordinates.
ok that function is removed now.  xt-mouse now uses (w (window-at x y=20
frame)).
coordinates-in-window-p now has a third optional argument,=20
REPORT-SCROLL-BARS, non-nil it can return if x y is on a scroll-bar.
>
>
>+(defun xterm-mouse--tty-vertical-border-window (x y frame)
>+  "Return the window whose TTY `|' border column is at frame column X, ro=
w Y.
>+Returns nil unless (X, Y) is on the `|' border of a non-rightmost TTY
>+window with a right scroll bar.  In that layout, [content][SB][|], the
>+`|' occupies the last column of the window's total-width allocation."
>... and a bunch of code ...
>
>Could this be replaced with:
>
>(eq (coordinates-in-window-p (cons x y) (window-at x y frame)
>     'vertical-line)
Yup, this is removed and replaced with what you say too now.
>
>
>+(defun xterm-mouse--tty-scroll-bar-part (window y)
>+  "Return the scroll bar part clicked at terminal row Y for WINDOW.
>+Returns one of the symbols `above-handle', `handle', or `below-handle'."
>
>This appears to be a copy of code added in tty_apply_scroll_bar_glyphs_for=
_window.  I would prefer that be extracted out to a utility function that x=
t-mouse.el can call instead so we do not need to duplicate code in both xt-=
mouse.el and in C.
>
Ok this is done.  There's now a utility function:   (tty-scroll-bar-part=20
WINDOW Y)

   It returns one of:

   above-handle
   handle
   below-handle

  and xt-mouse.el now just calls it when constructing the scroll-bar=20
event:

   (part (tty-scroll-bar-part w y))

also built a helper function for tty_scroll_bar_rows() to calculate the=20
usable tty rows for the scrollbar to avoid the header-line and=20
mode-lines.  used in a few places.

>@@ -341,6 +431,59 @@ xterm-mouse-event
>  				  frame)
>  				item)
>  			  (nthcdr 2 (posn-at-x-y x y (selected-frame)))))))
>+             ;; Check for a click in a TTY vertical scroll bar column.
>+             ;; When detected, replace the position with a scroll bar
>+             ;; position so that [vertical-scroll-bar mouse-N] bindings f=
ire.
>+             (sb-window (and (not (display-graphic-p))
>+                             frame
>+                             (not (eq type 'mouse-movement))
>+                             (xterm-mouse--tty-scroll-bar-window x y fram=
e)))
>
>I think the changes above could dramatically simplify this case.
yes, they did!

>+             (posn (if sb-window
>
>posn was just bound above. It would be better to put this code into the lo=
gic for constructing the posn.  There's already significant logic looking a=
t the x/y coordinate an calculating the window part from there.
>
yes, that was addressed by removing the separate=20
sb-window/post-processing path and folding the scrollbar case into the=20
main posn construction logic using window-at plus=20
coordinates-in-window-p.

>
>+                       (let* ((win-ht  (window-body-height sb-window))
>+                              (win-top (window-top-line sb-window))
>+                              (sb-row  (max 0 (min (1- win-ht) (- y win-t=
op))))
>+                              (part    (xterm-mouse--tty-scroll-bar-part
>+                                        sb-window y))
>+                              ;; For button-up events: if the drag starte=
d on
>+                              ;; the scroll-bar handle, keep part=3D'hand=
le' so
>+                              ;; scroll-bar-drag-1 proportionally scrolls =
to
>+                              ;; the release position rather than paging.
>+                              (down-ev  (terminal-parameter
>+                                         nil 'xterm-mouse-last-down))
>+                              (down-part (and down-ev
>+                                             (nth 4 (nth 1 down-ev))))
>+                              (part     (if (and (not (string-prefix-p
>+                                                       "down-"
>+                                                       (symbol-name type)=
))
>+                                                 (eq down-part 'handle))
>+                                            'handle
>
>I do not think it is a good idea to make tty mouse return different events =
than the graphical mouse.  I would instead suggest you figure out what par=
t of the scroll bar is clicked inside scroll-bar-toolkit-scroll.

ok.   we removed the down-part override entirely, and moved handle-drag=20
behavior into the scroll bar command path rather than changing what=20
xt-mouse reports.

>+                                          part)))
>+                         ;; Build a scroll-bar position in the same forma=
t as
>+                         ;; make_scroll_bar_position in keyboard.c:
>+                         ;;   (window AREA (pos . size) timestamp part)
>+                         ;; AREA must be the bare symbol `vertical-scroll=
-bar'
>+                         ;; (not a cons) so that read_key_sequence's SYMB=
OLP
>+                         ;; check expands the event to [vertical-scroll-b=
ar
>+                         ;; mouse-1], which fires `scroll-bar-toolkit-scr=
oll'.
>+                         (list sb-window
>+                               'vertical-scroll-bar
>+                               (cons sb-row win-ht)
>+                               timestamp
>+                               part))
>+                     posn))
>+             ;; Check for a click on the TTY '|' window border.
>+             ;; For a right scroll bar on a non-rightmost TTY window the=
 '|'
>+             ;; glyph occupies the last column of the window allocation;=
 a
>+             ;; click there should generate a vertical-line position so t=
hat
>+             ;; [vertical-line down-mouse-1] =E2=86=92 mouse-drag-vertica=
l-line fires.
>+             (border-window (and (not sb-window)
>+                                 frame
>+                                 (not (eq type 'mouse-movement))
>+                                 (xterm-mouse--tty-vertical-border-window
>+                                  x y frame)))
>+             (posn (if border-window
>+                       (list border-window 'vertical-line (cons x y) time=
stamp)
>+                     posn))
>               (event (list type posn)))
>          (setcar (nthcdr 3 posn) timestamp)
>
>Overall, I suspect the above code can be made much simpler if it used the=
 above suggestions, especially moving to the existing functions that already =
determine what part of a window a coordinate is in.
>

Yup agreed, please have a look when i repost the patch, i think we=20
indeed managed to simplify it and clean things up based on your=20
comments.  Thanks for that!

Found a couple other bugs, cleaned up some things, and merged in latest=20
version from savannah.  Will post an updated patch here shortly.

Michael Grant




Information forwarded to bug-gnu-emacs@HIDDEN:
bug#80993; Package emacs. Full text available.

Message received at 80993 <at> debbugs.gnu.org:


Received: (at 80993) by debbugs.gnu.org; 15 Jun 2026 18:42:11 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Mon Jun 15 14:42:10 2026
Received: from localhost ([127.0.0.1]:43963 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1wZCG7-0001Td-2i
	for submit <at> debbugs.gnu.org; Mon, 15 Jun 2026 14:42:09 -0400
Received: from strange.networkguild.org ([2600:3c02:e000:dd::1]:55637)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <mgrant@HIDDEN>) id 1wZCG0-0001SW-Fk
 for 80993 <at> debbugs.gnu.org; Mon, 15 Jun 2026 14:42:03 -0400
Received: from auth (localhost [127.0.0.1]) (authenticated bits=0)
 by strange.networkguild.org (8.18.1/8.18.1/Debian-6) with ESMTPSA id
 65FIfko81099025
 (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384 bits=256 verify=NOT);
 Mon, 15 Jun 2026 14:41:53 -0400
From: "Michael Grant" <mgrant@HIDDEN>
To: "Jared Finder" <jared@HIDDEN>, "Eli Zaretskii" <eliz@HIDDEN>
Subject: Re[2]: bug#80993: [PATCH] Add support for tty scroll-bars
Date: Mon, 15 Jun 2026 18:41:45 +0000
Message-Id: <emce4db2f7-3eda-4a6d-a812-4319d9d93d47@HIDDEN>
In-Reply-To: <cd126f06e0745f7331cdcf066c73a51b@HIDDEN>
References: <af36i-emhv7cCESf@HIDDEN> <86cxyv660l.fsf@HIDDEN>
 <em44ec92d2-646d-46d0-897c-2fe53f7d24d4@HIDDEN> <864ij5mp52.fsf@HIDDEN>
 <ema4d265a8-02b4-4ed5-8298-d5387b0193c1@HIDDEN> <86h5n4kqqm.fsf@HIDDEN>
 <cd126f06e0745f7331cdcf066c73a51b@HIDDEN>
User-Agent: eMClient/10.4.0.0
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8; format=flowed
Content-Transfer-Encoding: quoted-printable
X-Virus-Scanned: clamav-milter 1.4.3 at strange.networkguild.org
X-Virus-Status: Clean
X-Spam-Status: No, score=-99.0 required=5.0 autolearn=disabled
X-Spam-Report: *  -99 ALL_TRUSTED Passed through trusted hosts only via SMTP
X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-25) on
 strange.networkguild.org
X-Spam-Score: -0.0 (/)
X-Debbugs-Envelope-To: 80993
Cc: 80993 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Reply-To: Michael Grant <mgrant@HIDDEN>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)

From "Jared Finder" <jared@HIDDEN
>On 2026-06-15 04:06, Eli Zaretskii wrote:
>>>From: "Michael Grant" <mgrant@HIDDEN>
>>>Not sure about that.  In X there is a scroll bar width, so it's logical=
 to follow that.  The width is in pixels but in the
>>>tty, the width of a "pixel" is a character.  I think what I will try is=
 if someone sets a string, 3 characters wide then
>>>I will default the width to 3.  However, if someone sets the width large=
r, I will just loop over and fill it out to that
>>>width.  For example if they set the width to 5, it would be like 12312 f=
rom the string "123".
>>
>>I'm asking why do we need to allow customizing this via both the
>>string and the width?  If someone wants to have a wider scroll bar
>>than the characters in the string, they can always pad with blanks.
>
>The variable and frame parameter scroll-bar-width already exists.  Why do=
 we need to add more customization options?  The simplest thing would be to=
 just say the scroll bar is scroll-bar-width SPC characters in the foregroun=
d color of the scroll-bar font.  Use inverse video here so it works even on =
monochrome TTYs.  This is very similar behavior to on GUI displays.  This=
 also avoids all the concerns around character choices and straightforwardly =
allows per-frame customization.
Ok, this works for me.  I'll leave it hard-wired as a SPC character. =20
Someone can always change this later.




Information forwarded to bug-gnu-emacs@HIDDEN:
bug#80993; Package emacs. Full text available.

Message received at 80993 <at> debbugs.gnu.org:


Received: (at 80993) by debbugs.gnu.org; 15 Jun 2026 14:50:24 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Mon Jun 15 10:50:23 2026
Received: from localhost ([127.0.0.1]:42204 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1wZ8dp-00009X-TL
	for submit <at> debbugs.gnu.org; Mon, 15 Jun 2026 10:50:23 -0400
Received: from greenhill.hpalace.com ([192.155.80.58]:36642)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <jared@HIDDEN>) id 1wZ8dk-00007C-Hm
 for 80993 <at> debbugs.gnu.org; Mon, 15 Jun 2026 10:50:18 -0400
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=finder.org; s=2018;
 t=1781535015; bh=/iwmC4w08hvIVIo5L7nV2z5HZnkpCfAjmZz14FDWcbc=;
 h=Date:From:To:Cc:Subject:In-Reply-To:References:From;
 b=q6C0zO2sew1JJ8m3Y3oytCkiuZWfqq/6AqY/ldL4d/CrcaQ/RDCkTfxgGursZ5sTq
 6wfZ3WT4AGaUHdmAE7Yb2AdqlpAMpvmzfGpugKBA8V5iWlqDn7P5wP+CJUVwEWeian
 w8PnBANOewv9RvqwjYCGy1maW+kEcMgM7UBvMaCLosAtPwbF3wcu3A8ysBpR2UCDAn
 ZR3YMo2rnVROWr7J07rWwMYqtMjTqxK6qUxquvjkMiGuqFVIaUazKhhW6ko8j4tVhQ
 jexLYudX9n1tDSmW9Z2KvsmKIH5pwL0K4VWmfsmIls1kt12lfXnJQyzkPoJhJKCPuX
 wuW4bvgkFvi0A==
Received: from mail.finder.org (unknown [192.155.80.58])
 by greenhill.hpalace.com (Postfix) with ESMTPSA id 26BF5642;
 Mon, 15 Jun 2026 14:50:15 +0000 (UTC)
MIME-Version: 1.0
Date: Mon, 15 Jun 2026 07:50:14 -0700
From: Jared Finder <jared@HIDDEN>
To: Eli Zaretskii <eliz@HIDDEN>
Subject: Re: bug#80993: [PATCH] Add support for tty scroll-bars
In-Reply-To: <86h5n4kqqm.fsf@HIDDEN>
References: <af36i-emhv7cCESf@HIDDEN> <86cxyv660l.fsf@HIDDEN>
 <em44ec92d2-646d-46d0-897c-2fe53f7d24d4@HIDDEN> <864ij5mp52.fsf@HIDDEN>
 <ema4d265a8-02b4-4ed5-8298-d5387b0193c1@HIDDEN> <86h5n4kqqm.fsf@HIDDEN>
Message-ID: <cd126f06e0745f7331cdcf066c73a51b@HIDDEN>
X-Sender: jared@HIDDEN
Content-Type: text/plain; charset=US-ASCII;
 format=flowed
Content-Transfer-Encoding: 7bit
X-Spam-Score: 0.0 (/)
X-Debbugs-Envelope-To: 80993
Cc: 80993 <at> debbugs.gnu.org, Michael Grant <mgrant@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)

On 2026-06-15 04:06, Eli Zaretskii wrote:
>> From: "Michael Grant" <mgrant@HIDDEN>
>> Not sure about that.  In X there is a scroll bar width, so it's 
>> logical to follow that.  The width is in pixels but in the
>> tty, the width of a "pixel" is a character.  I think what I will try 
>> is if someone sets a string, 3 characters wide then
>> I will default the width to 3.  However, if someone sets the width 
>> larger, I will just loop over and fill it out to that
>> width.  For example if they set the width to 5, it would be like 12312 
>> from the string "123".
> 
> I'm asking why do we need to allow customizing this via both the
> string and the width?  If someone wants to have a wider scroll bar
> than the characters in the string, they can always pad with blanks.

The variable and frame parameter scroll-bar-width already exists.  Why 
do we need to add more customization options?  The simplest thing would 
be to just say the scroll bar is scroll-bar-width SPC characters in the 
foreground color of the scroll-bar font.  Use inverse video here so it 
works even on monochrome TTYs.  This is very similar behavior to on GUI 
displays.  This also avoids all the concerns around character choices 
and straightforwardly allows per-frame customization.

   -- MJF




Information forwarded to bug-gnu-emacs@HIDDEN:
bug#80993; Package emacs. Full text available.

Message received at 80993 <at> debbugs.gnu.org:


Received: (at 80993) by debbugs.gnu.org; 15 Jun 2026 11:06:24 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Mon Jun 15 07:06:24 2026
Received: from localhost ([127.0.0.1]:39855 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1wZ595-00013m-FR
	for submit <at> debbugs.gnu.org; Mon, 15 Jun 2026 07:06:23 -0400
Received: from eggs.gnu.org ([2001:470:142:3::10]:53078)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <eliz@HIDDEN>) id 1wZ592-00013W-Dh
 for 80993 <at> debbugs.gnu.org; Mon, 15 Jun 2026 07:06:21 -0400
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <eliz@HIDDEN>)
 id 1wZ58u-0007Xu-2I; Mon, 15 Jun 2026 07:06:12 -0400
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=References:Subject:In-Reply-To:To:From:Date:
 mime-version; bh=w/lQZW0CGsoPKoA6YssJmRh4SBl2G6W/+rlPUrBY9nU=; b=Psn1rkPBXG71
 TOPIqhtZgEI02T7OQRqKmpAhIduQtLNGjrG48GeEUx4MzFtWpVJzj+4OnbAzAQEAcL80vzvpskp8E
 TLHbmAIuojU3LusLxRPuP2bcAwTm1xiOWzrW0YBS4JpwK+4PtTA7+auT1p8YlARh5DFq/QMDqLAbG
 4lGWRmtS/ijx/+a4B82eP1y43QXJjjDLyLTDMhi/e7tXNTwHOU5U+y3hIHT0mAsQvE6gGzypOgGGs
 PnpTwaXiUedNmDmJVw9HxKDFsOGc5nnQRHL4nKrz7A/pisvzrEnG+hVCsyi39c41AwrxMj+5R94Mt
 9nMS/r1F4OfsSeeWVw1TrA==;
Date: Mon, 15 Jun 2026 14:06:09 +0300
Message-Id: <86h5n4kqqm.fsf@HIDDEN>
From: Eli Zaretskii <eliz@HIDDEN>
To: "Michael Grant" <mgrant@HIDDEN>
In-Reply-To: <ema4d265a8-02b4-4ed5-8298-d5387b0193c1@HIDDEN>
 (mgrant@HIDDEN)
Subject: Re: bug#80993: [PATCH] Add support for tty scroll-bars
References: <af36i-emhv7cCESf@HIDDEN> <86cxyv660l.fsf@HIDDEN>
 <em44ec92d2-646d-46d0-897c-2fe53f7d24d4@HIDDEN> <864ij5mp52.fsf@HIDDEN>
 <ema4d265a8-02b4-4ed5-8298-d5387b0193c1@HIDDEN>
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 80993
Cc: 80993 <at> debbugs.gnu.org, jared@HIDDEN
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

> From: "Michael Grant" <mgrant@HIDDEN>
> Cc: jared@HIDDEN, 80993 <at> debbugs.gnu.org
> Date: Sun, 14 Jun 2026 18:55:58 +0000
> 
>  Without scrollbars, FRAME_COLS(f) and FrameCols(tty) are the same value,
>  the frame text area fills the entire terminal width. Needed to do
>  because the scroll bar when on the right was incorrectly causing
>  scrolling to happen. This fixes that.
> 
>   
>  I think it means we should add FRAME_SCROLL_BAR_COLS to FRAME_COLS,
>  not use FrameCols.
> 
> How about this:
> 
>    if (AutoWrap (tty)
>        && curY (tty) + 1 == FRAME_TOTAL_LINES (f)
> -      && curX (tty) + len == FRAME_COLS (f)
> +      && curX (tty) + len == FRAME_TOTAL_COLS (f)
>        && len > 0)
> 
> The width of the scroll bar is in FRAME_TOTAL_COLS already so this is nice and clean.

If you prefer that, okay.

>  OK. But maybe we don't need both the string and the width separately
>  customizable, since the string determines the width?
> 
> Not sure about that.  In X there is a scroll bar width, so it's logical to follow that.  The width is in pixels but in the
> tty, the width of a "pixel" is a character.  I think what I will try is if someone sets a string, 3 characters wide then
> I will default the width to 3.  However, if someone sets the width larger, I will just loop over and fill it out to that
> width.  For example if they set the width to 5, it would be like 12312 from the string "123".

I'm asking why do we need to allow customizing this via both the
string and the width?  If someone wants to have a wider scroll bar
than the characters in the string, they can always pad with blanks.

I do NOT argue with you that on the C level we need to maintain the
width separately.  The question is how it is determined.

> Now if someone
> uses a double-width unicode character in the string, that will affect the width for sure.

If you use lisp_string_width, it will account for double-width
characters as needed.

>  I didn't want this to get too overly complicated, you could go crazy
>  with unicode trying to define super fancy scroll thumbs and gutters but
>  i don't think it's worth it.
> 
>  The default should be ASCII characters, because these are always
>  supported. Fancier characters should be left to user customizations,
>  IMO.
> 
> 100% agree.  It's going to default to a string with a single SPC character and by default the thumb will be
> inverse-video of that string.  Though I guess I will also allow the user to define a scroll-bar-thumb string and use
> that in place of the SPC character for the thumb if defined.  That's as far as I would go.  If someone wants to
> extend this further and add a zillion settings to be able to paint fancy unicode scroll bars, they will have a good
> base to start from.

Thanks.




Information forwarded to bug-gnu-emacs@HIDDEN:
bug#80993; Package emacs. Full text available.

Message received at 80993 <at> debbugs.gnu.org:


Received: (at 80993) by debbugs.gnu.org; 14 Jun 2026 18:56:26 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Sun Jun 14 14:56:25 2026
Received: from localhost ([127.0.0.1]:34194 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1wYq0L-0001aw-6i
	for submit <at> debbugs.gnu.org; Sun, 14 Jun 2026 14:56:24 -0400
Received: from strange.networkguild.org ([2600:3c02:e000:dd::1]:56091)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <mgrant@HIDDEN>) id 1wYq0F-0001Zw-Lc
 for 80993 <at> debbugs.gnu.org; Sun, 14 Jun 2026 14:56:19 -0400
Received: from auth (localhost [127.0.0.1]) (authenticated bits=0)
 by strange.networkguild.org (8.18.1/8.18.1/Debian-6) with ESMTPSA id
 65EItxvR910128
 (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384 bits=256 verify=NOT);
 Sun, 14 Jun 2026 14:56:06 -0400
From: "Michael Grant" <mgrant@HIDDEN>
To: "Eli Zaretskii" <eliz@HIDDEN>
Subject: Re[2]: bug#80993: [PATCH] Add support for tty scroll-bars
Date: Sun, 14 Jun 2026 18:55:58 +0000
Message-Id: <ema4d265a8-02b4-4ed5-8298-d5387b0193c1@HIDDEN>
In-Reply-To: <864ij5mp52.fsf@HIDDEN>
References: <af36i-emhv7cCESf@HIDDEN> <86cxyv660l.fsf@HIDDEN>
 <em44ec92d2-646d-46d0-897c-2fe53f7d24d4@HIDDEN> <864ij5mp52.fsf@HIDDEN>
User-Agent: eMClient/10.4.0.0
MIME-Version: 1.0
Content-Type: multipart/alternative;
 boundary="------=_MBE8033CF7-4362-418F-BF62-629A1A3836F5"
X-Virus-Scanned: clamav-milter 1.4.3 at strange.networkguild.org
X-Virus-Status: Clean
X-Spam-Status: No, score=-99.0 required=5.0 autolearn=disabled
X-Spam-Report: *  -99 ALL_TRUSTED Passed through trusted hosts only via SMTP
 *  0.0 HTML_MESSAGE BODY: HTML included in message
X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-25) on
 strange.networkguild.org
X-Spam-Score: -0.0 (/)
X-Debbugs-Envelope-To: 80993
Cc: 80993 <at> debbugs.gnu.org, jared@HIDDEN
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Reply-To: Michael Grant <mgrant@HIDDEN>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)

--------=_MBE8033CF7-4362-418F-BF62-629A1A3836F5
Content-Type: text/plain; charset=utf-8; format=flowed
Content-Transfer-Encoding: quoted-printable

From "Eli Zaretskii"
To "Michael Grant"
Date 14/06/2026 11:45:29
>>  From: "Michael Grant"
>>  Date: Sat, 13 Jun 2026 21:18:20 +0000
>>
>>  >>  @@ -976,7 +983,7 @@ tty_write_glyphs (struct frame *f, struct glyph =
*string, int len)
>>  >>        since that would scroll the whole frame on some terminals.  *=
/
>>  >>     if (AutoWrap (tty)
>>  >>         && curY (tty) + 1 =3D=3D FRAME_TOTAL_LINES (f)
>>  >>  -      && curX (tty) + len =3D=3D FRAME_COLS (f)
>>  >>  +      && curX (tty) + len =3D=3D FrameCols (tty)
>>  >
>>  >Why was this needed?
>>  Without scrollbars, FRAME_COLS(f) and FrameCols(tty) are the same value=
,
>>  the frame text area fills the entire terminal width.  Needed to do
>>  because the scroll bar when on the right was incorrectly causing
>>  scrolling to happen.  This fixes that.
>
>I think it means we should add FRAME_SCROLL_BAR_COLS to FRAME_COLS,
>not use FrameCols.
How about this:

    if (AutoWrap (tty)
        && curY (tty) + 1 =3D=3D FRAME_TOTAL_LINES (f)
-      && curX (tty) + len =3D=3D FRAME_COLS (f)
+      && curX (tty) + len =3D=3D FRAME_TOTAL_COLS (f)
        && len > 0)

The width of the scroll bar is in FRAME_TOTAL_COLS already so this is=20
nice and clean.

>OK.  But maybe we don't need both the string and the width separately
>customizable, since the string determines the width?
Not sure about that.  In X there is a scroll bar width, so it's logical=20
to follow that.  The width is in pixels but in the tty, the width of a=20
"pixel" is a character.  I think what I will try is if someone sets a=20
string, 3 characters wide then I will default the width to 3.  However,=20
if someone sets the width larger, I will just loop over and fill it out=20
to that width.  For example if they set the width to 5, it would be like=20
12312 from the string "123".  Now if someone uses a double-width unicode=20
character in the string, that will affect the width for sure.


>>  I didn't want this to get too overly complicated, you could go crazy
>>  with unicode trying to define super fancy scroll thumbs and gutters but
>>  i don't think it's worth it.
>
>The default should be ASCII characters, because these are always
>supported.  Fancier characters should be left to user customizations,
>IMO.

100% agree.  It's going to default to a string with a single SPC=20
character and by default the thumb will be inverse-video of that string.=20
  Though I guess I will also allow the user to define a scroll-bar-thumb=20
string and use that in place of the SPC character for the thumb if=20
defined.  That's as far as I would go.  If someone wants to extend this=20
further and add a zillion settings to be able to paint fancy unicode=20
scroll bars, they will have a good base to start from.



--------=_MBE8033CF7-4362-418F-BF62-629A1A3836F5
Content-Type: text/html; charset=utf-8
Content-Transfer-Encoding: quoted-printable

<html><head>

<style id=3D"css_styles" type=3D"text/css"><!--blockquote.cite { margin-lef=
t: 5px; margin-right: 0px; padding-left: 10px; padding-right:0px; border-le=
ft: 1px solid #cccccc }
blockquote.cite2 {margin-left: 5px; margin-right: 0px; padding-left: 10px;=
 padding-right:0px; border-left: 1px solid #cccccc; margin-top: 3px; padding=
-top: 0px; }
a img { border: 0px; }
li[style=3D'text-align: center;'], li[style=3D'text-align: center; '], li[s=
tyle=3D'text-align: right;'], li[style=3D'text-align: right; '] {  list-sty=
le-position: inside;}
body { font-family: 'Segoe UI'; font-size: 12pt; }
.quote { margin-left: 1em; margin-right: 1em; border-left: 5px #ebebeb soli=
d; padding-left: 0.3em; }
a.em-mention[href] { text-decoration: none; color: inherit; border-radius:=
 3px; padding-left: 2px; padding-right: 2px; background-color: #e2e2e2; }
._em_placeholder {color: gray; border-bottom: 1px dotted lightblue;} ._em_p=
laceholder:before{color:gray; content: '{{ ';} ._em_placeholder:after{color=
:gray; content: ' }}';}
--></style></head><body class=3D"plain" style=3D""><div><span>From "Eli Zar=
etskii"=C2=A0</span></div><div>
<div>To "Michael Grant"</div>
<div><span>Date 14/06/2026 11:45:29</span></div></div>
<div id=3D"x40f2c8e031f0430"><blockquote type=3D"cite" class=3D"cite2">

<blockquote type=3D"cite" class=3D"cite">
<div class=3D"plain_line"> From: "Michael Grant" </div>
<div class=3D"plain_line"><span> Date: Sat, 13 Jun 2026 21:18:20 +0000</spa=
n></div>
<div class=3D"plain_line">=C2=A0</div>
<div class=3D"plain_line"> &gt;&gt;  @@ -976,7 +983,7 @@ tty_write_glyphs (=
struct frame *f, struct glyph *string, int len)</div>
<div class=3D"plain_line"> &gt;&gt;        since that would scroll the whol=
e frame on some terminals.  */</div>
<div class=3D"plain_line"> &gt;&gt;     if (AutoWrap (tty)</div>
<div class=3D"plain_line"> &gt;&gt;         &amp;&amp; curY (tty) + 1 =3D=
=3D FRAME_TOTAL_LINES (f)</div>
<div class=3D"plain_line"> &gt;&gt;  -      &amp;&amp; curX (tty) + len =3D=
=3D FRAME_COLS (f)</div>
<div class=3D"plain_line"> &gt;&gt;  +      &amp;&amp; curX (tty) + len =3D=
=3D FrameCols (tty)</div>
<div class=3D"plain_line"> &gt;</div>
<div class=3D"plain_line"> &gt;Why was this needed?</div>
<div class=3D"plain_line"> Without scrollbars, FRAME_COLS(f) and FrameCols(=
tty) are the same value,</div>
<div class=3D"plain_line"> the frame text area fills the entire terminal wi=
dth.  Needed to do</div>
<div class=3D"plain_line"> because the scroll bar when on the right was inc=
orrectly causing</div>
<div class=3D"plain_line"> scrolling to happen.  This fixes that.</div>
</blockquote>
<div class=3D"plain_line">=C2=A0</div>
<div class=3D"plain_line">I think it means we should add FRAME_SCROLL_BAR_C=
OLS to FRAME_COLS,</div>
<div class=3D"plain_line">not use FrameCols.</div></blockquote><span>How ab=
out this:</span></div><div id=3D"x40f2c8e031f0430"><br /></div><div id=3D"x=
40f2c8e031f0430">=C2=A0 =C2=A0if (AutoWrap (tty)</div><div id=3D"x40f2c8e03=
1f0430">=C2=A0 =C2=A0 =C2=A0 =C2=A0&amp;&amp; curY (tty) + 1 =3D=3D FRAME_T=
OTAL_LINES (f)</div><div id=3D"x40f2c8e031f0430">-=C2=A0 =C2=A0=C2=A0 =C2=
=A0&amp;&amp; curX (tty) + len =3D=3D FRAME_COLS (f)</div><div id=3D"x40f2c=
8e031f0430">+=C2=A0 =C2=A0=C2=A0 =C2=A0&amp;&amp; curX (tty) + len =3D=3D F=
RAME_TOTAL_COLS (f)</div><div id=3D"x40f2c8e031f0430">=C2=A0 =C2=A0 =C2=A0 =
=C2=A0&amp;&amp; len &gt;=C2=A00)</div><div id=3D"x40f2c8e031f0430"><br />=
</div><div id=3D"x40f2c8e031f0430">The width of the scroll bar is in FRAME_=
TOTAL_COLS already so this is nice and clean.</div><div id=3D"x40f2c8e031f0=
430"><br /><blockquote type=3D"cite" class=3D"cite2">
<div class=3D"plain_line">OK.  But maybe we don't need both the string and=
 the width separately</div>
<div class=3D"plain_line">customizable, since the string determines the wid=
th?</div></blockquote><span>Not sure about that.=C2=A0 In X there is a scro=
ll bar width, so it's logical to follow that.=C2=A0 The width is in pixels=
 but in the tty, the width of a "pixel" is a character.=C2=A0 I think what I =
will try is if someone sets a string, 3 characters wide then I will defaul=
t the width to 3.=C2=A0 However, if someone sets the width larger, I will j=
ust loop over and fill it out to that width.=C2=A0 For example if they set=
 the width to 5, it would be like 12312 from the string "123".=C2=A0 Now if=
 someone uses a double-width unicode character in the string, that will affe=
ct the width for sure.</span></div><div id=3D"x40f2c8e031f0430"><span><br /=
></span></div><div id=3D"x40f2c8e031f0430"><span>=C2=A0</span></div><div id=
=3D"x40f2c8e031f0430"><blockquote type=3D"cite" class=3D"cite2">
<blockquote type=3D"cite" class=3D"cite2">
<div class=3D"plain_line"> I didn't want this to get too overly complicated=
, you could go crazy</div>
<div class=3D"plain_line"> with unicode trying to define super fancy scroll =
thumbs and gutters but</div>
<div class=3D"plain_line"> i don't think it's worth it.</div>
</blockquote>
<div class=3D"plain_line">=C2=A0</div>
<div class=3D"plain_line">The default should be ASCII characters, because t=
hese are always</div>
<div class=3D"plain_line">supported.  Fancier characters should be left to=
 user customizations,</div>
<div class=3D"plain_line">IMO.</div></blockquote><span><div id=3D"x40f2c8e0=
31f0430"><span><br /></span></div>100% agree.=C2=A0 It's going to default t=
o a string with a single SPC character and by default the thumb will be inv=
erse-video of that string.=C2=A0 Though I guess I will also allow the user=
 to define a scroll-bar-thumb string and use that in place of the SPC charac=
ter for the thumb if defined.=C2=A0 That's as far as I would go.=C2=A0 If s=
omeone wants to extend this further and add a zillion settings to be able t=
o paint fancy unicode scroll bars, they will have a good base to start from=
.</span></div><div id=3D"x40f2c8e031f0430"><span><br /></span></div><div id=
=3D"x40f2c8e031f0430"><span><br /></span></div><div id=3D"x40f2c8e031f0430"=
><span>=C2=A0</span></div>
</body></html>
--------=_MBE8033CF7-4362-418F-BF62-629A1A3836F5--





Information forwarded to bug-gnu-emacs@HIDDEN:
bug#80993; Package emacs. Full text available.

Message received at 80993 <at> debbugs.gnu.org:


Received: (at 80993) by debbugs.gnu.org; 14 Jun 2026 09:45:45 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Sun Jun 14 05:45:45 2026
Received: from localhost ([127.0.0.1]:57337 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1wYhPV-0004Z9-9V
	for submit <at> debbugs.gnu.org; Sun, 14 Jun 2026 05:45:45 -0400
Received: from eggs.gnu.org ([2001:470:142:3::10]:38136)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <eliz@HIDDEN>) id 1wYhPS-0004Ym-BT
 for 80993 <at> debbugs.gnu.org; Sun, 14 Jun 2026 05:45:43 -0400
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <eliz@HIDDEN>)
 id 1wYhPJ-00077U-Tb; Sun, 14 Jun 2026 05:45:35 -0400
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=References:Subject:In-Reply-To:To:From:Date:
 mime-version; bh=6Q13rsoosywDoS//HhcAb3QOC4ClclXP/6NtUEcB4mc=; b=R6TOdVb+eeyt
 p74FoRu+/J/HmnOy3RlWaaylUWidAGPZhnQpULVWcmTcct9R9v9zw5i560kCbYCO61rexvVU1sZAY
 hBm18SmFCNEf8GG3bbY1lqflKuMWoIAmlNKNiRSGVEb4ehdcd6DKsbK27jLPZpc2vGJhf4JhnKE9b
 RGZf9rCk2i0diwJxcbzj4HT6dH2oeA8JLGxpR0HooLlKEQ2/P/2tPp7bcVFnryVFnjUaKGEf+Q5Iu
 gbCNRDNkSi4xPApe+nfOWw4XmQIxcr/wVXmNh0ShSrKNLJr90K9SITFGNDPTPkOuag9i3ofehra23
 Ix5SgEGvJlI5ZpEsdq7U9Q==;
Date: Sun, 14 Jun 2026 12:45:29 +0300
Message-Id: <864ij5mp52.fsf@HIDDEN>
From: Eli Zaretskii <eliz@HIDDEN>
To: "Michael Grant" <mgrant@HIDDEN>
In-Reply-To: <em44ec92d2-646d-46d0-897c-2fe53f7d24d4@HIDDEN>
 (mgrant@HIDDEN)
Subject: Re: bug#80993: [PATCH] Add support for tty scroll-bars
References: <af36i-emhv7cCESf@HIDDEN> <86cxyv660l.fsf@HIDDEN>
 <em44ec92d2-646d-46d0-897c-2fe53f7d24d4@HIDDEN>
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 80993
Cc: 80993 <at> debbugs.gnu.org, jared@HIDDEN
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

> From: "Michael Grant" <mgrant@HIDDEN>
> Cc: 80993 <at> debbugs.gnu.org
> Date: Sat, 13 Jun 2026 21:18:20 +0000
> 
> >>  @@ -976,7 +983,7 @@ tty_write_glyphs (struct frame *f, struct glyph *string, int len)
> >>        since that would scroll the whole frame on some terminals.  */
> >>     if (AutoWrap (tty)
> >>         && curY (tty) + 1 == FRAME_TOTAL_LINES (f)
> >>  -      && curX (tty) + len == FRAME_COLS (f)
> >>  +      && curX (tty) + len == FrameCols (tty)
> >
> >Why was this needed?
> Without scrollbars, FRAME_COLS(f) and FrameCols(tty) are the same value, 
> the frame text area fills the entire terminal width.  Needed to do 
> because the scroll bar when on the right was incorrectly causing 
> scrolling to happen.  This fixes that.

I think it means we should add FRAME_SCROLL_BAR_COLS to FRAME_COLS,
not use FrameCols.

> >And I have several more questions:
> >
> >   . where are the glyphs defined that are used to draw the TTY
> >     scroll-bar and its thumb? it sounds like they are always SPC
> >     characters with a special face, is that right?
> Yes, it's very minimalist.  The scroll bar itself (the gutter) is a 
> single SPC character and the thumb is an inverse SPC.  It's hardwired as 
> ' ' in dispnew.c:4103.
> 
> I will change this and make this configurable in scroll-bar.el and add 
> some defcustoms there.  I will also add a config for the width of the 
> scroll bar.

OK.  But maybe we don't need both the string and the width separately
customizable, since the string determines the width?

> I didn't want this to get too overly complicated, you could go crazy 
> with unicode trying to define super fancy scroll thumbs and gutters but 
> i don't think it's worth it.

The default should be ASCII characters, because these are always
supported.  Fancier characters should be left to user customizations,
IMO.

> Good comments, thank you!  Working on the lisp file with devon and will 
> get the character change above in, want to work through the rest of the 
> comments and fix some other things and will post full patch again.

Thanks.




Information forwarded to bug-gnu-emacs@HIDDEN:
bug#80993; Package emacs. Full text available.

Message received at 80993 <at> debbugs.gnu.org:


Received: (at 80993) by debbugs.gnu.org; 14 Jun 2026 05:08:16 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Sun Jun 14 01:08:16 2026
Received: from localhost ([127.0.0.1]:55569 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1wYd4x-0003mW-LC
	for submit <at> debbugs.gnu.org; Sun, 14 Jun 2026 01:08:15 -0400
Received: from strange.networkguild.org ([2600:3c02:e000:dd::1]:38915)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <mgrant@HIDDEN>) id 1wYd4u-0003mB-MZ
 for 80993 <at> debbugs.gnu.org; Sun, 14 Jun 2026 01:08:14 -0400
Received: from auth (localhost [127.0.0.1]) (authenticated bits=0)
 by strange.networkguild.org (8.18.1/8.18.1/Debian-6) with ESMTPSA id
 65E57vqr773490
 (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384 bits=256 verify=NOT);
 Sun, 14 Jun 2026 01:08:04 -0400
From: "Michael Grant" <mgrant@HIDDEN>
To: "Eli Zaretskii" <eliz@HIDDEN>, "Jared Finder" <jared@HIDDEN>
Subject: Re[2]: bug#80993: [PATCH] Add support for tty scroll-bars
Date: Sun, 14 Jun 2026 05:07:55 +0000
Message-Id: <eme107d0e9-4100-4ee9-adec-55e0d0965768@HIDDEN>
In-Reply-To: <86ldcsko7u.fsf@HIDDEN>
References: <af36i-emhv7cCESf@HIDDEN> <86cxyv660l.fsf@HIDDEN>
 <fe8b6d3d49ec4eb84acd8b17f164d199@HIDDEN> <86ldcsko7u.fsf@HIDDEN>
User-Agent: eMClient/10.4.0.0
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8; format=flowed
Content-Transfer-Encoding: quoted-printable
X-Virus-Scanned: clamav-milter 1.4.3 at strange.networkguild.org
X-Virus-Status: Clean
X-Spam-Status: No, score=-99.0 required=5.0 autolearn=disabled
X-Spam-Report: *  -99 ALL_TRUSTED Passed through trusted hosts only via SMTP
X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-25) on
 strange.networkguild.org
X-Spam-Score: -0.0 (/)
X-Debbugs-Envelope-To: 80993
Cc: 80993 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Reply-To: Michael Grant <mgrant@HIDDEN>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)

Currently the tty scroll-bar calculates the thumb height based on the=20
percentage of the buffer in the frame rather than the percentage of the=20
number of lines of the buffer being displayed.  It appears that the GUI=20
scroll-bars are also a percentage of the buffer based on number of=20
characters--not lines.

So technically there is no real bug in the current tty scroll bar thumb=20
calculation.  It is just a bit more apparent what the scroll-bar is=20
doing in smaller buffers where some lines are more dense than others. =20
Also, since the tty scroll bars are character based rather than pixel=20
based, it becomes a bit more apparent.

But to be honest, I have now been using this for a few months and I=20
rarely notice it.  Technically, in my opinion, scroll bars should=20
percentage of lines not characters.

Unless you tell me to change the calculation for just the tty scroll=20
bars, I am just going to leave it alone for now.  Maybe we can do a=20
separate change later to change both the gui and tty scroll bar=20
calculations to be line based later.

I am trying to address Jared's comments next.




Information forwarded to bug-gnu-emacs@HIDDEN:
bug#80993; Package emacs. Full text available.

Message received at 80993 <at> debbugs.gnu.org:


Received: (at 80993) by debbugs.gnu.org; 13 Jun 2026 21:18:43 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Sat Jun 13 17:18:43 2026
Received: from localhost ([127.0.0.1]:52977 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1wYVkY-0007Yn-R4
	for submit <at> debbugs.gnu.org; Sat, 13 Jun 2026 17:18:43 -0400
Received: from strange.networkguild.org ([2600:3c02:e000:dd::1]:55349)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <mgrant@HIDDEN>) id 1wYVkU-0007YU-8f
 for 80993 <at> debbugs.gnu.org; Sat, 13 Jun 2026 17:18:39 -0400
Received: from auth (localhost [127.0.0.1]) (authenticated bits=0)
 by strange.networkguild.org (8.18.1/8.18.1/Debian-6) with ESMTPSA id
 65DLIL7W713110
 (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384 bits=256 verify=NOT);
 Sat, 13 Jun 2026 17:18:28 -0400
From: "Michael Grant" <mgrant@HIDDEN>
To: "Eli Zaretskii" <eliz@HIDDEN>, "Jared Finder" <jared@HIDDEN>
Subject: Re[2]: bug#80993: [PATCH] Add support for tty scroll-bars
Date: Sat, 13 Jun 2026 21:18:20 +0000
Message-Id: <em44ec92d2-646d-46d0-897c-2fe53f7d24d4@HIDDEN>
In-Reply-To: <86cxyv660l.fsf@HIDDEN>
References: <af36i-emhv7cCESf@HIDDEN> <86cxyv660l.fsf@HIDDEN>
User-Agent: eMClient/10.4.0.0
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8; format=flowed
Content-Transfer-Encoding: quoted-printable
X-Virus-Scanned: clamav-milter 1.4.3 at strange.networkguild.org
X-Virus-Status: Clean
X-Spam-Status: No, score=-99.0 required=5.0 autolearn=disabled
X-Spam-Report: *  -99 ALL_TRUSTED Passed through trusted hosts only via SMTP
X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-25) on
 strange.networkguild.org
X-Spam-Score: -0.0 (/)
X-Debbugs-Envelope-To: 80993
Cc: 80993 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Reply-To: Michael Grant <mgrant@HIDDEN>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)

I will have to answer this in parts.  First this.
>
>>  @@ -976,7 +983,7 @@ tty_write_glyphs (struct frame *f, struct glyph *st=
ring, int len)
>>        since that would scroll the whole frame on some terminals.  */
>>     if (AutoWrap (tty)
>>         && curY (tty) + 1 =3D=3D FRAME_TOTAL_LINES (f)
>>  -      && curX (tty) + len =3D=3D FRAME_COLS (f)
>>  +      && curX (tty) + len =3D=3D FrameCols (tty)
>
>Why was this needed?
Without scrollbars, FRAME_COLS(f) and FrameCols(tty) are the same value,=20
the frame text area fills the entire terminal width.  Needed to do=20
because the scroll bar when on the right was incorrectly causing=20
scrolling to happen.  This fixes that.
>
>
>And I have several more questions:
>
>   . where are the glyphs defined that are used to draw the TTY
>     scroll-bar and its thumb? it sounds like they are always SPC
>     characters with a special face, is that right?
Yes, it's very minimalist.  The scroll bar itself (the gutter) is a=20
single SPC character and the thumb is an inverse SPC.  It's hardwired as=20
' ' in dispnew.c:4103.

I will change this and make this configurable in scroll-bar.el and add=20
some defcustoms there.  I will also add a config for the width of the=20
scroll bar.

I didn't want this to get too overly complicated, you could go crazy=20
with unicode trying to define super fancy scroll thumbs and gutters but=20
i don't think it's worth it.  I could define a top, middle, and bottom=20
if you like...ahh but what happens when the thumb goes to a single=20
character high?  yah i remember now, Devon and I went around on this and=20
simplicity won!  But I will at minimum do width and let the user set a=20
string for the thumb instead of a single space.

the  SCROLL_BAR_FACE_ID and SCROLL_BAR_THUMB_FACE_ID are defined in=20
lisp/faces.el:2935-2952:

(defface scroll-bar
   '((((type tty)) :background "black")
     (t nil))
   "Basic face for the scroll bar colors under X.
On TTY frames, this face determines the appearance of the scroll bar
gutter (track).  The default TTY appearance is a black background."
   :version "21.1"
   :group 'frames
   :group 'basic-faces)

(defface scroll-bar-thumb
   '((((type tty)) :inverse-video t)
     (t nil))
   "Basic face for the scroll bar thumb (draggable portion) in TTY=20
frames.
On character-based terminals, the thumb is rendered as inverse-video=20
spaces."
   :version "30.1"
   :group 'frames
   :group 'basic-faces)

and of course these are tied together:
   realize_named_face (f, Qscroll_bar,       SCROLL_BAR_FACE_ID);
   realize_named_face (f, Qscroll_bar_thumb, SCROLL_BAR_THUMB_FACE_ID);

>
>   . since the scroll bar takes up another column of each window's
>     screen line, shouldn't we make last_visible_x set up in
>     init_iterator by one? otherwise, a long enough line could
>     overwrite the scroll-bar glyphs, no?
no, i don't think so.   window_box_width at xdisp.c:1285 has this:
       width -=3D WINDOW_SCROLL_BAR_AREA_WIDTH (w);
  So body_width already excludes the scrollbar column, and last_visible_x=
=20
at line 3507 is correctly bounded before the scrollbar starts.
>
>   . similarly, shouldn't append_glyph avoid adding glyphs past the
>     scroll-bar? e.g., did you try displaying a buffer with wide
>     characters, those which take more than 1 column, when the line is
>     long enough to reach the right edge of the window?
also no, this is taken care of.by 2 independent layers:

Layer 1: last_visible_x: As established, window_box_width subtracts=20
WINDOW_SCROLL_BAR_AREA_WIDTH, so last_visible_x  already stops before=20
the scrollbar column.  So no text glyph can legitimately land in the=20
scrollbar column via the normal display path.

Layer 2: tty_apply_scroll_bar_glyphs: Even if something slipped through,=20
this function runs after build_frame_matrix and unconditionally=20
overwrites the scrollbar column in every frame row with the=20
scrollbar/thumb glyphs. It's a hard stomp regardless of what text=20
rendering put there.

So append_glyph itself needs no change, it never checks last_visible_x=20
(that's the display loop's job), and the display loop already has the=20
scrollbar excluded from the boundary it enforces.
>
>
>And finally, would people please try this patch and report back any
>issues they find with the code?
>
>Thanks.
>
Good comments, thank you!  Working on the lisp file with devon and will=20
get the character change above in, want to work through the rest of the=20
comments and fix some other things and will post full patch again.




Information forwarded to bug-gnu-emacs@HIDDEN:
bug#80993; Package emacs. Full text available.

Message received at 80993 <at> debbugs.gnu.org:


Received: (at 80993) by debbugs.gnu.org; 6 Jun 2026 09:33:39 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Sat Jun 06 05:33:39 2026
Received: from localhost ([127.0.0.1]:36123 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1wVnPO-0008KF-MB
	for submit <at> debbugs.gnu.org; Sat, 06 Jun 2026 05:33:39 -0400
Received: from eggs.gnu.org ([2001:470:142:3::10]:33924)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <eliz@HIDDEN>) id 1wVnPM-0008Jr-4r
 for 80993 <at> debbugs.gnu.org; Sat, 06 Jun 2026 05:33:37 -0400
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <eliz@HIDDEN>)
 id 1wVnPE-0006Q4-Sg; Sat, 06 Jun 2026 05:33:28 -0400
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-version:References:Subject:In-Reply-To:To:From:
 Date; bh=CrXiC+0VQ4sfcDpp+Rquk4jkvEQ3CRYtc4H+F3fEhPg=; b=iSbosotT0kI7XcTuFAgP
 I6OSKjqjhGLNtQlbo6wLUxfPbXYoGFh/SHQj8xHZi3RLUmjyU3UhQdHwCOpZJERiQs3oXgELBl5dr
 2HqlpPksUAs2k6CeBa8I146LTuPOFuG1jJL+F2LcVu49jb0LxzRwz6+Pg+522YiNzx9XgH2rVyp/5
 ICZDR9nVzFRDMUiG5Rfh2GfC4shCgM2YHNhly1RDqTdTcZyzjHZRJqcfcjxbWUF297R4xVl8wKvkg
 H9rGs4CoerMCDAK7LrbphoHlC9UK94S/gwJujKI9mcfcO6Z+pk3Tt0nLjIi8Ujz/SAAs0ZSsgDwKw
 v1RBmahIwFTAmw==;
Date: Sat, 06 Jun 2026 12:33:25 +0300
Message-Id: <86ldcsko7u.fsf@HIDDEN>
From: Eli Zaretskii <eliz@HIDDEN>
To: mgrant@HIDDEN, Jared Finder <jared@HIDDEN>
In-Reply-To: <fe8b6d3d49ec4eb84acd8b17f164d199@HIDDEN> (message from Jared
 Finder on Sun, 17 May 2026 18:56:29 -0700)
Subject: Re: bug#80993: [PATCH] Add support for tty scroll-bars
References: <af36i-emhv7cCESf@HIDDEN> <86cxyv660l.fsf@HIDDEN>
 <fe8b6d3d49ec4eb84acd8b17f164d199@HIDDEN>
MIME-version: 1.0
Content-type: text/plain; charset=utf-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 80993
Cc: 80993 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

Ping!  Micheal, can you please chime in and respond to the comments, so
we could make progress in preparing this feature for installation?

> Date: Sun, 17 May 2026 18:56:29 -0700
> From: Jared Finder <jared@HIDDEN>
> Cc: Michael Grant <mgrant@HIDDEN>, 80993 <at> debbugs.gnu.org
> 
> On 2026-05-16 02:46, Eli Zaretskii wrote:
> >> Date: Fri, 8 May 2026 11:00:27 -0400
> >> From:  Michael Grant via "Bug reports for GNU Emacs,
> >>  the Swiss army knife of text editors" <bug-gnu-emacs@HIDDEN>
> >> 
> >> This is a feature patch which implements tty based scroll-bars which
> >> mimick the X-windows toolkit scrollbars.  It reserves a column on the
> >> left or right (configurable) for the scroll-bar.  The scroll-bar thumb
> >> is composed of inverse video white spaces and the scroll-bar gutter 
> >> dark
> >> spaces.  The scroll-bar thumb is draggable and clicking above or below
> >> the scroll-bar scrolls the buffer.
> > 
> > Thanks, a few comments below.
> 
> Some additional comments.
> 
> +(defface scroll-bar-thumb
> +  '((((type tty)) :inverse-video t)
> +    (t nil))
> +  "Basic face for the scroll bar thumb (draggable portion) in TTY 
> frames.
> +On character-based terminals, the thumb is rendered as inverse-video 
> spaces."
> +  :version "30.1"
> +  :group 'frames
> +  :group 'basic-faces)
> 
> I think it would be better to have the face definition have the same 
> meaning as under X, where the scroll-bar face's foreground color is the 
> color of the thumb and the background is the color of the track.  This 
> additional face is unnecessary.
> 
> >> --- a/lisp/mouse.el
> >> +++ b/lisp/mouse.el
> >> @@ -865,7 +865,16 @@ mouse-position-for-drag-line
> >>  relative to the selected frame, unless the current drag operation was
> >>  produced from a touch screen event, in which event, return the 
> >> position
> >>  of the active touch-screen tool relative to the same."
> >> -  (if tty (mouse-position-in-root-frame)
> >> +  (if tty
> >> +      ;; mouse-position-in-root-frame reads from the GPM mouse hook,
> >> +      ;; which is not updated by xterm mouse events.  When xterm 
> >> mouse
> >> +      ;; mode is active the coordinates are stored as terminal 
> >> parameters
> >> +      ;; by xterm-mouse-event; use those when available.
> >> +      (let ((xt-x (terminal-parameter nil 'xterm-mouse-x))
> >> +            (xt-y (terminal-parameter nil 'xterm-mouse-y)))
> >> +        (if (and xt-x xt-y)
> >> +            (cons xt-x xt-y)
> >> +          (mouse-position-in-root-frame)))
> > 
> > Jared, any comments?  Would it be cleaner to update xtmouse such that
> > mouse_position_hook works for it?  Or some other way of supporting
> > mouse-position-in-root-frame on xtmouse?
> 
> I don't think this change is needed. Local experimentation shows that 
> mouse-position-in-root-frame properly reports mouse coordinates when 
> xterm-mouse-mode is enabled. This is because xterm-mouse-mode sets 
> mouse-position-function to xterm-mouse-position-function which does 
> exactly this transformation.
> 
> What am I missing here?
> 
> +  (let* ((start-pos    (event-start event))
> +         (window       (nth 0 start-pos))
> +         (click-sb-row (car (nth 2 start-pos)))
> 
> Here, and in other places throughout this patch nth is used instead of 
> the posn utility functions like posn-window, posn-x-y, etc.  I believe 
> the posn utility functions are preferred stylistically.
> 
> +(defun xterm-mouse--tty-scroll-bar-window (x y frame)
> +  "Return the window whose TTY scroll bar column is at frame column X, 
> row Y.
> +Returns nil if no TTY scroll bar occupies position (X, Y)."
> +  (let ((sb-side (frame-parameter frame 'vertical-scroll-bars))
> +        result)
> +    (when sb-side
> +      (walk-windows
> ... and a bunch of code ...
> 
> Can this just use window-at instead to get the specific window? And it 
> would be nice if the function coordinates_in_window properly detected 
> the scroll bar, in which case you could add a parameter to 
> coordinates-in-window-p that allows it to return scroll bar areas.  For 
> backward compat it currently returns nil when passed scrollbar 
> coordinates.
> 
> +(defun xterm-mouse--tty-vertical-border-window (x y frame)
> +  "Return the window whose TTY `|' border column is at frame column X, 
> row Y.
> +Returns nil unless (X, Y) is on the `|' border of a non-rightmost TTY
> +window with a right scroll bar.  In that layout, [content][SB][|], the
> +`|' occupies the last column of the window's total-width allocation."
> ... and a bunch of code ...
> 
> Could this be replaced with:
> 
> (eq (coordinates-in-window-p (cons x y) (window-at x y frame)
>      'vertical-line)
> 
> +(defun xterm-mouse--tty-scroll-bar-part (window y)
> +  "Return the scroll bar part clicked at terminal row Y for WINDOW.
> +Returns one of the symbols `above-handle', `handle', or 
> `below-handle'."
> 
> This appears to be a copy of code added in 
> tty_apply_scroll_bar_glyphs_for_window.  I would prefer that be 
> extracted out to a utility function that xt-mouse.el can call instead so 
> we do not need to duplicate code in both xt-mouse.el and in C.
> 
> @@ -341,6 +431,59 @@ xterm-mouse-event
>   				  frame)
>   				item)
>   			  (nthcdr 2 (posn-at-x-y x y (selected-frame)))))))
> +             ;; Check for a click in a TTY vertical scroll bar column.
> +             ;; When detected, replace the position with a scroll bar
> +             ;; position so that [vertical-scroll-bar mouse-N] bindings 
> fire.
> +             (sb-window (and (not (display-graphic-p))
> +                             frame
> +                             (not (eq type 'mouse-movement))
> +                             (xterm-mouse--tty-scroll-bar-window x y 
> frame)))
> 
> I think the changes above could dramatically simplify this case.
> 
> +             (posn (if sb-window
> 
> posn was just bound above. It would be better to put this code into the 
> logic for constructing the posn.  There's already significant logic 
> looking at the x/y coordinate an calculating the window part from there.
> 
> +                       (let* ((win-ht  (window-body-height sb-window))
> +                              (win-top (window-top-line sb-window))
> +                              (sb-row  (max 0 (min (1- win-ht) (- y 
> win-top))))
> +                              (part    
> (xterm-mouse--tty-scroll-bar-part
> +                                        sb-window y))
> +                              ;; For button-up events: if the drag 
> started on
> +                              ;; the scroll-bar handle, keep 
> part='handle' so
> +                              ;; scroll-bar-drag-1 proportionally 
> scrolls to
> +                              ;; the release position rather than 
> paging.
> +                              (down-ev  (terminal-parameter
> +                                         nil 'xterm-mouse-last-down))
> +                              (down-part (and down-ev
> +                                             (nth 4 (nth 1 down-ev))))
> +                              (part     (if (and (not (string-prefix-p
> +                                                       "down-"
> +                                                       (symbol-name 
> type)))
> +                                                 (eq down-part 
> 'handle))
> +                                            'handle
> 
> I do not think it is a good idea to make tty mouse return different 
> events than the graphical mouse.  I would instead suggest you figure out 
> what part of the scroll bar is clicked inside scroll-bar-toolkit-scroll.
> 
> +                                          part)))
> +                         ;; Build a scroll-bar position in the same 
> format as
> +                         ;; make_scroll_bar_position in keyboard.c:
> +                         ;;   (window AREA (pos . size) timestamp part)
> +                         ;; AREA must be the bare symbol 
> `vertical-scroll-bar'
> +                         ;; (not a cons) so that read_key_sequence's 
> SYMBOLP
> +                         ;; check expands the event to 
> [vertical-scroll-bar
> +                         ;; mouse-1], which fires 
> `scroll-bar-toolkit-scroll'.
> +                         (list sb-window
> +                               'vertical-scroll-bar
> +                               (cons sb-row win-ht)
> +                               timestamp
> +                               part))
> +                     posn))
> +             ;; Check for a click on the TTY '|' window border.
> +             ;; For a right scroll bar on a non-rightmost TTY window 
> the '|'
> +             ;; glyph occupies the last column of the window 
> allocation; a
> +             ;; click there should generate a vertical-line position so 
> that
> +             ;; [vertical-line down-mouse-1] → mouse-drag-vertical-line 
> fires.
> +             (border-window (and (not sb-window)
> +                                 frame
> +                                 (not (eq type 'mouse-movement))
> +                                 
> (xterm-mouse--tty-vertical-border-window
> +                                  x y frame)))
> +             (posn (if border-window
> +                       (list border-window 'vertical-line (cons x y) 
> timestamp)
> +                     posn))
>                (event (list type posn)))
>           (setcar (nthcdr 3 posn) timestamp)
> 
> Overall, I suspect the above code can be made much simpler if it used 
> the above suggestions, especially moving to the existing functions that 
> already determine what part of a window a coordinate is in.
> 
>    -- MJF
> 




Information forwarded to bug-gnu-emacs@HIDDEN:
bug#80993; Package emacs. Full text available.

Message received at 80993 <at> debbugs.gnu.org:


Received: (at 80993) by debbugs.gnu.org; 18 May 2026 01:56:42 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Sun May 17 21:56:41 2026
Received: from localhost ([127.0.0.1]:51076 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1wOnDh-0001Hw-Id
	for submit <at> debbugs.gnu.org; Sun, 17 May 2026 21:56:41 -0400
Received: from greenhill.hpalace.com ([192.155.80.58]:53064)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <jared@HIDDEN>) id 1wOnDa-0001Gq-O2
 for 80993 <at> debbugs.gnu.org; Sun, 17 May 2026 21:56:34 -0400
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=finder.org; s=2018;
 t=1779069389; bh=DJUMTHz8e0RPwBSpTUn+bsfyHgzz/WVK1nHlBgHUgig=;
 h=Date:From:To:Cc:Subject:In-Reply-To:References:From;
 b=T7gzfT85MHSBqMBpnIyJjoeWdJUXV2LP8GwEKXbGFawa1bSq6pGrXgv8s9i8ShkGl
 MkyLvo1Z02K/trX1TapffTcM5GhVmJwgljaCwYBFv/DPSJKQedloHgNVhHp3hdo3Jr
 4rl56/RYaxle9VIPFT0De5syKuDfmTUHb/v7kMbqnY5P40bVZowbCJGYCb1gpRKsUn
 BzHHsKr3roabu60pmy8ImnUmLWnbwbwrPtlahdBB6s0kW+EWoyEh6Q7Z62IuvypFFl
 uAwEiaS151qEl9VphdaZa+Uuoislgr2LWpKHXTwygsJwbj9WJvW8DCTmP2f3DxU773
 YJjH/yHvz7xUw==
Received: from mail.finder.org (unknown [192.155.80.58])
 by greenhill.hpalace.com (Postfix) with ESMTPSA id 5321470A;
 Mon, 18 May 2026 01:56:29 +0000 (UTC)
MIME-Version: 1.0
Date: Sun, 17 May 2026 18:56:29 -0700
From: Jared Finder <jared@HIDDEN>
To: Eli Zaretskii <eliz@HIDDEN>
Subject: Re: bug#80993: [PATCH] Add support for tty scroll-bars
In-Reply-To: <86cxyv660l.fsf@HIDDEN>
References: <af36i-emhv7cCESf@HIDDEN> <86cxyv660l.fsf@HIDDEN>
Message-ID: <fe8b6d3d49ec4eb84acd8b17f164d199@HIDDEN>
X-Sender: jared@HIDDEN
Content-Type: text/plain; charset=UTF-8;
 format=flowed
Content-Transfer-Encoding: 8bit
X-Spam-Score: 0.0 (/)
X-Debbugs-Envelope-To: 80993
Cc: 80993 <at> debbugs.gnu.org, Michael Grant <mgrant@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)

On 2026-05-16 02:46, Eli Zaretskii wrote:
>> Date: Fri, 8 May 2026 11:00:27 -0400
>> From:  Michael Grant via "Bug reports for GNU Emacs,
>>  the Swiss army knife of text editors" <bug-gnu-emacs@HIDDEN>
>> 
>> This is a feature patch which implements tty based scroll-bars which
>> mimick the X-windows toolkit scrollbars.  It reserves a column on the
>> left or right (configurable) for the scroll-bar.  The scroll-bar thumb
>> is composed of inverse video white spaces and the scroll-bar gutter 
>> dark
>> spaces.  The scroll-bar thumb is draggable and clicking above or below
>> the scroll-bar scrolls the buffer.
> 
> Thanks, a few comments below.

Some additional comments.

+(defface scroll-bar-thumb
+  '((((type tty)) :inverse-video t)
+    (t nil))
+  "Basic face for the scroll bar thumb (draggable portion) in TTY 
frames.
+On character-based terminals, the thumb is rendered as inverse-video 
spaces."
+  :version "30.1"
+  :group 'frames
+  :group 'basic-faces)

I think it would be better to have the face definition have the same 
meaning as under X, where the scroll-bar face's foreground color is the 
color of the thumb and the background is the color of the track.  This 
additional face is unnecessary.

>> --- a/lisp/mouse.el
>> +++ b/lisp/mouse.el
>> @@ -865,7 +865,16 @@ mouse-position-for-drag-line
>>  relative to the selected frame, unless the current drag operation was
>>  produced from a touch screen event, in which event, return the 
>> position
>>  of the active touch-screen tool relative to the same."
>> -  (if tty (mouse-position-in-root-frame)
>> +  (if tty
>> +      ;; mouse-position-in-root-frame reads from the GPM mouse hook,
>> +      ;; which is not updated by xterm mouse events.  When xterm 
>> mouse
>> +      ;; mode is active the coordinates are stored as terminal 
>> parameters
>> +      ;; by xterm-mouse-event; use those when available.
>> +      (let ((xt-x (terminal-parameter nil 'xterm-mouse-x))
>> +            (xt-y (terminal-parameter nil 'xterm-mouse-y)))
>> +        (if (and xt-x xt-y)
>> +            (cons xt-x xt-y)
>> +          (mouse-position-in-root-frame)))
> 
> Jared, any comments?  Would it be cleaner to update xtmouse such that
> mouse_position_hook works for it?  Or some other way of supporting
> mouse-position-in-root-frame on xtmouse?

I don't think this change is needed. Local experimentation shows that 
mouse-position-in-root-frame properly reports mouse coordinates when 
xterm-mouse-mode is enabled. This is because xterm-mouse-mode sets 
mouse-position-function to xterm-mouse-position-function which does 
exactly this transformation.

What am I missing here?

+  (let* ((start-pos    (event-start event))
+         (window       (nth 0 start-pos))
+         (click-sb-row (car (nth 2 start-pos)))

Here, and in other places throughout this patch nth is used instead of 
the posn utility functions like posn-window, posn-x-y, etc.  I believe 
the posn utility functions are preferred stylistically.

+(defun xterm-mouse--tty-scroll-bar-window (x y frame)
+  "Return the window whose TTY scroll bar column is at frame column X, 
row Y.
+Returns nil if no TTY scroll bar occupies position (X, Y)."
+  (let ((sb-side (frame-parameter frame 'vertical-scroll-bars))
+        result)
+    (when sb-side
+      (walk-windows
... and a bunch of code ...

Can this just use window-at instead to get the specific window? And it 
would be nice if the function coordinates_in_window properly detected 
the scroll bar, in which case you could add a parameter to 
coordinates-in-window-p that allows it to return scroll bar areas.  For 
backward compat it currently returns nil when passed scrollbar 
coordinates.

+(defun xterm-mouse--tty-vertical-border-window (x y frame)
+  "Return the window whose TTY `|' border column is at frame column X, 
row Y.
+Returns nil unless (X, Y) is on the `|' border of a non-rightmost TTY
+window with a right scroll bar.  In that layout, [content][SB][|], the
+`|' occupies the last column of the window's total-width allocation."
... and a bunch of code ...

Could this be replaced with:

(eq (coordinates-in-window-p (cons x y) (window-at x y frame)
     'vertical-line)

+(defun xterm-mouse--tty-scroll-bar-part (window y)
+  "Return the scroll bar part clicked at terminal row Y for WINDOW.
+Returns one of the symbols `above-handle', `handle', or 
`below-handle'."

This appears to be a copy of code added in 
tty_apply_scroll_bar_glyphs_for_window.  I would prefer that be 
extracted out to a utility function that xt-mouse.el can call instead so 
we do not need to duplicate code in both xt-mouse.el and in C.

@@ -341,6 +431,59 @@ xterm-mouse-event
  				  frame)
  				item)
  			  (nthcdr 2 (posn-at-x-y x y (selected-frame)))))))
+             ;; Check for a click in a TTY vertical scroll bar column.
+             ;; When detected, replace the position with a scroll bar
+             ;; position so that [vertical-scroll-bar mouse-N] bindings 
fire.
+             (sb-window (and (not (display-graphic-p))
+                             frame
+                             (not (eq type 'mouse-movement))
+                             (xterm-mouse--tty-scroll-bar-window x y 
frame)))

I think the changes above could dramatically simplify this case.

+             (posn (if sb-window

posn was just bound above. It would be better to put this code into the 
logic for constructing the posn.  There's already significant logic 
looking at the x/y coordinate an calculating the window part from there.

+                       (let* ((win-ht  (window-body-height sb-window))
+                              (win-top (window-top-line sb-window))
+                              (sb-row  (max 0 (min (1- win-ht) (- y 
win-top))))
+                              (part    
(xterm-mouse--tty-scroll-bar-part
+                                        sb-window y))
+                              ;; For button-up events: if the drag 
started on
+                              ;; the scroll-bar handle, keep 
part='handle' so
+                              ;; scroll-bar-drag-1 proportionally 
scrolls to
+                              ;; the release position rather than 
paging.
+                              (down-ev  (terminal-parameter
+                                         nil 'xterm-mouse-last-down))
+                              (down-part (and down-ev
+                                             (nth 4 (nth 1 down-ev))))
+                              (part     (if (and (not (string-prefix-p
+                                                       "down-"
+                                                       (symbol-name 
type)))
+                                                 (eq down-part 
'handle))
+                                            'handle

I do not think it is a good idea to make tty mouse return different 
events than the graphical mouse.  I would instead suggest you figure out 
what part of the scroll bar is clicked inside scroll-bar-toolkit-scroll.

+                                          part)))
+                         ;; Build a scroll-bar position in the same 
format as
+                         ;; make_scroll_bar_position in keyboard.c:
+                         ;;   (window AREA (pos . size) timestamp part)
+                         ;; AREA must be the bare symbol 
`vertical-scroll-bar'
+                         ;; (not a cons) so that read_key_sequence's 
SYMBOLP
+                         ;; check expands the event to 
[vertical-scroll-bar
+                         ;; mouse-1], which fires 
`scroll-bar-toolkit-scroll'.
+                         (list sb-window
+                               'vertical-scroll-bar
+                               (cons sb-row win-ht)
+                               timestamp
+                               part))
+                     posn))
+             ;; Check for a click on the TTY '|' window border.
+             ;; For a right scroll bar on a non-rightmost TTY window 
the '|'
+             ;; glyph occupies the last column of the window 
allocation; a
+             ;; click there should generate a vertical-line position so 
that
+             ;; [vertical-line down-mouse-1] → mouse-drag-vertical-line 
fires.
+             (border-window (and (not sb-window)
+                                 frame
+                                 (not (eq type 'mouse-movement))
+                                 
(xterm-mouse--tty-vertical-border-window
+                                  x y frame)))
+             (posn (if border-window
+                       (list border-window 'vertical-line (cons x y) 
timestamp)
+                     posn))
               (event (list type posn)))
          (setcar (nthcdr 3 posn) timestamp)

Overall, I suspect the above code can be made much simpler if it used 
the above suggestions, especially moving to the existing functions that 
already determine what part of a window a coordinate is in.

   -- MJF




Information forwarded to bug-gnu-emacs@HIDDEN:
bug#80993; Package emacs. Full text available.

Message received at 80993 <at> debbugs.gnu.org:


Received: (at 80993) by debbugs.gnu.org; 16 May 2026 09:47:09 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Sat May 16 05:47:09 2026
Received: from localhost ([127.0.0.1]:56528 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1wOBbw-00048u-Vi
	for submit <at> debbugs.gnu.org; Sat, 16 May 2026 05:47:09 -0400
Received: from eggs.gnu.org ([2001:470:142:3::10]:54274)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <eliz@HIDDEN>) id 1wOBbu-00048M-JO
 for 80993 <at> debbugs.gnu.org; Sat, 16 May 2026 05:47:07 -0400
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <eliz@HIDDEN>)
 id 1wOBbn-0000oA-EN; Sat, 16 May 2026 05:46:59 -0400
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=References:Subject:In-Reply-To:To:From:Date:
 mime-version; bh=vELxjSR+O5eGuDvvpigw0HSl56QoMoOoGcorxbthjsw=; b=pzuTBiLQf13H
 EkOrhHTDW9txMJ8RykDn/+cWJlOm6vcS9gVGE5nM0/JxfQruQ6g37sEhm1e/W8d1DPchbDGBRgxi2
 SpkyJsaJZOAhTCGqrIErP8R5ip9TaBFFrEjmF9QQZ3QZBVryqMjAQBQribmoFqjDEmhLtCIR4mzEX
 /K3aC4HJo+mCLVWxL1zH3c2TtSzcsywzNrpB2raLYmd22N2teKotTCOetK4iBE1RbccprS6FFHCGt
 IjTdlZ66Nm7P9bc75UEeqMRtlVHhOCJRU8KctIt22I0AULQSg/TUE9eWm8zxuI3plqf6qaMXtCswP
 o/Dt1V1PIR93ijItDrRjzw==;
Date: Sat, 16 May 2026 12:46:50 +0300
Message-Id: <86cxyv660l.fsf@HIDDEN>
From: Eli Zaretskii <eliz@HIDDEN>
To: Michael Grant <mgrant@HIDDEN>, Jared Finder <jared@HIDDEN>
In-Reply-To: <af36i-emhv7cCESf@HIDDEN> (bug-gnu-emacs@HIDDEN)
Subject: Re: bug#80993: [PATCH] Add support for tty scroll-bars
References: <af36i-emhv7cCESf@HIDDEN>
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 80993
Cc: 80993 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

> Date: Fri, 8 May 2026 11:00:27 -0400
> From:  Michael Grant via "Bug reports for GNU Emacs,
>  the Swiss army knife of text editors" <bug-gnu-emacs@HIDDEN>
> 
> This is a feature patch which implements tty based scroll-bars which
> mimick the X-windows toolkit scrollbars.  It reserves a column on the
> left or right (configurable) for the scroll-bar.  The scroll-bar thumb
> is composed of inverse video white spaces and the scroll-bar gutter dark
> spaces.  The scroll-bar thumb is draggable and clicking above or below
> the scroll-bar scrolls the buffer.

Thanks, a few comments below.

> --- a/lisp/mouse.el
> +++ b/lisp/mouse.el
> @@ -865,7 +865,16 @@ mouse-position-for-drag-line
>  relative to the selected frame, unless the current drag operation was
>  produced from a touch screen event, in which event, return the position
>  of the active touch-screen tool relative to the same."
> -  (if tty (mouse-position-in-root-frame)
> +  (if tty
> +      ;; mouse-position-in-root-frame reads from the GPM mouse hook,
> +      ;; which is not updated by xterm mouse events.  When xterm mouse
> +      ;; mode is active the coordinates are stored as terminal parameters
> +      ;; by xterm-mouse-event; use those when available.
> +      (let ((xt-x (terminal-parameter nil 'xterm-mouse-x))
> +            (xt-y (terminal-parameter nil 'xterm-mouse-y)))
> +        (if (and xt-x xt-y)
> +            (cons xt-x xt-y)
> +          (mouse-position-in-root-frame)))

Jared, any comments?  Would it be cleaner to update xtmouse such that
mouse_position_hook works for it?  Or some other way of supporting
mouse-position-in-root-frame on xtmouse?

> diff --git a/lisp/xt-mouse.el b/lisp/xt-mouse.el
> index b93d914380f..b9e85e22c40 100644
> --- a/lisp/xt-mouse.el
> +++ b/lisp/xt-mouse.el

Jared, any comments on the xt-mouse parts (or stuff related to
xt-mouse elsewhere in the patch)?

> +                     ;; On TTY frames a right scroll bar on a non-rightmost
> +                     ;; window has its indicator one column left of the last
> +                     ;; column, which holds the '|' border glyph.  Layout:
> +                     ;; [content][SB][|].  On the rightmost window there is
> +                     ;; no '|', so the SB occupies the last column as usual.
> +                     ;;
> +                     ;; NOTE: (frame-width) returns the TEXT-area column
> +                     ;; count (excluding the SB column), so the rightmost
> +                     ;; window has right-edge = (1+ (frame-width frame)).
> +                     (if (and (not (display-graphic-p))
> +                              (/= right-edge
> +                                  (1+ (frame-width (window-frame w)))))
> +                         (- right-edge 2)
> +                       (1- right-edge)))))

Couldn't this be simplified using what window-right returns?

> +    (let (result)
> +      (walk-windows
> +       (lambda (w)
> +         (unless result
> +           (let* ((right-edge (+ (window-left-column w)
> +                                 (window-total-width w)))
> +                  (win-top (window-top-line w))
> +                  (win-bot (+ win-top (window-total-height w))))
> +             (when (and (/= right-edge (1+ (frame-width (window-frame w))))
> +                        (= x (1- right-edge))
> +                        (<= win-top y)
> +                        (< y win-bot))
> +               (setq result w)))))

Same here?

> +	      /* For TTY frames with character-based scroll bars, reserve
> +		 columns at the left or right edge of each window row.
> +		 The scroll bar columns are at glyphs[LEFT_MARGIN_AREA][0..sbl-1]
> +		 (left scroll bar) or glyphs[LAST_AREA][0..sbr-1] (right).
> +		 TEXT_AREA and RIGHT_MARGIN_AREA are shifted accordingly so
> +		 the text iterator doesn't overwrite scroll bar columns.  */
> +	      int sbl = 0, sbr = 0;
> +	      if (w && !FRAME_WINDOW_P (XFRAME (w->frame))
> +		  && !MINI_WINDOW_P (w))
> +		{
> +		  sbl = (WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (w)
> +			 ? WINDOW_SCROLL_BAR_COLS (w) : 0);
> +		  sbr = (WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_RIGHT (w)
> +			 ? WINDOW_SCROLL_BAR_COLS (w) : 0);
> +		}
>  	      row->glyphs[TEXT_AREA]
> -		= row->glyphs[LEFT_MARGIN_AREA] + left;
> +		= row->glyphs[LEFT_MARGIN_AREA] + sbl + left;
>  	      row->glyphs[RIGHT_MARGIN_AREA]
> -		= row->glyphs[TEXT_AREA] + dim.width - left - right;
> -	      /* Leave room for a border glyph.  */
> +		= row->glyphs[TEXT_AREA] + dim.width - sbl - sbr - left - right;
> +	      /* Leave room for a border glyph unless the window has a right
> +		 scroll bar (which serves as the visual separator).  */
>  	      if (!FRAME_WINDOW_P (XFRAME (w->frame))
>  		  && !WINDOW_RIGHTMOST_P (w)
> -		  && right > 0)
> +		  && right > 0
> +		  && sbr == 0)
>  		row->glyphs[RIGHT_MARGIN_AREA] -= 1;
> +	      /* LAST_AREA ends before the right scroll bar columns.  */
>  	      row->glyphs[LAST_AREA]
> -		= row->glyphs[LEFT_MARGIN_AREA] + dim.width;
> +		= row->glyphs[LEFT_MARGIN_AREA] + dim.width - sbr;
>  	    }

I believe the code here was modified lately, so please rebase.

> @@ -976,7 +983,7 @@ tty_write_glyphs (struct frame *f, struct glyph *string, int len)
>       since that would scroll the whole frame on some terminals.  */
>    if (AutoWrap (tty)
>        && curY (tty) + 1 == FRAME_TOTAL_LINES (f)
> -      && curX (tty) + len == FRAME_COLS (f)
> +      && curX (tty) + len == FrameCols (tty)

Why was this needed?

And I have several more questions:

  . where are the glyphs defined that are used to draw the TTY
    scroll-bar and its thumb? it sounds like they are always SPC
    characters with a special face, is that right?
  . since the scroll bar takes up another column of each window's
    screen line, shouldn't we make last_visible_x set up in
    init_iterator by one? otherwise, a ling enough line could
    overwrite the scroll-bar glyphs, no?
  . similarly, shouldn't append_glyph avoid adding glyphs past the
    scroll-bar? e.g., did you try displaying a buffer with wide
    characters, those which take more than 1 column, when the line is
    long enough to reach the right edge of the window?

And finally, would people please try this patch and report back any
issues they find with the code?

Thanks.




Information forwarded to bug-gnu-emacs@HIDDEN:
bug#80993; Package emacs. Full text available.

Message received at submit <at> debbugs.gnu.org:


Received: (at submit) by debbugs.gnu.org; 8 May 2026 15:01:12 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Fri May 08 11:01:12 2026
Received: from localhost ([127.0.0.1]:39209 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1wLMhM-0005on-Ck
	for submit <at> debbugs.gnu.org; Fri, 08 May 2026 11:01:12 -0400
Received: from lists1p.gnu.org ([2001:470:142::17]:57722)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <mgrant@HIDDEN>) id 1wLMhE-0005ll-Jc
 for submit <at> debbugs.gnu.org; Fri, 08 May 2026 11:01:01 -0400
Received: from eggs.gnu.org ([2001:470:142:3::10])
 by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <mgrant@HIDDEN>) id 1wLMgz-00081y-Kg
 for bug-gnu-emacs@HIDDEN; Fri, 08 May 2026 11:00:42 -0400
Received: from strange.networkguild.org ([2600:3c02:e000:dd::1])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <mgrant@HIDDEN>) id 1wLMgo-0005ou-D9
 for bug-gnu-emacs@HIDDEN; Fri, 08 May 2026 11:00:36 -0400
Received: from strange.networkguild.org (localhost [127.0.0.1])
 by strange.networkguild.org (8.18.1/8.18.1/Debian-6) with ESMTPS id
 648F0RjD399370
 (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384 bits=256 verify=NOT)
 for <bug-gnu-emacs@HIDDEN>; Fri, 8 May 2026 11:00:27 -0400
Received: (from root@localhost)
 by strange.networkguild.org (8.18.1/8.18.1/Submit) id 648F0RJ5399369
 for bug-gnu-emacs@HIDDEN; Fri, 8 May 2026 11:00:27 -0400
Date: Fri, 8 May 2026 11:00:27 -0400
From: Michael Grant <mgrant@HIDDEN>
To: bug-gnu-emacs@HIDDEN
Subject: [PATCH] Add support for tty scroll-bars
Message-ID: <af36i-emhv7cCESf@HIDDEN>
MIME-Version: 1.0
Content-Type: multipart/signed; micalg=pgp-sha512;
 protocol="application/pgp-signature"; boundary="JZGPDlq/4kg2H8cZ"
Content-Disposition: inline
X-Virus-Scanned: clamav-milter 1.4.3 at strange.networkguild.org
X-Virus-Status: Clean
Received-SPF: pass client-ip=2600:3c02:e000:dd::1;
 envelope-from=mgrant@HIDDEN; helo=strange.networkguild.org
X-Spam_score_int: -18
X-Spam_score: -1.9
X-Spam_bar: -
X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, SPF_HELO_PASS=-0.001,
 SPF_PASS=-0.001 autolearn=ham autolearn_force=no
X-Spam_action: no action
X-Spam-Score: 0.9 (/)
X-Debbugs-Envelope-To: submit
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -0.1 (/)


--JZGPDlq/4kg2H8cZ
Content-Type: multipart/mixed; boundary="36I/gurMzNR42vlK"
Content-Disposition: inline


--36I/gurMzNR42vlK
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

This bug report will be sent to the Bug-GNU-Emacs mailing list
and the GNU bug tracker at debbugs.gnu.org.  Please check that
the From: line contains a valid email address.  After a delay of up
to one day, you should receive an acknowledgment at that address.

Please write in English if possible, as the Emacs maintainers
usually do not have translators for other languages.

Please describe exactly what actions triggered the bug, and
the precise symptoms of the bug.  If you can, give a recipe
starting from 'emacs -Q':

This is a feature patch which implements tty based scroll-bars which
mimick the X-windows toolkit scrollbars.  It reserves a column on the
left or right (configurable) for the scroll-bar.  The scroll-bar thumb
is composed of inverse video white spaces and the scroll-bar gutter dark
spaces.  The scroll-bar thumb is draggable and clicking above or below
the scroll-bar scrolls the buffer.

I have created this bug-report from within an emacs compiled with these
scroll-bars, hence the version and configuration information below.

If Emacs crashed, and you have the Emacs process in the gdb debugger,
please include the output from the following gdb commands:
    'bt full' and 'xbacktrace'.
For information about debugging Emacs, please read the file
/home/mgrant/emacs-master/etc/DEBUG.

In GNU Emacs 32.0.50 (build 2, x86_64-pc-linux-gnu, GTK+ Version
 3.24.41, cairo version 1.18.0) of 2026-05-08 built on Slablet
Repository revision: 1019ae4e29f24232ea40668a7622b9bd01bc1e02
Repository branch: tty_scrollbars
System Description: Ubuntu 24.04.4 LTS
Configured features:
ACL CAIRO DBUS FREETYPE GIF GLIB GMP GNUTLS GPM GSETTINGS HARFBUZZ JPEG
LCMS2 LIBOTF LIBSYSTEMD LIBXML2 M17N_FLT MODULES NATIVE_COMP NOTIFY
INOTIFY PDUMPER PNG RSVG SECCOMP SOUND SQLITE3 THREADS TIFF
TOOLKIT_SCROLL_BARS TREE_SITTER WEBP X11 XDBE XIM XINERAMA XINPUT2 XPM
XRANDR GTK3 ZLIB

Important settings:
  value of $LANG: C.UTF-8
  locale-coding-system: utf-8-unix

Major mode: Lisp Interaction

Minor modes in effect:
  recentf-mode: t
  desktop-save-mode: t
  save-place-mode: t
  xterm-mouse-mode: t
  winner-mode: t
  delete-selection-mode: t
  cua-mode: t
  tooltip-mode: t
  global-eldoc-mode: t
  eldoc-mode: t
  show-paren-mode: t
  electric-indent-mode: t
  mouse-wheel-mode: t
  file-name-shadow-mode: t
  global-font-lock-mode: t
  font-lock-mode: t
  blink-cursor-mode: t
  window-divider-mode: t
  minibuffer-nonselected-mode: t
  minibuffer-regexp-mode: t
  column-number-mode: t
  line-number-mode: t
  indent-tabs-mode: t
  transient-mark-mode: t
  auto-composition-mode: t
  auto-encryption-mode: t
  auto-compression-mode: t

Load-path shadows:
/home/mgrant/.emacs.d/lisp/completion hides /home/mgrant/emacs-master/lisp/completion
/home/mgrant/.emacs.d/lisp/ispell hides /home/mgrant/emacs-master/lisp/textmodes/ispell
/home/mgrant/.emacs.d/lisp/sendmail hides /home/mgrant/emacs-master/lisp/mail/sendmail
/home/mgrant/.emacs.d/lisp/vt-control hides /home/mgrant/emacs-master/lisp/obsolete/vt-control

Features:
(shadow sort mail-extr emacsbug lisp-mnt message yank-media puny dired
dired-loaddefs rfc822 mml mml-sec epa derived epg rfc6068 epg-config
gnus-util mm-decode mm-bodies mm-encode mail-parse rfc2231 rfc2047
rfc2045 mm-util ietf-drums mail-prsvr mailabbrev mail-utils gmm-utils
mailheader sendmail cl-extra help-mode warnings time-date term/xterm
xterm compile text-property-search comp-run bytecomp byte-compile
comp-common rx wombat-theme recentf tree-widget desktop frameset
saveplace server comint ansi-osc ansi-color xt-mouse winner cus-edit pp
cus-start cus-load wid-edit ring delsel cua-base finder-inf package
browse-url xdg url url-proxy url-privacy url-expand url-methods
url-history url-cookie generate-lisp-file url-domsuf url-util mailcap
url-handlers url-parse auth-source cl-seq eieio eieio-core cl-macs gv
icons password-cache json subr-x mule-util map url-vars cl-loaddefs
cl-lib package-activate rmc iso-transl tooltip cconv eldoc paren
electric uniquify ediff-hook vc-hooks lisp-float-type elisp-mode mwheel
term/x-win x-win term/common-win x-dnd touch-screen tool-bar dnd fontset
image regexp-opt fringe tabulated-list replace newcomment text-mode
lisp-mode prog-mode register page tab-bar menu-bar rfn-eshadow isearch
easymenu timer select scroll-bar mouse jit-lock font-lock syntax
font-core term/tty-colors frame minibuffer nadvice seq simple cl-generic
indonesian philippine cham georgian utf-8-lang misc-lang vietnamese
tibetan thai tai-viet lao korean japanese eucjp-ms cp51932 hebrew greek
romanian slovak czech european ethiopic indian cyrillic chinese
composite emoji-zwj charscript charprop case-table epa-hook
jka-cmpr-hook help abbrev obarray oclosure cl-preloaded button loaddefs
theme-loaddefs faces cus-face macroexp files window text-properties
overlay sha1 md5 base64 format env code-pages mule custom widget keymap
hashtable-print-readable backquote threads dbusbind inotify lcms2
dynamic-setting system-font-setting font-render-setting cairo gtk
x-toolkit xinput2 x multi-tty move-toolbar make-network-process
tty-child-frames native-compile emacs)

Memory information:
((conses 16 147245 20124) (symbols 48 11511 0) (strings 32 37115 2565)
 (string-bytes 1 1236747) (vectors 16 22745)
 (vector-slots 8 617206 41990) (floats 8 83 13435)
 (intervals 56 319 0) (buffers 1064 12))

--36I/gurMzNR42vlK
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment; filename="tty-scrollbars.patch"
Content-Transfer-Encoding: quoted-printable

diff --git a/lisp/faces.el b/lisp/faces.el
index 94da4ba0290..07a5da8522b 100644
--- a/lisp/faces.el
+++ b/lisp/faces.el
@@ -2932,12 +2932,25 @@ fringe
   :group 'frames
   :group 'basic-faces)
=20
-(defface scroll-bar '((t nil))
-  "Basic face for the scroll bar colors under X."
+(defface scroll-bar
+  '((((type tty)) :background "black")
+    (t nil))
+  "Basic face for the scroll bar colors under X.
+On TTY frames, this face determines the appearance of the scroll bar
+gutter (track).  The default TTY appearance is a black background."
   :version "21.1"
   :group 'frames
   :group 'basic-faces)
=20
+(defface scroll-bar-thumb
+  '((((type tty)) :inverse-video t)
+    (t nil))
+  "Basic face for the scroll bar thumb (draggable portion) in TTY frames.
+On character-based terminals, the thumb is rendered as inverse-video space=
s."
+  :version "30.1"
+  :group 'frames
+  :group 'basic-faces)
+
 (defface border '((t nil))
   "Basic face for the frame border under X."
   :version "21.1"
diff --git a/lisp/mouse.el b/lisp/mouse.el
index 20c819ee0a8..5ff9e1ab87a 100644
--- a/lisp/mouse.el
+++ b/lisp/mouse.el
@@ -865,7 +865,16 @@ mouse-position-for-drag-line
 relative to the selected frame, unless the current drag operation was
 produced from a touch screen event, in which event, return the position
 of the active touch-screen tool relative to the same."
-  (if tty (mouse-position-in-root-frame)
+  (if tty
+      ;; mouse-position-in-root-frame reads from the GPM mouse hook,
+      ;; which is not updated by xterm mouse events.  When xterm mouse
+      ;; mode is active the coordinates are stored as terminal parameters
+      ;; by xterm-mouse-event; use those when available.
+      (let ((xt-x (terminal-parameter nil 'xterm-mouse-x))
+            (xt-y (terminal-parameter nil 'xterm-mouse-y)))
+        (if (and xt-x xt-y)
+            (cons xt-x xt-y)
+          (mouse-position-in-root-frame)))
     (or (touch-screen-last-drag-position)
         (mouse-absolute-pixel-position))))
=20
diff --git a/lisp/scroll-bar.el b/lisp/scroll-bar.el
index b9d1d3a441e..7430ee82a3b 100644
--- a/lisp/scroll-bar.el
+++ b/lisp/scroll-bar.el
@@ -92,6 +92,7 @@ scroll-bar-mode-explicit
   "Non-nil means `set-scroll-bar-mode' should really do something.
 This is nil while loading `scroll-bar.el', and t afterward.")
=20
+;;;###autoload
 (defun set-scroll-bar-mode (value)
   "Set the scroll bar mode to VALUE and put the new value into effect.
 See the `scroll-bar-mode' variable for possible values to use."
@@ -104,6 +105,7 @@ set-scroll-bar-mode
     (modify-all-frames-parameters (list (cons 'vertical-scroll-bars
 					      scroll-bar-mode)))))
=20
+(custom-autoload 'scroll-bar-mode "scroll-bar" t)
 (defcustom scroll-bar-mode default-frame-scroll-bars
   "Specify whether to have vertical scroll bars, and on which side.
 Possible values are nil (no scroll bars), `left' (scroll bars on left)
@@ -124,6 +126,16 @@ scroll-bar-mode
 ;; If it is set again, that is for real.
 (setq scroll-bar-mode-explicit t)
=20
+(defun scroll-bar--tty-frame-setup ()
+  "Apply `scroll-bar-mode' to TTY frames at startup.
+TTY frames don't go through the GUI frame-parameter initialization
+that would apply `scroll-bar-mode' during frame creation, so we
+apply it explicitly here via `window-setup-hook'."
+  (when scroll-bar-mode
+    (set-scroll-bar-mode scroll-bar-mode)))
+
+(add-hook 'window-setup-hook #'scroll-bar--tty-frame-setup)
+
 (defun get-scroll-bar-mode ()
   (declare (gv-setter set-scroll-bar-mode))
   scroll-bar-mode)
@@ -301,6 +313,106 @@ scroll-bar-drag
     (with-current-buffer (window-buffer window)
       (setq point-before-scroll before-scroll))))
=20
+(defun tty-scroll-bar--thumb-geometry (window)
+  "Return (START . END) thumb geometry for WINDOW's TTY scroll bar.
+START and END are 0-indexed row numbers; the thumb occupies rows
+\[START, END) (exclusive END).  Mirrors the formula in C function
+`tty_apply_scroll_bar_glyphs_for_window'."
+  (let* ((buf     (window-buffer window))
+         (win-ht  (window-body-height window))
+         (whole   (buffer-size buf))
+         (pos     (with-current-buffer buf
+                    (- (window-start window) (point-min))))
+         (portion (- (window-end window t) (window-start window))))
+    (if (or (<=3D whole 0) (>=3D portion whole))
+        (cons 0 win-ht)
+      (let* ((ta    (floor (* (/ (float pos) whole) win-ht)))
+             (below (- whole pos portion))
+             (tb    (if (> below 0)
+                        (floor (* (/ (float below) whole) win-ht))
+                      0)))
+        (when (and (> pos 0) (=3D ta 0)) (setq ta 1))
+        (when (and (> below 0) (=3D tb 0)) (setq tb 1))
+        (let ((ts ta)
+              (te (- win-ht tb)))
+          (when (<=3D te ts) (setq te (1+ ts)))
+          (setq ts (min ts (1- win-ht)))
+          (setq te (min te win-ht))
+          (when (>=3D ts te) (setq te (1+ ts)))
+          (cons ts te))))))
+
+(defun tty-scroll-bar--thumb-start (window)
+  "Return the 0-indexed thumb-start row for WINDOW's TTY scroll bar."
+  (car (tty-scroll-bar--thumb-geometry window)))
+
+(defun tty-scroll-bar-drag (event)
+  "Scroll a TTY scroll bar window live as the mouse is dragged.
+EVENT is the down-mouse-1 event on the scroll bar handle.
+Uses `read-key' (not `read-event') so that xterm mouse escape sequences
+are decoded through `input-decode-map' during the drag loop.
+
+Handles both `mouse-movement' events (when the mouse is over the text
+area) and `scroll-bar-movement' events (when the mouse is over the
+scroll bar itself); only the y coordinate is used to scroll, so moving
+horizontally into the text area while dragging still scrolls correctly.
+
+The grab point =E2=80=94 the row within the thumb where the drag was initi=
ated
+=E2=80=94 is preserved throughout the drag, so the thumb follows the cursor
+rather than jumping to align its top edge with the cursor."
+  (interactive "e")
+  (let* ((start-pos    (event-start event))
+         (window       (nth 0 start-pos))
+         (click-sb-row (car (nth 2 start-pos)))
+         (grab-offset  (max 0 (- click-sb-row
+                                 (tty-scroll-bar--thumb-start window)))))
+    (track-mouse
+      (let (done)
+        (while (not done)
+          (let ((ev (read-key)))
+            (cond
+             ((eq (car-safe ev) 'scroll-bar-movement)
+              ;; Mouse moved within the scroll bar: extract sb-row from
+              ;; the event's (PORTION . WHOLE) field directly.
+              (let* ((posn   (nth 1 ev))
+                     (ratio  (nth 2 posn))
+                     (win-ht (window-body-height window))
+                     (sb-row (max 0 (min (1- win-ht)
+                                         (- (car ratio) grab-offset)))))
+                (when (> win-ht 0)
+                  (with-current-buffer (window-buffer window)
+                    (goto-char (+ (point-min)
+                                  (/ (* sb-row (- (point-max) (point-min)))
+                                     win-ht)))
+                    (vertical-motion 0 window)
+                    (set-window-start window (point))))))
+             ((mouse-movement-p ev)
+              ;; Mouse moved outside the scroll bar (e.g. into the text
+              ;; area): use the y coordinate stored by xterm-mouse.
+              (let* ((y       (terminal-parameter nil 'xterm-mouse-y))
+                     (win-ht  (window-body-height window))
+                     (win-top (window-top-line window))
+                     (sb-row  (max 0 (min (1- win-ht)
+                                          (- (- y win-top) grab-offset)))))
+                (when (> win-ht 0)
+                  (with-current-buffer (window-buffer window)
+                    (goto-char (+ (point-min)
+                                  (/ (* sb-row (- (point-max) (point-min)))
+                                     win-ht)))
+                    (vertical-motion 0 window)
+                    (set-window-start window (point))))))
+             (t
+              (setq done t)))))))))
+
+(defun tty-scroll-bar-down-mouse-1 (event)
+  "Handle down-mouse-1 on a TTY vertical scroll bar.
+When clicked on the thumb handle, initiate live drag scrolling via
+`tty-scroll-bar-drag'.  When clicked above or below the handle, do
+nothing so that the subsequent button-up event fires
+`scroll-bar-toolkit-scroll' to page up or down."
+  (interactive "e")
+  (when (eq (nth 4 (event-start event)) 'handle)
+    (tty-scroll-bar-drag event)))
+
 ;; Scroll the window to the proper position for EVENT.
 (defun scroll-bar-horizontal-drag-1 (event)
   (let* ((start-position (event-start event))
@@ -494,12 +606,34 @@ scroll-bar-toolkit-horizontal-scroll
        (global-set-key [vertical-scroll-bar mouse-1]
 		       'scroll-bar-toolkit-scroll)
        (global-set-key [horizontal-scroll-bar mouse-1]
-		       'scroll-bar-toolkit-horizontal-scroll))
+		       'scroll-bar-toolkit-horizontal-scroll)
+       ;; Also bind the TTY live-drag key so that `src/emacs -nw' in a
+       ;; toolkit build uses the same drag handler as non-toolkit builds.
+       ;; In graphical frames the toolkit delivers drags as mouse-1
+       ;; (not down-mouse-1), so this binding does not conflict.
+       (global-set-key [vertical-scroll-bar down-mouse-1]
+		       'tty-scroll-bar-down-mouse-1)
+       ;; When a TTY drag ends outside the scroll bar column, the release
+       ;; event becomes drag-mouse-1; handle it like a click on the end
+       ;; position so the buffer still scrolls proportionally.
+       (global-set-key [vertical-scroll-bar drag-mouse-1]
+		       'scroll-bar-toolkit-scroll))
       (t
+       ;; TTY (character-based) scroll bars include part information
+       ;; (above-handle, handle, below-handle).
+       ;;
+       ;; down-mouse-1 is bound to `tty-scroll-bar-down-mouse-1': when
+       ;; the thumb handle is clicked it enters a live-drag loop using
+       ;; `read-key' (which decodes xterm escape sequences); clicking
+       ;; above/below the handle is a no-op so the button-up event falls
+       ;; through to `scroll-bar-toolkit-scroll' for page up/down.
+       (global-set-key [vertical-scroll-bar down-mouse-1]
+		       'tty-scroll-bar-down-mouse-1)
        (global-set-key [vertical-scroll-bar mouse-1]
-		       'scroll-bar-scroll-up)
+		       'scroll-bar-toolkit-scroll)
+       ;; Dragging the thumb: treat it as a click on the final position.
        (global-set-key [vertical-scroll-bar drag-mouse-1]
-		       'scroll-bar-scroll-up)
+		       'scroll-bar-toolkit-scroll)
        (global-set-key [vertical-scroll-bar down-mouse-2]
 		       'scroll-bar-drag)
        (global-set-key [vertical-scroll-bar mouse-3]
diff --git a/lisp/xt-mouse.el b/lisp/xt-mouse.el
index b93d914380f..b9e85e22c40 100644
--- a/lisp/xt-mouse.el
+++ b/lisp/xt-mouse.el
@@ -131,6 +131,96 @@ xterm-mouse-translate-1
                 (xterm-mouse--handle-mouse-movement)
 		(vector (list 'mouse-movement ev-data))))))))))))
=20
+(defun xterm-mouse--tty-scroll-bar-window (x y frame)
+  "Return the window whose TTY scroll bar column is at frame column X, row=
 Y.
+Returns nil if no TTY scroll bar occupies position (X, Y)."
+  (let ((sb-side (frame-parameter frame 'vertical-scroll-bars))
+        result)
+    (when sb-side
+      (walk-windows
+       (lambda (w)
+         (unless result
+           (let* ((right-edge (+ (window-left-column w)
+                                 (window-total-width w)))
+                  (sb-col
+                   (cond
+                    ((eq sb-side 'left) (window-left-column w))
+                    ((eq sb-side 'right)
+                     ;; On TTY frames a right scroll bar on a non-rightmost
+                     ;; window has its indicator one column left of the la=
st
+                     ;; column, which holds the '|' border glyph.  Layout:
+                     ;; [content][SB][|].  On the rightmost window there is
+                     ;; no '|', so the SB occupies the last column as usua=
l.
+                     ;;
+                     ;; NOTE: (frame-width) returns the TEXT-area column
+                     ;; count (excluding the SB column), so the rightmost
+                     ;; window has right-edge =3D (1+ (frame-width frame)).
+                     (if (and (not (display-graphic-p))
+                              (/=3D right-edge
+                                  (1+ (frame-width (window-frame w)))))
+                         (- right-edge 2)
+                       (1- right-edge)))))
+                  (win-top (window-top-line w))
+                  (win-bot (+ win-top (window-total-height w))))
+             (when (and sb-col
+                        (=3D x sb-col)
+                        (<=3D win-top y)
+                        (< y win-bot))
+               (setq result w)))))
+       nil frame))
+    result))
+
+(defun xterm-mouse--tty-vertical-border-window (x y frame)
+  "Return the window whose TTY `|' border column is at frame column X, row=
 Y.
+Returns nil unless (X, Y) is on the `|' border of a non-rightmost TTY
+window with a right scroll bar.  In that layout, [content][SB][|], the
+`|' occupies the last column of the window's total-width allocation."
+  (when (and (not (display-graphic-p))
+             (eq (frame-parameter frame 'vertical-scroll-bars) 'right))
+    (let (result)
+      (walk-windows
+       (lambda (w)
+         (unless result
+           (let* ((right-edge (+ (window-left-column w)
+                                 (window-total-width w)))
+                  (win-top (window-top-line w))
+                  (win-bot (+ win-top (window-total-height w))))
+             (when (and (/=3D right-edge (1+ (frame-width (window-frame w)=
)))
+                        (=3D x (1- right-edge))
+                        (<=3D win-top y)
+                        (< y win-bot))
+               (setq result w)))))
+       nil frame)
+      result)))
+
+(defun xterm-mouse--tty-scroll-bar-part (window y)
+  "Return the scroll bar part clicked at terminal row Y for WINDOW.
+Returns one of the symbols `above-handle', `handle', or `below-handle'."
+  (let* ((buf         (window-buffer window))
+         (win-height  (window-body-height window))
+         (win-top     (window-top-line window))
+         (sb-row      (max 0 (min (1- win-height) (- y win-top))))
+         (buf-size    (buffer-size buf))
+         (win-start   (window-start window))
+         (win-end     (window-end window t))
+         (portion     (max 1 (- win-end win-start)))
+         (whole       (max portion buf-size))
+         ;; Mirror the C formula: compute track above and below separately.
+         (track-above (if (> whole 0)
+                          (floor (* win-start (/ (float win-height) whole)=
))
+                        0))
+         (below-chars (max 0 (- whole win-start portion)))
+         (track-below (if (> whole 0)
+                          (floor (* below-chars (/ (float win-height) whol=
e)))
+                        0))
+         (thumb-start track-above)
+         (thumb-end   (- win-height track-below)))
+    (when (>=3D thumb-end win-height) (setq thumb-end (1- win-height)))
+    (cond
+     ((< sb-row thumb-start)  'above-handle)
+     ((>=3D sb-row thumb-end)   'below-handle)
+     (t                       'handle))))
+
 (defun xterm-mouse--handle-mouse-movement ()
   "Handle mouse motion that was just generated for XTerm mouse."
   (when-let* ((frame (terminal-parameter nil 'xterm-mouse-frame)))
@@ -341,6 +431,59 @@ xterm-mouse-event
 				  frame)
 				item)
 			  (nthcdr 2 (posn-at-x-y x y (selected-frame)))))))
+             ;; Check for a click in a TTY vertical scroll bar column.
+             ;; When detected, replace the position with a scroll bar
+             ;; position so that [vertical-scroll-bar mouse-N] bindings fi=
re.
+             (sb-window (and (not (display-graphic-p))
+                             frame
+                             (not (eq type 'mouse-movement))
+                             (xterm-mouse--tty-scroll-bar-window x y frame=
)))
+             (posn (if sb-window
+                       (let* ((win-ht  (window-body-height sb-window))
+                              (win-top (window-top-line sb-window))
+                              (sb-row  (max 0 (min (1- win-ht) (- y win-to=
p))))
+                              (part    (xterm-mouse--tty-scroll-bar-part
+                                        sb-window y))
+                              ;; For button-up events: if the drag started=
 on
+                              ;; the scroll-bar handle, keep part=3D'handl=
e' so
+                              ;; scroll-bar-drag-1 proportionally scrolls =
to
+                              ;; the release position rather than paging.
+                              (down-ev  (terminal-parameter
+                                         nil 'xterm-mouse-last-down))
+                              (down-part (and down-ev
+                                             (nth 4 (nth 1 down-ev))))
+                              (part     (if (and (not (string-prefix-p
+                                                       "down-"
+                                                       (symbol-name type)))
+                                                 (eq down-part 'handle))
+                                            'handle
+                                          part)))
+                         ;; Build a scroll-bar position in the same format=
 as
+                         ;; make_scroll_bar_position in keyboard.c:
+                         ;;   (window AREA (pos . size) timestamp part)
+                         ;; AREA must be the bare symbol `vertical-scroll-=
bar'
+                         ;; (not a cons) so that read_key_sequence's SYMBO=
LP
+                         ;; check expands the event to [vertical-scroll-bar
+                         ;; mouse-1], which fires `scroll-bar-toolkit-scro=
ll'.
+                         (list sb-window
+                               'vertical-scroll-bar
+                               (cons sb-row win-ht)
+                               timestamp
+                               part))
+                     posn))
+             ;; Check for a click on the TTY '|' window border.
+             ;; For a right scroll bar on a non-rightmost TTY window the '=
|'
+             ;; glyph occupies the last column of the window allocation; a
+             ;; click there should generate a vertical-line position so th=
at
+             ;; [vertical-line down-mouse-1] =E2=86=92 mouse-drag-vertical=
-line fires.
+             (border-window (and (not sb-window)
+                                 frame
+                                 (not (eq type 'mouse-movement))
+                                 (xterm-mouse--tty-vertical-border-window
+                                  x y frame)))
+             (posn (if border-window
+                       (list border-window 'vertical-line (cons x y) times=
tamp)
+                     posn))
              (event (list type posn)))
         (setcar (nthcdr 3 posn) timestamp)
=20
diff --git a/src/dispextern.h b/src/dispextern.h
index d08bd7ee7a9..f0d5be70f13 100644
--- a/src/dispextern.h
+++ b/src/dispextern.h
@@ -1967,6 +1967,7 @@ #define FACE_UNIBYTE_P(FACE) ((FACE)->charset < 0)
   TAB_LINE_ACTIVE_FACE_ID,
   TAB_LINE_INACTIVE_FACE_ID,
   MARGIN_FACE_ID,
+  SCROLL_BAR_THUMB_FACE_ID,
   BASIC_FACE_ID_SENTINEL
 };
=20
diff --git a/src/dispnew.c b/src/dispnew.c
index 284a0eb175f..001d7c29298 100644
--- a/src/dispnew.c
+++ b/src/dispnew.c
@@ -467,17 +467,35 @@ adjust_glyph_matrix (struct window *w, struct glyph_m=
atrix *matrix, int x, int y
 	    }
 	  else
 	    {
+	      /* For TTY frames with character-based scroll bars, reserve
+		 columns at the left or right edge of each window row.
+		 The scroll bar columns are at glyphs[LEFT_MARGIN_AREA][0..sbl-1]
+		 (left scroll bar) or glyphs[LAST_AREA][0..sbr-1] (right).
+		 TEXT_AREA and RIGHT_MARGIN_AREA are shifted accordingly so
+		 the text iterator doesn't overwrite scroll bar columns.  */
+	      int sbl =3D 0, sbr =3D 0;
+	      if (w && !FRAME_WINDOW_P (XFRAME (w->frame))
+		  && !MINI_WINDOW_P (w))
+		{
+		  sbl =3D (WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (w)
+			 ? WINDOW_SCROLL_BAR_COLS (w) : 0);
+		  sbr =3D (WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_RIGHT (w)
+			 ? WINDOW_SCROLL_BAR_COLS (w) : 0);
+		}
 	      row->glyphs[TEXT_AREA]
-		=3D row->glyphs[LEFT_MARGIN_AREA] + left;
+		=3D row->glyphs[LEFT_MARGIN_AREA] + sbl + left;
 	      row->glyphs[RIGHT_MARGIN_AREA]
-		=3D row->glyphs[TEXT_AREA] + dim.width - left - right;
-	      /* Leave room for a border glyph.  */
+		=3D row->glyphs[TEXT_AREA] + dim.width - sbl - sbr - left - right;
+	      /* Leave room for a border glyph unless the window has a right
+		 scroll bar (which serves as the visual separator).  */
 	      if (!FRAME_WINDOW_P (XFRAME (w->frame))
 		  && !WINDOW_RIGHTMOST_P (w)
-		  && right > 0)
+		  && right > 0
+		  && sbr =3D=3D 0)
 		row->glyphs[RIGHT_MARGIN_AREA] -=3D 1;
+	      /* LAST_AREA ends before the right scroll bar columns.  */
 	      row->glyphs[LAST_AREA]
-		=3D row->glyphs[LEFT_MARGIN_AREA] + dim.width;
+		=3D row->glyphs[LEFT_MARGIN_AREA] + dim.width - sbr;
 	    }
 	}
=20
@@ -2093,6 +2111,24 @@ adjust_frame_glyphs_for_frame_redisplay (struct fram=
e *f)
   pool_changed_p =3D realloc_glyph_pool (f->desired_pool, matrix_dim);
   realloc_glyph_pool (f->current_pool, matrix_dim);
=20
+  /* When the TTY scroll bar type changes, sbl/sbr (computed in
+     adjust_glyph_matrix) change too, so the TEXT_AREA glyph pointer
+     offsets within each pool row must be updated.  Because neither the
+     pool size nor the window sizes change in that case, the normal
+     pool_changed_p / window_change_flags detection misses it.
+     Use config_scroll_bar_height (unused by TTY frames) to track the
+     last-seen scroll bar type and force re-adjustment only on change.  */
+  if (!FRAME_WINDOW_P (f))
+    {
+      enum vertical_scroll_bar_type cur_sb
+	=3D FRAME_VERTICAL_SCROLL_BAR_TYPE (f);
+      if ((int) cur_sb !=3D f->config_scroll_bar_height)
+	{
+	  f->config_scroll_bar_height =3D (int) cur_sb;
+	  pool_changed_p =3D true;
+	}
+    }
+
   /* Set up glyph pointers within window matrices.  Do this only if
      absolutely necessary since it requires a frame redraw.  */
   if (pool_changed_p || window_change_flags)
@@ -2582,8 +2618,14 @@ build_frame_matrix_from_leaf_window (struct glyph_ma=
trix *frame_matrix, struct w
     {
       window_matrix =3D w->desired_matrix;
=20
-      /* Decide whether we want to add a vertical border glyph.  */
-      if (!WINDOW_RIGHTMOST_P (w))
+      /* Decide whether we want to add a vertical border glyph between
+	 horizontally adjacent windows.  For TTY frames we always insert
+	 '|' at LAST_AREA-1: with a right scroll bar, window_body_width
+	 now reserves that column explicitly so the border and the scroll
+	 bar indicator (one column further right) are visually distinct.  */
+      if (!WINDOW_RIGHTMOST_P (w)
+	  && (!WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_RIGHT (w)
+	      || !FRAME_WINDOW_P (f)))
 	{
 	  struct Lisp_Char_Table *dp =3D window_display_table (w);
 	  Lisp_Object gc;
@@ -2665,7 +2707,23 @@ build_frame_matrix_from_leaf_window (struct glyph_ma=
trix *frame_matrix, struct w
 	     windows.  */
 	  if (GLYPH_CHAR (right_border_glyph) !=3D 0)
 	    {
-	      struct glyph *border =3D window_row->glyphs[LAST_AREA] - 1;
+	      struct glyph *border;
+	      /* For TTY frames with a right scroll bar, the normal
+		 border position (LAST_AREA - 1) is used for the scroll
+		 bar indicator; tty_apply_scroll_bar_glyphs shifts the SB
+		 one column left to make room.  Place '|' at LAST_AREA[0]
+		 (the SB slot) so the layout is [content][SB][|].  */
+	      if (!FRAME_WINDOW_P (f)
+		  && WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_RIGHT (w))
+		{
+		  border =3D window_row->glyphs[LAST_AREA];
+		  /* Extend the used count to cover this extra column.  */
+		  int need =3D (int)(border - frame_row->glyphs[TEXT_AREA]) + 1;
+		  if (frame_row->used[TEXT_AREA] < need)
+		    frame_row->used[TEXT_AREA] =3D need;
+		}
+	      else
+		border =3D window_row->glyphs[LAST_AREA] - 1;
 	      /* It's a subtle bug if we are overwriting some non-char
 		 glyph with the vertical border glyph.  */
 	      eassert (border->type =3D=3D CHAR_GLYPH);
@@ -3913,10 +3971,171 @@ flush_terminal (struct frame *f)
   fflush (FRAME_TTY (f)->output);
 }
=20
+/* Apply TTY character-based scroll bar glyphs for window W into the
+   desired matrix of its frame.  Called recursively for the window tree.  =
*/
+static void
+tty_apply_scroll_bar_glyphs_for_window (struct frame *f, struct window *w)
+{
+  if (!WINDOW_LEAF_P (w))
+    {
+      /* Internal window: recurse into children.  */
+      struct window *child =3D XWINDOW (w->contents);
+      while (child)
+	{
+	  tty_apply_scroll_bar_glyphs_for_window (f, child);
+	  child =3D NILP (child->next) ? NULL : XWINDOW (child->next);
+	}
+      return;
+    }
+
+  /* Leaf window: draw scroll bar if active.  Skip minibuffer windows;
+     they occupy the last terminal row and writing 80 glyphs there would
+     trigger cmcheckmagic.  Minibuffer windows don't show scroll bars on
+     GUI either, so this is consistent behaviour.  */
+  if (MINI_WINDOW_P (w))
+    return;
+  if (!WINDOW_HAS_VERTICAL_SCROLL_BAR (w))
+    return;
+
+  /* Retrieve stored scroll bar parameters set by tty_set_vertical_scroll_=
bar.  */
+  Lisp_Object sb_data =3D w->vertical_scroll_bar;
+  if (!VECTORP (sb_data) || ASIZE (sb_data) < 3)
+    return;
+
+  int portion  =3D XFIXNUM (AREF (sb_data, 0));
+  int whole    =3D XFIXNUM (AREF (sb_data, 1));
+  int position =3D XFIXNUM (AREF (sb_data, 2));
+
+  struct glyph_matrix *matrix =3D f->desired_matrix;
+  if (!matrix)
+    return;
+
+  /* Window rows in the frame matrix.  */
+  int frame_y_top =3D w->desired_matrix->matrix_y;
+  int nrows =3D WINDOW_TOTAL_LINES (w);
+  /* Exclude mode line.  */
+  if (window_wants_mode_line (w))
+    nrows--;
+  /* Skip header/tab line rows at top.  */
+  int top_skip =3D 0;
+  if (window_wants_tab_line (w))
+    top_skip++;
+  if (window_wants_header_line (w))
+    top_skip++;
+
+  if (nrows <=3D top_skip)
+    return;
+  int sb_rows =3D nrows - top_skip;  /* usable rows for scroll bar */
+
+  /* Compute the scroll bar column in frame coordinates.  */
+  int sb_cols =3D WINDOW_SCROLL_BAR_COLS (w);
+  int frame_col;
+  if (WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (w))
+    frame_col =3D WINDOW_LEFT_EDGE_COL (w);
+  else
+    frame_col =3D WINDOW_RIGHT_EDGE_COL (w) - sb_cols;
+
+  /* For a right scroll bar on a non-rightmost TTY window, the last
+     column of the window allocation holds the '|' border glyph
+     (placed there by build_frame_matrix_from_leaf_window).  Shift the
+     SB indicator one column left so the layout becomes
+     [content][SB][|] rather than [content][|][SB].  */
+  bool right_border
+    =3D (!FRAME_WINDOW_P (f)
+       && WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_RIGHT (w)
+       && !WINDOW_RIGHTMOST_P (w));
+  if (right_border)
+    frame_col -=3D 1;
+
+  /* Compute thumb position within sb_rows.
+     The hook passes: portion =3D visible chars, whole =3D total chars,
+     position =3D char position of first visible line.
+     When the whole buffer fits in the window, portion >=3D whole and the
+     thumb spans the full bar.
+
+     We compute the track regions above and below the thumb by rounding
+     each down separately.  This keeps the thumb height constant as the
+     user scrolls: the thumb always abuts the top rail when position=3D=3D0
+     and the bottom rail when position+portion=3D=3Dwhole.  */
+  int thumb_start =3D 0, thumb_end =3D sb_rows;
+  if (whole > 0 && portion < whole)
+    {
+      int track_above =3D (int) ((double) position / whole * sb_rows);
+      ptrdiff_t below_chars =3D (ptrdiff_t) whole - position - portion;
+      int track_below =3D (below_chars > 0)
+	? (int) ((double) below_chars / whole * sb_rows) : 0;
+      /* When content exists beyond the visible area but the proportional
+	 track size rounds to zero, ensure at least 1 track row so the
+	 thumb never appears full-height when the buffer is not fully
+	 visible.  */
+      if (position > 0 && track_above =3D=3D 0)
+	track_above =3D 1;
+      if (below_chars > 0 && track_below =3D=3D 0)
+	track_below =3D 1;
+      thumb_start =3D track_above;
+      thumb_end   =3D sb_rows - track_below;
+      /* Guarantee at least a 1-row thumb.  */
+      if (thumb_end <=3D thumb_start)
+	thumb_end =3D thumb_start + 1;
+      thumb_start =3D min (thumb_start, sb_rows - 1);
+      thumb_end   =3D min (thumb_end,   sb_rows);
+      if (thumb_start >=3D thumb_end)
+	thumb_end =3D thumb_start + 1;
+    }
+
+  /* Write scroll bar glyphs into the frame desired matrix.  */
+  for (int r =3D 0; r < sb_rows; r++)
+    {
+      int frame_row =3D frame_y_top + top_skip + r;
+      if (frame_row >=3D matrix->nrows)
+	break;
+
+      struct glyph_row *frow =3D matrix->rows + frame_row;
+
+      /* Determine face: thumb (inverse video) or track (dark background).=
  */
+      bool is_thumb =3D (r >=3D thumb_start && r < thumb_end);
+      int face_id =3D is_thumb ? SCROLL_BAR_THUMB_FACE_ID : SCROLL_BAR_FAC=
E_ID;
+
+      /* Write sb_cols scroll bar glyphs into the frame row.  */
+      struct glyph *g =3D frow->glyphs[TEXT_AREA] + frame_col;
+      for (int c =3D 0; c < sb_cols; c++, g++)
+	{
+	  g->type =3D CHAR_GLYPH;
+	  g->u.ch =3D ' ';
+	  g->face_id =3D face_id;
+	  g->padding_p =3D false;
+	  g->charpos =3D -1;
+	  g->frame =3D f;
+	}
+      /* Ensure the used count covers the scroll bar column, and for the
+	 right-border case also the '|' glyph one column to its right.  */
+      int need =3D frame_col + sb_cols + (right_border ? 1 : 0);
+      if (frow->used[TEXT_AREA] < need)
+	frow->used[TEXT_AREA] =3D need;
+      /* Mark the row enabled so it gets written to the terminal.  */
+      frow->enabled_p =3D true;
+    }
+}
+
+/* Apply character-based scroll bar glyphs to frame F's desired matrix.
+   Called after build_frame_matrix so fill_up_glyph_row_with_spaces has
+   run, and we can safely overwrite the scroll bar columns.  */
+static void
+tty_apply_scroll_bar_glyphs (struct frame *f)
+{
+  if (!f->desired_matrix)
+    return;
+  tty_apply_scroll_bar_glyphs_for_window (f, XWINDOW (f->root_window));
+}
+
 static void
 update_tty_frame (struct frame *f)
 {
   build_frame_matrix (f);
+  /* Apply character-based scroll bar glyphs after fill_up_glyph_row_with_=
spaces
+     has run (which is called from build_frame_matrix).  */
+  if (FRAME_TERMCAP_P (f))
+    tty_apply_scroll_bar_glyphs (f);
 }
=20
 #ifndef HAVE_ANDROID
@@ -3942,6 +4161,11 @@ abs_cursor_pos (struct frame *f, int *x, int *y)
       int wx =3D window_to_frame_hpos (w, w->cursor.hpos);
       int wy =3D window_to_frame_vpos (w, w->cursor.vpos);
=20
+      /* cursor.hpos is TEXT_AREA-relative; account for the left scroll
+	 bar width so the absolute cursor position is in the text area.
+	 Mini-windows have no scroll bar even when the frame does.  */
+      if (!MINI_WINDOW_P (w))
+	wx +=3D WINDOW_LEFT_SCROLL_BAR_COLS (w);
       wx +=3D max (0, w->left_margin_cols);
=20
       root_xy (f, wx, wy, x, y);
@@ -5746,6 +5970,12 @@ tty_set_cursor (struct frame *f)
 	  int x =3D window_to_frame_hpos (w, w->cursor.hpos);
 	  int y =3D window_to_frame_vpos (w, w->cursor.vpos);
=20
+	  /* cursor.hpos is TEXT_AREA-relative; add the left scroll bar
+	     width so the terminal cursor lands in the text area, not in
+	     the scroll bar column.  Mini-windows have no scroll bar even
+	     when the frame does, so skip the offset for them.  */
+	  if (!MINI_WINDOW_P (w))
+	    x +=3D WINDOW_LEFT_SCROLL_BAR_COLS (w);
 	  x +=3D max (0, w->left_margin_cols);
 	  cursor_to (f, y, x);
 	}
diff --git a/src/frame.c b/src/frame.c
index 2c0a27cf47c..ffbb234d6a1 100644
--- a/src/frame.c
+++ b/src/frame.c
@@ -204,7 +204,9 @@ frame_inhibit_resize (struct frame *f, bool horizontal,=
 Lisp_Object parameter)
   return (EQ (frame_inhibit_implied_resize, Qforce)
 	  || (f->after_make_frame
 #ifdef USE_GTK
-	      && f->tool_bar_resized
+	      /* TTY and MSDOS frames have no tool bar and tool_bar_resized
+		 is never set for them; handle them like non-GTK builds.  */
+	      && (f->tool_bar_resized || FRAME_TERMCAP_P (f) || FRAME_MSDOS_P (f))
 #endif
 	      && (EQ (frame_inhibit_implied_resize, Qt)
 		  || (CONSP (frame_inhibit_implied_resize)
@@ -1184,8 +1186,8 @@ make_frame (bool mini_p)
   f->new_width =3D -1;
   f->new_height =3D -1;
   f->no_special_glyphs =3D false;
-#ifdef HAVE_WINDOW_SYSTEM
   f->vertical_scroll_bar_type =3D vertical_scroll_bar_none;
+#ifdef HAVE_WINDOW_SYSTEM
   f->horizontal_scroll_bars =3D false;
   f->want_fullscreen =3D FULLSCREEN_NONE;
   f->undecorated =3D false;
@@ -1448,11 +1450,7 @@ make_initial_frame (void)
=20
   FRAME_FOREGROUND_PIXEL (f) =3D FACE_TTY_DEFAULT_FG_COLOR;
   FRAME_BACKGROUND_PIXEL (f) =3D FACE_TTY_DEFAULT_BG_COLOR;
-
-#ifdef HAVE_WINDOW_SYSTEM
   f->vertical_scroll_bar_type =3D vertical_scroll_bar_none;
-  f->horizontal_scroll_bars =3D false;
-#endif
=20
   /* The default value of menu-bar-mode is t.  */
   set_menu_bar_lines (f, make_fixnum (1), Qnil);
@@ -4186,13 +4184,13 @@ DEFUN ("frame-parameter", Fframe_parameter, Sframe_=
parameter, 2, 2, 0,
       /* Avoid consing in frequent cases.  */
       if (EQ (parameter, Qname))
 	value =3D f->name;
-#ifdef HAVE_WINDOW_SYSTEM
       /* These are used by vertical motion commands.  */
       else if (EQ (parameter, Qvertical_scroll_bars))
 	value =3D (f->vertical_scroll_bar_type =3D=3D vertical_scroll_bar_none
 		 ? Qnil
 		 : (f->vertical_scroll_bar_type =3D=3D vertical_scroll_bar_left
 		    ? Qleft : Qright));
+#ifdef HAVE_WINDOW_SYSTEM
       else if (EQ (parameter, Qhorizontal_scroll_bars))
 	value =3D f->horizontal_scroll_bars ? Qt : Qnil;
       else if (EQ (parameter, Qline_spacing) && f->extra_line_spacing =3D=
=3D 0)
@@ -4301,6 +4299,8 @@ DEFUN ("modify-frame-parameters", Fmodify_frame_param=
eters,
 	  if (EQ (prop, Qforeground_color)
 	      || EQ (prop, Qbackground_color))
 	    update_face_from_frame_parameter (f, prop, val);
+	  else if (EQ (prop, Qvertical_scroll_bars))
+	    tty_set_vertical_scroll_bars (f, val);
 	}
=20
       if (is_tty_child_frame (f))
diff --git a/src/frame.h b/src/frame.h
index 091b112e8b9..1e2775c6a54 100644
--- a/src/frame.h
+++ b/src/frame.h
@@ -452,6 +452,11 @@ #define EMACS_FRAME_H
      via mouse clicks or by moving the mouse into it.  */
   bool_bf no_accept_focus : 1;
=20
+  /* If not vertical_scroll_bar_none, we should actually display the
+     scroll bars of this type on this frame.  Available on all frame
+     types, including TTY frames for character-based scroll bars.  */
+  ENUM_BF (vertical_scroll_bar_type) vertical_scroll_bar_type : 2;
+
 #ifdef HAVE_WINDOW_SYSTEM
   /* True if this frame is a tooltip frame.  */
   bool_bf tooltip : 1;
@@ -459,10 +464,6 @@ #define EMACS_FRAME_H
   /* See FULLSCREEN_ enum on top.  */
   ENUM_BF (fullscreen_type) want_fullscreen : 4;
=20
-  /* If not vertical_scroll_bar_none, we should actually
-     display the scroll bars of this type on this frame.  */
-  ENUM_BF (vertical_scroll_bar_type) vertical_scroll_bar_type : 2;
-
   /* Nonzero if we should actually display horizontal scroll bars on this =
frame.  */
   bool_bf horizontal_scroll_bars : 1;
=20
@@ -1211,9 +1212,8 @@ #define FRAME_INSERTN_COST(f) (f)->insert_n_lines_cost
 #define FRAME_DELETEN_COST(f) (f)->delete_n_lines_cost
 #define FRAME_FOCUS_FRAME(f) f->focus_frame
=20
-#ifdef HAVE_WINDOW_SYSTEM
 /* This frame slot says whether scroll bars are currently enabled for fram=
e F,
-   and which side they are on.  */
+   and which side they are on.  Works for all frame types including TTY.  =
*/
 #define FRAME_VERTICAL_SCROLL_BAR_TYPE(f) ((f)->vertical_scroll_bar_type)
 #define FRAME_HAS_VERTICAL_SCROLL_BARS(f) \
   ((f)->vertical_scroll_bar_type !=3D vertical_scroll_bar_none)
@@ -1221,14 +1221,6 @@ #define FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT(f) \
   ((f)->vertical_scroll_bar_type =3D=3D vertical_scroll_bar_left)
 #define FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT(f) \
   ((f)->vertical_scroll_bar_type =3D=3D vertical_scroll_bar_right)
-#else /* not HAVE_WINDOW_SYSTEM */
-/* If there is no window system, there are no scroll bars.  */
-#define FRAME_VERTICAL_SCROLL_BAR_TYPE(f) \
-  ((void) (f), vertical_scroll_bar_none)
-#define FRAME_HAS_VERTICAL_SCROLL_BARS(f) ((void) (f), 0)
-#define FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT(f) ((void) (f), 0)
-#define FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT(f) ((void) (f), 0)
-#endif /* HAVE_WINDOW_SYSTEM */
=20
 INLINE struct frame *
 FRAME_PARENT_FRAME (struct frame *f)
@@ -1503,6 +1495,7 @@ window_system_available (struct frame *f)
=20
 extern WINDOW_SYSTEM_RETURN void check_window_system (struct frame *);
 struct frame *decode_tty_frame (Lisp_Object frame);
+extern void tty_set_vertical_scroll_bars (struct frame *, Lisp_Object);
 extern void frame_make_pointer_invisible (struct frame *);
 extern void frame_make_pointer_visible (struct frame *);
 extern struct frame *root_frame (struct frame *f);
diff --git a/src/term.c b/src/term.c
index 354375085e2..e35eda745dd 100644
--- a/src/term.c
+++ b/src/term.c
@@ -62,6 +62,13 @@
 #include "w32term.h"
 #endif
=20
+static void tty_set_vertical_scroll_bar (struct window *w,
+					 int portion, int whole, int position);
+static void tty_condemn_scroll_bars (struct frame *f);
+static void tty_redeem_scroll_bar (struct window *w);
+static void tty_judge_scroll_bars (struct frame *f);
+static void tty_set_scroll_bar_default_width (struct frame *f);
+
 #ifndef HAVE_ANDROID
=20
 static void tty_set_scroll_region (struct frame *f, int start, int stop);
@@ -976,7 +983,7 @@ tty_write_glyphs (struct frame *f, struct glyph *string=
, int len)
      since that would scroll the whole frame on some terminals.  */
   if (AutoWrap (tty)
       && curY (tty) + 1 =3D=3D FRAME_TOTAL_LINES (f)
-      && curX (tty) + len =3D=3D FRAME_COLS (f)
+      && curX (tty) + len =3D=3D FrameCols (tty)
       && len > 0)
     {
       /* If writing only one glyph in the last column, make that two so
@@ -4335,7 +4342,15 @@ set_tty_hooks (struct terminal *terminal)
   terminal->delete_terminal_hook =3D &delete_tty;
=20
   terminal->frame_raise_lower_hook =3D tty_raise_lower_frame;
-  /* Other hooks are NULL by default.  */
+
+  /* Scroll Bar Hooks */
+  terminal->set_vertical_scroll_bar_hook =3D tty_set_vertical_scroll_bar;
+  terminal->condemn_scroll_bars_hook =3D tty_condemn_scroll_bars;
+  terminal->redeem_scroll_bar_hook =3D tty_redeem_scroll_bar;
+  terminal->judge_scroll_bars_hook =3D tty_judge_scroll_bars;
+  terminal->set_scroll_bar_default_width_hook =3D tty_set_scroll_bar_defau=
lt_width;
+
+   /* Other hooks are NULL by default.  */
 }
=20
 /* If FD is the controlling terminal, drop it.  */
@@ -4378,6 +4393,96 @@ dissociate_if_controlling_tty (int fd)
 _Noreturn
 #endif
=20
+/* Set the vertical scroll bar for window W to show PORTION/WHOLE of
+   the buffer, with scroll position POSITION.  Stores the info in the
+   window's vertical_scroll_bar slot as [portion whole position] for
+   later rendering by tty_apply_scroll_bar_glyphs.  */
+static void
+tty_set_vertical_scroll_bar (struct window *w,
+			     int portion, int whole, int position)
+{
+  struct frame *f =3D XFRAME (WINDOW_FRAME (w));
+
+  if (! FRAME_TERMCAP_P (f))
+    return;
+
+  /* Store scroll bar parameters for later rendering.  We can't render
+     here because build_frame_matrix hasn't been called yet and would
+     overwrite our glyphs.  Instead, tty_apply_scroll_bar_glyphs (called
+     from update_tty_frame after build_frame_matrix) will do the rendering=
=2E  */
+  w->vertical_scroll_bar =3D make_vector (3, make_fixnum (0));
+  ASET (w->vertical_scroll_bar, 0, make_fixnum (portion));
+  ASET (w->vertical_scroll_bar, 1, make_fixnum (whole));
+  ASET (w->vertical_scroll_bar, 2, make_fixnum (position));
+}
+
+static void
+tty_condemn_scroll_bars (struct frame *f)
+{
+}
+
+static void
+tty_redeem_scroll_bar (struct window *w)
+{
+}
+
+static void
+tty_judge_scroll_bars (struct frame *f)
+{
+}
+
+/* Set scroll bar default width for TTY frames: 1 character column.  */
+static void
+tty_set_scroll_bar_default_width (struct frame *f)
+{
+  /* For TTY, scroll bars are 1 character wide.  */
+  FRAME_CONFIG_SCROLL_BAR_WIDTH (f) =3D 1;
+  FRAME_CONFIG_SCROLL_BAR_COLS (f) =3D 1;
+}
+
+/* Called from frame.c when the vertical-scroll-bars parameter is changed
+   for a TTY frame.  */
+void
+tty_set_vertical_scroll_bars (struct frame *f, Lisp_Object arg)
+{
+  if (! FRAME_TERMCAP_P (f))
+    return;
+
+  enum vertical_scroll_bar_type new_type
+    =3D (NILP (arg)
+       ? vertical_scroll_bar_none
+       : EQ (Qleft, arg)
+       ? vertical_scroll_bar_left
+       : EQ (Qright, arg)
+       ? vertical_scroll_bar_right
+       : EQ (Qleft, Vdefault_frame_scroll_bars)
+       ? vertical_scroll_bar_left
+       : EQ (Qright, Vdefault_frame_scroll_bars)
+       ? vertical_scroll_bar_right
+       : vertical_scroll_bar_none);
+
+  if (FRAME_VERTICAL_SCROLL_BAR_TYPE (f) =3D=3D new_type)
+    return;
+
+  FRAME_VERTICAL_SCROLL_BAR_TYPE (f) =3D new_type;
+
+  /* Set the scroll bar width if enabling scroll bars.  */
+  if (new_type !=3D vertical_scroll_bar_none
+      && FRAME_TERMINAL (f)->set_scroll_bar_default_width_hook)
+    (*FRAME_TERMINAL (f)->set_scroll_bar_default_width_hook) (f);
+
+  /* Trigger a full redisplay.  adjust_frame_size recalculates window
+     text areas to account for the newly-reserved scroll bar columns.
+     When only the scroll bar side changes (e.g. right=E2=86=92left) all f=
rame
+     dimensions stay identical and adjust_frame_size returns early
+     without calling adjust_frame_glyphs.  Call it explicitly so that
+     the glyph matrix TEXT_AREA pointers (shifted by sbl/sbr) are
+     always updated to match the new scroll bar layout.  */
+  adjust_frame_size (f, -1, -1, 3, 0, Qvertical_scroll_bars);
+  adjust_frame_glyphs (f);
+  SET_FRAME_GARBAGED (f);
+}
+
 struct terminal *
 init_tty (const char *name, const char *terminal_type, bool must_succeed)
 {
diff --git a/src/window.c b/src/window.c
index 3dbf1530d78..066c7872c84 100644
--- a/src/window.c
+++ b/src/window.c
@@ -1100,7 +1100,19 @@ window_body_width (struct window *w, enum window_bod=
y_unit pixelwise)
   int width =3D (w->pixel_width
 	       - WINDOW_RIGHT_DIVIDER_WIDTH (w)
 	       - (WINDOW_HAS_VERTICAL_SCROLL_BAR (w)
-		  ? WINDOW_SCROLL_BAR_AREA_WIDTH (w)
+		  ? (WINDOW_SCROLL_BAR_AREA_WIDTH (w)
+		     /* On TTY frames a right scroll bar acts as the window
+			separator, so we reserve one extra character column
+			for the '|' border glyph that
+			build_frame_matrix_from_leaf_window inserts.  This
+			keeps the border visually separate from the scroll bar
+			indicator (thumb/track) even when the buffer is short
+			enough to fill the bar with a full-height thumb.
+			Left scroll bars already have a dedicated border column
+			(the condition below), so this adjustment is right-only.  */
+		     + (!FRAME_WINDOW_P (f)
+			&& !WINDOW_RIGHTMOST_P (w)
+			&& WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_RIGHT (w)))
 		  : (/* A vertical bar is either 1 or 0.  */
 		     !FRAME_WINDOW_P (f)
 		     && !WINDOW_RIGHTMOST_P (w)
diff --git a/src/xfaces.c b/src/xfaces.c
index 010b0e1847e..2f4d9f7e65e 100644
--- a/src/xfaces.c
+++ b/src/xfaces.c
@@ -5212,6 +5212,7 @@ lookup_basic_face (struct window *w, struct frame *f,=
 int face_id)
     case INTERNAL_BORDER_FACE_ID:	name =3D Qinternal_border; 	break;
     case CHILD_FRAME_BORDER_FACE_ID:	name =3D Qchild_frame_border; 	break;
     case MARGIN_FACE_ID:		name =3D Qmargin;			break;
+    case SCROLL_BAR_THUMB_FACE_ID:	name =3D Qscroll_bar_thumb;	break;
=20
     default:
       emacs_abort (); /* the caller is supposed to pass us a basic face id=
 */
@@ -5980,6 +5981,7 @@ realize_basic_faces (struct frame *f)
       realize_named_face (f, Qtab_line_active, TAB_LINE_ACTIVE_FACE_ID);
       realize_named_face (f, Qtab_line_inactive, TAB_LINE_INACTIVE_FACE_ID=
);
       realize_named_face (f, Qmargin, MARGIN_FACE_ID);
+      realize_named_face (f, Qscroll_bar_thumb, SCROLL_BAR_THUMB_FACE_ID);
       unbind_to (count, Qnil);
=20
       /* Reflect changes in the `menu' face in menu bars.  */
@@ -7544,6 +7546,7 @@ syms_of_xfaces (void)
   DEFSYM (Qheader_line_inactive, "header-line-inactive");
   DEFSYM (Qheader_line_active, "header-line-active");
   DEFSYM (Qscroll_bar, "scroll-bar");
+  DEFSYM (Qscroll_bar_thumb, "scroll-bar-thumb");
   DEFSYM (Qmenu, "menu");
   DEFSYM (Qcursor, "cursor");
   DEFSYM (Qborder, "border");

--36I/gurMzNR42vlK--

--JZGPDlq/4kg2H8cZ
Content-Type: application/pgp-signature; name="signature.asc"

-----BEGIN PGP SIGNATURE-----

iQIzBAABCgAdFiEEDXVee01gWrPIdWPRwgRAue7sYQMFAmn9+oIACgkQwgRAue7s
YQO7uRAAolB4AHspvZNAyJ2Nr/ymqW3IfSdSaF8H0NvJhLVOojJuUNIidy2f1DVo
ugo56tEHXqEGykM0KsdoObXeuA0zbP+kuYTXMRfqfjNk4Js4lIBrGcI6eGaVgq4R
xvObIlCwjLnT+NozlTYM/nhTLUoT4mHg3NlYirsFAVM1Z4JeNuvfMYLmUOL90WkU
k/tgGVorLf2c0lNmkVa5vfrpGrpmwPAm4qCRxxd1FC7ILvWP26jB05EvwA1RQuRh
BPWNpMcU/4QAKg+Cee8pa6ff4ZDt/OWRPZN9SczPEHG35eY20inbesOlQtYmyVNj
rs+znhmhGrgoj4hZ6Hn4KdLUjhiTsB0pA4pSQX+NGaW2D/Mkz9wsMDkUBdfqw3I6
fOHN6nn2NBSsal3SGmj5LiyzX0wMbiCPNrJsIlDcf6OTt+eBrlu+vCbmhUn/YrJt
Mwgwuk9diKWrjyaMmwmZx0Uga0Ieb4GIw5zVJNxAaIeS6r0fwS3STN+ZIYNsrNTN
1Ps2sy0lidGGv7sp8iPBoDnBngZI6YNYfCzZ2VU6EExT8kSUVIUE9BBW0ydCLmE9
v6gqT5NdQkSDK5pVCHmjoig2mL5oc3msMWNOkT1vQ00E+JISp24jH8xNCwzVkZUE
CfiUiEhz8egqIBX8jvjUnydWbJ+clk8s9HSIijaSo8H3EkYbmew=
=f+hp
-----END PGP SIGNATURE-----

--JZGPDlq/4kg2H8cZ--




Acknowledgement sent to Michael Grant <mgrant@HIDDEN>:
New bug report received and forwarded. Copy sent to bug-gnu-emacs@HIDDEN. Full text available.
Report forwarded to bug-gnu-emacs@HIDDEN:
bug#80993; Package emacs. Full text available.
Please note: This is a static page, with minimal formatting, updated once a day.
Click here to see this page with the latest information and nicer formatting.
Last modified: Fri, 26 Jun 2026 11:30:05 UTC

GNU bug tracking system
Copyright (C) 1999 Darren O. Benham, 1997 nCipher Corporation Ltd, 1994-97 Ian Jackson.