wez / wezterm

A GPU-accelerated cross-platform terminal emulator and multiplexer written by @wez and implemented in Rust
https://wezfurlong.org/wezterm/
Other
16.69k stars 746 forks source link

Fancy tab/title bar/frame #1180

Open wez opened 2 years ago

wez commented 2 years ago

This issue is tracking the work needed to provide a Chrome/Firefox style integrated tab/titlebar.

The intent is for it to be usable in place of the existing tab bar, potentially replacing it completely in the future; a config option will allow choosing between the two while things are worked out.

There are some considerations that need to be made for how to translate the existing monospace/cell based tab and right-status configurations to the new thing. I'll punt those for now

The custom titlebar has a number of platform specific considerations that are architecturally a bit awkward:

Anyway, with a design that accommodates the above, we could have a nice looking tab/title bar with new tab button that is more visually appealing that the simpler cell based tab bar.

sdrik commented 2 years ago

Hi,

Now that the fancy tab bar is the default, I'm wondering if the old tab bar will still be maintained. Because if that wasn't the case, it would totally ruin my setup.

use_fancy_tab_bar = false connected to a local tmux Capture d’écran de 2021-12-28 12-07-04 (the bottom bar comes from wezterm, the bar just above comes from tmux)

use_fancy_tab_bar = false connected to a remote tmux Capture d’écran de 2021-12-28 12-35-20 (the bottom bar comes from wezterm, the bar just above comes from tmux)

use_fancy_tab_bar = true connected to a local tmux Capture d’écran de 2021-12-28 11-51-06 (the top bar comes from wezterm, the bottom bar comes from tmux)

use_fancy_tab_bar = true connected to a remote tmux Capture d’écran de 2021-12-28 12-39-16 (the top bar comes from wezterm, the bottom bar comes from tmux)

I understand that embedding the tab bar in the title bar makes it impossible to render it at the bottom, but if title bar is disabled like in my setup, that would make sense. It should also be possible to make it only 1 cell height.

Anyway, thank you for your hard work !

wez commented 2 years ago

494a0983eef8f883ccd1a390d17a272a8d3293ee enables the fancy tab bar to be placed at the bottom, and a couple of other changes today tighten up its appearance. Fancy tabs do need to be taller than a single monospace row to accommodate the button UI/borders, but not as big as they were from your screenshot. Please grab a more recent nightly (from about an hour from now) and give it a try and let me know how well that works out for you.

I do think that the non-fancy tabs are an important aesthetic choice to preserve for wezterm's user community, so I plan on keeping them around!

gegoune commented 2 years ago

Thanks for keeping current implementation. I really like them and was worried that it will be replaced by native macOS tabs.

eugenesvk commented 2 years ago

Fancy tabs do need to be taller than a single monospace row to accommodate the button UI/borders

is it possible to disable all that to retain the same height (I've also noticed there is some unneeded vertical padding above/left of tabs, is that styling configurable)? I like the fact that you can use proportional fonts for the tab names, but don't like that I have to lose vertical space for that

davidrios commented 2 years ago

Note that on Windows, that DWM stuff is outdated as of Windows 10. I have some code to advance this issue on Windows in PRs #1675, or #1677 for more features and native feel. Considering that, I guess the only thing missing on Windows would be the minimize/maximize/close buttons.

I did some experiments to see if it was feasible to use the native tab bar from Windows Terminal, but I couldn't get it to work from Rust. There's not a lot of documentation out there, and the Windows Rust stuff are in still in heavy development, besides the fact that I'm not really a Windows programmer.

wez commented 2 years ago

Regarding platform-native tab bars: I'm not enthusiastic about using them (or other GUI toolkit type things) because they generally assume/require that the rest of the app also adopts that toolkit. That's problematic for a cross platform app like wezterm which doesn't do that, and that would have to to jump through some gnarly hoops on multiple different platforms to make that work. The effort/reward ratio isn't good enough to warrant it IMO.

davidrios commented 2 years ago

I totally agree, that's why I focused on making the current tab bar feel native on Windows, with as little intervention as possible in the main code.

miversen33 commented 1 year ago

I believe this is probably a better place to ask this vs opening a new issue about requests for the "fancy" tab bar.

It feels like there is alot less customization that is available with the fancy tab bar and I am wondering if that is a long term plan (making something that feels more "done"/"ready" out of the box?).

An example, formatting the tab is proving to be... Painful. Following the tab style doc, if I enable fancy tab bar and use the provided "elaborate" configuration

local wezterm = require("wezterm")

-- The filled in variant of the < symbol
local SOLID_LEFT_ARROW = wezterm.nerdfonts.pl_right_hard_divider

-- The filled in variant of the > symbol
local SOLID_RIGHT_ARROW = wezterm.nerdfonts.pl_left_hard_divider
wezterm.on(
'format-tab-title',
function(tab, tabs, panes, config, hover, max_width)
    local edge_background = '#0b0022'
    local background = '#1b1032'
    local foreground = '#808080'

    if tab.is_active then
        background = '#2b2042'
        foreground = '#c0c0c0'
    elseif hover then
        background = '#3b3052'
        foreground = '#909090'
    end

    local edge_foreground = background

    -- ensure that the titles fit in the available space,
    -- and that we have room for the edges.
    local title = wezterm.truncate_right(tab.active_pane.title, max_width - 2)

    return {
        { Background = { Color = edge_background } },
        { Foreground = { Color = edge_foreground } },
        { Text = SOLID_LEFT_ARROW },
        { Background = { Color = background } },
        { Foreground = { Color = foreground } },
        { Text = title },
        { Background = { Color = edge_background } },
        { Foreground = { Color = edge_foreground } },
        { Text = SOLID_RIGHT_ARROW },
    }
end)

return {
    use_fancy_tab_bar = true
}

You get a tab bar that looks like this. image There doesn't appear to be any way to "further" configure the tab itself (see #3158 for some confusion on this as well), just its contents. Things like defining what the edges of the tabs look like, changing the padding within them, removing the "x" or moving it, removing/adjusting the padding of tabs to the window, etc all appear to be non-configurable at this point in time.

This leaves those of us that want to have a more "custom" tab bar left with using the "non fancy" version. And that is fine as long as that is the intended goal. I guess the question is, is it?

As always, thank you for the work you put into this project, it is amazing :)

wez commented 1 year ago

What I've got in mind here is something like this:

Deprecate use_fancy_tab_bar in favor of a new setting:

-- sets up appearance in retro style; monospace font, no extra padding, no symbol glyphs
config.tab_bar_appearance = "Retro"
-- Adopts the current default fancy styling with more padding, more distinct tab outline, glyphs/buttons
config.tab_bar_appearance = "Fancy"

-- or custom, where you get to control more stuff
config.tab_bar_appearance = {
   font = wezterm.font "Roboto",
   font_size = 12,
   line_height = 1.75,

   -- Defines the `active_tab` element.  Element is a box_model element, which is a recursive
   -- tree like structure which has some similarities to the DOM, but is not anywhere near as
   -- full-featured.
   -- You'll also be able to specify `inactive_tab` and `new_tab` in the same way.
   -- Note that hover state is only supported for colors in the current implementation of box_model.
   -- changing content or geometry on hover is not supported.
   active_tab = {
      -- various geometry and color config
      padding = "0.25 cell",
      border = {
         top = "2 px",
      },
      border_color = "maroon",
      border_color_hover = "pink",
      bg_color = "black",
      bg_color_hover = "gray",
      text_color = "white",
      text_color_hover = "white",
      border_corners = {
          top_left = {
              width = "0.5 cell",
              height = "0.5 cell",
              -- reference a pre-defined polygon list
              poly = "TopLeftRoundedCorner",
          },
          -- top_right, bottom_left and bottom_right can be specified here
      },

      -- what is rendered in the element
      content = {
         "TITLE", -- will be replaced with the tab title text produced by format-tab-title
         -- Define a close button
         {
             padding = "0.25 cell",
             float = "right",
             z_index = 1,
             item_type = "CloseTab", -- so that it behaves like a close tab button
             content = {
                 -- custom polygon list; this one renders an X
                 poly = {
                    {
                         path = {
                            {MoveTo={"One", "Zero"}},
                            {LineTo={"Zero", "One"}},
                         },
                         intensity = "Full",
                         style = "Outline",
                     },
                    {
                         path = {
                            {MoveTo={"Zero", "Zero"}},
                            {LineTo={"One", "One"}},
                         },
                         intensity = "Full",
                         style = "Outline",
                    },
                 }, -- poly
              }, -- content
           } -- close button
       } -- content
   },
}

There are questions about how to apply color from the tab bar colors/color scheme (basically, all the existing old tab bar configuration: I'd like to essentially remove all of those so that I don't have to maintain 3 different ways to draw tab bars), and there are probably some limitations in box_model that get in the way of making this as flexible as I'd like, but that's the idea.

I just merged in window_decorations="INTEGRATED_BUTTONS|RESIZE" support from #2722, which has some options for sticking Minimize, Maximize and Close buttons in the title bar. The same content stuff could be applied to those to draw arbitrary content for them if you want a really unique setup.

snaggen commented 1 year ago

I rarely use tabs in my terminal, instead I use splits for my main workflow. Hence, I have hide_tab_bar_if_only_one_tab = true in my config. This confused me a lot when i then added window_decorations="INTEGRATED_BUTTONS|RESIZE" to test this new fancy window decoration, since I then ended up with no window decorations at all. I suggest to either ignore the hide_tab_bar_if_only_one_tab when used with integrated buttons setting, or not render it as a tab but just as a window title in that case.

Also, a styling issue. bild This is how it look under Fedora Wayland using the Gnome Style (I have default dark style set on my desktop). The buttons are the obvious issue here (if I remove the "Gnome" setting I get normal buttons that look ok). Also, the non-rounded corners look a bit off since gnome uses rounded corners. That I see both with and without explicit style set to Gnome.

Edit: I know this is a WIP, so I didn't want to create new separate bug reports... hence I just add a comment here since I thought it might be interesting to know.

wez commented 1 year ago

@snaggen I can't reproduce that, but see the discussion on https://github.com/wez/wezterm/commit/a278dbf43f275bbac1d03a93a89d0575edf30226

The way that I view that: the significant part of that shader change appears to be clamping the alpha value of the mix color in the range 0.0..=1.0, but that value should already be in that range.

It's possible that there's some missing initialization in the case where that element is rendered, so I'd like to get to the bottom of that.

It's also possible that this is some driver specific quirk.

Since I can't reproduce it, I'd appreciate it if you could try at least switching between the OpenGL and WebGPU front ends and reporting on whether that impacts the result. If that shader change is restored, it also needs to be applied to the WebGPU shader.

wez commented 1 year ago

@snaggen hmm, maybe 718397d05481e6563c6dae5cdd7add486a2754c1 fixes it?

snaggen commented 1 year ago

Tested latest nightly, with a minimal config:

return {
    -- Integrated Title Bar
    window_decorations="INTEGRATED_BUTTONS|RESIZE",
    integrated_title_button_style = "Gnome",
}

still got the same result. The hardware I use is a intel laptop with integrated graphics, and it is 2-3 year old now I guess, so the Intel driver support is usually very good. So, it is very standard that way. Will see if I can update thye rendering frontent to test OpenGL and WebGPU.

snaggen commented 1 year ago

Now with

return {
    -- Integrated Title Bar
    window_decorations="INTEGRATED_BUTTONS|RESIZE",
    integrated_title_button_style = "Gnome",
    front_end = "WebGpu",
}

bild So, WebGpu seems to solve the button issue, so the issue seems to be in the OpenGL some where then.

snaggen commented 1 year ago

Some more information about my system:

wezterm version: 20230403-224617-8ddd0d98 x86_64-unknown-linux-gnu
Window Environment: Wayland
OpenGL version: Mesa Intel(R) UHD Graphics (CML GT2) 4.6 (Compatibility Profile) Mesa 23.0.1
 wezterm.gui.enumerate_gpus()
[
    {
        "backend": "Vulkan",
        "device": 39745,
        "device_type": "IntegratedGpu",
        "driver": "Intel open-source Mesa driver",
        "driver_info": "Mesa 23.0.1",
        "name": "Intel(R) UHD Graphics (CML GT2)",
        "vendor": 32902,
    },
    {
        "backend": "Vulkan",
        "device": 0,
        "device_type": "Cpu",
        "driver": "llvmpipe",
        "driver_info": "Mesa 23.0.1 (LLVM 15.0.7)",
        "name": "llvmpipe (LLVM 15.0.7, 256 bits)",
        "vendor": 65541,
    },
    {
        "backend": "Gl",
        "device": 0,
        "device_type": "IntegratedGpu",
        "name": "Mesa Intel(R) UHD Graphics (CML GT2)",
        "vendor": 32902,
    },
]
wez commented 1 year ago

@yuraiz are you also running with intel on wayland?

yuraiz commented 1 year ago

@yuraiz are you also running with intel on wayland?

Yes

yuraiz commented 1 year ago

It also works the same with enable_wayland=false

image

yuraiz commented 1 year ago

IDK if that's bug in shader compiler or it's something different, but rounded corners doesn't support transparency without that hack that I did in shader

BTW why don't you use shader for rounded corners?

wez commented 1 year ago

What I'm trying to reason about here is why this happens for you and not me, and whether there's something else missing in the code.

In the shader, this is the common logic for computing the foreground color:

vec4 fg_color = mix(o_fg_color, o_fg_color_alt, o_fg_color_mix);

the shader hack you mentioned essentially replaces it with this for the grayscale polyquad case, just for the alpha channel:

mix(o_fg_color.a, o_fg_color_alt.a, clamp(o_fg_color_mix, 0.0, 1.0));

the difference there is that it clamps the o_fg_color_mix to the range 0.0 -> 1.0. But in the code, in the polyquad case, o_fg_color_alt == o_fg_color and o_fg_color_mix == 0.0. That should result in that line being a NOP and carrying through the alpha value from o_fg_color.a.

So that's what's puzzling me: it seem like that clamp term should do nothing.

I can't reproduce the effect you're seeing on either my AMD system or my mac system :-/

yuraiz commented 1 year ago

For some reason fg_color have invalid alpha

image

yuraiz commented 1 year ago

So I really don't understand why does it work like it works

image

yuraiz commented 1 year ago

image

image

wez commented 1 year ago

So, it's not zero and it's not-not-equal to zero? Is it somehow NaN?

wez commented 1 year ago

Maybe try this:

diff --git a/wezterm-gui/src/quad.rs b/wezterm-gui/src/quad.rs
index cbf8196af..f847ea9e2 100644
--- a/wezterm-gui/src/quad.rs
+++ b/wezterm-gui/src/quad.rs
@@ -244,6 +244,7 @@ impl QuadTrait for BoxedQuad {

     fn set_fg_color(&mut self, color: LinearRgba) {
         self.fg_color = color.into();
+        self.set_alt_color_and_mix_value(color, 0.);
     }
     fn set_alt_color_and_mix_value(&mut self, color: LinearRgba, mix_value: f32) {
         self.alt_color = color.into();
wez commented 1 year ago

and possibly:

diff --git a/wezterm-gui/src/renderstate.rs b/wezterm-gui/src/renderstate.rs
index 6fcc2695e..0583d702c 100644
--- a/wezterm-gui/src/renderstate.rs
+++ b/wezterm-gui/src/renderstate.rs
@@ -302,6 +302,7 @@ impl<'a> QuadAllocator for MappedQuads<'a> {
         };

         quad.set_has_color(false);
+        quad.set_fg_color(::window::color::LinearRgba::TRANSPARENT);

         Ok(QuadImpl::Vert(quad))
     }
yuraiz commented 1 year ago

For some reason those things aren't work, but if I override mix color in vertex shader it works

wez commented 1 year ago

What if the alpha is messed up on this side? Try hardcoding a value with explicit alpha here, in case there is something weird with the mul_alpha stuff? (doesn't look like there could be, but everything about this seems weird!)

https://github.com/wez/wezterm/blob/8ddd0d986d8cd609966bee1ddaa8d8351a0fb4e7/wezterm-gui/src/termwindow/render/window_buttons.rs#L204-L210

wez commented 1 year ago

I dug up an older laptop that has intel graphics to try this, and had to admit defeat. I've added that line back to the shader.

yuraiz commented 1 year ago

Ok, what about window border and rounded corners for wayland?

I can't resize window by top corners. Also I want border with rounded corners to match other apps on my system

yuraiz commented 1 year ago

Screencast from 2023-04-06 19-53-38.webm

snaggen commented 1 year ago

It would also be nice to either set the tab color, or have it default to something that matches native (Gnome in my case).

snaggen commented 1 year ago

Another issue I found, was that when I unplugged my laptop from the seconday screen, then it changes resolution. I use a lower resolution than my native 4k, to match the dpi on the secondary screen since Xwayland doesn't work well with multi dpi setup. So when I unplug it switches from a lower resolution to native 4k with 200% scaling. So after the resolution change I got this:

bild

snaggen commented 1 year ago

Update: The small close button is not related to the resize, since it is rendered that way on a clean reboot. The issue is probably just that the rendering doesn't account for the scale factor, in this case I have a 4k screen with 200% scale factor.

yuraiz commented 1 year ago

Yes, wezterm itself handles scale properly. I just didn't find how to get it. You can try windows style, it should respect scale factor

wez commented 1 year ago

I'd suggest looking at https://github.com/wez/wezterm/blob/main/wezterm-gui/src/termwindow/render/fancy_tab_bar.rs#L132-L136 which shows how the + button in the fancy tab bar works

yuraiz commented 1 year ago

Widget sizes in gtk are defined in pixels, so I want to have an ability to get the scale factor directly

pwsandoval commented 1 year ago

This icons can they be customized?

Screenshot_1a

yuraiz commented 1 year ago

This icons can they be customized?

Check tab_bar_style as you use retro tab bar

https://wezfurlong.org/wezterm/config/lua/config/tab_bar_style.html?h=#retro-tab-bar-with-integrated-window-management-buttons

yuraiz commented 1 year ago

@pwsandoval

If I understand correctly you use windows, so I'd recommend to set use_fancy_tab_bar = true and it will match other windows apps

pwsandoval commented 1 year ago

@pwsandoval

If I understand correctly you use windows, so I'd recommend to set use_fancy_tab_bar = true and it will match other windows apps

I understand, but if I use_fancy_tab_bar = false, is there a way to customize this by, maybe some icons from my fallback font, or an image, etc?

yuraiz commented 1 year ago

@pwsandoval yes, in that case you can customize them the same way as you customize tabs: change text, background and foreground colors

But them aren't actual icons in that case, but just " . ", ” - " and " X " strings

https://github.com/wez/wezterm/issues/1180#issuecomment-1579350670

hanxi commented 1 year ago

@pwsandoval yes, in that case you can customize them the same way as you customize tabs: change text, background and foreground colors

But them aren't actual icons in that case, but just " . ", ” - " and " X " strings

#1180 (comment)

Do you know how to modify string to '-' '+' 'x'?

yuraiz commented 1 year ago

@pwsandoval, @hanxi

image

    tab_bar_style = {
        window_hide = " minimize ",
        window_maximize = " maximize ",
        window_close = " close ",

        window_close_hover = " CLOSE ",
        window_hide_hover = " MINIMIZE ",
        window_maximize_hover = " MAXIMIZE ",
    },
frencojobs commented 1 year ago

Hopefully this is the right issue to address this, but I'd like to suggest that the integrated buttons should be vertically aligned to the fancy title bar. For example, chrome compared to Wezterm.

image
wez commented 1 year ago

@frencojobs macos owns those buttons. Moving them is something that may be possible, but will require some effort as there isn't a simple way of expressing that request to macOS. I'd welcome a PR that takes care of that!

frencojobs commented 1 year ago

macos owns those buttons. Moving them is something that may be possible, but will require some effort as there isn't a simple way of expressing that request to macOS. I'd welcome a PR that takes care of that!

I'll try to see if I can come up with a good way to approach this, but it seems a bit tricker than I initially thought. Wezterm is currently using the default titlebar and just setting the color to transparent. I don't think it's possible to set that titlebar's height, and according to the docs we'll have to use something called toolbar or something. I'm not exactly familiar with all these, rust, objc or macOS stuff but I'll give it a try.

Also, I was trying out INTEGRATED_BUTTONS and I think there's room for improvement. If the window decoration config contains INTEGRATED_BUTTONS, these conditions should be handled exhaustively (they currently aren't).

-- this is the case for when the integrated buttons and the tabbar is separated
1. if tab bar is disabled or at the bottom,
    -> add the height of the titlebar as top padding, show title in the middle
    -- this is what kitty does

-- this is when the buttons and tabbar is both on top
2. if tab bar is at the top and it is fancy
    -> if integrated buttons are on left, add a left padding to the tabbar
    -> if integrated buttons are on the right side, add a right padding to the tabbar

3. if tab bar is at the top and it is not fancy
    -- Wezterm maybe shouldn't allow this combination? 
    -- this makes things look weird because the integrated buttons are often larger 
    -- than the tabbar height, which is a single row

Here's what it looks like currently because condition 1 and 2 not being handled.

SCR-20230729-bqvy

Here's what it looks like after condition 1 and 2 is properly handled.

SCR-20230729-brio

I'd like to submit a PR but I haven't really figured out how to programmatically get the height of titlebar and the total width of control buttons to pad. I just made the above screenshot with hard coded values as a POC.

wez commented 1 year ago

@frencojobs if you'd like to submit a draft PR, we can discuss the details there and figure out how to solve it.

I'm currently fairly overwhelmed by the number of users making and commenting on issues, so from a time management perspective, I'm only reviewing a few issues at a time when I have time to work through part of the backlog.

I do try to prioritize PRs over issue triage, so we'd be able to communicate faster about this on a PR.

martin-braun commented 7 months ago

@frencojobs

Look at how iTerm solves the issue with the buttons when you explicitly wish to hide the title bar:

2024-01-23 11 54 41

I went with window_decorations = "RESIZE|MACOS_FORCE_DISABLE_SHADOW" which solves all my issues, because I don't really need the buttons anyway and I prefer a headless terminal. Also those shadows on MacOS slowed down everything where wizterm was involved, such as Mission Control or Stage Manager, but this is a different story.

ada2k commented 7 months ago

+1 for scaling on Wayland. On my GNOME system with fractional scaling the windows buttons do scale, but seem to have some strange aliasing issues, while the Gnome button show up tiny as reported earlier. With all wayland things, I don't know if this is something you can fix or just something gnome hasn't implemented yet ^_^