Documentation Index
Fetch the complete documentation index at: https://docs.debian.com.mx/llms.txt
Use this file to discover all available pages before exploring further.
Window Manager
The WindowManager is the core system responsible for managing all window operations in Time Capsule. It handles window lifecycle, positioning, dragging, focus management, z-index ordering, and workspace assignment.Overview
WindowManager is implemented as a singleton module pattern with private state and exposed public methods:const WindowManager = (() => {
let zIndex = CONFIG.WINDOW.BASE_Z_INDEX;
let highestWindowZIndex = CONFIG.WINDOW.BASE_Z_INDEX;
let highestModalZIndex = 90000;
let currentWorkspace = '1';
let lastFocusedWindowId: string | null = null;
const dragState: DragState = { /* ... */ };
// Public API
return {
init,
drag,
focusWindow,
registerWindow,
centerWindow,
switchWorkspace,
showWindow,
getNextZIndex,
getTopZIndex,
};
})();
Key Concepts
Window Registration
All windows must be registered with WindowManager to enable management features:function registerWindow(win: HTMLElement): void {
if (win.hasAttribute('data-cde-registered')) return;
const id = win.id;
const titlebar = document.getElementById(`${id}Titlebar`) ||
win.querySelector('.titlebar');
if (titlebar) {
// Restore session position if available
const session = settingsManager
.getSection('session')
.windows[id];
if (session && session.left && session.top) {
win.style.left = session.left;
win.style.top = session.top;
if (session.maximized) {
win.classList.add('maximized');
}
} else {
// First time: normalize position
setTimeout(() => {
normalizeWindowPosition(win);
}, CONFIG.TIMINGS.NORMALIZATION_DELAY);
}
// Enable dragging
titlebar.style.touchAction = 'none';
titlebar.addEventListener(
'pointerdown',
titlebarDragHandler
);
win.setAttribute('data-cde-registered', 'true');
}
}
Dynamic Scanning
WindowManager uses a MutationObserver to automatically detect and register new windows:function initDynamicScanning(): void {
// Scan existing windows
const windows = document.querySelectorAll(
'.window, .cde-retro-modal'
);
windows.forEach((el) => registerWindow(el as HTMLElement));
// Observe for new windows
const observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
mutation.addedNodes.forEach((node) => {
if (node instanceof HTMLElement) {
if (node.classList.contains('window') ||
node.classList.contains('cde-retro-modal')) {
registerWindow(node);
}
// Scan children
node.querySelectorAll('.window, .cde-retro-modal')
.forEach((el) => registerWindow(el as HTMLElement));
}
});
});
});
observer.observe(document.body, {
childList: true,
subtree: true
});
}
Z-Index Management
Layered Z-Index System
Z-indexes are managed in separate layers to prevent conflicts:// Layer allocation
const BASE_WINDOW_Z = 10000; // Regular windows
const BASE_MODAL_Z = 90000; // Modal dialogs
const DROPDOWN_Z = 20000; // Dropdown menus
let highestWindowZIndex = CONFIG.WINDOW.BASE_Z_INDEX;
let highestModalZIndex = 90000;
function getNextZIndex(isModal: boolean = false): number {
if (isModal) {
return ++highestModalZIndex;
}
return ++highestWindowZIndex;
}
function getTopZIndex(): number {
return Math.max(highestWindowZIndex, highestModalZIndex);
}
Focus and Z-Index
Focusing a window assigns it the highest z-index in its layer:function focusWindow(id: string): void {
if (id === lastFocusedWindowId) return;
const win = document.getElementById(id);
if (!win) return;
if (!dragState.isDragging) {
// Remove active class from previous window
if (lastFocusedWindowId) {
const prevWin = document.getElementById(
lastFocusedWindowId
);
if (prevWin) prevWin.classList.remove('active');
}
// Periodic cleanup of stale classes
if (Math.random() < 0.05) {
document.querySelectorAll('.active').forEach((el) => {
if (el.id !== id) el.classList.remove('active');
});
}
win.classList.add('active');
lastFocusedWindowId = id;
zIndex = getNextZIndex();
win.style.zIndex = String(zIndex);
if (window.AudioManager) window.AudioManager.click();
}
}
Drag and Drop
Drag State Management
interface DragState {
element: HTMLElement | null;
offsetX: number;
offsetY: number;
startX: number;
startY: number;
startLeft: number;
startTop: number;
lastX: number;
lastY: number;
isDragging: boolean;
}
Pointer-Based Dragging
Dragging uses PointerEvents for unified mouse/touch support:function drag(e: PointerEvent, id: string): void {
// Disable drag on mobile
if (isMobile()) {
logger.log(
`[WindowManager] Drag disabled on mobile for: ${id}`
);
return;
}
if (!e.isPrimary) return;
const el = document.getElementById(id);
if (!el) return;
e.preventDefault();
e.stopPropagation();
// Normalize position if transform is applied
if (window.getComputedStyle(el).transform !== 'none') {
normalizeWindowPosition(el);
}
focusWindow(id);
const rect = el.getBoundingClientRect();
dragState.element = el;
dragState.offsetX = e.clientX - rect.left;
dragState.offsetY = e.clientY - rect.top;
dragState.lastX = e.clientX;
dragState.lastY = e.clientY;
dragState.isDragging = true;
// Capture pointer for reliable tracking
el.setPointerCapture(e.pointerId);
// X11-style move cursor
document.documentElement.style.setProperty(
'--cde-cursor-override',
"url('/icons/cursors/cursor-move.svg') 12 12, move"
);
document.body.style.cursor =
"url('/icons/cursors/cursor-move.svg') 12 12, move";
// Performance optimization
el.style.willChange = 'transform, left, top';
el.addEventListener('pointermove', move, { passive: false });
el.addEventListener('pointerup', stopDrag, { passive: false });
el.addEventListener('pointercancel', stopDrag, { passive: false });
}
Mouse Acceleration
Mouse movement supports configurable acceleration:function move(e: PointerEvent): void {
if (!dragState.element || !dragState.isDragging) return;
e.preventDefault();
e.stopPropagation();
// Get acceleration from CSS variable
const accelStr = getComputedStyle(document.documentElement)
.getPropertyValue('--mouse-acceleration');
const acceleration = parseFloat(accelStr) || 1;
// Calculate delta
const deltaX = e.clientX - dragState.lastX;
const deltaY = e.clientY - dragState.lastY;
// Apply acceleration
let currentLeft = parseFloat(
dragState.element.style.left || '0'
);
let currentTop = parseFloat(
dragState.element.style.top || '0'
);
let left = currentLeft + deltaX * acceleration;
let top = currentTop + deltaY * acceleration;
// Update tracking
dragState.lastX = e.clientX;
dragState.lastY = e.clientY;
// Apply constraints (shown in next section)
// ...
dragState.element.style.left = left + 'px';
dragState.element.style.top = top + 'px';
}
Viewport Constraints
Windows are constrained to stay within viewport bounds:function move(e: PointerEvent): void {
// ... delta calculation ...
const winWidth = dragState.element.offsetWidth;
const winHeight = dragState.element.offsetHeight;
const viewportWidth = window.innerWidth;
const viewportHeight = window.innerHeight;
const TOP_BAR_HEIGHT = CONFIG.WINDOW.TOP_BAR_HEIGHT;
const PANEL_HEIGHT = isMobile() ? 65 : 85;
// Define bounds
const minX = 0;
const maxX = Math.max(0, viewportWidth - winWidth);
const minY = TOP_BAR_HEIGHT;
const maxY = Math.max(
minY,
viewportHeight - winHeight - PANEL_HEIGHT
);
// Clamp position
left = Math.max(minX, Math.min(left, maxX));
top = Math.max(minY, Math.min(top, maxY));
dragState.element.style.left = left + 'px';
dragState.element.style.top = top + 'px';
}
Opaque vs Wireframe Dragging
function move(e: PointerEvent): void {
// ...
// Check if opaque dragging is enabled
const opaque = document.documentElement
.getAttribute('data-opaque-drag') !== 'false';
if (!opaque) {
// Wireframe mode: lighter rendering
dragState.element.classList.add('dragging-wireframe');
}
// ...
}
Drag Completion
function stopDrag(e: PointerEvent): void {
if (!dragState.element || !dragState.isDragging) return;
e.preventDefault();
e.stopPropagation();
const el = dragState.element;
el.releasePointerCapture(e.pointerId);
el.removeEventListener('pointermove', move);
el.removeEventListener('pointerup', stopDrag);
el.removeEventListener('pointercancel', stopDrag);
// Clear performance hints
el.style.willChange = 'auto';
// Restore cursor
document.body.style.cursor = '';
el.classList.remove('dragging-wireframe');
dragState.isDragging = false;
// Persist position
settingsManager.updateWindowSession(el.id, {
left: el.style.left,
top: el.style.top,
maximized: el.classList.contains('maximized'),
});
dragState.element = null;
}
Window Operations
Minimize
function minimizeWindow(id: string): void {
const win = document.getElementById(id);
if (!win) return;
if (win.style.display !== 'none') {
// Save state before hiding
windowStates[id] = {
display: win.style.display,
left: win.style.left,
top: win.style.top,
width: win.style.width,
height: win.style.height,
maximized: win.classList.contains('maximized'),
};
// Animate closing
win.classList.add('window-closing');
if (window.AudioManager) {
window.AudioManager.windowMinimize();
}
// Hide after animation
win.addEventListener(
'animationend',
() => {
win.style.display = 'none';
win.classList.remove('window-closing');
},
{ once: true }
);
}
}
Maximize
function maximizeWindow(id: string): void {
const win = document.getElementById(id);
if (!win || win.hasAttribute('data-no-maximize')) return;
if (win.classList.contains('maximized')) {
// Restore
win.classList.remove('maximized');
if (window.AudioManager) {
window.AudioManager.windowMaximize();
}
// Update icon
const maxBtnImg = win.querySelector('.max-btn img') as
HTMLImageElement;
if (maxBtnImg) {
maxBtnImg.src = '/icons/ui/maximize-inactive.png';
}
// Restore saved size/position
if (windowStates[id]) {
win.style.left = windowStates[id].left || '';
win.style.top = windowStates[id].top || '';
win.style.width = windowStates[id].width || '';
win.style.height = windowStates[id].height || '';
}
settingsManager.updateWindowSession(id, {
maximized: false
});
} else {
// Maximize
windowStates[id] = {
left: win.style.left,
top: win.style.top,
width: win.style.width,
height: win.style.height,
maximized: false,
};
win.classList.add('maximized');
if (window.AudioManager) {
window.AudioManager.windowMaximize();
}
// Update icon
const maxBtnImg = win.querySelector('.max-btn img') as
HTMLImageElement;
if (maxBtnImg) {
maxBtnImg.src = '/icons/ui/maximize-toggled-inactive.png';
}
settingsManager.updateWindowSession(id, {
maximized: true
});
}
WindowManager.focusWindow(id);
}
Window Shading
Double-click titlebar to “shade” (roll up) a window:function shadeWindow(id: string): void {
const win = document.getElementById(id);
if (!win) return;
const titlebar = win.querySelector('.titlebar') as HTMLElement;
if (!titlebar) return;
const isMaximized = win.classList.contains('maximized');
if (win.classList.contains('shaded')) {
// Unshade: restore height
win.classList.remove('shaded');
if (isMaximized) {
win.style.height = '';
} else if (windowStates[id]?.height) {
win.style.height = windowStates[id].height!;
}
if (window.AudioManager) {
window.AudioManager.windowShade();
}
} else {
// Shade: save height and collapse
if (!isMaximized) {
windowStates[id] = {
...windowStates[id],
height: win.style.height ||
getComputedStyle(win).height,
};
}
win.classList.add('shaded');
win.style.height = titlebar.offsetHeight + 'px';
if (window.AudioManager) {
window.AudioManager.windowShade();
}
}
}
Focus Management
Focus Modes
Two focus modes are supported:- Click-to-Focus
- Point-to-Focus
Default mode. Windows receive focus when clicked.
document.addEventListener('pointerdown', (e) => {
if (dragState.isDragging) return;
const target = e.target as HTMLElement;
const win = target.closest('.window, .cde-retro-modal');
if (win) {
focusWindow(win.id);
}
});
X11-style: Windows receive focus when mouse enters.
document.addEventListener('pointerenter', (e) => {
const mode = document.documentElement
.getAttribute('data-focus-mode');
if (mode !== 'point') return;
const target = e.target as HTMLElement;
const win = target.closest('.window, .cde-retro-modal');
if (win) {
focusWindow(win.id);
}
}, true);
Workspace Management
Virtual Desktops
WindowManager supports 4 virtual workspaces:function switchWorkspace(id: string): void {
if (id === currentWorkspace) return;
AudioManager.click();
const windows = document.querySelectorAll(
'.window, .cde-retro-modal'
);
// Hide windows from current workspace
windows.forEach((win) => {
const el = win as HTMLElement;
const winWorkspace = el.getAttribute('data-workspace');
if (winWorkspace === currentWorkspace) {
const isVisible =
window.getComputedStyle(el).display !== 'none';
if (isVisible) {
el.setAttribute('data-was-opened', 'true');
el.style.display = 'none';
}
}
});
currentWorkspace = id;
// Show windows from new workspace
windows.forEach((win) => {
const el = win as HTMLElement;
const winWorkspace = el.getAttribute('data-workspace');
if (winWorkspace === currentWorkspace) {
if (el.getAttribute('data-was-opened') === 'true') {
el.style.display = 'flex';
}
}
});
// Update pager UI
const pagerItems = document.querySelectorAll(
'.pager-workspace'
);
pagerItems.forEach((item) => {
if ((item as HTMLElement).dataset.workspace === id) {
item.classList.add('active');
} else {
item.classList.remove('active');
}
});
}
Workspace Assignment
Windows are automatically assigned to the current workspace when opened:function showWindow(id: string): void {
const win = document.getElementById(id);
if (!win) return;
// Assign workspace on first show
if (!win.getAttribute('data-workspace')) {
win.setAttribute('data-workspace', currentWorkspace);
}
// Mark as opened
win.setAttribute('data-was-opened', 'true');
win.style.display = 'flex';
win.classList.add('window-opening');
// Center on mobile
if (isMobile()) {
centerWindow(win);
}
focusWindow(id);
AudioManager.windowOpen();
win.addEventListener(
'animationend',
() => {
win.classList.remove('window-opening');
},
{ once: true }
);
}
Mobile Considerations
Disabled Features
Certain features are disabled on mobile for better UX:function isMobile(): boolean {
return window.innerWidth < 768;
}
// Drag disabled on mobile
function drag(e: PointerEvent, id: string): void {
if (isMobile()) {
logger.log('[WindowManager] Drag disabled on mobile');
return;
}
// ...
}
Automatic Centering
Windows are automatically centered on mobile devices:function centerWindow(win: HTMLElement): void {
const winWidth = win.offsetWidth;
const winHeight = win.offsetHeight;
const viewportWidth = window.innerWidth;
const viewportHeight = window.innerHeight;
const TOP_BAR_HEIGHT = CONFIG.WINDOW.TOP_BAR_HEIGHT;
const PANEL_HEIGHT = isMobile() ? 65 : 85;
let left = (viewportWidth - winWidth) / 2;
let top = (viewportHeight - winHeight) / 2;
// Clamp to viewport
const minX = 0;
const maxX = Math.max(0, viewportWidth - winWidth);
const minY = TOP_BAR_HEIGHT;
const maxY = Math.max(
minY,
viewportHeight - winHeight - PANEL_HEIGHT
);
left = Math.max(minX, Math.min(left, maxX));
top = Math.max(minY, Math.min(top, maxY));
win.style.position = 'absolute';
win.style.left = `${left}px`;
win.style.top = `${top}px`;
win.style.transform = 'none';
}
Resize Handling
Windows are normalized when viewport resizes:window.addEventListener('resize', () => {
clearTimeout(resizeTimer);
resizeTimer = window.setTimeout(() => {
logger.log(
'[WindowManager] Viewport resized, ' +
'normalizing positions...'
);
document.querySelectorAll('.window, .cde-retro-modal')
.forEach((win) => {
if (win instanceof HTMLElement) {
if (isMobile()) {
centerWindow(win);
} else {
normalizeWindowPosition(win);
}
}
});
}, CONFIG.TIMINGS.NORMALIZATION_DELAY);
});
Global Exposure
WindowManager functions are exposed globally for legacy compatibility:declare global {
interface Window {
drag: (e: PointerEvent, id: string) => void;
focusWindow: (id: string) => void;
centerWindow: (win: HTMLElement) => void;
minimizeWindow: typeof minimizeWindow;
maximizeWindow: typeof maximizeWindow;
shadeWindow: typeof shadeWindow;
WindowManager: typeof WindowManager;
}
}
window.drag = WindowManager.drag;
window.focusWindow = WindowManager.focusWindow;
window.centerWindow = WindowManager.centerWindow;
window.minimizeWindow = minimizeWindow;
window.maximizeWindow = maximizeWindow;
window.shadeWindow = shadeWindow;
window.WindowManager = WindowManager;
Best Practices
Always Register Windows
Always Register Windows
Ensure windows have proper structure and are registered:
<div id="myWindow" class="window">
<div id="myWindowTitlebar" class="titlebar">
<span class="titlebar-text">My Window</span>
<div class="titlebar-buttons">
<button class="min-btn"
onclick="minimizeWindow('myWindow')">
<img src="/icons/ui/shade-inactive.png" />
</button>
<button class="max-btn"
onclick="maximizeWindow('myWindow')">
<img src="/icons/ui/maximize-inactive.png" />
</button>
<button class="close-btn"
onclick="document.getElementById('myWindow').style.display='none'">
<img src="/icons/ui/close-inactive.png" />
</button>
</div>
</div>
<div class="window-content">
<!-- Content -->
</div>
</div>
Persist Window State
Persist Window State
Use
updateWindowSession after position/state changes:settingsManager.updateWindowSession(id, {
left: win.style.left,
top: win.style.top,
maximized: win.classList.contains('maximized'),
});
Handle Mobile Gracefully
Handle Mobile Gracefully
Check
isMobile() before drag/resize operations:if (isMobile()) {
centerWindow(win);
return; // Skip desktop-specific operations
}
Related Documentation
Architecture
Overall system architecture overview
Storage
Window session persistence mechanism
Virtual Filesystem
File operations in window contexts
Development
Build applications using WindowManager

