197 lines
5.1 KiB
JavaScript
197 lines
5.1 KiB
JavaScript
|
const ByteArray = imports.byteArray
|
||
|
const GLib = imports.gi.GLib
|
||
|
const Meta = imports.gi.Meta
|
||
|
const Util = imports.misc.util
|
||
|
const Unite = imports.misc.extensionUtils.getCurrentExtension()
|
||
|
const Base = Unite.imports.module.BaseModule
|
||
|
const getWindowXID = Unite.imports.helpers.getWindowXID
|
||
|
const isWindow = Unite.imports.helpers.isWindow
|
||
|
const isMaximized = Unite.imports.helpers.isMaximized
|
||
|
const loadUserStyles = Unite.imports.helpers.loadUserStyles
|
||
|
|
||
|
var WindowDecoration = class WindowDecoration extends Base {
|
||
|
_onSetup() {
|
||
|
this._enableKey = 'hide-window-titlebars'
|
||
|
this._disableValue = 'never'
|
||
|
}
|
||
|
|
||
|
_onInitialize() {
|
||
|
this.monitorManager = Meta.MonitorManager.get()
|
||
|
}
|
||
|
|
||
|
_onActivate() {
|
||
|
this._signals.connect(global.display, 'notify::focus-window', 'updateTitlebar')
|
||
|
this._signals.connect(global.window_manager, 'size-change', 'updateTitlebar')
|
||
|
this._signals.connect(this.monitorManager, 'monitors-changed', 'undecorateWindows')
|
||
|
|
||
|
this._settings.connect('hide-window-titlebars', 'updateUserStyles')
|
||
|
this._settings.connect('button-layout', 'updateUserStyles')
|
||
|
this._settings.connect('restrict-to-primary-screen', 'undecorateWindows')
|
||
|
|
||
|
this._updateUserStyles()
|
||
|
this._undecorateWindows()
|
||
|
}
|
||
|
|
||
|
_onDeactivate() {
|
||
|
this._removeUserStyles()
|
||
|
this._decorateWindows()
|
||
|
}
|
||
|
|
||
|
_onReset() {
|
||
|
this._removeUserStyles()
|
||
|
this._updateUserStyles()
|
||
|
|
||
|
this._undecorateWindows()
|
||
|
}
|
||
|
|
||
|
_getWindowXID(win) {
|
||
|
win._windowXID = win._windowXID || getWindowXID(win)
|
||
|
return win._windowXID
|
||
|
}
|
||
|
|
||
|
_getHintValue(win, hint) {
|
||
|
let winId = this._getWindowXID(win)
|
||
|
if (!winId) return
|
||
|
|
||
|
let result = GLib.spawn_command_line_sync(`xprop -id ${winId} ${hint}`)
|
||
|
let string = ByteArray.toString(result[1])
|
||
|
if (!string.match(/=/)) return
|
||
|
|
||
|
string = string.split('=')[1].trim().split(',').map(part => {
|
||
|
part = part.trim()
|
||
|
return part.match(/\dx/) ? part : `0x${part}`
|
||
|
})
|
||
|
|
||
|
return string
|
||
|
}
|
||
|
|
||
|
_setHintValue(win, hint, value) {
|
||
|
let winId = this._getWindowXID(win)
|
||
|
if (!winId) return
|
||
|
|
||
|
Util.spawn(['xprop', '-id', winId, '-f', hint, '32c', '-set', hint, value])
|
||
|
}
|
||
|
|
||
|
_getMotifHints(win) {
|
||
|
if (!win._uniteOriginalState) {
|
||
|
let state = this._getHintValue(win, '_UNITE_ORIGINAL_STATE')
|
||
|
|
||
|
if (!state) {
|
||
|
state = this._getHintValue(win, '_MOTIF_WM_HINTS')
|
||
|
state = state || ['0x2', '0x0', '0x1', '0x0', '0x0']
|
||
|
|
||
|
this._setHintValue(win, '_UNITE_ORIGINAL_STATE', state.join(', '))
|
||
|
}
|
||
|
|
||
|
win._uniteOriginalState = state
|
||
|
}
|
||
|
|
||
|
return win._uniteOriginalState
|
||
|
}
|
||
|
|
||
|
_getAllWindows() {
|
||
|
let windows = global.get_window_actors().map(win => win.meta_window)
|
||
|
return windows.filter(win => this._handleWindow(win))
|
||
|
}
|
||
|
|
||
|
_handleWindow(win) {
|
||
|
let handleWin = false
|
||
|
if (!isWindow(win)) return
|
||
|
|
||
|
let state = this._getMotifHints(win)
|
||
|
handleWin = !win.is_client_decorated()
|
||
|
handleWin = handleWin && (state[2] != '0x2' && state[2] != '0x0')
|
||
|
|
||
|
return handleWin
|
||
|
}
|
||
|
|
||
|
_toggleDecorations(win, hide) {
|
||
|
let winId = this._getWindowXID(win)
|
||
|
if (!winId) return
|
||
|
|
||
|
let prop = '_MOTIF_WM_HINTS'
|
||
|
let flag = '0x2, 0x0, %s, 0x0, 0x0'
|
||
|
let value = hide ? flag.format('0x2') : flag.format('0x1')
|
||
|
|
||
|
Util.spawn(['xprop', '-id', winId, '-f', prop, '32c', '-set', prop, value])
|
||
|
}
|
||
|
|
||
|
_resetDecorations(win) {
|
||
|
if (!this._handleWindow(win))
|
||
|
return
|
||
|
|
||
|
this._toggleDecorations(win, false)
|
||
|
|
||
|
delete win._decorationOFF
|
||
|
delete win._windowXID
|
||
|
}
|
||
|
|
||
|
_updateTitlebar() {
|
||
|
let focusWindow = global.display.focus_window
|
||
|
if (!focusWindow) return
|
||
|
|
||
|
this._toggleTitlebar(focusWindow)
|
||
|
}
|
||
|
|
||
|
_showTitlebar(win) {
|
||
|
if (!win._decorationOFF) return
|
||
|
|
||
|
win._decorationOFF = false
|
||
|
this._toggleDecorations(win, false)
|
||
|
}
|
||
|
|
||
|
_hideTitlebar(win) {
|
||
|
if (win._decorationOFF) return
|
||
|
|
||
|
win._decorationOFF = true
|
||
|
this._toggleDecorations(win, true)
|
||
|
}
|
||
|
|
||
|
_toggleTitlebar(win) {
|
||
|
if (!this._handleWindow(win))
|
||
|
return
|
||
|
|
||
|
let maxed = isMaximized(win, this._setting)
|
||
|
let always = this._setting == 'always'
|
||
|
|
||
|
if (always || maxed)
|
||
|
this._hideTitlebar(win)
|
||
|
else
|
||
|
this._showTitlebar(win)
|
||
|
}
|
||
|
|
||
|
_getCssImports() {
|
||
|
let position = this._settings.get('window-buttons-position')
|
||
|
let filePath = `${Unite.path}/styles/buttons-${position}`
|
||
|
let maximized = `@import url('${filePath}.css');\n`
|
||
|
let tiled = `@import url('${filePath}-tiled.css');\n`
|
||
|
let always = `@import url('${filePath}-always.css');\n`
|
||
|
|
||
|
switch (this._setting) {
|
||
|
case 'both': return maximized + tiled
|
||
|
case 'maximized': return maximized
|
||
|
case 'tiled': return tiled
|
||
|
case 'always': return always
|
||
|
}
|
||
|
}
|
||
|
|
||
|
_updateUserStyles() {
|
||
|
let styles = this._getCssImports()
|
||
|
loadUserStyles(styles || '')
|
||
|
}
|
||
|
|
||
|
_removeUserStyles() {
|
||
|
loadUserStyles('')
|
||
|
}
|
||
|
|
||
|
_undecorateWindows() {
|
||
|
let windows = this._getAllWindows()
|
||
|
windows.forEach(win => { this._toggleTitlebar(win) })
|
||
|
}
|
||
|
|
||
|
_decorateWindows() {
|
||
|
let windows = this._getAllWindows()
|
||
|
windows.forEach(win => { this._resetDecorations(win) })
|
||
|
}
|
||
|
}
|