218 lines
5.8 KiB
JavaScript
218 lines
5.8 KiB
JavaScript
|
const ByteArray = imports.byteArray;
|
||
|
const GObject = imports.gi.GObject;
|
||
|
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 versionCheck = Unite.imports.helpers.versionCheck;
|
||
|
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 = new GObject.Class({
|
||
|
Name: 'UniteWindowDecoration',
|
||
|
Extends: Base,
|
||
|
|
||
|
_enableKey: 'hide-window-titlebars',
|
||
|
_disableValue: 'never',
|
||
|
|
||
|
_onInitialize() {
|
||
|
this.monitorManager = Meta.MonitorManager.get();
|
||
|
this._useMotifHints = versionCheck('> 3.30.2');
|
||
|
},
|
||
|
|
||
|
_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;
|
||
|
|
||
|
if (this._useMotifHints) {
|
||
|
let state = this._getMotifHints(win);
|
||
|
handleWin = !win.is_client_decorated();
|
||
|
handleWin = handleWin && (state[2] != '0x2' && state[2] != '0x0');
|
||
|
} else {
|
||
|
handleWin = win.decorated;
|
||
|
}
|
||
|
|
||
|
return handleWin;
|
||
|
},
|
||
|
|
||
|
_toggleDecorations(win, hide) {
|
||
|
let winId = this._getWindowXID(win);
|
||
|
if (!winId) return;
|
||
|
|
||
|
GLib.idle_add(0, () => {
|
||
|
if (this._useMotifHints)
|
||
|
this._toggleDecorationsMotif(winId, hide);
|
||
|
else
|
||
|
this._toggleDecorationsGtk(winId, hide);
|
||
|
});
|
||
|
},
|
||
|
|
||
|
_toggleDecorationsGtk(winId, hide) {
|
||
|
let prop = '_GTK_HIDE_TITLEBAR_WHEN_MAXIMIZED';
|
||
|
let value = hide ? '0x1' : '0x0';
|
||
|
|
||
|
Util.spawn(['xprop', '-id', winId, '-f', prop, '32c', '-set', prop, value]);
|
||
|
},
|
||
|
|
||
|
_toggleDecorationsMotif(winId, hide) {
|
||
|
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;
|
||
|
let toggleDecor = focusWindow;
|
||
|
|
||
|
if (!this._useMotifHints && this._setting == 'both')
|
||
|
toggleDecor = focusWindow && focusWindow.get_maximized() !== 0;
|
||
|
|
||
|
if (toggleDecor)
|
||
|
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;
|
||
|
|
||
|
if (isMaximized(win, this._setting))
|
||
|
this._hideTitlebar(win);
|
||
|
else
|
||
|
this._showTitlebar(win);
|
||
|
},
|
||
|
|
||
|
_updateUserStyles() {
|
||
|
let styles = '';
|
||
|
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`;
|
||
|
|
||
|
switch (this._setting) {
|
||
|
case 'both': styles = maximized + tiled; break;
|
||
|
case 'maximized': styles = maximized; break;
|
||
|
case 'tiled': styles = tiled; break;
|
||
|
}
|
||
|
|
||
|
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) });
|
||
|
}
|
||
|
});
|