use std::cell::{Cell, RefCell};
use std::sync::Arc;
use rustc_hash::{FxHashMap, FxHashSet};
use smallvec::SmallVec;
use crate::deferred::{DeferredQueue, DeferredSlot};
use crate::image_decode::{DecodeEntry, DecodeKey, Decoder, ImageEvent};
use crate::jobs::{JobQueues, ScheduledJob};
use crate::reactive::clipboard::{PasteTarget, PastedText, SelectionKind};
use crate::reactive::cursor::CursorIcon;
use crate::reactive::timer::Timers;
use crate::reactive::{OwnerId, Prop};
use crate::renderer::TextMeasurer;
use crate::session_lock::{LockData, LockRequest};
use crate::surface::{SurfaceCommand, SurfaceId};
use crate::tree::WidgetId;
use crate::widget_ref::WidgetRef;
use crate::widgets::font::{FontFamily, FontWeight};
thread_local! {
static APP: AppState = AppState::default();
}
pub(crate) fn with_app_state<R>(f: impl FnOnce(&AppState) -> R) -> R {
APP.with(f)
}
#[derive(Default)]
pub(crate) struct AppState {
pub(crate) pending_jobs: RefCell<JobQueues>,
pub(crate) scheduled_jobs: RefCell<Vec<ScheduledJob>>,
pub(crate) timers: RefCell<Timers>,
pub(crate) dirty_segments: RefCell<FxHashMap<WidgetId, SmallVec<[u32; 4]>>>,
pub(crate) surface_commands: DeferredQueue<SurfaceCommand>,
pub(crate) outgoing_cursor: DeferredSlot<CursorIcon>,
pub(crate) outgoing_clipboard: DeferredSlot<String>,
pub(crate) outgoing_primary: DeferredSlot<String>,
pub(crate) pending_focus: RefCell<Option<WidgetRef>>,
pub(crate) kept_focus: RefCell<FxHashMap<WidgetId, (WidgetId, bool)>>,
pub(crate) paste_requests: DeferredQueue<(SelectionKind, PasteTarget)>,
pub(crate) pastes: DeferredQueue<(PasteTarget, PastedText)>,
pub(crate) lock_request: DeferredSlot<LockRequest>,
pub(crate) current_cursor: Cell<CursorIcon>,
pub(crate) pointed_cursor: Cell<Prop<CursorIcon>>,
pub(crate) cursor_watch: Cell<Option<OwnerId>>,
pub(crate) clipboard_offered: Cell<bool>,
pub(crate) paste_reads: RefCell<Vec<(u64, Vec<PasteTarget>)>>,
pub(crate) next_paste_read: Cell<u64>,
pub(crate) lock: RefCell<LockData>,
pub(crate) live_popups: RefCell<FxHashSet<SurfaceId>>,
pub(crate) widget_refs: RefCell<FxHashMap<WidgetId, WidgetRef>>,
pub(crate) text_measurer: RefCell<Option<TextMeasurer>>,
pub(crate) default_font_family: Cell<FontFamily>,
pub(crate) custom_fonts: RefCell<Vec<Arc<Vec<u8>>>>,
pub(crate) custom_font_hashes: RefCell<FxHashSet<u64>>,
pub(crate) resolved_fonts:
RefCell<FxHashMap<(FontFamily, FontWeight), crate::renderer::ResolvedFont>>,
pub(crate) fonts_consumed: Cell<bool>,
pub(crate) decoded_images: RefCell<FxHashMap<DecodeKey, DecodeEntry>>,
pub(crate) image_decoder: RefCell<Option<Decoder>>,
pub(crate) image_events: DeferredQueue<ImageEvent>,
pub(crate) image_cache_budget: Cell<Option<usize>>,
}
pub(crate) fn reset() {
with_app_state(|app| {
let AppState {
pending_jobs,
scheduled_jobs,
timers,
dirty_segments,
surface_commands,
outgoing_cursor,
outgoing_clipboard,
outgoing_primary,
pending_focus,
kept_focus,
paste_requests,
pastes,
lock_request,
current_cursor,
pointed_cursor,
cursor_watch,
clipboard_offered,
paste_reads,
next_paste_read,
lock,
live_popups,
widget_refs,
text_measurer,
default_font_family,
custom_fonts,
custom_font_hashes,
resolved_fonts,
fonts_consumed,
decoded_images,
image_decoder,
image_events,
image_cache_budget,
} = app;
surface_commands.clear();
let successor = timers.borrow().successor();
drop(timers.replace(successor));
lock_request.clear();
paste_requests.clear();
paste_reads.take();
pastes.clear();
lock.take();
widget_refs.take();
text_measurer.take();
pending_jobs.take();
scheduled_jobs.take();
dirty_segments.take();
outgoing_cursor.clear();
outgoing_clipboard.clear();
outgoing_primary.clear();
pending_focus.take();
kept_focus.take();
current_cursor.take();
pointed_cursor.take();
cursor_watch.take();
clipboard_offered.take();
next_paste_read.take();
live_popups.take();
default_font_family.take();
custom_fonts.take();
custom_font_hashes.take();
resolved_fonts.take();
fonts_consumed.take();
image_events.clear();
decoded_images.take();
image_decoder.take();
image_cache_budget.take();
});
}