Skip to content

Commit

Permalink
Version 4
Browse files Browse the repository at this point in the history
  • Loading branch information
wilfm committed Aug 4, 2015
1 parent e2572ca commit 24d8efd
Show file tree
Hide file tree
Showing 4 changed files with 147 additions and 86 deletions.
34 changes: 12 additions & 22 deletions [email protected]/app_menu.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,14 @@ let appMenu = null;
*/
function updateAppMenu() {
let win = global.display.focus_window;

if(!win) {
if (!win) {
return false;
}

let title = win.title;

// Not the topmost maximized window.
if(win !== Util.getWindow()) {
if (win !== Util.getWindow()) {
let app = Shell.WindowTracker.get_default().get_window_app(win);
title = app.get_name();
}
Expand All @@ -50,17 +49,17 @@ function updateAppMenu() {
let activeWindow = null;
let awCallbackID = 0;
function changeActiveWindow(win) {
if(win === activeWindow) {
if (win === activeWindow) {
return;
}

if(activeWindow) {
if (activeWindow) {
activeWindow.disconnect(awCallbackID);
}

activeWindow = win;

if(win) {
if (win) {
awCallbackID = win.connect('notify::title', updateAppMenu);
updateAppMenu();
}
Expand Down Expand Up @@ -97,9 +96,9 @@ let HIDE_DURATION = 0.1;
let tooltipDelayCallbackID = 0;
let menuCallbackID = 0;

function onHover(actor) {
function onAppMenuHover(actor) {
let hover = actor.get_hover();
if(showTooltip === hover) {
if (showTooltip === hover) {
return false;
}

Expand All @@ -122,7 +121,7 @@ function onHover(actor) {

Main.uiGroup.add_actor(tooltip);
menuCallbackID = appMenu.menu.connect('open-state-changed', function(menu, open) {
if(open) {
if (open) {
Main.uiGroup.remove_actor(tooltip);
} else {
Main.uiGroup.add_actor(tooltip);
Expand All @@ -147,7 +146,7 @@ function onHover(actor) {

return false;
});
} else if(tooltipDelayCallbackID > 0) {
} else if (tooltipDelayCallbackID > 0) {
if(!Mainloop.source_remove(tooltipDelayCallbackID)) {
// If the event ran, then we hide.
LOG('hide title tooltip');
Expand Down Expand Up @@ -180,7 +179,7 @@ function onHover(actor) {
function init() {
tooltip = new St.Label({
style_class: 'tooltip dash-label',
text: ''
text: '',
});
}

Expand All @@ -189,16 +188,7 @@ let focusCallbackID = 0;
let tooltipCallbackID = 0;
function enable() {
tooltip.opacity = 0;

if(Main.panel.statusArea && Main.panel.statusArea["appMenu"]) {
appMenu = Main.panel.statusArea["appMenu"];
} else if(Main.panel._appMenu) {
appMenu = Main.panel._appMenu;
} else if(Main.panel.statusArea["appMenu"]) {
appMenu = Main.panel.statusArea["appMenu"];
} else {
appMenu = Main.panel.statusArea.appMenu;
}
appMenu = Main.panel.statusArea.appMenu;

focusCallbackID = Shell.WindowTracker.get_default().connect('notify::focus-app', onFocusChange);

Expand All @@ -210,7 +200,7 @@ function enable() {
Mainloop.idle_add(updateAppMenu);
}));

tooltipCallbackID = appMenu.actor.connect('notify::hover', onHover);
tooltipCallbackID = appMenu.actor.connect('notify::hover', onAppMenuHover);
}

function disable() {
Expand Down
175 changes: 123 additions & 52 deletions [email protected]/decoration.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,49 +30,95 @@ function WARN(message) {
* success if the window's actor (`win.get_compositor_private()`) exists.
*/
function guessWindowXID(win) {
let id = null;
// We cache the result so we don't need to redetect.
if (win._pixelSaverWindowID) {
return win._pixelSaverWindowID;
}

/* if window title has non-utf8 characters, get_description() complains
* "Failed to convert UTF-8 string to JS string: Invalid byte sequence in conversion input",
* event though get_title() works.
*/
try {
id = win.get_description().match(/0x[0-9a-f]+/);
if (id) {
id = id[0];
return id;
let m = win.get_description().match(/0x[0-9a-f]+/);
if (m && m[0]) {
return win._pixelSaverWindowID = m[0];
}
} catch (err) {
}
} catch (err) { }

// use xwininfo, take first child.
let act = win.get_compositor_private();
if (act) {
id = GLib.spawn_command_line_sync('xwininfo -children -id 0x%x'.format(act['x-window']));
if (id[0]) {
let str = id[1].toString();
let xwininfo = GLib.spawn_command_line_sync('xwininfo -children -id 0x%x'.format(act['x-window']));
if (xwininfo[0]) {
let str = xwininfo[1].toString();

/* The X ID of the window is the one preceding the target window's title.
* This is to handle cases where the window has no frame and so
* act['x-window'] is actually the X ID we want, not the child.
*/
let regexp = new RegExp('(0x[0-9a-f]+) +"%s"'.format(win.title));
id = str.match(regexp);
if (id) {
return id[1];
let m = str.match(regexp);
if (m && m[1]) {
return win._pixelSaverWindowID = m[1];
}

/* Otherwise, just grab the child and hope for the best */
id = str.split(/child(?:ren)?:/)[1].match(/0x[0-9a-f]+/);
if (id) {
return id[0];
m = str.split(/child(?:ren)?:/)[1].match(/0x[0-9a-f]+/);
if (m && m[0]) {
return win._pixelSaverWindowID = m[0];
}
}
}

// debugging for when people find bugs..
WARN("Could not find XID for window with title %s".format(win.title));
return null;
}

/**
* Get the value of _GTK_HIDE_TITLEBAR_WHEN_MAXIMIZED before
* pixel saver did its magic.
*
* @param {Meta.Window} win - the window to check the property
*/
function getOriginalState(win) {
if (win._pixelSaverOriginalState !== undefined) {
return win._pixelSaverOriginalState;
}

let id = guessWindowXID(win);
let cmd = 'xprop -id ' + id;
LOG(cmd);

let xprops = GLib.spawn_command_line_sync(cmd);
if (!xprops[0]) {
WARN("xprop failed for " + win.title + " with id " + id);
return false;
}

let str = xprops[1].toString();
let m = str.match(/^_PIXEL_SAVER_ORIGINAL_STATE\(CARDINAL\) = ([0-9]+)$/m);
if (m) {
return win._pixelSaverOriginalState = !!m[1];
}

m = str.match(/^_GTK_HIDE_TITLEBAR_WHEN_MAXIMIZED(\(CARDINAL\))? = ([0-9]+)$/m);
if (m) {
let state = !!m[1];
cmd = ['xprop', '-id', id,
'-f', '_PIXEL_SAVER_ORIGINAL_STATE', '32c',
'-set', '_PIXEL_SAVER_ORIGINAL_STATE',
(state ? '0x1' : '0x0')];
LOG(cmd.join(' '));
Util.spawn(cmd);
return win._pixelSaverOriginalState = state;
}

WARN("Can't find original state for " + win.title + " with id " + id);
return false;
}

/**
* Tells the window manager to hide the titlebar on maximised windows.
*
Expand All @@ -87,42 +133,45 @@ function guessWindowXID(win) {
*
* @param {Meta.Window} win - window to set the HIDE_TITLEBAR_WHEN_MAXIMIZED property of.
* @param {boolean} hide - whether to hide the titlebar or not.
* @param {boolean} [stopAdding] - if `win` does not have an actor and we couldn't
* find the window's XID, we try one more time to detect the XID, unless this
* is `true`. Internal use.
*/
function setHideTitlebar(win, hide, stopAdding) {
LOG('setHideTitlebar: ' + win.get_title() + ': ' + hide + (stopAdding ? ' (2)' : ''));
function setHideTitlebar(win, hide) {
LOG('setHideTitlebar: ' + win.get_title() + ': ' + hide);

let id = guessWindowXID(win);
/* Newly-created windows are added to the workspace before
* the compositor knows about them: get_compositor_private() is null.
* Additionally things like .get_maximized() aren't properly done yet.
* (see workspace.js _doAddWindow)
*/
if (!id && !win.get_compositor_private() && !stopAdding) {
Mainloop.idle_add(function () {
setHideTitlebar(win, hide, true); // only try once more.
return false; // define as one-time event
});
return;
}
// Make sure we save the state before altering it.
getOriginalState(win);

/* Undecorate with xprop. Use _GTK_HIDE_TITLEBAR_WHEN_MAXIMIZED.
* See (eg) mutter/src/window-props.c
*/
let cmd = ['xprop', '-id', id,
'-f', '_GTK_HIDE_TITLEBAR_WHEN_MAXIMIZED', '32c',
'-set', '_GTK_HIDE_TITLEBAR_WHEN_MAXIMIZED',
(hide ? '0x1' : '0x0')];

// fallback: if couldn't get id for some reason, use the window's name
if (!id) {
cmd[1] = '-name';
cmd[2] = win.get_title();
}
let cmd = ['xprop', '-id', guessWindowXID(win),
'-f', '_GTK_HIDE_TITLEBAR_WHEN_MAXIMIZED', '32c',
'-set', '_GTK_HIDE_TITLEBAR_WHEN_MAXIMIZED',
(hide ? '0x1' : '0x0')];
LOG(cmd.join(' '));
Util.spawn(cmd);

// Run xprop
[success, pid] = GLib.spawn_async(
null,
cmd,
null,
GLib.SpawnFlags.SEARCH_PATH | GLib.SpawnFlags.DO_NOT_REAP_CHILD,
null);

// After xprop completes, unmaximize and remaximize any window
// that is already maximized. It seems that setting the xprop on
// a window that is already maximized doesn't actually take
// effect immediately but it needs a focuse change or other
// action to force a relayout. Doing unmaximize and maximize
// here seems to be an uninvasive way to handle this. This needs
// to happen _after_ xprop completes.
GLib.child_watch_add(GLib.PRIORITY_DEFAULT, pid, function () {
const MAXIMIZED = Meta.MaximizeFlags.BOTH;
let flags = win.get_maximized();
if (flags == MAXIMIZED) {
win.unmaximize(MAXIMIZED);
win.maximize(MAXIMIZED);
}
});
}

/**** Callbacks ****/
Expand All @@ -138,6 +187,10 @@ function setHideTitlebar(win, hide, stopAdding) {
* @see undecorate
*/
function onWindowAdded(ws, win) {
if (win.window_type === Meta.WindowType.DESKTOP) {
return false;
}

// if the window is simply switching workspaces, it will trigger a
// window-added signal. We don't want to reprocess it then because we already
// have.
Expand All @@ -150,13 +203,30 @@ function onWindowAdded(ws, win) {
* Additionally things like .get_maximized() aren't properly done yet.
* (see workspace.js _doAddWindow)
*/
// FIXME: get hide-titlebar-when-maximized value
win._pixelSaverOriginalState = false;
LOG('onWindowAdded: ' + win.get_title() + ' initially hide title ? ' + win._pixelSaverOriginalState);
if (!win.get_compositor_private()) {
Mainloop.idle_add(function () {
onWindowAdded(ws, win);
return false;
});
return false;
}

let retry = 3;
Mainloop.idle_add(function () {
let id = guessWindowXID(win);
if (!id) {
if (--retry) {
return true;
}

WARN("Finding XID for window %s failed".format(win.title));
return false;
}

if(win._pixelSaverOriginalState === false) {
LOG('onWindowAdded: ' + win.get_title());
setHideTitlebar(win, true);
}
return false;
});

return false;
}
Expand Down Expand Up @@ -248,11 +318,12 @@ function disable() {
if (win.window_type === Meta.WindowType.DESKTOP) {
continue;
}
LOG('stopUndecorating: ' + win.title);

if (win._pixelSaverOriginalState === false) {
LOG('stopUndecorating: ' + win.title);
if (getOriginalState(win) === false) {
setHideTitlebar(win, false);
}

delete win._pixelSaverOriginalState;
}
}
Expand Down
22 changes: 11 additions & 11 deletions [email protected]/metadata.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
{ "description": "Removes the title bar on maximised windows.\n Based on Pixel Saver (use Window Buttons to get the buttons (you can configure them then)\n You should be able to use the original Maximus extension if you have 3.4 or 3.6\nPlease report bugs on the github issues page: https://github.com/wilfm/GnomeExtensionMaximusTwo/issues\nNote you need xprop installed for this to work - see the github page for help with which package to install.",
"name": "Maximus Two",
{
"_generated": "Generated by SweetTooth, do not edit",
"description": "Removes the title bar on maximised windows.\n Based on Pixel Saver (use Window Buttons to get the buttons (you can configure them then)\n You should be able to use the original Maximus extension if you have 3.4 or 3.6\nPlease report bugs on the github issues page: https://github.com/wilfm/GnomeExtensionMaximusTwo/issues\nNote you need xprop installed for this to work - see the github page for help with which package to install.",
"name": "Maximus Two",
"shell-version": [
"3.6",
"3.8",
"3.10",
"3.12"
],
"url": "https://github.com/wilfm/GnomeExtensionMaximusTwo",
"uuid": "[email protected]",
"version": 3
}
"3.12",
"3.14"
],
"url": "https://github.com/wilfm/GnomeExtensionMaximusTwo",
"uuid": "[email protected]",
"version": 4
}
2 changes: 1 addition & 1 deletion [email protected]/util.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
const Meta = imports.gi.Meta;

const MAXIMIZED = (Meta.MaximizeFlags.HORIZONTAL | Meta.MaximizeFlags.VERTICAL);
const MAXIMIZED = Meta.MaximizeFlags.BOTH;

function getWindow() {
// get all window in stacking order.
Expand Down

0 comments on commit 24d8efd

Please sign in to comment.