mirror of
https://github.com/ghostty-org/ghostty.git
synced 2026-04-30 19:13:55 +00:00
This adds the ability to use two fingers on a touchpad to scroll left or right on a Ghostty window to change tab pages. Uses the same basic machinery as scrolling up and down the scrollback buffer. Scrolling pages does not wrap around at the start or end of the tabs.
367 lines
7.9 KiB
Plaintext
367 lines
7.9 KiB
Plaintext
using Gtk 4.0;
|
|
using Adw 1;
|
|
|
|
Adw.StatusPage error_page {
|
|
icon-name: "computer-fail-symbolic";
|
|
title: _("Oh, no.");
|
|
description: _("Unable to acquire an OpenGL context for rendering.");
|
|
|
|
child: LinkButton {
|
|
label: "https://ghostty.org/docs/help/gtk-opengl-context";
|
|
uri: "https://ghostty.org/docs/help/gtk-opengl-context";
|
|
};
|
|
}
|
|
|
|
Overlay terminal_page {
|
|
focusable: false;
|
|
focus-on-click: false;
|
|
|
|
child: Box {
|
|
hexpand: true;
|
|
vexpand: true;
|
|
|
|
GLArea gl_area {
|
|
realize => $gl_realize();
|
|
unrealize => $gl_unrealize();
|
|
render => $gl_render();
|
|
resize => $gl_resize();
|
|
hexpand: true;
|
|
vexpand: true;
|
|
focusable: true;
|
|
focus-on-click: true;
|
|
has-stencil-buffer: false;
|
|
has-depth-buffer: false;
|
|
allowed-apis: gl;
|
|
}
|
|
|
|
PopoverMenu context_menu {
|
|
closed => $context_menu_closed();
|
|
menu-model: context_menu_model;
|
|
flags: nested;
|
|
halign: start;
|
|
has-arrow: false;
|
|
}
|
|
|
|
EventControllerFocus {
|
|
enter => $focus_enter();
|
|
leave => $focus_leave();
|
|
}
|
|
|
|
EventControllerKey {
|
|
key-pressed => $key_pressed();
|
|
key-released => $key_released();
|
|
}
|
|
|
|
EventControllerScroll {
|
|
scroll => $scroll_vertical();
|
|
scroll-begin => $scroll_vertical_begin();
|
|
scroll-end => $scroll_vertical_end();
|
|
flags: vertical;
|
|
}
|
|
|
|
EventControllerScroll {
|
|
scroll => $scroll_horizontal();
|
|
flags: horizontal;
|
|
}
|
|
|
|
EventControllerMotion {
|
|
motion => $mouse_motion();
|
|
leave => $mouse_leave();
|
|
}
|
|
|
|
GestureClick {
|
|
pressed => $mouse_down();
|
|
released => $mouse_up();
|
|
button: 0;
|
|
}
|
|
};
|
|
|
|
[overlay]
|
|
Revealer {
|
|
reveal-child: bind template.readonly;
|
|
transition-type: crossfade;
|
|
transition-duration: 500;
|
|
// Revealers take up the full size, we need this to not capture events.
|
|
can-focus: false;
|
|
can-target: false;
|
|
focusable: false;
|
|
|
|
Box readonly_overlay {
|
|
styles [
|
|
"readonly_overlay",
|
|
]
|
|
|
|
// TODO: the tooltip doesn't actually work, but keep it here for now so
|
|
// that we can get the tooltip text translated.
|
|
has-tooltip: true;
|
|
tooltip-text: _("This terminal is in read-only mode. You can still view, select, and scroll through the content, but no input events will be sent to the running application.");
|
|
halign: end;
|
|
valign: start;
|
|
spacing: 6;
|
|
|
|
Image {
|
|
icon-name: "changes-prevent-symbolic";
|
|
}
|
|
|
|
Label {
|
|
label: _("Read-only");
|
|
}
|
|
}
|
|
}
|
|
|
|
[overlay]
|
|
ProgressBar progress_bar_overlay {
|
|
styles [
|
|
"osd",
|
|
]
|
|
|
|
visible: false;
|
|
halign: fill;
|
|
valign: start;
|
|
}
|
|
|
|
[overlay]
|
|
// The "border" bell feature is implemented here as an overlay rather than
|
|
// just adding a border to the GLArea or other widget for two reasons.
|
|
// First, adding a border to an existing widget causes a resize of the
|
|
// widget which undesirable side effects. Second, we can make it reactive
|
|
// here in the blueprint with relatively little code.
|
|
Revealer {
|
|
reveal-child: bind $should_border_be_shown(template.config, template.bell-ringing) as <bool>;
|
|
transition-type: crossfade;
|
|
transition-duration: 500;
|
|
// Revealers take up the full size, we need this to not capture events.
|
|
can-focus: false;
|
|
can-target: false;
|
|
focusable: false;
|
|
|
|
Box bell_overlay {
|
|
styles [
|
|
"bell-overlay",
|
|
]
|
|
|
|
halign: fill;
|
|
valign: fill;
|
|
}
|
|
}
|
|
|
|
[overlay]
|
|
$GhosttySurfaceChildExited child_exited_overlay {
|
|
visible: bind template.child-exited;
|
|
close-request => $child_exited_close();
|
|
}
|
|
|
|
[overlay]
|
|
$GhosttyResizeOverlay resize_overlay {}
|
|
|
|
[overlay]
|
|
Label url_left {
|
|
styles [
|
|
"background",
|
|
"url-overlay",
|
|
]
|
|
|
|
visible: false;
|
|
halign: start;
|
|
valign: end;
|
|
label: bind template.mouse-hover-url;
|
|
|
|
EventControllerMotion url_ec_motion {
|
|
enter => $url_mouse_enter();
|
|
leave => $url_mouse_leave();
|
|
}
|
|
}
|
|
|
|
[overlay]
|
|
Label url_right {
|
|
styles [
|
|
"background",
|
|
"url-overlay",
|
|
]
|
|
|
|
visible: false;
|
|
halign: end;
|
|
valign: end;
|
|
label: bind template.mouse-hover-url;
|
|
}
|
|
|
|
[overlay]
|
|
$GhosttySearchOverlay search_overlay {
|
|
stop-search => $search_stop();
|
|
search-changed => $search_changed();
|
|
next-match => $search_next_match();
|
|
previous-match => $search_previous_match();
|
|
}
|
|
|
|
[overlay]
|
|
$GhosttyKeyStateOverlay key_state_overlay {
|
|
tables: bind template.key-table;
|
|
sequence: bind template.key-sequence;
|
|
}
|
|
|
|
[overlay]
|
|
// Apply unfocused-split-fill and unfocused-split-opacity to current surface
|
|
// this is only applied when a tab has more than one surface
|
|
Revealer {
|
|
reveal-child: bind $should_unfocused_split_be_shown(template.focused, template.is-split) as <bool>;
|
|
transition-duration: 0;
|
|
// This is all necessary so that the Revealer itself doesn't override
|
|
// any input events from the other overlays. Namely, if you don't have
|
|
// these then the search overlay won't get mouse events.
|
|
can-focus: false;
|
|
can-target: false;
|
|
focusable: false;
|
|
|
|
DrawingArea {
|
|
styles [
|
|
"unfocused-split",
|
|
]
|
|
}
|
|
}
|
|
|
|
DropTarget drop_target {
|
|
drop => $drop();
|
|
actions: copy;
|
|
}
|
|
}
|
|
|
|
template $GhosttySurface: Adw.Bin {
|
|
styles [
|
|
"surface",
|
|
]
|
|
|
|
notify::config => $notify_config();
|
|
notify::error => $notify_error();
|
|
notify::mouse-hover-url => $notify_mouse_hover_url();
|
|
notify::mouse-hidden => $notify_mouse_hidden();
|
|
notify::mouse-shape => $notify_mouse_shape();
|
|
notify::vadjustment => $notify_vadjustment();
|
|
// Some history: we used to use a Stack here and swap between the
|
|
// terminal and error pages as needed. But a Stack doesn't play nice
|
|
// with our SplitTree and Gtk.Paned usage[^1]. Replacing this with
|
|
// a manual programmatic child swap fixed this. So if you ever change
|
|
// this, be sure to test many splits!
|
|
//
|
|
// [^1]: https://github.com/ghostty-org/ghostty/issues/8533
|
|
child: terminal_page;
|
|
}
|
|
|
|
IMMulticontext im_context {
|
|
input-purpose: terminal;
|
|
preedit-start => $im_preedit_start();
|
|
preedit-changed => $im_preedit_changed();
|
|
preedit-end => $im_preedit_end();
|
|
commit => $im_commit();
|
|
}
|
|
|
|
menu context_menu_model {
|
|
section {
|
|
item {
|
|
label: _("Copy");
|
|
action: "win.copy";
|
|
}
|
|
|
|
item {
|
|
label: _("Paste");
|
|
action: "win.paste";
|
|
}
|
|
|
|
item {
|
|
label: _("Notify on Next Command Finish");
|
|
action: "surface.notify-on-next-command-finish";
|
|
}
|
|
}
|
|
|
|
section {
|
|
item {
|
|
label: _("Clear");
|
|
action: "win.clear";
|
|
}
|
|
|
|
item {
|
|
label: _("Reset");
|
|
action: "win.reset";
|
|
}
|
|
}
|
|
|
|
section {
|
|
submenu {
|
|
label: _("Split");
|
|
|
|
item {
|
|
label: _("Change Title…");
|
|
action: "surface.prompt-title";
|
|
}
|
|
|
|
item {
|
|
label: _("Split Up");
|
|
action: "split-tree.new-split";
|
|
target: "up";
|
|
}
|
|
|
|
item {
|
|
label: _("Split Down");
|
|
action: "split-tree.new-split";
|
|
target: "down";
|
|
}
|
|
|
|
item {
|
|
label: _("Split Left");
|
|
action: "split-tree.new-split";
|
|
target: "left";
|
|
}
|
|
|
|
item {
|
|
label: _("Split Right");
|
|
action: "split-tree.new-split";
|
|
target: "right";
|
|
}
|
|
}
|
|
|
|
submenu {
|
|
label: _("Tab");
|
|
|
|
item {
|
|
label: _("New Tab");
|
|
action: "win.new-tab";
|
|
}
|
|
|
|
item {
|
|
label: _("Close Tab");
|
|
action: "tab.close";
|
|
target: "this";
|
|
}
|
|
}
|
|
|
|
submenu {
|
|
label: _("Window");
|
|
|
|
item {
|
|
label: _("New Window");
|
|
action: "win.new-window";
|
|
}
|
|
|
|
item {
|
|
label: _("Close Window");
|
|
action: "win.close";
|
|
}
|
|
}
|
|
}
|
|
|
|
section {
|
|
submenu {
|
|
label: _("Config");
|
|
|
|
item {
|
|
label: _("Open Configuration");
|
|
action: "app.open-config";
|
|
}
|
|
|
|
item {
|
|
label: _("Reload Configuration");
|
|
action: "app.reload-config";
|
|
}
|
|
}
|
|
}
|
|
}
|