') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ', 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ', 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ', 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); })(); GitHub - redhog/InfiniteGlass: Window manager with infinite desktop, infinite zoom and infinite window resolution · GitHub
Skip to content

Latest commit

History

1,284 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

About

GitHub Workflow StatusGitHub release (latest by date)GitHub All ReleasesGitHub licenseGitHub issuesGitHub pull requestsGitHub stars

This is a minimalistic compositing window manager for X with infinite desktop, infinite zoom and infinite virtual window pixel resolution.

ScreenshotScreenshot

Videos:

Features:

  • Windows are glued to an infinite desktop to some coordinates and size
  • Window pixel resolution is independent of their size on the desktop
  • The user can zoom / pan to any view of the desktop
  • There are shortcut commands to zoom to a window, and to make a window have a 1:1 resolution to the screen
  • Window placement is stored between sessions
    • Windows that are closed leave a ghost window in their place that can be moved, resized and deleted.
    • When a window with the same name reappears, it takes the place of the ghost window if it still exists.
    • Ghost windows are stored in a file between sessions.
  • Window content / application state is stored between sessions for supported clients
    • Applications supporting the XSM protocol can be closed and saved and later restored, in the same session or another.
  • Infinitely zoomable SVG for buttons etc
    • A window can display an SVG image instead of content, and the SVG will render to the current screen resolution, no matter the zoom level.

Documentation

Installation

Tested on: Ubuntu-MATE 18.04 LTS Bionic Beaver.

Requires OpenGL version 3.0 or higher with support for GLSL 3.30, and pretty much all modern X extensions, including their development headers. To install all dependencies:

sudo apt install -y $(cat ./dependencies.txt)

To install InfiniteGlass on your machine

sudo make install

or, if you want to be able to edit the python files in in place without rerunning the install command:

sudo make devinstall

Note that this does not differ from a the above make install with regards to how the non-python binaries are installed.

Once installed, you should be able to select InfiniteGlass among the available sessions when logging in.

Testing

It is also possible to try the window manager inside a window using the Xephyr X server, without installing anything. To do so, simply run

make

If your Linux distribution does not have the right libraries or versions of libraries (e.g. X extensions, OpenGL version...) easily installable, you can test the same using a docker container! Just run

make run-in-docker

Configuration

Whichever method for running it you use, the first time you run the window manager, a set of default config files will be added to your ~/.config/glass directory. These files can be safely edited, but will be re-instated if deleted.

Unit- & integration-tests

make all
pip install nose2
nose2 -s tests -v

License

GNU GPL v3, see the file LICENSE for details

The file xevent.c has a different, more permissible license, see the top of the file for details. The file coastline50.geojson has a different, more permissible license, see coastline50.geojson.LICENSE for details. The file binary_tree_bin_packer.py has a different, more permissible license, see binary_tree_bin_packer.py.LICENSE for details.

About

Window manager with infinite desktop, infinite zoom and infinite window resolution

Resources

Stars

61 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages