feat(reload): reload the active tab with Cmd/Ctrl+R
This commit is contained in:
@@ -38,6 +38,7 @@ actions!(
|
|||||||
OpenSettings,
|
OpenSettings,
|
||||||
OpenTaskManager,
|
OpenTaskManager,
|
||||||
Quit,
|
Quit,
|
||||||
|
ReloadTab,
|
||||||
RestoreClosedTab,
|
RestoreClosedTab,
|
||||||
ResetZoom,
|
ResetZoom,
|
||||||
SelectNextSpace,
|
SelectNextSpace,
|
||||||
@@ -105,6 +106,7 @@ fn main() {
|
|||||||
MenuItem::action("Zoom Out", ZoomOut),
|
MenuItem::action("Zoom Out", ZoomOut),
|
||||||
MenuItem::action("Reset Zoom", ResetZoom),
|
MenuItem::action("Reset Zoom", ResetZoom),
|
||||||
MenuItem::separator(),
|
MenuItem::separator(),
|
||||||
|
MenuItem::action("Reload Tab", ReloadTab),
|
||||||
MenuItem::action("Close Tab", CloseCurrentTab),
|
MenuItem::action("Close Tab", CloseCurrentTab),
|
||||||
MenuItem::separator(),
|
MenuItem::separator(),
|
||||||
MenuItem::action("Restore Closed Tab", RestoreClosedTab),
|
MenuItem::action("Restore Closed Tab", RestoreClosedTab),
|
||||||
|
|||||||
@@ -177,6 +177,10 @@ impl ServoLiveClient {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn reload(&mut self, tab_id: String) -> Result<(), ServoLiveError> {
|
||||||
|
self.request(LiveRequest::Reload { tab_id }).map(|_| ())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn close(&mut self, tab_id: String) -> Result<(), ServoLiveError> {
|
pub fn close(&mut self, tab_id: String) -> Result<(), ServoLiveError> {
|
||||||
self.request(LiveRequest::Close { tab_id }).map(|_| ())
|
self.request(LiveRequest::Close { tab_id }).map(|_| ())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,6 +41,9 @@ pub(super) enum LiveRequest {
|
|||||||
ready_surface_ids: Vec<u64>,
|
ready_surface_ids: Vec<u64>,
|
||||||
pending_surface_ids: Vec<u64>,
|
pending_surface_ids: Vec<u64>,
|
||||||
},
|
},
|
||||||
|
Reload {
|
||||||
|
tab_id: String,
|
||||||
|
},
|
||||||
Close {
|
Close {
|
||||||
tab_id: String,
|
tab_id: String,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -119,6 +119,7 @@ impl ElyShell {
|
|||||||
.on_action(cx.listener(Self::on_open_new_tab))
|
.on_action(cx.listener(Self::on_open_new_tab))
|
||||||
.on_action(cx.listener(Self::on_open_settings))
|
.on_action(cx.listener(Self::on_open_settings))
|
||||||
.on_action(cx.listener(Self::on_open_task_manager))
|
.on_action(cx.listener(Self::on_open_task_manager))
|
||||||
|
.on_action(cx.listener(Self::on_reload_tab))
|
||||||
.on_action(cx.listener(Self::on_reset_zoom))
|
.on_action(cx.listener(Self::on_reset_zoom))
|
||||||
.on_action(cx.listener(Self::on_restore_closed_tab))
|
.on_action(cx.listener(Self::on_restore_closed_tab))
|
||||||
.on_action(cx.listener(Self::on_select_next_space))
|
.on_action(cx.listener(Self::on_select_next_space))
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ use gpui::{Context, Window};
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
CloseCurrentTab, DownloadCurrentPage, FocusAddressBar, FocusCommandMode, OpenDownloads,
|
CloseCurrentTab, DownloadCurrentPage, FocusAddressBar, FocusCommandMode, OpenDownloads,
|
||||||
OpenHistory, OpenNewTab, OpenSettings, OpenTaskManager, ResetZoom, RestoreClosedTab,
|
OpenHistory, OpenNewTab, OpenSettings, OpenTaskManager, ReloadTab, ResetZoom, RestoreClosedTab,
|
||||||
SelectNextTab, SelectPreviousTab, ToggleFavoriteTab, TogglePinnedTab, ZoomIn, ZoomOut,
|
SelectNextTab, SelectPreviousTab, ToggleFavoriteTab, TogglePinnedTab, ZoomIn, ZoomOut,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -45,6 +45,15 @@ impl ElyShell {
|
|||||||
self.open_new_tab(window, cx);
|
self.open_new_tab(window, cx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(super) fn on_reload_tab(
|
||||||
|
&mut self,
|
||||||
|
_: &ReloadTab,
|
||||||
|
window: &mut Window,
|
||||||
|
cx: &mut Context<Self>,
|
||||||
|
) {
|
||||||
|
self.reload_active_tab(window, cx);
|
||||||
|
}
|
||||||
|
|
||||||
pub(super) fn on_open_downloads(
|
pub(super) fn on_open_downloads(
|
||||||
&mut self,
|
&mut self,
|
||||||
_: &OpenDownloads,
|
_: &OpenDownloads,
|
||||||
|
|||||||
@@ -20,6 +20,21 @@ impl ElyShell {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Reload the active tab: recover it to the ready state in `BrowserCore`
|
||||||
|
/// and, when it hosts a live web surface, tell that surface's Servo
|
||||||
|
/// sidecar to refetch the page.
|
||||||
|
pub(super) fn reload_active_tab(&mut self, window: &mut Window, cx: &mut Context<Self>) {
|
||||||
|
let ShellState::Ready(core) = &mut self.state else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let Ok(tab_id) = core.reload_active_tab() else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
self.web_surfaces.reload_tab(&tab_id);
|
||||||
|
self.sync_address_input(window, cx);
|
||||||
|
cx.notify();
|
||||||
|
}
|
||||||
|
|
||||||
pub(super) fn wake_discarded_tab(
|
pub(super) fn wake_discarded_tab(
|
||||||
&mut self,
|
&mut self,
|
||||||
tab_id: &TabId,
|
tab_id: &TabId,
|
||||||
|
|||||||
@@ -353,6 +353,10 @@ impl WebSurfaceStore {
|
|||||||
self.surfaces.entry(tab_id.clone()).or_insert_with(PerTabSurface::new)
|
self.surfaces.entry(tab_id.clone()).or_insert_with(PerTabSurface::new)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(super) fn reload_tab(&mut self, tab_id: &TabId) {
|
||||||
|
self.runtime.reload_tab(tab_id);
|
||||||
|
}
|
||||||
|
|
||||||
pub(super) fn close_surface(&mut self, tab_id: &TabId) {
|
pub(super) fn close_surface(&mut self, tab_id: &TabId) {
|
||||||
self.runtime.close_tab(tab_id);
|
self.runtime.close_tab(tab_id);
|
||||||
self.surfaces.remove(tab_id);
|
self.surfaces.remove(tab_id);
|
||||||
|
|||||||
@@ -78,6 +78,15 @@ impl WebSurfaceRuntime {
|
|||||||
self.take_retired_permission_consumptions()
|
self.take_retired_permission_consumptions()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(in crate::shell) fn reload_tab(&mut self, tab_id: &TabId) {
|
||||||
|
let Some(session) = self.sessions.get(tab_id) else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
if let Some(scoped) = self.workers.get(&session.scope) {
|
||||||
|
scoped.worker.submit_reload(tab_id.as_str().to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(in crate::shell) fn close_tab(&mut self, tab_id: &TabId) {
|
pub(in crate::shell) fn close_tab(&mut self, tab_id: &TabId) {
|
||||||
let Some(session) = self.sessions.remove(tab_id) else {
|
let Some(session) = self.sessions.remove(tab_id) else {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -29,6 +29,11 @@ pub(super) trait LiveRuntimeClient {
|
|||||||
|
|
||||||
fn poll(&mut self, tab_id: String) -> Result<Option<ServoLiveFrame>, LiveRuntimeClientError>;
|
fn poll(&mut self, tab_id: String) -> Result<Option<ServoLiveFrame>, LiveRuntimeClientError>;
|
||||||
|
|
||||||
|
fn reload(&mut self, tab_id: String) -> Result<(), LiveRuntimeClientError> {
|
||||||
|
let _ = tab_id;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn close(&mut self, tab_id: String) -> Result<(), LiveRuntimeClientError>;
|
fn close(&mut self, tab_id: String) -> Result<(), LiveRuntimeClientError>;
|
||||||
|
|
||||||
fn take_permission_consumptions(&mut self) -> Vec<ServoLivePermissionGrant> {
|
fn take_permission_consumptions(&mut self) -> Vec<ServoLivePermissionGrant> {
|
||||||
@@ -48,6 +53,10 @@ impl LiveRuntimeClient for ServoLiveClient {
|
|||||||
ServoLiveClient::poll(self, tab_id).map_err(LiveRuntimeClientError::from)
|
ServoLiveClient::poll(self, tab_id).map_err(LiveRuntimeClientError::from)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn reload(&mut self, tab_id: String) -> Result<(), LiveRuntimeClientError> {
|
||||||
|
ServoLiveClient::reload(self, tab_id).map_err(LiveRuntimeClientError::from)
|
||||||
|
}
|
||||||
|
|
||||||
fn close(&mut self, tab_id: String) -> Result<(), LiveRuntimeClientError> {
|
fn close(&mut self, tab_id: String) -> Result<(), LiveRuntimeClientError> {
|
||||||
ServoLiveClient::close(self, tab_id).map_err(LiveRuntimeClientError::from)
|
ServoLiveClient::close(self, tab_id).map_err(LiveRuntimeClientError::from)
|
||||||
}
|
}
|
||||||
@@ -147,6 +156,7 @@ struct WorkerQueue {
|
|||||||
pending: BTreeMap<String, VecDeque<WorkerRequest>>,
|
pending: BTreeMap<String, VecDeque<WorkerRequest>>,
|
||||||
/// Round-robin tab order, with each pending tab represented once.
|
/// Round-robin tab order, with each pending tab represented once.
|
||||||
ready_tabs: VecDeque<String>,
|
ready_tabs: VecDeque<String>,
|
||||||
|
reloads: VecDeque<String>,
|
||||||
closes: VecDeque<String>,
|
closes: VecDeque<String>,
|
||||||
in_flight: bool,
|
in_flight: bool,
|
||||||
in_flight_tab: Option<String>,
|
in_flight_tab: Option<String>,
|
||||||
@@ -170,6 +180,7 @@ impl LiveRuntimeWorker {
|
|||||||
Mutex::new(WorkerQueue {
|
Mutex::new(WorkerQueue {
|
||||||
pending: BTreeMap::new(),
|
pending: BTreeMap::new(),
|
||||||
ready_tabs: VecDeque::new(),
|
ready_tabs: VecDeque::new(),
|
||||||
|
reloads: VecDeque::new(),
|
||||||
closes: VecDeque::new(),
|
closes: VecDeque::new(),
|
||||||
in_flight: false,
|
in_flight: false,
|
||||||
in_flight_tab: None,
|
in_flight_tab: None,
|
||||||
@@ -264,6 +275,21 @@ impl LiveRuntimeWorker {
|
|||||||
inserted
|
inserted
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(super) fn submit_reload(&self, tab_id: String) {
|
||||||
|
let (lock, cvar) = &*self.queue;
|
||||||
|
let mut q = match lock.lock() {
|
||||||
|
Ok(guard) => guard,
|
||||||
|
Err(poisoned) => poisoned.into_inner(),
|
||||||
|
};
|
||||||
|
if q.shutdown || q.initialization_failure.is_some() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if !q.reloads.contains(&tab_id) {
|
||||||
|
q.reloads.push_back(tab_id);
|
||||||
|
}
|
||||||
|
cvar.notify_one();
|
||||||
|
}
|
||||||
|
|
||||||
pub(super) fn submit_close(&self, tab_id: String) {
|
pub(super) fn submit_close(&self, tab_id: String) {
|
||||||
let (lock, cvar) = &*self.queue;
|
let (lock, cvar) = &*self.queue;
|
||||||
let mut q = match lock.lock() {
|
let mut q = match lock.lock() {
|
||||||
@@ -278,6 +304,7 @@ impl LiveRuntimeWorker {
|
|||||||
}
|
}
|
||||||
q.pending.remove(&tab_id);
|
q.pending.remove(&tab_id);
|
||||||
q.ready_tabs.retain(|ready_tab_id| ready_tab_id != &tab_id);
|
q.ready_tabs.retain(|ready_tab_id| ready_tab_id != &tab_id);
|
||||||
|
q.reloads.retain(|reload_tab_id| reload_tab_id != &tab_id);
|
||||||
q.closes.push_back(tab_id);
|
q.closes.push_back(tab_id);
|
||||||
cvar.notify_one();
|
cvar.notify_one();
|
||||||
}
|
}
|
||||||
@@ -298,7 +325,8 @@ impl LiveRuntimeWorker {
|
|||||||
Ok(guard) => guard,
|
Ok(guard) => guard,
|
||||||
Err(poisoned) => poisoned.into_inner(),
|
Err(poisoned) => poisoned.into_inner(),
|
||||||
};
|
};
|
||||||
while !q.pending.is_empty() || !q.closes.is_empty() || q.in_flight {
|
while !q.pending.is_empty() || !q.reloads.is_empty() || !q.closes.is_empty() || q.in_flight
|
||||||
|
{
|
||||||
q = match cvar.wait(q) {
|
q = match cvar.wait(q) {
|
||||||
Ok(guard) => guard,
|
Ok(guard) => guard,
|
||||||
Err(poisoned) => poisoned.into_inner(),
|
Err(poisoned) => poisoned.into_inner(),
|
||||||
@@ -336,6 +364,7 @@ fn fail_worker_initialization(
|
|||||||
};
|
};
|
||||||
q.initialization_failure = Some(message.clone());
|
q.initialization_failure = Some(message.clone());
|
||||||
q.ready_tabs.clear();
|
q.ready_tabs.clear();
|
||||||
|
q.reloads.clear();
|
||||||
q.closes.clear();
|
q.closes.clear();
|
||||||
q.in_flight = false;
|
q.in_flight = false;
|
||||||
q.in_flight_tab = None;
|
q.in_flight_tab = None;
|
||||||
@@ -368,7 +397,8 @@ fn run_worker(
|
|||||||
q.in_flight = false;
|
q.in_flight = false;
|
||||||
q.in_flight_tab = None;
|
q.in_flight_tab = None;
|
||||||
cvar.notify_all();
|
cvar.notify_all();
|
||||||
while q.pending.is_empty() && q.closes.is_empty() && !q.shutdown {
|
while q.pending.is_empty() && q.reloads.is_empty() && q.closes.is_empty() && !q.shutdown
|
||||||
|
{
|
||||||
q = match cvar.wait(q) {
|
q = match cvar.wait(q) {
|
||||||
Ok(guard) => guard,
|
Ok(guard) => guard,
|
||||||
Err(poisoned) => poisoned.into_inner(),
|
Err(poisoned) => poisoned.into_inner(),
|
||||||
@@ -379,6 +409,8 @@ fn run_worker(
|
|||||||
}
|
}
|
||||||
let next = if let Some(close_id) = q.closes.pop_front() {
|
let next = if let Some(close_id) = q.closes.pop_front() {
|
||||||
Work::Close(close_id)
|
Work::Close(close_id)
|
||||||
|
} else if let Some(reload_id) = q.reloads.pop_front() {
|
||||||
|
Work::Reload(reload_id)
|
||||||
} else {
|
} else {
|
||||||
if q.ready_tabs.len() > 1
|
if q.ready_tabs.len() > 1
|
||||||
&& q.ready_tabs.front() == last_dispatched_tab.as_ref()
|
&& q.ready_tabs.front() == last_dispatched_tab.as_ref()
|
||||||
@@ -407,7 +439,7 @@ fn run_worker(
|
|||||||
};
|
};
|
||||||
q.in_flight = true;
|
q.in_flight = true;
|
||||||
q.in_flight_tab = match &next {
|
q.in_flight_tab = match &next {
|
||||||
Work::Close(_) => None,
|
Work::Close(_) | Work::Reload(_) => None,
|
||||||
Work::Request(request) => Some(request.tab_id().to_string()),
|
Work::Request(request) => Some(request.tab_id().to_string()),
|
||||||
};
|
};
|
||||||
next
|
next
|
||||||
@@ -419,6 +451,11 @@ fn run_worker(
|
|||||||
forward_permission_consumptions(&mut *client, &response_tx);
|
forward_permission_consumptions(&mut *client, &response_tx);
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
Work::Reload(tab_id) => {
|
||||||
|
let _ = client.reload(tab_id);
|
||||||
|
forward_permission_consumptions(&mut *client, &response_tx);
|
||||||
|
false
|
||||||
|
}
|
||||||
Work::Request(WorkerRequest::Ensure { generation, mut request }) => {
|
Work::Request(WorkerRequest::Ensure { generation, mut request }) => {
|
||||||
let tab_id = request.tab_id.clone();
|
let tab_id = request.tab_id.clone();
|
||||||
let allow_once_grants = std::mem::take(&mut request.allow_once_grants);
|
let allow_once_grants = std::mem::take(&mut request.allow_once_grants);
|
||||||
@@ -454,6 +491,7 @@ fn run_worker(
|
|||||||
|
|
||||||
enum Work {
|
enum Work {
|
||||||
Close(String),
|
Close(String),
|
||||||
|
Reload(String),
|
||||||
Request(WorkerRequest),
|
Request(WorkerRequest),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ pub(crate) use profile::{
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
CloseCurrentTab, FocusAddressBar, FocusCommandMode, OpenDownloads, OpenHistory, OpenNewTab,
|
CloseCurrentTab, FocusAddressBar, FocusCommandMode, OpenDownloads, OpenHistory, OpenNewTab,
|
||||||
OpenPrivateWindow, OpenSettings, OpenTaskManager, Quit, ResetZoom, RestoreClosedTab,
|
OpenPrivateWindow, OpenSettings, OpenTaskManager, Quit, ReloadTab, ResetZoom, RestoreClosedTab,
|
||||||
SelectNextSpace, SelectNextTab, SelectPreviousSpace, SelectPreviousTab, SplitRight,
|
SelectNextSpace, SelectNextTab, SelectPreviousSpace, SelectPreviousTab, SplitRight,
|
||||||
ToggleFavoriteTab, ToggleSidebar, ZoomIn, ZoomOut,
|
ToggleFavoriteTab, ToggleSidebar, ZoomIn, ZoomOut,
|
||||||
};
|
};
|
||||||
@@ -39,6 +39,7 @@ pub(crate) enum ShortcutAction {
|
|||||||
OpenNewTab,
|
OpenNewTab,
|
||||||
OpenPrivateWindow,
|
OpenPrivateWindow,
|
||||||
CloseCurrentTab,
|
CloseCurrentTab,
|
||||||
|
ReloadTab,
|
||||||
RestoreClosedTab,
|
RestoreClosedTab,
|
||||||
SelectNextSpace,
|
SelectNextSpace,
|
||||||
SelectPreviousSpace,
|
SelectPreviousSpace,
|
||||||
@@ -65,6 +66,7 @@ impl ShortcutAction {
|
|||||||
Self::OpenNewTab => "New Tab",
|
Self::OpenNewTab => "New Tab",
|
||||||
Self::OpenPrivateWindow => "New Private Window",
|
Self::OpenPrivateWindow => "New Private Window",
|
||||||
Self::CloseCurrentTab => "Close Tab",
|
Self::CloseCurrentTab => "Close Tab",
|
||||||
|
Self::ReloadTab => "Reload Tab",
|
||||||
Self::RestoreClosedTab => "Restore Closed Tab",
|
Self::RestoreClosedTab => "Restore Closed Tab",
|
||||||
Self::SelectNextSpace => "Next Space",
|
Self::SelectNextSpace => "Next Space",
|
||||||
Self::SelectPreviousSpace => "Previous Space",
|
Self::SelectPreviousSpace => "Previous Space",
|
||||||
@@ -90,6 +92,7 @@ impl ShortcutAction {
|
|||||||
Self::OpenNewTab
|
Self::OpenNewTab
|
||||||
| Self::OpenPrivateWindow
|
| Self::OpenPrivateWindow
|
||||||
| Self::CloseCurrentTab
|
| Self::CloseCurrentTab
|
||||||
|
| Self::ReloadTab
|
||||||
| Self::RestoreClosedTab
|
| Self::RestoreClosedTab
|
||||||
| Self::SelectNextSpace
|
| Self::SelectNextSpace
|
||||||
| Self::SelectPreviousSpace
|
| Self::SelectPreviousSpace
|
||||||
@@ -114,6 +117,7 @@ impl ShortcutAction {
|
|||||||
Self::OpenNewTab => Some(">new-tab"),
|
Self::OpenNewTab => Some(">new-tab"),
|
||||||
Self::OpenPrivateWindow => None,
|
Self::OpenPrivateWindow => None,
|
||||||
Self::CloseCurrentTab => Some(">close-tab"),
|
Self::CloseCurrentTab => Some(">close-tab"),
|
||||||
|
Self::ReloadTab => None,
|
||||||
Self::RestoreClosedTab => Some(">restore-tab"),
|
Self::RestoreClosedTab => Some(">restore-tab"),
|
||||||
Self::SelectNextSpace => None,
|
Self::SelectNextSpace => None,
|
||||||
Self::SelectPreviousSpace => None,
|
Self::SelectPreviousSpace => None,
|
||||||
@@ -168,6 +172,7 @@ pub(crate) const SHORTCUT_ACTIONS: &[ShortcutAction] = &[
|
|||||||
ShortcutAction::OpenNewTab,
|
ShortcutAction::OpenNewTab,
|
||||||
ShortcutAction::OpenPrivateWindow,
|
ShortcutAction::OpenPrivateWindow,
|
||||||
ShortcutAction::CloseCurrentTab,
|
ShortcutAction::CloseCurrentTab,
|
||||||
|
ShortcutAction::ReloadTab,
|
||||||
ShortcutAction::RestoreClosedTab,
|
ShortcutAction::RestoreClosedTab,
|
||||||
ShortcutAction::SelectNextSpace,
|
ShortcutAction::SelectNextSpace,
|
||||||
ShortcutAction::SelectPreviousSpace,
|
ShortcutAction::SelectPreviousSpace,
|
||||||
@@ -189,6 +194,8 @@ pub(crate) const SHORTCUT_ACTIONS: &[ShortcutAction] = &[
|
|||||||
pub(crate) const SHORTCUT_BINDINGS: &[ShortcutBinding] = &[
|
pub(crate) const SHORTCUT_BINDINGS: &[ShortcutBinding] = &[
|
||||||
shortcut(ShortcutAction::OpenNewTab, ShortcutPlatform::Macos, "cmd-t"),
|
shortcut(ShortcutAction::OpenNewTab, ShortcutPlatform::Macos, "cmd-t"),
|
||||||
shortcut(ShortcutAction::OpenNewTab, ShortcutPlatform::WindowsLinux, "ctrl-t"),
|
shortcut(ShortcutAction::OpenNewTab, ShortcutPlatform::WindowsLinux, "ctrl-t"),
|
||||||
|
shortcut(ShortcutAction::ReloadTab, ShortcutPlatform::Macos, "cmd-r"),
|
||||||
|
shortcut(ShortcutAction::ReloadTab, ShortcutPlatform::WindowsLinux, "ctrl-r"),
|
||||||
shortcut(ShortcutAction::OpenPrivateWindow, ShortcutPlatform::Macos, "cmd-shift-n"),
|
shortcut(ShortcutAction::OpenPrivateWindow, ShortcutPlatform::Macos, "cmd-shift-n"),
|
||||||
shortcut(ShortcutAction::OpenPrivateWindow, ShortcutPlatform::WindowsLinux, "ctrl-shift-n"),
|
shortcut(ShortcutAction::OpenPrivateWindow, ShortcutPlatform::WindowsLinux, "ctrl-shift-n"),
|
||||||
shortcut(ShortcutAction::SplitRight, ShortcutPlatform::Macos, "cmd-\\"),
|
shortcut(ShortcutAction::SplitRight, ShortcutPlatform::Macos, "cmd-\\"),
|
||||||
@@ -278,6 +285,7 @@ pub(crate) fn key_binding_for_action(action: ShortcutAction, keystroke: &str) ->
|
|||||||
ShortcutAction::OpenSettings => KeyBinding::new(keystroke, OpenSettings, None),
|
ShortcutAction::OpenSettings => KeyBinding::new(keystroke, OpenSettings, None),
|
||||||
ShortcutAction::OpenTaskManager => KeyBinding::new(keystroke, OpenTaskManager, None),
|
ShortcutAction::OpenTaskManager => KeyBinding::new(keystroke, OpenTaskManager, None),
|
||||||
ShortcutAction::Quit => KeyBinding::new(keystroke, Quit, None),
|
ShortcutAction::Quit => KeyBinding::new(keystroke, Quit, None),
|
||||||
|
ShortcutAction::ReloadTab => KeyBinding::new(keystroke, ReloadTab, None),
|
||||||
ShortcutAction::ResetZoom => KeyBinding::new(keystroke, ResetZoom, None),
|
ShortcutAction::ResetZoom => KeyBinding::new(keystroke, ResetZoom, None),
|
||||||
ShortcutAction::RestoreClosedTab => KeyBinding::new(keystroke, RestoreClosedTab, None),
|
ShortcutAction::RestoreClosedTab => KeyBinding::new(keystroke, RestoreClosedTab, None),
|
||||||
ShortcutAction::SelectNextSpace => KeyBinding::new(keystroke, SelectNextSpace, None),
|
ShortcutAction::SelectNextSpace => KeyBinding::new(keystroke, SelectNextSpace, None),
|
||||||
|
|||||||
@@ -50,6 +50,14 @@ impl BrowserCore {
|
|||||||
self.mark_tab_ready(tab_id)
|
self.mark_tab_ready(tab_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Reload the active tab in place: recover a crashed or sleeping tab to
|
||||||
|
/// the ready state and stamp fresh activity. The shell pairs this with a
|
||||||
|
/// Servo reload so the page is actually refetched.
|
||||||
|
pub fn reload_active_tab(&mut self) -> Result<TabId, CoreError> {
|
||||||
|
let tab_id = self.active_tab_id.clone();
|
||||||
|
self.refresh_tab(&tab_id)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn archive_idle_tabs(&mut self, now: SystemTime) -> Result<usize, CoreError> {
|
pub fn archive_idle_tabs(&mut self, now: SystemTime) -> Result<usize, CoreError> {
|
||||||
let ArchivePolicy::IdleDays(idle_days) = self.active_space()?.archive_policy() else {
|
let ArchivePolicy::IdleDays(idle_days) = self.active_space()?.archive_policy() else {
|
||||||
return Ok(0);
|
return Ok(0);
|
||||||
|
|||||||
@@ -53,6 +53,21 @@ fn recover_crashed_tab_marks_tab_ready() -> Result<(), Box<dyn Error>> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn reload_active_tab_recovers_a_crashed_tab() -> Result<(), Box<dyn Error>> {
|
||||||
|
let mut core = BrowserCore::new(InitialBrowserConfig::ely_defaults()?)?;
|
||||||
|
let tab_id = core.open_tab(UrlText::parse("https://example.com/reload")?);
|
||||||
|
core.crash_active_tab()?;
|
||||||
|
assert_eq!(core.active_tab()?.state(), &TabState::Crashed);
|
||||||
|
|
||||||
|
let reloaded = core.reload_active_tab()?;
|
||||||
|
|
||||||
|
assert_eq!(reloaded, tab_id);
|
||||||
|
assert_eq!(core.active_tab()?.state(), &TabState::Ready);
|
||||||
|
assert_eq!(core.active_tab()?.url().as_str(), "https://example.com/reload");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn crash_tab_command_marks_active_tab_crashed() -> Result<(), Box<dyn Error>> {
|
fn crash_tab_command_marks_active_tab_crashed() -> Result<(), Box<dyn Error>> {
|
||||||
let mut core = BrowserCore::new(InitialBrowserConfig::ely_defaults()?)?;
|
let mut core = BrowserCore::new(InitialBrowserConfig::ely_defaults()?)?;
|
||||||
|
|||||||
@@ -297,6 +297,13 @@ fn handle_request(
|
|||||||
drop((webview_id, ready_surface_ids, pending_surface_ids));
|
drop((webview_id, ready_surface_ids, pending_surface_ids));
|
||||||
Ok(outcome)
|
Ok(outcome)
|
||||||
}
|
}
|
||||||
|
LiveRequest::Reload { tab_id } => {
|
||||||
|
if let Some(session) = sessions.get_mut(&tab_id) {
|
||||||
|
session.clear_presented_frame();
|
||||||
|
host.reload(&session.webview_id)?;
|
||||||
|
}
|
||||||
|
Ok(LiveOutcome::empty())
|
||||||
|
}
|
||||||
LiveRequest::Close { tab_id } => {
|
LiveRequest::Close { tab_id } => {
|
||||||
if let Some(session) = sessions.remove(&tab_id) {
|
if let Some(session) = sessions.remove(&tab_id) {
|
||||||
host.close_webview(&session.webview_id);
|
host.close_webview(&session.webview_id);
|
||||||
|
|||||||
@@ -68,6 +68,9 @@ pub(super) enum LiveRequest {
|
|||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pending_surface_ids: Vec<u64>,
|
pending_surface_ids: Vec<u64>,
|
||||||
},
|
},
|
||||||
|
Reload {
|
||||||
|
tab_id: String,
|
||||||
|
},
|
||||||
Close {
|
Close {
|
||||||
tab_id: String,
|
tab_id: String,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -372,6 +372,11 @@ pub trait ServoHost {
|
|||||||
|
|
||||||
fn navigate(&mut self, request: NavigationRequest) -> Result<(), ServoHostError>;
|
fn navigate(&mut self, request: NavigationRequest) -> Result<(), ServoHostError>;
|
||||||
|
|
||||||
|
/// Reload the current document in place (the URL is unchanged). Servo's
|
||||||
|
/// load-status transitions drive the loading indicator, so no navigation
|
||||||
|
/// hold is armed.
|
||||||
|
fn reload(&mut self, webview_id: &WebViewId) -> Result<(), ServoHostError>;
|
||||||
|
|
||||||
fn scroll(&mut self, request: ScrollRequest) -> Result<(), ServoHostError>;
|
fn scroll(&mut self, request: ScrollRequest) -> Result<(), ServoHostError>;
|
||||||
|
|
||||||
fn resize(&mut self, request: ResizeRequest) -> Result<(), ServoHostError>;
|
fn resize(&mut self, request: ResizeRequest) -> Result<(), ServoHostError>;
|
||||||
|
|||||||
@@ -227,6 +227,17 @@ impl ServoHost for SoftwareServoHost {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn reload(&mut self, webview_id: &WebViewId) -> Result<(), ServoHostError> {
|
||||||
|
self.servo.spin_event_loop();
|
||||||
|
let webview = self
|
||||||
|
.webviews
|
||||||
|
.get_mut(webview_id)
|
||||||
|
.ok_or_else(|| ServoHostError::WebViewNotFound { id: webview_id.clone() })?;
|
||||||
|
webview.delegate.set_state(WebViewState::Loading);
|
||||||
|
webview.webview.reload();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn scroll(&mut self, request: ScrollRequest) -> Result<(), ServoHostError> {
|
fn scroll(&mut self, request: ScrollRequest) -> Result<(), ServoHostError> {
|
||||||
if request.delta_x == 0 && request.delta_y == 0 {
|
if request.delta_x == 0 && request.delta_y == 0 {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
|
|||||||
Reference in New Issue
Block a user